Author: yronglin Date: 2024-12-10T20:56:52+08:00 New Revision: 740861d69c2d2988ed69bc264df73bc5ae9d9e49
URL: https://github.com/llvm/llvm-project/commit/740861d69c2d2988ed69bc264df73bc5ae9d9e49 DIFF: https://github.com/llvm/llvm-project/commit/740861d69c2d2988ed69bc264df73bc5ae9d9e49.diff LOG: [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 <yronglin...@gmail.com> Added: Modified: clang/include/clang/Sema/Sema.h clang/lib/Parse/ParseCXXInlineMethods.cpp clang/lib/Sema/SemaDeclCXX.cpp clang/lib/Sema/SemaExpr.cpp clang/lib/Sema/SemaInit.cpp clang/test/AST/ast-dump-recovery.cpp clang/test/SemaCXX/cxx1y-initializer-aggregates.cpp Removed: ################################################################################ diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index b8684d11460eda..ae07ed8478f2a8 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -5314,7 +5314,7 @@ class Sema final : public SemaBase { /// is complete. void ActOnFinishCXXInClassMemberInitializer(Decl *VarDecl, SourceLocation EqualLoc, - Expr *Init); + ExprResult Init); /// Handle a C++ member initializer using parentheses syntax. MemInitResult diff --git a/clang/lib/Parse/ParseCXXInlineMethods.cpp b/clang/lib/Parse/ParseCXXInlineMethods.cpp index 2ec66fe95708e1..6c01af55ef3c46 100644 --- a/clang/lib/Parse/ParseCXXInlineMethods.cpp +++ b/clang/lib/Parse/ParseCXXInlineMethods.cpp @@ -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)) { diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index f7a0b3c059ec91..b2c5bb235c119c 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -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; } diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index 1524622408a18a..20bf6f7f6f28ff 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -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()); diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp index 7c03a12e812809..5909457b04e663 100644 --- a/clang/lib/Sema/SemaInit.cpp +++ b/clang/lib/Sema/SemaInit.cpp @@ -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 diff --git a/clang/test/AST/ast-dump-recovery.cpp b/clang/test/AST/ast-dump-recovery.cpp index 43884622240269..b59fa3778192f9 100644 --- a/clang/test/AST/ast-dump-recovery.cpp +++ b/clang/test/AST/ast-dump-recovery.cpp @@ -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 diff --git a/clang/test/SemaCXX/cxx1y-initializer-aggregates.cpp b/clang/test/SemaCXX/cxx1y-initializer-aggregates.cpp index 03a6800898d18f..8360b8fd7d8ee2 100644 --- a/clang/test/SemaCXX/cxx1y-initializer-aggregates.cpp +++ b/clang/test/SemaCXX/cxx1y-initializer-aggregates.cpp @@ -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 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits