[CodeGen] Do not push a destructor cleanup for a struct that doesn't
authorAkira Hatanaka <ahatanaka@apple.com>
Wed, 18 Apr 2018 23:33:15 +0000 (23:33 +0000)
committerAkira Hatanaka <ahatanaka@apple.com>
Wed, 18 Apr 2018 23:33:15 +0000 (23:33 +0000)
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

clang/lib/CodeGen/CGCall.cpp
clang/test/CodeGenCXX/microsoft-abi-eh-cleanups.cpp

index 6797a54..27aa69d 100644 (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.
index 116ce09..6682faf 100644 (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());
+}
+
+}