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

Open
wants to merge 2 commits into
base: main
Choose a base branch
from

Conversation

yronglin
Copy link
Contributor

Fixes: #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:

int main(void) {
    if (1)
        [[]];
}

@llvmbot llvmbot added clang Clang issues not falling into any other category clang:frontend Language frontend issues, e.g. anything involving "Sema" labels Jun 28, 2025
@llvmbot
Copy link
Member

llvmbot commented Jun 28, 2025

@llvm/pr-subscribers-clang

Author: None (yronglin)

Changes

Fixes: #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:

int main(void) {
    if (1)
        [[]];
}

Patch is 37.12 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/146224.diff

8 Files Affected:

  • (modified) clang/docs/ReleaseNotes.rst (+3)
  • (modified) clang/include/clang/Basic/DiagnosticParseKinds.td (+1)
  • (modified) clang/include/clang/Parse/Parser.h (+336-332)
  • (modified) clang/lib/Parse/ParseStmt.cpp (+29-10)
  • (modified) clang/test/Parser/statements.c (+27)
  • (modified) clang/test/Sema/c2x-fallthrough.c (+7-6)
  • (added) clang/test/Sema/c2x-fallthrough2.c (+18)
  • (added) clang/test/Sema/fallthrough.cpp (+75)
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 01f3b7a557a5c..78e20bd8900f8 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -727,6 +727,9 @@ Bug Fixes in This Version
 - Fixed an infinite recursion when checking constexpr destructors. (#GH141789)
 - Fixed a crash when a malformed using declaration appears in a ``constexpr`` function. (#GH144264)
 - Fixed a bug when use unicode character name in macro concatenation. (#GH145240) 
+- 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. Clang now reject this pattern and give a diagnostic. (#GH141659)
 
 Bug Fixes to Compiler Builtins
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/clang/include/clang/Basic/DiagnosticParseKinds.td b/clang/include/clang/Basic/DiagnosticParseKinds.td
index 6c30da376dafb..a8b77e0f4ebdf 100644
--- a/clang/include/clang/Basic/DiagnosticParseKinds.td
+++ b/clang/include/clang/Basic/DiagnosticParseKinds.td
@@ -276,6 +276,7 @@ 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 err_expected_stmt_before_semi : Error<"expected a statement before ';'">;
 def err_extraneous_token_before_semi : Error<"extraneous '%0' before ';'">;
 
 def err_expected_semi_after_method_proto : Error<
diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h
index a47e23ffbd357..7c85bbefe57a8 100644
--- a/clang/include/clang/Parse/Parser.h
+++ b/clang/include/clang/Parse/Parser.h
@@ -7168,13 +7168,15 @@ class Parser : public CodeCompletionHandler {
     AllowStandaloneOpenMPDirectives = 0x2,
     /// This context is at the top level of a GNU statement expression.
     InStmtExpr = 0x4,
+    /// This context is the C99 secondary-block in selection-/iteration-statement.
+    SecondaryBlock = 0x8,
 
     /// The context of a regular substatement.
     SubStmt = 0,
     /// The context of a compound-statement.
     Compound = AllowDeclarationsInC | AllowStandaloneOpenMPDirectives,
 
-    LLVM_MARK_AS_BITMASK_ENUM(InStmtExpr)
+    LLVM_MARK_AS_BITMASK_ENUM(SecondaryBlock)
   };
 
   /// Act on an expression statement that might be the last statement in a
@@ -7246,337 +7248,339 @@ class Parser : public CodeCompletionHandler {
   ParseStatementOrDeclaration(StmtVector &Stmts, ParsedStmtContext StmtCtx,
                               SourceLocation *TrailingElseLoc = nullptr);
 
-  StmtResult ParseStatementOrDeclarationAfterAttributes(
-      StmtVector &Stmts, ParsedStmtContext StmtCtx,
-      SourceLocation *TrailingElseLoc, ParsedAttributes &DeclAttrs,
-      ParsedAttributes &DeclSpecAttrs);
-
-  /// Parse an expression statement.
-  StmtResult ParseExprStatement(ParsedStmtContext StmtCtx);
-
-  /// ParseLabeledStatement - We have an identifier and a ':' after it.
-  ///
-  /// \verbatim
-  ///       label:
-  ///         identifier ':'
-  /// [GNU]   identifier ':' attributes[opt]
-  ///
-  ///       labeled-statement:
-  ///         label statement
-  /// \endverbatim
-  ///
-  StmtResult ParseLabeledStatement(ParsedAttributes &Attrs,
-                                   ParsedStmtContext StmtCtx);
-
-  /// ParseCaseStatement
-  /// \verbatim
-  ///       labeled-statement:
-  ///         'case' constant-expression ':' statement
-  /// [GNU]   'case' constant-expression '...' constant-expression ':' statement
-  /// \endverbatim
-  ///
-  StmtResult ParseCaseStatement(ParsedStmtContext StmtCtx,
-                                bool MissingCase = false,
-                                ExprResult Expr = ExprResult());
-
-  /// ParseDefaultStatement
-  /// \verbatim
-  ///       labeled-statement:
-  ///         'default' ':' statement
-  /// \endverbatim
-  /// Note that this does not parse the 'statement' at the end.
-  ///
-  StmtResult ParseDefaultStatement(ParsedStmtContext StmtCtx);
-
-  StmtResult ParseCompoundStatement(bool isStmtExpr = false);
-
-  /// ParseCompoundStatement - Parse a "{}" block.
-  ///
-  /// \verbatim
-  ///       compound-statement: [C99 6.8.2]
-  ///         { block-item-list[opt] }
-  /// [GNU]   { label-declarations block-item-list } [TODO]
-  ///
-  ///       block-item-list:
-  ///         block-item
-  ///         block-item-list block-item
-  ///
-  ///       block-item:
-  ///         declaration
-  /// [GNU]   '__extension__' declaration
-  ///         statement
-  ///
-  /// [GNU] label-declarations:
-  /// [GNU]   label-declaration
-  /// [GNU]   label-declarations label-declaration
-  ///
-  /// [GNU] label-declaration:
-  /// [GNU]   '__label__' identifier-list ';'
-  /// \endverbatim
-  ///
-  StmtResult ParseCompoundStatement(bool isStmtExpr, unsigned ScopeFlags);
-
-  /// Parse any pragmas at the start of the compound expression. We handle these
-  /// separately since some pragmas (FP_CONTRACT) must appear before any C
-  /// statement in the compound, but may be intermingled with other pragmas.
-  void ParseCompoundStatementLeadingPragmas();
-
-  void DiagnoseLabelAtEndOfCompoundStatement();
-
-  /// Consume any extra semi-colons resulting in null statements,
-  /// returning true if any tok::semi were consumed.
-  bool ConsumeNullStmt(StmtVector &Stmts);
-
-  /// ParseCompoundStatementBody - Parse a sequence of statements optionally
-  /// followed by a label and invoke the ActOnCompoundStmt action.  This expects
-  /// the '{' to be the current token, and consume the '}' at the end of the
-  /// block.  It does not manipulate the scope stack.
-  StmtResult ParseCompoundStatementBody(bool isStmtExpr = false);
-
-  /// ParseParenExprOrCondition:
-  /// \verbatim
-  /// [C  ]     '(' expression ')'
-  /// [C++]     '(' condition ')'
-  /// [C++1z]   '(' init-statement[opt] condition ')'
-  /// \endverbatim
-  ///
-  /// This function parses and performs error recovery on the specified
-  /// condition or expression (depending on whether we're in C++ or C mode).
-  /// This function goes out of its way to recover well.  It returns true if
-  /// there was a parser error (the right paren couldn't be found), which
-  /// indicates that the caller should try to recover harder.  It returns false
-  /// if the condition is successfully parsed.  Note that a successful parse can
-  /// still have semantic errors in the condition. Additionally, it will assign
-  /// the location of the outer-most '(' and ')', to LParenLoc and RParenLoc,
-  /// respectively.
-  bool ParseParenExprOrCondition(StmtResult *InitStmt,
-                                 Sema::ConditionResult &CondResult,
-                                 SourceLocation Loc, Sema::ConditionKind CK,
-                                 SourceLocation &LParenLoc,
-                                 SourceLocation &RParenLoc);
-
-  /// ParseIfStatement
-  /// \verbatim
-  ///       if-statement: [C99 6.8.4.1]
-  ///         'if' '(' expression ')' statement
-  ///         'if' '(' expression ')' statement 'else' statement
-  /// [C++]   'if' '(' condition ')' statement
-  /// [C++]   'if' '(' condition ')' statement 'else' statement
-  /// [C++23] 'if' '!' [opt] consteval compound-statement
-  /// [C++23] 'if' '!' [opt] consteval compound-statement 'else' statement
-  /// \endverbatim
-  ///
-  StmtResult ParseIfStatement(SourceLocation *TrailingElseLoc);
-
-  /// ParseSwitchStatement
-  /// \verbatim
-  ///       switch-statement:
-  ///         'switch' '(' expression ')' statement
-  /// [C++]   'switch' '(' condition ')' statement
-  /// \endverbatim
-  StmtResult ParseSwitchStatement(SourceLocation *TrailingElseLoc);
-
-  /// ParseWhileStatement
-  /// \verbatim
-  ///       while-statement: [C99 6.8.5.1]
-  ///         'while' '(' expression ')' statement
-  /// [C++]   'while' '(' condition ')' statement
-  /// \endverbatim
-  StmtResult ParseWhileStatement(SourceLocation *TrailingElseLoc);
-
-  /// ParseDoStatement
-  /// \verbatim
-  ///       do-statement: [C99 6.8.5.2]
-  ///         'do' statement 'while' '(' expression ')' ';'
-  /// \endverbatim
-  /// Note: this lets the caller parse the end ';'.
-  StmtResult ParseDoStatement();
-
-  /// ParseForStatement
-  /// \verbatim
-  ///       for-statement: [C99 6.8.5.3]
-  ///         'for' '(' expr[opt] ';' expr[opt] ';' expr[opt] ')' statement
-  ///         'for' '(' declaration expr[opt] ';' expr[opt] ')' statement
-  /// [C++]   'for' '(' for-init-statement condition[opt] ';' expression[opt] ')'
-  /// [C++]       statement
-  /// [C++0x] 'for'
-  ///             'co_await'[opt]    [Coroutines]
-  ///             '(' for-range-declaration ':' for-range-initializer ')'
-  ///             statement
-  /// [OBJC2] 'for' '(' declaration 'in' expr ')' statement
-  /// [OBJC2] 'for' '(' expr 'in' expr ')' statement
-  ///
-  /// [C++] for-init-statement:
-  /// [C++]   expression-statement
-  /// [C++]   simple-declaration
-  /// [C++23] alias-declaration
-  ///
-  /// [C++0x] for-range-declaration:
-  /// [C++0x]   attribute-specifier-seq[opt] type-specifier-seq declarator
-  /// [C++0x] for-range-initializer:
-  /// [C++0x]   expression
-  /// [C++0x]   braced-init-list            [TODO]
-  /// \endverbatim
-  StmtResult ParseForStatement(SourceLocation *TrailingElseLoc);
-
-  /// ParseGotoStatement
-  /// \verbatim
-  ///       jump-statement:
-  ///         'goto' identifier ';'
-  /// [GNU]   'goto' '*' expression ';'
-  /// \endverbatim
-  ///
-  /// Note: this lets the caller parse the end ';'.
-  ///
-  StmtResult ParseGotoStatement();
-
-  /// ParseContinueStatement
-  /// \verbatim
-  ///       jump-statement:
-  ///         'continue' ';'
-  /// \endverbatim
-  ///
-  /// Note: this lets the caller parse the end ';'.
-  ///
-  StmtResult ParseContinueStatement();
-
-  /// ParseBreakStatement
-  /// \verbatim
-  ///       jump-statement:
-  ///         'break' ';'
-  /// \endverbatim
-  ///
-  /// Note: this lets the caller parse the end ';'.
-  ///
-  StmtResult ParseBreakStatement();
-
-  /// ParseReturnStatement
-  /// \verbatim
-  ///       jump-statement:
-  ///         'return' expression[opt] ';'
-  ///         'return' braced-init-list ';'
-  ///         'co_return' expression[opt] ';'
-  ///         'co_return' braced-init-list ';'
-  /// \endverbatim
-  StmtResult ParseReturnStatement();
-
-  StmtResult ParsePragmaLoopHint(StmtVector &Stmts, ParsedStmtContext StmtCtx,
-                                 SourceLocation *TrailingElseLoc,
-                                 ParsedAttributes &Attrs);
-
-  void ParseMicrosoftIfExistsStatement(StmtVector &Stmts);
-
-  //===--------------------------------------------------------------------===//
-  // C++ 6: Statements and Blocks
-
-  /// ParseCXXTryBlock - Parse a C++ try-block.
-  ///
-  /// \verbatim
-  ///       try-block:
-  ///         'try' compound-statement handler-seq
-  /// \endverbatim
-  ///
-  StmtResult ParseCXXTryBlock();
-
-  /// ParseCXXTryBlockCommon - Parse the common part of try-block and
-  /// function-try-block.
-  ///
-  /// \verbatim
-  ///       try-block:
-  ///         'try' compound-statement handler-seq
-  ///
-  ///       function-try-block:
-  ///         'try' ctor-initializer[opt] compound-statement handler-seq
-  ///
-  ///       handler-seq:
-  ///         handler handler-seq[opt]
-  ///
-  ///       [Borland] try-block:
-  ///         'try' compound-statement seh-except-block
-  ///         'try' compound-statement seh-finally-block
-  /// \endverbatim
-  ///
-  StmtResult ParseCXXTryBlockCommon(SourceLocation TryLoc, bool FnTry = false);
-
-  /// ParseCXXCatchBlock - Parse a C++ catch block, called handler in the
-  /// standard
-  ///
-  /// \verbatim
-  ///   handler:
-  ///     'catch' '(' exception-declaration ')' compound-statement
-  ///
-  ///   exception-declaration:
-  ///     attribute-specifier-seq[opt] type-specifier-seq declarator
-  ///     attribute-specifier-seq[opt] type-specifier-seq abstract-declarator[opt]
-  ///     '...'
-  /// \endverbatim
-  ///
-  StmtResult ParseCXXCatchBlock(bool FnCatch = false);
-
-  //===--------------------------------------------------------------------===//
-  // MS: SEH Statements and Blocks
-
-  /// ParseSEHTryBlockCommon
-  ///
-  /// \verbatim
-  /// seh-try-block:
-  ///   '__try' compound-statement seh-handler
-  ///
-  /// seh-handler:
-  ///   seh-except-block
-  ///   seh-finally-block
-  /// \endverbatim
-  ///
-  StmtResult ParseSEHTryBlock();
-
-  /// ParseSEHExceptBlock - Handle __except
-  ///
-  /// \verbatim
-  /// seh-except-block:
-  ///   '__except' '(' seh-filter-expression ')' compound-statement
-  /// \endverbatim
-  ///
-  StmtResult ParseSEHExceptBlock(SourceLocation Loc);
-
-  /// ParseSEHFinallyBlock - Handle __finally
-  ///
-  /// \verbatim
-  /// seh-finally-block:
-  ///   '__finally' compound-statement
-  /// \endverbatim
-  ///
-  StmtResult ParseSEHFinallyBlock(SourceLocation Loc);
-
-  StmtResult ParseSEHLeaveStatement();
-
-  Decl *ParseFunctionStatementBody(Decl *Decl, ParseScope &BodyScope);
-
-  /// ParseFunctionTryBlock - Parse a C++ function-try-block.
-  ///
-  /// \verbatim
-  ///       function-try-block:
-  ///         'try' ctor-initializer[opt] compound-statement handler-seq
-  /// \endverbatim
-  ///
-  Decl *ParseFunctionTryBlock(Decl *Decl, ParseScope &BodyScope);
-
-  /// When in code-completion, skip parsing of the function/method body
-  /// unless the body contains the code-completion point.
-  ///
-  /// \returns true if the function body was skipped.
-  bool trySkippingFunctionBody();
-
-  /// isDeclarationStatement - Disambiguates between a declaration or an
-  /// expression statement, when parsing function bodies.
-  ///
-  /// \param DisambiguatingWithExpression - True to indicate that the purpose of
-  /// this check is to disambiguate between an expression and a declaration.
-  /// Returns true for declaration, false for expression.
-  bool isDeclarationStatement(bool DisambiguatingWithExpression = false) {
-    if (getLangOpts().CPlusPlus)
-      return isCXXDeclarationStatement(DisambiguatingWithExpression);
-    return isDeclarationSpecifier(ImplicitTypenameContext::No, true);
-  }
+    StmtResult ParseStatementOrDeclarationAfterAttributes(
+        StmtVector &Stmts, ParsedStmtContext StmtCtx,
+        SourceLocation *TrailingElseLoc, ParsedAttributes &DeclAttrs,
+        ParsedAttributes &DeclSpecAttrs);
+
+    /// Parse an expression statement.
+    StmtResult ParseExprStatement(ParsedStmtContext StmtCtx);
+
+    /// ParseLabeledStatement - We have an identifier and a ':' after it.
+    ///
+    /// \verbatim
+    ///       label:
+    ///         identifier ':'
+    /// [GNU]   identifier ':' attributes[opt]
+    ///
+    ///       labeled-statement:
+    ///         label statement
+    /// \endverbatim
+    ///
+    StmtResult ParseLabeledStatement(ParsedAttributes &Attrs,
+                                     ParsedStmtContext StmtCtx);
+
+    /// ParseCaseStatement
+    /// \verbatim
+    ///       labeled-statement:
+    ///         'case' constant-expression ':' statement
+    /// [GNU]   'case' constant-expression '...' constant-expression ':'
+    /// statement
+    /// \endverbatim
+    ///
+    StmtResult ParseCaseStatement(ParsedStmtContext StmtCtx,
+                                  bool MissingCase = false,
+                                  ExprResult Expr = ExprResult());
+
+    /// ParseDefaultStatement
+    /// \verbatim
+    ///       labeled-statement:
+    ///         'default' ':' statement
+    /// \endverbatim
+    /// Note that this does not parse the 'statement' at the end.
+    ///
+    StmtResult ParseDefaultStatement(ParsedStmtContext StmtCtx);
+
+    StmtResult ParseCompoundStatement(bool isStmtExpr = false);
+
+    /// ParseCompoundStatement - Parse a "{}" block.
+    ///
+    /// \verbatim
+    ///       compound-statement: [C99 6.8.2]
+    ///         { block-item-list[opt] }
+    /// [GNU]   { label-declarations block-item-list } [TODO]
+    ///
+    ///       block-item-list:
+    ///         block-item
+    ///         block-item-list block-item
+    ///
+    ///       block-item:
+    ///         declaration
+    /// [GNU]   '__extension__' declaration
+    ///         statement
+    ///
+    /// [GNU] label-declarations:
+    /// [GNU]   label-declaration
+    /// [GNU]   label-declarations label-declaration
+    ///
+    /// [GNU] label-declaration:
+    /// [GNU]   '__label__' identifier-list ';'
+    /// \endverbatim
+    ///
+    StmtResult ParseCompoundStatement(bool isStmtExpr, unsigned ScopeFlags);
+
+    /// Parse any pragmas at the start of the compound expression. We handle
+    /// these separately since some pragmas (FP_CONTRACT) must appear before any
+    /// C statement in the compound, but may be intermingled with other pragmas.
+    void ParseCompoundStatementLeadingPragmas();
+
+    void DiagnoseLabelAtEndOfCompoundStatement();
+
+    /// Consume any extra semi-colons resulting in null statements,
+    /// returning true if any tok::semi were consumed.
+    bool ConsumeNullStmt(StmtVector &Stmts);
+
+    /// ParseCompoundStatementBody - Parse a sequence of statements optionally
+    /// followed by a label and invoke the ActOnCompoundStmt action.  This
+    /// expects the '{' to be the current token, and consume the '}' at the end
+    /// of the block.  It does not manipulate the scope stack.
+    StmtResult ParseCompoundStatementBody(bool isStmtExpr = false);
+
+    /// ParseParenExprOrCondition:
+    /// \verbatim
+    /// [C  ]     '(' expression ')'
+    /// [C++]     '(' condition ')'
+    /// [C++1z]   '(' init-statement[opt] condition ')'
+    /// \endverbatim
+    ///
+    /// This function parses and performs error recovery on the specified
+    /// condition or expression (depending on whether we're in C++ or C mode).
+    /// This function goes out of its way to recover well.  It returns true if
+    /// there was a parser error (the right paren couldn't be found), which
+    /// indicates that the caller should try to recover harder.  It returns
+    /// false if the condition is successfully parsed.  Note that a successful
+    /// parse can still have semantic errors in the condition. Additionally, it
+    /// will assign the location of the outer-most '(' and ')', to LParenLoc and
+    /// RParenLoc, respectively.
+    bool ParseParenExprOrCondition(StmtResult *InitStmt,
+                                   Sema::ConditionResult &CondResult,
+                                   SourceLocation Loc, Sema::ConditionKind CK,
+                                   SourceLocation &LParenLoc,
+                                   SourceLocation &RParenLoc);
+
+    /// ParseIfStatement
+    /// \verbatim
+    ///       if-statement: [C99 6.8.4.1]
+    ///         'if' '(' expression ')' statement
+    ///         'if' '(' expression ')' statement 'else' statement
+    /// [C++]   'if' '(' condition ')' statement
+    /// [C++]   'if' '(' condition ')' statement 'else' statement
+    /// [C++23] 'if' '!' [opt] consteval compound-statement
+    /// [C++23] 'if' '!' [opt] consteval compound-statement 'else' statement
+    /// \endverbatim
+    ///
+    StmtResult ParseIfStatement(SourceLocation *TrailingElseLoc);
+
+    /// ParseSwitchStatement
+    /// \verbatim
+    ///       switch-statement:
+    ///         'switch' '(' expression ')' statement
+    /// [C++]   'switch' '(' condition ')' statement
+    /// \endverbatim
+    StmtResult ParseSwitchStatement(SourceLocation *TrailingElseLoc);
+
+    /// ParseWhileStatement
+    /// \verbatim
+    ///       while-statement: [C99 6.8.5.1]
+    ///         'while' '(' expression ')' statement
+    /// [C++]   'while' '(' condition ')' statement
+    /// \endverbatim
+    StmtResult ParseWhileStatement(SourceLocation *TrailingElseLoc);
+
+    /// ParseDoStatement
+    /// \verbatim
+    ///       do-statement: [C99 6.8.5.2]
+    ///         'do' statement 'while' '(' expression ')' ';'
+    /// \endverbatim
+    /// Note: this lets the caller parse the end ';'.
+    StmtResult ParseDoStatement();
+
+    /// ParseForStatement
+    /// \verbatim
+    ///       for-statement: [C99 6.8.5.3]
+    ///         'for' '(' expr[opt] ';' e...
[truncated]

Copy link

github-actions bot commented Jun 28, 2025

⚠️ C/C++ code formatter, clang-format found issues in your code. ⚠️

You can test this locally with the following command:
git-clang-format --diff HEAD~1 HEAD --extensions h,c,cpp -- clang/include/clang/Parse/Parser.h clang/lib/Parse/ParseStmt.cpp clang/test/Parser/statements.c clang/test/Sema/c2x-fallthrough.c
View the diff from clang-format here.
diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h
index cca4f14a2..d4dba1d46 100644
--- a/clang/include/clang/Parse/Parser.h
+++ b/clang/include/clang/Parse/Parser.h
@@ -7160,426 +7160,428 @@ public:
   private:
 
   /// Flags describing a context in which we're parsing a statement.
-  enum class ParsedStmtContext {
-    /// This context permits declarations in language modes where declarations
-    /// are not statements.
-    AllowDeclarationsInC = 0x1,
-    /// This context permits standalone OpenMP directives.
-    AllowStandaloneOpenMPDirectives = 0x2,
-    /// This context is at the top level of a GNU statement expression.
-    InStmtExpr = 0x4,
-    /// This context is the C99 secondary-block in selection or iteration
-    /// statement.
-    SecondaryBlockInC = 0x8,
-
-    /// The context of a regular substatement.
-    SubStmt = 0,
-    /// The context of a compound-statement.
-    Compound = AllowDeclarationsInC | AllowStandaloneOpenMPDirectives,
-
-    LLVM_MARK_AS_BITMASK_ENUM(SecondaryBlockInC)
-  };
-
-  /// Act on an expression statement that might be the last statement in a
-  /// GNU statement expression. Checks whether we are actually at the end of
-  /// a statement expression and builds a suitable expression statement.
-  StmtResult handleExprStmt(ExprResult E, ParsedStmtContext StmtCtx);
-
-  //===--------------------------------------------------------------------===//
-  // C99 6.8: Statements and Blocks.
-
-  /// Parse a standalone statement (for instance, as the body of an 'if',
-  /// 'while', or 'for').
-  StmtResult
-  ParseStatement(SourceLocation *TrailingElseLoc = nullptr,
-                 ParsedStmtContext StmtCtx = ParsedStmtContext::SubStmt);
-
-  /// ParseStatementOrDeclaration - Read 'statement' or 'declaration'.
-  /// \verbatim
-  ///       StatementOrDeclaration:
-  ///         statement
-  ///         declaration
-  ///
-  ///       statement:
-  ///         labeled-statement
-  ///         compound-statement
-  ///         expression-statement
-  ///         selection-statement
-  ///         iteration-statement
-  ///         jump-statement
-  /// [C++]   declaration-statement
-  /// [C++]   try-block
-  /// [MS]    seh-try-block
-  /// [OBC]   objc-throw-statement
-  /// [OBC]   objc-try-catch-statement
-  /// [OBC]   objc-synchronized-statement
-  /// [GNU]   asm-statement
-  /// [OMP]   openmp-construct             [TODO]
-  ///
-  ///       labeled-statement:
-  ///         identifier ':' statement
-  ///         'case' constant-expression ':' statement
-  ///         'default' ':' statement
-  ///
-  ///       selection-statement:
-  ///         if-statement
-  ///         switch-statement
-  ///
-  ///       iteration-statement:
-  ///         while-statement
-  ///         do-statement
-  ///         for-statement
-  ///
-  ///       expression-statement:
-  ///         expression[opt] ';'
-  ///
-  ///       jump-statement:
-  ///         'goto' identifier ';'
-  ///         'continue' ';'
-  ///         'break' ';'
-  ///         'return' expression[opt] ';'
-  /// [GNU]   'goto' '*' expression ';'
-  ///
-  /// [OBC] objc-throw-statement:
-  /// [OBC]   '@' 'throw' expression ';'
-  /// [OBC]   '@' 'throw' ';'
-  /// \endverbatim
-  ///
-  StmtResult
-  ParseStatementOrDeclaration(StmtVector &Stmts, ParsedStmtContext StmtCtx,
-                              SourceLocation *TrailingElseLoc = nullptr);
-
-  StmtResult ParseStatementOrDeclarationAfterAttributes(
-      StmtVector &Stmts, ParsedStmtContext StmtCtx,
-      SourceLocation *TrailingElseLoc, ParsedAttributes &DeclAttrs,
-      ParsedAttributes &DeclSpecAttrs);
-
-  /// Parse an expression statement.
-  StmtResult ParseExprStatement(ParsedStmtContext StmtCtx);
-
-  /// ParseLabeledStatement - We have an identifier and a ':' after it.
-  ///
-  /// \verbatim
-  ///       label:
-  ///         identifier ':'
-  /// [GNU]   identifier ':' attributes[opt]
-  ///
-  ///       labeled-statement:
-  ///         label statement
-  /// \endverbatim
-  ///
-  StmtResult ParseLabeledStatement(ParsedAttributes &Attrs,
-                                   ParsedStmtContext StmtCtx);
-
-  /// ParseCaseStatement
-  /// \verbatim
-  ///       labeled-statement:
-  ///         'case' constant-expression ':' statement
-  /// [GNU]   'case' constant-expression '...' constant-expression ':' statement
-  /// \endverbatim
-  ///
-  StmtResult ParseCaseStatement(ParsedStmtContext StmtCtx,
-                                bool MissingCase = false,
-                                ExprResult Expr = ExprResult());
-
-  /// ParseDefaultStatement
-  /// \verbatim
-  ///       labeled-statement:
-  ///         'default' ':' statement
-  /// \endverbatim
-  /// Note that this does not parse the 'statement' at the end.
-  ///
-  StmtResult ParseDefaultStatement(ParsedStmtContext StmtCtx);
-
-  StmtResult ParseCompoundStatement(bool isStmtExpr = false);
-
-  /// ParseCompoundStatement - Parse a "{}" block.
-  ///
-  /// \verbatim
-  ///       compound-statement: [C99 6.8.2]
-  ///         { block-item-list[opt] }
-  /// [GNU]   { label-declarations block-item-list } [TODO]
-  ///
-  ///       block-item-list:
-  ///         block-item
-  ///         block-item-list block-item
-  ///
-  ///       block-item:
-  ///         declaration
-  /// [GNU]   '__extension__' declaration
-  ///         statement
-  ///
-  /// [GNU] label-declarations:
-  /// [GNU]   label-declaration
-  /// [GNU]   label-declarations label-declaration
-  ///
-  /// [GNU] label-declaration:
-  /// [GNU]   '__label__' identifier-list ';'
-  /// \endverbatim
-  ///
-  StmtResult ParseCompoundStatement(bool isStmtExpr, unsigned ScopeFlags);
-
-  /// Parse any pragmas at the start of the compound expression. We handle these
-  /// separately since some pragmas (FP_CONTRACT) must appear before any C
-  /// statement in the compound, but may be intermingled with other pragmas.
-  void ParseCompoundStatementLeadingPragmas();
-
-  void DiagnoseLabelAtEndOfCompoundStatement();
-
-  /// Consume any extra semi-colons resulting in null statements,
-  /// returning true if any tok::semi were consumed.
-  bool ConsumeNullStmt(StmtVector &Stmts);
-
-  /// ParseCompoundStatementBody - Parse a sequence of statements optionally
-  /// followed by a label and invoke the ActOnCompoundStmt action.  This expects
-  /// the '{' to be the current token, and consume the '}' at the end of the
-  /// block.  It does not manipulate the scope stack.
-  StmtResult ParseCompoundStatementBody(bool isStmtExpr = false);
-
-  /// ParseParenExprOrCondition:
-  /// \verbatim
-  /// [C  ]     '(' expression ')'
-  /// [C++]     '(' condition ')'
-  /// [C++1z]   '(' init-statement[opt] condition ')'
-  /// \endverbatim
-  ///
-  /// This function parses and performs error recovery on the specified
-  /// condition or expression (depending on whether we're in C++ or C mode).
-  /// This function goes out of its way to recover well.  It returns true if
-  /// there was a parser error (the right paren couldn't be found), which
-  /// indicates that the caller should try to recover harder.  It returns false
-  /// if the condition is successfully parsed.  Note that a successful parse can
-  /// still have semantic errors in the condition. Additionally, it will assign
-  /// the location of the outer-most '(' and ')', to LParenLoc and RParenLoc,
-  /// respectively.
-  bool ParseParenExprOrCondition(StmtResult *InitStmt,
-                                 Sema::ConditionResult &CondResult,
-                                 SourceLocation Loc, Sema::ConditionKind CK,
-                                 SourceLocation &LParenLoc,
-                                 SourceLocation &RParenLoc);
-
-  /// ParseIfStatement
-  /// \verbatim
-  ///       if-statement: [C99 6.8.4.1]
-  ///         'if' '(' expression ')' statement
-  ///         'if' '(' expression ')' statement 'else' statement
-  /// [C++]   'if' '(' condition ')' statement
-  /// [C++]   'if' '(' condition ')' statement 'else' statement
-  /// [C++23] 'if' '!' [opt] consteval compound-statement
-  /// [C++23] 'if' '!' [opt] consteval compound-statement 'else' statement
-  /// \endverbatim
-  ///
-  StmtResult ParseIfStatement(SourceLocation *TrailingElseLoc);
-
-  /// ParseSwitchStatement
-  /// \verbatim
-  ///       switch-statement:
-  ///         'switch' '(' expression ')' statement
-  /// [C++]   'switch' '(' condition ')' statement
-  /// \endverbatim
-  StmtResult ParseSwitchStatement(SourceLocation *TrailingElseLoc);
-
-  /// ParseWhileStatement
-  /// \verbatim
-  ///       while-statement: [C99 6.8.5.1]
-  ///         'while' '(' expression ')' statement
-  /// [C++]   'while' '(' condition ')' statement
-  /// \endverbatim
-  StmtResult ParseWhileStatement(SourceLocation *TrailingElseLoc);
-
-  /// ParseDoStatement
-  /// \verbatim
-  ///       do-statement: [C99 6.8.5.2]
-  ///         'do' statement 'while' '(' expression ')' ';'
-  /// \endverbatim
-  /// Note: this lets the caller parse the end ';'.
-  StmtResult ParseDoStatement();
-
-  /// ParseForStatement
-  /// \verbatim
-  ///       for-statement: [C99 6.8.5.3]
-  ///         'for' '(' expr[opt] ';' expr[opt] ';' expr[opt] ')' statement
-  ///         'for' '(' declaration expr[opt] ';' expr[opt] ')' statement
-  /// [C++]   'for' '(' for-init-statement condition[opt] ';' expression[opt] ')'
-  /// [C++]       statement
-  /// [C++0x] 'for'
-  ///             'co_await'[opt]    [Coroutines]
-  ///             '(' for-range-declaration ':' for-range-initializer ')'
-  ///             statement
-  /// [OBJC2] 'for' '(' declaration 'in' expr ')' statement
-  /// [OBJC2] 'for' '(' expr 'in' expr ')' statement
-  ///
-  /// [C++] for-init-statement:
-  /// [C++]   expression-statement
-  /// [C++]   simple-declaration
-  /// [C++23] alias-declaration
-  ///
-  /// [C++0x] for-range-declaration:
-  /// [C++0x]   attribute-specifier-seq[opt] type-specifier-seq declarator
-  /// [C++0x] for-range-initializer:
-  /// [C++0x]   expression
-  /// [C++0x]   braced-init-list            [TODO]
-  /// \endverbatim
-  StmtResult ParseForStatement(SourceLocation *TrailingElseLoc);
-
-  /// ParseGotoStatement
-  /// \verbatim
-  ///       jump-statement:
-  ///         'goto' identifier ';'
-  /// [GNU]   'goto' '*' expression ';'
-  /// \endverbatim
-  ///
-  /// Note: this lets the caller parse the end ';'.
-  ///
-  StmtResult ParseGotoStatement();
-
-  /// ParseContinueStatement
-  /// \verbatim
-  ///       jump-statement:
-  ///         'continue' ';'
-  /// \endverbatim
-  ///
-  /// Note: this lets the caller parse the end ';'.
-  ///
-  StmtResult ParseContinueStatement();
-
-  /// ParseBreakStatement
-  /// \verbatim
-  ///       jump-statement:
-  ///         'break' ';'
-  /// \endverbatim
-  ///
-  /// Note: this lets the caller parse the end ';'.
-  ///
-  StmtResult ParseBreakStatement();
-
-  /// ParseReturnStatement
-  /// \verbatim
-  ///       jump-statement:
-  ///         'return' expression[opt] ';'
-  ///         'return' braced-init-list ';'
-  ///         'co_return' expression[opt] ';'
-  ///         'co_return' braced-init-list ';'
-  /// \endverbatim
-  StmtResult ParseReturnStatement();
-
-  StmtResult ParsePragmaLoopHint(StmtVector &Stmts, ParsedStmtContext StmtCtx,
-                                 SourceLocation *TrailingElseLoc,
-                                 ParsedAttributes &Attrs);
-
-  void ParseMicrosoftIfExistsStatement(StmtVector &Stmts);
-
-  //===--------------------------------------------------------------------===//
-  // C++ 6: Statements and Blocks
-
-  /// ParseCXXTryBlock - Parse a C++ try-block.
-  ///
-  /// \verbatim
-  ///       try-block:
-  ///         'try' compound-statement handler-seq
-  /// \endverbatim
-  ///
-  StmtResult ParseCXXTryBlock();
-
-  /// ParseCXXTryBlockCommon - Parse the common part of try-block and
-  /// function-try-block.
-  ///
-  /// \verbatim
-  ///       try-block:
-  ///         'try' compound-statement handler-seq
-  ///
-  ///       function-try-block:
-  ///         'try' ctor-initializer[opt] compound-statement handler-seq
-  ///
-  ///       handler-seq:
-  ///         handler handler-seq[opt]
-  ///
-  ///       [Borland] try-block:
-  ///         'try' compound-statement seh-except-block
-  ///         'try' compound-statement seh-finally-block
-  /// \endverbatim
-  ///
-  StmtResult ParseCXXTryBlockCommon(SourceLocation TryLoc, bool FnTry = false);
-
-  /// ParseCXXCatchBlock - Parse a C++ catch block, called handler in the
-  /// standard
-  ///
-  /// \verbatim
-  ///   handler:
-  ///     'catch' '(' exception-declaration ')' compound-statement
-  ///
-  ///   exception-declaration:
-  ///     attribute-specifier-seq[opt] type-specifier-seq declarator
-  ///     attribute-specifier-seq[opt] type-specifier-seq abstract-declarator[opt]
-  ///     '...'
-  /// \endverbatim
-  ///
-  StmtResult ParseCXXCatchBlock(bool FnCatch = false);
-
-  //===--------------------------------------------------------------------===//
-  // MS: SEH Statements and Blocks
-
-  /// ParseSEHTryBlockCommon
-  ///
-  /// \verbatim
-  /// seh-try-block:
-  ///   '__try' compound-statement seh-handler
-  ///
-  /// seh-handler:
-  ///   seh-except-block
-  ///   seh-finally-block
-  /// \endverbatim
-  ///
-  StmtResult ParseSEHTryBlock();
-
-  /// ParseSEHExceptBlock - Handle __except
-  ///
-  /// \verbatim
-  /// seh-except-block:
-  ///   '__except' '(' seh-filter-expression ')' compound-statement
-  /// \endverbatim
-  ///
-  StmtResult ParseSEHExceptBlock(SourceLocation Loc);
-
-  /// ParseSEHFinallyBlock - Handle __finally
-  ///
-  /// \verbatim
-  /// seh-finally-block:
-  ///   '__finally' compound-statement
-  /// \endverbatim
-  ///
-  StmtResult ParseSEHFinallyBlock(SourceLocation Loc);
-
-  StmtResult ParseSEHLeaveStatement();
-
-  Decl *ParseFunctionStatementBody(Decl *Decl, ParseScope &BodyScope);
-
-  /// ParseFunctionTryBlock - Parse a C++ function-try-block.
-  ///
-  /// \verbatim
-  ///       function-try-block:
-  ///         'try' ctor-initializer[opt] compound-statement handler-seq
-  /// \endverbatim
-  ///
-  Decl *ParseFunctionTryBlock(Decl *Decl, ParseScope &BodyScope);
-
-  /// When in code-completion, skip parsing of the function/method body
-  /// unless the body contains the code-completion point.
-  ///
-  /// \returns true if the function body was skipped.
-  bool trySkippingFunctionBody();
+    enum class ParsedStmtContext {
+      /// This context permits declarations in language modes where declarations
+      /// are not statements.
+      AllowDeclarationsInC = 0x1,
+      /// This context permits standalone OpenMP directives.
+      AllowStandaloneOpenMPDirectives = 0x2,
+      /// This context is at the top level of a GNU statement expression.
+      InStmtExpr = 0x4,
+      /// This context is the C99 secondary-block in selection or iteration
+      /// statement.
+      SecondaryBlockInC = 0x8,
+
+      /// The context of a regular substatement.
+      SubStmt = 0,
+      /// The context of a compound-statement.
+      Compound = AllowDeclarationsInC | AllowStandaloneOpenMPDirectives,
+
+      LLVM_MARK_AS_BITMASK_ENUM(SecondaryBlockInC)
+    };
 
-  /// isDeclarationStatement - Disambiguates between a declaration or an
-  /// expression statement, when parsing function bodies.
-  ///
-  /// \param DisambiguatingWithExpression - True to indicate that the purpose of
-  /// this check is to disambiguate between an expression and a declaration.
-  /// Returns true for declaration, false for expression.
-  bool isDeclarationStatement(bool DisambiguatingWithExpression = false) {
-    if (getLangOpts().CPlusPlus)
-      return isCXXDeclarationStatement(DisambiguatingWithExpression);
-    return isDeclarationSpecifier(ImplicitTypenameContext::No, true);
-  }
+    /// Act on an expression statement that might be the last statement in a
+    /// GNU statement expression. Checks whether we are actually at the end of
+    /// a statement expression and builds a suitable expression statement.
+    StmtResult handleExprStmt(ExprResult E, ParsedStmtContext StmtCtx);
+
+    //===--------------------------------------------------------------------===//
+    // C99 6.8: Statements and Blocks.
+
+    /// Parse a standalone statement (for instance, as the body of an 'if',
+    /// 'while', or 'for').
+    StmtResult
+    ParseStatement(SourceLocation *TrailingElseLoc = nullptr,
+                   ParsedStmtContext StmtCtx = ParsedStmtContext::SubStmt);
+
+    /// ParseStatementOrDeclaration - Read 'statement' or 'declaration'.
+    /// \verbatim
+    ///       StatementOrDeclaration:
+    ///         statement
+    ///         declaration
+    ///
+    ///       statement:
+    ///         labeled-statement
+    ///         compound-statement
+    ///         expression-statement
+    ///         selection-statement
+    ///         iteration-statement
+    ///         jump-statement
+    /// [C++]   declaration-statement
+    /// [C++]   try-block
+    /// [MS]    seh-try-block
+    /// [OBC]   objc-throw-statement
+    /// [OBC]   objc-try-catch-statement
+    /// [OBC]   objc-synchronized-statement
+    /// [GNU]   asm-statement
+    /// [OMP]   openmp-construct             [TODO]
+    ///
+    ///       labeled-statement:
+    ///         identifier ':' statement
+    ///         'case' constant-expression ':' statement
+    ///         'default' ':' statement
+    ///
+    ///       selection-statement:
+    ///         if-statement
+    ///         switch-statement
+    ///
+    ///       iteration-statement:
+    ///         while-statement
+    ///         do-statement
+    ///         for-statement
+    ///
+    ///       expression-statement:
+    ///         expression[opt] ';'
+    ///
+    ///       jump-statement:
+    ///         'goto' identifier ';'
+    ///         'continue' ';'
+    ///         'break' ';'
+    ///         'return' expression[opt] ';'
+    /// [GNU]   'goto' '*' expression ';'
+    ///
+    /// [OBC] objc-throw-statement:
+    /// [OBC]   '@' 'throw' expression ';'
+    /// [OBC]   '@' 'throw' ';'
+    /// \endverbatim
+    ///
+    StmtResult
+    ParseStatementOrDeclaration(StmtVector &Stmts, ParsedStmtContext StmtCtx,
+                                SourceLocation *TrailingElseLoc = nullptr);
+
+    StmtResult ParseStatementOrDeclarationAfterAttributes(
+        StmtVector &Stmts, ParsedStmtContext StmtCtx,
+        SourceLocation *TrailingElseLoc, ParsedAttributes &DeclAttrs,
+        ParsedAttributes &DeclSpecAttrs);
+
+    /// Parse an expression statement.
+    StmtResult ParseExprStatement(ParsedStmtContext StmtCtx);
+
+    /// ParseLabeledStatement - We have an identifier and a ':' after it.
+    ///
+    /// \verbatim
+    ///       label:
+    ///         identifier ':'
+    /// [GNU]   identifier ':' attributes[opt]
+    ///
+    ///       labeled-statement:
+    ///         label statement
+    /// \endverbatim
+    ///
+    StmtResult ParseLabeledStatement(ParsedAttributes &Attrs,
+                                     ParsedStmtContext StmtCtx);
+
+    /// ParseCaseStatement
+    /// \verbatim
+    ///       labeled-statement:
+    ///         'case' constant-expression ':' statement
+    /// [GNU]   'case' constant-expression '...' constant-expression ':'
+    /// statement
+    /// \endverbatim
+    ///
+    StmtResult ParseCaseStatement(ParsedStmtContext StmtCtx,
+                                  bool MissingCase = false,
+                                  ExprResult Expr = ExprResult());
+
+    /// ParseDefaultStatement
+    /// \verbatim
+    ///       labeled-statement:
+    ///         'default' ':' statement
+    /// \endverbatim
+    /// Note that this does not parse the 'statement' at the end.
+    ///
+    StmtResult ParseDefaultStatement(ParsedStmtContext StmtCtx);
+
+    StmtResult ParseCompoundStatement(bool isStmtExpr = false);
+
+    /// ParseCompoundStatement - Parse a "{}" block.
+    ///
+    /// \verbatim
+    ///       compound-statement: [C99 6.8.2]
+    ///         { block-item-list[opt] }
+    /// [GNU]   { label-declarations block-item-list } [TODO]
+    ///
+    ///       block-item-list:
+    ///         block-item
+    ///         block-item-list block-item
+    ///
+    ///       block-item:
+    ///         declaration
+    /// [GNU]   '__extension__' declaration
+    ///         statement
+    ///
+    /// [GNU] label-declarations:
+    /// [GNU]   label-declaration
+    /// [GNU]   label-declarations label-declaration
+    ///
+    /// [GNU] label-declaration:
+    /// [GNU]   '__label__' identifier-list ';'
+    /// \endverbatim
+    ///
+    StmtResult ParseCompoundStatement(bool isStmtExpr, unsigned ScopeFlags);
+
+    /// Parse any pragmas at the start of the compound expression. We handle
+    /// these separately since some pragmas (FP_CONTRACT) must appear before any
+    /// C statement in the compound, but may be intermingled with other pragmas.
+    void ParseCompoundStatementLeadingPragmas();
+
+    void DiagnoseLabelAtEndOfCompoundStatement();
+
+    /// Consume any extra semi-colons resulting in null statements,
+    /// returning true if any tok::semi were consumed.
+    bool ConsumeNullStmt(StmtVector &Stmts);
+
+    /// ParseCompoundStatementBody - Parse a sequence of statements optionally
+    /// followed by a label and invoke the ActOnCompoundStmt action.  This
+    /// expects the '{' to be the current token, and consume the '}' at the end
+    /// of the block.  It does not manipulate the scope stack.
+    StmtResult ParseCompoundStatementBody(bool isStmtExpr = false);
+
+    /// ParseParenExprOrCondition:
+    /// \verbatim
+    /// [C  ]     '(' expression ')'
+    /// [C++]     '(' condition ')'
+    /// [C++1z]   '(' init-statement[opt] condition ')'
+    /// \endverbatim
+    ///
+    /// This function parses and performs error recovery on the specified
+    /// condition or expression (depending on whether we're in C++ or C mode).
+    /// This function goes out of its way to recover well.  It returns true if
+    /// there was a parser error (the right paren couldn't be found), which
+    /// indicates that the caller should try to recover harder.  It returns
+    /// false if the condition is successfully parsed.  Note that a successful
+    /// parse can still have semantic errors in the condition. Additionally, it
+    /// will assign the location of the outer-most '(' and ')', to LParenLoc and
+    /// RParenLoc, respectively.
+    bool ParseParenExprOrCondition(StmtResult *InitStmt,
+                                   Sema::ConditionResult &CondResult,
+                                   SourceLocation Loc, Sema::ConditionKind CK,
+                                   SourceLocation &LParenLoc,
+                                   SourceLocation &RParenLoc);
+
+    /// ParseIfStatement
+    /// \verbatim
+    ///       if-statement: [C99 6.8.4.1]
+    ///         'if' '(' expression ')' statement
+    ///         'if' '(' expression ')' statement 'else' statement
+    /// [C++]   'if' '(' condition ')' statement
+    /// [C++]   'if' '(' condition ')' statement 'else' statement
+    /// [C++23] 'if' '!' [opt] consteval compound-statement
+    /// [C++23] 'if' '!' [opt] consteval compound-statement 'else' statement
+    /// \endverbatim
+    ///
+    StmtResult ParseIfStatement(SourceLocation *TrailingElseLoc);
+
+    /// ParseSwitchStatement
+    /// \verbatim
+    ///       switch-statement:
+    ///         'switch' '(' expression ')' statement
+    /// [C++]   'switch' '(' condition ')' statement
+    /// \endverbatim
+    StmtResult ParseSwitchStatement(SourceLocation *TrailingElseLoc);
+
+    /// ParseWhileStatement
+    /// \verbatim
+    ///       while-statement: [C99 6.8.5.1]
+    ///         'while' '(' expression ')' statement
+    /// [C++]   'while' '(' condition ')' statement
+    /// \endverbatim
+    StmtResult ParseWhileStatement(SourceLocation *TrailingElseLoc);
+
+    /// ParseDoStatement
+    /// \verbatim
+    ///       do-statement: [C99 6.8.5.2]
+    ///         'do' statement 'while' '(' expression ')' ';'
+    /// \endverbatim
+    /// Note: this lets the caller parse the end ';'.
+    StmtResult ParseDoStatement();
+
+    /// ParseForStatement
+    /// \verbatim
+    ///       for-statement: [C99 6.8.5.3]
+    ///         'for' '(' expr[opt] ';' expr[opt] ';' expr[opt] ')' statement
+    ///         'for' '(' declaration expr[opt] ';' expr[opt] ')' statement
+    /// [C++]   'for' '(' for-init-statement condition[opt] ';' expression[opt]
+    /// ')' [C++]       statement [C++0x] 'for'
+    ///             'co_await'[opt]    [Coroutines]
+    ///             '(' for-range-declaration ':' for-range-initializer ')'
+    ///             statement
+    /// [OBJC2] 'for' '(' declaration 'in' expr ')' statement
+    /// [OBJC2] 'for' '(' expr 'in' expr ')' statement
+    ///
+    /// [C++] for-init-statement:
+    /// [C++]   expression-statement
+    /// [C++]   simple-declaration
+    /// [C++23] alias-declaration
+    ///
+    /// [C++0x] for-range-declaration:
+    /// [C++0x]   attribute-specifier-seq[opt] type-specifier-seq declarator
+    /// [C++0x] for-range-initializer:
+    /// [C++0x]   expression
+    /// [C++0x]   braced-init-list            [TODO]
+    /// \endverbatim
+    StmtResult ParseForStatement(SourceLocation *TrailingElseLoc);
+
+    /// ParseGotoStatement
+    /// \verbatim
+    ///       jump-statement:
+    ///         'goto' identifier ';'
+    /// [GNU]   'goto' '*' expression ';'
+    /// \endverbatim
+    ///
+    /// Note: this lets the caller parse the end ';'.
+    ///
+    StmtResult ParseGotoStatement();
+
+    /// ParseContinueStatement
+    /// \verbatim
+    ///       jump-statement:
+    ///         'continue' ';'
+    /// \endverbatim
+    ///
+    /// Note: this lets the caller parse the end ';'.
+    ///
+    StmtResult ParseContinueStatement();
+
+    /// ParseBreakStatement
+    /// \verbatim
+    ///       jump-statement:
+    ///         'break' ';'
+    /// \endverbatim
+    ///
+    /// Note: this lets the caller parse the end ';'.
+    ///
+    StmtResult ParseBreakStatement();
+
+    /// ParseReturnStatement
+    /// \verbatim
+    ///       jump-statement:
+    ///         'return' expression[opt] ';'
+    ///         'return' braced-init-list ';'
+    ///         'co_return' expression[opt] ';'
+    ///         'co_return' braced-init-list ';'
+    /// \endverbatim
+    StmtResult ParseReturnStatement();
+
+    StmtResult ParsePragmaLoopHint(StmtVector &Stmts, ParsedStmtContext StmtCtx,
+                                   SourceLocation *TrailingElseLoc,
+                                   ParsedAttributes &Attrs);
+
+    void ParseMicrosoftIfExistsStatement(StmtVector &Stmts);
+
+    //===--------------------------------------------------------------------===//
+    // C++ 6: Statements and Blocks
+
+    /// ParseCXXTryBlock - Parse a C++ try-block.
+    ///
+    /// \verbatim
+    ///       try-block:
+    ///         'try' compound-statement handler-seq
+    /// \endverbatim
+    ///
+    StmtResult ParseCXXTryBlock();
+
+    /// ParseCXXTryBlockCommon - Parse the common part of try-block and
+    /// function-try-block.
+    ///
+    /// \verbatim
+    ///       try-block:
+    ///         'try' compound-statement handler-seq
+    ///
+    ///       function-try-block:
+    ///         'try' ctor-initializer[opt] compound-statement handler-seq
+    ///
+    ///       handler-seq:
+    ///         handler handler-seq[opt]
+    ///
+    ///       [Borland] try-block:
+    ///         'try' compound-statement seh-except-block
+    ///         'try' compound-statement seh-finally-block
+    /// \endverbatim
+    ///
+    StmtResult ParseCXXTryBlockCommon(SourceLocation TryLoc,
+                                      bool FnTry = false);
+
+    /// ParseCXXCatchBlock - Parse a C++ catch block, called handler in the
+    /// standard
+    ///
+    /// \verbatim
+    ///   handler:
+    ///     'catch' '(' exception-declaration ')' compound-statement
+    ///
+    ///   exception-declaration:
+    ///     attribute-specifier-seq[opt] type-specifier-seq declarator
+    ///     attribute-specifier-seq[opt] type-specifier-seq
+    ///     abstract-declarator[opt]
+    ///     '...'
+    /// \endverbatim
+    ///
+    StmtResult ParseCXXCatchBlock(bool FnCatch = false);
+
+    //===--------------------------------------------------------------------===//
+    // MS: SEH Statements and Blocks
+
+    /// ParseSEHTryBlockCommon
+    ///
+    /// \verbatim
+    /// seh-try-block:
+    ///   '__try' compound-statement seh-handler
+    ///
+    /// seh-handler:
+    ///   seh-except-block
+    ///   seh-finally-block
+    /// \endverbatim
+    ///
+    StmtResult ParseSEHTryBlock();
+
+    /// ParseSEHExceptBlock - Handle __except
+    ///
+    /// \verbatim
+    /// seh-except-block:
+    ///   '__except' '(' seh-filter-expression ')' compound-statement
+    /// \endverbatim
+    ///
+    StmtResult ParseSEHExceptBlock(SourceLocation Loc);
+
+    /// ParseSEHFinallyBlock - Handle __finally
+    ///
+    /// \verbatim
+    /// seh-finally-block:
+    ///   '__finally' compound-statement
+    /// \endverbatim
+    ///
+    StmtResult ParseSEHFinallyBlock(SourceLocation Loc);
+
+    StmtResult ParseSEHLeaveStatement();
+
+    Decl *ParseFunctionStatementBody(Decl *Decl, ParseScope &BodyScope);
+
+    /// ParseFunctionTryBlock - Parse a C++ function-try-block.
+    ///
+    /// \verbatim
+    ///       function-try-block:
+    ///         'try' ctor-initializer[opt] compound-statement handler-seq
+    /// \endverbatim
+    ///
+    Decl *ParseFunctionTryBlock(Decl *Decl, ParseScope &BodyScope);
+
+    /// When in code-completion, skip parsing of the function/method body
+    /// unless the body contains the code-completion point.
+    ///
+    /// \returns true if the function body was skipped.
+    bool trySkippingFunctionBody();
+
+    /// isDeclarationStatement - Disambiguates between a declaration or an
+    /// expression statement, when parsing function bodies.
+    ///
+    /// \param DisambiguatingWithExpression - True to indicate that the purpose
+    /// of this check is to disambiguate between an expression and a
+    /// declaration. Returns true for declaration, false for expression.
+    bool isDeclarationStatement(bool DisambiguatingWithExpression = false) {
+      if (getLangOpts().CPlusPlus)
+        return isCXXDeclarationStatement(DisambiguatingWithExpression);
+      return isDeclarationSpecifier(ImplicitTypenameContext::No, true);
+    }
 
   /// isForInitDeclaration - Disambiguates between a declaration or an
   /// expression in the context of the C 'clause-1' or the C++

@erichkeane erichkeane requested a review from cor3ntin June 30, 2025 14:03
@yronglin yronglin changed the title [C][Parser] Diagnostic for attribute declaration where statement is required [C23][Parser] Diagnostic for attribute declaration where statement is required Jun 30, 2025
@yronglin yronglin self-assigned this Jun 30, 2025
@yronglin yronglin added the c23 label Jun 30, 2025
@yronglin
Copy link
Contributor Author

The code format issue looks very strange, should we add an // clang-format off here?

@@ -80,6 +81,11 @@ Parser::ParseStatementOrDeclaration(StmtVector &Stmts,
assert((CXX11Attrs.empty() || Res.isInvalid() || Res.isUsable()) &&
"attributes on empty statement");

if (HasStdAttr && getLangOpts().C99 &&
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why are all the checks predicated on C99?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I originally want to emit this warning in C99 mode, but now I have changed the condition here to C23.

@@ -15,18 +15,19 @@ void f(int n) {
return;
}
case 2:
// FIXME: Should we emit an error {{fallthrough annotation does not directly precede switch label}}?
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah that seems like a regression in behavior.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, this because I originally set the new diagnostic's severity to Error, which will interrupt the warning static analysis based warnings.

if (S.hasUncompilableErrorOccurred() || Diags.getIgnoreAllWarnings())
// exit if having uncompilable errors or ignoring all warnings:

I have changed the severity to Warning now.

@@ -0,0 +1,18 @@
// RUN: %clang_cc1 -fsyntax-only -std=c2x -verify %s
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// RUN: %clang_cc1 -fsyntax-only -std=c2x -verify %s
// RUN: %clang_cc1 -fsyntax-only -std=c23 -verify %s

Maybe rename the file to be c23 instead of c2x as well?

… required

Signed-off-by: yronglin <yronglin777@gmail.com>
@yronglin yronglin force-pushed the fix_missing_stmt_before_semi branch from d46ebd6 to 43e2dc6 Compare July 2, 2025 18:15
Signed-off-by: yronglin <yronglin777@gmail.com>
@yronglin
Copy link
Contributor Author

yronglin commented Jul 2, 2025

Thanks for your review!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
c23 clang:frontend Language frontend issues, e.g. anything involving "Sema" clang Clang issues not falling into any other category
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[Clang][C23] No diagnostic for attribute declaration where statement is required
3 participants