balazske updated this revision to Diff 501161. balazske added a comment. Added a test case.
Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D144622/new/ https://reviews.llvm.org/D144622 Files: clang/lib/AST/ASTImporter.cpp clang/unittests/AST/ASTImporterTest.cpp Index: clang/unittests/AST/ASTImporterTest.cpp =================================================================== --- clang/unittests/AST/ASTImporterTest.cpp +++ clang/unittests/AST/ASTImporterTest.cpp @@ -8137,6 +8137,76 @@ EXPECT_FALSE(SharedStatePtr->isNewDecl(ToBar)); } +TEST_P(ASTImporterOptionSpecificTestBase, ImportCorrectTemplateName) { + Decl *ToTU = getToTuDecl( + R"( + template <class T> + struct A; + template <class T> + struct A {}; + template <template<class> class T = A> + struct B {}; + using C = B<>; + )", + Lang_CXX11); + Decl *FromTU = getTuDecl( + R"( + template <class T> + struct A; + template <class T> + struct A {}; + template <template<class> class T = A> + struct B {}; + using C = B<>; + )", + 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_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); Index: clang/lib/AST/ASTImporter.cpp =================================================================== --- clang/lib/AST/ASTImporter.cpp +++ clang/lib/AST/ASTImporter.cpp @@ -9376,7 +9376,7 @@ 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();
Index: clang/unittests/AST/ASTImporterTest.cpp =================================================================== --- clang/unittests/AST/ASTImporterTest.cpp +++ clang/unittests/AST/ASTImporterTest.cpp @@ -8137,6 +8137,76 @@ EXPECT_FALSE(SharedStatePtr->isNewDecl(ToBar)); } +TEST_P(ASTImporterOptionSpecificTestBase, ImportCorrectTemplateName) { + Decl *ToTU = getToTuDecl( + R"( + template <class T> + struct A; + template <class T> + struct A {}; + template <template<class> class T = A> + struct B {}; + using C = B<>; + )", + Lang_CXX11); + Decl *FromTU = getTuDecl( + R"( + template <class T> + struct A; + template <class T> + struct A {}; + template <template<class> class T = A> + struct B {}; + using C = B<>; + )", + 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_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); Index: clang/lib/AST/ASTImporter.cpp =================================================================== --- clang/lib/AST/ASTImporter.cpp +++ clang/lib/AST/ASTImporter.cpp @@ -9376,7 +9376,7 @@ 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();
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits