r366818 - [ASTImporter] Fix inequivalence of ClassTemplateInstantiations
Gabor Marton via cfe-commits
cfe-commits at lists.llvm.org
Tue Jul 23 08:46:38 PDT 2019
Author: martong
Date: Tue Jul 23 08:46:38 2019
New Revision: 366818
URL: http://llvm.org/viewvc/llvm-project?rev=366818&view=rev
Log:
[ASTImporter] Fix inequivalence of ClassTemplateInstantiations
Summary:
We falsely state inequivalence if the template parameter is a
qualified/nonquialified template in the first/second instantiation.
Also, different kinds of TemplateName should be equal if the template
decl (if available) is equal (even if the name kind is different).
Reviewers: a_sidorin, a.sidorin
Subscribers: rnkovacs, dkrupp, Szelethus, gamesh411, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D64241
Modified:
cfe/trunk/lib/AST/ASTStructuralEquivalence.cpp
cfe/trunk/unittests/AST/StructuralEquivalenceTest.cpp
Modified: cfe/trunk/lib/AST/ASTStructuralEquivalence.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ASTStructuralEquivalence.cpp?rev=366818&r1=366817&r2=366818&view=diff
==============================================================================
--- cfe/trunk/lib/AST/ASTStructuralEquivalence.cpp (original)
+++ cfe/trunk/lib/AST/ASTStructuralEquivalence.cpp Tue Jul 23 08:46:38 2019
@@ -235,12 +235,21 @@ static bool IsStructurallyEquivalent(Str
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 @@ static bool IsStructurallyEquivalent(Str
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 @@ static bool IsStructurallyEquivalent(Str
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 @@ static bool IsStructurallyEquivalent(Str
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.
Modified: cfe/trunk/unittests/AST/StructuralEquivalenceTest.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/AST/StructuralEquivalenceTest.cpp?rev=366818&r1=366817&r2=366818&view=diff
==============================================================================
--- cfe/trunk/unittests/AST/StructuralEquivalenceTest.cpp (original)
+++ cfe/trunk/unittests/AST/StructuralEquivalenceTest.cpp Tue Jul 23 08:46:38 2019
@@ -944,6 +944,67 @@ TEST_F(StructuralEquivalenceTemplateTest
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 @@ TEST_F(StructuralEquivalenceDependentTem
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
More information about the cfe-commits
mailing list