[clang] 07ab514 - [clang][ASTImporter]Skip check depth of friend template parameter

via cfe-commits cfe-commits at lists.llvm.org
Mon Aug 21 22:16:40 PDT 2023


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) {


        


More information about the cfe-commits mailing list