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) {} @@ -2609,6 +2624,8 @@ ToAlias->setAccess(D->getAccess()); ToAlias->setLexicalDeclContext(LexicalDC); LexicalDC->addDeclInternal(ToAlias); + if (DC != Importer.getToContext().getTranslationUnitDecl()) + updateLookupTableForTemplateParameters(*ToTemplateParameters); return ToAlias; } @@ -5511,6 +5528,7 @@ D2->setLexicalDeclContext(LexicalDC); addDeclToContexts(D, D2); + updateLookupTableForTemplateParameters(**TemplateParamsOrErr); if (FoundByLookup) { auto *Recent = @@ -5654,6 +5672,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, @@ -5803,6 +5822,8 @@ ToVarTD->setAccess(D->getAccess()); ToVarTD->setLexicalDeclContext(LexicalDC); LexicalDC->addDeclInternal(ToVarTD); + if (DC != Importer.getToContext().getTranslationUnitDecl()) + updateLookupTableForTemplateParameters(**TemplateParamsOrErr); if (FoundByLookup) { auto *Recent = @@ -5928,6 +5949,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, @@ -6016,14 +6040,30 @@ 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 of the ClassTemplateDecl and FunctionTemplateDecl are + // shared, if the FunctionTemplateDecl is a deduction guide for the class. + // At import the ClassTemplateDecl object is always created first (FIXME: is + // this really true?) because the dependency, then the FunctionTemplateDecl. + // The DeclContext of the template parameters is changed when the + // FunctionTemplateDecl is created, but was set already when the class + // template was created. So here it is not the TU (default value) any more. + // FIXME: The DeclContext of the parameters is now set finally to the + // CXXDeductionGuideDecl object that was imported later. This may not be the + // same that is in the original AST, specially if there are multiple deduction + // guides. + 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); @@ -6031,6 +6071,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 @@ -4382,6 +4382,245 @@ 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, + CXXDeductionGuideTemplateParameterDeclContext) { + Decl *FromTU = getTuDecl( + R"( + template struct A { + A(T); + }; + A a{(int)0}; + )", + Lang_CXX17, "input.cc"); +// clang-format off +/* +|-ClassTemplateDecl 0x1fe5000 line:2:36 A +| |-TemplateTypeParmDecl 0x1fe4eb0 col:26 referenced typename depth 0 index 0 T +| |-CXXRecordDecl 0x1fe4f70 line:2:36 struct A definition + +|-FunctionTemplateDecl 0x1fe5860 col:9 implicit +| |-TemplateTypeParmDecl 0x1fe4eb0 col:26 referenced typename depth 0 index 0 T +| |-CXXDeductionGuideDecl 0x1fe57a8 col:9 implicit 'auto (T) -> A' +| | `-ParmVarDecl 0x1fe56b0 col:12 'T' +| `-CXXDeductionGuideDecl 0x20515d8 col:9 implicit used 'auto (int) -> A' +| |-TemplateArgument type 'int' +| | `-BuiltinType 0x20587e0 'int' +| `-ParmVarDecl 0x2051388 col:12 'int':'int' +`-FunctionTemplateDecl 0x1fe5a78 col:36 implicit + |-TemplateTypeParmDecl 0x1fe4eb0 col:26 referenced typename depth 0 index 0 T + `-CXXDeductionGuideDecl 0x1fe59c0 col:36 implicit 'auto (A) -> A' + `-ParmVarDecl 0x1fe5958 col:36 'A' +*/ +// clang-format on + auto *FromD1 = FirstDeclMatcher().match( + FromTU, cxxDeductionGuideDecl()); + auto *FromD2 = LastDeclMatcher().match( + FromTU, cxxDeductionGuideDecl()); + + NamedDecl *P1 = + FromD1->getDescribedFunctionTemplate()->getTemplateParameters()->getParam( + 0); + NamedDecl *P2 = + FromD2->getDescribedFunctionTemplate()->getTemplateParameters()->getParam( + 0); + DeclContext *DC = P1->getDeclContext(); + + ASSERT_EQ(P1, P2); + ASSERT_TRUE(DC == FromD1 || DC == FromD2); + + auto *ToD1 = Import(FromD1, Lang_CXX17); + auto *ToD2 = Import(FromD2, Lang_CXX17); + ASSERT_TRUE(ToD1 && ToD2); + + P1 = ToD1->getDescribedFunctionTemplate()->getTemplateParameters()->getParam( + 0); + P2 = ToD2->getDescribedFunctionTemplate()->getTemplateParameters()->getParam( + 0); + DC = P1->getDeclContext(); + + EXPECT_EQ(P1, P2); + EXPECT_TRUE(DC == ToD1 || DC == ToD2); + + ASTImporterLookupTable *Tbl = SharedStatePtr->getLookupTable(); + if (Tbl->contains(ToD1, P1)) { + EXPECT_FALSE(Tbl->contains(ToD2, P1)); + } else { + EXPECT_TRUE(Tbl->contains(ToD2, P1)); + } +} + +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) {