[clang] 5901d40 - [C] Disallow declarations where a statement is required (#92908)
via cfe-commits
cfe-commits at lists.llvm.org
Tue May 28 11:55:23 PDT 2024
Author: Aaron Ballman
Date: 2024-05-28T14:55:18-04:00
New Revision: 5901d4005f015a46185ddc080038c1a3db3fa2c7
URL: https://github.com/llvm/llvm-project/commit/5901d4005f015a46185ddc080038c1a3db3fa2c7
DIFF: https://github.com/llvm/llvm-project/commit/5901d4005f015a46185ddc080038c1a3db3fa2c7.diff
LOG: [C] Disallow declarations where a statement is required (#92908)
This fixes a regression introduced in
8bd06d5b65845e5e01dd899a2deb773580460b89 where Clang began to accept a
declaration where a statement is required. e.g.,
```
if (1)
int x; // Previously accepted, now properly rejected
```
Fixes #92775
Added:
clang/test/Parser/decls.c
Modified:
clang/docs/ReleaseNotes.rst
clang/include/clang/Parse/Parser.h
clang/lib/Parse/ParseStmt.cpp
clang/test/C/C99/block-scopes.c
clang/test/SemaOpenACC/parallel-loc-and-stmt.c
Removed:
################################################################################
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 894f6b04431744..9091f6341bd9b8 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -632,6 +632,9 @@ Bug Fixes in This Version
- ``__is_array`` and ``__is_bounded_array`` no longer return ``true`` for
zero-sized arrays. Fixes (#GH54705).
+- Correctly reject declarations where a statement is required in C.
+ Fixes #GH92775
+
Bug Fixes to Compiler Builtins
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h
index 8493026f5f7a69..00b475e5b42824 100644
--- a/clang/include/clang/Parse/Parser.h
+++ b/clang/include/clang/Parse/Parser.h
@@ -467,15 +467,18 @@ class Parser : public CodeCompletionHandler {
/// 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 = 0x1,
+ AllowStandaloneOpenMPDirectives = 0x2,
/// This context is at the top level of a GNU statement expression.
- InStmtExpr = 0x2,
+ InStmtExpr = 0x4,
/// The context of a regular substatement.
SubStmt = 0,
/// The context of a compound-statement.
- Compound = AllowStandaloneOpenMPDirectives,
+ Compound = AllowDeclarationsInC | AllowStandaloneOpenMPDirectives,
LLVM_MARK_AS_BITMASK_ENUM(InStmtExpr)
};
diff --git a/clang/lib/Parse/ParseStmt.cpp b/clang/lib/Parse/ParseStmt.cpp
index b0af04451166ca..c25203243ee49b 100644
--- a/clang/lib/Parse/ParseStmt.cpp
+++ b/clang/lib/Parse/ParseStmt.cpp
@@ -239,7 +239,15 @@ StmtResult Parser::ParseStatementOrDeclarationAfterAttributes(
auto IsStmtAttr = [](ParsedAttr &Attr) { return Attr.isStmtAttr(); };
bool AllAttrsAreStmtAttrs = llvm::all_of(CXX11Attrs, IsStmtAttr) &&
llvm::all_of(GNUAttrs, IsStmtAttr);
- if (((GNUAttributeLoc.isValid() && !(HaveAttrs && AllAttrsAreStmtAttrs)) ||
+ // In C, the grammar production for statement (C23 6.8.1p1) does not allow
+ // for declarations, which is
diff erent from C++ (C++23 [stmt.pre]p1). So
+ // in C++, we always allow a declaration, but in C we need to check whether
+ // we're in a statement context that allows declarations. e.g., in C, the
+ // following is invalid: if (1) int x;
+ if ((getLangOpts().CPlusPlus || getLangOpts().MicrosoftExt ||
+ (StmtCtx & ParsedStmtContext::AllowDeclarationsInC) !=
+ ParsedStmtContext()) &&
+ ((GNUAttributeLoc.isValid() && !(HaveAttrs && AllAttrsAreStmtAttrs)) ||
isDeclarationStatement())) {
SourceLocation DeclStart = Tok.getLocation(), DeclEnd;
DeclGroupPtrTy Decl;
diff --git a/clang/test/C/C99/block-scopes.c b/clang/test/C/C99/block-scopes.c
index 589047df3e52bc..116e5d922593e0 100644
--- a/clang/test/C/C99/block-scopes.c
+++ b/clang/test/C/C99/block-scopes.c
@@ -18,8 +18,9 @@
enum {a, b};
void
diff erent(void) {
- if (sizeof(enum {b, a}) != sizeof(int))
+ if (sizeof(enum {b, a}) != sizeof(int)) {
_Static_assert(a == 1, "");
+ }
/* In C89, the 'b' found here would have been from the enum declaration in
* the controlling expression of the selection statement, not from the global
* declaration. In C99 and later, that enumeration is scoped to the 'if'
diff --git a/clang/test/Parser/decls.c b/clang/test/Parser/decls.c
new file mode 100644
index 00000000000000..39ef05bf4bd999
--- /dev/null
+++ b/clang/test/Parser/decls.c
@@ -0,0 +1,39 @@
+// RUN: %clang_cc1 %s -fsyntax-only -verify -pedantic
+
+// Test that we can parse declarations at global scope.
+int v;
+
+void func(void) {
+ // Test that we can parse declarations within a compound statement.
+ int a;
+ {
+ int b;
+ }
+
+ int z = ({ // expected-warning {{use of GNU statement expression extension}}
+ // Test that we can parse declarations within a GNU statement expression.
+ int w = 12;
+ w;
+ });
+
+ // Test that we diagnose declarations where a statement is required.
+ // See GH92775.
+ if (1)
+ int x; // expected-error {{expected expression}}
+ for (;;)
+ int c; // expected-error {{expected expression}}
+
+ label:
+ int y; // expected-warning {{label followed by a declaration is a C23 extension}}
+
+ // Test that lookup works as expected.
+ (void)a;
+ (void)v;
+ (void)z;
+ (void)b; // expected-error {{use of undeclared identifier 'b'}}
+ (void)w; // expected-error {{use of undeclared identifier 'w'}}
+ (void)x; // expected-error {{use of undeclared identifier 'x'}}
+ (void)c; // expected-error {{use of undeclared identifier 'c'}}
+ (void)y;
+}
+
diff --git a/clang/test/SemaOpenACC/parallel-loc-and-stmt.c b/clang/test/SemaOpenACC/parallel-loc-and-stmt.c
index ba29f6da8ba25d..bbcdd823483a52 100644
--- a/clang/test/SemaOpenACC/parallel-loc-and-stmt.c
+++ b/clang/test/SemaOpenACC/parallel-loc-and-stmt.c
@@ -33,9 +33,11 @@ int foo3;
void func() {
// FIXME: Should we disallow this on declarations, or consider this to be on
- // the initialization?
+ // the initialization? This is currently rejected in C because
+ // Parser::ParseOpenACCDirectiveStmt() calls ParseStatement() and passes the
+ // statement context as "SubStmt" which does not allow for a declaration in C.
#pragma acc parallel
- int foo;
+ int foo; // expected-error {{expected expression}}
#pragma acc parallel
{
More information about the cfe-commits
mailing list