https://github.com/MaxEW707 created 
https://github.com/llvm/llvm-project/pull/84651

Hit this when trying upgrade an old project of mine. I couldn't find a 
corresponding existing issue for this when spelunking the open issues here on 
github.
Thankfully I can work-around it today with the `[[clang::no_destroy]]` 
attribute for my use case. However it should still be properly fixed.

### Issue and History ###

https://godbolt.org/z/EYnhce8MK for reference.
All subsequent text below refers to the example in the godbolt above.

Anonymous unions never have their destructor invoked automatically. Therefore 
we can skip vtable initialization of the destructor of a dynamic class if that 
destructor effectively does no work.

This worked previously as the following check would be hit and return true for 
the trivial anonymous union, 
https://github.com/llvm/llvm-project/blob/main/clang/lib/CodeGen/CGClass.cpp#L1348,
 resulting in the code skipping vtable initialization.

This was broken here 
https://github.com/llvm/llvm-project/commit/982bbf404eba2d968afda5c674d4821652159c53
 in relation to comments made on this review here 
https://reviews.llvm.org/D10508.

### Fixes ###

The check the code is doing is correct however the return value is inverted. We 
want to return true here since a field with anonymous union never has its 
destructor invoked and thus effectively has a trivial destructor body from the 
perspective of requiring vtable init in the parent dynamic class.

Also added some extra missing unit tests to test for this use case.


>From 28cbaad3c16e985306c7b977cb7d9e8e89c39a07 Mon Sep 17 00:00:00 2001
From: MaxEW707 <82551778+maxew...@users.noreply.github.com>
Date: Sat, 9 Mar 2024 15:40:52 -0500
Subject: [PATCH] Fix `CanSkipVTablePointerInitialization` for dynamic classes
 with an anonymous union

---
 clang/lib/CodeGen/CGClass.cpp                 |  2 +-
 .../skip-vtable-pointer-initialization.cpp    | 63 +++++++++++++++++++
 2 files changed, 64 insertions(+), 1 deletion(-)

diff --git a/clang/lib/CodeGen/CGClass.cpp b/clang/lib/CodeGen/CGClass.cpp
index d18f186ce5b415..ca3ac7142af9c0 100644
--- a/clang/lib/CodeGen/CGClass.cpp
+++ b/clang/lib/CodeGen/CGClass.cpp
@@ -1395,7 +1395,7 @@ FieldHasTrivialDestructorBody(ASTContext &Context,
 
   // The destructor for an implicit anonymous union member is never invoked.
   if (FieldClassDecl->isUnion() && FieldClassDecl->isAnonymousStructOrUnion())
-    return false;
+    return true;
 
   return HasTrivialDestructorBody(Context, FieldClassDecl, FieldClassDecl);
 }
diff --git a/clang/test/CodeGenCXX/skip-vtable-pointer-initialization.cpp 
b/clang/test/CodeGenCXX/skip-vtable-pointer-initialization.cpp
index eb8f21b57aa7b6..d99a45869fdb54 100644
--- a/clang/test/CodeGenCXX/skip-vtable-pointer-initialization.cpp
+++ b/clang/test/CodeGenCXX/skip-vtable-pointer-initialization.cpp
@@ -1,4 +1,5 @@
 // RUN: %clang_cc1 %s -triple=x86_64-apple-darwin10 -emit-llvm -o - | 
FileCheck %s
+// RUN: %clang_cc1 %s -triple=x86_64-pc-linux-gnu -emit-llvm -o - | FileCheck 
%s
 
 // See Test9 for test description.
 // CHECK: @_ZTTN5Test91BE = linkonce_odr unnamed_addr constant
@@ -198,3 +199,65 @@ struct C : virtual B {
 C::~C() {}
 
 }
+
+namespace Test10 {
+
+// Check that we don't initialize the vtable pointer in A::~A(), since the 
class has an anonymous union which
+// never has its destructor invoked.
+struct A {
+    virtual void f();
+    ~A();
+
+    union
+    {
+        int i;
+        unsigned u;
+    };
+};
+
+// CHECK-LABEL: define{{.*}} void @_ZN6Test101AD2Ev
+// CHECK-NOT: store ptr getelementptr inbounds ({ [3 x ptr] }, ptr 
@_ZTVN6Test101AE, i32 0, inrange i32 0, i32 2), ptr
+A::~A() {
+}
+
+}
+
+namespace Test11 {
+
+// Check that we don't initialize the vtable pointer in A::~A(), even if the 
base class has a non trivial destructor.
+struct Field {
+    ~Field();
+};
+
+struct A : public Field {
+    virtual void f();
+    ~A();
+};
+
+// CHECK-LABEL: define{{.*}} void @_ZN6Test111AD2Ev
+// CHECK-NOT: store ptr getelementptr inbounds ({ [3 x ptr] }, ptr 
@_ZTVN6Test111AE, i32 0, inrange i32 0, i32 2), ptr
+A::~A() {
+}
+
+}
+
+namespace Test12 {
+
+// Check that we don't initialize the vtable pointer in A::~A(), since the 
class has an anonymous struct with trivial fields.
+struct A {
+    virtual void f();
+    ~A();
+
+    struct
+    {
+        int i;
+        unsigned u;
+    };
+};
+
+// CHECK-LABEL: define{{.*}} void @_ZN6Test121AD2Ev
+// CHECK-NOT: store ptr getelementptr inbounds ({ [3 x ptr] }, ptr 
@_ZTVN6Test121AE, i32 0, inrange i32 0, i32 2), ptr
+A::~A() {
+}
+
+}

_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to