Skip to content

Commit b0cc947

Browse files
committed
[Clang] Diagnose jumps into statement expressions
Such jumps are not allowed by GCC and allowing them can lead to situations where we jumps into unevaluated statements. Fixes #63682 Reviewed By: aaron.ballman, #clang-language-wg Differential Revision: https://reviews.llvm.org/D154696
1 parent a608076 commit b0cc947

File tree

9 files changed

+71
-22
lines changed

9 files changed

+71
-22
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -582,6 +582,9 @@ Bug Fixes in This Version
582582
(`#50243 <https://github.com/llvm/llvm-project/issues/50243>`_),
583583
(`#48636 <https://github.com/llvm/llvm-project/issues/48636>`_),
584584
(`#50320 <https://github.com/llvm/llvm-project/issues/50320>`_).
585+
- Correcly diagnose jumps into statement expressions.
586+
This ensures the behavior of Clang is consistent with GCC.
587+
(`#63682 <https://github.com/llvm/llvm-project/issues/63682>`_)
585588

586589
Bug Fixes to Compiler Builtins
587590
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

clang/include/clang/Basic/DiagnosticSemaKinds.td

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6196,6 +6196,8 @@ def note_enters_block_captures_non_trivial_c_struct : Note<
61966196
"to destroy">;
61976197
def note_enters_compound_literal_scope : Note<
61986198
"jump enters lifetime of a compound literal that is non-trivial to destruct">;
6199+
def note_enters_statement_expression : Note<
6200+
"jump enters a statement expression">;
61996201

62006202
def note_exits_cleanup : Note<
62016203
"jump exits scope of variable with __attribute__((cleanup))">;

clang/lib/Sema/JumpDiagnostics.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -477,6 +477,21 @@ void JumpScopeChecker::BuildScopeInformation(Stmt *S,
477477
return;
478478
}
479479

