Skip to content

Commit 60b3cc6

Browse files
[CodeGen] Fix cleanup attribute for C89 for-loop init variables (llvm#156643)
In C89, for-init variables have function scope, so cleanup should occur at function exit, not loop exit. This implements deferred cleanup registration for C89 mode while preserving C99+ behavior. Fixes llvm#154624
1 parent 3b456fa commit 60b3cc6

File tree

2 files changed

+27
-4
lines changed

2 files changed

+27
-4
lines changed

clang/lib/CodeGen/CGStmt.cpp

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1291,7 +1291,9 @@ void CodeGenFunction::EmitForStmt(const ForStmt &S,
12911291
ArrayRef<const Attr *> ForAttrs) {
12921292
JumpDest LoopExit = getJumpDestInCurrentScope("for.end");
12931293

1294-
LexicalScope ForScope(*this, S.getSourceRange());
1294+
std::optional<LexicalScope> ForScope;
1295+
if (getLangOpts().C99 || getLangOpts().CPlusPlus)
1296+
ForScope.emplace(*this, S.getSourceRange());
12951297

12961298
// Evaluate the first part before the loop.
12971299
if (S.getInit())
@@ -1350,7 +1352,7 @@ void CodeGenFunction::EmitForStmt(const ForStmt &S,
13501352
llvm::BasicBlock *ExitBlock = LoopExit.getBlock();
13511353
// If there are any cleanups between here and the loop-exit scope,
13521354
// create a block to stage a loop exit along.
1353-
if (ForScope.requiresCleanups())
1355+
if (ForScope && ForScope->requiresCleanups())
13541356
ExitBlock = createBasicBlock("for.cond.cleanup");
13551357

13561358
// As long as the condition is true, iterate the loop.
@@ -1419,7 +1421,8 @@ void CodeGenFunction::EmitForStmt(const ForStmt &S,
14191421
EmitStopPoint(&S);
14201422
EmitBranch(CondBlock);
14211423

1422-
ForScope.ForceCleanup();
1424+
if (ForScope)
1425+
ForScope->ForceCleanup();
14231426

14241427
LoopStack.pop();
14251428

clang/test/CodeGen/attr-cleanup.c

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,27 @@
1-
// RUN: %clang_cc1 -emit-llvm %s -o %t
1+
// RUN: %clang_cc1 -std=c89 -emit-llvm %s -o - | FileCheck %s --check-prefix=C89
2+
// RUN: %clang_cc1 -std=c99 -emit-llvm %s -o - | FileCheck %s --check-prefix=C99
23

34
void f(void* arg);
45
void g(void) {
56
__attribute__((cleanup(f))) void *g;
67
}
78

9+
void cleaner(int *p);
10+
11+
// C89-LABEL: define{{.*}} void @test_nested_for_loop_cleanup()
12+
// C99-LABEL: define{{.*}} void @test_nested_for_loop_cleanup()
13+
void test_nested_for_loop_cleanup(void) {
14+
for (int i = 10; 0;) {
15+
for (__attribute__((cleanup(cleaner))) int j = 20; 0;)
16+
;
17+
i = 5; // Some operation after inner loop
18+
}
19+
}
20+
21+
// C89: for.end:
22+
// C89-NEXT: store i32 5, ptr %i, align 4
23+
// C89-NEXT: call void @cleaner(ptr noundef %j)
24+
25+
// C99: for.cond.cleanup:
26+
// C99-NEXT: call void @cleaner(ptr noundef %j)
27+
// C99-NEXT: br label %for.end

0 commit comments

Comments
 (0)