]> granicus.if.org Git - clang/commitdiff
[ASTImporter] Extend lookup logic in class templates
authorAleksei Sidorin <a.sidorin@samsung.com>
Tue, 15 May 2018 11:09:07 +0000 (11:09 +0000)
committerAleksei Sidorin <a.sidorin@samsung.com>
Tue, 15 May 2018 11:09:07 +0000 (11:09 +0000)
During import of a class template, lookup may find a forward
declaration and structural match falsely reports equivalency
between a forward decl and a definition. The result is that
some definitions are not imported if we had imported a forward
decl previously. This patch gives a fix.

Patch by Gabor Marton!

Differential Revision: https://reviews.llvm.org/D46353

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@332338 91177308-0d34-0410-b5e6-96231b3b80d8

lib/AST/ASTImporter.cpp
unittests/AST/ASTImporterTest.cpp

index 57d4585e07d2004e8b00020ca60f17ba0786f2f4..d8c2259e1c2491950486d66162718fbdc3536a42 100644 (file)
@@ -4108,8 +4108,14 @@ Decl *ASTNodeImporter::VisitClassTemplateDecl(ClassTemplateDecl *D) {
       if (auto *FoundTemplate = dyn_cast<ClassTemplateDecl>(Found)) {
         if (IsStructuralMatch(D, FoundTemplate)) {
           // The class templates structurally match; call it the same template.
-          // FIXME: We may be filling in a forward declaration here. Handle
-          // this case!
+
+          // We found a forward declaration but the class to be imported has a
+          // definition.
+          // FIXME Add this forward declaration to the redeclaration chain.
+          if (D->isThisDeclarationADefinition() &&
+              !FoundTemplate->isThisDeclarationADefinition())
+            continue;
+
           Importer.Imported(D->getTemplatedDecl(), 
                             FoundTemplate->getTemplatedDecl());
           return Importer.Imported(D, FoundTemplate);
index debcfe67d9629408f477717a3c4639917dc96b82..9eec1d20bac688166bc2a767ed41808277666288 100644 (file)
@@ -1431,6 +1431,39 @@ TEST_P(ASTImporterTestBase,
       MatchVerifier<Decl>{}.match(To->getTranslationUnitDecl(), Pattern));
 }
 
+TEST_P(ASTImporterTestBase, ImportDefinitionOfClassTemplateAfterFwdDecl) {
+  {
+    Decl *FromTU = getTuDecl(
+        R"(
+            template <typename T>
+            struct B;
+            )",
+        Lang_CXX, "input0.cc");
+    auto *FromD = FirstDeclMatcher<ClassTemplateDecl>().match(
+        FromTU, classTemplateDecl(hasName("B")));
+
+    Import(FromD, Lang_CXX);
+  }
+
+  {
+    Decl *FromTU = getTuDecl(
+        R"(
+            template <typename T>
+            struct B {
+              void f();
+            };
+            )",
+        Lang_CXX, "input1.cc");
+    FunctionDecl *FromD = FirstDeclMatcher<FunctionDecl>().match(
+        FromTU, functionDecl(hasName("f")));
+    Import(FromD, Lang_CXX);
+    auto *FromCTD = FirstDeclMatcher<ClassTemplateDecl>().match(
+        FromTU, classTemplateDecl(hasName("B")));
+    auto *ToCTD = cast<ClassTemplateDecl>(Import(FromCTD, Lang_CXX));
+    EXPECT_TRUE(ToCTD->isThisDeclarationADefinition());
+  }
+}
+
 INSTANTIATE_TEST_CASE_P(
     ParameterizedTests, ASTImporterTestBase,
     ::testing::Values(ArgVector(), ArgVector{"-fdelayed-template-parsing"}),);