martong created this revision.
martong added reviewers: a.sidorin, r.stahl, xazax.hun, balazske.
Herald added subscribers: cfe-commits, dkrupp, rnkovacs.

With this patch when any `FunctionDecl` of a redeclaration chain is imported
then we bring in the whole declaration chain.  This involves functions and
function template specializations.  Also friend functions are affected.  The
chain is imported as it is in the "from" tu, the order of the redeclarations
are kept.  I also changed the lookup logic in order to find friends, but first
making them visible in their declaration context.  We may have long
redeclaration chains if all TU contains the same prototype, but our
measurements shows no degradation in time of CTU analysis (Tmux, Xerces,
Bitcoin, Protobuf).  Also, as further work we could squash redundant
prototypes, but first ensure that functionality is working properly; then
should we optimize.

This may seem like a huge patch, sorry about that. But, most of the changes are
new tests, changes in the production code is not that much.  I also tried to
create a smaller patch which does not affect specializations, but that patch
failed to pass some of the `clang-import-test`s because there we import
function specializations. Also very importantly, we can't just change the
import of `FunctionDecl`s without changing the import of function template
specializations because they are handled as `FunctionDecl`s.


Repository:
  rC Clang

https://reviews.llvm.org/D47532

Files:
  include/clang/AST/ASTImporter.h
  lib/AST/ASTImporter.cpp
  lib/AST/DeclBase.cpp
  test/ASTMerge/class/test.cpp
  unittests/AST/ASTImporterTest.cpp

Index: unittests/AST/ASTImporterTest.cpp
===================================================================
--- unittests/AST/ASTImporterTest.cpp
+++ unittests/AST/ASTImporterTest.cpp
@@ -20,7 +20,7 @@
 
 #include "DeclMatcher.h"
 #include "Language.h"
-#include "gtest/gtest.h"
+#include "gmock/gmock.h"
 #include "llvm/ADT/StringMap.h"
 
 namespace clang {
@@ -425,6 +425,48 @@
   }
 }
 
+struct CanonicalRedeclChain : ASTImporterTestBase {};
+
+TEST_P(CanonicalRedeclChain, ShouldBeConsequentWithMatchers) {
+  Decl *FromTU = getTuDecl("void f();", Lang_CXX);
+  auto Pattern = functionDecl(hasName("f"));
+  auto D0 = FirstDeclMatcher<FunctionDecl>().match(FromTU, Pattern);
+
+  auto Redecls = getCanonicalForwardRedeclChain(D0);
+  ASSERT_EQ(Redecls.size(), 1u);
+  EXPECT_EQ(D0, Redecls[0]);
+}
+
+TEST_P(CanonicalRedeclChain, ShouldBeConsequentWithMatchers2) {
+  Decl *FromTU = getTuDecl("void f(); void f(); void f();", Lang_CXX);
+  auto Pattern = functionDecl(hasName("f"));
+  auto D0 = FirstDeclMatcher<FunctionDecl>().match(FromTU, Pattern);
+  auto D2 = LastDeclMatcher<FunctionDecl>().match(FromTU, Pattern);
+  FunctionDecl *D1 = D2->getPreviousDecl();
+
+  auto Redecls = getCanonicalForwardRedeclChain(D0);
+  ASSERT_EQ(Redecls.size(), 3u);
+  EXPECT_EQ(D0, Redecls[0]);
+  EXPECT_EQ(D1, Redecls[1]);
+  EXPECT_EQ(D2, Redecls[2]);
+}
+
+TEST_P(CanonicalRedeclChain, ShouldBeSameForAllDeclInTheChain) {
+  Decl *FromTU = getTuDecl("void f(); void f(); void f();", Lang_CXX);
+  auto Pattern = functionDecl(hasName("f"));
+  auto D0 = FirstDeclMatcher<FunctionDecl>().match(FromTU, Pattern);
+  auto D2 = LastDeclMatcher<FunctionDecl>().match(FromTU, Pattern);
+  FunctionDecl *D1 = D2->getPreviousDecl();
+
+  auto RedeclsD0 = getCanonicalForwardRedeclChain(D0);
+  auto RedeclsD1 = getCanonicalForwardRedeclChain(D1);
+  auto RedeclsD2 = getCanonicalForwardRedeclChain(D2);
+
+  EXPECT_THAT(RedeclsD0, ::testing::ContainerEq(RedeclsD1));
+  EXPECT_THAT(RedeclsD1, ::testing::ContainerEq(RedeclsD2));
+}
+
+
 TEST(ImportExpr, ImportStringLiteral) {
   MatchVerifier<Decl> Verifier;
   testImport("void declToImport() { \"foo\"; }",
@@ -1607,41 +1649,9 @@
                     .match(ToTU, classTemplateSpecializationDecl()));
 }
 
-INSTANTIATE_TEST_CASE_P(
-    ParameterizedTests, ASTImporterTestBase,
-    ::testing::Values(ArgVector(), ArgVector{"-fdelayed-template-parsing"}),);
-
 struct ImportFunctions : ASTImporterTestBase {};
 
 TEST_P(ImportFunctions,
-       PrototypeShouldBeImportedAsAPrototypeWhenThereIsNoDefinition) {
-  Decl *FromTU = getTuDecl("void f();", Lang_CXX);
-  auto Pattern = functionDecl(hasName("f"));
-  FunctionDecl *FromD =
-      FirstDeclMatcher<FunctionDecl>().match(FromTU, Pattern);
-
-  Decl *ImportedD = Import(FromD, Lang_CXX);
-  Decl *ToTU = ImportedD->getTranslationUnitDecl();
-
-  EXPECT_EQ(DeclCounter<FunctionDecl>().match(ToTU, Pattern), 1u);
-  EXPECT_TRUE(!cast<FunctionDecl>(ImportedD)->doesThisDeclarationHaveABody());
-}
-
-TEST_P(ImportFunctions,
-       PrototypeShouldBeImportedAsDefintionWhenThereIsADefinition) {
-  Decl *FromTU = getTuDecl("void f(); void f() {}", Lang_CXX);
-  auto Pattern = functionDecl(hasName("f"));
-  FunctionDecl *FromD = // Prototype
-      FirstDeclMatcher<FunctionDecl>().match(FromTU, Pattern);
-
-  Decl *ImportedD = Import(FromD, Lang_CXX);
-  Decl *ToTU = ImportedD->getTranslationUnitDecl();
-
-  EXPECT_EQ(DeclCounter<FunctionDecl>().match(ToTU, Pattern), 1u);
-  EXPECT_TRUE(cast<FunctionDecl>(ImportedD)->doesThisDeclarationHaveABody());
-}
-
-TEST_P(ImportFunctions,
        DefinitionShouldBeImportedAsDefintionWhenThereIsAPrototype) {
   Decl *FromTU = getTuDecl("void f(); void f() {}", Lang_CXX);
   auto Pattern = functionDecl(hasName("f"));
@@ -1651,7 +1661,7 @@
   Decl *ImportedD = Import(FromD, Lang_CXX);
   Decl *ToTU = ImportedD->getTranslationUnitDecl();
 
-  EXPECT_EQ(DeclCounter<FunctionDecl>().match(ToTU, Pattern), 1u);
+  EXPECT_EQ(DeclCounter<FunctionDecl>().match(ToTU, Pattern), 2u);
   EXPECT_TRUE(cast<FunctionDecl>(ImportedD)->doesThisDeclarationHaveABody());
 }
 
