-
Notifications
You must be signed in to change notification settings - Fork 14.3k
[C] Disallow declarations where a statement is required #92908
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
[C] Disallow declarations where a statement is required #92908
Conversation
8bd06d5 removed the notion of parsed statement contexts that track whether a declaration is valid for C or not. This resurrects the concept, because C still does not allow a declaration as a substatement.
@llvm/pr-subscribers-clang Author: Aaron Ballman (AaronBallman) ChangesThis fixes a regression introduced in 8bd06d5 where Clang began to accept a declaration where a statement is required. e.g.,
Fixes #92775 Full diff: https://github.com/llvm/llvm-project/pull/92908.diff 6 Files Affected:
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 81e9d0423f96a..a47252c536c0f 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -589,6 +589,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 5f04664141d29..5e455b16fb8c0 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 b0af04451166c..57b9fb10a1e08 100644
--- a/clang/lib/Parse/ParseStmt.cpp
+++ b/clang/lib/Parse/ParseStmt.cpp
@@ -239,7 +239,10 @@ 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)) ||
+ 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 589047df3e52b..116e5d922593e 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 different(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 0000000000000..39ef05bf4bd99
--- /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 ba29f6da8ba25..bbcdd823483a5 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
{
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The original patch changed some of the ParsedStmtContext's in ParseOMP that might need to be changed back? Looking back, I think the intent there was in part to not specify OMP standalone directives, so that part should be reverted as well perhaps?
I'm less certain, but CC @jdoerfert @mikerice1969 for more opinions. The original changes actually fixed a bug in OpenMP related to standalone directives.
|
@@ -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, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This feels a little mysterious, I only see that we check it but it is not obvious how it gets set.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@shafik L481 below
It gets set a few lines down for
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM modulo comment
@@ -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, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@shafik L481 below
if ((getLangOpts().CPlusPlus || getLangOpts().MicrosoftExt || | ||
(StmtCtx & ParsedStmtContext::AllowDeclarationsInC) != | ||
ParsedStmtContext()) && | ||
((GNUAttributeLoc.isValid() && !(HaveAttrs && AllAttrsAreStmtAttrs)) || |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you add a standard quote?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've added one, let me know if you're happy with it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks (somehow i did not get notified)
This fixes a regression introduced in 8bd06d5 where Clang began to accept a declaration where a statement is required. e.g., ``` if (1) int x; // Previously accepted, now properly rejected ``` Fixes llvm#92775
This fixes a regression introduced in 8bd06d5 where Clang began to accept a declaration where a statement is required. e.g.,
Fixes #92775