danix800 created this revision.
Herald added subscribers: martong, kristof.beyls.
Herald added a reviewer: a.sidorin.
Herald added a reviewer: shafik.
Herald added a project: All.
danix800 requested review of this revision.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.

For friend class template within dependent context:

1. Should not do structure matching checking
2. Should not be added into redecls chain

See `Sema::CheckClassTemplate`.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D155661

Files:
  clang/lib/AST/ASTImporter.cpp
  clang/unittests/AST/ASTImporterTest.cpp

Index: clang/unittests/AST/ASTImporterTest.cpp
===================================================================
--- clang/unittests/AST/ASTImporterTest.cpp
+++ clang/unittests/AST/ASTImporterTest.cpp
@@ -3969,7 +3969,32 @@
 }
 
 
-struct ImportFriendClasses : ASTImporterOptionSpecificTestBase {};
+struct ImportFriendClasses : ASTImporterOptionSpecificTestBase {
+  void testRecursiveFriendClassTemplate(Decl *FromTu) {
+    auto *FromD =
+        FirstDeclMatcher<ClassTemplateDecl>().match(FromTu,
+            classTemplateDecl());
+    auto *ToD = Import(FromD, Lang_CXX03);
+
+    auto Pattern = classTemplateDecl(
+        has(cxxRecordDecl(has(friendDecl(has(classTemplateDecl()))))));
+    ASSERT_TRUE(MatchVerifier<Decl>{}.match(FromD, Pattern));
+    EXPECT_TRUE(MatchVerifier<Decl>{}.match(ToD, Pattern));
+
+    auto *FromFriend =
+        FirstDeclMatcher<FriendDecl>().match(FromD, friendDecl());
+    auto *FromClass =
+        FirstDeclMatcher<ClassTemplateDecl>().match(FromD, classTemplateDecl());
+    EXPECT_NE(FromFriend->getFriendDecl(), FromClass);
+    EXPECT_TRUE(FromFriend->getFriendDecl()->getPreviousDecl() == nullptr);
+
+    auto *Class =
+        FirstDeclMatcher<ClassTemplateDecl>().match(ToD, classTemplateDecl());
+    auto *Friend = FirstDeclMatcher<FriendDecl>().match(ToD, friendDecl());
+    EXPECT_NE(Friend->getFriendDecl(), Class);
+    EXPECT_TRUE(Friend->getFriendDecl()->getPreviousDecl() == nullptr);
+  }
+};
 
 TEST_P(ImportFriendClasses, ImportOfFriendRecordDoesNotMergeDefinition) {
   Decl *FromTU = getTuDecl(
@@ -4074,20 +4099,19 @@
       )",
       Lang_CXX03, "input.cc");
 
-  auto *FromD =
-      FirstDeclMatcher<ClassTemplateDecl>().match(FromTu, classTemplateDecl());
-  auto *ToD = Import(FromD, Lang_CXX03);
-
-  auto Pattern = classTemplateDecl(
-      has(cxxRecordDecl(has(friendDecl(has(classTemplateDecl()))))));
-  ASSERT_TRUE(MatchVerifier<Decl>{}.match(FromD, Pattern));
-  EXPECT_TRUE(MatchVerifier<Decl>{}.match(ToD, Pattern));
+  testRecursiveFriendClassTemplate(FromTu);
+}
 
-  auto *Class =
-      FirstDeclMatcher<ClassTemplateDecl>().match(ToD, classTemplateDecl());
-  auto *Friend = FirstDeclMatcher<FriendDecl>().match(ToD, friendDecl());
-  EXPECT_NE(Friend->getFriendDecl(), Class);
-  EXPECT_EQ(Friend->getFriendDecl()->getPreviousDecl(), Class);
+TEST_P(ImportFriendClasses,
+       ImportOfRecursiveFriendClassTemplateWithNonTypeParm) {
+  Decl *FromTu = getTuDecl(
+      R"(
+      template<class A1, A1> class declToImport {
+        template<class B1, B1> friend class declToImport;
+      };
+      )",
+      Lang_CXX03, "input.cc");
+  testRecursiveFriendClassTemplate(FromTu);
 }
 
 TEST_P(ImportFriendClasses, ProperPrevDeclForClassTemplateDecls) {
Index: clang/lib/AST/ASTImporter.cpp
===================================================================
--- clang/lib/AST/ASTImporter.cpp
+++ clang/lib/AST/ASTImporter.cpp
@@ -2857,6 +2857,10 @@
   } else if (Importer.getToContext().getLangOpts().CPlusPlus)
     IDNS |= Decl::IDNS_Ordinary | Decl::IDNS_TagFriend;
 