@@ -1668,80 +1678,116 @@
   EXPECT_TRUE(cast<FunctionDecl>(ImportedD)->doesThisDeclarationHaveABody());
 }
 
-TEST_P(ImportFunctions, DISABLED_ImportPrototypeOfRecursiveFunction) {
+TEST_P(ImportFunctions, ImportPrototypeOfRecursiveFunction) {
   Decl *FromTU = getTuDecl("void f(); void f() { f(); }", Lang_CXX);
   auto Pattern = functionDecl(hasName("f"));
-  FunctionDecl *PrototypeFD =
-      FirstDeclMatcher<FunctionDecl>().match(FromTU, Pattern);
+  auto From =
+      FirstDeclMatcher<FunctionDecl>().match(FromTU, Pattern); // Proto
 
-  Decl *ImportedD = Import(PrototypeFD, Lang_CXX);
+  Decl *ImportedD = Import(From, Lang_CXX);
   Decl *ToTU = ImportedD->getTranslationUnitDecl();
 
-  EXPECT_EQ(DeclCounter<FunctionDecl>().match(ToTU, Pattern), 1u);
-  EXPECT_TRUE(cast<FunctionDecl>(ImportedD)->doesThisDeclarationHaveABody());
+  EXPECT_EQ(DeclCounter<FunctionDecl>().match(ToTU, Pattern), 2u);
+  auto To0 = FirstDeclMatcher<FunctionDecl>().match(ToTU, Pattern);
+  auto To1 = LastDeclMatcher<FunctionDecl>().match(ToTU, Pattern);
+  EXPECT_TRUE(ImportedD == To0);
+  EXPECT_TRUE(!To0->doesThisDeclarationHaveABody());
+  EXPECT_TRUE(To1->doesThisDeclarationHaveABody());
+  EXPECT_EQ(To1->getPreviousDecl(), To0);
 }
 
 TEST_P(ImportFunctions, ImportDefinitionOfRecursiveFunction) {
   Decl *FromTU = getTuDecl("void f(); void f() { f(); }", Lang_CXX);
   auto Pattern = functionDecl(hasName("f"));
-  FunctionDecl *DefinitionFD =
-      LastDeclMatcher<FunctionDecl>().match(FromTU, Pattern);
+  auto From =
+      LastDeclMatcher<FunctionDecl>().match(FromTU, Pattern); // Def
 
-  Decl *ImportedD = Import(DefinitionFD, Lang_CXX);
+  Decl *ImportedD = Import(From, Lang_CXX);
   Decl *ToTU = ImportedD->getTranslationUnitDecl();
 
-  EXPECT_EQ(DeclCounter<FunctionDecl>().match(ToTU, Pattern), 1u);
-  EXPECT_TRUE(cast<FunctionDecl>(ImportedD)->doesThisDeclarationHaveABody());
+  EXPECT_EQ(DeclCounter<FunctionDecl>().match(ToTU, Pattern), 2u);
+  auto To0 = FirstDeclMatcher<FunctionDecl>().match(ToTU, Pattern);
+  auto To1 = LastDeclMatcher<FunctionDecl>().match(ToTU, Pattern);
+  EXPECT_TRUE(ImportedD == To1);
+  EXPECT_TRUE(!To0->doesThisDeclarationHaveABody());
+  EXPECT_TRUE(To1->doesThisDeclarationHaveABody());
+  EXPECT_EQ(To1->getPreviousDecl(), To0);
 }
 
 TEST_P(ImportFunctions, ImportPrototypes) {
   auto Pattern = functionDecl(hasName("f"));
 
   Decl *ImportedD;
   {
     Decl *FromTU = getTuDecl("void f();", Lang_CXX, "input0.cc");
-    FunctionDecl *FromD =
-        FirstDeclMatcher<FunctionDecl>().match(FromTU, Pattern);
+    auto FromD = FirstDeclMatcher<FunctionDecl>().match(FromTU, Pattern);
 
     ImportedD = Import(FromD, Lang_CXX);
   }
-  Decl *ImportedD1;
   {
     Decl *FromTU = getTuDecl("void f();", Lang_CXX, "input1.cc");
-    FunctionDecl *FromD =
-        FirstDeclMatcher<FunctionDecl>().match(FromTU, Pattern);
-    ImportedD1 = Import(FromD, Lang_CXX);
+    auto FromD = FirstDeclMatcher<FunctionDecl>().match(FromTU, Pattern);
+    Import(FromD, Lang_CXX);
   }
 
-  Decl *ToTU = ToAST->getASTContext().getTranslationUnitDecl();
+  Decl *ToTU = ImportedD->getTranslationUnitDecl();
+
+  EXPECT_EQ(DeclCounter<FunctionDecl>().match(ToTU, Pattern), 2u);
+  auto To0 = FirstDeclMatcher<FunctionDecl>().match(ToTU, Pattern);
+  auto To1 = LastDeclMatcher<FunctionDecl>().match(ToTU, Pattern);
+  EXPECT_TRUE(ImportedD == To0);
+  EXPECT_TRUE(!To0->doesThisDeclarationHaveABody());
+  EXPECT_TRUE(!To1->doesThisDeclarationHaveABody());
+  EXPECT_EQ(To1->getPreviousDecl(), To0);
+}
+
+TEST_P(ImportFunctions, ImportDefinitions) {
+  auto Pattern = functionDecl(hasName("f"));
+
+  Decl *ImportedD;
+  {
+    Decl *FromTU = getTuDecl("void f(){}", Lang_CXX, "input0.cc");
+    auto FromD = FirstDeclMatcher<FunctionDecl>().match(FromTU, Pattern);
+    ImportedD = Import(FromD, Lang_CXX);
+  }
+  {
+    Decl *FromTU = getTuDecl("void f(){};", Lang_CXX, "input1.cc");
+    auto FromD = FirstDeclMatcher<FunctionDecl>().match(FromTU, Pattern);
+    Import(FromD, Lang_CXX);
+  }
+
+  Decl *ToTU = ImportedD->getTranslationUnitDecl();
+
   EXPECT_EQ(DeclCounter<FunctionDecl>().match(ToTU, Pattern), 1u);
-  EXPECT_EQ(ImportedD, ImportedD1);
-  EXPECT_TRUE(!cast<FunctionDecl>(ImportedD)->doesThisDeclarationHaveABody());
+  auto To0 = FirstDeclMatcher<FunctionDecl>().match(ToTU, Pattern);
+  EXPECT_TRUE(ImportedD == To0);
+  EXPECT_TRUE(To0->doesThisDeclarationHaveABody());
 }
 
 TEST_P(ImportFunctions, ImportDefinitionThenPrototype) {
   auto Pattern = functionDecl(hasName("f"));
 
   Decl *ImportedD;
   {
     Decl *FromTU = getTuDecl("void f(){}", Lang_CXX, "input0.cc");
-    FunctionDecl *FromD =
-        FirstDeclMatcher<FunctionDecl>().match(FromTU, Pattern);
-
+    auto FromD = FirstDeclMatcher<FunctionDecl>().match(FromTU, Pattern);
     ImportedD = Import(FromD, Lang_CXX);
   }
-  Decl *ImportedD1;
   {
     Decl *FromTU = getTuDecl("void f();", Lang_CXX, "input1.cc");
-    FunctionDecl *FromD =
-        FirstDeclMatcher<FunctionDecl>().match(FromTU, Pattern);
-    ImportedD1 = Import(FromD, Lang_CXX);
+    auto FromD = FirstDeclMatcher<FunctionDecl>().match(FromTU, Pattern);
+    Import(FromD, Lang_CXX);
   }
 
   Decl *ToTU = ToAST->getASTContext().getTranslationUnitDecl();
-  EXPECT_EQ(DeclCounter<FunctionDecl>().match(ToTU, Pattern), 1u);
-  EXPECT_EQ(ImportedD, ImportedD1);
-  EXPECT_TRUE(cast<FunctionDecl>(ImportedD)->doesThisDeclarationHaveABody());
+
+  EXPECT_EQ(DeclCounter<FunctionDecl>().match(ToTU, Pattern), 2u);
+  auto To0 = FirstDeclMatcher<FunctionDecl>().match(ToTU, Pattern);
+  auto To1 = LastDeclMatcher<FunctionDecl>().match(ToTU, Pattern);
+  EXPECT_TRUE(ImportedD == To0);
+  EXPECT_TRUE(To0->doesThisDeclarationHaveABody());
+  EXPECT_TRUE(!To1->doesThisDeclarationHaveABody());
+  EXPECT_EQ(To1->getPreviousDecl(), To0);
 }
 
 TEST_P(ImportFunctions, ImportPrototypeThenDefinition) {
@@ -1771,31 +1817,33 @@
   EXPECT_EQ(DefinitionD->getPreviousDecl(), ProtoD);
 }
 
-TEST_P(ImportFunctions, DISABLED_ImportPrototypeThenProtoAndDefinition) {
+TEST_P(ImportFunctions,
+       ImportPrototypeThenProtoAndDefinition) {
   auto Pattern = functionDecl(hasName("f"));
 
   {
     Decl *FromTU = getTuDecl("void f();", Lang_CXX, "input0.cc");
-    FunctionDecl *FromD =
-        FirstDeclMatcher<FunctionDecl>().match(FromTU, Pattern);
-
+    auto FromD = FirstDeclMatcher<FunctionDecl>().match(FromTU, Pattern);
     Import(FromD, Lang_CXX);
   }
   {
     Decl *FromTU = getTuDecl("void f(); void f(){}", Lang_CXX, "input1.cc");
-    FunctionDecl *FromD =
-        FirstDeclMatcher<FunctionDecl>().match(FromTU, Pattern);
+    auto FromD = FirstDeclMatcher<FunctionDecl>().match(FromTU, Pattern);
     Import(FromD, Lang_CXX);
   }
 
   Decl *ToTU = ToAST->getASTContext().getTranslationUnitDecl();
-  ASSERT_EQ(DeclCounter<FunctionDecl>().match(ToTU, Pattern), 2u);
-  FunctionDecl *ProtoD = FirstDeclMatcher<FunctionDecl>().match(ToTU, Pattern);
+
+  ASSERT_EQ(DeclCounter<FunctionDecl>().match(ToTU, Pattern), 3u);
+  FunctionDecl* ProtoD = FirstDeclMatcher<FunctionDecl>().match(ToTU, Pattern);
   EXPECT_TRUE(!ProtoD->doesThisDeclarationHaveABody());
-  FunctionDecl *DefinitionD =
-      LastDeclMatcher<FunctionDecl>().match(ToTU, Pattern);
+
+  FunctionDecl* DefinitionD = LastDeclMatcher<FunctionDecl>().match(ToTU, Pattern);
   EXPECT_TRUE(DefinitionD->doesThisDeclarationHaveABody());
-  EXPECT_EQ(DefinitionD->getPreviousDecl(), ProtoD);
+
+  EXPECT_TRUE(DefinitionD->getPreviousDecl());
+  EXPECT_TRUE(!DefinitionD->getPreviousDecl()->doesThisDeclarationHaveABody());
+  EXPECT_EQ(DefinitionD->getPreviousDecl()->getPreviousDecl(), ProtoD);
 }
 
 TEST_P(ImportFunctions, OverriddenMethodsShouldBeImported) {
@@ -1835,9 +1883,185 @@
   EXPECT_TRUE(To->isVirtual());
 }
 
-INSTANTIATE_TEST_CASE_P(
-    ParameterizedTests, ImportFunctions,
-    ::testing::Values(ArgVector(), ArgVector{"-fdelayed-template-parsing"}),);
+TEST_P(ImportFunctions,
+       ImportDefinitionIfThereIsAnExistingDefinitionAndFwdDecl) {
+  Decl *ToTU = getToTuDecl(
+      R"(
+      void f() {}
+      void f();
+      )",
+      Lang_CXX);
+  ASSERT_EQ(1u,
+            DeclCounterWithPredicate<FunctionDecl>([](const FunctionDecl *FD) {
+              return FD->doesThisDeclarationHaveABody();
+            }).match(ToTU, functionDecl()));
+
+  Decl *FromTU = getTuDecl("void f() {}", Lang_CXX, "input0.cc");
+  auto *FromD = FirstDeclMatcher<FunctionDecl>().match(FromTU, functionDecl());
+
+  Import(FromD, Lang_CXX);
+
+  EXPECT_EQ(1u,
+            DeclCounterWithPredicate<FunctionDecl>([](const FunctionDecl *FD) {
+              return FD->doesThisDeclarationHaveABody();
+            }).match(ToTU, functionDecl()));
+}
+
+struct ImportFriendFunctions : ImportFunctions {};
+
+TEST_P(ImportFriendFunctions, ImportFriendFunctionRedeclChainProto) {
+  auto Pattern = functionDecl(hasName("f"));
+
+  Decl *FromTU = getTuDecl("struct X { friend void f(); };"
+                           "void f();",
+                           Lang_CXX,
+                           "input0.cc");
+  auto FromD = FirstDeclMatcher<FunctionDecl>().match(FromTU, Pattern);
+
+  auto *ImportedD = cast<FunctionDecl>(Import(FromD, Lang_CXX));
+  Decl *ToTU = ToAST->getASTContext().getTranslationUnitDecl();
+  ASSERT_EQ(DeclCounter<FunctionDecl>().match(ToTU, Pattern), 2u);
+  EXPECT_TRUE(!ImportedD->doesThisDeclarationHaveABody());
+  auto ToFD = LastDeclMatcher<FunctionDecl>().match(ToTU, Pattern);
+  EXPECT_TRUE(!ToFD->doesThisDeclarationHaveABody());
+  EXPECT_EQ(ToFD->getPreviousDecl(), ImportedD);
+}
+
+TEST_P(ImportFriendFunctions,
+       ImportFriendFunctionRedeclChainProto_OutOfClassProtoFirst) {
+  auto Pattern = functionDecl(hasName("f"));
+
+  Decl *FromTU = getTuDecl("void f();"
+                           "struct X { friend void f(); };",
+                           Lang_CXX, "input0.cc");
+  auto FromD = FirstDeclMatcher<FunctionDecl>().match(FromTU, Pattern);
+
+  auto *ImportedD = cast<FunctionDecl>(Import(FromD, Lang_CXX));
+  Decl *ToTU = ToAST->getASTContext().getTranslationUnitDecl();
+  ASSERT_EQ(DeclCounter<FunctionDecl>().match(ToTU, Pattern), 2u);
+  EXPECT_TRUE(!ImportedD->doesThisDeclarationHaveABody());
+  auto ToFD = LastDeclMatcher<FunctionDecl>().match(ToTU, Pattern);
+  EXPECT_TRUE(!ToFD->doesThisDeclarationHaveABody());
+  EXPECT_EQ(ToFD->getPreviousDecl(), ImportedD);
+}
+
+TEST_P(ImportFriendFunctions, ImportFriendFunctionRedeclChainDef) {
+  auto Pattern = functionDecl(hasName("f"));
+
+  Decl *FromTU = getTuDecl("struct X { friend void f(){} };"
+                           "void f();",
+                           Lang_CXX,
+                           "input0.cc");
+  auto FromD = FirstDeclMatcher<FunctionDecl>().match(FromTU, Pattern);
+
+  auto *ImportedD = cast<FunctionDecl>(Import(FromD, Lang_CXX));
+  Decl *ToTU = ToAST->getASTContext().getTranslationUnitDecl();
+  ASSERT_EQ(DeclCounter<FunctionDecl>().match(ToTU, Pattern), 2u);
+  EXPECT_TRUE(ImportedD->doesThisDeclarationHaveABody());
+  auto ToFD = LastDeclMatcher<FunctionDecl>().match(ToTU, Pattern);
+  EXPECT_TRUE(!ToFD->doesThisDeclarationHaveABody());
+  EXPECT_EQ(ToFD->getPreviousDecl(), ImportedD);
+}
+
+TEST_P(ImportFriendFunctions,
+       ImportFriendFunctionRedeclChainDef_OutOfClassDef) {
+  auto Pattern = functionDecl(hasName("f"));
+
+  Decl *FromTU = getTuDecl("struct X { friend void f(); };"
+                           "void f(){}",
+                           Lang_CXX, "input0.cc");
+  auto FromD = FirstDeclMatcher<FunctionDecl>().match(FromTU, Pattern);
+
+  auto *ImportedD = cast<FunctionDecl>(Import(FromD, Lang_CXX));
+  Decl *ToTU = ToAST->getASTContext().getTranslationUnitDecl();
+  ASSERT_EQ(DeclCounter<FunctionDecl>().match(ToTU, Pattern), 2u);
+  EXPECT_TRUE(!ImportedD->doesThisDeclarationHaveABody());
+  auto ToFD = LastDeclMatcher<FunctionDecl>().match(ToTU, Pattern);
+  EXPECT_TRUE(ToFD->doesThisDeclarationHaveABody());
+  EXPECT_EQ(ToFD->getPreviousDecl(), ImportedD);
+}
+
+TEST_P(ImportFriendFunctions,
+    DISABLED_ImportFriendFunctionRedeclChainDefWithClass) {
+  auto Pattern = functionDecl(hasName("f"));
+
+  Decl *FromTU = getTuDecl(
+      R"(
+        class X;
+        void f(X *x){}
+        class X{
+        friend void f(X *x);
+        };
+      )",
+      Lang_CXX, "input0.cc");
+  auto FromD = FirstDeclMatcher<FunctionDecl>().match(FromTU, Pattern);
+
+  auto *ImportedD = cast<FunctionDecl>(Import(FromD, Lang_CXX));
+  Decl *ToTU = ToAST->getASTContext().getTranslationUnitDecl();
+  ASSERT_EQ(DeclCounter<FunctionDecl>().match(ToTU, Pattern), 2u);
+  EXPECT_TRUE(ImportedD->doesThisDeclarationHaveABody());
+  auto *InClassFD = cast<FunctionDecl>(FirstDeclMatcher<FriendDecl>()
+                                              .match(ToTU, friendDecl())
+                                              ->getFriendDecl());
+  EXPECT_TRUE(!InClassFD->doesThisDeclarationHaveABody());
+  EXPECT_EQ(InClassFD->getPreviousDecl(), ImportedD);
+  // The parameters must refer the same type
+  EXPECT_EQ((*InClassFD->param_begin())->getOriginalType(),
+            (*ImportedD->param_begin())->getOriginalType());
+}
+
+TEST_P(ImportFriendFunctions,
+       DISABLED_ImportFriendFunctionRedeclChainDefWithClass_ImportTheProto) {
+  auto Pattern = functionDecl(hasName("f"));
+
+  Decl *FromTU = getTuDecl(
+      R"(
+        class X;
+        void f(X *x){}
+        class X{
+        friend void f(X *x);
+        };
+      )",
+      Lang_CXX, "input0.cc");
+  auto FromD = LastDeclMatcher<FunctionDecl>().match(FromTU, Pattern);
+
+  auto *ImportedD = cast<FunctionDecl>(Import(FromD, Lang_CXX));
+  Decl *ToTU = ToAST->getASTContext().getTranslationUnitDecl();
+  ASSERT_EQ(DeclCounter<FunctionDecl>().match(ToTU, Pattern), 2u);
+  EXPECT_TRUE(!ImportedD->doesThisDeclarationHaveABody());
+  auto *OutOfClassFD = FirstDeclMatcher<FunctionDecl>().match(
+      ToTU, functionDecl(unless(hasParent(friendDecl()))));
+
+  EXPECT_TRUE(OutOfClassFD->doesThisDeclarationHaveABody());
+  EXPECT_EQ(ImportedD->getPreviousDecl(), OutOfClassFD);
+  // The parameters must refer the same type
+  EXPECT_EQ((*OutOfClassFD->param_begin())->getOriginalType(),
+            (*ImportedD->param_begin())->getOriginalType());
+}
+
+TEST_P(ImportFriendFunctions, ImportFriendFunctionFromMultipleTU) {
+  auto Pattern = functionDecl(hasName("f"));
+
+  FunctionDecl *ImportedD;
+  {
+    Decl *FromTU =
+        getTuDecl("struct X { friend void f(){} };", Lang_CXX, "input0.cc");
+    auto FromD = FirstDeclMatcher<FunctionDecl>().match(FromTU, Pattern);
+    ImportedD = cast<FunctionDecl>(Import(FromD, Lang_CXX));
+  }
+  FunctionDecl *ImportedD1;
+  {
+    Decl *FromTU = getTuDecl("void f();", Lang_CXX, "input1.cc");
+    auto FromD = FirstDeclMatcher<FunctionDecl>().match(FromTU, Pattern);
+    ImportedD1 = cast<FunctionDecl>(Import(FromD, Lang_CXX));
+  }
+
+  Decl *ToTU = ToAST->getASTContext().getTranslationUnitDecl();
+  ASSERT_EQ(DeclCounter<FunctionDecl>().match(ToTU, Pattern), 2u);
+  EXPECT_TRUE(ImportedD->doesThisDeclarationHaveABody());
+  EXPECT_TRUE(!ImportedD1->doesThisDeclarationHaveABody());
+  EXPECT_EQ(ImportedD1->getPreviousDecl(), ImportedD);
+}
 
 AST_MATCHER_P(TagDecl, hasTypedefForAnonDecl, Matcher<TypedefNameDecl>,
               InnerMatcher) {
@@ -1969,9 +2193,341 @@
   EXPECT_FALSE(NS->containsDecl(Spec));
 }
 
