Author: huqizhi Date: 2023-08-22T13:16:11+08:00 New Revision: 07ab5140080eecdf9f0f6215f70377accb8696f1
URL: https://github.com/llvm/llvm-project/commit/07ab5140080eecdf9f0f6215f70377accb8696f1 DIFF: https://github.com/llvm/llvm-project/commit/07ab5140080eecdf9f0f6215f70377accb8696f1.diff LOG: [clang][ASTImporter]Skip check depth of friend template parameter Depth of the parameter of friend template class declaration in a template class is 1, while in the specialization the depth is 0. This will cause failure on 'IsStructurallyEquivalent' as a name conflict in 'VisitClassTemplateDecl'(see testcase of 'SkipComparingFriendTemplateDepth'). The patch fix it by ignore the depth only in this special case. Reviewed By: balazske Differential Revision: https://reviews.llvm.org/D156693 Added: Modified: clang/include/clang/AST/ASTStructuralEquivalence.h clang/lib/AST/ASTImporter.cpp clang/lib/AST/ASTStructuralEquivalence.cpp clang/unittests/AST/ASTImporterTest.cpp clang/unittests/AST/StructuralEquivalenceTest.cpp Removed: ################################################################################ diff --git a/clang/include/clang/AST/ASTStructuralEquivalence.h b/clang/include/clang/AST/ASTStructuralEquivalence.h index 4a79e64fe5d517..029439c8e9a3ac 100644 --- a/clang/include/clang/AST/ASTStructuralEquivalence.h +++ b/clang/include/clang/AST/ASTStructuralEquivalence.h @@ -69,15 +69,19 @@ struct StructuralEquivalenceContext { /// \c true if the last diagnostic came from ToCtx. bool LastDiagFromC2 = false; + /// Whether to ignore comparing the depth of template param(TemplateTypeParm) + bool IgnoreTemplateParmDepth; + StructuralEquivalenceContext( ASTContext &FromCtx, ASTContext &ToCtx, llvm::DenseSet<std::pair<Decl *, Decl *>> &NonEquivalentDecls, - StructuralEquivalenceKind EqKind, - bool StrictTypeSpelling = false, bool Complain = true, - bool ErrorOnTagTypeMismatch = false) + StructuralEquivalenceKind EqKind, bool StrictTypeSpelling = false, + bool Complain = true, bool ErrorOnTagTypeMismatch = false, + bool IgnoreTemplateParmDepth = false) : FromCtx(FromCtx), ToCtx(ToCtx), NonEquivalentDecls(NonEquivalentDecls), EqKind(EqKind), StrictTypeSpelling(StrictTypeSpelling), - ErrorOnTagTypeMismatch(ErrorOnTagTypeMismatch), Complain(Complain) {} + ErrorOnTagTypeMismatch(ErrorOnTagTypeMismatch), Complain(Complain), + IgnoreTemplateParmDepth(IgnoreTemplateParmDepth) {} DiagnosticBuilder Diag1(SourceLocation Loc, unsigned DiagID); DiagnosticBuilder Diag2(SourceLocation Loc, unsigned DiagID); diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp index 736aac8a646b7a..5ef8b6a5c50ee9 100644 --- a/clang/lib/AST/ASTImporter.cpp +++ b/clang/lib/AST/ASTImporter.cpp @@ -508,7 +508,8 @@ namespace clang { template <typename T> bool hasSameVisibilityContextAndLinkage(T *Found, T *From); - bool IsStructuralMatch(Decl *From, Decl *To, bool Complain = true); + bool IsStructuralMatch(Decl *From, Decl *To, bool Complain = true, + bool IgnoreTemplateParmDepth = false); ExpectedDecl VisitDecl(Decl *D); ExpectedDecl VisitImportDecl(ImportDecl *D); ExpectedDecl VisitEmptyDecl(EmptyDecl *D); @@ -2269,7 +2270,8 @@ getStructuralEquivalenceKind(const ASTImporter &Importer) { : StructuralEquivalenceKind::Default; } -bool ASTNodeImporter::IsStructuralMatch(Decl *From, Decl *To, bool Complain) { +bool ASTNodeImporter::IsStructuralMatch(Decl *From, Decl *To, bool Complain, + bool IgnoreTemplateParmDepth) { // Eliminate a potential failure point where we attempt to re-import // something we're trying to import while completing ToRecord. Decl *ToOrigin = Importer.GetOriginalDecl(To); @@ -2280,7 +2282,8 @@ bool ASTNodeImporter::IsStructuralMatch(Decl *From, Decl *To, bool Complain) { StructuralEquivalenceContext Ctx( Importer.getFromContext(), Importer.getToContext(), Importer.getNonEquivalentDecls(), getStructuralEquivalenceKind(Importer), - false, Complain); + /*StrictTypeSpelling=*/false, Complain, /*ErrorOnTagTypeMismatch=*/false, + IgnoreTemplateParmDepth); return Ctx.IsEquivalent(From, To); } @@ -5848,7 +5851,12 @@ ExpectedDecl ASTNodeImporter::VisitClassTemplateDecl(ClassTemplateDecl *D) { if (!hasSameVisibilityContextAndLinkage(FoundTemplate, D)) continue; - if (IsStructuralMatch(D, FoundTemplate)) { + // FIXME: sufficient conditon for 'IgnoreTemplateParmDepth'? + bool IgnoreTemplateParmDepth = + FoundTemplate->getFriendObjectKind() != Decl::FOK_None && + !D->specializations().empty(); + if (IsStructuralMatch(D, FoundTemplate, /*Complain=*/true, + IgnoreTemplateParmDepth)) { ClassTemplateDecl *TemplateWithDef = getTemplateDefinition(FoundTemplate); if (D->isThisDeclarationADefinition() && TemplateWithDef) diff --git a/clang/lib/AST/ASTStructuralEquivalence.cpp b/clang/lib/AST/ASTStructuralEquivalence.cpp index f867b6bf84beb7..b211e349a41299 100644 --- a/clang/lib/AST/ASTStructuralEquivalence.cpp +++ b/clang/lib/AST/ASTStructuralEquivalence.cpp @@ -1092,7 +1092,8 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, case Type::TemplateTypeParm: { const auto *Parm1 = cast<TemplateTypeParmType>(T1); const auto *Parm2 = cast<TemplateTypeParmType>(T2); - if (Parm1->getDepth() != Parm2->getDepth()) + if (!Context.IgnoreTemplateParmDepth && + Parm1->getDepth() != Parm2->getDepth()) return false; if (Parm1->getIndex() != Parm2->getIndex()) return false; diff --git a/clang/unittests/AST/ASTImporterTest.cpp b/clang/unittests/AST/ASTImporterTest.cpp index 057701dea2c51d..ed3703d116a626 100644 --- a/clang/unittests/AST/ASTImporterTest.cpp +++ b/clang/unittests/AST/ASTImporterTest.cpp @@ -4246,6 +4246,58 @@ TEST_P(ImportFriendClasses, DeclsFromFriendsShouldBeInRedeclChains) { EXPECT_TRUE(Imported->getPreviousDecl()); } +TEST_P(ImportFriendClasses, SkipComparingFriendTemplateDepth) { + Decl *ToTU = getToTuDecl( + R"( + template <class T, T U> + class A; + + template <class T, T U> + class A { + public: + template <class P, P Q> + friend class A; + + A(T x) :x(x) {} + + private: + T x; + }; + )", + Lang_CXX11); + + auto *Fwd = FirstDeclMatcher<ClassTemplateDecl>().match( + ToTU, + classTemplateDecl(has(cxxRecordDecl(hasDefinition(), hasName("A"))))); + Decl *FromTU = getTuDecl( + R"( + template <class T, T U> + class A; + + template <class T, T U> + class A { + public: + template <class P, P Q> + friend class A; + + A(T x) : x(x) {} + + private: + T x; + }; + + A<int,3> a1(0); + )", + Lang_CXX11, "input1.cc"); + auto *FromA = FirstDeclMatcher<ClassTemplateDecl>().match( + FromTU, + classTemplateDecl(has(cxxRecordDecl(hasDefinition(), hasName("A"))))); + auto *ToA = Import(FromA, Lang_CXX11); + EXPECT_TRUE(ToA); + EXPECT_EQ(Fwd->getTemplatedDecl()->getTypeForDecl(), + ToA->getTemplatedDecl()->getTypeForDecl()); +} + TEST_P(ImportFriendClasses, ImportOfClassTemplateDefinitionShouldConnectToFwdFriend) { Decl *ToTU = getToTuDecl( diff --git a/clang/unittests/AST/StructuralEquivalenceTest.cpp b/clang/unittests/AST/StructuralEquivalenceTest.cpp index 092d9cc319a2e5..1001ce49b06739 100644 --- a/clang/unittests/AST/StructuralEquivalenceTest.cpp +++ b/clang/unittests/AST/StructuralEquivalenceTest.cpp @@ -1,5 +1,6 @@ #include "clang/AST/ASTContext.h" #include "clang/AST/ASTStructuralEquivalence.h" +#include "clang/AST/DeclTemplate.h" #include "clang/ASTMatchers/ASTMatchers.h" #include "clang/Frontend/ASTUnit.h" #include "clang/Testing/CommandLineArgs.h" @@ -130,15 +131,20 @@ struct StructuralEquivalenceTest : ::testing::Test { return makeStmts(Wrap(SrcCode0), Wrap(SrcCode1), Lang, AMatcher); } - bool testStructuralMatch(Decl *D0, Decl *D1) { + bool testStructuralMatch(Decl *D0, Decl *D1, + bool IgnoreTemplateParmDepth = false) { llvm::DenseSet<std::pair<Decl *, Decl *>> NonEquivalentDecls01; llvm::DenseSet<std::pair<Decl *, Decl *>> NonEquivalentDecls10; StructuralEquivalenceContext Ctx01( - D0->getASTContext(), D1->getASTContext(), - NonEquivalentDecls01, StructuralEquivalenceKind::Default, false, false); + D0->getASTContext(), D1->getASTContext(), NonEquivalentDecls01, + StructuralEquivalenceKind::Default, /*StrictTypeSpelling=*/false, + /*Complain=*/false, /*ErrorOnTagTypeMismatch=*/false, + IgnoreTemplateParmDepth); StructuralEquivalenceContext Ctx10( - D1->getASTContext(), D0->getASTContext(), - NonEquivalentDecls10, StructuralEquivalenceKind::Default, false, false); + D1->getASTContext(), D0->getASTContext(), NonEquivalentDecls10, + StructuralEquivalenceKind::Default, /*StrictTypeSpelling=*/false, + /*Complain=*/false, /*ErrorOnTagTypeMismatch=*/false, + IgnoreTemplateParmDepth); bool Eq01 = Ctx01.IsEquivalent(D0, D1); bool Eq10 = Ctx10.IsEquivalent(D1, D0); EXPECT_EQ(Eq01, Eq10); @@ -165,8 +171,9 @@ struct StructuralEquivalenceTest : ::testing::Test { return testStructuralMatch(get<0>(t), get<1>(t)); } - bool testStructuralMatch(std::tuple<Decl *, Decl *> t) { - return testStructuralMatch(get<0>(t), get<1>(t)); + bool testStructuralMatch(std::tuple<Decl *, Decl *> t, + bool IgnoreTemplateParmDepth = false) { + return testStructuralMatch(get<0>(t), get<1>(t), IgnoreTemplateParmDepth); } }; @@ -1689,6 +1696,40 @@ TEST_F( EXPECT_FALSE(testStructuralMatch(t)); } +TEST_F(StructuralEquivalenceTemplateTest, + IgnoreTemplateParmDepthAtTemplateTypeParmDecl) { + auto Decls = makeDecls<ClassTemplateDecl>( + R"( + template<class> struct A; + )", + R"( + template<class> struct S { + template<class> friend struct A; + }; + )", + Lang_CXX03, classTemplateDecl(hasName("A")), + classTemplateDecl(hasName("A"))); + EXPECT_TRUE(testStructuralMatch(Decls)); + EXPECT_TRUE(testStructuralMatch(Decls, true)); +} + +TEST_F(StructuralEquivalenceTemplateTest, + IgnoreTemplateParmDepthAtNonTypeTemplateParmDecl) { + auto Decls = makeDecls<ClassTemplateDecl>( + R"( + template<class T, T U> struct A; + )", + R"( + template<class T> struct S { + template<class P, P Q> friend struct A; + }; + )", + Lang_CXX03, classTemplateDecl(hasName("A")), + classTemplateDecl(hasName("A"))); + EXPECT_FALSE(testStructuralMatch(Decls)); + EXPECT_TRUE(testStructuralMatch(Decls, /*IgnoreTemplateParmDepth=*/true)); +} + TEST_F( StructuralEquivalenceTemplateTest, ClassTemplSpecWithInequivalentShadowedTemplArg) { _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits