Skip to content

Commit 123f6ff

Browse files
author
Gabor Marton
committed
[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 llvm-svn: 366818
1 parent 0e8359a commit 123f6ff

File tree

2 files changed

+214
-22
lines changed

2 files changed

+214
-22
lines changed

clang/lib/AST/ASTStructuralEquivalence.cpp

Lines changed: 22 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -235,12 +235,21 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
235235
static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
236236
const TemplateName &N1,
237237
const TemplateName &N2) {
238-
if (N1.getKind() != N2.getKind())
238+
TemplateDecl *TemplateDeclN1 = N1.getAsTemplateDecl();
239+
TemplateDecl *TemplateDeclN2 = N2.getAsTemplateDecl();
240+
if (TemplateDeclN1 && TemplateDeclN2) {
241+
if (!IsStructurallyEquivalent(Context, TemplateDeclN1, TemplateDeclN2))
242+
return false;
243+
// If the kind is different we compare only the template decl.
244+
if (N1.getKind() != N2.getKind())
245+
return true;
246+
} else if (TemplateDeclN1 || TemplateDeclN2)
239247
return false;
248+
else if (N1.getKind() != N2.getKind())
249+
return false;
250+
251+
// Check for special case incompatibilities.
240252
switch (N1.getKind()) {
241-
case TemplateName::Template:
242-
return IsStructurallyEquivalent(Context, N1.getAsTemplateDecl(),
243-
N2.getAsTemplateDecl());
244253

245254
case TemplateName::OverloadedTemplate: {
246255
OverloadedTemplateStorage *OS1 = N1.getAsOverloadedTemplate(),
@@ -259,14 +268,6 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
259268
return TN1->getDeclName() == TN2->getDeclName();
260269
}
261270

262-
case TemplateName::QualifiedTemplate: {
263-
QualifiedTemplateName *QN1 = N1.getAsQualifiedTemplateName(),
264-
*QN2 = N2.getAsQualifiedTemplateName();
265-
return IsStructurallyEquivalent(Context, QN1->getDecl(), QN2->getDecl()) &&
266-
IsStructurallyEquivalent(Context, QN1->getQualifier(),
267-
QN2->getQualifier());
268-
}
269-
270271
case TemplateName::DependentTemplate: {
271272
DependentTemplateName *DN1 = N1.getAsDependentTemplateName(),
272273
*DN2 = N2.getAsDependentTemplateName();
@@ -281,15 +282,6 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
281282
return false;
282283
}
283284

284-
case TemplateName::SubstTemplateTemplateParm: {
285-
SubstTemplateTemplateParmStorage *TS1 = N1.getAsSubstTemplateTemplateParm(),
286-
*TS2 = N2.getAsSubstTemplateTemplateParm();
287-
return IsStructurallyEquivalent(Context, TS1->getParameter(),
288-
TS2->getParameter()) &&
289-
IsStructurallyEquivalent(Context, TS1->getReplacement(),
290-
TS2->getReplacement());
291-
}
292-
293285
case TemplateName::SubstTemplateTemplateParmPack: {
294286
SubstTemplateTemplateParmPackStorage
295287
*P1 = N1.getAsSubstTemplateTemplateParmPack(),
@@ -299,8 +291,16 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
299291
IsStructurallyEquivalent(Context, P1->getParameterPack(),
300292
P2->getParameterPack());
301293
}
294+
295+
case TemplateName::Template:
296+
case TemplateName::QualifiedTemplate:
297+
case TemplateName::SubstTemplateTemplateParm:
298+
// It is sufficient to check value of getAsTemplateDecl.
299+
break;
300+
302301
}
303-
return false;
302+
303+
return true;
304304
}
305305

306306
/// Determine whether two template arguments are equivalent.

clang/unittests/AST/StructuralEquivalenceTest.cpp

Lines changed: 192 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -944,6 +944,67 @@ TEST_F(StructuralEquivalenceTemplateTest, ExplicitBoolDifference) {
944944
EXPECT_FALSE(testStructuralMatch(First, Second));
945945
}
946946