+struct ImportFunctionTemplateSpecializations : ASTImporterTestBase {};
+
+TEST_P(ImportFunctionTemplateSpecializations,
+       TUshouldNotContainFunctionTemplateImplicitInstantiation) {
+
+  Decl *FromTU = getTuDecl(
+      R"(
+      template<class T>
+      int f() { return 0; }
+      void foo() { f<int>(); }
+      )",
+      Lang_CXX, "input0.cc");
+
+  //Check that the function template instantiation is NOT the child of the TU
+  auto Pattern = translationUnitDecl(
+      unless(has(functionDecl(hasName("f"), isTemplateInstantiation()))));
+  ASSERT_TRUE(MatchVerifier<Decl>{}.match(FromTU, Pattern));
+
+  auto *Foo = FirstDeclMatcher<FunctionDecl>().match(
+      FromTU, functionDecl(hasName("foo")));
+  ASSERT_TRUE(Import(Foo, Lang_CXX));
+
+  auto ToTU = ToAST->getASTContext().getTranslationUnitDecl();
+  EXPECT_TRUE(MatchVerifier<Decl>{}.match(ToTU, Pattern));
+}
+
+TEST_P(ImportFunctionTemplateSpecializations,
+       TUshouldNotContainFunctionTemplateExplicitInstantiation) {
+
+  Decl *FromTU = getTuDecl(
+      R"(
+      template<class T>
+      int f() { return 0; }
+      template int f<int>();
+      )",
+      Lang_CXX, "input0.cc");
+
+  //Check that the function template instantiation is NOT the child of the TU
+  auto Instantiation = functionDecl(hasName("f"), isTemplateInstantiation());
+  auto Pattern = translationUnitDecl(unless(has(Instantiation)));
+  ASSERT_TRUE(MatchVerifier<Decl>{}.match(FromTU, Pattern));
+
+  ASSERT_TRUE(Import(FirstDeclMatcher<Decl>().match(FromTU, Instantiation), Lang_CXX));
+
+  auto ToTU = ToAST->getASTContext().getTranslationUnitDecl();
+  EXPECT_TRUE(MatchVerifier<Decl>{}.match(ToTU, Pattern));
+}
+
+TEST_P(ImportFunctionTemplateSpecializations,
+       TUshouldContainFunctionTemplateSpecialization) {
+
+  Decl *FromTU = getTuDecl(
+      R"(
+      template<class T>
+      int f() { return 0; }
+      template <> int f<int>() { return 4; }
+      )",
+      Lang_CXX, "input0.cc");
+
+  //Check that the function template specialization is the child of the TU
+  auto Specialization = functionDecl(hasName("f"), isExplicitTemplateSpecialization());
+  auto Pattern = translationUnitDecl(has(Specialization));
+  ASSERT_TRUE(MatchVerifier<Decl>{}.match(FromTU, Pattern));
+
+  ASSERT_TRUE(Import(FirstDeclMatcher<Decl>().match(FromTU, Specialization), Lang_CXX));
+
+  auto ToTU = ToAST->getASTContext().getTranslationUnitDecl();
+  EXPECT_TRUE(MatchVerifier<Decl>{}.match(ToTU, Pattern));
+}
+
+TEST_P(ImportFunctionTemplateSpecializations,
+       FunctionTemplateSpecializationRedeclChain) {
+
+  Decl *FromTU = getTuDecl(
+      R"(
+      template<class T>
+      int f() { return 0; }
+      template <> int f<int>() { return 4; }
+      )",
+      Lang_CXX, "input0.cc");
+
+  auto Spec = functionDecl(hasName("f"), isExplicitTemplateSpecialization(),
+                           hasParent(translationUnitDecl()));
+  auto *FromSpecD = FirstDeclMatcher<Decl>().match(FromTU, Spec);
+  {
+    auto *TU = FromTU;
+    auto *SpecD = FromSpecD;
+    auto *TemplateD = FirstDeclMatcher<FunctionTemplateDecl>().match(
+        TU, functionTemplateDecl());
+    auto *FirstSpecD = *(TemplateD->spec_begin());
+    ASSERT_EQ(SpecD, FirstSpecD);
+    ASSERT_TRUE(SpecD->getPreviousDecl());
+    ASSERT_FALSE(cast<FunctionDecl>(SpecD->getPreviousDecl())
+                     ->doesThisDeclarationHaveABody());
+  }
+
+  ASSERT_TRUE(Import(FromSpecD, Lang_CXX));
+
+  {
+    auto *TU = ToAST->getASTContext().getTranslationUnitDecl();
+    auto *SpecD = FirstDeclMatcher<Decl>().match(TU, Spec);
+    auto *TemplateD = FirstDeclMatcher<FunctionTemplateDecl>().match(
+        TU, functionTemplateDecl());
+    auto *FirstSpecD = *(TemplateD->spec_begin());
+    EXPECT_EQ(SpecD, FirstSpecD);
+    ASSERT_TRUE(SpecD->getPreviousDecl());
+    EXPECT_FALSE(cast<FunctionDecl>(SpecD->getPreviousDecl())
+                     ->doesThisDeclarationHaveABody());
+  }
+}
+
+TEST_P(ImportFunctionTemplateSpecializations,
+       MatchNumberOfFunctionTemplateSpecializations) {
+
+  Decl *FromTU = getTuDecl(
+      R"(
+      template <typename T> constexpr int f() { return 0; }
+      template <> constexpr int f<int>() { return 4; }
+      void foo() {
+        static_assert(f<char>() == 0, "");
+        static_assert(f<int>() == 4, "");
+      }
+      )",
+      Lang_CXX11, "input0.cc");
+  auto *FromD = FirstDeclMatcher<FunctionDecl>().match(
+      FromTU, functionDecl(hasName("foo")));
+
+  Import(FromD, Lang_CXX11);
+  auto ToTU = ToAST->getASTContext().getTranslationUnitDecl();
+  EXPECT_EQ(
+      DeclCounter<FunctionDecl>().match(FromTU, functionDecl(hasName("f"))),
+      DeclCounter<FunctionDecl>().match(ToTU, functionDecl(hasName("f"))));
+}
+
+TEST_P(ImportFunctionTemplateSpecializations,
+       ImportPrototypes) {
+  auto Pattern = functionDecl(hasName("f"), isExplicitTemplateSpecialization());
+  auto Code =
+      R"(
+      // Proto of the primary template.
+      template <class T>
+      void f();
+      // Proto of the specialization.
+      template <>
+      void f<int>();
+      )";
+
+  Decl *ImportedD;
+  {
+    Decl *FromTU = getTuDecl(Code, Lang_CXX, "input0.cc");
+    auto FromD = LastDeclMatcher<FunctionDecl>().match(FromTU, Pattern);
+
+    ImportedD = Import(FromD, Lang_CXX);
+  }
+  {
+    Decl *FromTU = getTuDecl(Code, Lang_CXX, "input1.cc");
+    auto FromD = LastDeclMatcher<FunctionDecl>().match(FromTU, Pattern);
+    Import(FromD, Lang_CXX);
+  }
+
+  Decl *ToTU = ImportedD->getTranslationUnitDecl();
+
+  EXPECT_EQ(DeclCounter<FunctionDecl>().match(ToTU, Pattern), 2u);
+  auto To0 = FirstDeclMatcher<FunctionDecl>().match(ToTU, Pattern);
+  auto To1 = LastDeclMatcher<FunctionDecl>().match(ToTU, Pattern);
+  EXPECT_TRUE(ImportedD == To0);
+  EXPECT_TRUE(ImportedD != To1);
+  EXPECT_TRUE(!To0->doesThisDeclarationHaveABody());
+  EXPECT_TRUE(!To1->doesThisDeclarationHaveABody());
+  // Check that they are part of the same redecl chain.
+  EXPECT_EQ(To1->getCanonicalDecl(), To0->getCanonicalDecl());
+}
+
+TEST_P(ImportFunctionTemplateSpecializations, ImportDefinitions) {
+  auto Pattern = functionDecl(hasName("f"), isExplicitTemplateSpecialization());
+  auto Code =
+      R"(
+      // Proto of the primary template.
+      template <class T>
+      void f();
+      // Specialization and definition.
+      template <>
+      void f<int>() {}
+      )";
+
+  Decl *ImportedD;
+  {
+    Decl *FromTU = getTuDecl(Code, Lang_CXX, "input0.cc");
+    auto FromD = FirstDeclMatcher<FunctionDecl>().match(FromTU, Pattern);
+    ImportedD = Import(FromD, Lang_CXX);
+  }
+  {
+    Decl *FromTU = getTuDecl(Code, Lang_CXX, "input1.cc");
+    auto FromD = FirstDeclMatcher<FunctionDecl>().match(FromTU, Pattern);
+    Import(FromD, Lang_CXX);
+  }
+
+  Decl *ToTU = ImportedD->getTranslationUnitDecl();
+
+  EXPECT_EQ(DeclCounter<FunctionDecl>().match(ToTU, Pattern), 1u);
+  auto To0 = FirstDeclMatcher<FunctionDecl>().match(ToTU, Pattern);
+  EXPECT_TRUE(ImportedD == To0);
+  EXPECT_TRUE(To0->doesThisDeclarationHaveABody());
+
+  auto *TemplateD = FirstDeclMatcher<FunctionTemplateDecl>().match(
+      ToTU, functionTemplateDecl());
+  auto *FirstSpecD = *(TemplateD->spec_begin());
+  EXPECT_EQ(FirstSpecD->getCanonicalDecl(), To0->getCanonicalDecl());
+}
+
+TEST_P(ImportFunctionTemplateSpecializations, PrototypeThenPrototype) {
+  auto Pattern = functionDecl(hasName("f"), isExplicitTemplateSpecialization());
+  auto Code =
+      R"(
+      // Proto of the primary template.
+      template <class T>
+      void f();
+      // Specialization proto.
+      template <>
+      void f<int>();
+      // Specialization proto.
+      template <>
+      void f<int>();
+      )";
+
+  Decl *ImportedD;
+  {
+    Decl *FromTU = getTuDecl(Code, Lang_CXX, "input0.cc");
+    auto FromD = FirstDeclMatcher<FunctionDecl>().match(FromTU, Pattern);
+    ImportedD = Import(FromD, Lang_CXX);
+  }
+
+  Decl *ToTU = ImportedD->getTranslationUnitDecl();
+
+  EXPECT_EQ(DeclCounter<FunctionDecl>().match(ToTU, Pattern), 2u);
+  auto To0 = FirstDeclMatcher<FunctionDecl>().match(ToTU, Pattern);
+  auto To1 = LastDeclMatcher<FunctionDecl>().match(ToTU, Pattern);
+  EXPECT_TRUE(ImportedD == To0);
+  EXPECT_TRUE(ImportedD != To1);
+  EXPECT_TRUE(!To0->doesThisDeclarationHaveABody());
+  EXPECT_TRUE(!To1->doesThisDeclarationHaveABody());
+  EXPECT_EQ(To1->getPreviousDecl(), To0);
+}
+
+TEST_P(ImportFunctionTemplateSpecializations, PrototypeThenDefinition) {
+  auto Pattern = functionDecl(hasName("f"), isExplicitTemplateSpecialization());
+  auto Code =
+      R"(
+      // Proto of the primary template.
+      template <class T>
+      void f();
+      // Specialization proto.
+      template <>
+      void f<int>();
+      // Specialization definition.
+      template <>
+      void f<int>() {}
+      )";
+
+  Decl *ImportedD;
+  {
+    Decl *FromTU = getTuDecl(Code, Lang_CXX, "input0.cc");
+    auto FromD = FirstDeclMatcher<FunctionDecl>().match(FromTU, Pattern);
+    ImportedD = Import(FromD, Lang_CXX);
+  }
+
+  Decl *ToTU = ImportedD->getTranslationUnitDecl();
+
+  EXPECT_EQ(DeclCounter<FunctionDecl>().match(ToTU, Pattern), 2u);
+  auto To0 = FirstDeclMatcher<FunctionDecl>().match(ToTU, Pattern);
+  auto To1 = LastDeclMatcher<FunctionDecl>().match(ToTU, Pattern);
+  EXPECT_TRUE(ImportedD == To0);
+  EXPECT_TRUE(ImportedD != To1);
+  EXPECT_TRUE(!To0->doesThisDeclarationHaveABody());
+  EXPECT_TRUE(To1->doesThisDeclarationHaveABody());
+  EXPECT_EQ(To1->getPreviousDecl(), To0);
+}
+
+TEST_P(ImportFunctionTemplateSpecializations, DefinitionThenPrototype) {
+  auto Pattern = functionDecl(hasName("f"), isExplicitTemplateSpecialization());
+  auto Code =
+      R"(
+      // Proto of the primary template.
+      template <class T>
+      void f();
+      // Specialization definition.
+      template <>
+      void f<int>() {}
+      // Specialization proto.
+      template <>
+      void f<int>();
+      )";
+
+  Decl *ImportedD;
+  {
+    Decl *FromTU = getTuDecl(Code, Lang_CXX, "input0.cc");
+    auto FromD = FirstDeclMatcher<FunctionDecl>().match(FromTU, Pattern);
+    ImportedD = Import(FromD, Lang_CXX);
+  }
+
+  Decl *ToTU = ImportedD->getTranslationUnitDecl();
+
+  EXPECT_EQ(DeclCounter<FunctionDecl>().match(ToTU, Pattern), 2u);
+  auto To0 = FirstDeclMatcher<FunctionDecl>().match(ToTU, Pattern);
+  auto To1 = LastDeclMatcher<FunctionDecl>().match(ToTU, Pattern);
+  EXPECT_TRUE(ImportedD == To0);
+  EXPECT_TRUE(ImportedD != To1);
+  EXPECT_TRUE(To0->doesThisDeclarationHaveABody());
+  EXPECT_TRUE(!To1->doesThisDeclarationHaveABody());
+  EXPECT_EQ(To1->getPreviousDecl(), To0);
+}
+
 INSTANTIATE_TEST_CASE_P(
     ParameterizedTests, DeclContextTest,
     ::testing::Values(ArgVector(), ArgVector{"-fdelayed-template-parsing"}),);
 
