Compare commits

...

3 Commits

Author SHA1 Message Date
Oliver Hunt
020147d9ea
Actually commit the codegen fixes this time 2025-08-14 01:52:18 -07:00
Oliver Hunt
e2b0c23af1
other loop kinds in progress 2025-08-08 11:02:21 -07:00
Oliver Hunt
467f72d8e2
[clang][Sema] Fix the continue and break scope for while loops
Make sure we don't push the break and continue scope for a while
loop until after we have evaluated the condition.
2025-08-07 15:31:35 -07:00
6 changed files with 71 additions and 38 deletions

View File

@ -161,6 +161,8 @@ Bug Fixes in This Version
targets that treat ``_Float16``/``__fp16`` as native scalar types. Previously targets that treat ``_Float16``/``__fp16`` as native scalar types. Previously
the warning was silently lost because the operands differed only by an implicit the warning was silently lost because the operands differed only by an implicit
cast chain. (#GH149967). cast chain. (#GH149967).
- Correct the continue and break scope for while statements to be after the
condition is evaluated.
Bug Fixes to Compiler Builtins Bug Fixes to Compiler Builtins
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

View File

@ -1087,9 +1087,6 @@ void CodeGenFunction::EmitWhileStmt(const WhileStmt &S,
// also become the break target. // also become the break target.
JumpDest LoopExit = getJumpDestInCurrentScope("while.end"); JumpDest LoopExit = getJumpDestInCurrentScope("while.end");
// Store the blocks to use for break and continue.
BreakContinueStack.push_back(BreakContinue(LoopExit, LoopHeader));
// C++ [stmt.while]p2: // C++ [stmt.while]p2:
// When the condition of a while statement is a declaration, the // When the condition of a while statement is a declaration, the
// scope of the variable that is declared extends from its point // scope of the variable that is declared extends from its point
@ -1158,6 +1155,9 @@ void CodeGenFunction::EmitWhileStmt(const WhileStmt &S,
<< SourceRange(S.getWhileLoc(), S.getRParenLoc()); << SourceRange(S.getWhileLoc(), S.getRParenLoc());
} }
// Store the blocks to use for break and continue.
BreakContinueStack.push_back(BreakContinue(LoopExit, LoopHeader));
// Emit the loop body. We have to emit this in a cleanup scope // Emit the loop body. We have to emit this in a cleanup scope
// because it might be a singleton DeclStmt. // because it might be a singleton DeclStmt.
{ {
@ -1206,8 +1206,6 @@ void CodeGenFunction::EmitDoStmt(const DoStmt &S,
uint64_t ParentCount = getCurrentProfileCount(); uint64_t ParentCount = getCurrentProfileCount();
// Store the blocks to use for break and continue.
BreakContinueStack.push_back(BreakContinue(LoopExit, LoopCond));
// Emit the body of the loop. // Emit the body of the loop.
llvm::BasicBlock *LoopBody = createBasicBlock("do.body"); llvm::BasicBlock *LoopBody = createBasicBlock("do.body");
@ -1220,10 +1218,13 @@ void CodeGenFunction::EmitDoStmt(const DoStmt &S,
if (CGM.shouldEmitConvergenceTokens()) if (CGM.shouldEmitConvergenceTokens())
ConvergenceTokenStack.push_back(emitConvergenceLoopToken(LoopBody)); ConvergenceTokenStack.push_back(emitConvergenceLoopToken(LoopBody));
// Store the blocks to use for break and continue.
BreakContinueStack.push_back(BreakContinue(LoopExit, LoopCond));
{ {
RunCleanupsScope BodyScope(*this); RunCleanupsScope BodyScope(*this);
EmitStmt(S.getBody()); EmitStmt(S.getBody());
} }
BreakContinueStack.pop_back();
EmitBlock(LoopCond.getBlock()); EmitBlock(LoopCond.getBlock());
// When single byte coverage mode is enabled, add a counter to loop condition. // When single byte coverage mode is enabled, add a counter to loop condition.
@ -1238,8 +1239,6 @@ void CodeGenFunction::EmitDoStmt(const DoStmt &S,
// compares unequal to 0. The condition must be a scalar type. // compares unequal to 0. The condition must be a scalar type.
llvm::Value *BoolCondVal = EvaluateExprAsBool(S.getCond()); llvm::Value *BoolCondVal = EvaluateExprAsBool(S.getCond());
BreakContinueStack.pop_back();
// "do {} while (0)" is common in macros, avoid extra blocks. Be sure // "do {} while (0)" is common in macros, avoid extra blocks. Be sure
// to correctly handle break/continue though. // to correctly handle break/continue though.
llvm::ConstantInt *C = dyn_cast<llvm::ConstantInt>(BoolCondVal); llvm::ConstantInt *C = dyn_cast<llvm::ConstantInt>(BoolCondVal);
@ -1328,7 +1327,6 @@ void CodeGenFunction::EmitForStmt(const ForStmt &S,
Continue = CondDest; Continue = CondDest;
else if (!S.getConditionVariable()) else if (!S.getConditionVariable())
Continue = getJumpDestInCurrentScope("for.inc"); Continue = getJumpDestInCurrentScope("for.inc");
BreakContinueStack.push_back(BreakContinue(LoopExit, Continue));
if (S.getCond()) { if (S.getCond()) {
// If the for statement has a condition scope, emit the local variable // If the for statement has a condition scope, emit the local variable
@ -1339,7 +1337,6 @@ void CodeGenFunction::EmitForStmt(const ForStmt &S,
// We have entered the condition variable's scope, so we're now able to // We have entered the condition variable's scope, so we're now able to
// jump to the continue block. // jump to the continue block.
Continue = S.getInc() ? getJumpDestInCurrentScope("for.inc") : CondDest; Continue = S.getInc() ? getJumpDestInCurrentScope("for.inc") : CondDest;
BreakContinueStack.back().ContinueBlock = Continue;
} }
// When single byte coverage mode is enabled, add a counter to loop // When single byte coverage mode is enabled, add a counter to loop
@ -1381,7 +1378,6 @@ void CodeGenFunction::EmitForStmt(const ForStmt &S,
EmitBlock(ExitBlock); EmitBlock(ExitBlock);
EmitBranchThroughCleanup(LoopExit); EmitBranchThroughCleanup(LoopExit);
} }
EmitBlock(ForBody); EmitBlock(ForBody);
} else { } else {
// Treat it as a non-zero constant. Don't even create a new block for the // Treat it as a non-zero constant. Don't even create a new block for the
@ -1393,12 +1389,15 @@ void CodeGenFunction::EmitForStmt(const ForStmt &S,
incrementProfileCounter(S.getBody()); incrementProfileCounter(S.getBody());
else else
incrementProfileCounter(&S); incrementProfileCounter(&S);
BreakContinueStack.push_back(BreakContinue(LoopExit, Continue));
{ {
// Create a separate cleanup scope for the body, in case it is not // Create a separate cleanup scope for the body, in case it is not
// a compound statement. // a compound statement.
RunCleanupsScope BodyScope(*this); RunCleanupsScope BodyScope(*this);
EmitStmt(S.getBody()); EmitStmt(S.getBody());
} }
BreakContinueStack.pop_back();
// The last block in the loop's body (which unconditionally branches to the // The last block in the loop's body (which unconditionally branches to the
// `inc` block if there is one). // `inc` block if there is one).
@ -1412,8 +1411,6 @@ void CodeGenFunction::EmitForStmt(const ForStmt &S,
incrementProfileCounter(S.getInc()); incrementProfileCounter(S.getInc());
} }
BreakContinueStack.pop_back();
ConditionScope.ForceCleanup(); ConditionScope.ForceCleanup();
EmitStopPoint(&S); EmitStopPoint(&S);
@ -1518,6 +1515,8 @@ CodeGenFunction::EmitCXXForRangeStmt(const CXXForRangeStmt &S,
EmitStmt(S.getLoopVarStmt()); EmitStmt(S.getLoopVarStmt());
EmitStmt(S.getBody()); EmitStmt(S.getBody());
} }
BreakContinueStack.pop_back();
// The last block in the loop's body (which unconditionally branches to the // The last block in the loop's body (which unconditionally branches to the
// `inc` block if there is one). // `inc` block if there is one).
auto *FinalBodyBB = Builder.GetInsertBlock(); auto *FinalBodyBB = Builder.GetInsertBlock();
@ -1527,8 +1526,6 @@ CodeGenFunction::EmitCXXForRangeStmt(const CXXForRangeStmt &S,
EmitBlock(Continue.getBlock()); EmitBlock(Continue.getBlock());
EmitStmt(S.getInc()); EmitStmt(S.getInc());
BreakContinueStack.pop_back();
EmitBranch(CondBlock); EmitBranch(CondBlock);
ForScope.ForceCleanup(); ForScope.ForceCleanup();

View File

@ -1877,10 +1877,8 @@ Parser::ParseCXXCondition(StmtResult *InitStmt, SourceLocation Loc,
struct ForConditionScopeRAII { struct ForConditionScopeRAII {
Scope *S; Scope *S;
void enter(bool IsConditionVariable) { void enter(bool IsConditionVariable) {
if (S) { if (S)
S->AddFlags(Scope::BreakScope | Scope::ContinueScope);
S->setIsConditionVarScope(IsConditionVariable); S->setIsConditionVarScope(IsConditionVariable);
}
} }
~ForConditionScopeRAII() { ~ForConditionScopeRAII() {
if (S) if (S)

View File

@ -1728,12 +1728,10 @@ StmtResult Parser::ParseWhileStatement(SourceLocation *TrailingElseLoc) {
// while, for, and switch statements are local to the if, while, for, or // while, for, and switch statements are local to the if, while, for, or
// switch statement (including the controlled statement). // switch statement (including the controlled statement).
// //
unsigned ScopeFlags; unsigned ScopeFlags = 0;
if (C99orCXX) if (C99orCXX)
ScopeFlags = Scope::BreakScope | Scope::ContinueScope | ScopeFlags = Scope::DeclScope | Scope::ControlScope;
Scope::DeclScope | Scope::ControlScope;
else
ScopeFlags = Scope::BreakScope | Scope::ContinueScope;
ParseScope WhileScope(this, ScopeFlags); ParseScope WhileScope(this, ScopeFlags);
// Parse the condition. // Parse the condition.
@ -1744,6 +1742,8 @@ StmtResult Parser::ParseWhileStatement(SourceLocation *TrailingElseLoc) {
Sema::ConditionKind::Boolean, LParen, RParen)) Sema::ConditionKind::Boolean, LParen, RParen))
return StmtError(); return StmtError();
getCurScope()->AddFlags(Scope::BreakScope | Scope::ContinueScope);
// OpenACC Restricts a while-loop inside of certain construct/clause // OpenACC Restricts a while-loop inside of certain construct/clause
// combinations, so diagnose that here in OpenACC mode. // combinations, so diagnose that here in OpenACC mode.
SemaOpenACC::LoopInConstructRAII LCR{getActions().OpenACC()}; SemaOpenACC::LoopInConstructRAII LCR{getActions().OpenACC()};
@ -1838,6 +1838,8 @@ StmtResult Parser::ParseDoStatement() {
// A do-while expression is not a condition, so can't have attributes. // A do-while expression is not a condition, so can't have attributes.
DiagnoseAndSkipCXX11Attributes(); DiagnoseAndSkipCXX11Attributes();
DoScope.Exit();
SourceLocation Start = Tok.getLocation(); SourceLocation Start = Tok.getLocation();
ExprResult Cond = ParseExpression(); ExprResult Cond = ParseExpression();
if (!Cond.isUsable()) { if (!Cond.isUsable()) {
@ -1848,7 +1850,6 @@ StmtResult Parser::ParseDoStatement() {
Actions.getASTContext().BoolTy); Actions.getASTContext().BoolTy);
} }
T.consumeClose(); T.consumeClose();
DoScope.Exit();
if (Cond.isInvalid() || Body.isInvalid()) if (Cond.isInvalid() || Body.isInvalid())
return StmtError(); return StmtError();
@ -2123,9 +2124,6 @@ StmtResult Parser::ParseForStatement(SourceLocation *TrailingElseLoc) {
} }
} else { } else {
// We permit 'continue' and 'break' in the condition of a for loop.
getCurScope()->AddFlags(Scope::BreakScope | Scope::ContinueScope);
ExprResult SecondExpr = ParseExpression(); ExprResult SecondExpr = ParseExpression();
if (SecondExpr.isInvalid()) if (SecondExpr.isInvalid())
SecondPart = Sema::ConditionError(); SecondPart = Sema::ConditionError();
@ -2137,11 +2135,6 @@ StmtResult Parser::ParseForStatement(SourceLocation *TrailingElseLoc) {
} }
} }
// Enter a break / continue scope, if we didn't already enter one while
// parsing the second part.
if (!getCurScope()->isContinueScope())
getCurScope()->AddFlags(Scope::BreakScope | Scope::ContinueScope);
// Parse the third part of the for statement. // Parse the third part of the for statement.
if (!ForEach && !ForRangeInfo.ParsedForRangeDecl()) { if (!ForEach && !ForRangeInfo.ParsedForRangeDecl()) {
if (Tok.isNot(tok::semi)) { if (Tok.isNot(tok::semi)) {
@ -2164,6 +2157,8 @@ StmtResult Parser::ParseForStatement(SourceLocation *TrailingElseLoc) {
// Match the ')'. // Match the ')'.
T.consumeClose(); T.consumeClose();
getCurScope()->AddFlags(Scope::BreakScope | Scope::ContinueScope);
// C++ Coroutines [stmt.iter]: // C++ Coroutines [stmt.iter]:
// 'co_await' can only be used for a range-based for statement. // 'co_await' can only be used for a range-based for statement.
if (CoawaitLoc.isValid() && !ForRangeInfo.ParsedForRangeDecl()) { if (CoawaitLoc.isValid() && !ForRangeInfo.ParsedForRangeDecl()) {

View File

@ -33,12 +33,25 @@ int main(void) { // CHECK: File 0, [[@LINE]]:16 -> {{[0-9]+}}:2 = #0
} }
// CHECK-LABEL: break_continue_in_increment: // CHECK-LABEL: break_continue_in_increment:
// CHECK: [[@LINE+6]]:11 -> [[@LINE+6]]:45 = #1 /*
// CHECK: [[@LINE+5]]:18 -> [[@LINE+5]]:19 = #1 52:41 -> 57:2 = #0
// CHECK: [[@LINE+4]]:21 -> [[@LINE+4]]:26 = #2 53:10 -> 53:11 = ((#0 + #1) + #2)
// CHECK: [[@LINE+3]]:33 -> [[@LINE+3]]:41 = (#1 - #2) Branch,File 0, 53:10 -> 53:11 = #1, 0
// CHECK: [[@LINE+3]]:5 -> [[@LINE+3]]:6 = #1
53:13 -> 56:4 = #1
*/
// CHECK: [[@LINE+6]]:20 -> [[@LINE+6]]:21 = #2
// CHECK: [[@LINE+5]]:23 -> [[@LINE+5]]:28 = #3
// CHECK: [[@LINE+4]]:35 -> [[@LINE+4]]:43 = (#2 - #3)
// CHECK: [[@LINE+4]]:7 -> [[@LINE+4]]:8 = #2
void break_continue_in_increment(int x) { void break_continue_in_increment(int x) {
for (;; ({ if (x) break; else continue; })) while (1) {
; for (;; ({ if (x) break; else continue; }))
;
}
} }

View File

@ -0,0 +1,28 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
void f() {
while (({ continue; 1; })) {}
// expected-error@-1 {{'continue' statement not in loop statement}}
while (({ break; 1; })) {}
// expected-error@-1 {{'break' statement not in loop or switch statement}}
do {} while (({ break; 1; }));
// expected-error@-1 {{'break' statement not in loop or switch statement}}
do {} while (({ continue; 1;}));
// expected-error@-1 {{'continue' statement not in loop statement}}
for (({ continue; });;) {}
// expected-error@-1 {{'continue' statement not in loop statement}}
for (;({ continue; 1;});) {}
// expected-error@-1 {{'continue' statement not in loop statement}}
for (;;({ continue;})) {}
// expected-error@-1 {{'continue' statement not in loop statement}}
for (({ break;});;) {}
// expected-error@-1 {{'break' statement not in loop or switch statement}}
for (;({ break; 1;});) {}
// expected-error@-1 {{'break' statement not in loop or switch statement}}
for (;;({ break;})) {}
// expected-error@-1 {{'break' statement not in loop or switch statement}}
switch(({break;1;})){
// expected-error@-1 {{'break' statement not in loop or switch statement}}
case 1: break;
}
}