Skip to content

Commit 191386f

Browse files
yronglinFznamznon
andauthored
[C23][Parser] Diagnostic for attribute declaration where statement is required (llvm#146224)
Fixes: llvm#141659 In C23, something like [[/*possible attributes*/]]; is an attribute declaration, not a statement. So it is not allowed by the syntax in places where a statement is required, specifically as the secondary block of a selection or iteration statement. Therefore, code like the following should give a diagnostic (at least with -std=c23 -pedantic), but Clang currently does not produce one: ```cpp int main(void) { if (1) [[]]; } ``` --------- Signed-off-by: yronglin <yronglin777@gmail.com> Signed-off-by: Wang, Yihan <yronglin777@gmail.com> Co-authored-by: Mariya Podchishchaeva <mariya.podchishchaeva@intel.com>
1 parent 78039e1 commit 191386f

File tree

5 files changed

+58
-7
lines changed

5 files changed

+58
-7
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -767,6 +767,11 @@ Bug Fixes in This Version
767767
flag and diagnostic because the macro injection was used to emit this warning.
768768
Unfortunately there is no other good way to diagnose usage of ``static_assert``
769769
macro without inclusion of ``<assert.h>``.
770+
- In C23, something like ``[[/*possible attributes*/]];`` is an attribute
771+
declaration, not a statement. So it is not allowed by the syntax in places
772+
where a statement is required, specifically as the secondary block of a
773+
selection or iteration statement. This differs from C++, since C++ allows
774+
declaration statements. Clang now emits a warning for these patterns. (#GH141659)
770775

771776
Bug Fixes to Compiler Builtins
772777
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

clang/include/clang/Basic/DiagnosticParseKinds.td

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -276,6 +276,9 @@ def err_expected_while : Error<"expected 'while' in do/while loop">;
276276

277277
def err_expected_semi_after_stmt : Error<"expected ';' after %0 statement">;
278278
def err_expected_semi_after_expr : Error<"expected ';' after expression">;
279+
def warn_attr_in_secondary_block : ExtWarn<
280+
"ISO C does not allow an attribute list to appear here">,
281+
InGroup<DiagGroup<"c-attribute-extension">>;
279282
def err_extraneous_token_before_semi : Error<"extraneous '%0' before ';'">;
280283

281284
def err_expected_semi_after_method_proto : Error<

clang/lib/Parse/ParseStmt.cpp

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,8 @@ Parser::ParseStatementOrDeclaration(StmtVector &Stmts,
6363
// at the start of the statement. Thus, we're not using MaybeParseAttributes
6464
// here because we don't want to allow arbitrary orderings.
6565
ParsedAttributes CXX11Attrs(AttrFactory);
66-
MaybeParseCXX11Attributes(CXX11Attrs, /*MightBeObjCMessageSend*/ true);
66+
bool HasStdAttr =
67+
MaybeParseCXX11Attributes(CXX11Attrs, /*MightBeObjCMessageSend*/ true);
6768
ParsedAttributes GNUOrMSAttrs(AttrFactory);
6869
if (getLangOpts().OpenCL)
6970
MaybeParseGNUAttributes(GNUOrMSAttrs);
@@ -80,6 +81,13 @@ Parser::ParseStatementOrDeclaration(StmtVector &Stmts,
8081
assert((CXX11Attrs.empty() || Res.isInvalid() || Res.isUsable()) &&
8182
"attributes on empty statement");
8283

84+
if (HasStdAttr && getLangOpts().C23 &&
85+
(StmtCtx & ParsedStmtContext::AllowDeclarationsInC) ==
86+
ParsedStmtContext{} &&
87+
isa_and_present<NullStmt>(Res.get()))
88+
Diag(CXX11Attrs.Range.getBegin(), diag::warn_attr_in_secondary_block)
89+
<< CXX11Attrs.Range;
90+
8391
if (CXX11Attrs.empty() || Res.isInvalid())
8492
return Res;
8593

clang/test/Parser/statements.c

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
// RUN: %clang_cc1 -fsyntax-only -verify %s -Wno-unreachable-code
2+
// RUN: %clang_cc1 -std=c23 -fsyntax-only -verify %s -Wno-unreachable-code
23

34
void test1(void) {
45
{ ; { ;;}} ;;
@@ -77,3 +78,32 @@ int test9(void) {
7778

7879
return 4, // expected-error {{expected ';' after return statement}}
7980
}
81+
82+
#if __STDC_VERSION__ >= 202311L
83+
void attr_decl_in_selection_statement(int n) {
84+
if (1)
85+
[[]]; // expected-warning {{ISO C does not allow an attribute list to appear here}}
86+
87+
if (1) {
88+
89+
} else
90+
[[]]; // expected-warning {{ISO C does not allow an attribute list to appear here}}
91+
92+
93+
switch (n)
94+
[[]]; // expected-warning {{ISO C does not allow an attribute list to appear here}}
95+
}
96+
97+
void attr_decl_in_iteration_statement(int n) {
98+
int i;
99+
for (i = 0; i < n; ++i)
100+
[[]]; // expected-warning {{ISO C does not allow an attribute list to appear here}}
101+
102+
while (i > 0)
103+
[[]]; // expected-warning {{ISO C does not allow an attribute list to appear here}}
104+
105+
do
106+
[[]]; // expected-warning {{ISO C does not allow an attribute list to appear here}}
107+
while (i > 0);
108+
}
109+
#endif // __STDC_VERSION__ >= 202311L

clang/test/Sema/c2x-fallthrough.c

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// RUN: %clang_cc1 -fsyntax-only -std=c2x -verify %s
1+
// RUN: %clang_cc1 -fsyntax-only -std=c23 -verify %s
22

33
// This is the latest version of fallthrough that we support.
44
_Static_assert(__has_c_attribute(fallthrough) == 201910L);
@@ -16,17 +16,22 @@ void f(int n) {
1616
}
1717
case 2:
1818
for (int n = 0; n != 10; ++n)
19-
[[fallthrough]]; // expected-error {{does not directly precede switch label}}
19+
[[fallthrough]]; // expected-error {{does not directly precede switch label}} \
20+
// expected-warning {{ISO C does not allow an attribute list to appear here}}
2021
case 3:
2122
while (1)
22-
[[fallthrough]]; // expected-error {{does not directly precede switch label}}
23+
[[fallthrough]]; // expected-error {{does not directly precede switch label}} \
24+
// expected-warning {{ISO C does not allow an attribute list to appear here}}
2325
case 4:
2426
while (0)
25-
[[fallthrough]]; // expected-error {{does not directly precede switch label}}
27+
[[fallthrough]]; // expected-error {{does not directly precede switch label}} \
28+
// expected-warning {{ISO C does not allow an attribute list to appear here}}
2629
case 5:
27-
do [[fallthrough]]; while (1); // expected-error {{does not directly precede switch label}}
30+
do [[fallthrough]]; while (1); // expected-error {{does not directly precede switch label}} \
31+
// expected-warning {{ISO C does not allow an attribute list to appear here}}
2832
case 6:
29-
do [[fallthrough]]; while (0); // expected-error {{does not directly precede switch label}}
33+
do [[fallthrough]]; while (0); // expected-error {{does not directly precede switch label}} \
34+
// expected-warning {{ISO C does not allow an attribute list to appear here}}
3035
case 7:
3136
switch (n) {
3237
case 0:

0 commit comments

Comments
 (0)