[clang] Fix a crash issue that caused by handling of fields with initializers in nested anonymous unions (#113049)

Fixes: https://github.com/llvm/llvm-project/issues/112560

This PR create an RecoveryExpr for invalid in-class-initializer.

---------

Signed-off-by: yronglin <yronglin777@gmail.com>
This commit is contained in:
yronglin 2024-12-10 20:56:52 +08:00 committed by GitHub
parent cb4433b677
commit 740861d69c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 62 additions and 17 deletions

View File

@ -5314,7 +5314,7 @@ public:
/// is complete.
void ActOnFinishCXXInClassMemberInitializer(Decl *VarDecl,
SourceLocation EqualLoc,
Expr *Init);
ExprResult Init);
/// Handle a C++ member initializer using parentheses syntax.
MemInitResult

View File

@ -722,8 +722,7 @@ void Parser::ParseLexedMemberInitializer(LateParsedMemberInitializer &MI) {
ExprResult Init = ParseCXXMemberInitializer(MI.Field, /*IsFunction=*/false,
EqualLoc);
Actions.ActOnFinishCXXInClassMemberInitializer(MI.Field, EqualLoc,
Init.get());
Actions.ActOnFinishCXXInClassMemberInitializer(MI.Field, EqualLoc, Init);
// The next token should be our artificial terminating EOF token.
if (Tok.isNot(tok::eof)) {

View File

@ -4074,24 +4074,28 @@ ExprResult Sema::ConvertMemberDefaultInitExpression(FieldDecl *FD,
void Sema::ActOnFinishCXXInClassMemberInitializer(Decl *D,
SourceLocation InitLoc,
Expr *InitExpr) {
ExprResult InitExpr) {
// Pop the notional constructor scope we created earlier.
PopFunctionScopeInfo(nullptr, D);
FieldDecl *FD = dyn_cast<FieldDecl>(D);
assert((isa<MSPropertyDecl>(D) || FD->getInClassInitStyle() != ICIS_NoInit) &&
"must set init style when field is created");
if (!InitExpr) {
// Microsoft C++'s property declaration cannot have a default member
// initializer.
if (isa<MSPropertyDecl>(D)) {
D->setInvalidDecl();
if (FD)
FD->removeInClassInitializer();
return;
}
if (DiagnoseUnexpandedParameterPack(InitExpr, UPPC_Initializer)) {
FieldDecl *FD = dyn_cast<FieldDecl>(D);
assert((FD && FD->getInClassInitStyle() != ICIS_NoInit) &&
"must set init style when field is created");
if (!InitExpr.isUsable() ||
DiagnoseUnexpandedParameterPack(InitExpr.get(), UPPC_Initializer)) {
FD->setInvalidDecl();
FD->removeInClassInitializer();
ExprResult RecoveryInit =
CreateRecoveryExpr(InitLoc, InitLoc, {}, FD->getType());
if (RecoveryInit.isUsable())
FD->setInClassInitializer(RecoveryInit.get());
return;
}

View File

@ -5587,10 +5587,6 @@ static FieldDecl *FindFieldDeclInstantiationPattern(const ASTContext &Ctx,
ExprResult Sema::BuildCXXDefaultInitExpr(SourceLocation Loc, FieldDecl *Field) {
assert(Field->hasInClassInitializer());
// If we might have already tried and failed to instantiate, don't try again.
if (Field->isInvalidDecl())
return ExprError();
CXXThisScopeRAII This(*this, Field->getParent(), Qualifiers());
auto *ParentRD = cast<CXXRecordDecl>(Field->getParent());

View File

@ -745,6 +745,7 @@ void InitListChecker::FillInEmptyInitForField(unsigned Init, FieldDecl *Field,
if (Field->hasInClassInitializer()) {
if (VerifyOnly)
return;
ExprResult DIE;
{
// Enter a default initializer rebuild context, then we can support

View File

@ -480,3 +480,37 @@ void RecoveryForStmtCond() {
// CHECK-NEXT: `-CompoundStmt {{.*}}
for (int i = 0; i < invalid; ++i) {}
}
// Fix crash issue https://github.com/llvm/llvm-project/issues/112560.
// Make sure clang compiles the following code without crashing:
// CHECK:NamespaceDecl {{.*}} GH112560
// CHECK-NEXT: |-CXXRecordDecl {{.*}} referenced union U definition
// CHECK-NEXT: | |-DefinitionData {{.*}}
// CHECK-NEXT: | | |-DefaultConstructor {{.*}}
// CHECK-NEXT: | | |-CopyConstructor {{.*}}
// CHECK-NEXT: | | |-MoveConstructor {{.*}}
// CHECK-NEXT: | | |-CopyAssignment {{.*}}
// CHECK-NEXT: | | |-MoveAssignment {{.*}}
// CHECK-NEXT: | | `-Destructor {{.*}}
// CHECK-NEXT: | |-CXXRecordDecl {{.*}} implicit union U
// CHECK-NEXT: | `-FieldDecl {{.*}} invalid f 'int'
// CHECK-NEXT: | `-RecoveryExpr {{.*}} 'int' contains-errors
// DISABLED-NOT: -RecoveryExpr {{.*}} contains-errors
namespace GH112560 {
union U {
int f = ;
};
// CHECK: FunctionDecl {{.*}} foo 'void ()'
// CHECK-NEXT: `-CompoundStmt {{.*}}
// CHECK-NEXT: `-DeclStmt {{.*}}
// CHECK-NEXT: `-VarDecl {{.*}} g 'U':'GH112560::U' listinit
// CHECK-NEXT: `-InitListExpr {{.*}} 'U':'GH112560::U' contains-errors field Field {{.*}} 'f' 'int'
// CHECK-NEXT: `-CXXDefaultInitExpr {{.*}} 'int' contains-errors has rewritten init
// CHECK-NEXT: `-RecoveryExpr {{.*}} 'int' contains-errors
// DISABLED-NOT: -RecoveryExpr {{.*}} contains-errors
void foo() {
U g{};
}
} // namespace GH112560

View File

@ -115,3 +115,14 @@ namespace nested_union {
// of Test3, or we should exclude f(Test3) as a candidate.
static_assert(f({1}) == 2, ""); // expected-error {{call to 'f' is ambiguous}}
}
// Fix crash issue https://github.com/llvm/llvm-project/issues/112560.
// Make sure clang compiles the following code without crashing:
namespace GH112560 {
union U {
int f = ; // expected-error {{expected expression}}
};
void foo() {
U g{};
}
} // namespace GH112560