Author: yronglin Date: 2025-07-09T08:54:30+08:00 New Revision: 191386fcd3335c5b7194da209d71d16549a2bb2f
URL: https://github.com/llvm/llvm-project/commit/191386fcd3335c5b7194da209d71d16549a2bb2f DIFF: https://github.com/llvm/llvm-project/commit/191386fcd3335c5b7194da209d71d16549a2bb2f.diff LOG: [C23][Parser] Diagnostic for attribute declaration where statement is required (#146224) Fixes: https://github.com/llvm/llvm-project/issues/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 <yronglin...@gmail.com> Signed-off-by: Wang, Yihan <yronglin...@gmail.com> Co-authored-by: Mariya Podchishchaeva <mariya.podchishcha...@intel.com> Added: Modified: clang/docs/ReleaseNotes.rst clang/include/clang/Basic/DiagnosticParseKinds.td clang/lib/Parse/ParseStmt.cpp clang/test/Parser/statements.c clang/test/Sema/c2x-fallthrough.c Removed: ################################################################################ diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 8b4f9229c4463..57a94242c9e61 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -767,6 +767,11 @@ Bug Fixes in This Version flag and diagnostic because the macro injection was used to emit this warning. Unfortunately there is no other good way to diagnose usage of ``static_assert`` macro without inclusion of ``<assert.h>``. +- 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. This diff ers from C++, since C++ allows + declaration statements. Clang now emits a warning for these patterns. (#GH141659) Bug Fixes to Compiler Builtins ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/clang/include/clang/Basic/DiagnosticParseKinds.td b/clang/include/clang/Basic/DiagnosticParseKinds.td index 4636eaf2291ab..fd8e5c3c6ad87 100644 --- a/clang/include/clang/Basic/DiagnosticParseKinds.td +++ b/clang/include/clang/Basic/DiagnosticParseKinds.td @@ -276,6 +276,9 @@ def err_expected_while : Error<"expected 'while' in do/while loop">; def err_expected_semi_after_stmt : Error<"expected ';' after %0 statement">; def err_expected_semi_after_expr : Error<"expected ';' after expression">; +def warn_attr_in_secondary_block : ExtWarn< + "ISO C does not allow an attribute list to appear here">, + InGroup<DiagGroup<"c-attribute-extension">>; def err_extraneous_token_before_semi : Error<"extraneous '%0' before ';'">; def err_expected_semi_after_method_proto : Error< diff --git a/clang/lib/Parse/ParseStmt.cpp b/clang/lib/Parse/ParseStmt.cpp index 8217151a0259a..31b84b6f2ede0 100644 --- a/clang/lib/Parse/ParseStmt.cpp +++ b/clang/lib/Parse/ParseStmt.cpp @@ -63,7 +63,8 @@ Parser::ParseStatementOrDeclaration(StmtVector &Stmts, // at the start of the statement. Thus, we're not using MaybeParseAttributes // here because we don't want to allow arbitrary orderings. ParsedAttributes CXX11Attrs(AttrFactory); - MaybeParseCXX11Attributes(CXX11Attrs, /*MightBeObjCMessageSend*/ true); + bool HasStdAttr = + MaybeParseCXX11Attributes(CXX11Attrs, /*MightBeObjCMessageSend*/ true); ParsedAttributes GNUOrMSAttrs(AttrFactory); if (getLangOpts().OpenCL) MaybeParseGNUAttributes(GNUOrMSAttrs); @@ -80,6 +81,13 @@ Parser::ParseStatementOrDeclaration(StmtVector &Stmts, assert((CXX11Attrs.empty() || Res.isInvalid() || Res.isUsable()) && "attributes on empty statement"); + if (HasStdAttr && getLangOpts().C23 && + (StmtCtx & ParsedStmtContext::AllowDeclarationsInC) == + ParsedStmtContext{} && + isa_and_present<NullStmt>(Res.get())) + Diag(CXX11Attrs.Range.getBegin(), diag::warn_attr_in_secondary_block) + << CXX11Attrs.Range; + if (CXX11Attrs.empty() || Res.isInvalid()) return Res; diff --git a/clang/test/Parser/statements.c b/clang/test/Parser/statements.c index 2566da83d7c53..22a6633bdf262 100644 --- a/clang/test/Parser/statements.c +++ b/clang/test/Parser/statements.c @@ -1,4 +1,5 @@ // RUN: %clang_cc1 -fsyntax-only -verify %s -Wno-unreachable-code +// RUN: %clang_cc1 -std=c23 -fsyntax-only -verify %s -Wno-unreachable-code void test1(void) { { ; { ;;}} ;; @@ -77,3 +78,32 @@ int test9(void) { return 4, // expected-error {{expected ';' after return statement}} } + +#if __STDC_VERSION__ >= 202311L +void attr_decl_in_selection_statement(int n) { + if (1) + [[]]; // expected-warning {{ISO C does not allow an attribute list to appear here}} + + if (1) { + + } else + [[]]; // expected-warning {{ISO C does not allow an attribute list to appear here}} + + + switch (n) + [[]]; // expected-warning {{ISO C does not allow an attribute list to appear here}} +} + +void attr_decl_in_iteration_statement(int n) { + int i; + for (i = 0; i < n; ++i) + [[]]; // expected-warning {{ISO C does not allow an attribute list to appear here}} + + while (i > 0) + [[]]; // expected-warning {{ISO C does not allow an attribute list to appear here}} + + do + [[]]; // expected-warning {{ISO C does not allow an attribute list to appear here}} + while (i > 0); +} +#endif // __STDC_VERSION__ >= 202311L diff --git a/clang/test/Sema/c2x-fallthrough.c b/clang/test/Sema/c2x-fallthrough.c index 092d5285f80ba..7d2f25ed5187b 100644 --- a/clang/test/Sema/c2x-fallthrough.c +++ b/clang/test/Sema/c2x-fallthrough.c @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -fsyntax-only -std=c2x -verify %s +// RUN: %clang_cc1 -fsyntax-only -std=c23 -verify %s // This is the latest version of fallthrough that we support. _Static_assert(__has_c_attribute(fallthrough) == 201910L); @@ -16,17 +16,22 @@ void f(int n) { } case 2: for (int n = 0; n != 10; ++n) - [[fallthrough]]; // expected-error {{does not directly precede switch label}} + [[fallthrough]]; // expected-error {{does not directly precede switch label}} \ + // expected-warning {{ISO C does not allow an attribute list to appear here}} case 3: while (1) - [[fallthrough]]; // expected-error {{does not directly precede switch label}} + [[fallthrough]]; // expected-error {{does not directly precede switch label}} \ + // expected-warning {{ISO C does not allow an attribute list to appear here}} case 4: while (0) - [[fallthrough]]; // expected-error {{does not directly precede switch label}} + [[fallthrough]]; // expected-error {{does not directly precede switch label}} \ + // expected-warning {{ISO C does not allow an attribute list to appear here}} case 5: - do [[fallthrough]]; while (1); // expected-error {{does not directly precede switch label}} + do [[fallthrough]]; while (1); // expected-error {{does not directly precede switch label}} \ + // expected-warning {{ISO C does not allow an attribute list to appear here}} case 6: - do [[fallthrough]]; while (0); // expected-error {{does not directly precede switch label}} + do [[fallthrough]]; while (0); // expected-error {{does not directly precede switch label}} \ + // expected-warning {{ISO C does not allow an attribute list to appear here}} case 7: switch (n) { case 0: _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits