https://github.com/Fznamznon updated 
https://github.com/llvm/llvm-project/pull/218384

>From 233982bacdb13ade41716feae01536d8de88c5a3 Mon Sep 17 00:00:00 2001
From: Mariya Podchishchaeva <[email protected]>
Date: Fri, 21 Aug 2026 11:56:47 -0500
Subject: [PATCH 1/3] [clang][CUDA/HIP] Fix parsing of `operator<<<...>`

In CUDA mode Lexer merges <<< into a single token and Parser fails to
recognize that it is actually a template specialization of operator<<.
Split <<< following operator token to << and <.
---
 clang/include/clang/Lex/Lexer.h             |  2 +-
 clang/lib/Parse/ParseExprCXX.cpp            | 24 +++++++++++++++++++++
 clang/test/Parser/cuda-kernel-call-c++11.cu | 17 +++++++++++++++
 3 files changed, 42 insertions(+), 1 deletion(-)

diff --git a/clang/include/clang/Lex/Lexer.h b/clang/include/clang/Lex/Lexer.h
index b042e5fb088fa..f96d4d72feb1a 100644
--- a/clang/include/clang/Lex/Lexer.h
+++ b/clang/include/clang/Lex/Lexer.h
@@ -395,7 +395,7 @@ class Lexer : public PreprocessorLexer {
                                             const LangOptions &LangOpts);
 
   /// Get the physical length (including trigraphs and escaped newlines) of the
