[CodeGen] Do not push a destructor cleanup for a struct that doesn't

have a non-trivial destructor.

This fixes a bug introduced in r328731 where CodeGen emits calls to
synthesized destructors for non-trivial C structs in C++ mode when the
struct passed to EmitCallArg doesn't have a non-trivial destructor.
Under Microsoft's ABI, ASTContext::isParamDestroyedInCallee currently
always returns true, so it's necessary to check whether the struct has a
non-trivial destructor before pushing a cleanup in EmitCallArg.

This fixes PR37146.

llvm-svn: 330304
This commit is contained in:
Akira Hatanaka 2018-04-18 23:33:15 +00:00
parent 54a33d7a27
commit 4ce0e5a892
2 changed files with 33 additions and 2 deletions

View File

@ -3541,13 +3541,20 @@ void CodeGenFunction::EmitCallArg(CallArgList &args, const Expr *E,
else
Slot = CreateAggTemp(type, "agg.tmp");
Slot.setExternallyDestructed();
bool DestroyedInCallee = true, NeedsEHCleanup = true;
if (const auto *RD = type->getAsCXXRecordDecl())
DestroyedInCallee = RD->hasNonTrivialDestructor();
else
NeedsEHCleanup = needsEHCleanup(type.isDestructedType());
if (DestroyedInCallee)
Slot.setExternallyDestructed();
EmitAggExpr(E, Slot);
RValue RV = Slot.asRValue();
args.add(RV, type);
if (type->getAsCXXRecordDecl() || needsEHCleanup(type.isDestructedType())) {
if (DestroyedInCallee && NeedsEHCleanup) {
// 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.

View File

@ -313,3 +313,27 @@ class_0::class_0() {
// WIN32: br label %[[SKIP_VBASE]]
// WIN32: [[SKIP_VBASE]]
}
namespace PR37146 {
// Check that IRGen doesn't emit calls to synthesized destructors for
// non-trival C structs.
// WIN32: define dso_local void @"?test@PR37146@@YAXXZ"()
// WIN32: call void @llvm.memset.p0i8.i32(
// WIN32: call i32 @"?getS@PR37146@@YA?AUS@1@XZ"(
// WIN32: call void @"?func@PR37146@@YAXUS@1@0@Z"(
// WIN32-NEXT: ret void
// WIN32-NEXT: {{^}$}}
struct S {
int f;
};
void func(S, S);
S getS();
void test() {
func(getS(), S());
}
}