Skip to content

Commit 8612730

Browse files
authored
[clang][ASTImporter][StructuralEquivalence] improve StructuralEquivalence on recordType (llvm#76226)
Types comparison in `StructuralEquivalence` ignores its `DeclContext` when they are generated by template specialization implicitly and this will produce incorrect result. Add comparison of `DeclContext` of ClassTemplateSpecializationDecl to improve result. fix [issue](llvm#65913) Co-authored-by: huqizhi <[email protected]>
1 parent d187dfe commit 8612730

File tree

2 files changed

+33
-3
lines changed

2 files changed

+33
-3
lines changed

clang/lib/AST/ASTStructuralEquivalence.cpp

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1463,8 +1463,9 @@ IsStructurallyEquivalentLambdas(StructuralEquivalenceContext &Context,
14631463
}
14641464

14651465
/// Determine if context of a class is equivalent.
1466-
static bool IsRecordContextStructurallyEquivalent(RecordDecl *D1,
1467-
RecordDecl *D2) {
1466+
static bool
1467+
IsRecordContextStructurallyEquivalent(StructuralEquivalenceContext &Context,
1468+
RecordDecl *D1, RecordDecl *D2) {
14681469
// The context should be completely equal, including anonymous and inline
14691470
// namespaces.
14701471
// We compare objects as part of full translation units, not subtrees of
@@ -1491,6 +1492,12 @@ static bool IsRecordContextStructurallyEquivalent(RecordDecl *D1,
14911492
return false;
14921493
}
14931494

1495+
if (auto *D1Spec = dyn_cast<ClassTemplateSpecializationDecl>(DC1)) {
1496+
auto *D2Spec = dyn_cast<ClassTemplateSpecializationDecl>(DC2);
1497+
if (!IsStructurallyEquivalent(Context, D1Spec, D2Spec))
1498+
return false;
1499+
}
1500+
14941501
DC1 = DC1->getParent()->getNonTransparentContext();
14951502
DC2 = DC2->getParent()->getNonTransparentContext();
14961503
}
@@ -1544,7 +1551,7 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
15441551
// If the records occur in different context (namespace), these should be
15451552
// different. This is specially important if the definition of one or both
15461553
// records is missing.
1547-
if (!IsRecordContextStructurallyEquivalent(D1, D2))
1554+
if (!IsRecordContextStructurallyEquivalent(Context, D1, D2))
15481555
return false;
15491556

15501557
// If both declarations are class template specializations, we know

clang/unittests/AST/StructuralEquivalenceTest.cpp

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1024,6 +1024,29 @@ TEST_F(StructuralEquivalenceRecordContextTest, TransparentContextInNamespace) {
10241024
EXPECT_TRUE(testStructuralMatch(Decls));
10251025
}
10261026

1027+
TEST_F(StructuralEquivalenceRecordContextTest,
1028+
ClassTemplateSpecializationContext) {
1029+
std::string Code =
1030+
R"(
1031+
template <typename T> struct O {
1032+
struct M {};
1033+
};
1034+
)";
1035+
auto t = makeDecls<VarDecl>(Code + R"(
1036+
typedef O<int>::M MT1;
1037+
MT1 A;
1038+
)",
1039+
Code + R"(
1040+
namespace {
1041+
struct I {};
1042+
} // namespace
1043+
typedef O<I>::M MT2;
1044+
MT2 A;
1045+
)",
1046+
Lang_CXX11, varDecl(hasName("A")));
1047+
EXPECT_FALSE(testStructuralMatch(t));
1048+
}
1049+
10271050
TEST_F(StructuralEquivalenceTest, NamespaceOfRecordMember) {
10281051
auto Decls = makeNamedDecls(
10291052
R"(

0 commit comments

Comments
 (0)