480+
case Stmt::StmtExprClass: {
481+
// [GNU]
482+
// Jumping into a statement expression with goto or using
483+
// a switch statement outside the statement expression with
484+
// a case or default label inside the statement expression is not permitted.
485+
// Jumping out of a statement expression is permitted.
486+
StmtExpr *SE = cast<StmtExpr>(S);
487+
unsigned NewParentScope = Scopes.size();
488+
Scopes.push_back(GotoScope(ParentScope,
489+
diag::note_enters_statement_expression,
490+
/*OutDiag=*/0, SE->getBeginLoc()));
491+
BuildScopeInformation(SE->getSubStmt(), NewParentScope);
492+
return;
493+
}
494+
480495
case Stmt::ObjCAtTryStmtClass: {
481496
// Disallow jumps into any part of an @try statement by pushing a scope and
482497
// walking all sub-stmts in that scope.

clang/lib/Sema/SemaExpr.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16490,6 +16490,8 @@ ExprResult Sema::ActOnAddrLabel(SourceLocation OpLoc, SourceLocation LabLoc,
1649016490

1649116491
void Sema::ActOnStartStmtExpr() {
1649216492
PushExpressionEvaluationContext(ExprEvalContexts.back().Context);
16493+
// Make sure we diagnose jumping into a statement expression.
16494+
setFunctionHasBranchProtectedScope();
1649316495
}
1649416496

1649516497
void Sema::ActOnStmtExprError() {

clang/test/CXX/stmt.stmt/stmt.select/stmt.if/p2.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -153,7 +153,8 @@ a: if constexpr(sizeof(n) == 4) // expected-error {{redefinition}} expected-not
153153

154154
void evil_things() {
155155
goto evil_label; // expected-error {{cannot jump}}
156-
if constexpr (true || ({evil_label: false;})) {} // expected-note {{constexpr if}}
156+
if constexpr (true || ({evil_label: false;})) {} // expected-note {{constexpr if}} \
157+
// expected-note {{jump enters a statement expression}}
157158

158159
if constexpr (true) // expected-note {{constexpr if}}
159160
goto surprise; // expected-error {{cannot jump}}

clang/test/Sema/asm-goto.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,8 +50,9 @@ int test3(int n)
5050
// expected-error@+2 {{cannot jump from this asm goto statement to one of its possible targets}}
5151
// expected-error@+1 {{cannot jump from this asm goto statement to one of its possible targets}}
5252
asm volatile goto("testl %0, %0; jne %l1;" :: "r"(n)::label_true, loop);
53-
// expected-note@+2 {{jump bypasses initialization of variable length array}}
54-
// expected-note@+1 {{possible target of asm goto statement}}
53+
// expected-note@+3 {{jump bypasses initialization of variable length array}}
54+
// expected-note@+2 {{possible target of asm goto statement}}
55+
// expected-note@+1 {{jump enters a statement expression}}
5556
return ({int a[n];label_true: 2;});
5657
// expected-note@+1 {{jump bypasses initialization of variable length array}}
5758
int b[n];

clang/test/Sema/scope-check.c

Lines changed: 32 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,8 @@ int test8(int x) {
6565

6666
// Statement expressions.
6767
goto L3; // expected-error {{cannot jump from this goto statement to its label}}
68-
int Y = ({ int a[x]; // expected-note {{jump bypasses initialization of variable length array}}
68+
int Y = ({ int a[x]; // expected-note {{jump bypasses initialization of variable length array}} \
69+
// expected-note {{jump enters a statement expression}}
6970
L3: 4; });
7071

7172
goto L4; // expected-error {{cannot jump from this goto statement to its label}}
@@ -107,25 +108,25 @@ int test8(int x) {
107108
4; })];
108109
L10:; // bad
109110
}
110-
111+
111112
{
112113
// FIXME: Crashes goto checker.
113114
//goto L11;// ok
114115
//int A[({ L11: 4; })];
115116
}
116-
117+
117118
{
118119
goto L12;
119-
120+
120121
int y = 4; // fixme-warn: skips initializer.
121122
L12:
122123
;
123124
}
124-
125+
125126
// Statement expressions 2.
126127
goto L1; // expected-error {{cannot jump from this goto statement to its label}}
127-
return x == ({
128-
int a[x]; // expected-note {{jump bypasses initialization of variable length array}}
128+
return x == ({ // expected-note {{jump enters a statement expression}}
129+
int a[x]; // expected-note {{jump bypasses initialization of variable length array}}
129130
L1:
130131
42; });
131132
}
@@ -231,3 +232,27 @@ void test15(int n, void *pc) {
231232
}
232233

233234
int test16(int [sizeof &&z]); // expected-error {{use of address-of-label extension outside of a function body}}
235+
236+
void GH63682() {
237+
{
238+
goto L; // expected-error {{cannot jump from this goto statement to its label}}
239+
(void)sizeof (int){({ L:; 1; })}; // expected-note {{jump enters a statement expression}}
240+
}
241+
{
242+
goto M; // expected-error {{cannot jump from this goto statement to its label}}
243+
(void)({ M:; 1; }); // expected-note {{jump enters a statement expression}}
244+
}
245+
{
246+
(void)({ goto N; 1; }); // ok
247+
N: ;
248+
}
249+
{
250+
(void)sizeof (int){({ goto O; 1; })}; // ok (not evaluated)
251+
O: ;
252+
}
253+
{
254+
(void)sizeof(({goto P;}), 0); // expected-error {{cannot jump from this goto statement to its label}}
255+
return;
256+
(void)({P:1;}); // expected-note {{jump enters a statement expression}}
257+
}
258+
}

clang/test/SemaCXX/constant-expression-cxx14.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -831,8 +831,9 @@ namespace StmtExpr {
831831
case 0:
832832
return 0;
833833

834-
({
835-
case 1: // expected-note {{not supported}}
834+
({ // expected-note {{jump enters a statement expression}}
835+
case 1:// expected-error {{cannot jump from switch statement to this case label}} \
836+
// expected-note {{not supported}}
836837
return 1;
837838
});
838839
}

clang/test/SemaObjC/scope-check.m

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ void test1(void) {
1515
} @finally {// expected-note {{jump bypasses initialization of @finally block}}
1616
L3: ;
1717
}
18-
18+
1919
@try {
2020
goto L4; // expected-error{{cannot jump}}
2121
goto L5; // expected-error{{cannot jump}}
@@ -27,29 +27,28 @@ void test1(void) {
2727
} @finally { // expected-note {{jump bypasses initialization of @finally block}}
2828
L4: ;
2929
}
30-
31-
30+
31+
3232
@try { // expected-note 2 {{jump bypasses initialization of @try block}}
3333
L7: ;
3434
} @catch (C *c) {
3535
goto L7; // expected-error{{cannot jump}}
3636
} @finally {
3737
goto L7; // expected-error{{cannot jump}}
3838
}
39-
39+
4040
goto L8; // expected-error{{cannot jump}}
41-
@try {
41+
@try {
4242
} @catch (A *c) {
4343
} @catch (B *c) {
4444
} @catch (C *c) { // expected-note {{jump bypasses initialization of @catch block}}
4545
L8: ;
4646
}
47-
47+
4848
id X;
4949
goto L9; // expected-error{{cannot jump}}
50-
goto L10; // ok
51-
@synchronized // expected-note {{jump bypasses initialization of @synchronized block}}
52-
( ({ L10: ; X; })) {
50+
@synchronized (X) // expected-note {{jump bypasses initialization of @synchronized block}}
51+
{
5352
L9:
5453
;
5554
}
@@ -88,7 +87,7 @@ + (void)meth2 {
8887
goto L0; // expected-error {{cannot jump}}
8988
typedef int A[n]; // expected-note {{jump bypasses initialization of VLA typedef}}
9089
L0:
91-
90+
9291
goto L1; // expected-error {{cannot jump}}
9392
A b, c[10]; // expected-note 2 {{jump bypasses initialization of variable length array}}
9493
L1:

0 commit comments

Comments
 (0)