Skip to content
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

Re-apply "Emit missing cleanups for stmt-expr" and other commits #89154

Merged
merged 7 commits into from
Apr 29, 2024
Merged
27 changes: 5 additions & 22 deletions clang/lib/CodeGen/CGCleanup.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1169,25 +1169,6 @@ void CodeGenFunction::EmitBranchThroughCleanup(JumpDest Dest) {
Builder.ClearInsertionPoint();
}

static bool IsUsedAsNormalCleanup(EHScopeStack &EHStack,
EHScopeStack::stable_iterator C) {
// If we needed a normal block for any reason, that counts.
if (cast<EHCleanupScope>(*EHStack.find(C)).getNormalBlock())
return true;

// Check whether any enclosed cleanups were needed.
for (EHScopeStack::stable_iterator
I = EHStack.getInnermostNormalCleanup();
I != C; ) {
assert(C.strictlyEncloses(I));
EHCleanupScope &S = cast<EHCleanupScope>(*EHStack.find(I));
if (S.getNormalBlock()) return true;
I = S.getEnclosingNormalCleanup();
}

return false;
}

static bool IsUsedAsEHCleanup(EHScopeStack &EHStack,
EHScopeStack::stable_iterator cleanup) {
// If we needed an EH block for any reason, that counts.
Expand Down Expand Up @@ -1236,8 +1217,7 @@ static void SetupCleanupBlockActivation(CodeGenFunction &CGF,
// Calculate whether the cleanup was used:

// - as a normal cleanup
if (Scope.isNormalCleanup() &&
(isActivatedInConditional || IsUsedAsNormalCleanup(CGF.EHStack, C))) {
if (Scope.isNormalCleanup()) {
Scope.setTestFlagInNormalCleanup();
needFlag = true;
}
Expand All @@ -1250,13 +1230,16 @@ static void SetupCleanupBlockActivation(CodeGenFunction &CGF,
}

// If it hasn't yet been used as either, we're done.
if (!needFlag) return;
if (!needFlag)
return;

Address var = Scope.getActiveFlag();
if (!var.isValid()) {
CodeGenFunction::AllocaTrackerRAII AllocaTracker(CGF);
var = CGF.CreateTempAlloca(CGF.Builder.getInt1Ty(), CharUnits::One(),
"cleanup.isactive");
Scope.setActiveFlag(var);
Scope.AddAuxAllocas(AllocaTracker.Take());

assert(dominatingIP && "no existing variable and no dominating IP!");

Expand Down
69 changes: 69 additions & 0 deletions clang/test/CodeGenCXX/control-flow-in-stmt-expr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -407,3 +407,72 @@ void TrivialABI() {
0;
}));
}

namespace CleanupFlag {
struct A {
A() {}
~A() {}
};

struct B {
B(const A&) {}
B() {}
~B() {}
};

struct S {
A a;
B b;
};

int AcceptS(S s);

void Accept2(int x, int y);

void InactiveNormalCleanup() {
// CHECK-LABEL: define {{.*}}InactiveNormalCleanupEv()

// The first A{} below is an inactive normal cleanup which
// is not popped from EHStack on deactivation. This needs an
// "active" cleanup flag.

// CHECK: [[ACTIVE:%cleanup.isactive.*]] = alloca i1, align 1
// CHECK: call void [[A_CTOR:@.*AC1Ev]]
// CHECK: store i1 true, ptr [[ACTIVE]], align 1
// CHECK: call void [[A_CTOR]]
// CHECK: call void [[B_CTOR:@.*BC1ERKNS_1AE]]
// CHECK: store i1 false, ptr [[ACTIVE]], align 1
// CHECK: call noundef i32 [[ACCEPTS:@.*AcceptSENS_1SE]]
Accept2(AcceptS({.a = A{}, .b = A{}}), ({
if (foo()) return;
// CHECK: if.then:
// CHECK: br label %cleanup
0;
// CHECK: if.end:
// CHECK: call void [[ACCEPT2:@.*Accept2Eii]]
// CHECK: br label %cleanup
}));
// CHECK: cleanup:
// CHECK: call void [[S_DTOR:@.*SD1Ev]]
// CHECK: call void [[A_DTOR:@.*AD1Ev]]
// CHECK: %cleanup.is_active = load i1, ptr [[ACTIVE]]
// CHECK: br i1 %cleanup.is_active, label %cleanup.action, label %cleanup.done

// CHECK: cleanup.action:
// CHECK: call void [[A_DTOR]]

// The "active" cleanup flag is not required for unused cleanups.
Accept2(AcceptS({.a = A{}, .b = A{}}), 0);
// CHECK: cleanup.cont:
// CHECK: call void [[A_CTOR]]
// CHECK-NOT: store i1 true
// CHECK: call void [[A_CTOR]]
// CHECK: call void [[B_CTOR]]
// CHECK-NOT: store i1 false
// CHECK: call noundef i32 [[ACCEPTS]]
// CHECK: call void [[ACCEPT2]]
// CHECK: call void [[S_DTOR]]
// CHECK: call void [[A_DTOR]]
// CHECK: br label %return
}
} // namespace CleanupFlag