947+
TEST_F(StructuralEquivalenceTemplateTest,
948+
TemplateVsSubstTemplateTemplateParmInArgEq) {
949+
auto t = makeDecls<ClassTemplateSpecializationDecl>(
950+
R"(
951+
template <typename P1> class Arg { };
952+
template <template <typename PP1> class P1> class Primary { };
953+
954+
void f() {
955+
// Make specialization with simple template.
956+
Primary <Arg> A;
957+
}
958+
)",
959+
R"(
960+
template <typename P1> class Arg { };
961+
template <template <typename PP1> class P1> class Primary { };
962+
963+
template <template <typename PP1> class P1> class Templ {
964+
void f() {
965+
// Make specialization with substituted template template param.
966+
Primary <P1> A;
967+
};
968+
};
969+
970+
// Instantiate with substitution Arg into P1.
971+
template class Templ <Arg>;
972+
)",
973+
Lang_CXX, classTemplateSpecializationDecl(hasName("Primary")));
974+
EXPECT_TRUE(testStructuralMatch(t));
975+
}
976+
977+
TEST_F(StructuralEquivalenceTemplateTest,
978+
TemplateVsSubstTemplateTemplateParmInArgNotEq) {
979+
auto t = makeDecls<ClassTemplateSpecializationDecl>(
980+
R"(
981+
template <typename P1> class Arg { };
982+
template <template <typename PP1> class P1> class Primary { };
983+
984+
void f() {
985+
// Make specialization with simple template.
986+
Primary <Arg> A;
987+
}
988+
)",
989+
R"(
990+
// Arg is different from the other, this should cause non-equivalence.
991+
template <typename P1> class Arg { int X; };
992+
template <template <typename PP1> class P1> class Primary { };
993+
994+
template <template <typename PP1> class P1> class Templ {
995+
void f() {
996+
// Make specialization with substituted template template param.
997+
Primary <P1> A;
998+
};
999+
};
1000+
1001+
// Instantiate with substitution Arg into P1.
1002+
template class Templ <Arg>;
1003+
)",
1004+
Lang_CXX, classTemplateSpecializationDecl(hasName("Primary")));
1005+
EXPECT_FALSE(testStructuralMatch(t));
1006+
}
1007+
9471008
struct StructuralEquivalenceDependentTemplateArgsTest
9481009
: StructuralEquivalenceTemplateTest {};
9491010

@@ -1082,5 +1143,136 @@ TEST_F(StructuralEquivalenceDependentTemplateArgsTest,
10821143
EXPECT_FALSE(testStructuralMatch(t));
10831144
}
10841145

