https://github.com/a-tarasyuk updated 
https://github.com/llvm/llvm-project/pull/147308

>From 8f1c383f8f84fb636af4a78e0ff504830f9272f5 Mon Sep 17 00:00:00 2001
From: Oleksandr Tarasiuk <oleksandr.taras...@outlook.com>
Date: Mon, 7 Jul 2025 17:20:48 +0300
Subject: [PATCH 1/5] [Clang] disallow  operator in attribute argument lists

---
 clang/docs/ReleaseNotes.rst                       | 1 +
 clang/include/clang/Basic/DiagnosticParseKinds.td | 2 ++
 clang/lib/Parse/ParseDecl.cpp                     | 7 +++++++
 clang/test/Parser/cxx0x-attributes.cpp            | 5 +++++
 4 files changed, 15 insertions(+)

diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index a6be59f1d6bd7..b8032ee9c03da 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -673,6 +673,7 @@ Improvements to Clang's diagnostics
   false positives in exception-heavy code, though only simple patterns
   are currently recognized.
 
+- Clang now rejects ``#`` operators in attribute argument lists. (#GH147217)
 
 Improvements to Clang's time-trace
 ----------------------------------
diff --git a/clang/include/clang/Basic/DiagnosticParseKinds.td 
b/clang/include/clang/Basic/DiagnosticParseKinds.td
index 6c30da376dafb..b39e2a7359c22 100644
--- a/clang/include/clang/Basic/DiagnosticParseKinds.td
+++ b/clang/include/clang/Basic/DiagnosticParseKinds.td
@@ -830,6 +830,8 @@ def err_ms_property_expected_comma_or_rparen : Error<
   "expected ',' or ')' at end of property accessor list">;
 def err_ms_property_initializer : Error<
   "property declaration cannot have a default member initializer">;
+def err_invalid_attribute_argument
+    : Error<"'%0' is not allowed in attribute argument lists">;
 
 def err_assume_attr_expects_cond_expr : Error<
   "use of this expression in an %0 attribute requires parentheses">;
diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp
index 7e739e09b15e8..059636653723c 100644
--- a/clang/lib/Parse/ParseDecl.cpp
+++ b/clang/lib/Parse/ParseDecl.cpp
@@ -488,6 +488,13 @@ unsigned Parser::ParseAttributeArgsCommon(
   bool AttributeHasVariadicIdentifierArg =
       attributeHasVariadicIdentifierArg(*AttrName, Form.getSyntax(), 
ScopeName);
 
+  if (Tok.is(tok::hash) || Tok.is(tok::hashhash)) {
+    Diag(Tok.getLocation(), diag::err_invalid_attribute_argument)
+        << PP.getSpelling(Tok);
+    SkipUntil(tok::r_paren, StopAtSemi);
+    return 0;
+  }
+
   // Interpret "kw_this" as an identifier if the attributed requests it.
   if (ChangeKWThisToIdent && Tok.is(tok::kw_this))
     Tok.setKind(tok::identifier);
diff --git a/clang/test/Parser/cxx0x-attributes.cpp 
b/clang/test/Parser/cxx0x-attributes.cpp
index 372a373a49ec5..d343cd4f3a93e 100644
--- a/clang/test/Parser/cxx0x-attributes.cpp
+++ b/clang/test/Parser/cxx0x-attributes.cpp
@@ -477,3 +477,8 @@ namespace P2361 {
 }
 
 alignas(int) struct AlignAsAttribute {}; // expected-error {{misplaced 
attributes; expected attributes here}}
+
+namespace GH147217 {
+  [[clang::annotate(#)]] void a();      // expected-error {{'#' is not allowed 
in attribute argument lists}}
+  [[clang::annotate(##)]] void b();     // expected-error {{'##' is not 
allowed in attribute argument lists}}
+}

>From 962f703e11a25f6ddf9b0ba5ac045456d5167242 Mon Sep 17 00:00:00 2001
From: Oleksandr Tarasiuk <oleksandr.taras...@outlook.com>
Date: Mon, 7 Jul 2025 18:49:55 +0300
Subject: [PATCH 2/5] update diagnostic message

---
 clang/include/clang/Basic/DiagnosticParseKinds.td | 2 +-
 clang/test/Parser/cxx0x-attributes.cpp            | 6 ++++--
 2 files changed, 5 insertions(+), 3 deletions(-)

diff --git a/clang/include/clang/Basic/DiagnosticParseKinds.td 
b/clang/include/clang/Basic/DiagnosticParseKinds.td
index b39e2a7359c22..d53ef7a93bfda 100644
--- a/clang/include/clang/Basic/DiagnosticParseKinds.td
+++ b/clang/include/clang/Basic/DiagnosticParseKinds.td
@@ -831,7 +831,7 @@ def err_ms_property_expected_comma_or_rparen : Error<
 def err_ms_property_initializer : Error<
   "property declaration cannot have a default member initializer">;
 def err_invalid_attribute_argument
-    : Error<"'%0' is not allowed in attribute argument lists">;
+    : Error<"'%0' is not allowed in an attribute argument list">;
 
 def err_assume_attr_expects_cond_expr : Error<
   "use of this expression in an %0 attribute requires parentheses">;
diff --git a/clang/test/Parser/cxx0x-attributes.cpp 
b/clang/test/Parser/cxx0x-attributes.cpp
index d343cd4f3a93e..f5a3039c4470c 100644
--- a/clang/test/Parser/cxx0x-attributes.cpp
+++ b/clang/test/Parser/cxx0x-attributes.cpp
@@ -479,6 +479,8 @@ namespace P2361 {
 alignas(int) struct AlignAsAttribute {}; // expected-error {{misplaced 
attributes; expected attributes here}}
 
 namespace GH147217 {
-  [[clang::annotate(#)]] void a();      // expected-error {{'#' is not allowed 
in attribute argument lists}}
-  [[clang::annotate(##)]] void b();     // expected-error {{'##' is not 
allowed in attribute argument lists}}
+  [[clang::annotate(#)]] void a();    // expected-error {{'#' is not allowed 
in an attribute argument list}}
+  [[clang::annotate(##)]] void b();   // expected-error {{'##' is not allowed 
in an attribute argument list}}
+  [[clang::annotate(%:)]] void c();   // expected-error {{'%:' is not allowed 
in an attribute argument list}}
+  [[clang::annotate(%:%:)]] void d(); // expected-error {{'%:%:' is not 
allowed in an attribute argument list}}
 }

>From a697990d1fc6aa021c4b63bc0b3ad1efe55cec5b Mon Sep 17 00:00:00 2001
From: Oleksandr Tarasiuk <oleksandr.taras...@outlook.com>
Date: Mon, 7 Jul 2025 18:51:30 +0300
Subject: [PATCH 3/5] disallow  and  operators in C++ mode only

---
 clang/lib/Parse/ParseDecl.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp
index 059636653723c..495aa778b0d7f 100644
--- a/clang/lib/Parse/ParseDecl.cpp
+++ b/clang/lib/Parse/ParseDecl.cpp
@@ -488,7 +488,7 @@ unsigned Parser::ParseAttributeArgsCommon(
   bool AttributeHasVariadicIdentifierArg =
       attributeHasVariadicIdentifierArg(*AttrName, Form.getSyntax(), 
ScopeName);
 
-  if (Tok.is(tok::hash) || Tok.is(tok::hashhash)) {
+  if (getLangOpts().CPlusPlus && Tok.isOneOf(tok::hash, tok::hashhash)) {
     Diag(Tok.getLocation(), diag::err_invalid_attribute_argument)
         << PP.getSpelling(Tok);
     SkipUntil(tok::r_paren, StopAtSemi);

>From ac38e4d2b4432af6c1eb6f69a76394c205c3eea7 Mon Sep 17 00:00:00 2001
From: Oleksandr Tarasiuk <oleksandr.taras...@outlook.com>
Date: Wed, 9 Jul 2025 00:41:52 +0300
Subject: [PATCH 4/5] update release notes

---
 clang/docs/ReleaseNotes.rst | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 554f89cc498c2..a7adb8919e5b4 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -678,7 +678,10 @@ Improvements to Clang's diagnostics
 - Clang now accepts ``@tparam`` comments on variable template partial
   specializations. (#GH144775)
 
-- Clang now rejects ``#`` operators in attribute argument lists. (#GH147217)
+- Clang rejects the ``#`` and ``##`` preprocessor tokens in an attribute
+  argument list in C++. The operators can be used in macro replacement lists
+  with the usual preprocessor semantics. What is rejected are non-preprocessor
+  uses of the tokens. The same restrictions do not apply in C. (#GH147217)
 
 Improvements to Clang's time-trace
 ----------------------------------

>From 9204a36843d27fa23a522aacee3a6a16d9388970 Mon Sep 17 00:00:00 2001
From: Oleksandr Tarasiuk <oleksandr.taras...@outlook.com>
Date: Wed, 9 Jul 2025 00:42:59 +0300
Subject: [PATCH 5/5] handle preprocessor tokens in unknown attributes

---
 clang/lib/Parse/ParseDecl.cpp                 |  7 ---
 clang/lib/Parse/ParseDeclCXX.cpp              | 21 +++++++
 .../cxx0x-attributes-preprocessor-tokens.cpp  | 58 +++++++++++++++++++
 clang/test/Parser/cxx0x-attributes.cpp        |  7 ---
 4 files changed, 79 insertions(+), 14 deletions(-)
 create mode 100644 clang/test/Parser/cxx0x-attributes-preprocessor-tokens.cpp

diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp
index 495aa778b0d7f..7e739e09b15e8 100644
--- a/clang/lib/Parse/ParseDecl.cpp
+++ b/clang/lib/Parse/ParseDecl.cpp
@@ -488,13 +488,6 @@ unsigned Parser::ParseAttributeArgsCommon(
   bool AttributeHasVariadicIdentifierArg =
       attributeHasVariadicIdentifierArg(*AttrName, Form.getSyntax(), 
ScopeName);
 
-  if (getLangOpts().CPlusPlus && Tok.isOneOf(tok::hash, tok::hashhash)) {
-    Diag(Tok.getLocation(), diag::err_invalid_attribute_argument)
-        << PP.getSpelling(Tok);
-    SkipUntil(tok::r_paren, StopAtSemi);
-    return 0;
-  }
-
   // Interpret "kw_this" as an identifier if the attributed requests it.
   if (ChangeKWThisToIdent && Tok.is(tok::kw_this))
     Tok.setKind(tok::identifier);
diff --git a/clang/lib/Parse/ParseDeclCXX.cpp b/clang/lib/Parse/ParseDeclCXX.cpp
index 6b0564dca6f45..57555a287382b 100644
--- a/clang/lib/Parse/ParseDeclCXX.cpp
+++ b/clang/lib/Parse/ParseDeclCXX.cpp
@@ -4523,6 +4523,27 @@ bool Parser::ParseCXX11AttributeArgs(
       Form = ParsedAttr::Form::Microsoft();
   }
 
+  if (LO.CPlusPlus) {
+    TentativeParsingAction TPA(*this);
+    bool HasInvalidArgument = false;
+    while (Tok.isNot(tok::r_paren) && Tok.isNot(tok::eof)) {
+      if (Tok.isOneOf(tok::hash, tok::hashhash)) {
+        Diag(Tok.getLocation(), diag::err_invalid_attribute_argument)
+            << PP.getSpelling(Tok);
+        HasInvalidArgument = true;
+      }
+      ConsumeAnyToken();
+    }
+
+    if (HasInvalidArgument) {
+      SkipUntil(tok::r_paren);
+      TPA.Commit();
+      return true;
+    }
+
+    TPA.Revert();
+  }
+
   // If the attribute isn't known, we will not attempt to parse any
   // arguments.
   if (Form.getSyntax() != ParsedAttr::AS_Microsoft &&
diff --git a/clang/test/Parser/cxx0x-attributes-preprocessor-tokens.cpp 
b/clang/test/Parser/cxx0x-attributes-preprocessor-tokens.cpp
new file mode 100644
index 0000000000000..23a9d597e5dd8
--- /dev/null
+++ b/clang/test/Parser/cxx0x-attributes-preprocessor-tokens.cpp
@@ -0,0 +1,58 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -E %s | FileCheck %s
+// RUN: %clang_cc1 -x c -fsyntax-only -verify=c %s
+// RUN: %clang_cc1 -x c -E %s | FileCheck %s
+
+#define ATTR_STR(X) [[clang::annotate(#X)]]
+#define ATTR_PASTE(X, Y) [[clang::annotate("test", X ## Y)]]
+
+[[clang::assume(#)]] void f1();           // c-error {{expected expression}} \
+                                          // expected-error {{'#' is not 
allowed in an attribute argument list}}
+
+[[clang::assume(##)]] void f2();          // c-error {{expected expression}} \
+                                          // expected-error {{'##' is not 
allowed in an attribute argument list}}
+
+[[clang::assume(1#2#3)]] void f3();       // c-error {{use of this expression 
in an 'assume' attribute requires parentheses}} \
+                                          // c-error {{expected ')'}} \
+                                          // c-note {{to match this '('}} \
+                                          // expected-error {{'#' is not 
allowed in an attribute argument list}} \
+                                          // expected-error {{'#' is not 
allowed in an attribute argument list}}
+
+[[unknown::unknown(#)]] void f4();        // c-warning {{unknown attribute 
'unknown::unknown' ignored}} \
+                                          // expected-error {{'#' is not 
allowed in an attribute argument list}}
+
+[[unknown::unknown(##)]] void f5();       // c-warning {{unknown attribute 
'unknown::unknown' ignored}} \
+                                          // expected-error {{'##' is not 
allowed in an attribute argument list}}
+
+[[unknown::unknown(1#2#3)]] void f6();    // c-warning {{unknown attribute 
'unknown::unknown' ignored}} \
+                                          // expected-error {{'#' is not 
allowed in an attribute argument list}} \
+                                          // expected-error {{'#' is not 
allowed in an attribute argument list}}
+
+[[clang::assume(%:)]] void f7();          // c-error {{expected expression}} \
+                                          // expected-error {{'%:' is not 
allowed in an attribute argument list}}
+
+
+[[clang::assume(%:%:)]] void f8();        // c-error {{expected expression}} \
+                                          // expected-error {{'%:%:' is not 
allowed in an attribute argument list}}
+
+[[clang::assume(1%:2%:3)]] void f9();     // c-error {{use of this expression 
in an 'assume' attribute requires parentheses}} \
+                                          // c-error {{expected ')'}} \
+                                          // c-note {{to match this '('}} \
+                                          // expected-error {{'%:' is not 
allowed in an attribute argument list}} \
+                                          // expected-error {{'%:' is not 
allowed in an attribute argument list}}
+
+[[unknown::unknown(%:)]] void f10();      // c-warning {{unknown attribute 
'unknown::unknown' ignored}} \
+                                          // expected-error {{'%:' is not 
allowed in an attribute argument list}}
+
+[[unknown::unknown(%:%:)]] void f11();    // c-warning {{unknown attribute 
'unknown::unknown' ignored}} \
+                                          // expected-error {{'%:%:' is not 
allowed in an attribute argument list}}
+
+[[unknown::unknown(1%:2%:3)]] void f12(); // c-warning {{unknown attribute 
'unknown::unknown' ignored}} \
+                                          // expected-error {{'%:' is not 
allowed in an attribute argument list}} \
+                                          // expected-error {{'%:' is not 
allowed in an attribute argument list}}
+
+ATTR_STR(stringify) void f13();
+// CHECK: {{\[\[}}clang{{::}}annotate("stringify"){{\]\]}} void f13();
+
+ATTR_PASTE(1, 2) void f14();
+// CHECK: {{\[\[}}clang{{::}}annotate("test", 12){{\]\]}} void f14();
diff --git a/clang/test/Parser/cxx0x-attributes.cpp 
b/clang/test/Parser/cxx0x-attributes.cpp
index f5a3039c4470c..372a373a49ec5 100644
--- a/clang/test/Parser/cxx0x-attributes.cpp
+++ b/clang/test/Parser/cxx0x-attributes.cpp
@@ -477,10 +477,3 @@ namespace P2361 {
 }
 
 alignas(int) struct AlignAsAttribute {}; // expected-error {{misplaced 
attributes; expected attributes here}}
-
-namespace GH147217 {
-  [[clang::annotate(#)]] void a();    // expected-error {{'#' is not allowed 
in an attribute argument list}}
-  [[clang::annotate(##)]] void b();   // expected-error {{'##' is not allowed 
in an attribute argument list}}
-  [[clang::annotate(%:)]] void c();   // expected-error {{'%:' is not allowed 
in an attribute argument list}}
-  [[clang::annotate(%:%:)]] void d(); // expected-error {{'%:%:' is not 
allowed in an attribute argument list}}
-}

_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to