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 @@ -9385,7 +9385,7 @@ switch (From.getKind()) { case TemplateName::Template: if (ExpectedDecl ToTemplateOrErr = Import(From.getAsTemplateDecl())) - return TemplateName(cast(*ToTemplateOrErr)); + return TemplateName(cast((*ToTemplateOrErr)->getCanonicalDecl())); else return ToTemplateOrErr.takeError(); 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 @@ -8378,6 +8378,66 @@ EXPECT_TRUE(ToCtx.hasSameType(ToInjTypedef, ToInjParmVar)); } +TEST_P(ASTImporterOptionSpecificTestBase, ImportCorrectTemplateName) { + constexpr auto TestCode = R"( + template + struct A; + template + struct A {}; + template class T = A> + struct B {}; + using C = B<>; + )"; + Decl *ToTU = getToTuDecl(TestCode, Lang_CXX11); + Decl *FromTU = getTuDecl(TestCode, Lang_CXX11); + + auto *ToUsingFirst = FirstDeclMatcher().match( + ToTU, typeAliasDecl(hasName("C"))); + + auto *FromUsing = FirstDeclMatcher().match( + FromTU, typeAliasDecl(hasName("C"))); + auto *ToUsing = Import(FromUsing, Lang_CXX11); + EXPECT_TRUE(ToUsing); + + auto *ToB = FirstDeclMatcher().match( + ToTU, classTemplateDecl(hasName("B"))); + auto *ToB1 = LastDeclMatcher().match( + ToTU, classTemplateDecl(hasName("B"))); + // One template definition of 'B' should exist. + EXPECT_EQ(ToB, ToB1); + + // These declarations are imported separately. + EXPECT_NE(ToUsingFirst, ToUsing); + + auto SpB = ToB->spec_begin(); + auto SpE = ToB->spec_end(); + EXPECT_TRUE(SpB != SpE); + ClassTemplateSpecializationDecl *Spec1 = *SpB; + ++SpB; + // The template 'B' should have one specialization (with default argument). + EXPECT_TRUE(SpB == SpE); + + // Even if 'B' has one specialization with the default arguments, the AST + // contains after the import two specializations that are linked in the + // declaration chain. The 'spec_begin' iteration does not find these because + // the template arguments are the same. But the imported type alias has the + // link to the second specialization. The template name object in these + // specializations must point to the same (and one) instance of definition of + // 'B'. + auto *Spec2 = cast( + ToUsing->getUnderlyingType() + ->getAs() + ->getAsRecordDecl()); + EXPECT_NE(Spec1, Spec2); + EXPECT_TRUE(Spec1->getPreviousDecl() == Spec2 || + Spec2->getPreviousDecl() == Spec1); + TemplateDecl *Templ1 = + Spec1->getTemplateArgs()[0].getAsTemplate().getAsTemplateDecl(); + TemplateDecl *Templ2 = + Spec2->getTemplateArgs()[0].getAsTemplate().getAsTemplateDecl(); + EXPECT_EQ(Templ1, Templ2); +} + INSTANTIATE_TEST_SUITE_P(ParameterizedTests, ASTImporterLookupTableTest, DefaultTestValuesForRunOptions);