aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBalazs Keri <1.int32@gmail.com>2019-08-12 10:07:38 +0000
committerBalazs Keri <1.int32@gmail.com>2019-08-12 10:07:38 +0000
commitb58fb4558d242eeddf845703aa36b521f565f339 (patch)
treedbf843a5149df3d74297f02ed62e82e622c003ae
parent8e613d7a8d21a0c0cc4b604cd7be017f8636ec86 (diff)
[ASTImporter] Fix for import of friend class template with definition.
Summary: If there is a friend class template "prototype" (forward declaration) and later a definition for it in the existing code, this existing definition may be not found by ASTImporter because it is not linked to the prototype (under the friend AST node). The problem is fixed by looping over all found matching decls instead of break after the first found one. Reviewers: martong, a.sidorin, shafik, a_sidorin Reviewed By: a_sidorin Subscribers: rnkovacs, dkrupp, Szelethus, gamesh411, cfe-commits Tags: #clang Differential Revision: https://reviews.llvm.org/D65269 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@368551 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--lib/AST/ASTImporter.cpp10
-rw-r--r--unittests/AST/ASTImporterTest.cpp44
2 files changed, 50 insertions, 4 deletions
diff --git a/lib/AST/ASTImporter.cpp b/lib/AST/ASTImporter.cpp
index 69a9f9ddb6..e999e89eda 100644
--- a/lib/AST/ASTImporter.cpp
+++ b/lib/AST/ASTImporter.cpp
@@ -5082,11 +5082,13 @@ ExpectedDecl ASTNodeImporter::VisitClassTemplateDecl(ClassTemplateDecl *D) {
if (IsStructuralMatch(D, FoundTemplate)) {
ClassTemplateDecl *TemplateWithDef =
getTemplateDefinition(FoundTemplate);
- if (D->isThisDeclarationADefinition() && TemplateWithDef) {
+ if (D->isThisDeclarationADefinition() && TemplateWithDef)
return Importer.MapImported(D, TemplateWithDef);
- }
- FoundByLookup = FoundTemplate;
- break;
+ if (!FoundByLookup)
+ FoundByLookup = FoundTemplate;
+ // Search in all matches because there may be multiple decl chains,
+ // see ASTTests test ImportExistingFriendClassTemplateDef.
+ continue;
}
}
diff --git a/unittests/AST/ASTImporterTest.cpp b/unittests/AST/ASTImporterTest.cpp
index 97c88b95be..3cdad0dfd5 100644
--- a/unittests/AST/ASTImporterTest.cpp
+++ b/unittests/AST/ASTImporterTest.cpp
@@ -5191,6 +5191,50 @@ TEST_P(ASTImporterOptionSpecificTestBase, LambdaInGlobalScope) {
EXPECT_TRUE(ToF);
}
+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);
+
+ auto *FromClassProto = FirstDeclMatcher<ClassTemplateDecl>().match(
+ FromTU, classTemplateDecl(hasName("Class")));
+ auto *FromClassDef = LastDeclMatcher<ClassTemplateDecl>().match(
+ FromTU, classTemplateDecl(hasName("Class")));
+ ASSERT_FALSE(FromClassProto->isThisDeclarationADefinition());
+ ASSERT_TRUE(FromClassDef->isThisDeclarationADefinition());
+ ASSERT_FALSE(FromClassDef->getPreviousDecl());
+ ASSERT_EQ(FromClassDef->getMostRecentDecl(), FromClassDef);
+ ASSERT_EQ(FromClassProto->getMostRecentDecl(), FromClassProto);
+
+ auto *ImportedDef = Import(FromClassDef, Lang_CXX);
+ // At import we should find the definition for 'Class' even if the
+ // prototype (inside 'friend') for it comes first in the AST and is not
+ // linked to the definition.
+ EXPECT_EQ(ImportedDef, ToClassDef);
+}
+
struct LLDBLookupTest : ASTImporterOptionSpecificTestBase {
LLDBLookupTest() {
Creator = [](ASTContext &ToContext, FileManager &ToFileManager,