Author: Balázs Kéri Date: 2023-03-03T09:16:43+01:00 New Revision: 27ab138c69fc61b22ef898a0f4d0f5c9bad649bd
URL: https://github.com/llvm/llvm-project/commit/27ab138c69fc61b22ef898a0f4d0f5c9bad649bd DIFF: https://github.com/llvm/llvm-project/commit/27ab138c69fc61b22ef898a0f4d0f5c9bad649bd.diff LOG: [clang][ASTImporter] Import TemplateName correctly This is a fix for a problem when multiple template specializations are created by ASTImporter for the same specialization. The problem happens if a TemplateName is imported that points to a template delcaration (for a template template argument) (specialization) that has multiple instances in the declaration chain. If two TemplateName objects contain different pointers to a template specialization, these TemplateName objects will have different checksum even if they point into the same declaration chain. The problem is fixed if the canonical declaration is used. Reviewed By: vabridgers, donat.nagy Differential Revision: https://reviews.llvm.org/D144622 Added: Modified: clang/lib/AST/ASTImporter.cpp clang/unittests/AST/ASTImporterTest.cpp Removed: ################################################################################ diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp index 4c173ebb10d1e..bd055082778df 100644 --- a/clang/lib/AST/ASTImporter.cpp +++ b/clang/lib/AST/ASTImporter.cpp @@ -9385,7 +9385,7 @@ Expected<TemplateName> ASTImporter::Import(TemplateName From) { switch (From.getKind()) { case TemplateName::Template: if (ExpectedDecl ToTemplateOrErr = Import(From.getAsTemplateDecl())) - return TemplateName(cast<TemplateDecl>(*ToTemplateOrErr)); + return TemplateName(cast<TemplateDecl>((*ToTemplateOrErr)->getCanonicalDecl())); else return ToTemplateOrErr.takeError(); diff --git a/clang/unittests/AST/ASTImporterTest.cpp b/clang/unittests/AST/ASTImporterTest.cpp index 87b9fe52d906c..3c9b804a92e13 100644 --- a/clang/unittests/AST/ASTImporterTest.cpp +++ b/clang/unittests/AST/ASTImporterTest.cpp @@ -8378,6 +8378,66 @@ TEST_P(ImportInjectedClassNameType, ImportTypedefType) { EXPECT_TRUE(ToCtx.hasSameType(ToInjTypedef, ToInjParmVar)); } +TEST_P(ASTImporterOptionSpecificTestBase, ImportCorrectTemplateName) { + constexpr auto TestCode = R"( + template <class T> + struct A; + template <class T> + struct A {}; + template <template<class> class T = A> + struct B {}; + using C = B<>; + )"; + Decl *ToTU = getToTuDecl(TestCode, Lang_CXX11); + Decl *FromTU = getTuDecl(TestCode, Lang_CXX11); + + auto *ToUsingFirst = FirstDeclMatcher<TypeAliasDecl>().match( + ToTU, typeAliasDecl(hasName("C"))); + + auto *FromUsing = FirstDeclMatcher<TypeAliasDecl>().match( + FromTU, typeAliasDecl(hasName("C"))); + auto *ToUsing = Import(FromUsing, Lang_CXX11); + EXPECT_TRUE(ToUsing); + + auto *ToB = FirstDeclMatcher<ClassTemplateDecl>().match( + ToTU, classTemplateDecl(hasName("B"))); + auto *ToB1 = LastDeclMatcher<ClassTemplateDecl>().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<ClassTemplateSpecializationDecl>( + ToUsing->getUnderlyingType() + ->getAs<TemplateSpecializationType>() + ->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); _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits