Skip to content

Commit 6997e94

Browse files
KaiYGtclin914
authored andcommitted
Revert "Ignore trailing NullStmts in StmtExprs for GCC compatibility." (llvm#166036)
This reverts commit b1e511b. llvm#160243 Reverting because the GCC C front end is incorrect. --------- Co-authored-by: Jim Lin <[email protected]>
1 parent 6f37ab1 commit 6997e94

File tree

12 files changed

+81
-82
lines changed

12 files changed

+81
-82
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,16 @@ Potentially Breaking Changes
6969
call the member ``operator delete`` instead of the expected global
7070
delete operator. The old behavior is retained under ``-fclang-abi-compat=21``
7171
flag.
72+
- Trailing null statements in GNU statement expressions are no longer
73+
ignored by Clang; they now result in a void type. Clang previously
74+
matched GCC's behavior, which was recently clarified to be incorrect.
75+
76+
.. code-block:: c++
77+
78+
// The resulting type is 'void', not 'int'
79+
void foo(void) {
80+
return ({ 1;; });
81+
}
7282

7383
C/C++ Language Potentially Breaking Changes
7484
-------------------------------------------

clang/include/clang/AST/Stmt.h

Lines changed: 0 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1831,26 +1831,6 @@ class CompoundStmt final
18311831
return const_reverse_body_iterator(body_begin());
18321832
}
18331833

1834-
// Get the Stmt that StmtExpr would consider to be the result of this
1835-
// compound statement. This is used by StmtExpr to properly emulate the GCC
1836-
// compound expression extension, which ignores trailing NullStmts when
1837-
// getting the result of the expression.
1838-
// i.e. ({ 5;;; })
1839-
// ^^ ignored
1840-
// If we don't find something that isn't a NullStmt, just return the last
1841-
// Stmt.
1842-
Stmt *getStmtExprResult() {
1843-
for (auto *B : llvm::reverse(body())) {
1844-
if (!isa<NullStmt>(B))
1845-
return B;
1846-
}
1847-
return body_back();
1848-
}
1849-
1850-
const Stmt *getStmtExprResult() const {
1851-
return const_cast<CompoundStmt *>(this)->getStmtExprResult();
1852-
}
1853-
18541834
SourceLocation getBeginLoc() const { return LBraceLoc; }
18551835
SourceLocation getEndLoc() const { return RBraceLoc; }
18561836