1146+
TEST_F(
1147+
StructuralEquivalenceTemplateTest,
1148+
ClassTemplSpecWithQualifiedAndNonQualifiedTypeArgsShouldBeEqual) {
1149+
auto t = makeDecls<ClassTemplateSpecializationDecl>(
1150+
R"(
1151+
template <class T> struct Primary {};
1152+
namespace N {
1153+
struct Arg;
1154+
}
1155+
// Explicit instantiation with qualified name.
1156+
template struct Primary<N::Arg>;
1157+
)",
1158+
R"(
1159+
template <class T> struct Primary {};
1160+
namespace N {
1161+
struct Arg;
1162+
}
1163+
using namespace N;
1164+
// Explicit instantiation with UNqualified name.
1165+
template struct Primary<Arg>;
1166+
)",
1167+
Lang_CXX,
1168+
classTemplateSpecializationDecl(hasName("Primary")));
1169+
EXPECT_TRUE(testStructuralMatch(t));
1170+
}
1171+
1172+
TEST_F(
1173+
StructuralEquivalenceTemplateTest,
1174+
ClassTemplSpecWithInequivalentQualifiedAndNonQualifiedTypeArgs) {
1175+
auto t = makeDecls<ClassTemplateSpecializationDecl>(
1176+
R"(
1177+
template <class T> struct Primary {};
1178+
namespace N {
1179+
struct Arg { int a; };
1180+
}
1181+
// Explicit instantiation with qualified name.
1182+
template struct Primary<N::Arg>;
1183+
)",
1184+
R"(
1185+
template <class T> struct Primary {};
1186+
namespace N {
1187+
// This struct is not equivalent with the other in the prev TU.
1188+
struct Arg { double b; }; // -- Field mismatch.
1189+
}
1190+
using namespace N;
1191+
// Explicit instantiation with UNqualified name.
1192+
template struct Primary<Arg>;
1193+
)",
1194+
Lang_CXX,
1195+
classTemplateSpecializationDecl(hasName("Primary")));
1196+
EXPECT_FALSE(testStructuralMatch(t));
1197+
}
1198+
1199+
TEST_F(
1200+
StructuralEquivalenceTemplateTest,
1201+
ClassTemplSpecWithQualifiedAndNonQualifiedTemplArgsShouldBeEqual) {
1202+
auto t = makeDecls<ClassTemplateSpecializationDecl>(
1203+
R"(
1204+
template <template <class> class T> struct Primary {};
1205+
namespace N {
1206+
template <class T> struct Arg;
1207+
}
1208+
// Explicit instantiation with qualified name.
1209+
template struct Primary<N::Arg>;
1210+
)",
1211+
R"(
1212+
template <template <class> class T> struct Primary {};
1213+
namespace N {
1214+
template <class T> struct Arg;
1215+
}
1216+
using namespace N;
1217+
// Explicit instantiation with UNqualified name.
1218+
template struct Primary<Arg>;
1219+
)",
1220+
Lang_CXX,
1221+
classTemplateSpecializationDecl(hasName("Primary")));
1222+
EXPECT_TRUE(testStructuralMatch(t));
1223+
}
1224+
1225+
TEST_F(
1226+
StructuralEquivalenceTemplateTest,
1227+
ClassTemplSpecWithInequivalentQualifiedAndNonQualifiedTemplArgs) {
1228+
auto t = makeDecls<ClassTemplateSpecializationDecl>(
1229+
R"(
1230+
template <template <class> class T> struct Primary {};
1231+
namespace N {
1232+
template <class T> struct Arg { int a; };
1233+
}
1234+
// Explicit instantiation with qualified name.
1235+
template struct Primary<N::Arg>;
1236+
)",
1237+
R"(
1238+
template <template <class> class T> struct Primary {};
1239+
namespace N {
1240+
// This template is not equivalent with the other in the prev TU.
1241+
template <class T> struct Arg { double b; }; // -- Field mismatch.
1242+
}
1243+
using namespace N;
1244+
// Explicit instantiation with UNqualified name.
1245+
template struct Primary<Arg>;
1246+
)",
1247+
Lang_CXX,
1248+
classTemplateSpecializationDecl(hasName("Primary")));
1249+
EXPECT_FALSE(testStructuralMatch(t));
1250+
}
1251+
1252+
TEST_F(
1253+
StructuralEquivalenceTemplateTest,
1254+
ClassTemplSpecWithInequivalentShadowedTemplArg) {
1255+
auto t = makeDecls<ClassTemplateSpecializationDecl>(
1256+
R"(
1257+
template <template <class> class T> struct Primary {};
1258+
template <class T> struct Arg { int a; };
1259+
// Explicit instantiation with ::Arg
1260+
template struct Primary<Arg>;
1261+
)",
1262+
R"(
1263+
template <template <class> class T> struct Primary {};
1264+
template <class T> struct Arg { int a; };
1265+
namespace N {
1266+
// This template is not equivalent with the other in the global scope.
1267+
template <class T> struct Arg { double b; }; // -- Field mismatch.
1268+
// Explicit instantiation with N::Arg which shadows ::Arg
1269+
template struct Primary<Arg>;
1270+
}
1271+
)",
1272+
Lang_CXX,
1273+
classTemplateSpecializationDecl(hasName("Primary")));
1274+
EXPECT_FALSE(testStructuralMatch(t));
1275+
}
1276+
10851277
} // end namespace ast_matchers
10861278
} // end namespace clang

0 commit comments

Comments
 (0)