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