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

via cfe-commits cfe-commits at lists.llvm.org
Tue Dec 10 04:56:56 PST 2024


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 <yronglin777 at 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


        


More information about the cfe-commits mailing list