Skip to content

Fix missing dtor in function calls accepting trivial ABI structs #88751

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

Merged
merged 1 commit into from
Apr 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 7 additions & 6 deletions clang/lib/CodeGen/CGCall.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4694,11 +4694,11 @@ void CodeGenFunction::EmitCallArg(CallArgList &args, const Expr *E,
AggValueSlot Slot = args.isUsingInAlloca()
? createPlaceholderSlot(*this, type) : CreateAggTemp(type, "agg.tmp");

bool DestroyedInCallee = true, NeedsEHCleanup = true;
bool DestroyedInCallee = true, NeedsCleanup = true;
if (const auto *RD = type->getAsCXXRecordDecl())
DestroyedInCallee = RD->hasNonTrivialDestructor();
else
NeedsEHCleanup = needsEHCleanup(type.isDestructedType());
NeedsCleanup = type.isDestructedType();

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

if (DestroyedInCallee && NeedsEHCleanup) {
if (DestroyedInCallee && NeedsCleanup) {
// Create a no-op GEP between the placeholder and the cleanup so we can
// RAUW it successfully. It also serves as a marker of the first
// instruction where the cleanup is active.
pushFullExprCleanup<DestroyUnpassedArg>(EHCleanup, Slot.getAddress(),
type);
pushFullExprCleanup<DestroyUnpassedArg>(NormalAndEHCleanup,
Slot.getAddress(), type);
// This unreachable is a temporary marker which will be removed later.
llvm::Instruction *IsActive = Builder.CreateUnreachable();
llvm::Instruction *IsActive =
Builder.CreateFlagLoad(llvm::Constant::getNullValue(Int8PtrTy));
args.addArgCleanupDeactivation(EHStack.stable_begin(), IsActive);
}
return;
Expand Down
37 changes: 23 additions & 14 deletions clang/lib/CodeGen/CGCleanup.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -634,12 +634,19 @@ static void destroyOptimisticNormalEntry(CodeGenFunction &CGF,
/// Pops a cleanup block. If the block includes a normal cleanup, the
/// current insertion point is threaded through the cleanup, as are
/// any branch fixups on the cleanup.
void CodeGenFunction::PopCleanupBlock(bool FallthroughIsBranchThrough) {
void CodeGenFunction::PopCleanupBlock(bool FallthroughIsBranchThrough,
bool ForDeactivation) {
assert(!EHStack.empty() && "cleanup stack is empty!");
assert(isa<EHCleanupScope>(*EHStack.begin()) && "top not a cleanup!");
EHCleanupScope &Scope = cast<EHCleanupScope>(*EHStack.begin());
assert(Scope.getFixupDepth() <= EHStack.getNumBranchFixups());

// If we are deactivating a normal cleanup, we need to pretend that the
// fallthrough is unreachable. We restore this IP before returning.
CGBuilderTy::InsertPoint NormalDeactivateOrigIP;
if (ForDeactivation && (Scope.isNormalCleanup() || !getLangOpts().EHAsynch)) {
NormalDeactivateOrigIP = Builder.saveAndClearIP();
}
// Remember activation information.
bool IsActive = Scope.isActive();
Address NormalActiveFlag =
Expand Down Expand Up @@ -729,6 +736,8 @@ void CodeGenFunction::PopCleanupBlock(bool FallthroughIsBranchThrough) {
EHStack.popCleanup(); // safe because there are no fixups
assert(EHStack.getNumBranchFixups() == 0 ||
EHStack.hasNormalCleanups());
if (NormalDeactivateOrigIP.isSet())
Builder.restoreIP(NormalDeactivateOrigIP);
return;
}

Expand Down Expand Up @@ -765,9 +774,16 @@ void CodeGenFunction::PopCleanupBlock(bool FallthroughIsBranchThrough) {
if (!RequiresNormalCleanup) {
// Mark CPP scope end for passed-by-value Arg temp
// per Windows ABI which is "normally" Cleanup in callee
if (IsEHa && getInvokeDest() && Builder.GetInsertBlock()) {
if (Personality.isMSVCXXPersonality())
if (IsEHa && getInvokeDest()) {
// If we are deactivating a normal cleanup then we don't have a
// fallthrough. Restore original IP to emit CPP scope ends in the correct
// block.
if (NormalDeactivateOrigIP.isSet())
Builder.restoreIP(NormalDeactivateOrigIP);
if (Personality.isMSVCXXPersonality() && Builder.GetInsertBlock())
EmitSehCppScopeEnd();
if (NormalDeactivateOrigIP.isSet())
NormalDeactivateOrigIP = Builder.saveAndClearIP();
}
destroyOptimisticNormalEntry(*this, Scope);
Scope.MarkEmitted();
Expand Down Expand Up @@ -992,6 +1008,8 @@ void CodeGenFunction::PopCleanupBlock(bool FallthroughIsBranchThrough) {
}
}

if (NormalDeactivateOrigIP.isSet())
Builder.restoreIP(NormalDeactivateOrigIP);
assert(EHStack.hasNormalCleanups() || EHStack.getNumBranchFixups() == 0);

// Emit the EH cleanup if required.
Expand Down Expand Up @@ -1281,17 +1299,8 @@ void CodeGenFunction::DeactivateCleanupBlock(EHScopeStack::stable_iterator C,
// to the current RunCleanupsScope.
if (C == EHStack.stable_begin() &&
CurrentCleanupScopeDepth.strictlyEncloses(C)) {
// Per comment below, checking EHAsynch is not really necessary
// it's there to assure zero-impact w/o EHAsynch option
if (!Scope.isNormalCleanup() && getLangOpts().EHAsynch) {
PopCleanupBlock();
} else {
// If it's a normal cleanup, we need to pretend that the
// fallthrough is unreachable.
CGBuilderTy::InsertPoint SavedIP = Builder.saveAndClearIP();
PopCleanupBlock();
Builder.restoreIP(SavedIP);
}
PopCleanupBlock(/*FallthroughIsBranchThrough=*/false,
/*ForDeactivation=*/true);
return;
}

Expand Down
3 changes: 2 additions & 1 deletion clang/lib/CodeGen/CodeGenFunction.h
Original file line number Diff line number Diff line change
Expand Up @@ -957,7 +957,8 @@ class CodeGenFunction : public CodeGenTypeCache {

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

/// DeactivateCleanupBlock - Deactivates the given cleanup block.
/// The block cannot be reactivated. Pops it if it's the top of the
Expand Down
16 changes: 16 additions & 0 deletions clang/test/CodeGenCXX/control-flow-in-stmt-expr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -362,3 +362,19 @@ void ArrayInitWithContinue() {
})};
}
}

struct [[clang::trivial_abi]] HasTrivialABI {
HasTrivialABI();
~HasTrivialABI();
};
void AcceptTrivialABI(HasTrivialABI, int);
void TrivialABI() {
// CHECK-LABEL: define dso_local void @_Z10TrivialABIv()
AcceptTrivialABI(HasTrivialABI(), ({
if (foo()) return;
// CHECK: if.then:
// CHECK-NEXT: call void @_ZN13HasTrivialABID1Ev
// CHECK-NEXT: br label %return
0;
}));
}