+  bool IsDependentContext = DC != LexicalDC ?
+      LexicalDC->isDependentContext() : DC->isDependentContext();
+  bool ShouldAddRedecl = !(IsFriendTemplate && IsDependentContext);
+
   // We may already have a record of the same name; try to find and match it.
   RecordDecl *PrevDecl = nullptr;
   if (!DC->isFunctionOrMethod() && !D->isLambda()) {
@@ -2897,7 +2901,7 @@
         if (!hasSameVisibilityContextAndLinkage(FoundRecord, D))
           continue;
 
-        if (IsStructuralMatch(D, FoundRecord)) {
+        if (!ShouldAddRedecl || IsStructuralMatch(D, FoundRecord)) {
           RecordDecl *FoundDef = FoundRecord->getDefinition();
           if (D->isThisDeclarationADefinition() && FoundDef) {
             // FIXME: Structural equivalence check should check for same
@@ -2955,7 +2959,7 @@
         return CDeclOrErr.takeError();
       Numbering.ContextDecl = *CDeclOrErr;
       D2CXX->setLambdaNumbering(Numbering);
-   } else if (DCXX->isInjectedClassName()) {
+    } else if (DCXX->isInjectedClassName()) {
       // We have to be careful to do a similar dance to the one in
       // Sema::ActOnStartCXXMemberDeclarations
       const bool DelayTypeCreation = true;
@@ -2970,7 +2974,9 @@
       if (GetImportedOrCreateDecl(D2CXX, D, Importer.getToContext(),
                                   D->getTagKind(), DC, *BeginLocOrErr, Loc,
                                   Name.getAsIdentifierInfo(),
-                                  cast_or_null<CXXRecordDecl>(PrevDecl)))
+                                  ShouldAddRedecl ?
+                                      cast_or_null<CXXRecordDecl>(PrevDecl) :
+                                      nullptr))
         return D2CXX;
     }
 
@@ -5785,6 +5791,11 @@
   if (ToD)
     return ToD;
 
+  bool IsFriendTemplate = D->getFriendObjectKind() != Decl::FOK_None;
+  bool IsDependentContext = DC != LexicalDC ?
+      LexicalDC->isDependentContext() : DC->isDependentContext();
+  bool ShouldAddRedecl = !(IsFriendTemplate && IsDependentContext);
+
   ClassTemplateDecl *FoundByLookup = nullptr;
 
   // We may already have a template of the same name; try to find and match it.
@@ -5802,7 +5813,7 @@
         if (!hasSameVisibilityContextAndLinkage(FoundTemplate, D))
           continue;
 
-        if (IsStructuralMatch(D, FoundTemplate)) {
+        if (!ShouldAddRedecl || IsStructuralMatch(D, FoundTemplate)) {
           ClassTemplateDecl *TemplateWithDef =
               getTemplateDefinition(FoundTemplate);
           if (D->isThisDeclarationADefinition() && TemplateWithDef)
@@ -5853,7 +5864,7 @@
   addDeclToContexts(D, D2);
   updateLookupTableForTemplateParameters(**TemplateParamsOrErr);
 
-  if (FoundByLookup) {
+  if (ShouldAddRedecl && FoundByLookup) {
     auto *Recent =
         const_cast<ClassTemplateDecl *>(FoundByLookup->getMostRecentDecl());
 
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to