Skip to content

Commit

Permalink
[clang][ASTImporter] Fix for importing functions with EST_Unevaluated…
Browse files Browse the repository at this point in the history
… prototype.

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

Reviewed By: martong, steakhal

Differential Revision: https://reviews.llvm.org/D112013
  • Loading branch information
balazske committed Oct 22, 2021
1 parent 3b93dc6 commit 4ff103c
Show file tree
Hide file tree
Showing 2 changed files with 54 additions and 1 deletion.
11 changes: 10 additions & 1 deletion clang/lib/AST/ASTImporter.cpp
Expand Up @@ -3422,11 +3422,14 @@ ExpectedDecl ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) {
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();
Expand All @@ -3453,11 +3456,13 @@ ExpectedDecl ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) {
}
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());
Expand Down Expand Up @@ -3635,6 +3640,10 @@ ExpectedDecl ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) {
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?
Expand Down
44 changes: 44 additions & 0 deletions clang/unittests/AST/ASTImporterTest.cpp
Expand Up @@ -6145,6 +6145,50 @@ TEST_P(ASTImporterOptionSpecificTestBase, ImportDefaultConstructibleLambdas) {
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<typename T> 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<LambdaExpr>()
.match(FromTU, lambdaExpr())
->getLambdaClass();

CXXConstructorDecl *FromCtor = *FromL->ctor_begin();
ASSERT_TRUE(FromCtor->isCopyConstructor());
ASSERT_TRUE(FromCtor->getTypeSourceInfo());
const auto *FromFPT = FromCtor->getType()->getAs<FunctionProtoType>();
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<FunctionProtoType>();
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) {
Expand Down

0 comments on commit 4ff103c

Please sign in to comment.