Author: Qizhi Hu Date: 2024-01-05T20:53:04+08:00 New Revision: 86127305d4602801ba7ffdc74377ed67b18819ac
URL: https://github.com/llvm/llvm-project/commit/86127305d4602801ba7ffdc74377ed67b18819ac DIFF: https://github.com/llvm/llvm-project/commit/86127305d4602801ba7ffdc74377ed67b18819ac.diff LOG: [clang][ASTImporter][StructuralEquivalence] improve StructuralEquivalence 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](https://github.com/llvm/llvm-project/issues/65913) Co-authored-by: huqizhi <836744...@qq.com> Added: Modified: clang/lib/AST/ASTStructuralEquivalence.cpp clang/unittests/AST/StructuralEquivalenceTest.cpp Removed: ################################################################################ diff --git a/clang/lib/AST/ASTStructuralEquivalence.cpp b/clang/lib/AST/ASTStructuralEquivalence.cpp index 1f492b051e0341..a9e0d1698a9178 100644 --- a/clang/lib/AST/ASTStructuralEquivalence.cpp +++ b/clang/lib/AST/ASTStructuralEquivalence.cpp @@ -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 @@ -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(); } @@ -1544,7 +1551,7 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, // If the records occur in diff erent context (namespace), these should be // diff erent. 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 diff --git a/clang/unittests/AST/StructuralEquivalenceTest.cpp b/clang/unittests/AST/StructuralEquivalenceTest.cpp index 44d950cfe758f1..22c7b82460f0a0 100644 --- a/clang/unittests/AST/StructuralEquivalenceTest.cpp +++ b/clang/unittests/AST/StructuralEquivalenceTest.cpp @@ -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"( _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits