This revision was automatically updated to reflect the committed changes. Closed by commit rL366818: [ASTImporter] Fix inequivalence of ClassTemplateInstantiations (authored by martong, committed by ). Herald added a project: LLVM. Herald added a subscriber: llvm-commits.
Changed prior to commit: https://reviews.llvm.org/D64241?vs=210581&id=211311#toc Repository: rL LLVM CHANGES SINCE LAST ACTION https://reviews.llvm.org/D64241/new/ https://reviews.llvm.org/D64241 Files: cfe/trunk/lib/AST/ASTStructuralEquivalence.cpp cfe/trunk/unittests/AST/StructuralEquivalenceTest.cpp
Index: cfe/trunk/lib/AST/ASTStructuralEquivalence.cpp =================================================================== --- cfe/trunk/lib/AST/ASTStructuralEquivalence.cpp +++ cfe/trunk/lib/AST/ASTStructuralEquivalence.cpp @@ -235,12 +235,21 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, const TemplateName &N1, const TemplateName &N2) { - if (N1.getKind() != N2.getKind()) + TemplateDecl *TemplateDeclN1 = N1.getAsTemplateDecl(); + TemplateDecl *TemplateDeclN2 = N2.getAsTemplateDecl(); + if (TemplateDeclN1 && TemplateDeclN2) { + if (!IsStructurallyEquivalent(Context, TemplateDeclN1, TemplateDeclN2)) + return false; + // If the kind is different we compare only the template decl. + if (N1.getKind() != N2.getKind()) + return true; + } else if (TemplateDeclN1 || TemplateDeclN2) return false; + else if (N1.getKind() != N2.getKind()) + return false; + + // Check for special case incompatibilities. switch (N1.getKind()) { - case TemplateName::Template: - return IsStructurallyEquivalent(Context, N1.getAsTemplateDecl(), - N2.getAsTemplateDecl()); case TemplateName::OverloadedTemplate: { OverloadedTemplateStorage *OS1 = N1.getAsOverloadedTemplate(), @@ -259,14 +268,6 @@ return TN1->getDeclName() == TN2->getDeclName(); } - case TemplateName::QualifiedTemplate: { - QualifiedTemplateName *QN1 = N1.getAsQualifiedTemplateName(), - *QN2 = N2.getAsQualifiedTemplateName(); - return IsStructurallyEquivalent(Context, QN1->getDecl(), QN2->getDecl()) && - IsStructurallyEquivalent(Context, QN1->getQualifier(), - QN2->getQualifier()); - } - case TemplateName::DependentTemplate: { DependentTemplateName *DN1 = N1.getAsDependentTemplateName(), *DN2 = N2.getAsDependentTemplateName(); @@ -281,15 +282,6 @@ return false; } - case TemplateName::SubstTemplateTemplateParm: { - SubstTemplateTemplateParmStorage *TS1 = N1.getAsSubstTemplateTemplateParm(), - *TS2 = N2.getAsSubstTemplateTemplateParm(); - return IsStructurallyEquivalent(Context, TS1->getParameter(), - TS2->getParameter()) && - IsStructurallyEquivalent(Context, TS1->getReplacement(), - TS2->getReplacement()); - } - case TemplateName::SubstTemplateTemplateParmPack: { SubstTemplateTemplateParmPackStorage *P1 = N1.getAsSubstTemplateTemplateParmPack(), @@ -299,8 +291,16 @@ IsStructurallyEquivalent(Context, P1->getParameterPack(), P2->getParameterPack()); } + + case TemplateName::Template: + case TemplateName::QualifiedTemplate: + case TemplateName::SubstTemplateTemplateParm: + // It is sufficient to check value of getAsTemplateDecl. + break; + } - return false; + + return true; } /// Determine whether two template arguments are equivalent. Index: cfe/trunk/unittests/AST/StructuralEquivalenceTest.cpp =================================================================== --- cfe/trunk/unittests/AST/StructuralEquivalenceTest.cpp +++ cfe/trunk/unittests/AST/StructuralEquivalenceTest.cpp @@ -944,6 +944,67 @@ EXPECT_FALSE(testStructuralMatch(First, Second)); } +TEST_F(StructuralEquivalenceTemplateTest, + TemplateVsSubstTemplateTemplateParmInArgEq) { + auto t = makeDecls<ClassTemplateSpecializationDecl>( + R"( +template <typename P1> class Arg { }; +template <template <typename PP1> class P1> class Primary { }; + +void f() { + // Make specialization with simple template. + Primary <Arg> A; +} + )", + R"( +template <typename P1> class Arg { }; +template <template <typename PP1> class P1> class Primary { }; + +template <template <typename PP1> class P1> class Templ { + void f() { + // Make specialization with substituted template template param. + Primary <P1> A; + }; +}; + +// Instantiate with substitution Arg into P1. +template class Templ <Arg>; + )", + Lang_CXX, classTemplateSpecializationDecl(hasName("Primary"))); + EXPECT_TRUE(testStructuralMatch(t)); +} + +TEST_F(StructuralEquivalenceTemplateTest, + TemplateVsSubstTemplateTemplateParmInArgNotEq) { + auto t = makeDecls<ClassTemplateSpecializationDecl>( + R"( +template <typename P1> class Arg { }; +template <template <typename PP1> class P1> class Primary { }; + +void f() { + // Make specialization with simple template. + Primary <Arg> A; +} + )", + R"( +// Arg is different from the other, this should cause non-equivalence. +template <typename P1> class Arg { int X; }; +template <template <typename PP1> class P1> class Primary { }; + +template <template <typename PP1> class P1> class Templ { + void f() { + // Make specialization with substituted template template param. + Primary <P1> A; + }; +}; + +// Instantiate with substitution Arg into P1. +template class Templ <Arg>; + )", + Lang_CXX, classTemplateSpecializationDecl(hasName("Primary"))); + EXPECT_FALSE(testStructuralMatch(t)); +} + struct StructuralEquivalenceDependentTemplateArgsTest : StructuralEquivalenceTemplateTest {}; @@ -1082,5 +1143,136 @@ EXPECT_FALSE(testStructuralMatch(t)); } +TEST_F( + StructuralEquivalenceTemplateTest, + ClassTemplSpecWithQualifiedAndNonQualifiedTypeArgsShouldBeEqual) { + auto t = makeDecls<ClassTemplateSpecializationDecl>( + R"( + template <class T> struct Primary {}; + namespace N { + struct Arg; + } + // Explicit instantiation with qualified name. + template struct Primary<N::Arg>; + )", + R"( + template <class T> struct Primary {}; + namespace N { + struct Arg; + } + using namespace N; + // Explicit instantiation with UNqualified name. + template struct Primary<Arg>; + )", + Lang_CXX, + classTemplateSpecializationDecl(hasName("Primary"))); + EXPECT_TRUE(testStructuralMatch(t)); +} + +TEST_F( + StructuralEquivalenceTemplateTest, + ClassTemplSpecWithInequivalentQualifiedAndNonQualifiedTypeArgs) { + auto t = makeDecls<ClassTemplateSpecializationDecl>( + R"( + template <class T> struct Primary {}; + namespace N { + struct Arg { int a; }; + } + // Explicit instantiation with qualified name. + template struct Primary<N::Arg>; + )", + R"( + template <class T> struct Primary {}; + namespace N { + // This struct is not equivalent with the other in the prev TU. + struct Arg { double b; }; // -- Field mismatch. + } + using namespace N; + // Explicit instantiation with UNqualified name. + template struct Primary<Arg>; + )", + Lang_CXX, + classTemplateSpecializationDecl(hasName("Primary"))); + EXPECT_FALSE(testStructuralMatch(t)); +} + +TEST_F( + StructuralEquivalenceTemplateTest, + ClassTemplSpecWithQualifiedAndNonQualifiedTemplArgsShouldBeEqual) { + auto t = makeDecls<ClassTemplateSpecializationDecl>( + R"( + template <template <class> class T> struct Primary {}; + namespace N { + template <class T> struct Arg; + } + // Explicit instantiation with qualified name. + template struct Primary<N::Arg>; + )", + R"( + template <template <class> class T> struct Primary {}; + namespace N { + template <class T> struct Arg; + } + using namespace N; + // Explicit instantiation with UNqualified name. + template struct Primary<Arg>; + )", + Lang_CXX, + classTemplateSpecializationDecl(hasName("Primary"))); + EXPECT_TRUE(testStructuralMatch(t)); +} + +TEST_F( + StructuralEquivalenceTemplateTest, + ClassTemplSpecWithInequivalentQualifiedAndNonQualifiedTemplArgs) { + auto t = makeDecls<ClassTemplateSpecializationDecl>( + R"( + template <template <class> class T> struct Primary {}; + namespace N { + template <class T> struct Arg { int a; }; + } + // Explicit instantiation with qualified name. + template struct Primary<N::Arg>; + )", + R"( + template <template <class> class T> struct Primary {}; + namespace N { + // This template is not equivalent with the other in the prev TU. + template <class T> struct Arg { double b; }; // -- Field mismatch. + } + using namespace N; + // Explicit instantiation with UNqualified name. + template struct Primary<Arg>; + )", + Lang_CXX, + classTemplateSpecializationDecl(hasName("Primary"))); + EXPECT_FALSE(testStructuralMatch(t)); +} + +TEST_F( + StructuralEquivalenceTemplateTest, + ClassTemplSpecWithInequivalentShadowedTemplArg) { + auto t = makeDecls<ClassTemplateSpecializationDecl>( + R"( + template <template <class> class T> struct Primary {}; + template <class T> struct Arg { int a; }; + // Explicit instantiation with ::Arg + template struct Primary<Arg>; + )", + R"( + template <template <class> class T> struct Primary {}; + template <class T> struct Arg { int a; }; + namespace N { + // This template is not equivalent with the other in the global scope. + template <class T> struct Arg { double b; }; // -- Field mismatch. + // Explicit instantiation with N::Arg which shadows ::Arg + template struct Primary<Arg>; + } + )", + Lang_CXX, + classTemplateSpecializationDecl(hasName("Primary"))); + EXPECT_FALSE(testStructuralMatch(t)); +} + } // end namespace ast_matchers } // end namespace clang
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits