Skip to content

Commit 740861d

Browse files
authored
[clang] Fix a crash issue that caused by handling of fields with initializers in nested anonymous unions (#113049)
Fixes: #112560 This PR create an RecoveryExpr for invalid in-class-initializer. --------- Signed-off-by: yronglin <[email protected]>
1 parent cb4433b commit 740861d

File tree

7 files changed

+62
-17
lines changed

7 files changed

+62
-17
lines changed

clang/include/clang/Sema/Sema.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5314,7 +5314,7 @@ class Sema final : public SemaBase {
53145314
/// is complete.
53155315
void ActOnFinishCXXInClassMemberInitializer(Decl *VarDecl,
53165316
SourceLocation EqualLoc,
5317-
Expr *Init);
5317+
ExprResult Init);
53185318

53195319
/// Handle a C++ member initializer using parentheses syntax.
53205320
MemInitResult

clang/lib/Parse/ParseCXXInlineMethods.cpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -722,8 +722,7 @@ void Parser::ParseLexedMemberInitializer(LateParsedMemberInitializer &MI) {
722722
ExprResult Init = ParseCXXMemberInitializer(MI.Field, /*IsFunction=*/false,
723723
EqualLoc);
724724

725-
Actions.ActOnFinishCXXInClassMemberInitializer(MI.Field, EqualLoc,
726-
Init.get());
725+
Actions.ActOnFinishCXXInClassMemberInitializer(MI.Field, EqualLoc, Init);
727726

728727
// The next token should be our artificial terminating EOF token.
729728
if (Tok.isNot(tok::eof)) {

clang/lib/Sema/SemaDeclCXX.cpp

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4074,24 +4074,28 @@ ExprResult Sema::ConvertMemberDefaultInitExpression(FieldDecl *FD,
40744074

40754075
void Sema::ActOnFinishCXXInClassMemberInitializer(Decl *D,
40764076
SourceLocation InitLoc,
4077-
Expr *InitExpr) {
4077+
ExprResult InitExpr) {
40784078
// Pop the notional constructor scope we created earlier.
40794079
PopFunctionScopeInfo(nullptr, D);
40804080

4081-
FieldDecl *FD = dyn_cast<FieldDecl>(D);
4082-
assert((isa<MSPropertyDecl>(D) || FD->getInClassInitStyle() != ICIS_NoInit) &&
4083-
"must set init style when field is created");
4084-
4085-
if (!InitExpr) {
4081+
// Microsoft C++'s property declaration cannot have a default member
4082+
// initializer.
4083+
if (isa<MSPropertyDecl>(D)) {
40864084
D->setInvalidDecl();
4087-
if (FD)
4088-
FD->removeInClassInitializer();
40894085
return;
40904086
}
40914087

4092-
if (DiagnoseUnexpandedParameterPack(InitExpr, UPPC_Initializer)) {
4088+
FieldDecl *FD = dyn_cast<FieldDecl>(D);
4089+
assert((FD && FD->getInClassInitStyle() != ICIS_NoInit) &&
4090+
"must set init style when field is created");
4091+
4092+
if (!InitExpr.isUsable() ||
4093+
DiagnoseUnexpandedParameterPack(InitExpr.get(), UPPC_Initializer)) {
40934094
FD->setInvalidDecl();
4094-
FD->removeInClassInitializer();
4095+
ExprResult RecoveryInit =
4096+
CreateRecoveryExpr(InitLoc, InitLoc, {}, FD->getType());
4097+
if (RecoveryInit.isUsable())
4098+
FD->setInClassInitializer(RecoveryInit.get());
40954099
return;
40964100
}
40974101

clang/lib/Sema/SemaExpr.cpp

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5587,10 +5587,6 @@ static FieldDecl *FindFieldDeclInstantiationPattern(const ASTContext &Ctx,
55875587
ExprResult Sema::BuildCXXDefaultInitExpr(SourceLocation Loc, FieldDecl *Field) {
55885588
assert(Field->hasInClassInitializer());
55895589

5590-
// If we might have already tried and failed to instantiate, don't try again.
5591-
if (Field->isInvalidDecl())
5592-
return ExprError();
5593-
55945590
CXXThisScopeRAII This(*this, Field->getParent(), Qualifiers());
55955591

55965592
auto *ParentRD = cast<CXXRecordDecl>(Field->getParent());

clang/lib/Sema/SemaInit.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -745,6 +745,7 @@ void InitListChecker::FillInEmptyInitForField(unsigned Init, FieldDecl *Field,
745745
if (Field->hasInClassInitializer()) {
746746
if (VerifyOnly)
747747
return;
748+
748749
ExprResult DIE;
749750
{
750751
// Enter a default initializer rebuild context, then we can support

clang/test/AST/ast-dump-recovery.cpp

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -480,3 +480,37 @@ void RecoveryForStmtCond() {
480480
// CHECK-NEXT: `-CompoundStmt {{.*}}
481481
for (int i = 0; i < invalid; ++i) {}
482482
}
483+
484+
// Fix crash issue https://github.com/llvm/llvm-project/issues/112560.
485+
// Make sure clang compiles the following code without crashing:
486+
487+
// CHECK:NamespaceDecl {{.*}} GH112560
488+
// CHECK-NEXT: |-CXXRecordDecl {{.*}} referenced union U definition
489+
// CHECK-NEXT: | |-DefinitionData {{.*}}
490+
// CHECK-NEXT: | | |-DefaultConstructor {{.*}}
491+
// CHECK-NEXT: | | |-CopyConstructor {{.*}}
492+
// CHECK-NEXT: | | |-MoveConstructor {{.*}}
493+
// CHECK-NEXT: | | |-CopyAssignment {{.*}}
494+
// CHECK-NEXT: | | |-MoveAssignment {{.*}}
495+
// CHECK-NEXT: | | `-Destructor {{.*}}
496+
// CHECK-NEXT: | |-CXXRecordDecl {{.*}} implicit union U
497+
// CHECK-NEXT: | `-FieldDecl {{.*}} invalid f 'int'
498+
// CHECK-NEXT: | `-RecoveryExpr {{.*}} 'int' contains-errors
499+
// DISABLED-NOT: -RecoveryExpr {{.*}} contains-errors
500+
namespace GH112560 {
501+
union U {
502+
int f = ;
503+
};
504+
505+
// CHECK: FunctionDecl {{.*}} foo 'void ()'
506+
// CHECK-NEXT: `-CompoundStmt {{.*}}
507+
// CHECK-NEXT: `-DeclStmt {{.*}}
508+
// CHECK-NEXT: `-VarDecl {{.*}} g 'U':'GH112560::U' listinit
509+
// CHECK-NEXT: `-InitListExpr {{.*}} 'U':'GH112560::U' contains-errors field Field {{.*}} 'f' 'int'
510+
// CHECK-NEXT: `-CXXDefaultInitExpr {{.*}} 'int' contains-errors has rewritten init
511+
// CHECK-NEXT: `-RecoveryExpr {{.*}} 'int' contains-errors
512+
// DISABLED-NOT: -RecoveryExpr {{.*}} contains-errors
513+
void foo() {
514+
U g{};
515+
}
516+
} // namespace GH112560

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)