[ASTImporter] Fix import of lambda in function param

Summary:
The current import implementation fails to import the definition of a
lambda class if the lambda class is defined in a function param.
E.g., the lambda class below will be imported without any methods:
```
  template <typename F>
  void f(F L = [](){}) {}
```

Reviewers: a_sidorin, a.sidorin, shafik

Subscribers: rnkovacs, dkrupp, Szelethus, gamesh411, cfe-commits

Tags: #clang

Differential Revision: https://reviews.llvm.org/D64073

llvm-svn: 365315
This commit is contained in:
Gabor Marton 2019-07-08 12:49:13 +00:00
parent 0752d12c09
commit e73805f80e
2 changed files with 51 additions and 11 deletions

View File

@ -1708,8 +1708,18 @@ static Error setTypedefNameForAnonDecl(TagDecl *From, TagDecl *To,
Error ASTNodeImporter::ImportDefinition(
RecordDecl *From, RecordDecl *To, ImportDefinitionKind Kind) {
if (To->getDefinition() || To->isBeingDefined()) {
if (Kind == IDK_Everything)
return ImportDeclContext(From, /*ForceImport=*/true);
if (Kind == IDK_Everything ||
// In case of lambdas, the class already has a definition ptr set, but
// the contained decls are not imported yet. Also, isBeingDefined was
// set in CXXRecordDecl::CreateLambda. We must import the contained
// decls here and finish the definition.
(To->isLambda() && shouldForceImportDeclContext(Kind))) {
Error Result = ImportDeclContext(From, /*ForceImport=*/true);
// Finish the definition of the lambda, set isBeingDefined to false.
if (To->isLambda())
To->completeDefinition();
return Result;
}
return Error::success();
}
@ -7422,19 +7432,10 @@ ExpectedStmt ASTNodeImporter::VisitLambdaExpr(LambdaExpr *E) {
return ToClassOrErr.takeError();
CXXRecordDecl *ToClass = *ToClassOrErr;
// NOTE: lambda classes are created with BeingDefined flag set up.
// It means that ImportDefinition doesn't work for them and we should fill it
// manually.
if (ToClass->isBeingDefined())
if (Error Err = ImportDeclContext(FromClass, /*ForceImport = */ true))
return std::move(Err);
auto ToCallOpOrErr = import(E->getCallOperator());
if (!ToCallOpOrErr)
return ToCallOpOrErr.takeError();
ToClass->completeDefinition();
SmallVector<LambdaCapture, 8> ToCaptures;
ToCaptures.reserve(E->capture_size());
for (const auto &FromCapture : E->captures()) {

View File

@ -5083,6 +5083,45 @@ INSTANTIATE_TEST_CASE_P(ParameterizedTests, DeclContextTest,
INSTANTIATE_TEST_CASE_P(ParameterizedTests, CanonicalRedeclChain,
::testing::Values(ArgVector()), );
TEST_P(ASTImporterOptionSpecificTestBase, LambdaInFunctionBody) {
Decl *FromTU = getTuDecl(
R"(
void f() {
auto L = [](){};
}
)",
Lang_CXX11, "input0.cc");
auto Pattern = lambdaExpr();
CXXRecordDecl *FromL =
FirstDeclMatcher<LambdaExpr>().match(FromTU, Pattern)->getLambdaClass();
auto ToL = Import(FromL, Lang_CXX11);
unsigned ToLSize = std::distance(ToL->decls().begin(), ToL->decls().end());
unsigned FromLSize =
std::distance(FromL->decls().begin(), FromL->decls().end());
EXPECT_NE(ToLSize, 0u);
EXPECT_EQ(ToLSize, FromLSize);
}
TEST_P(ASTImporterOptionSpecificTestBase, LambdaInFunctionParam) {
Decl *FromTU = getTuDecl(
R"(
template <typename F>
void f(F L = [](){}) {}
)",
Lang_CXX11, "input0.cc");
auto Pattern = lambdaExpr();
CXXRecordDecl *FromL =
FirstDeclMatcher<LambdaExpr>().match(FromTU, Pattern)->getLambdaClass();
auto ToL = Import(FromL, Lang_CXX11);
unsigned ToLSize = std::distance(ToL->decls().begin(), ToL->decls().end());
unsigned FromLSize =
std::distance(FromL->decls().begin(), FromL->decls().end());
EXPECT_NE(ToLSize, 0u);
EXPECT_EQ(ToLSize, FromLSize);
}
INSTANTIATE_TEST_CASE_P(ParameterizedTests, ASTImporterLookupTableTest,
DefaultTestValuesForRunOptions, );