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 @@ -322,6 +322,21 @@ } } + void updateLookupTableForTemplateParameters(TemplateParameterList &Params, + DeclContext *OldDC) { + ASTImporterLookupTable *LT = Importer.SharedState->getLookupTable(); + if (!LT) + return; + + for (NamedDecl *TP : Params) + LT->update(TP, OldDC); + } + + void updateLookupTableForTemplateParameters(TemplateParameterList &Params) { + updateLookupTableForTemplateParameters( + Params, Importer.getToContext().getTranslationUnitDecl()); + } + public: explicit ASTNodeImporter(ASTImporter &Importer) : Importer(Importer) {} @@ -2607,6 +2622,8 @@ ToAlias->setAccess(D->getAccess()); ToAlias->setLexicalDeclContext(LexicalDC); LexicalDC->addDeclInternal(ToAlias); + if (DC != Importer.getToContext().getTranslationUnitDecl()) + updateLookupTableForTemplateParameters(*ToTemplateParameters); return ToAlias; } @@ -5467,6 +5484,7 @@ D2->setLexicalDeclContext(LexicalDC); addDeclToContexts(D, D2); + updateLookupTableForTemplateParameters(**TemplateParamsOrErr); if (FoundByLookup) { auto *Recent = @@ -5610,6 +5628,7 @@ // Add this partial specialization to the class template. ClassTemplate->AddPartialSpecialization(PartSpec2, InsertPos); + updateLookupTableForTemplateParameters(*ToTPList); } else { // Not a partial specialization. if (GetImportedOrCreateDecl( D2, D, Importer.getToContext(), D->getTagKind(), DC, @@ -5759,6 +5778,8 @@ ToVarTD->setAccess(D->getAccess()); ToVarTD->setLexicalDeclContext(LexicalDC); LexicalDC->addDeclInternal(ToVarTD); + if (DC != Importer.getToContext().getTranslationUnitDecl()) + updateLookupTableForTemplateParameters(**TemplateParamsOrErr); if (FoundByLookup) { auto *Recent = @@ -5884,6 +5905,9 @@ D2 = ToPartial; + // FIXME: Use this update if VarTemplatePartialSpecializationDecl is fixed + // to adopt template parameters. + // updateLookupTableForTemplateParameters(**ToTPListOrErr); } else { // Full specialization if (GetImportedOrCreateDecl(D2, D, Importer.getToContext(), DC, *BeginLocOrErr, *IdLocOrErr, VarTemplate, @@ -5972,14 +5996,26 @@ auto ParamsOrErr = import(D->getTemplateParameters()); if (!ParamsOrErr) return ParamsOrErr.takeError(); + TemplateParameterList *Params = *ParamsOrErr; FunctionDecl *TemplatedFD; if (Error Err = importInto(TemplatedFD, D->getTemplatedDecl())) return std::move(Err); + // Template parameters for a CXXDeductionGuideDecl are re-used by the + // non-deduction-guide-decl template. That template is imported too, and + // DeclContext of the template parameters is changed by both imports. So we + // do not know what the old DC is here without saving it. + // FIXME: The DeclContext of the parameters is now set finally to the function + // or DeductionGuideDecl that was imported later. This may not be the same + // that is in the original AST. + DeclContext *OldParamDC = nullptr; + if (Params->size() > 0) + OldParamDC = Params->getParam(0)->getDeclContext(); + FunctionTemplateDecl *ToFunc; if (GetImportedOrCreateDecl(ToFunc, D, Importer.getToContext(), DC, Loc, Name, - *ParamsOrErr, TemplatedFD)) + Params, TemplatedFD)) return ToFunc; TemplatedFD->setDescribedFunctionTemplate(ToFunc); @@ -5987,6 +6023,7 @@ ToFunc->setAccess(D->getAccess()); ToFunc->setLexicalDeclContext(LexicalDC); LexicalDC->addDeclInternal(ToFunc); + updateLookupTableForTemplateParameters(*Params, OldParamDC); if (FoundByLookup) { auto *Recent = 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 @@ -4368,6 +4368,178 @@ EXPECT_EQ(ToD->getNumTemplateParameterLists(), 1u); } +const internal::VariadicDynCastAllOfMatcher + varTemplateDecl; + +const internal::VariadicDynCastAllOfMatcher< + Decl, VarTemplatePartialSpecializationDecl> + varTemplatePartialSpecializationDecl; + +TEST_P(ASTImporterOptionSpecificTestBase, + FunctionTemplateParameterDeclContext) { + constexpr auto Code = + R"( + template + void f() {}; + )"; + + Decl *FromTU = getTuDecl(Code, Lang_CXX11); + + auto *FromD = FirstDeclMatcher().match( + FromTU, functionTemplateDecl(hasName("f"))); + + ASSERT_EQ(FromD->getTemplateParameters()->getParam(0)->getDeclContext(), + FromD->getTemplatedDecl()); + + auto *ToD = Import(FromD, Lang_CXX11); + EXPECT_EQ(ToD->getTemplateParameters()->getParam(0)->getDeclContext(), + ToD->getTemplatedDecl()); + EXPECT_TRUE(SharedStatePtr->getLookupTable()->contains( + ToD->getTemplatedDecl(), ToD->getTemplateParameters()->getParam(0))); +} + +TEST_P(ASTImporterOptionSpecificTestBase, ClassTemplateParameterDeclContext) { + constexpr auto Code = + R"( + template + struct S {}; + template + struct S {}; + )"; + + Decl *FromTU = getTuDecl(Code, Lang_CXX11); + + auto *FromD = FirstDeclMatcher().match( + FromTU, classTemplateDecl(hasName("S"))); + auto *FromDPart = + FirstDeclMatcher().match( + FromTU, classTemplatePartialSpecializationDecl(hasName("S"))); + + ASSERT_EQ(FromD->getTemplateParameters()->getParam(0)->getDeclContext(), + FromD->getTemplatedDecl()); + ASSERT_EQ(FromDPart->getTemplateParameters()->getParam(0)->getDeclContext(), + FromDPart); + + auto *ToD = Import(FromD, Lang_CXX11); + auto *ToDPart = Import(FromDPart, Lang_CXX11); + + EXPECT_EQ(ToD->getTemplateParameters()->getParam(0)->getDeclContext(), + ToD->getTemplatedDecl()); + EXPECT_TRUE(SharedStatePtr->getLookupTable()->contains( + ToD->getTemplatedDecl(), ToD->getTemplateParameters()->getParam(0))); + + EXPECT_EQ(ToDPart->getTemplateParameters()->getParam(0)->getDeclContext(), + ToDPart); + EXPECT_TRUE(SharedStatePtr->getLookupTable()->contains( + ToDPart, ToDPart->getTemplateParameters()->getParam(0))); +} + +TEST_P(ASTImporterOptionSpecificTestBase, VarTemplateParameterDeclContext) { + constexpr auto Code = + R"( + template + int X1; + template + int X1; + + namespace Ns { + template + int X2; + template + int X2; + } + )"; + + Decl *FromTU = getTuDecl(Code, Lang_CXX14); + + auto *FromD1 = FirstDeclMatcher().match( + FromTU, varTemplateDecl(hasName("X1"))); + auto *FromD1Part = + FirstDeclMatcher().match( + FromTU, varTemplatePartialSpecializationDecl(hasName("X1"))); + auto *FromD2 = FirstDeclMatcher().match( + FromTU, varTemplateDecl(hasName("X2"))); + auto *FromD2Part = + FirstDeclMatcher().match( + FromTU, varTemplatePartialSpecializationDecl(hasName("X2"))); + + ASSERT_EQ(FromD1->getTemplateParameters()->getParam(0)->getDeclContext(), + FromD1->getDeclContext()); + ASSERT_EQ(FromD2->getTemplateParameters()->getParam(0)->getDeclContext(), + FromD2->getDeclContext()); + + ASSERT_EQ(FromD1Part->getTemplateParameters()->getParam(0)->getDeclContext(), + FromD1Part->getDeclContext()); + // FIXME: VarTemplatePartialSpecializationDecl does not update ("adopt") + // template parameter decl context + // ASSERT_EQ(FromD2Part->getTemplateParameters()->getParam(0)->getDeclContext(), + // FromD2Part->getDeclContext()); + + auto *ToD1 = Import(FromD1, Lang_CXX14); + auto *ToD2 = Import(FromD2, Lang_CXX14); + + auto *ToD1Part = Import(FromD1Part, Lang_CXX14); + auto *ToD2Part = Import(FromD2Part, Lang_CXX14); + + EXPECT_EQ(ToD1->getTemplateParameters()->getParam(0)->getDeclContext(), + ToD1->getDeclContext()); + EXPECT_TRUE(SharedStatePtr->getLookupTable()->contains( + ToD1->getDeclContext(), ToD1->getTemplateParameters()->getParam(0))); + EXPECT_EQ(ToD2->getTemplateParameters()->getParam(0)->getDeclContext(), + ToD2->getDeclContext()); + EXPECT_TRUE(SharedStatePtr->getLookupTable()->contains( + ToD2->getDeclContext(), ToD2->getTemplateParameters()->getParam(0))); + + EXPECT_EQ(ToD1Part->getTemplateParameters()->getParam(0)->getDeclContext(), + ToD1Part->getDeclContext()); + EXPECT_TRUE(SharedStatePtr->getLookupTable()->contains( + ToD1Part->getDeclContext(), + ToD1Part->getTemplateParameters()->getParam(0))); + // EXPECT_EQ(ToD2Part->getTemplateParameters()->getParam(0)->getDeclContext(), + // ToD2Part->getDeclContext()); + // EXPECT_TRUE(SharedStatePtr->getLookupTable()->contains( + // ToD2Part->getDeclContext(), + // ToD2Part->getTemplateParameters()->getParam(0))); + (void)ToD2Part; +} + +TEST_P(ASTImporterOptionSpecificTestBase, + TypeAliasTemplateParameterDeclContext) { + constexpr auto Code = + R"( + template + struct S {}; + template using S1 = S; + namespace Ns { + template using S2 = S; + } + )"; + + Decl *FromTU = getTuDecl(Code, Lang_CXX11); + + auto *FromD1 = FirstDeclMatcher().match( + FromTU, typeAliasTemplateDecl(hasName("S1"))); + auto *FromD2 = FirstDeclMatcher().match( + FromTU, typeAliasTemplateDecl(hasName("S2"))); + + ASSERT_EQ(FromD1->getTemplateParameters()->getParam(0)->getDeclContext(), + FromD1->getDeclContext()); + ASSERT_EQ(FromD2->getTemplateParameters()->getParam(0)->getDeclContext(), + FromD2->getDeclContext()); + + auto *ToD1 = Import(FromD1, Lang_CXX11); + auto *ToD2 = Import(FromD2, Lang_CXX11); + + EXPECT_EQ(ToD1->getTemplateParameters()->getParam(0)->getDeclContext(), + ToD1->getDeclContext()); + EXPECT_TRUE(SharedStatePtr->getLookupTable()->contains( + ToD1->getDeclContext(), ToD1->getTemplateParameters()->getParam(0))); + EXPECT_EQ(ToD2->getTemplateParameters()->getParam(0)->getDeclContext(), + ToD2->getDeclContext()); + EXPECT_TRUE(SharedStatePtr->getLookupTable()->contains( + ToD2->getDeclContext(), ToD2->getTemplateParameters()->getParam(0))); +} + struct ASTImporterLookupTableTest : ASTImporterOptionSpecificTestBase {}; TEST_P(ASTImporterLookupTableTest, OneDecl) {