balazske created this revision.
Herald added subscribers: steakhal, whisperity, martong, teemperor, gamesh411, 
Szelethus, dkrupp.
Herald added a reviewer: a.sidorin.
Herald added a reviewer: shafik.
balazske requested review of this revision.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.

Fix for importing functions where the TypeSourceInfo is set and the
exception specification information contains reference to the function
declaration itself.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D112013

Files:
  clang/lib/AST/ASTImporter.cpp
  clang/unittests/AST/ASTImporterTest.cpp

Index: clang/unittests/AST/ASTImporterTest.cpp
===================================================================
--- clang/unittests/AST/ASTImporterTest.cpp
+++ clang/unittests/AST/ASTImporterTest.cpp
@@ -6145,6 +6145,57 @@
             2u);
 }
 
+TEST_P(ASTImporterOptionSpecificTestBase,
+       ImportTypeSourceInfoWithExceptionSpecUnevaluated) {
+  // This code results in a lambda with implicit constructor.
+  // The constructor should have a "unevaluated" exception specification in its
+  // prototype information.
+  // In some cases the constructor has a TypeSourceInfo that contains the
+  // function's prototype, but often the TypeSourceInfo is not set
+  // (like in the code used here).
+  // The test sets the TypeSourceInfo artifically to simulate a case when it is
+  // set. The test verifies that AST import of such AST does not crash.
+  // (Here the function's TypeSourceInfo references the function itself in the
+  // exception information of the prototype.)
+  // A lambda and implicit constructor of it is used because the problem was
+  // encountered in a similar real code.
+  Decl *FromTU =
+      getTuDecl("void f() { auto X = [](){}; }", Lang_CXX11, "input0.cc");
+
+  CXXRecordDecl *FromL = FirstDeclMatcher<LambdaExpr>()
+                             .match(FromTU, lambdaExpr())
+                             ->getLambdaClass();
+
+  CXXConstructorDecl *FromCtor = *FromL->ctor_begin();
+  QualType FromTy = FromCtor->getType();
+  const auto *FromFPT = FromTy->getAs<FunctionProtoType>();
+  ASSERT_TRUE(FromFPT);
+  FunctionProtoType::ExtProtoInfo FromEPI = FromFPT->getExtProtoInfo();
+  // If type is EST_Unevaluated, SourceDecl should be set to the parent decl.
+  EXPECT_EQ(FromEPI.ExceptionSpec.Type, EST_Unevaluated);
+  EXPECT_EQ(FromEPI.ExceptionSpec.SourceDecl, FromCtor);
+
+  // No TypeSourceInfo for the constructor.
+  ASSERT_FALSE(FromCtor->getTypeSourceInfo());
+  // Set a TypeSourceInfo for the function, this state may occur in reality.
+  TypeSourceInfo *FromTSI = FromTU->getASTContext().getTrivialTypeSourceInfo(
+      FromTy, FromCtor->getBeginLoc());
+  FromCtor->setTypeSourceInfo(FromTSI);
+
+  // Import it.
+  auto ToL = Import(FromL, Lang_CXX11);
+
+  // Check if the import was correct.
+  CXXConstructorDecl *ToCtor = *ToL->ctor_begin();
+  const auto *ToFPT = ToCtor->getType()->getAs<FunctionProtoType>();
+  ASSERT_TRUE(FromFPT);
+  FunctionProtoType::ExtProtoInfo ToEPI = ToFPT->getExtProtoInfo();
+  EXPECT_EQ(ToEPI.ExceptionSpec.Type, EST_Unevaluated);
+  EXPECT_EQ(ToEPI.ExceptionSpec.SourceDecl, ToCtor);
+  EXPECT_TRUE(ToCtor->getTypeSourceInfo());
+  EXPECT_EQ(ToCtor->getTypeSourceInfo()->getType().getTypePtr(), ToFPT);
+}
+
 struct ImportAutoFunctions : ASTImporterOptionSpecificTestBase {};
 
 TEST_P(ImportAutoFunctions, ReturnWithTypedefDeclaredInside) {
Index: clang/lib/AST/ASTImporter.cpp
===================================================================
--- clang/lib/AST/ASTImporter.cpp
+++ clang/lib/AST/ASTImporter.cpp
@@ -3422,11 +3422,14 @@
     return std::move(Err);
 
   QualType FromTy = D->getType();
+  TypeSourceInfo *FromTSI = D->getTypeSourceInfo();
   // Set to true if we do not import the type of the function as is. There are
   // cases when the original type would result in an infinite recursion during
   // the import. To avoid an infinite recursion when importing, we create the
   // FunctionDecl with a simplified function type and update it only after the
   // relevant AST nodes are already imported.
+  // The type is related to TypeSourceInfo (it references the type), so we must
+  // do the same with TypeSourceInfo.
   bool UsedDifferentProtoType = false;
   if (const auto *FromFPT = FromTy->getAs<FunctionProtoType>()) {
     QualType FromReturnTy = FromFPT->getReturnType();
@@ -3453,11 +3456,13 @@
     }
     FromTy = Importer.getFromContext().getFunctionType(
         FromReturnTy, FromFPT->getParamTypes(), FromEPI);
+    FromTSI = Importer.getFromContext().getTrivialTypeSourceInfo(
+        FromTy, D->getBeginLoc());
   }
 
   Error Err = Error::success();
   auto T = importChecked(Err, FromTy);
-  auto TInfo = importChecked(Err, D->getTypeSourceInfo());
+  auto TInfo = importChecked(Err, FromTSI);
   auto ToInnerLocStart = importChecked(Err, D->getInnerLocStart());
   auto ToEndLoc = importChecked(Err, D->getEndLoc());
   auto ToQualifierLoc = importChecked(Err, D->getQualifierLoc());
@@ -3635,6 +3640,10 @@
       ToFunction->setType(*TyOrErr);
     else
       return TyOrErr.takeError();
+    if (Expected<TypeSourceInfo *> TSIOrErr = import(D->getTypeSourceInfo()))
+      ToFunction->setTypeSourceInfo(*TSIOrErr);
+    else
+      return TSIOrErr.takeError();
   }
 
   // FIXME: Other bits to merge?
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to