jcsxky created this revision.
jcsxky added reviewers: a.sidorin, shafik, balazske, steakhal, aaron.ballman, 
Michael137.
jcsxky added projects: clang, clang-c.
Herald added a project: All.
jcsxky requested review of this revision.
Herald added a subscriber: cfe-commits.

Don't increase template parameter's depth when it's a friend declaration in 
template class. The reason is that this member(template class) should match the 
previous class definition and when import from external ast file, type of them 
should be equivalence.
See import issue <https://reviews.llvm.org/D156693>


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D157170

Files:
  clang/lib/Parse/ParseTemplate.cpp
  clang/unittests/AST/ASTImporterTest.cpp


Index: clang/unittests/AST/ASTImporterTest.cpp
===================================================================
--- clang/unittests/AST/ASTImporterTest.cpp
+++ clang/unittests/AST/ASTImporterTest.cpp
@@ -4212,6 +4212,56 @@
   EXPECT_TRUE(Imported->getPreviousDecl());
 }
 
+TEST_P(ImportFriendClasses, SkipFriendTemplateDeclaration) {
+  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(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(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(
Index: clang/lib/Parse/ParseTemplate.cpp
===================================================================
--- clang/lib/Parse/ParseTemplate.cpp
+++ clang/lib/Parse/ParseTemplate.cpp
@@ -127,8 +127,30 @@
     // Parse the '<' template-parameter-list '>'
     SourceLocation LAngleLoc, RAngleLoc;
     SmallVector<NamedDecl*, 4> TemplateParams;
+
+    bool SeeFriendKeyWord = false;
+    {
+      SmallVector<NamedDecl *, 4> TemplateParams;
+      SourceLocation LAngleLoc, RAngleLoc;
+      RevertingTentativeParsingAction TPA(*this);
+      MultiParseScope TemplateParamScopesTmp(*this);
+      if (ParseTemplateParameters(TemplateParamScopesTmp,
+                                  CurTemplateDepthTracker.getDepth(),
+                                  TemplateParams, LAngleLoc, RAngleLoc)) {
+        // returns true don't need process
+        // returns false, blowe 'ParseTemplateParameters' will do it after
+        // revert
+      }
+      // skip outmost declaration
+      if (Tok.is(tok::kw_friend) && CurTemplateDepthTracker.getDepth() > 0) {
+        SeeFriendKeyWord = true;
+      }
+    }
+
     if (ParseTemplateParameters(TemplateParamScopes,
-                                CurTemplateDepthTracker.getDepth(),
+                                SeeFriendKeyWord
+                                    ? CurTemplateDepthTracker.getDepth() - 1
+                                    : CurTemplateDepthTracker.getDepth(),
                                 TemplateParams, LAngleLoc, RAngleLoc)) {
       // Skip until the semi-colon or a '}'.
       SkipUntil(tok::r_brace, StopAtSemi | StopBeforeMatch);


Index: clang/unittests/AST/ASTImporterTest.cpp
===================================================================
--- clang/unittests/AST/ASTImporterTest.cpp
+++ clang/unittests/AST/ASTImporterTest.cpp
@@ -4212,6 +4212,56 @@
   EXPECT_TRUE(Imported->getPreviousDecl());
 }
 
+TEST_P(ImportFriendClasses, SkipFriendTemplateDeclaration) {
+  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(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(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(
Index: clang/lib/Parse/ParseTemplate.cpp
===================================================================
--- clang/lib/Parse/ParseTemplate.cpp
+++ clang/lib/Parse/ParseTemplate.cpp
@@ -127,8 +127,30 @@
     // Parse the '<' template-parameter-list '>'
     SourceLocation LAngleLoc, RAngleLoc;
     SmallVector<NamedDecl*, 4> TemplateParams;
+
+    bool SeeFriendKeyWord = false;
+    {
+      SmallVector<NamedDecl *, 4> TemplateParams;
+      SourceLocation LAngleLoc, RAngleLoc;
+      RevertingTentativeParsingAction TPA(*this);
+      MultiParseScope TemplateParamScopesTmp(*this);
+      if (ParseTemplateParameters(TemplateParamScopesTmp,
+                                  CurTemplateDepthTracker.getDepth(),
+                                  TemplateParams, LAngleLoc, RAngleLoc)) {
+        // returns true don't need process
+        // returns false, blowe 'ParseTemplateParameters' will do it after
+        // revert
+      }
+      // skip outmost declaration
+      if (Tok.is(tok::kw_friend) && CurTemplateDepthTracker.getDepth() > 0) {
+        SeeFriendKeyWord = true;
+      }
+    }
+
     if (ParseTemplateParameters(TemplateParamScopes,
-                                CurTemplateDepthTracker.getDepth(),
+                                SeeFriendKeyWord
+                                    ? CurTemplateDepthTracker.getDepth() - 1
+                                    : CurTemplateDepthTracker.getDepth(),
                                 TemplateParams, LAngleLoc, RAngleLoc)) {
       // Skip until the semi-colon or a '}'.
       SkipUntil(tok::r_brace, StopAtSemi | StopBeforeMatch);
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to