r339560 - [ASTImporter] Improved import of friend templates.
Balazs Keri via cfe-commits
cfe-commits at lists.llvm.org
Mon Aug 13 06:08:37 PDT 2018
Author: balazske
Date: Mon Aug 13 06:08:37 2018
New Revision: 339560
URL: http://llvm.org/viewvc/llvm-project?rev=339560&view=rev
Log:
[ASTImporter] Improved import of friend templates.
Summary:
When importing a friend class template declaration,
this declaration should not be merged with any other existing declaration
for the same type. Otherwise the getFriendDecl of the FriendDecl can point
to an other already referenced declaration, this case causes problems.
Additionally the previous decl of class templates is set at import.
Reviewers: a.sidorin, a_sidorin
Reviewed By: a_sidorin
Subscribers: a_sidorin, martong, cfe-commits
Differential Revision: https://reviews.llvm.org/D50516
Modified:
cfe/trunk/lib/AST/ASTImporter.cpp
cfe/trunk/unittests/AST/ASTImporterTest.cpp
Modified: cfe/trunk/lib/AST/ASTImporter.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ASTImporter.cpp?rev=339560&r1=339559&r2=339560&view=diff
==============================================================================
--- cfe/trunk/lib/AST/ASTImporter.cpp (original)
+++ cfe/trunk/lib/AST/ASTImporter.cpp Mon Aug 13 06:08:37 2018
@@ -2164,11 +2164,21 @@ Decl *ASTNodeImporter::VisitEnumDecl(Enu
}
Decl *ASTNodeImporter::VisitRecordDecl(RecordDecl *D) {
+ bool IsFriendTemplate = false;
+ if (auto *DCXX = dyn_cast<CXXRecordDecl>(D)) {
+ IsFriendTemplate =
+ DCXX->getDescribedClassTemplate() &&
+ DCXX->getDescribedClassTemplate()->getFriendObjectKind() !=
+ Decl::FOK_None;
+ }
+
// If this record has a definition in the translation unit we're coming from,
// but this particular declaration is not that definition, import the
// definition and map to that.
TagDecl *Definition = D->getDefinition();
if (Definition && Definition != D &&
+ // Friend template declaration must be imported on its own.
+ !IsFriendTemplate &&
// In contrast to a normal CXXRecordDecl, the implicit
// CXXRecordDecl of ClassTemplateSpecializationDecl is its redeclaration.
// The definition of the implicit CXXRecordDecl in this case is the
@@ -2241,7 +2251,7 @@ Decl *ASTNodeImporter::VisitRecordDecl(R
PrevDecl = FoundRecord;
if (RecordDecl *FoundDef = FoundRecord->getDefinition()) {
- if ((SearchName && !D->isCompleteDefinition())
+ if ((SearchName && !D->isCompleteDefinition() && !IsFriendTemplate)
|| (D->isCompleteDefinition() &&
D->isAnonymousStructOrUnion()
== FoundDef->isAnonymousStructOrUnion() &&
@@ -2281,6 +2291,9 @@ Decl *ASTNodeImporter::VisitRecordDecl(R
!IsStructuralMatch(D, FoundRecord))
continue;
+ if (IsFriendTemplate)
+ continue;
+
AdoptDecl = FoundRecord;
continue;
} else if (!SearchName) {
@@ -2348,7 +2361,7 @@ Decl *ASTNodeImporter::VisitRecordDecl(R
if (!ToDescribed)
return nullptr;
D2CXX->setDescribedClassTemplate(ToDescribed);
- if (!DCXX->isInjectedClassName()) {
+ if (!DCXX->isInjectedClassName() && !IsFriendTemplate) {
// In a record describing a template the type should be an
// InjectedClassNameType (see Sema::CheckClassTemplate). Update the
// previously set type to the correct value here (ToDescribed is not
@@ -4371,12 +4384,14 @@ static ClassTemplateDecl *getDefinition(
}
Decl *ASTNodeImporter::VisitClassTemplateDecl(ClassTemplateDecl *D) {
+ bool IsFriend = D->getFriendObjectKind() != Decl::FOK_None;
+
// If this record has a definition in the translation unit we're coming from,
// but this particular declaration is not that definition, import the
// definition and map to that.
auto *Definition =
cast_or_null<CXXRecordDecl>(D->getTemplatedDecl()->getDefinition());
- if (Definition && Definition != D->getTemplatedDecl()) {
+ if (Definition && Definition != D->getTemplatedDecl() && !IsFriend) {
Decl *ImportedDef
= Importer.Import(Definition->getDescribedClassTemplate());
if (!ImportedDef)
@@ -4413,17 +4428,20 @@ Decl *ASTNodeImporter::VisitClassTemplat
// definition. So, try to get the definition if that is available in
// the redecl chain.
ClassTemplateDecl *TemplateWithDef = getDefinition(FoundTemplate);
- if (!TemplateWithDef)
+ if (TemplateWithDef)
+ FoundTemplate = TemplateWithDef;
+ else
continue;
- FoundTemplate = TemplateWithDef; // Continue with the definition.
}
if (IsStructuralMatch(D, FoundTemplate)) {
- // The class templates structurally match; call it the same template.
+ if (!IsFriend) {
+ Importer.MapImported(D->getTemplatedDecl(),
+ FoundTemplate->getTemplatedDecl());
+ return Importer.MapImported(D, FoundTemplate);
+ }
- Importer.MapImported(D->getTemplatedDecl(),
- FoundTemplate->getTemplatedDecl());
- return Importer.MapImported(D, FoundTemplate);
+ continue;
}
}
@@ -4461,9 +4479,17 @@ Decl *ASTNodeImporter::VisitClassTemplat
ToTemplated->setDescribedClassTemplate(D2);
+ if (ToTemplated->getPreviousDecl()) {
+ assert(
+ ToTemplated->getPreviousDecl()->getDescribedClassTemplate() &&
+ "Missing described template");
+ D2->setPreviousDecl(
+ ToTemplated->getPreviousDecl()->getDescribedClassTemplate());
+ }
D2->setAccess(D->getAccess());
D2->setLexicalDeclContext(LexicalDC);
- LexicalDC->addDeclInternal(D2);
+ if (!IsFriend)
+ LexicalDC->addDeclInternal(D2);
if (FromTemplated->isCompleteDefinition() &&
!ToTemplated->isCompleteDefinition()) {
Modified: cfe/trunk/unittests/AST/ASTImporterTest.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/AST/ASTImporterTest.cpp?rev=339560&r1=339559&r2=339560&view=diff
==============================================================================
--- cfe/trunk/unittests/AST/ASTImporterTest.cpp (original)
+++ cfe/trunk/unittests/AST/ASTImporterTest.cpp Mon Aug 13 06:08:37 2018
@@ -2677,6 +2677,93 @@ TEST_P(ASTImporterTestBase, ImportUnname
EXPECT_EQ(FromIndex, 3u);
}
+TEST_P(
+ ASTImporterTestBase,
+ ImportOfFriendRecordDoesNotMergeDefinition) {
+ Decl *FromTU = getTuDecl(
+ R"(
+ class A {
+ template <int I> class F {};
+ class X {
+ template <int I> friend class F;
+ };
+ };
+ )",
+ Lang_CXX, "input0.cc");
+
+ auto *FromClass = FirstDeclMatcher<CXXRecordDecl>().match(
+ FromTU, cxxRecordDecl(hasName("F"), isDefinition()));
+ auto *FromFriendClass = LastDeclMatcher<CXXRecordDecl>().match(
+ FromTU, cxxRecordDecl(hasName("F")));
+
+ ASSERT_TRUE(FromClass);
+ ASSERT_TRUE(FromFriendClass);
+ ASSERT_NE(FromClass, FromFriendClass);
+ ASSERT_EQ(FromFriendClass->getDefinition(), FromClass);
+ ASSERT_EQ(FromFriendClass->getPreviousDecl(), FromClass);
+ ASSERT_EQ(
+ FromFriendClass->getDescribedClassTemplate()->getPreviousDecl(),
+ FromClass->getDescribedClassTemplate());
+
+ auto *ToClass = cast<CXXRecordDecl>(Import(FromClass, Lang_CXX));
+ auto *ToFriendClass = cast<CXXRecordDecl>(Import(FromFriendClass, Lang_CXX));
+
+ EXPECT_TRUE(ToClass);
+ EXPECT_TRUE(ToFriendClass);
+ EXPECT_NE(ToClass, ToFriendClass);
+ EXPECT_EQ(ToFriendClass->getDefinition(), ToClass);
+ EXPECT_EQ(ToFriendClass->getPreviousDecl(), ToClass);
+ EXPECT_EQ(
+ ToFriendClass->getDescribedClassTemplate()->getPreviousDecl(),
+ ToClass->getDescribedClassTemplate());
+}
+
+TEST_P(
+ ASTImporterTestBase,
+ ImportOfRecursiveFriendClass) {
+ Decl *FromTu = getTuDecl(
+ R"(
+ class declToImport {
+ friend class declToImport;
+ };
+ )",
+ Lang_CXX, "input.cc");
+
+ auto *FromD = FirstDeclMatcher<CXXRecordDecl>().match(
+ FromTu, cxxRecordDecl(hasName("declToImport")));
+ auto *ToD = Import(FromD, Lang_CXX);
+ auto Pattern = cxxRecordDecl(hasName("declToImport"), has(friendDecl()));
+ ASSERT_TRUE(MatchVerifier<Decl>{}.match(FromD, Pattern));
+ EXPECT_TRUE(MatchVerifier<Decl>{}.match(ToD, Pattern));
+}
+
+TEST_P(
+ ASTImporterTestBase,
+ ImportOfRecursiveFriendClassTemplate) {
+ Decl *FromTu = getTuDecl(
+ R"(
+ template <class A> class declToImport {
+ template <class A1> friend class declToImport;
+ };
+ )",
+ Lang_CXX, "input.cc");
+
+ auto *FromD = FirstDeclMatcher<ClassTemplateDecl>().match(
+ FromTu, classTemplateDecl(hasName("declToImport")));
+ auto *ToD = Import(FromD, Lang_CXX);
+
+ auto Pattern = classTemplateDecl(
+ has(cxxRecordDecl(has(friendDecl(has(classTemplateDecl()))))));
+ ASSERT_TRUE(MatchVerifier<Decl>{}.match(FromD, Pattern));
+ EXPECT_TRUE(MatchVerifier<Decl>{}.match(ToD, Pattern));
+
+ 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);
+}
+
struct DeclContextTest : ASTImporterTestBase {};
TEST_P(DeclContextTest, removeDeclOfClassTemplateSpecialization) {
More information about the cfe-commits
mailing list