+INSTANTIATE_TEST_CASE_P(
+    ParameterizedTests, ASTImporterTestBase,
+    ::testing::Values(ArgVector(), ArgVector{"-fdelayed-template-parsing"}),);
+
+INSTANTIATE_TEST_CASE_P(
+    ParameterizedTests, ImportFriendFunctions,
+    ::testing::Values(ArgVector(), ArgVector{"-fdelayed-template-parsing"}),);
+
+INSTANTIATE_TEST_CASE_P(
+    ParameterizedTests, ImportFunctions,
+    ::testing::Values(ArgVector(), ArgVector{"-fdelayed-template-parsing"}),);
+
+INSTANTIATE_TEST_CASE_P(
+    ParameterizedTests, ImportFunctionTemplateSpecializations,
+    ::testing::Values(ArgVector(), ArgVector{"-fdelayed-template-parsing"}),);
+
+INSTANTIATE_TEST_CASE_P(
+    ParameterizedTests, CanonicalRedeclChain,
+    ::testing::Values(ArgVector()),);
+
 } // end namespace ast_matchers
 } // end namespace clang
Index: test/ASTMerge/class/test.cpp
===================================================================
--- test/ASTMerge/class/test.cpp
+++ test/ASTMerge/class/test.cpp
@@ -13,12 +13,12 @@
 // CHECK: class1.cpp:19:3: note: enumerator 'b' with value 1 here
 // CHECK: class2.cpp:12:3: note: enumerator 'a' with value 0 here
 
