Skip to content

[C23][Parser] Diagnostic for attribute declaration where statement is required #146224

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 9 commits into from
Jul 9, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions clang/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -761,6 +761,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 differs from C++, since C++ allows
declaration statements. Clang now emits a warning for these patterns. (#GH141659)

Bug Fixes to Compiler Builtins
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Expand Down
3 changes: 3 additions & 0 deletions clang/include/clang/Basic/DiagnosticParseKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -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<
Expand Down
10 changes: 9 additions & 1 deletion clang/lib/Parse/ParseStmt.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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;

Expand Down
30 changes: 30 additions & 0 deletions clang/test/Parser/statements.c
Original file line number Diff line number Diff line change
@@ -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) {
{ ; { ;;}} ;;
Expand Down Expand Up @@ -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
17 changes: 11 additions & 6 deletions clang/test/Sema/c2x-fallthrough.c
Original file line number Diff line number Diff line change
@@ -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);
Expand All @@ -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:
Expand Down