Redecl chain of friend class template is broken ?

classic Classic list List threaded Threaded
3 messages Options
Reply | Threaded
Open this post in threaded view
|

Redecl chain of friend class template is broken ?

Nathan Ridge via cfe-dev
Hi,

During the improvement of clang::ASTImporter we discovered something strange with redecl chains. 

Consider the following code:
   1         template <class T1, class T2>
   2         struct Base {
   3           template <class U1, class U2>
   4           friend struct Class;
   5         };
   6         template <class T1, class T2>
   7         struct Class { }; 
Here we'd expect that the prototype of `Class` at line 4 is linked to the same redecl chain as the definition at line 7 (see the test case below to be more precise, the test passes on llvm/master).
I wonder if this is an error in clang::Sema? If this is not an error then what is the explanation?

Thanks,
Gabor


TEST_P(ASTImporterOptionSpecificTestBase,
       ImportExistingFriendClassTemplateDef) {
  auto Code =
      R"(
        template <class T1, class T2>
        struct Base {
          template <class U1, class U2>
          friend struct Class;
        };
        template <class T1, class T2>
        struct Class { };
        )";

  TranslationUnitDecl *ToTU = getToTuDecl(Code, Lang_CXX);
  TranslationUnitDecl *FromTU = getTuDecl(Code, Lang_CXX, "input.cc");

  auto *ToClassProto = FirstDeclMatcher<ClassTemplateDecl>().match(
      ToTU, classTemplateDecl(hasName("Class")));
  auto *ToClassDef = LastDeclMatcher<ClassTemplateDecl>().match(
      ToTU, classTemplateDecl(hasName("Class")));
  ASSERT_FALSE(ToClassProto->isThisDeclarationADefinition());
  ASSERT_TRUE(ToClassDef->isThisDeclarationADefinition());
  // Previous friend decl is not linked to it!
  ASSERT_FALSE(ToClassDef->getPreviousDecl());
  ASSERT_EQ(ToClassDef->getMostRecentDecl(), ToClassDef);
  ASSERT_EQ(ToClassProto->getMostRecentDecl(), ToClassProto);
}

_______________________________________________
cfe-dev mailing list
[hidden email]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev
Reply | Threaded
Open this post in threaded view
|

Re: Redecl chain of friend class template is broken ?

Nathan Ridge via cfe-dev
On Tue, 23 Jul 2019, 05:37 Gábor Márton via cfe-dev, <[hidden email]> wrote:
Hi,

During the improvement of clang::ASTImporter we discovered something strange with redecl chains. 

Consider the following code:
   1         template <class T1, class T2>
   2         struct Base {
   3           template <class U1, class U2>
   4           friend struct Class;
   5         };
   6         template <class T1, class T2>
   7         struct Class { }; 
Here we'd expect that the prototype of `Class` at line 4 is linked to the same redecl chain as the definition at line 7 (see the test case below to be more precise, the test passes on llvm/master).
I wonder if this is an error in clang::Sema? If this is not an error then what is the explanation?

It's intentional. The friend in the template does not constitute a declaration of ::Class until the template Base is instantiated. For example, the template parameters of the friend are at different depths than those of the class.

Thanks,
Gabor


TEST_P(ASTImporterOptionSpecificTestBase,
       ImportExistingFriendClassTemplateDef) {
  auto Code =
      R"(
        template <class T1, class T2>
        struct Base {
          template <class U1, class U2>
          friend struct Class;
        };
        template <class T1, class T2>
        struct Class { };
        )";

  TranslationUnitDecl *ToTU = getToTuDecl(Code, Lang_CXX);
  TranslationUnitDecl *FromTU = getTuDecl(Code, Lang_CXX, "input.cc");

  auto *ToClassProto = FirstDeclMatcher<ClassTemplateDecl>().match(
      ToTU, classTemplateDecl(hasName("Class")));
  auto *ToClassDef = LastDeclMatcher<ClassTemplateDecl>().match(
      ToTU, classTemplateDecl(hasName("Class")));
  ASSERT_FALSE(ToClassProto->isThisDeclarationADefinition());
  ASSERT_TRUE(ToClassDef->isThisDeclarationADefinition());
  // Previous friend decl is not linked to it!
  ASSERT_FALSE(ToClassDef->getPreviousDecl());
  ASSERT_EQ(ToClassDef->getMostRecentDecl(), ToClassDef);
  ASSERT_EQ(ToClassProto->getMostRecentDecl(), ToClassProto);
}
_______________________________________________
cfe-dev mailing list
[hidden email]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev

_______________________________________________
cfe-dev mailing list
[hidden email]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev
Reply | Threaded
Open this post in threaded view
|

Re: Redecl chain of friend class template is broken ?

Nathan Ridge via cfe-dev
Ok, thanks for the clarification. 

On Tue, Jul 23, 2019 at 5:17 PM Richard Smith <[hidden email]> wrote:
On Tue, 23 Jul 2019, 05:37 Gábor Márton via cfe-dev, <[hidden email]> wrote:
Hi,

During the improvement of clang::ASTImporter we discovered something strange with redecl chains. 

Consider the following code:
   1         template <class T1, class T2>
   2         struct Base {
   3           template <class U1, class U2>
   4           friend struct Class;
   5         };
   6         template <class T1, class T2>
   7         struct Class { }; 
Here we'd expect that the prototype of `Class` at line 4 is linked to the same redecl chain as the definition at line 7 (see the test case below to be more precise, the test passes on llvm/master).
I wonder if this is an error in clang::Sema? If this is not an error then what is the explanation?

It's intentional. The friend in the template does not constitute a declaration of ::Class until the template Base is instantiated. For example, the template parameters of the friend are at different depths than those of the class.

Thanks,
Gabor


TEST_P(ASTImporterOptionSpecificTestBase,
       ImportExistingFriendClassTemplateDef) {
  auto Code =
      R"(
        template <class T1, class T2>
        struct Base {
          template <class U1, class U2>
          friend struct Class;
        };
        template <class T1, class T2>
        struct Class { };
        )";

  TranslationUnitDecl *ToTU = getToTuDecl(Code, Lang_CXX);
  TranslationUnitDecl *FromTU = getTuDecl(Code, Lang_CXX, "input.cc");

  auto *ToClassProto = FirstDeclMatcher<ClassTemplateDecl>().match(
      ToTU, classTemplateDecl(hasName("Class")));
  auto *ToClassDef = LastDeclMatcher<ClassTemplateDecl>().match(
      ToTU, classTemplateDecl(hasName("Class")));
  ASSERT_FALSE(ToClassProto->isThisDeclarationADefinition());
  ASSERT_TRUE(ToClassDef->isThisDeclarationADefinition());
  // Previous friend decl is not linked to it!
  ASSERT_FALSE(ToClassDef->getPreviousDecl());
  ASSERT_EQ(ToClassDef->getMostRecentDecl(), ToClassDef);
  ASSERT_EQ(ToClassProto->getMostRecentDecl(), ToClassProto);
}
_______________________________________________
cfe-dev mailing list
[hidden email]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev

_______________________________________________
cfe-dev mailing list
[hidden email]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev