Skip to content

Commit 804b103

Browse files
committed
[clang] Fix a crash issue that caused by handling of fields with initializers in nested anonymous unions
Signed-off-by: yronglin <[email protected]>
1 parent 92ad039 commit 804b103

File tree

6 files changed

+52
-9
lines changed

6 files changed

+52
-9
lines changed

clang/include/clang/AST/Decl.h

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3219,15 +3219,7 @@ class FieldDecl : public DeclaratorDecl, public Mergeable<FieldDecl> {
32193219

32203220
public:
32213221
/// Remove the C++11 in-class initializer from this member.
3222-
void removeInClassInitializer() {
3223-
assert(hasInClassInitializer() && "no initializer to remove");
3224-
StorageKind = ISK_NoInit;
3225-
if (BitField) {
3226-
// Read the bit width before we change the active union member.
3227-
Expr *ExistingBitWidth = InitAndBitWidth->BitWidth;
3228-
BitWidth = ExistingBitWidth;
3229-
}
3230-
}
3222+
void removeInClassInitializer();
32313223

32323224
/// Determine whether this member captures the variable length array
32333225
/// type.

clang/include/clang/AST/DeclCXX.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -269,6 +269,7 @@ class CXXRecordDecl : public RecordDecl {
269269

270270
friend void FunctionDecl::setIsPureVirtual(bool);
271271
friend void TagDecl::startDefinition();
272+
friend void FieldDecl::removeInClassInitializer();
272273

273274
/// Values used in DefinitionData fields to represent special members.
274275
enum SpecialMemberFlags {
@@ -319,6 +320,9 @@ class CXXRecordDecl : public RecordDecl {
319320
/// The number of virtual base class specifiers in VBases.
320321
unsigned NumVBases = 0;
321322

323+
/// The number of C++11 in-class-initializers in this class.
324+
unsigned NumInClassInitializers = 0;
325+
322326
/// Base classes of this class.
323327
///
324328
/// FIXME: This is wasted space for a union.
@@ -497,6 +501,17 @@ class CXXRecordDecl : public RecordDecl {
497501
/// whenever a member is added to this record.
498502
void addedMember(Decl *D);
499503

504+
/// Decreasing the number of C++11 in-class-initializers, and update the
505+
/// HasInClassInitializer if there is no in-class-initializer in this class.
506+
///
507+
/// This routine helps maintain the number of C++11 in-class-initializers.
508+
/// The RecordDecl::hasInClassInitializer() needs to be consistent with the
509+
/// FieldDecl::hasInClassInitializer(), When calling
510+
/// FieldDecl::hasInClassInitializer() to remove the in-class-initializer in
511+
/// the field, we need to check whether there are any in-class-initializers in
512+
/// this class, and update HasInClassInitializer to the correct value.
513+
void removeInClassInitializer();
514+
500515
void markedVirtualFunctionPure();
501516

502517
/// Get the head of our list of friend declarations, possibly

clang/lib/AST/Decl.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4584,6 +4584,22 @@ void FieldDecl::setInClassInitializer(Expr *NewInit) {
45844584
setLazyInClassInitializer(LazyDeclStmtPtr(NewInit));
45854585
}
45864586

4587+
void FieldDecl::removeInClassInitializer() {
4588+
assert(hasInClassInitializer() && "no initializer to remove");
4589+
StorageKind = ISK_NoInit;
4590+
if (BitField) {
4591+
// Read the bit width before we change the active union member.
4592+
Expr *ExistingBitWidth = InitAndBitWidth->BitWidth;
4593+
BitWidth = ExistingBitWidth;
4594+
}
4595+
4596+
// The RecordDecl::hasInClassInitializer() needs to be consistent with the
4597+
// FieldDecl::hasInClassInitializer(). Check the number of C++11
4598+
// in-class-initializers in the parent class.
4599+
if (CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(getParent()))
4600+
RD->removeInClassInitializer();
4601+
}
4602+
45874603
void FieldDecl::setLazyInClassInitializer(LazyDeclStmtPtr NewInit) {
45884604
assert(hasInClassInitializer() && !getInClassInitializer());
45894605
if (BitField)

clang/lib/AST/DeclCXX.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1145,6 +1145,7 @@ void CXXRecordDecl::addedMember(Decl *D) {
11451145
(Field->isAnonymousStructOrUnion() &&
11461146
Field->getType()->getAsCXXRecordDecl()->hasInClassInitializer())) {
11471147
data().HasInClassInitializer = true;
1148+
data().NumInClassInitializers++;
11481149

11491150
// C++11 [class]p5:
11501151
// A default constructor is trivial if [...] no non-static data member
@@ -1441,6 +1442,13 @@ void CXXRecordDecl::addedMember(Decl *D) {
14411442
}
14421443
}
14431444

1445+
void CXXRecordDecl::removeInClassInitializer() {
1446+
assert(data().NumInClassInitializers > 0 &&
1447+
"No member initializer in this class");
1448+
if (--data().NumInClassInitializers == 0)
1449+
data().HasInClassInitializer = false;
1450+
}
1451+
14441452
bool CXXRecordDecl::isLiteral() const {
14451453
const LangOptions &LangOpts = getLangOpts();
14461454
if (!(LangOpts.CPlusPlus20 ? hasConstexprDestructor()

clang/lib/Sema/SemaDeclCXX.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4088,6 +4088,7 @@ void Sema::ActOnFinishCXXInClassMemberInitializer(Decl *D,
40884088
assert((isa<MSPropertyDecl>(D) || FD->getInClassInitStyle() != ICIS_NoInit) &&
40894089
"must set init style when field is created");
40904090

4091+
/// FIXME: We might create an RecoveryExpr for the in-class-initializer.
40914092
if (!InitExpr) {
40924093
D->setInvalidDecl();
40934094
if (FD)

clang/test/SemaCXX/cxx1y-initializer-aggregates.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,3 +115,14 @@ namespace nested_union {
115115
// of Test3, or we should exclude f(Test3) as a candidate.
116116
static_assert(f({1}) == 2, ""); // expected-error {{call to 'f' is ambiguous}}
117117
}
118+
119+
// Fix crash issue https://github.com/llvm/llvm-project/issues/112560.
120+
// Make sure clang compiles the following code without crashing:
121+
namespace GH112560 {
122+
union U {
123+
int f = ; // expected-error {{expected expression}}
124+
};
125+
void foo() {
126+
U g{};
127+
}
128+
} // namespace GH112560

0 commit comments

Comments
 (0)