Skip to content

Commit a22e966

Browse files
authored
[Clang] disallow # operators in attribute argument lists (#147308)
Fixes #147217 --- This PR addresses the parsing of attribute arguments by diagnosing and disallowing the `#` operator
1 parent a43c49f commit a22e966

File tree

4 files changed

+88
-0
lines changed

4 files changed

+88
-0
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -228,6 +228,12 @@ Improvements to Clang's diagnostics
228228
- Fixed false positive in ``-Wmissing-noreturn`` diagnostic when it was requiring the usage of
229229
``[[noreturn]]`` on lambdas before C++23 (#GH154493).
230230

231+
- Clang now diagnoses the use of ``#`` and ``##`` preprocessor tokens in
232+
attribute argument lists in C++ when ``-pedantic`` is enabled. The operators
233+
can be used in macro replacement lists with the usual preprocessor semantics,
234+
however, non-preprocessor use of tokens now triggers a pedantic warning in C++.
235+
Compilation in C mode is unchanged, and still permits these tokens to be used. (#GH147217)
236+
231237
Improvements to Clang's time-trace
232238
----------------------------------
233239

clang/include/clang/Basic/DiagnosticParseKinds.td

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -830,6 +830,9 @@ def err_ms_property_expected_comma_or_rparen : Error<
830830
"expected ',' or ')' at end of property accessor list">;
831831
def err_ms_property_initializer : Error<
832832
"property declaration cannot have a default member initializer">;
833+
def ext_invalid_attribute_argument
834+
: Extension<"'%0' is not allowed in an attribute argument list">,
835+
InGroup<DiagGroup<"attribute-preprocessor-tokens">>;
833836

834837
def err_assume_attr_expects_cond_expr : Error<
835838
"use of this expression in an %0 attribute requires parentheses">;

clang/lib/Parse/ParseDeclCXX.cpp

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4512,6 +4512,27 @@ bool Parser::ParseCXX11AttributeArgs(
45124512
Form = ParsedAttr::Form::Microsoft();
45134513
}
45144514

4515+
if (LO.CPlusPlus) {
4516+
TentativeParsingAction TPA(*this);
4517+
bool HasInvalidArgument = false;
4518+
while (Tok.isNot(tok::r_paren) && Tok.isNot(tok::eof)) {
4519+
if (Tok.isOneOf(tok::hash, tok::hashhash)) {
4520+
Diag(Tok.getLocation(), diag::ext_invalid_attribute_argument)
4521+
<< PP.getSpelling(Tok);
4522+
HasInvalidArgument = true;
4523+
}
4524+
ConsumeAnyToken();
4525+
}
4526+
4527+
if (HasInvalidArgument) {
4528+
SkipUntil(tok::r_paren);
4529+
TPA.Commit();
4530+
return true;
4531+
}
4532+
4533+
TPA.Revert();
4534+
}
4535+
45154536
// If the attribute isn't known, we will not attempt to parse any
45164537
// arguments.
45174538
if (Form.getSyntax() != ParsedAttr::AS_Microsoft &&
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
// RUN: %clang_cc1 -fsyntax-only -Wattribute-preprocessor-tokens -verify %s
2+
// RUN: %clang_cc1 -Wattribute-preprocessor-tokens -E %s | FileCheck %s
3+
// RUN: %clang_cc1 -x c -fsyntax-only -verify=c %s
4+
// RUN: %clang_cc1 -x c -E %s | FileCheck %s
5+
6+
#define ATTR_STR(X) [[clang::annotate(#X)]]
7+
#define ATTR_PASTE(X, Y) [[clang::annotate("test", X ## Y)]]
8+
9+
[[clang::assume(#)]] void f1(); // c-error {{expected expression}} \
10+
// expected-warning {{'#' is not allowed in an attribute argument list}}
11+
12+
[[clang::assume(##)]] void f2(); // c-error {{expected expression}} \
13+
// expected-warning {{'##' is not allowed in an attribute argument list}}
14+
15+
[[clang::assume(1#2#3)]] void f3(); // c-error {{use of this expression in an 'assume' attribute requires parentheses}} \
16+
// c-error {{expected ')'}} \
17+
// c-note {{to match this '('}} \
18+
// expected-warning {{'#' is not allowed in an attribute argument list}} \
19+
// expected-warning {{'#' is not allowed in an attribute argument list}}
20+
21+
[[unknown::unknown(#)]] void f4(); // c-warning {{unknown attribute 'unknown::unknown' ignored}} \
22+
// expected-warning {{'#' is not allowed in an attribute argument list}}
23+
24+
[[unknown::unknown(##)]] void f5(); // c-warning {{unknown attribute 'unknown::unknown' ignored}} \
25+
// expected-warning {{'##' is not allowed in an attribute argument list}}
26+
27+
[[unknown::unknown(1#2#3)]] void f6(); // c-warning {{unknown attribute 'unknown::unknown' ignored}} \
28+
// expected-warning {{'#' is not allowed in an attribute argument list}} \
29+
// expected-warning {{'#' is not allowed in an attribute argument list}}
30+
31+
[[clang::assume(%:)]] void f7(); // c-error {{expected expression}} \
32+
// expected-warning {{'%:' is not allowed in an attribute argument list}}
33+
34+
35+
[[clang::assume(%:%:)]] void f8(); // c-error {{expected expression}} \
36+
// expected-warning {{'%:%:' is not allowed in an attribute argument list}}
37+
38+
[[clang::assume(1%:2%:3)]] void f9(); // c-error {{use of this expression in an 'assume' attribute requires parentheses}} \
39+
// c-error {{expected ')'}} \
40+
// c-note {{to match this '('}} \
41+
// expected-warning {{'%:' is not allowed in an attribute argument list}} \
42+
// expected-warning {{'%:' is not allowed in an attribute argument list}}
43+
44+
[[unknown::unknown(%:)]] void f10(); // c-warning {{unknown attribute 'unknown::unknown' ignored}} \
45+
// expected-warning {{'%:' is not allowed in an attribute argument list}}
46+
47+
[[unknown::unknown(%:%:)]] void f11(); // c-warning {{unknown attribute 'unknown::unknown' ignored}} \
48+
// expected-warning {{'%:%:' is not allowed in an attribute argument list}}
49+
50+
[[unknown::unknown(1%:2%:3)]] void f12(); // c-warning {{unknown attribute 'unknown::unknown' ignored}} \
51+
// expected-warning {{'%:' is not allowed in an attribute argument list}} \
52+
// expected-warning {{'%:' is not allowed in an attribute argument list}}
53+
54+
ATTR_STR(stringify) void f13();
55+
// CHECK: {{\[\[}}clang{{::}}annotate("stringify"){{\]\]}} void f13();
56+
57+
ATTR_PASTE(1, 2) void f14();
58+
// CHECK: {{\[\[}}clang{{::}}annotate("test", 12){{\]\]}} void f14();

0 commit comments

Comments
 (0)