Skip to content

Commit 5a46123

Browse files
authored
Fix missing dtor in function calls accepting trivial ABI structs (llvm#88751)
Fixes llvm#88478 Promoting the `EHCleanup` to `NormalAndEHCleanup` in `EmitCallArgs` surfaced another bug with deactivation of normal cleanups. Here we missed emitting CPP scope ends for deactivated normal cleanups. This patch also fixes that bug. We missed emitting CPP scope ends because we remove the `fallthrough` (clears the insertion point) before deactivating normal cleanups. This is to make the emitted "normal" cleanup code unreachable. But we still need to emit CPP scope ends in the original basic block even for a deactivated normal cleanup. (This worked correctly before we did not remove `fallthrough` for `EHCleanup`s).
1 parent 40dd3aa commit 5a46123

File tree

4 files changed

+48
-21
lines changed

4 files changed

+48
-21
lines changed

clang/lib/CodeGen/CGCall.cpp

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4694,11 +4694,11 @@ void CodeGenFunction::EmitCallArg(CallArgList &args, const Expr *E,
46944694
AggValueSlot Slot = args.isUsingInAlloca()
46954695
? createPlaceholderSlot(*this, type) : CreateAggTemp(type, "agg.tmp");
46964696

4697-
bool DestroyedInCallee = true, NeedsEHCleanup = true;
4697+
bool DestroyedInCallee = true, NeedsCleanup = true;
46984698
if (const auto *RD = type->getAsCXXRecordDecl())
46994699
DestroyedInCallee = RD->hasNonTrivialDestructor();
47004700
else
4701-
NeedsEHCleanup = needsEHCleanup(type.isDestructedType());
4701+
NeedsCleanup = type.isDestructedType();
47024702

47034703
if (DestroyedInCallee)
47044704
Slot.setExternallyDestructed();
@@ -4707,14 +4707,15 @@ void CodeGenFunction::EmitCallArg(CallArgList &args, const Expr *E,
47074707
RValue RV = Slot.asRValue();
47084708
args.add(RV, type);
47094709

4710-
if (DestroyedInCallee && NeedsEHCleanup) {
4710+
if (DestroyedInCallee && NeedsCleanup) {
47114711
// Create a no-op GEP between the placeholder and the cleanup so we can
47124712
// RAUW it successfully. It also serves as a marker of the first
47134713
// instruction where the cleanup is active.
4714-
pushFullExprCleanup<DestroyUnpassedArg>(EHCleanup, Slot.getAddress(),
4715-
type);
4714+
pushFullExprCleanup<DestroyUnpassedArg>(NormalAndEHCleanup,
4715+
Slot.getAddress(), type);
47164716
// This unreachable is a temporary marker which will be removed later.
4717-
llvm::Instruction *IsActive = Builder.CreateUnreachable();
4717+
llvm::Instruction *IsActive =
4718+
Builder.CreateFlagLoad(llvm::Constant::getNullValue(Int8PtrTy));
47184719
args.addArgCleanupDeactivation(EHStack.stable_begin(), IsActive);
47194720
}
47204721
return;

clang/lib/CodeGen/CGCleanup.cpp

Lines changed: 23 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -634,12 +634,19 @@ static void destroyOptimisticNormalEntry(CodeGenFunction &CGF,
634634
/// Pops a cleanup block. If the block includes a normal cleanup, the
635635
/// current insertion point is threaded through the cleanup, as are
636636
/// any branch fixups on the cleanup.
637-
void CodeGenFunction::PopCleanupBlock(bool FallthroughIsBranchThrough) {
637+
void CodeGenFunction::PopCleanupBlock(bool FallthroughIsBranchThrough,
638+
bool ForDeactivation) {
638639
assert(!EHStack.empty() && "cleanup stack is empty!");
639640
assert(isa<EHCleanupScope>(*EHStack.begin()) && "top not a cleanup!");
640641
EHCleanupScope &Scope = cast<EHCleanupScope>(*EHStack.begin());
641642
assert(Scope.getFixupDepth() <= EHStack.getNumBranchFixups());
642643

644+
// If we are deactivating a normal cleanup, we need to pretend that the
645+
// fallthrough is unreachable. We restore this IP before returning.
646+
CGBuilderTy::InsertPoint NormalDeactivateOrigIP;
647+
if (ForDeactivation && (Scope.isNormalCleanup() || !getLangOpts().EHAsynch)) {
648+
NormalDeactivateOrigIP = Builder.saveAndClearIP();
649+
}
643650
// Remember activation information.
644651
bool IsActive = Scope.isActive();
645652
Address NormalActiveFlag =
@@ -729,6 +736,8 @@ void CodeGenFunction::PopCleanupBlock(bool FallthroughIsBranchThrough) {
729736
EHStack.popCleanup(); // safe because there are no fixups
730737
assert(EHStack.getNumBranchFixups() == 0 ||
731738
EHStack.hasNormalCleanups());
739+
if (NormalDeactivateOrigIP.isSet())
740+
Builder.restoreIP(NormalDeactivateOrigIP);
732741
return;
733742
}
734743

@@ -765,9 +774,16 @@ void CodeGenFunction::PopCleanupBlock(bool FallthroughIsBranchThrough) {
765774
if (!RequiresNormalCleanup) {
766775
// Mark CPP scope end for passed-by-value Arg temp
767776
// per Windows ABI which is "normally" Cleanup in callee
768-
if (IsEHa && getInvokeDest() && Builder.GetInsertBlock()) {
769-
if (Personality.isMSVCXXPersonality())
777+
if (IsEHa && getInvokeDest()) {
778+
// If we are deactivating a normal cleanup then we don't have a
779+
// fallthrough. Restore original IP to emit CPP scope ends in the correct
780+
// block.
781+
if (NormalDeactivateOrigIP.isSet())
782+
Builder.restoreIP(NormalDeactivateOrigIP);
783+
if (Personality.isMSVCXXPersonality() && Builder.GetInsertBlock())
770784
EmitSehCppScopeEnd();
785+
if (NormalDeactivateOrigIP.isSet())
786+
NormalDeactivateOrigIP = Builder.saveAndClearIP();
771787
}
772788
destroyOptimisticNormalEntry(*this, Scope);
773789
Scope.MarkEmitted();
@@ -992,6 +1008,8 @@ void CodeGenFunction::PopCleanupBlock(bool FallthroughIsBranchThrough) {
9921008
}
9931009
}
9941010

1011+
if (NormalDeactivateOrigIP.isSet())
1012+
Builder.restoreIP(NormalDeactivateOrigIP);
9951013
assert(EHStack.hasNormalCleanups() || EHStack.getNumBranchFixups() == 0);
9961014

9971015
// Emit the EH cleanup if required.
@@ -1281,17 +1299,8 @@ void CodeGenFunction::DeactivateCleanupBlock(EHScopeStack::stable_iterator C,
12811299
// to the current RunCleanupsScope.
12821300
if (C == EHStack.stable_begin() &&
12831301
CurrentCleanupScopeDepth.strictlyEncloses(C)) {
1284-
// Per comment below, checking EHAsynch is not really necessary
1285-
// it's there to assure zero-impact w/o EHAsynch option
1286-
if (!Scope.isNormalCleanup() && getLangOpts().EHAsynch) {
1287-
PopCleanupBlock();
1288-
} else {
1289-
// If it's a normal cleanup, we need to pretend that the
1290-
// fallthrough is unreachable.
1291-
CGBuilderTy::InsertPoint SavedIP = Builder.saveAndClearIP();
1292-
PopCleanupBlock();
1293-
Builder.restoreIP(SavedIP);
1294-
}
1302+
PopCleanupBlock(/*FallthroughIsBranchThrough=*/false,
1303+
/*ForDeactivation=*/true);
12951304
return;
12961305
}
12971306

clang/lib/CodeGen/CodeGenFunction.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -957,7 +957,8 @@ class CodeGenFunction : public CodeGenTypeCache {
957957

958958
/// PopCleanupBlock - Will pop the cleanup entry on the stack and
959959
/// process all branch fixups.
960-
void PopCleanupBlock(bool FallThroughIsBranchThrough = false);
960+
void PopCleanupBlock(bool FallThroughIsBranchThrough = false,
961+
bool ForDeactivation = false);
961962

962963
/// DeactivateCleanupBlock - Deactivates the given cleanup block.
963964
/// The block cannot be reactivated. Pops it if it's the top of the

clang/test/CodeGenCXX/control-flow-in-stmt-expr.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -391,3 +391,19 @@ void ArrayInitWithContinue() {
391391
})};
392392
}
393393
}
394+
395+
struct [[clang::trivial_abi]] HasTrivialABI {
396+
HasTrivialABI();
397+
~HasTrivialABI();
398+
};
399+
void AcceptTrivialABI(HasTrivialABI, int);
400+
void TrivialABI() {
401+
// CHECK-LABEL: define dso_local void @_Z10TrivialABIv()
402+
AcceptTrivialABI(HasTrivialABI(), ({
403+
if (foo()) return;
404+
// CHECK: if.then:
405+
// CHECK-NEXT: call void @_ZN13HasTrivialABID1Ev
406+
// CHECK-NEXT: br label %return
407+
0;
408+
}));
409+
}

0 commit comments

Comments
 (0)