[clang] [Sema] Instantiate destructors for initialized anonymous union fields (PR #128866)
Maurice Heumann via cfe-commits
cfe-commits at lists.llvm.org
Fri Feb 28 00:11:14 PST 2025
https://github.com/momo5502 updated https://github.com/llvm/llvm-project/pull/128866
>From 4353dbd9acc6c3e577b9aa65f5628602cf015caf 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 | 95 ++++++++++++-------
.../test/SemaCXX/union-member-destructor.cpp | 48 ++++++++++
3 files changed, 110 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..5eafc539dd0fc 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -5451,10 +5451,31 @@ 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 *Parent = Field->getParent();
+
+ while (Parent) {
+ if (Parent->isUnion()) {
+ MarkFieldDestructorReferenced(Location, Field);
+ break;
+ }
+
+ if (!Parent->isAnonymousStructOrUnion() || Parent == ClassDecl) {
+ break;
+ }
+
+ Parent = cast<RecordDecl>(Parent->getDeclContext());
+ }
+ }
// Constructors implicitly reference the base and member
// destructors.
- MarkBaseAndMemberDestructorsReferenced(Constructor->getLocation(),
- Constructor->getParent());
+ MarkBaseAndMemberDestructorsReferenced(Location, Constructor->getParent());
}
return HadError;
@@ -5759,6 +5780,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 +5831,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..cdb704a461e84
--- /dev/null
+++ b/clang/test/SemaCXX/union-member-destructor.cpp
@@ -0,0 +1,48 @@
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
+
+namespace t1{
+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 't1::VSX<int>::~VSX' requested here}}
+}
+
+
+namespace t2 {
+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 {
+ struct {
+ VSX<int> _Tail;
+ };
+ };
+ ~VS() { }
+ VS(short);
+};
+VS::VS(short) : _Tail() { } // expected-note {{in instantiation of member function 't2::VSX<int>::~VSX' requested here}}
+}
+
+
+namespace t3 {
+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'}}
+};
+union VS {
+ VSX<int> _Tail;
+ ~VS() { }
+ VS(short);
+};
+VS::VS(short) : _Tail() { } // expected-note {{in instantiation of member function 't3::VSX<int>::~VSX' requested here}}
+}
\ No newline at end of file
More information about the cfe-commits
mailing list