diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp --- a/clang/lib/AST/ASTImporter.cpp +++ b/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()) { 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 TSIOrErr = import(D->getTypeSourceInfo())) + ToFunction->setTypeSourceInfo(*TSIOrErr); + else + return TSIOrErr.takeError(); } // FIXME: Other bits to merge? diff --git a/clang/unittests/AST/ASTImporterTest.cpp b/clang/unittests/AST/ASTImporterTest.cpp --- a/clang/unittests/AST/ASTImporterTest.cpp +++ b/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() + .match(FromTU, lambdaExpr()) + ->getLambdaClass(); + + CXXConstructorDecl *FromCtor = *FromL->ctor_begin(); + QualType FromTy = FromCtor->getType(); + const auto *FromFPT = FromTy->getAs(); + 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(); + 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) {