clang/lib/AST/ByteCode/Compiler.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4175,7 +4175,7 @@ bool Compiler<Emitter>::VisitStmtExpr(const StmtExpr *E) {
41754175
StmtExprScope<Emitter> SS(this);
41764176

41774177
const CompoundStmt *CS = E->getSubStmt();
4178-
const Stmt *Result = CS->getStmtExprResult();
4178+
const Stmt *Result = CS->body_back();
41794179
for (const Stmt *S : CS->body()) {
41804180
if (S != Result) {
41814181
if (!this->visitStmt(S))

clang/lib/AST/ComputeDependence.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -178,7 +178,7 @@ ExprDependence clang::computeDependence(StmtExpr *E, unsigned TemplateDepth) {
178178
auto D = toExprDependenceForImpliedType(E->getType()->getDependence());
179179
// Propagate dependence of the result.
180180
if (const auto *CompoundExprResult =
181-
dyn_cast_or_null<ValueStmt>(E->getSubStmt()->getStmtExprResult()))
181+
dyn_cast_or_null<ValueStmt>(E->getSubStmt()->body_back()))
182182
if (const Expr *ResultExpr = CompoundExprResult->getExprStmt())
183183
D |= ResultExpr->getDependence();
184184
// Note: we treat a statement-expression in a dependent context as always

clang/lib/CodeGen/CGStmt.cpp

Lines changed: 33 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -582,48 +582,45 @@ CodeGenFunction::EmitCompoundStmtWithoutScope(const CompoundStmt &S,
582582
bool GetLast,
583583
AggValueSlot AggSlot) {
584584

585-
const Stmt *ExprResult = S.getStmtExprResult();
586-
assert((!GetLast || (GetLast && ExprResult)) &&
587-
"If GetLast is true then the CompoundStmt must have a StmtExprResult");
585+
for (CompoundStmt::const_body_iterator I = S.body_begin(),
586+
E = S.body_end() - GetLast;
587+
I != E; ++I)
588+
EmitStmt(*I);
588589

589590
Address RetAlloca = Address::invalid();
590-
591-
for (auto *CurStmt : S.body()) {
592-
if (GetLast && ExprResult == CurStmt) {
593-
// We have to special case labels here. They are statements, but when put
594-
// at the end of a statement expression, they yield the value of their
595-
// subexpression. Handle this by walking through all labels we encounter,
596-
// emitting them before we evaluate the subexpr.
597-
// Similar issues arise for attributed statements.
598-
while (!isa<Expr>(ExprResult)) {
599-
if (const auto *LS = dyn_cast<LabelStmt>(ExprResult)) {
600-
EmitLabel(LS->getDecl());
601-
ExprResult = LS->getSubStmt();
602-
} else if (const auto *AS = dyn_cast<AttributedStmt>(ExprResult)) {
603-
// FIXME: Update this if we ever have attributes that affect the
604-
// semantics of an expression.
605-
ExprResult = AS->getSubStmt();
606-
} else {
607-
llvm_unreachable("unknown value statement");
608-
}
591+
if (GetLast) {
592+
// We have to special case labels here. They are statements, but when put
593+
// at the end of a statement expression, they yield the value of their
594+
// subexpression. Handle this by walking through all labels we encounter,
595+
// emitting them before we evaluate the subexpr.
596+
// Similar issues arise for attributed statements.
597+
const Stmt *LastStmt = S.body_back();
598+
while (!isa<Expr>(LastStmt)) {
599+
if (const auto *LS = dyn_cast<LabelStmt>(LastStmt)) {
600+
EmitLabel(LS->getDecl());
601+
LastStmt = LS->getSubStmt();
602+
} else if (const auto *AS = dyn_cast<AttributedStmt>(LastStmt)) {
603+
// FIXME: Update this if we ever have attributes that affect the
604+
// semantics of an expression.
605+
LastStmt = AS->getSubStmt();
606+
} else {
607+
llvm_unreachable("unknown value statement");
609608
}
609+
}
610610

611-
EnsureInsertPoint();
611+
EnsureInsertPoint();
612612

613-
const Expr *E = cast<Expr>(ExprResult);
614-
QualType ExprTy = E->getType();
615-
if (hasAggregateEvaluationKind(ExprTy)) {
616-
EmitAggExpr(E, AggSlot);
617-
} else {
618-
// We can't return an RValue here because there might be cleanups at
619-
// the end of the StmtExpr. Because of that, we have to emit the result
620-
// here into a temporary alloca.
621-
RetAlloca = CreateMemTemp(ExprTy);
622-
EmitAnyExprToMem(E, RetAlloca, Qualifiers(),
623-
/*IsInit*/ false);
624-
}
613+
const Expr *E = cast<Expr>(LastStmt);
614+
QualType ExprTy = E->getType();
615+
if (hasAggregateEvaluationKind(ExprTy)) {
616+
EmitAggExpr(E, AggSlot);
625617
} else {
626-
EmitStmt(CurStmt);
618+
// We can't return an RValue here because there might be cleanups at
619+
// the end of the StmtExpr. Because of that, we have to emit the result
620+
// here into a temporary alloca.
621+
RetAlloca = CreateMemTemp(ExprTy);
622+
EmitAnyExprToMem(E, RetAlloca, Qualifiers(),
623+
/*IsInit*/ false);
627624
}
628625
}
629626

clang/lib/Parse/ParseStmt.cpp

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1079,16 +1079,10 @@ bool Parser::ConsumeNullStmt(StmtVector &Stmts) {
10791079
StmtResult Parser::handleExprStmt(ExprResult E, ParsedStmtContext StmtCtx) {
10801080
bool IsStmtExprResult = false;
10811081
if ((StmtCtx & ParsedStmtContext::InStmtExpr) != ParsedStmtContext()) {
1082-
// For GCC compatibility we skip past NullStmts.
1083-
unsigned LookAhead = 0;
1084-
while (GetLookAheadToken(LookAhead).is(tok::semi)) {
1085-
++LookAhead;
1086-
}
1087-
// Then look to see if the next two tokens close the statement expression;
1088-
// if so, this expression statement is the last statement in a statement
1089-
// expression.
1090-
IsStmtExprResult = GetLookAheadToken(LookAhead).is(tok::r_brace) &&
1091-
GetLookAheadToken(LookAhead + 1).is(tok::r_paren);
1082+
// Look ahead to see if the next two tokens close the statement expression;
1083+
// if so, this expression statement is the last statement in a
1084+
// statment expression.
1085+
IsStmtExprResult = Tok.is(tok::r_brace) && NextToken().is(tok::r_paren);
10921086
}
10931087

10941088
if (IsStmtExprResult)

clang/lib/Sema/SemaExpr.cpp

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16185,9 +16185,7 @@ ExprResult Sema::BuildStmtExpr(SourceLocation LPLoc, Stmt *SubStmt,
1618516185
QualType Ty = Context.VoidTy;
1618616186
bool StmtExprMayBindToTemp = false;
1618716187
if (!Compound->body_empty()) {
16188-
// For GCC compatibility we get the last Stmt excluding trailing NullStmts.
16189-
if (const auto *LastStmt =
16190-
dyn_cast<ValueStmt>(Compound->getStmtExprResult())) {
16188+
if (const auto *LastStmt = dyn_cast<ValueStmt>(Compound->body_back())) {
1619116189
if (const Expr *Value = LastStmt->getExprStmt()) {
1619216190
StmtExprMayBindToTemp = true;
1619316191
Ty = Value->getType();

clang/lib/Sema/TreeTransform.h

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8076,14 +8076,13 @@ TreeTransform<Derived>::TransformCompoundStmt(CompoundStmt *S,
80768076
getSema().resetFPOptions(
80778077
S->getStoredFPFeatures().applyOverrides(getSema().getLangOpts()));
80788078

8079-
const Stmt *ExprResult = S->getStmtExprResult();
80808079
bool SubStmtInvalid = false;
80818080
bool SubStmtChanged = false;
80828081
SmallVector<Stmt*, 8> Statements;
80838082
for (auto *B : S->body()) {
80848083
StmtResult Result = getDerived().TransformStmt(
8085-
B, IsStmtExpr && B == ExprResult ? StmtDiscardKind::StmtExprResult
8086-
: StmtDiscardKind::Discarded);
8084+
B, IsStmtExpr && B == S->body_back() ? StmtDiscardKind::StmtExprResult
8085+
: StmtDiscardKind::Discarded);
80878086

80888087
if (Result.isInvalid()) {
80898088
// Immediately fail if this was a DeclStmt, since it's very

clang/test/AST/ast-dump-stmt.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -400,7 +400,7 @@ void TestMiscStmts(void) {
400400
// CHECK-NEXT: ImplicitCastExpr
401401
// CHECK-NEXT: DeclRefExpr 0x{{[^ ]*}} <col:17> 'int' lvalue Var 0x{{[^ ]*}} 'a' 'int'
402402
({int a = 10; a;;; });
403-
// CHECK-NEXT: StmtExpr 0x{{[^ ]*}} <line:[[@LINE-1]]:3, col:23> 'int'
403+
// CHECK-NEXT: StmtExpr 0x{{[^ ]*}} <line:[[@LINE-1]]:3, col:23> 'void'
404404
// CHECK-NEXT: CompoundStmt
405405
// CHECK-NEXT: DeclStmt
406406
// CHECK-NEXT: VarDecl 0x{{[^ ]*}} <col:5, col:13> col:9 used a 'int' cinit

clang/test/CodeGen/exprs.c

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -196,10 +196,17 @@ void f18(void) {
196196

197197
// Ensure the right stmt is returned
198198
int f19(void) {
199-
return ({ 3;;4;; });
199+
return ({ 3;;4; });
200200
}
201201
// CHECK-LABEL: define{{.*}} i32 @f19()
202202
// CHECK: [[T:%.*]] = alloca i32
203203
// CHECK: store i32 4, ptr [[T]]
204204
// CHECK: [[L:%.*]] = load i32, ptr [[T]]
205205
// CHECK: ret i32 [[L]]
206+
207+
// PR166036: The trailing NullStmt should result in a void.
208+
void f20(void) {
209+
return ({ 3;;4;; });
210+
}
211+
// CHECK-LABEL: define{{.*}} void @f20()
212+
// CHECK: ret void

0 commit comments

Comments
 (0)