Skip to content

Commit

Permalink
[clang][ASTImporter][StructuralEquivalence] improve StructuralEquival…
Browse files Browse the repository at this point in the history
…ence on recordType (#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](#65913)

Co-authored-by: huqizhi <836744285@qq.com>
  • Loading branch information
jcsxky committed Jan 5, 2024
1 parent d187dfe commit 8612730
Show file tree
Hide file tree
Showing 2 changed files with 33 additions and 3 deletions.
13 changes: 10 additions & 3 deletions clang/lib/AST/ASTStructuralEquivalence.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1463,8 +1463,9 @@ IsStructurallyEquivalentLambdas(StructuralEquivalenceContext &Context,
}

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

if (auto *D1Spec = dyn_cast<ClassTemplateSpecializationDecl>(DC1)) {
auto *D2Spec = dyn_cast<ClassTemplateSpecializationDecl>(DC2);
if (!IsStructurallyEquivalent(Context, D1Spec, D2Spec))
return false;
}

DC1 = DC1->getParent()->getNonTransparentContext();
DC2 = DC2->getParent()->getNonTransparentContext();
}
Expand Down Expand Up @@ -1544,7 +1551,7 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
// If the records occur in different context (namespace), these should be
// different. This is specially important if the definition of one or both
// records is missing.
if (!IsRecordContextStructurallyEquivalent(D1, D2))
if (!IsRecordContextStructurallyEquivalent(Context, D1, D2))
return false;

// If both declarations are class template specializations, we know
Expand Down
23 changes: 23 additions & 0 deletions clang/unittests/AST/StructuralEquivalenceTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1024,6 +1024,29 @@ TEST_F(StructuralEquivalenceRecordContextTest, TransparentContextInNamespace) {
EXPECT_TRUE(testStructuralMatch(Decls));
}

TEST_F(StructuralEquivalenceRecordContextTest,
ClassTemplateSpecializationContext) {
std::string Code =
R"(
template <typename T> struct O {
struct M {};
};
)";
auto t = makeDecls<VarDecl>(Code + R"(
typedef O<int>::M MT1;
MT1 A;
)",
Code + R"(
namespace {
struct I {};
} // namespace
typedef O<I>::M MT2;
MT2 A;
)",
Lang_CXX11, varDecl(hasName("A")));
EXPECT_FALSE(testStructuralMatch(t));
}

TEST_F(StructuralEquivalenceTest, NamespaceOfRecordMember) {
auto Decls = makeNamedDecls(
R"(
Expand Down

0 comments on commit 8612730

Please sign in to comment.