[clang] f94bbfe - [Clang][CodeGen] Fix `CanSkipVTablePointerInitialization` for dynamic classes with a trivial anonymous union (#84651)

via cfe-commits cfe-commits at lists.llvm.org
Mon Apr 8 15:24:12 PDT 2024


Author: Max Winkler
Date: 2024-04-08T15:24:08-07:00
New Revision: f94bbfed7cf08f60e20756dce8965d2c6ed70ea1

URL: https://github.com/llvm/llvm-project/commit/f94bbfed7cf08f60e20756dce8965d2c6ed70ea1
DIFF: https://github.com/llvm/llvm-project/commit/f94bbfed7cf08f60e20756dce8965d2c6ed70ea1.diff

LOG: [Clang][CodeGen] Fix `CanSkipVTablePointerInitialization` for dynamic classes with a trivial anonymous union (#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/release/18.x/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 and a
couple others.

Added: 
    

Modified: 
    clang/lib/CodeGen/CGClass.cpp
    clang/test/CodeGenCXX/skip-vtable-pointer-initialization.cpp

Removed: 
    


################################################################################
diff  --git a/clang/lib/CodeGen/CGClass.cpp b/clang/lib/CodeGen/CGClass.cpp
index 8c1c8ee455d2e6..b3077292f4a206 100644
--- a/clang/lib/CodeGen/CGClass.cpp
+++ b/clang/lib/CodeGen/CGClass.cpp
@@ -1404,7 +1404,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 c001ce9b755d14..714ce3e67be7c6 100644
--- a/clang/test/CodeGenCXX/skip-vtable-pointer-initialization.cpp
+++ b/clang/test/CodeGenCXX/skip-vtable-pointer-initialization.cpp
@@ -198,3 +198,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() {
+}
+
+}


        


More information about the cfe-commits mailing list