-// CHECK: class1.cpp:36:8: warning: type 'F2' has incompatible definitions in different translation units
-// CHECK: class1.cpp:39:3: note: friend declared here
-// CHECK: class2.cpp:30:8: note: no corresponding friend here
-
 // CHECK: class1.cpp:43:8: warning: type 'F3' has incompatible definitions in different translation units
 // CHECK: class1.cpp:46:3: note: friend declared here
 // CHECK: class2.cpp:36:8: note: no corresponding friend here
 
+// CHECK: class1.cpp:36:8: warning: type 'F2' has incompatible definitions in different translation units
+// CHECK: class1.cpp:39:3: note: friend declared here
+// CHECK: class2.cpp:30:8: note: no corresponding friend here
+
 // CHECK: 4 warnings generated.
Index: lib/AST/DeclBase.cpp
===================================================================
--- lib/AST/DeclBase.cpp
+++ lib/AST/DeclBase.cpp
@@ -1343,6 +1343,8 @@
 }
 
 bool DeclContext::containsDecl(Decl *D) const {
+  if (hasExternalLexicalStorage())
+    LoadLexicalDeclsFromExternalStorage();
   return (D->getLexicalDeclContext() == this &&
           (D->NextInContextAndBits.getPointer() || D == LastDecl));
 }
