From: Aleksei Sidorin Date: Tue, 15 May 2018 11:09:07 +0000 (+0000) Subject: [ASTImporter] Extend lookup logic in class templates X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=de8567cd2889a2bb07e298a47b15302f08f42162;p=clang [ASTImporter] Extend lookup logic in class templates During import of a class template, lookup may find a forward declaration and structural match falsely reports equivalency between a forward decl and a definition. The result is that some definitions are not imported if we had imported a forward decl previously. This patch gives a fix. Patch by Gabor Marton! Differential Revision: https://reviews.llvm.org/D46353 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@332338 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/AST/ASTImporter.cpp b/lib/AST/ASTImporter.cpp index 57d4585e07..d8c2259e1c 100644 --- a/lib/AST/ASTImporter.cpp +++ b/lib/AST/ASTImporter.cpp @@ -4108,8 +4108,14 @@ Decl *ASTNodeImporter::VisitClassTemplateDecl(ClassTemplateDecl *D) { if (auto *FoundTemplate = dyn_cast(Found)) { if (IsStructuralMatch(D, FoundTemplate)) { // The class templates structurally match; call it the same template. - // FIXME: We may be filling in a forward declaration here. Handle - // this case! + + // We found a forward declaration but the class to be imported has a + // definition. + // FIXME Add this forward declaration to the redeclaration chain. + if (D->isThisDeclarationADefinition() && + !FoundTemplate->isThisDeclarationADefinition()) + continue; + Importer.Imported(D->getTemplatedDecl(), FoundTemplate->getTemplatedDecl()); return Importer.Imported(D, FoundTemplate); diff --git a/unittests/AST/ASTImporterTest.cpp b/unittests/AST/ASTImporterTest.cpp index debcfe67d9..9eec1d20ba 100644 --- a/unittests/AST/ASTImporterTest.cpp +++ b/unittests/AST/ASTImporterTest.cpp @@ -1431,6 +1431,39 @@ TEST_P(ASTImporterTestBase, MatchVerifier{}.match(To->getTranslationUnitDecl(), Pattern)); } +TEST_P(ASTImporterTestBase, ImportDefinitionOfClassTemplateAfterFwdDecl) { + { + Decl *FromTU = getTuDecl( + R"( + template + struct B; + )", + Lang_CXX, "input0.cc"); + auto *FromD = FirstDeclMatcher().match( + FromTU, classTemplateDecl(hasName("B"))); + + Import(FromD, Lang_CXX); + } + + { + Decl *FromTU = getTuDecl( + R"( + template + struct B { + void f(); + }; + )", + Lang_CXX, "input1.cc"); + FunctionDecl *FromD = FirstDeclMatcher().match( + FromTU, functionDecl(hasName("f"))); + Import(FromD, Lang_CXX); + auto *FromCTD = FirstDeclMatcher().match( + FromTU, classTemplateDecl(hasName("B"))); + auto *ToCTD = cast(Import(FromCTD, Lang_CXX)); + EXPECT_TRUE(ToCTD->isThisDeclarationADefinition()); + } +} + INSTANTIATE_TEST_CASE_P( ParameterizedTests, ASTImporterTestBase, ::testing::Values(ArgVector(), ArgVector{"-fdelayed-template-parsing"}),);