-  /// first \p Characters characters of the token starting at TokStart.
+  /// first \p CharNo characters of the token starting at TokStart.
   static unsigned getTokenPrefixLength(SourceLocation TokStart,
                                        unsigned CharNo,
                                        const SourceManager &SM,
diff --git a/clang/lib/Parse/ParseExprCXX.cpp b/clang/lib/Parse/ParseExprCXX.cpp
index f9a0dcc7d53af..883da4907b8eb 100644
--- a/clang/lib/Parse/ParseExprCXX.cpp
+++ b/clang/lib/Parse/ParseExprCXX.cpp
@@ -2485,6 +2485,30 @@ bool Parser::ParseUnqualifiedIdOperator(CXXScopeSpec 
&SS, bool EnteringContext,
       Actions.CodeCompletion().CodeCompleteOperatorName(getCurScope());
       return true;
     }
+    case tok::lesslessless: {
+      // For CUDA, the Lexer will greedily merge all three <<< in operator<<<
+      // which, in fact, can be a valid template specialization of operator<<,
+      // and will never be a valid kernel launch expression, so split.
+      bool CachingTokens = PP.IsPreviousCachedToken(Tok);
+      // If there was a cache, we should update it when doing token split.
+      // The code below never does.
+      assert(!CachingTokens && "No cache expected");
+
+      SourceLocation TokLoc = Tok.getLocation();
+      unsigned LessLessLength = Lexer::getTokenPrefixLength(
+          TokLoc, /*CharNo=*/2, PP.getSourceManager(), getLangOpts());
+
+      SourceLocation LessLoc = PP.SplitToken(TokLoc, LessLessLength);
+      unsigned OldLength = Tok.getLength();
+
+      Tok.setKind(tok::less);
+      Tok.setLength(OldLength - LessLessLength);
+      Tok.setLocation(LessLoc);
+
+      SymbolLocations[SymbolIdx++] = TokLoc;
+      Op = OO_LessLess;
+      break;
+     }
 
     default:
       break;
diff --git a/clang/test/Parser/cuda-kernel-call-c++11.cu 
b/clang/test/Parser/cuda-kernel-call-c++11.cu
index ef71e2a9acf45..f2fd8ab06ce88 100644
--- a/clang/test/Parser/cuda-kernel-call-c++11.cu
+++ b/clang/test/Parser/cuda-kernel-call-c++11.cu
@@ -1,4 +1,5 @@
 // RUN: %clang_cc1 -fsyntax-only -std=c++11 -verify %s
+// RUN: %clang_cc1 -fsyntax-only -std=c++11 -verify -x hip %s
 
 template<typename T=int> struct S {};
 template<typename> void f();
@@ -33,3 +34,19 @@ template<typename ...T>
 void bar(T... args) {
   S<S<V<void(T)...>>> s7;
 }
+
+template <typename T, typename T1> void operator<<(T, T1);
+
+struct S1 {};
+
+template <> void operator<<<>(S1, S1);
+
+class C {
+public:
+  template <typename T> void operator<<(T) {}
+};
+
+void foobar() {
+  C CC;
+  CC.operator<<<int>(1);
+}

>From e8e0c20f18b1ebae88006aa4daedd6e0a76913f0 Mon Sep 17 00:00:00 2001
From: Mariya Podchishchaeva <[email protected]>
Date: Tue, 25 Aug 2026 05:32:37 -0500
Subject: [PATCH 2/3] Fix source location, fix cache, add test

---
 clang/lib/Parse/ParseExprCXX.cpp            | 22 +++++++++++++--------
 clang/test/Parser/cuda-kernel-call-c++11.cu | 20 +++++++++++++++++++
 2 files changed, 34 insertions(+), 8 deletions(-)

diff --git a/clang/lib/Parse/ParseExprCXX.cpp b/clang/lib/Parse/ParseExprCXX.cpp
index 883da4907b8eb..a25d814d326c4 100644
--- a/clang/lib/Parse/ParseExprCXX.cpp
+++ b/clang/lib/Parse/ParseExprCXX.cpp
@@ -2489,26 +2489,32 @@ bool Parser::ParseUnqualifiedIdOperator(CXXScopeSpec 
&SS, bool EnteringContext,
       // For CUDA, the Lexer will greedily merge all three <<< in operator<<<
       // which, in fact, can be a valid template specialization of operator<<,
       // and will never be a valid kernel launch expression, so split.
-      bool CachingTokens = PP.IsPreviousCachedToken(Tok);
-      // If there was a cache, we should update it when doing token split.
-      // The code below never does.
-      assert(!CachingTokens && "No cache expected");
 
       SourceLocation TokLoc = Tok.getLocation();
       unsigned LessLessLength = Lexer::getTokenPrefixLength(
           TokLoc, /*CharNo=*/2, PP.getSourceManager(), getLangOpts());
 
-      SourceLocation LessLoc = PP.SplitToken(TokLoc, LessLessLength);
+      SourceLocation LessLessLoc = PP.SplitToken(TokLoc, LessLessLength);
+      Token LessLess = Tok;
+      LessLess.setLocation(LessLessLoc);
+      LessLess.setKind(tok::lessless);
+      LessLess.setLength(LessLessLength);
+
       unsigned OldLength = Tok.getLength();
 
       Tok.setKind(tok::less);
       Tok.setLength(OldLength - LessLessLength);
-      Tok.setLocation(LessLoc);
+      Tok.setLocation(TokLoc.getLocWithOffset(LessLessLength));
 
-      SymbolLocations[SymbolIdx++] = TokLoc;
+      // Update the cache if there is any.
+      bool CachingTokens = PP.IsPreviousCachedToken(Tok);
+      if (CachingTokens)
+        PP.ReplacePreviousCachedToken({LessLess});
+
+      SymbolLocations[SymbolIdx++] = LessLessLoc;
       Op = OO_LessLess;
       break;
-     }
+    }
 
     default:
       break;
diff --git a/clang/test/Parser/cuda-kernel-call-c++11.cu 
b/clang/test/Parser/cuda-kernel-call-c++11.cu
index f2fd8ab06ce88..9223be4e1812a 100644
--- a/clang/test/Parser/cuda-kernel-call-c++11.cu
+++ b/clang/test/Parser/cuda-kernel-call-c++11.cu
@@ -1,5 +1,6 @@
 // RUN: %clang_cc1 -fsyntax-only -std=c++11 -verify %s
 // RUN: %clang_cc1 -fsyntax-only -std=c++11 -verify -x hip %s
