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,50 @@ 2u); } +TEST_P(ASTImporterOptionSpecificTestBase, + ImportFunctionDeclWithTypeSourceInfoWithSourceDecl) { + // This code results in a lambda with implicit constructor. + // The constructor's TypeSourceInfo points out the function prototype. + // This prototype has an EST_Unevaluated in its exception information and a + // SourceDecl that is the function declaration itself. + // The test verifies that AST import of such AST does not crash. + // (Here the function's TypeSourceInfo references the function itself.) + Decl *FromTU = getTuDecl( + R"( + template void f(T) { auto X = [](){}; } + void g() { f(10); } + )", + Lang_CXX11, "input0.cc"); + + // Use LastDeclMatcher to find the LambdaExpr in the template specialization. + CXXRecordDecl *FromL = LastDeclMatcher() + .match(FromTU, lambdaExpr()) + ->getLambdaClass(); + + CXXConstructorDecl *FromCtor = *FromL->ctor_begin(); + ASSERT_TRUE(FromCtor->isCopyConstructor()); + ASSERT_TRUE(FromCtor->getTypeSourceInfo()); + const auto *FromFPT = FromCtor->getType()->getAs(); + ASSERT_TRUE(FromFPT); + EXPECT_EQ(FromCtor->getTypeSourceInfo()->getType().getTypePtr(), 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); + + auto ToL = Import(FromL, Lang_CXX11); + + // Check if the import was correct. + CXXConstructorDecl *ToCtor = *ToL->ctor_begin(); + EXPECT_TRUE(ToCtor->getTypeSourceInfo()); + const auto *ToFPT = ToCtor->getType()->getAs(); + ASSERT_TRUE(ToFPT); + EXPECT_EQ(ToCtor->getTypeSourceInfo()->getType().getTypePtr(), ToFPT); + FunctionProtoType::ExtProtoInfo ToEPI = ToFPT->getExtProtoInfo(); + EXPECT_EQ(ToEPI.ExceptionSpec.Type, EST_Unevaluated); + EXPECT_EQ(ToEPI.ExceptionSpec.SourceDecl, ToCtor); +} + struct ImportAutoFunctions : ASTImporterOptionSpecificTestBase {}; TEST_P(ImportAutoFunctions, ReturnWithTypedefDeclaredInside) {