[clang] Mark union member destructors referenced (PR #128866)

Maurice Heumann via cfe-commits cfe-commits at lists.llvm.org
Thu Feb 27 03:56:44 PST 2025


https://github.com/momo5502 updated https://github.com/llvm/llvm-project/pull/128866

>From 9234ac6c96f83977c32f2e90ebb553975dc209a5 Mon Sep 17 00:00:00 2001
From: Maurice Heumann <maurice.heumann at wibu.com>
Date: Wed, 26 Feb 2025 14:31:47 +0100
Subject: [PATCH] Instantiate destructors from initialized anonymous union
 fields

---
 clang/include/clang/Sema/Sema.h               |  2 +
 clang/lib/Sema/SemaDeclCXX.cpp                | 87 +++++++++++--------
 .../test/SemaCXX/union-member-destructor.cpp  | 14 +++
 3 files changed, 68 insertions(+), 35 deletions(-)
 create mode 100644 clang/test/SemaCXX/union-member-destructor.cpp

diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index 476abe86cb2d2..6d3879985c6ce 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -5432,6 +5432,8 @@ class Sema final : public SemaBase {
   void MarkBaseAndMemberDestructorsReferenced(SourceLocation Loc,
                                               CXXRecordDecl *Record);
 
+  void MarkFieldDestructorReferenced(SourceLocation Loc, FieldDecl *Field);
+
   /// Mark destructors of virtual bases of this class referenced. In the Itanium
   /// C++ ABI, this is done when emitting a destructor for any non-abstract
   /// class. In the Microsoft C++ ABI, this is done any time a class's
diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp
index 664d48ccbc382..842c4a866fc88 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -5451,10 +5451,23 @@ bool Sema::SetCtorInitializers(CXXConstructorDecl *Constructor, bool AnyErrors,
            NumInitializers * sizeof(CXXCtorInitializer*));
     Constructor->setCtorInitializers(baseOrMemberInitializers);
 
+    SourceLocation Location = Constructor->getLocation();
+
+    for (CXXCtorInitializer *Initializer : Info.AllToInit) {
+      FieldDecl *Field = Initializer->getAnyMember();
+      if (!Field)
+        continue;
+
+      RecordDecl *FieldRecordDecl = Field->getParent();
+      if (!FieldRecordDecl->isUnion() ||
+          !FieldRecordDecl->isAnonymousStructOrUnion())
+        continue;
+
+      MarkFieldDestructorReferenced(Location, Field);
+    }
     // Constructors implicitly reference the base and member
     // destructors.
-    MarkBaseAndMemberDestructorsReferenced(Constructor->getLocation(),
-                                           Constructor->getParent());
+    MarkBaseAndMemberDestructorsReferenced(Location, Constructor->getParent());
   }
 
   return HadError;
@@ -5759,6 +5772,42 @@ void Sema::ActOnMemInitializers(Decl *ConstructorDecl,
   DiagnoseUninitializedFields(*this, Constructor);
 }
 
+void Sema::MarkFieldDestructorReferenced(SourceLocation Location,
+                                         FieldDecl *Field) {
+  if (Field->isInvalidDecl())
+    return;
+
+  // Don't destroy incomplete or zero-length arrays.
+  if (isIncompleteOrZeroLengthArrayType(Context, Field->getType()))
+    return;
+
+  QualType FieldType = Context.getBaseElementType(Field->getType());
+
+  const RecordType *RT = FieldType->getAs<RecordType>();
+  if (!RT)
+    return;
+
+  CXXRecordDecl *FieldClassDecl = cast<CXXRecordDecl>(RT->getDecl());
+  if (FieldClassDecl->isInvalidDecl())
+    return;
+  if (FieldClassDecl->hasIrrelevantDestructor())
+    return;
+  // The destructor for an implicit anonymous union member is never invoked.
+  if (FieldClassDecl->isUnion() && FieldClassDecl->isAnonymousStructOrUnion())
+    return;
+
+  CXXDestructorDecl *Dtor = LookupDestructor(FieldClassDecl);
+  // Dtor might still be missing, e.g because it's invalid.
+  if (!Dtor)
+    return;
+  CheckDestructorAccess(Field->getLocation(), Dtor,
+                        PDiag(diag::err_access_dtor_field)
+                            << Field->getDeclName() << FieldType);
+
+  MarkFunctionReferenced(Location, Dtor);
+  DiagnoseUseOfDecl(Dtor, Location);
+}
+
 void
 Sema::MarkBaseAndMemberDestructorsReferenced(SourceLocation Location,
                                              CXXRecordDecl *ClassDecl) {
@@ -5774,39 +5823,7 @@ Sema::MarkBaseAndMemberDestructorsReferenced(SourceLocation Location,
 
   // Non-static data members.
   for (auto *Field : ClassDecl->fields()) {
-    if (Field->isInvalidDecl())
-      continue;
-
-    // Don't destroy incomplete or zero-length arrays.
-    if (isIncompleteOrZeroLengthArrayType(Context, Field->getType()))
-      continue;
-
-    QualType FieldType = Context.getBaseElementType(Field->getType());
-
-    const RecordType* RT = FieldType->getAs<RecordType>();
-    if (!RT)
-      continue;
-
-    CXXRecordDecl *FieldClassDecl = cast<CXXRecordDecl>(RT->getDecl());
-    if (FieldClassDecl->isInvalidDecl())
-      continue;
-    if (FieldClassDecl->hasIrrelevantDestructor())
-      continue;
-    // The destructor for an implicit anonymous union member is never invoked.
-    if (FieldClassDecl->isUnion() && FieldClassDecl->isAnonymousStructOrUnion())
-      continue;
-
-    CXXDestructorDecl *Dtor = LookupDestructor(FieldClassDecl);
-    // Dtor might still be missing, e.g because it's invalid.
-    if (!Dtor)
-      continue;
-    CheckDestructorAccess(Field->getLocation(), Dtor,
-                          PDiag(diag::err_access_dtor_field)
-                            << Field->getDeclName()
-                            << FieldType);
-
-    MarkFunctionReferenced(Location, Dtor);
-    DiagnoseUseOfDecl(Dtor, Location);
+    MarkFieldDestructorReferenced(Location, Field);
   }
 
   // We only potentially invoke the destructors of potentially constructed
diff --git a/clang/test/SemaCXX/union-member-destructor.cpp b/clang/test/SemaCXX/union-member-destructor.cpp
new file mode 100644
index 0000000000000..ba64983220ea5
--- /dev/null
+++ b/clang/test/SemaCXX/union-member-destructor.cpp
@@ -0,0 +1,14 @@
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
+
+template <class T> struct VSX {
+  ~VSX() { static_assert(sizeof(T) != 4, ""); } // expected-error {{static assertion failed due to requirement 'sizeof(int) != 4':}} \
+                                                // expected-note {{expression evaluates to '4 != 4'}}
+};
+struct VS {
+  union {
+    VSX<int> _Tail;
+  };
+  ~VS() { }
+  VS(short);
+};
+VS::VS(short) : _Tail() { } // expected-note {{in instantiation of member function 'VSX<int>::~VSX' requested here}}



More information about the cfe-commits mailing list