+// RUN: not %clang_cc1 %s -DSLOC_CHECK 2>&1 | FileCheck %s --strict-whitespace
 
 template<typename T=int> struct S {};
 template<typename> void f();
@@ -49,4 +50,23 @@ public:
 void foobar() {
   C CC;
   CC.operator<<<int>(1);
+  CC.template operator<<<int>(1);
+#ifdef SLOC_CHECK
+  // We split <<< into a << followed by a <, check that < has right source
+  // location.
+  CC.operator<<<int;
+  // CHECK: error: expected '>'
+  // CHECK-NEXT: CC.operator<<<int;
+  // CHECK-NEXT:                  ^
+  // CHECK-NEXT: to match this '<'
+  // CHECK-NEXT: CC.operator<<<int;
+  // CHECK-NEXT:              ^
+  CC.template operator<<<int;
+  // CHECK: error: expected '>'
+  // CHECK-NEXT: CC.template operator<<<int;
+  // CHECK-NEXT:                           ^
+  // CHECK-NEXT: to match this '<'
+  // CHECK-NEXT: CC.template operator<<<int;
+  // CHECK-NEXT:                        ^
+#endif
 }

>From ad58f4031f0b0be0d88f413ab53bda6c37a7bbff Mon Sep 17 00:00:00 2001
From: Mariya Podchishchaeva <[email protected]>
Date: Tue, 25 Aug 2026 06:13:28 -0500
Subject: [PATCH 3/3] Fix bad test

---
 clang/test/Parser/cuda-kernel-call-c++11.cu | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/clang/test/Parser/cuda-kernel-call-c++11.cu 
b/clang/test/Parser/cuda-kernel-call-c++11.cu
index 9223be4e1812a..4ea91d8477e40 100644
--- a/clang/test/Parser/cuda-kernel-call-c++11.cu
+++ b/clang/test/Parser/cuda-kernel-call-c++11.cu
@@ -1,6 +1,6 @@
 // RUN: %clang_cc1 -fsyntax-only -std=c++11 -verify %s
 // RUN: %clang_cc1 -fsyntax-only -std=c++11 -verify -x hip %s
-// RUN: not %clang_cc1 %s -DSLOC_CHECK 2>&1 | FileCheck %s --strict-whitespace
+// RUN: not %clang_cc1 -fsyntax-only %s -DSLOC_CHECK 2>&1 | FileCheck %s 
--strict-whitespace
 
 template<typename T=int> struct S {};
 template<typename> void f();
@@ -55,18 +55,18 @@ void foobar() {
   // We split <<< into a << followed by a <, check that < has right source
   // location.
   CC.operator<<<int;
-  // CHECK: error: expected '>'
+  // CHECK: [[@LINE-1]]:20: error: expected '>'
   // CHECK-NEXT: CC.operator<<<int;
   // CHECK-NEXT:                  ^
-  // CHECK-NEXT: to match this '<'
+  // CHECK-NEXT: [[@LINE-4]]:16: note: to match this '<'
   // CHECK-NEXT: CC.operator<<<int;
   // CHECK-NEXT:              ^
   CC.template operator<<<int;
-  // CHECK: error: expected '>'
+  // CHECK: [[@LINE-1]]:29: error: expected '>'
   // CHECK-NEXT: CC.template operator<<<int;
   // CHECK-NEXT:                           ^
-  // CHECK-NEXT: to match this '<'
+  // CHECK-NEXT: [[@LINE-4]]:25: note: to match this '<'
   // CHECK-NEXT: CC.template operator<<<int;
-  // CHECK-NEXT:                        ^
+  // CHECK-NEXT:                       ^
 #endif
 }

_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to