Index: lib/AST/ASTImporter.cpp
===================================================================
--- lib/AST/ASTImporter.cpp
+++ lib/AST/ASTImporter.cpp
@@ -71,6 +71,25 @@
 
 namespace clang {
 
+  template <class T>
+  llvm::SmallVector<Decl*, 2>
+  getCanonicalForwardRedeclChain(Redeclarable<T>* D) {
+    llvm::SmallVector<Decl*, 2> Redecls;
+    for (auto R : D->getFirstDecl()->redecls()) {
+      if (R != D->getFirstDecl())
+        Redecls.push_back(R);
+    }
+    Redecls.push_back(D->getFirstDecl());
+    std::reverse(Redecls.begin(), Redecls.end());
+    return Redecls;
+  }
+
+  llvm::SmallVector<Decl*, 2> getCanonicalForwardRedeclChain(Decl* D) {
+    // Currently only FunctionDecl is supported
+    auto FD = cast<FunctionDecl>(D);
+    return getCanonicalForwardRedeclChain<FunctionDecl>(FD);
+  }
+
   class ASTNodeImporter : public TypeVisitor<ASTNodeImporter, QualType>,
                           public DeclVisitor<ASTNodeImporter, Decl *>,
                           public StmtVisitor<ASTNodeImporter, Stmt *> {
@@ -408,6 +427,8 @@
 
     // Importing overrides.
     void ImportOverrides(CXXMethodDecl *ToMethod, CXXMethodDecl *FromMethod);
+
+    FunctionDecl *FindFunctionTemplateSpecialization(FunctionDecl *FromFD);
   };
 
 template <typename InContainerTy>
@@ -2312,7 +2333,37 @@
   llvm_unreachable("All cases should be covered!");
 }
 
