Skip to content

Commit bb4091d

Browse files
committed
Instantiate destructors from initialized anonymous union fields
1 parent 6c87ec4 commit bb4091d

File tree

4 files changed

+113
-38
lines changed

4 files changed

+113
-38
lines changed

clang/include/clang/Sema/Sema.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5432,6 +5432,8 @@ class Sema final : public SemaBase {
54325432
void MarkBaseAndMemberDestructorsReferenced(SourceLocation Loc,
54335433
CXXRecordDecl *Record);
54345434

5435+
void MarkFieldDestructorReferenced(SourceLocation Loc, FieldDecl *Field);
5436+
54355437
/// Mark destructors of virtual bases of this class referenced. In the Itanium
54365438
/// C++ ABI, this is done when emitting a destructor for any non-abstract
54375439
/// class. In the Microsoft C++ ABI, this is done any time a class's

clang/lib/Sema/SemaDeclCXX.cpp

Lines changed: 60 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -5450,10 +5450,31 @@ bool Sema::SetCtorInitializers(CXXConstructorDecl *Constructor, bool AnyErrors,
54505450
NumInitializers * sizeof(CXXCtorInitializer*));
54515451
Constructor->setCtorInitializers(baseOrMemberInitializers);
54525452

5453+
SourceLocation Location = Constructor->getLocation();
5454+
5455+
for (CXXCtorInitializer *Initializer : Info.AllToInit) {
5456+
FieldDecl *Field = Initializer->getAnyMember();
5457+
if (!Field)
5458+
continue;
5459+
5460+
RecordDecl *Parent = Field->getParent();
5461+
5462+
while (Parent) {
5463+
if (Parent->isUnion()) {
5464+
MarkFieldDestructorReferenced(Location, Field);
5465+
break;
5466+
}
5467+
5468+
if (!Parent->isAnonymousStructOrUnion() || Parent == ClassDecl) {
5469+
break;
5470+
}
5471+
5472+
Parent = cast<RecordDecl>(Parent->getDeclContext());
5473+
}
5474+
}
54535475
// Constructors implicitly reference the base and member
54545476
// destructors.
5455-
MarkBaseAndMemberDestructorsReferenced(Constructor->getLocation(),
5456-
Constructor->getParent());
5477+
MarkBaseAndMemberDestructorsReferenced(Location, Constructor->getParent());
54575478
}
54585479

54595480
return HadError;
@@ -5758,6 +5779,42 @@ void Sema::ActOnMemInitializers(Decl *ConstructorDecl,
57585779
DiagnoseUninitializedFields(*this, Constructor);
57595780
}
57605781

5782+
void Sema::MarkFieldDestructorReferenced(SourceLocation Location,
5783+
FieldDecl *Field) {
5784+
if (Field->isInvalidDecl())
5785+
return;
5786+
5787+
// Don't destroy incomplete or zero-length arrays.
5788+
if (isIncompleteOrZeroLengthArrayType(Context, Field->getType()))
5789+
return;
5790+
5791+
QualType FieldType = Context.getBaseElementType(Field->getType());
5792+
5793+
const RecordType *RT = FieldType->getAs<RecordType>();
5794+
if (!RT)
5795+
return;
5796+
5797+
CXXRecordDecl *FieldClassDecl = cast<CXXRecordDecl>(RT->getDecl());
5798+
if (FieldClassDecl->isInvalidDecl())
5799+
return;
5800+
if (FieldClassDecl->hasIrrelevantDestructor())
5801+
return;
5802+
// The destructor for an implicit anonymous union member is never invoked.
5803+
if (FieldClassDecl->isUnion() && FieldClassDecl->isAnonymousStructOrUnion())
5804+
return;
5805+
5806+
CXXDestructorDecl *Dtor = LookupDestructor(FieldClassDecl);
5807+
// Dtor might still be missing, e.g because it's invalid.
5808+
if (!Dtor)
5809+
return;
5810+
CheckDestructorAccess(Field->getLocation(), Dtor,
5811+
PDiag(diag::err_access_dtor_field)
5812+
<< Field->getDeclName() << FieldType);
5813+
5814+
MarkFunctionReferenced(Location, Dtor);
5815+
DiagnoseUseOfDecl(Dtor, Location);
5816+
}
5817+
57615818
void
57625819
Sema::MarkBaseAndMemberDestructorsReferenced(SourceLocation Location,
57635820
CXXRecordDecl *ClassDecl) {
@@ -5773,39 +5830,7 @@ Sema::MarkBaseAndMemberDestructorsReferenced(SourceLocation Location,
57735830

57745831
// Non-static data members.
57755832
for (auto *Field : ClassDecl->fields()) {
5776-
if (Field->isInvalidDecl())
5777-
continue;
5778-
5779-
// Don't destroy incomplete or zero-length arrays.
5780-
if (isIncompleteOrZeroLengthArrayType(Context, Field->getType()))
5781-
continue;
5782-
5783-
QualType FieldType = Context.getBaseElementType(Field->getType());
5784-
5785-
const RecordType* RT = FieldType->getAs<RecordType>();
5786-
if (!RT)
5787-
continue;
5788-
5789-
CXXRecordDecl *FieldClassDecl = cast<CXXRecordDecl>(RT->getDecl());
5790-
if (FieldClassDecl->isInvalidDecl())
5791-
continue;
5792-
if (FieldClassDecl->hasIrrelevantDestructor())
5793-
continue;
5794-
// The destructor for an implicit anonymous union member is never invoked.
5795-
if (FieldClassDecl->isUnion() && FieldClassDecl->isAnonymousStructOrUnion())
5796-
continue;
5797-
5798-
CXXDestructorDecl *Dtor = LookupDestructor(FieldClassDecl);
5799-
// Dtor might still be missing, e.g because it's invalid.
5800-
if (!Dtor)
5801-
continue;
5802-
CheckDestructorAccess(Field->getLocation(), Dtor,
5803-
PDiag(diag::err_access_dtor_field)
5804-
<< Field->getDeclName()
5805-
<< FieldType);
5806-
5807-
MarkFunctionReferenced(Location, Dtor);
5808-
DiagnoseUseOfDecl(Dtor, Location);
5833+
MarkFieldDestructorReferenced(Location, Field);
58095834
}
58105835

58115836
// We only potentially invoke the destructors of potentially constructed

clang/test/SemaCXX/cxx0x-nontrivial-union.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -51,18 +51,18 @@ namespace disabled_dtor {
5151
union disable_dtor {
5252
T val;
5353
template<typename...U>
54-
disable_dtor(U &&...u) : val(forward<U>(u)...) {}
54+
disable_dtor(U &&...u) : val(forward<U>(u)...) {} // expected-error {{attempt to use a deleted function}}
5555
~disable_dtor() {}
5656
};
5757

5858
struct deleted_dtor {
5959
deleted_dtor(int n, char c) : n(n), c(c) {}
6060
int n;
6161
char c;
62-
~deleted_dtor() = delete;
62+
~deleted_dtor() = delete; // expected-note {{'~deleted_dtor' has been explicitly marked deleted here}}
6363
};
6464

65-
disable_dtor<deleted_dtor> dd(4, 'x');
65+
disable_dtor<deleted_dtor> dd(4, 'x'); // expected-note {{in instantiation of function template specialization 'disabled_dtor::disable_dtor<disabled_dtor::deleted_dtor>::disable_dtor<int, char>' requested here}}
6666
}
6767

6868
namespace optional {
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
2+
3+
namespace t1{
4+
template <class T> struct VSX {
5+
~VSX() { static_assert(sizeof(T) != 4, ""); } // expected-error {{static assertion failed due to requirement 'sizeof(int) != 4':}} \
6+
// expected-note {{expression evaluates to '4 != 4'}}
7+
};
8+
struct VS {
9+
union {
10+
VSX<int> _Tail;
11+
};
12+
~VS() { }
13+
VS(short);
14+
};
15+
VS::VS(short) : _Tail() { } // expected-note {{in instantiation of member function 't1::VSX<int>::~VSX' requested here}}
16+
}
17+
18+
19+
namespace t2 {
20+
template <class T> struct VSX {
21+
~VSX() { static_assert(sizeof(T) != 4, ""); } // expected-error {{static assertion failed due to requirement 'sizeof(int) != 4':}} \
22+
// expected-note {{expression evaluates to '4 != 4'}}
23+
};
24+
struct VS {
25+
union {
26+
struct {
27+
VSX<int> _Tail;
28+
};
29+
};
30+
~VS() { }
31+
VS(short);
32+
};
33+
VS::VS(short) : _Tail() { } // expected-note {{in instantiation of member function 't2::VSX<int>::~VSX' requested here}}
34+
}
35+
36+
37+
namespace t3 {
38+
template <class T> struct VSX {
39+
~VSX() { static_assert(sizeof(T) != 4, ""); } // expected-error {{static assertion failed due to requirement 'sizeof(int) != 4':}} \
40+
// expected-note {{expression evaluates to '4 != 4'}}
41+
};
42+
union VS {
43+
VSX<int> _Tail;
44+
~VS() { }
45+
VS(short);
46+
};
47+
VS::VS(short) : _Tail() { } // expected-note {{in instantiation of member function 't3::VSX<int>::~VSX' requested here}}
48+
}

0 commit comments

Comments
 (0)