+FunctionDecl *
+ASTNodeImporter::FindFunctionTemplateSpecialization(FunctionDecl *FromFD) {
+  assert(FromFD->getTemplatedKind() ==
+         FunctionDecl::TK_FunctionTemplateSpecialization);
+  auto *FTSInfo = FromFD->getTemplateSpecializationInfo();
+  auto *Template = cast_or_null<FunctionTemplateDecl>(
+      Importer.Import(FTSInfo->getTemplate()));
+  if (!Template)
+    return nullptr;
+
+  // Import template arguments.
+  auto TemplArgs = FTSInfo->TemplateArguments->asArray();
+  SmallVector<TemplateArgument, 8> ToTemplArgs;
+  if (ImportTemplateArguments(TemplArgs.data(), TemplArgs.size(), ToTemplArgs))
+    return nullptr;
+
+  void *InsertPos = nullptr;
+  auto *FoundSpec = Template->findSpecialization(ToTemplArgs, InsertPos);
+  return FoundSpec;
+}
+
 Decl *ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) {
+
+  llvm::SmallVector<Decl*, 2> Redecls = getCanonicalForwardRedeclChain(D);
+  auto RedeclIt = Redecls.begin();
+  // Import the first part of the decl chain. I.e. import all previous
+  // declarations starting from the canonical decl.
+  for (;RedeclIt != Redecls.end() && *RedeclIt != D; ++RedeclIt)
+    Importer.Import(*RedeclIt);
+  assert(*RedeclIt == D);
+
   // Import the major distinguishing characteristics of this function.
   DeclContext *DC, *LexicalDC;
   DeclarationName Name;
@@ -2323,13 +2374,27 @@
   if (ToD)
     return ToD;
 
-  const FunctionDecl *FoundWithoutBody = nullptr;
-
+  const FunctionDecl *FoundByLookup = nullptr;
+
+  // If this is a function template specialization, then try to find the same
+  // existing specialization in the "to" context.  The localUncachedLookup
+  // below will not find any specialization, but would find the primary
+  // template; thus, we have to skip normal lookup in case of specializations.
+  // FIXME handle member function templates (TK_MemberSpecialization) similarly?
+  if (D->getTemplatedKind() ==
+      FunctionDecl::TK_FunctionTemplateSpecialization) {
+    if (FunctionDecl *FoundFunction = FindFunctionTemplateSpecialization(D)) {
+      if (D->doesThisDeclarationHaveABody() &&
+          FoundFunction->hasBody())
+        return Importer.Imported(D, FoundFunction);
+      FoundByLookup = FoundFunction;
+    }
+  }
   // Try to find a function in our own ("to") context with the same name, same
   // type, and in the same context as the function we're importing.
   if (!LexicalDC->isFunctionOrMethod()) {
     SmallVector<NamedDecl *, 4> ConflictingDecls;
-    unsigned IDNS = Decl::IDNS_Ordinary;
+    unsigned IDNS = Decl::IDNS_Ordinary | Decl::IDNS_OrdinaryFriend;
     SmallVector<NamedDecl *, 2> FoundDecls;
     DC->getRedeclContext()->localUncachedLookup(Name, FoundDecls);
     for (auto *FoundDecl : FoundDecls) {
@@ -2341,15 +2406,11 @@
             D->hasExternalFormalLinkage()) {
           if (Importer.IsStructurallyEquivalent(D->getType(), 
                                                 FoundFunction->getType())) {
-            // FIXME: Actually try to merge the body and other attributes.
-            const FunctionDecl *FromBodyDecl = nullptr;
-            D->hasBody(FromBodyDecl);
-            if (D == FromBodyDecl && !FoundFunction->hasBody()) {
-              // This function is needed to merge completely.
-              FoundWithoutBody = FoundFunction;
+              if (D->doesThisDeclarationHaveABody() &&
+                  FoundFunction->hasBody())
+                return Importer.Imported(D, FoundFunction);
+              FoundByLookup = FoundFunction;
               break;
-            }
-            return Importer.Imported(D, FoundFunction);
           }
 
           // FIXME: Check for overloading more carefully, e.g., by boosting
@@ -2499,9 +2560,9 @@
   }
   ToFunction->setParams(Parameters);
 
-  if (FoundWithoutBody) {
+  if (FoundByLookup) {
     auto *Recent = const_cast<FunctionDecl *>(
-          FoundWithoutBody->getMostRecentDecl());
+          FoundByLookup->getMostRecentDecl());
     ToFunction->setPreviousDecl(Recent);
   }
 
@@ -2523,10 +2584,11 @@
     ToFunction->setType(T);
   }
 
-  // Import the body, if any.
-  if (Stmt *FromBody = D->getBody()) {
-    if (Stmt *ToBody = Importer.Import(FromBody)) {
-      ToFunction->setBody(ToBody);
+  if (D->doesThisDeclarationHaveABody()) {
+    if (Stmt *FromBody = D->getBody()) {
+      if (Stmt *ToBody = Importer.Import(FromBody)) {
+        ToFunction->setBody(ToBody);
+      }
     }
   }
 
@@ -2536,14 +2598,28 @@
   if (ImportTemplateInformation(D, ToFunction))
     return nullptr;
 
-  // Add this function to the lexical context.
-  // NOTE: If the function is templated declaration, it should be not added into
-  // LexicalDC. But described template is imported during import of
-  // FunctionTemplateDecl (it happens later). So, we use source declaration
-  // to determine if we should add the result function.
-  if (!D->getDescribedFunctionTemplate())
+  bool IsFriend = D->isInIdentifierNamespace(Decl::IDNS_OrdinaryFriend);
+
+  // TODO Can we generalize this approach to other AST nodes as well?
+  if (D->getDeclContext()->containsDecl(D))
+    DC->addDeclInternal(ToFunction);
+  if (DC != LexicalDC && D->getLexicalDeclContext()->containsDecl(D))
     LexicalDC->addDeclInternal(ToFunction);
 
+  // Friend declarations lexical context is the befriending class, but the
+  // semantic context is the enclosing scope of the befriending class.
+  // We want the friend functions to be found in the semantic context by lookup.
+  // FIXME should we handle this genrically in VisitFriendDecl?
+  // In Other cases when LexicalDC != DC we don't want it to be added,
+  // e.g out-of-class definitions like void B::f() {} .
+  if (LexicalDC != DC && IsFriend) {
+    DC->makeDeclVisibleInContext(ToFunction);
+  }
+
+  // Import the rest of the chain. I.e. import all subsequent declarations.
+  for (++RedeclIt; RedeclIt != Redecls.end(); ++RedeclIt)
+    Importer.Import(*RedeclIt);
+
   if (auto *FromCXXMethod = dyn_cast<CXXMethodDecl>(D))
     ImportOverrides(cast<CXXMethodDecl>(ToFunction), FromCXXMethod);
 
Index: include/clang/AST/ASTImporter.h
===================================================================
--- include/clang/AST/ASTImporter.h
+++ include/clang/AST/ASTImporter.h
@@ -43,6 +43,15 @@
 class TypeSourceInfo;
 class Attr;
 
+  // \brief Returns with a list of declarations started from the canonical decl
+  // then followed by subsequent decls in the translation unit.
+  // This gives a canonical list for each entry in the redecl chain.
+  // `Decl::redecls()` gives a list of decls which always start from the
+  // previous decl and the next item is actually the previous item in the order
+  // of source locations.  Thus, `Decl::redecls()` gives different lists for
+  // the different entries in a given redecl chain.
+  llvm::SmallVector<Decl*, 2> getCanonicalForwardRedeclChain(Decl* D);
+
   /// Imports selected nodes from one AST context into another context,
   /// merging AST nodes where appropriate.
   class ASTImporter {
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to