r314336 - Add support for remembering origins to ExternalASTMerger

Sean Callanan via cfe-commits cfe-commits at lists.llvm.org
Wed Sep 27 12:57:58 PDT 2017


Author: spyffe
Date: Wed Sep 27 12:57:58 2017
New Revision: 314336

URL: http://llvm.org/viewvc/llvm-project?rev=314336&view=rev
Log:
Add support for remembering origins to ExternalASTMerger

ExternalASTMerger has hitherto relied on being able to look up 
any Decl through its named DeclContext chain. This works for 
many cases, but causes problems for function-local structs, 
which cannot be looked up in their containing FunctionDecl. An
example case is

void f() {
  { struct S { int a; }; }
  { struct S { bool b; }; }
}

It is not possible to lookup either of the two Ses individually 
(or even to provide enough information to disambiguate) after 
parsing is over; and there is typically no need to, since they 
are invisible to the outside world.

However, ExternalASTMerger needs to be able to complete either 
S on demand. This led to an XFAIL on test/Import/local-struct, 
which this patch removes. The way the patch works is:

It defines a new data structure, ExternalASTMerger::OriginMap,
which clients are expected to maintain (default-constructing 
if the origin does not have an ExternalASTMerger servicing it)
As DeclContexts are imported, if they cannot be looked up by 
name they are placed in the OriginMap. This allows 
ExternalASTMerger to complete them later if necessary.
As DeclContexts are imported from an origin that already has 
its own OriginMap, the origins are forwarded – but only for 
those DeclContexts that are actually used. This keeps the 
amount of stored data minimal.

The patch also applies several improvements from review:

- Thoroughly documents the interface to ExternalASTMerger;
- Adds optional logging to help track what's going on; and
- Cleans up a bunch of braces and dangling elses.

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

Added:
    cfe/trunk/test/Import/extern-c-function/
      - copied from r311017, cfe/trunk/test/Import/overloaded-function/
    cfe/trunk/test/Import/extern-c-function/Inputs/F.cpp
      - copied, changed from r311017, cfe/trunk/test/Import/overloaded-function/Inputs/F1.c
    cfe/trunk/test/Import/extern-c-function/test.cpp
      - copied, changed from r311017, cfe/trunk/test/Import/overloaded-function/test.c
    cfe/trunk/test/Import/forward-declared-objc-class/
      - copied from r311468, cfe/trunk/test/Import/forward-declared-struct/
    cfe/trunk/test/Import/forward-declared-objc-class/Inputs/S1.m
      - copied, changed from r311468, cfe/trunk/test/Import/forward-declared-struct/Inputs/S1.c
    cfe/trunk/test/Import/forward-declared-objc-class/Inputs/S2.m
      - copied, changed from r311468, cfe/trunk/test/Import/forward-declared-struct/Inputs/S2.c
    cfe/trunk/test/Import/forward-declared-objc-class/Inputs/S3.m
      - copied, changed from r311468, cfe/trunk/test/Import/forward-declared-struct/Inputs/S1.c
    cfe/trunk/test/Import/forward-declared-objc-class/test.m
      - copied, changed from r311468, cfe/trunk/test/Import/forward-declared-struct/test.c
    cfe/trunk/test/Import/forward-declared-struct/Inputs/S3.c
      - copied unchanged from r311468, cfe/trunk/test/Import/forward-declared-struct/Inputs/S1.c
    cfe/trunk/test/Import/local-struct-use-origins/
      - copied from r310656, cfe/trunk/test/Import/local-struct/
    cfe/trunk/test/Import/objc-definitions-in-expression/
      - copied from r311468, cfe/trunk/test/Import/objc-method/
    cfe/trunk/test/Import/struct-and-var/
      - copied from r310656, cfe/trunk/test/Import/conflicting-struct/
    cfe/trunk/test/Import/template/
      - copied from r310656, cfe/trunk/test/Import/template-specialization/
Removed:
    cfe/trunk/test/Import/extern-c-function/Inputs/F1.c
    cfe/trunk/test/Import/extern-c-function/Inputs/F2.c
    cfe/trunk/test/Import/extern-c-function/test.c
    cfe/trunk/test/Import/forward-declared-objc-class/Inputs/S1.c
    cfe/trunk/test/Import/forward-declared-objc-class/Inputs/S2.c
    cfe/trunk/test/Import/forward-declared-objc-class/test.c
Modified:
    cfe/trunk/include/clang/AST/ExternalASTMerger.h
    cfe/trunk/lib/AST/ExternalASTMerger.cpp
    cfe/trunk/lib/Sema/SemaType.cpp
    cfe/trunk/test/Import/forward-declared-struct/test.c
    cfe/trunk/test/Import/local-struct-use-origins/test.cpp
    cfe/trunk/test/Import/local-struct/test.cpp
    cfe/trunk/test/Import/objc-definitions-in-expression/test.m
    cfe/trunk/test/Import/struct-and-var/Inputs/S1.cpp
    cfe/trunk/test/Import/struct-and-var/Inputs/S2.cpp
    cfe/trunk/test/Import/struct-and-var/test.cpp
    cfe/trunk/test/Import/template/Inputs/T.cpp
    cfe/trunk/test/Import/template/test.cpp
    cfe/trunk/tools/clang-import-test/clang-import-test.cpp

Modified: cfe/trunk/include/clang/AST/ExternalASTMerger.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/ExternalASTMerger.h?rev=314336&r1=314335&r2=314336&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/ExternalASTMerger.h (original)
+++ cfe/trunk/include/clang/AST/ExternalASTMerger.h Wed Sep 27 12:57:58 2017
@@ -16,34 +16,159 @@
 
 #include "clang/AST/ASTImporter.h"
 #include "clang/AST/ExternalASTSource.h"
+#include "llvm/Support/raw_ostream.h"
 
 namespace clang {
 
+/// ExternalASTSource implementation that merges information from several
+/// ASTContexts.
+///
+/// ExtermalASTMerger maintains a vector of ASTImporters that it uses to import
+/// (potentially incomplete) Decls and DeclContexts from the source ASTContexts
+/// in response to ExternalASTSource API calls.
+///
+/// When lookup occurs in the resulting imported DeclContexts, the original
+/// DeclContexts need to be queried.  Roughly, there are three cases here:
+///
+/// - The DeclContext of origin can be found by simple name lookup.  In this
+///   case, no additional state is required.
+///
+/// - The DeclContext of origin is different from what would be found by name
+///   lookup.  In this case, Origins contains an entry overriding lookup and
+///   specifying the correct pair of DeclContext/ASTContext.
+///
+/// - The DeclContext of origin was determined by another ExterenalASTMerger. 
+///   (This is possible when the source ASTContext for one of the Importers has
+///   its own ExternalASTMerger).  The origin must be properly forwarded in this
+///   case.
+///
+/// ExternalASTMerger's job is to maintain the data structures necessary to
+/// allow this.  The data structures themselves can be extracted (read-only) and
+/// copied for re-use.
 class ExternalASTMerger : public ExternalASTSource {
 public:
-  struct ImporterPair {
-    std::unique_ptr<ASTImporter> Forward;
-    std::unique_ptr<ASTImporter> Reverse;
+  /// A single origin for a DeclContext.  Unlike Decls, DeclContexts do
+  /// not allow their containing ASTContext to be determined in all cases.
+  struct DCOrigin {
+    DeclContext *DC;
+    ASTContext *AST;
   };
 
+  typedef std::map<const DeclContext *, DCOrigin> OriginMap;
+  typedef std::vector<std::unique_ptr<ASTImporter>> ImporterVector;
 private:
-  std::vector<ImporterPair> Importers;
+  /// One importer exists for each source.  
+  ImporterVector Importers;
+  /// Overrides in case name lookup would return nothing or would return
+  /// the wrong thing.
+  OriginMap Origins;
+  /// The installed log stream.
+  llvm::raw_ostream *LogStream;
 
 public:
-  struct ImporterEndpoint {
+  /// The target for an ExternalASTMerger.
+  ///
+  /// ASTImporters require both ASTContext and FileManager to be able to
+  /// import SourceLocations properly.
+  struct ImporterTarget {
     ASTContext &AST;
     FileManager &FM;
   };
-  ExternalASTMerger(const ImporterEndpoint &Target,
-                    llvm::ArrayRef<ImporterEndpoint> Sources);
+  /// A source for an ExternalASTMerger.
+  ///
+  /// ASTImporters require both ASTContext and FileManager to be able to
+  /// import SourceLocations properly.  Additionally, when import occurs for
+  /// a DeclContext whose origin has been overridden, then this
+  /// ExternalASTMerger must be able to determine that.
+  struct ImporterSource {
+    ASTContext &AST;
+    FileManager &FM;
+    const OriginMap &OM;
+  };
+
+private:
+  /// The target for this ExtenralASTMerger.
+  ImporterTarget Target;
 
+public:
+  ExternalASTMerger(const ImporterTarget &Target,
+                    llvm::ArrayRef<ImporterSource> Sources);
+
+  /// Add a set of ASTContexts as possible origins.
+  ///
+  /// Usually the set will be initialized in the constructor, but long-lived
+  /// ExternalASTMergers may neeed to import from new sources (for example,
+  /// newly-parsed source files).
+  ///
+  /// Ensures that Importers does not gain duplicate entries as a result.
+  void AddSources(llvm::ArrayRef<ImporterSource> Sources);
+
+  /// Remove a set of ASTContexts as possible origins.
+  ///
+  /// Sometimes an origin goes away (for example, if a source file gets
+  /// superseded by a newer version). 
+  ///
+  /// The caller is responsible for ensuring that this doesn't leave
+  /// DeclContexts that can't be completed.
+  void RemoveSources(llvm::ArrayRef<ImporterSource> Sources);
+
+  /// Implementation of the ExternalASTSource API.
   bool FindExternalVisibleDeclsByName(const DeclContext *DC,
                                       DeclarationName Name) override;
 
+  /// Implementation of the ExternalASTSource API.
   void
   FindExternalLexicalDecls(const DeclContext *DC,
                            llvm::function_ref<bool(Decl::Kind)> IsKindWeWant,
                            SmallVectorImpl<Decl *> &Result) override;
+
+  /// Implementation of the ExternalASTSource API.
+  void CompleteType(TagDecl *Tag) override;
+
+  /// Implementation of the ExternalASTSource API.
+  void CompleteType(ObjCInterfaceDecl *Interface) override;
+
+  /// Returns true if DC can be found in any source AST context.
+  bool CanComplete(DeclContext *DC);
+
+  /// Records an origin in Origins only if name lookup would find
+  /// something different or nothing at all.
+  void MaybeRecordOrigin(const DeclContext *ToDC, DCOrigin Origin);
+
+  /// Regardless of any checks, override the Origin for a DeclContext.
+  void ForceRecordOrigin(const DeclContext *ToDC, DCOrigin Origin);
+
+  /// Get a read-only view of the Origins map, for use in constructing
+  /// an ImporterSource for another ExternalASTMerger.
+  const OriginMap &GetOrigins() { return Origins; }
+
+  /// Returns true if Importers contains an ASTImporter whose source is
+  /// OriginContext.
+  bool HasImporterForOrigin(ASTContext &OriginContext);
+
+  /// Returns a reference to the ASTRImporter from Importers whose origin
+  /// is OriginContext.  This allows manual import of ASTs while preserving the
+  /// OriginMap correctly.
+  ASTImporter &ImporterForOrigin(ASTContext &OriginContext);
+
+  /// Sets the current log stream.
+  void SetLogStream(llvm::raw_string_ostream &Stream) { LogStream = &Stream; }
+private:
+  /// Records and origin in Origins.
+  void RecordOriginImpl(const DeclContext *ToDC, DCOrigin Origin,
+                                  ASTImporter &importer);
+
+  /// Performs an action for every DeclContext that is identified as
+  /// corresponding (either by forced origin or by name lookup) to DC.
+  template <typename CallbackType>
+  void ForEachMatchingDC(const DeclContext *DC, CallbackType Callback);
+
+public: 
+  /// Log something if there is a logging callback installed.
+  llvm::raw_ostream &logs() { return *LogStream; }
+
+  /// True if the log stream is not llvm::nulls();
+  bool LoggingEnabled() { return LogStream != &llvm::nulls(); }
 };
 
 } // end namespace clang

Modified: cfe/trunk/lib/AST/ExternalASTMerger.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ExternalASTMerger.cpp?rev=314336&r1=314335&r2=314336&view=diff
==============================================================================
--- cfe/trunk/lib/AST/ExternalASTMerger.cpp (original)
+++ cfe/trunk/lib/AST/ExternalASTMerger.cpp Wed Sep 27 12:57:58 2017
@@ -14,6 +14,7 @@
 
 #include "clang/AST/ASTContext.h"
 #include "clang/AST/Decl.h"
+#include "clang/AST/DeclCXX.h"
 #include "clang/AST/DeclObjC.h"
 #include "clang/AST/ExternalASTMerger.h"
 
@@ -32,29 +33,18 @@ template <typename T> struct Source {
 
 typedef std::pair<Source<NamedDecl *>, ASTImporter *> Candidate;
 
-class LazyASTImporter : public ASTImporter {
-public:
-  LazyASTImporter(ASTContext &ToContext, FileManager &ToFileManager,
-                  ASTContext &FromContext, FileManager &FromFileManager)
-      : ASTImporter(ToContext, ToFileManager, FromContext, FromFileManager,
-                    /*MinimalImport=*/true) {}
-  Decl *Imported(Decl *From, Decl *To) override {
-    if (auto ToTag = dyn_cast<TagDecl>(To)) {
-      ToTag->setHasExternalLexicalStorage();
-      ToTag->setMustBuildLookupTable();
-    } else if (auto ToNamespace = dyn_cast<NamespaceDecl>(To)) {
-      ToNamespace->setHasExternalVisibleStorage();
-    } else if (auto ToContainer = dyn_cast<ObjCContainerDecl>(To)) {
-      ToContainer->setHasExternalLexicalStorage();
-      ToContainer->setMustBuildLookupTable();
-    }
-    return ASTImporter::Imported(From, To);
-  }
-};
+/// For the given DC, return the DC that is safe to perform lookups on.  This is
+/// the DC we actually want to work with most of the time.
+const DeclContext *CanonicalizeDC(const DeclContext *DC) {
+  if (isa<LinkageSpecDecl>(DC))
+    return DC->getRedeclContext();
+  return DC;
+}
 
 Source<const DeclContext *>
 LookupSameContext(Source<TranslationUnitDecl *> SourceTU, const DeclContext *DC,
                   ASTImporter &ReverseImporter) {
+  DC = CanonicalizeDC(DC);
   if (DC->isTranslationUnit()) {
     return SourceTU;
   }
@@ -64,101 +54,328 @@ LookupSameContext(Source<TranslationUnit
     // If we couldn't find the parent DC in this TranslationUnit, give up.
     return nullptr;
   }
-  auto ND = cast<NamedDecl>(DC);
+  auto *ND = cast<NamedDecl>(DC);
   DeclarationName Name = ND->getDeclName();
   Source<DeclarationName> SourceName = ReverseImporter.Import(Name);
   DeclContext::lookup_result SearchResult =
       SourceParentDC.get()->lookup(SourceName.get());
   size_t SearchResultSize = SearchResult.size();
-  // Handle multiple candidates once we have a test for it.
-  // This may turn up when we import template specializations correctly.
-  assert(SearchResultSize < 2);
-  if (SearchResultSize == 0) {
-    // couldn't find the name, so we have to give up
+  if (SearchResultSize == 0 || SearchResultSize > 1) {
+    // There are two cases here.  First, we might not find the name.
+    // We might also find multiple copies, in which case we have no
+    // guarantee that the one we wanted is the one we pick.  (E.g.,
+    // if we have two specializations of the same template it is
+    // very hard to determine which is the one you want.)
+    //
+    // The Origins map fixes this problem by allowing the origin to be
+    // explicitly recorded, so we trigger that recording by returning
+    // nothing (rather than a possibly-inaccurate guess) here.
     return nullptr;
   } else {
     NamedDecl *SearchResultDecl = SearchResult[0];
-    return dyn_cast<DeclContext>(SearchResultDecl);
+    if (isa<DeclContext>(SearchResultDecl) &&
+        SearchResultDecl->getKind() == DC->getDeclKind())
+      return cast<DeclContext>(SearchResultDecl)->getPrimaryContext();
+    return nullptr; // This type of lookup is unsupported
   }
 }
 
-bool IsForwardDeclaration(Decl *D) {
-  if (auto TD = dyn_cast<TagDecl>(D)) {
-    return !TD->isThisDeclarationADefinition();
-  } else if (auto FD = dyn_cast<FunctionDecl>(D)) {
-    return !FD->isThisDeclarationADefinition();
-  } else if (auto OID = dyn_cast<ObjCInterfaceDecl>(D)) {
-     return OID->isThisDeclarationADefinition();
-  } else {
-    return false;
-  }
-}
+/// A custom implementation of ASTImporter, for ExternalASTMerger's purposes.
+///
+/// There are several modifications:
+///
+/// - It enables lazy lookup (via the HasExternalLexicalStorage flag and a few
+///   others), which instructs Clang to refer to ExternalASTMerger.  Also, it
+///   forces MinimalImport to true, which is necessary to make this work.
+/// - It maintains a reverse importer for use with names.  This allows lookup of
+///   arbitrary names in the source context.
+/// - It updates the ExternalASTMerger's origin map as needed whenever a
+///   it sees a DeclContext.
+class LazyASTImporter : public ASTImporter {
+private:
+  ExternalASTMerger &Parent;
+  ASTImporter Reverse;
+  const ExternalASTMerger::OriginMap &FromOrigins;
 
-template <typename CallbackType>
-void ForEachMatchingDC(
-    const DeclContext *DC,
-    llvm::ArrayRef<ExternalASTMerger::ImporterPair> Importers,
-    CallbackType Callback) {
-  for (const ExternalASTMerger::ImporterPair &IP : Importers) {
-    Source<TranslationUnitDecl *> SourceTU =
-        IP.Forward->getFromContext().getTranslationUnitDecl();
-    if (auto SourceDC = LookupSameContext(SourceTU, DC, *IP.Reverse))
-      Callback(IP, SourceDC);
+  llvm::raw_ostream &logs() { return Parent.logs(); }
+public:
+  LazyASTImporter(ExternalASTMerger &_Parent, ASTContext &ToContext,
+                  FileManager &ToFileManager, ASTContext &FromContext,
+                  FileManager &FromFileManager,
+                  const ExternalASTMerger::OriginMap &_FromOrigins)
+      : ASTImporter(ToContext, ToFileManager, FromContext, FromFileManager,
+                    /*MinimalImport=*/true),
+        Parent(_Parent), Reverse(FromContext, FromFileManager, ToContext,
+                                 ToFileManager, /*MinimalImport=*/true), FromOrigins(_FromOrigins) {}
+
+  /// Whenever a DeclContext is imported, ensure that ExternalASTSource's origin
+  /// map is kept up to date.  Also set the appropriate flags.
+  Decl *Imported(Decl *From, Decl *To) override {
+    if (auto *ToDC = dyn_cast<DeclContext>(To)) {
+      const bool LoggingEnabled = Parent.LoggingEnabled();
+      if (LoggingEnabled)
+        logs() << "(ExternalASTMerger*)" << (void*)&Parent
+               << " imported (DeclContext*)" << (void*)ToDC
+               << ", (ASTContext*)" << (void*)&getToContext()
+               << " from (DeclContext*)" << (void*)llvm::cast<DeclContext>(From)
+               << ", (ASTContext*)" << (void*)&getFromContext()
+               << "\n";
+      Source<DeclContext *> FromDC(
+          cast<DeclContext>(From)->getPrimaryContext());
+      if (FromOrigins.count(FromDC) &&
+          Parent.HasImporterForOrigin(*FromOrigins.at(FromDC).AST)) {
+        if (LoggingEnabled)
+          logs() << "(ExternalASTMerger*)" << (void*)&Parent
+                 << " forced origin (DeclContext*)"
+                 << (void*)FromOrigins.at(FromDC).DC
+                 << ", (ASTContext*)"
+                 << (void*)FromOrigins.at(FromDC).AST
+                 << "\n";
+        Parent.ForceRecordOrigin(ToDC, FromOrigins.at(FromDC));
+      } else {
+        if (LoggingEnabled)
+          logs() << "(ExternalASTMerger*)" << (void*)&Parent
+                 << " maybe recording origin (DeclContext*)" << (void*)FromDC
+                 << ", (ASTContext*)" << (void*)&getFromContext()
+                 << "\n";
+        Parent.MaybeRecordOrigin(ToDC, {FromDC, &getFromContext()});
+      }
+    }
+    if (auto *ToTag = dyn_cast<TagDecl>(To)) {
+      ToTag->setHasExternalLexicalStorage();
+      ToTag->setMustBuildLookupTable();
+      assert(Parent.CanComplete(ToTag));
+    } else if (auto *ToNamespace = dyn_cast<NamespaceDecl>(To)) {
+      ToNamespace->setHasExternalVisibleStorage();
+      assert(Parent.CanComplete(ToNamespace));
+    } else if (auto *ToContainer = dyn_cast<ObjCContainerDecl>(To)) {
+      ToContainer->setHasExternalLexicalStorage();
+      ToContainer->setMustBuildLookupTable();
+      assert(Parent.CanComplete(ToContainer));
+    }
+    return ASTImporter::Imported(From, To);
   }
-}
+  ASTImporter &GetReverse() { return Reverse; }
+};
 
 bool HasDeclOfSameType(llvm::ArrayRef<Candidate> Decls, const Candidate &C) {
+  if (isa<FunctionDecl>(C.first.get()))
+    return false;
   return llvm::any_of(Decls, [&](const Candidate &D) {
     return C.first.get()->getKind() == D.first.get()->getKind();
   });
 }
+
 } // end namespace
 
-ExternalASTMerger::ExternalASTMerger(const ImporterEndpoint &Target,
-                                     llvm::ArrayRef<ImporterEndpoint> Sources) {
-  for (const ImporterEndpoint &S : Sources) {
-    Importers.push_back(
-        {llvm::make_unique<LazyASTImporter>(Target.AST, Target.FM, S.AST, S.FM),
-         llvm::make_unique<ASTImporter>(S.AST, S.FM, Target.AST, Target.FM,
-                                        /*MinimalImport=*/true)});
-  }
+ASTImporter &ExternalASTMerger::ImporterForOrigin(ASTContext &OriginContext) {
+  for (const std::unique_ptr<ASTImporter> &I : Importers)
+    if (&I->getFromContext() == &OriginContext)
+      return *I;
+  llvm_unreachable("We should have an importer for this origin!");
 }
 
-bool ExternalASTMerger::FindExternalVisibleDeclsByName(const DeclContext *DC,
-                                                       DeclarationName Name) {
-  llvm::SmallVector<NamedDecl *, 1> Decls;
-  llvm::SmallVector<Candidate, 4> CompleteDecls;
-  llvm::SmallVector<Candidate, 4> ForwardDecls;
+namespace {
+LazyASTImporter &LazyImporterForOrigin(ExternalASTMerger &Merger,
+                                   ASTContext &OriginContext) {
+  return static_cast<LazyASTImporter &>(
+      Merger.ImporterForOrigin(OriginContext));
+}
+}
 
-  auto FilterFoundDecl = [&CompleteDecls, &ForwardDecls](const Candidate &C) {
-    if (IsForwardDeclaration(C.first.get())) {
-      if (!HasDeclOfSameType(ForwardDecls, C)) {
-        ForwardDecls.push_back(C);
+bool ExternalASTMerger::HasImporterForOrigin(ASTContext &OriginContext) {
+  for (const std::unique_ptr<ASTImporter> &I : Importers)
+    if (&I->getFromContext() == &OriginContext)
+      return true;
+  return false;
+}
+
+template <typename CallbackType>
+void ExternalASTMerger::ForEachMatchingDC(const DeclContext *DC,
+                                          CallbackType Callback) {
+  if (Origins.count(DC)) {
+    ExternalASTMerger::DCOrigin Origin = Origins[DC];
+    LazyASTImporter &Importer = LazyImporterForOrigin(*this, *Origin.AST);
+    Callback(Importer, Importer.GetReverse(), Origin.DC);
+  } else {
+    bool DidCallback = false;
+    for (const std::unique_ptr<ASTImporter> &Importer : Importers) {
+      Source<TranslationUnitDecl *> SourceTU =
+          Importer->getFromContext().getTranslationUnitDecl();
+      ASTImporter &Reverse =
+          static_cast<LazyASTImporter *>(Importer.get())->GetReverse();
+      if (auto SourceDC = LookupSameContext(SourceTU, DC, Reverse)) {
+        DidCallback = true;
+        if (Callback(*Importer, Reverse, SourceDC))
+          break;
       }
-    } else {
-      CompleteDecls.push_back(C);
     }
-  };
+    if (!DidCallback && LoggingEnabled())
+      logs() << "(ExternalASTMerger*)" << (void*)this
+             << " asserting for (DeclContext*)" << (void*)DC
+             << ", (ASTContext*)" << (void*)&Target.AST
+             << "\n";
+    assert(DidCallback && "Couldn't find a source context matching our DC");
+  }
+}
+
+void ExternalASTMerger::CompleteType(TagDecl *Tag) {
+  assert(Tag->hasExternalLexicalStorage());
+  ForEachMatchingDC(Tag, [&](ASTImporter &Forward, ASTImporter &Reverse,
+                             Source<const DeclContext *> SourceDC) -> bool {
+    auto *SourceTag = const_cast<TagDecl *>(cast<TagDecl>(SourceDC.get()));
+    if (SourceTag->hasExternalLexicalStorage())
+      SourceTag->getASTContext().getExternalSource()->CompleteType(SourceTag);
+    if (!SourceTag->getDefinition())
+      return false;
+    Forward.Imported(SourceTag, Tag);
+    Forward.ImportDefinition(SourceTag);
+    Tag->setCompleteDefinition(SourceTag->isCompleteDefinition());
+    return true;
+  });
+}
 
+void ExternalASTMerger::CompleteType(ObjCInterfaceDecl *Interface) {
+  assert(Interface->hasExternalLexicalStorage());
   ForEachMatchingDC(
-      DC, Importers,
-      [&](const ImporterPair &IP, Source<const DeclContext *> SourceDC) {
-        DeclarationName FromName = IP.Reverse->Import(Name);
-        DeclContextLookupResult Result = SourceDC.get()->lookup(FromName);
-        for (NamedDecl *FromD : Result) {
-          FilterFoundDecl(std::make_pair(FromD, IP.Forward.get()));
-        }
+      Interface, [&](ASTImporter &Forward, ASTImporter &Reverse,
+                     Source<const DeclContext *> SourceDC) -> bool {
+        auto *SourceInterface = const_cast<ObjCInterfaceDecl *>(
+            cast<ObjCInterfaceDecl>(SourceDC.get()));
+        if (SourceInterface->hasExternalLexicalStorage())
+          SourceInterface->getASTContext().getExternalSource()->CompleteType(
+              SourceInterface);
+        if (!SourceInterface->getDefinition())
+          return false;
+        Forward.Imported(SourceInterface, Interface);
+        Forward.ImportDefinition(SourceInterface);
+        return true;
       });
+}
 
-  llvm::ArrayRef<Candidate> DeclsToReport =
-      CompleteDecls.empty() ? ForwardDecls : CompleteDecls;
+bool ExternalASTMerger::CanComplete(DeclContext *Interface) {
+  assert(Interface->hasExternalLexicalStorage() ||
+         Interface->hasExternalVisibleStorage());
+  bool FoundMatchingDC = false;
+  ForEachMatchingDC(Interface,
+                    [&](ASTImporter &Forward, ASTImporter &Reverse,
+                        Source<const DeclContext *> SourceDC) -> bool {
+                      FoundMatchingDC = true;
+                      return true;
+                    });
+  return FoundMatchingDC;
+}
 
-  if (DeclsToReport.empty()) {
-    return false;
+namespace {
+bool IsSameDC(const DeclContext *D1, const DeclContext *D2) {
+  if (isa<ObjCContainerDecl>(D1) && isa<ObjCContainerDecl>(D2))
+    return true; // There are many cases where Objective-C is ambiguous.
+  if (auto *T1 = dyn_cast<TagDecl>(D1))
+    if (auto *T2 = dyn_cast<TagDecl>(D2))
+      if (T1->getFirstDecl() == T2->getFirstDecl())
+        return true;
+  return D1 == D2 || D1 == CanonicalizeDC(D2);
+}
+}
+
+void ExternalASTMerger::MaybeRecordOrigin(const DeclContext *ToDC,
+                                          DCOrigin Origin) {
+  LazyASTImporter &Importer = LazyImporterForOrigin(*this, *Origin.AST);
+  ASTImporter &Reverse = Importer.GetReverse();
+  Source<const DeclContext *> FoundFromDC =
+      LookupSameContext(Origin.AST->getTranslationUnitDecl(), ToDC, Reverse);
+  const bool DoRecord = !FoundFromDC || !IsSameDC(FoundFromDC.get(), Origin.DC);
+  if (DoRecord)
+    RecordOriginImpl(ToDC, Origin, Importer);
+  if (LoggingEnabled())
+    logs() << "(ExternalASTMerger*)" << (void*)this
+             << (DoRecord ? " decided " : " decided NOT")
+             << " to record origin (DeclContext*)" << (void*)Origin.DC
+             << ", (ASTContext*)" << (void*)&Origin.AST
+             << "\n";
+}
+
+void ExternalASTMerger::ForceRecordOrigin(const DeclContext *ToDC,
+                                          DCOrigin Origin) {
+  RecordOriginImpl(ToDC, Origin, ImporterForOrigin(*Origin.AST));
+}
+
+void ExternalASTMerger::RecordOriginImpl(const DeclContext *ToDC, DCOrigin Origin,
+                                         ASTImporter &Importer) {
+  Origins[ToDC] = Origin;
+  Importer.ASTImporter::Imported(cast<Decl>(Origin.DC), const_cast<Decl*>(cast<Decl>(ToDC)));
+}
+
+ExternalASTMerger::ExternalASTMerger(const ImporterTarget &Target,
+                                     llvm::ArrayRef<ImporterSource> Sources) : LogStream(&llvm::nulls()), Target(Target) {
+  AddSources(Sources);
+}
+
+void ExternalASTMerger::AddSources(llvm::ArrayRef<ImporterSource> Sources) {
+  for (const ImporterSource &S : Sources) {
+    assert(&S.AST != &Target.AST);
+    Importers.push_back(llvm::make_unique<LazyASTImporter>(
+        *this, Target.AST, Target.FM, S.AST, S.FM, S.OM));
+  }
+}
+
+void ExternalASTMerger::RemoveSources(llvm::ArrayRef<ImporterSource> Sources) {
+  if (LoggingEnabled())
+    for (const ImporterSource &S : Sources)
+      logs() << "(ExternalASTMerger*)" << (void*)this
+             << " removing source (ASTContext*)" << (void*)&S.AST
+             << "\n";
+  Importers.erase(
+      std::remove_if(Importers.begin(), Importers.end(),
+                     [&Sources](std::unique_ptr<ASTImporter> &Importer) -> bool {
+                       for (const ImporterSource &S : Sources) {
+                         if (&Importer->getFromContext() == &S.AST)
+                           return true;
+                       }
+                       return false;
+                     }),
+      Importers.end());
+  for (OriginMap::iterator OI = Origins.begin(), OE = Origins.end(); OI != OE; ) {
+    std::pair<const DeclContext *, DCOrigin> Origin = *OI;
+    bool Erase = false;
+    for (const ImporterSource &S : Sources) {
+      if (&S.AST == Origin.second.AST) {
+        Erase = true;
+        break;
+      }
+    }
+    if (Erase)
+      OI = Origins.erase(OI);
+    else
+      ++OI;
   }
+}
+
+bool ExternalASTMerger::FindExternalVisibleDeclsByName(const DeclContext *DC,
+                                                       DeclarationName Name) {
+  llvm::SmallVector<NamedDecl *, 1> Decls;
+  llvm::SmallVector<Candidate, 4> Candidates;
 
-  Decls.reserve(DeclsToReport.size());
-  for (const Candidate &C : DeclsToReport) {
+  auto FilterFoundDecl = [&Candidates](const Candidate &C) {
+   if (!HasDeclOfSameType(Candidates, C))
+     Candidates.push_back(C);
+  };
+
+  ForEachMatchingDC(DC, [&](ASTImporter &Forward, ASTImporter &Reverse,
+                            Source<const DeclContext *> SourceDC) -> bool {
+    DeclarationName FromName = Reverse.Import(Name);
+    DeclContextLookupResult Result = SourceDC.get()->lookup(FromName);
+    for (NamedDecl *FromD : Result) {
+      FilterFoundDecl(std::make_pair(FromD, &Forward));
+    }
+    return false;
+  });
+
+  if (Candidates.empty())
+    return false;
+
+  Decls.reserve(Candidates.size());
+  for (const Candidate &C : Candidates) {
     NamedDecl *d = cast<NamedDecl>(C.second->Import(C.first.get()));
     assert(d);
     Decls.push_back(d);
@@ -170,17 +387,16 @@ bool ExternalASTMerger::FindExternalVisi
 void ExternalASTMerger::FindExternalLexicalDecls(
     const DeclContext *DC, llvm::function_ref<bool(Decl::Kind)> IsKindWeWant,
     SmallVectorImpl<Decl *> &Result) {
-  ForEachMatchingDC(
-      DC, Importers,
-      [&](const ImporterPair &IP, Source<const DeclContext *> SourceDC) {
-        for (const Decl *SourceDecl : SourceDC.get()->decls()) {
-          if (IsKindWeWant(SourceDecl->getKind())) {
-            Decl *ImportedDecl =
-                IP.Forward->Import(const_cast<Decl *>(SourceDecl));
-            assert(ImportedDecl->getDeclContext() == DC);
-            (void)ImportedDecl;
-          }
-        }
-      });
+  ForEachMatchingDC(DC, [&](ASTImporter &Forward, ASTImporter &Reverse,
+                            Source<const DeclContext *> SourceDC) -> bool {
+    for (const Decl *SourceDecl : SourceDC.get()->decls()) {
+      if (IsKindWeWant(SourceDecl->getKind())) {
+        Decl *ImportedDecl = Forward.Import(const_cast<Decl *>(SourceDecl));
+        assert(!ImportedDecl || IsSameDC(ImportedDecl->getDeclContext(), DC));
+        (void)ImportedDecl;
+      }
+    }
+    return false;
+  });
 }
 

Modified: cfe/trunk/lib/Sema/SemaType.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaType.cpp?rev=314336&r1=314335&r2=314336&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaType.cpp (original)
+++ cfe/trunk/lib/Sema/SemaType.cpp Wed Sep 27 12:57:58 2017
@@ -7309,11 +7309,15 @@ bool Sema::RequireCompleteTypeImpl(Sourc
 
     // Give the external AST source a chance to complete the type.
     if (auto *Source = Context.getExternalSource()) {
-      if (Tag)
-        Source->CompleteType(Tag->getDecl());
-      else
-        Source->CompleteType(IFace->getDecl());
-
+      if (Tag) {
+        TagDecl *TagD = Tag->getDecl();
+        if (TagD->hasExternalLexicalStorage())
+          Source->CompleteType(TagD);
+      } else {
+        ObjCInterfaceDecl *IFaceD = IFace->getDecl();
+        if (IFaceD->hasExternalLexicalStorage())
+          Source->CompleteType(IFace->getDecl());
+      }
       // If the external source completed the type, go through the motions
       // again to ensure we're allowed to use the completed type.
       if (!T->isIncompleteType())

Copied: cfe/trunk/test/Import/extern-c-function/Inputs/F.cpp (from r311017, cfe/trunk/test/Import/overloaded-function/Inputs/F1.c)
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Import/extern-c-function/Inputs/F.cpp?p2=cfe/trunk/test/Import/extern-c-function/Inputs/F.cpp&p1=cfe/trunk/test/Import/overloaded-function/Inputs/F1.c&r1=311017&r2=314336&rev=314336&view=diff
==============================================================================
--- cfe/trunk/test/Import/overloaded-function/Inputs/F1.c (original)
+++ cfe/trunk/test/Import/extern-c-function/Inputs/F.cpp Wed Sep 27 12:57:58 2017
@@ -1 +1,3 @@
-void f(int arg) { }
+extern "C" {
+  void f(int arg);
+}

Removed: cfe/trunk/test/Import/extern-c-function/Inputs/F1.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Import/overloaded-function/Inputs/F1.c?rev=311017&view=auto
==============================================================================
--- cfe/trunk/test/Import/extern-c-function/Inputs/F1.c (original)
+++ cfe/trunk/test/Import/extern-c-function/Inputs/F1.c (removed)
@@ -1 +0,0 @@
-void f(int arg) { }

Removed: cfe/trunk/test/Import/extern-c-function/Inputs/F2.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Import/overloaded-function/Inputs/F2.c?rev=311017&view=auto
==============================================================================
--- cfe/trunk/test/Import/extern-c-function/Inputs/F2.c (original)
+++ cfe/trunk/test/Import/extern-c-function/Inputs/F2.c (removed)
@@ -1,4 +0,0 @@
-struct S { int a; };
-
-void f(const char *arg) { }
-void f(S arg) { }

Removed: cfe/trunk/test/Import/extern-c-function/test.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Import/overloaded-function/test.c?rev=311017&view=auto
==============================================================================
--- cfe/trunk/test/Import/extern-c-function/test.c (original)
+++ cfe/trunk/test/Import/extern-c-function/test.c (removed)
@@ -1,7 +0,0 @@
-// RUN: clang-import-test -import %S/Inputs/F1.c -import %S/Inputs/F2.c -expression %s
-void expr() {
-  f(2);
-  f("world");
-  S s;
-  f(s);
-}

Copied: cfe/trunk/test/Import/extern-c-function/test.cpp (from r311017, cfe/trunk/test/Import/overloaded-function/test.c)
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Import/extern-c-function/test.cpp?p2=cfe/trunk/test/Import/extern-c-function/test.cpp&p1=cfe/trunk/test/Import/overloaded-function/test.c&r1=311017&r2=314336&rev=314336&view=diff
==============================================================================
--- cfe/trunk/test/Import/overloaded-function/test.c (original)
+++ cfe/trunk/test/Import/extern-c-function/test.cpp Wed Sep 27 12:57:58 2017
@@ -1,7 +1,4 @@
-// RUN: clang-import-test -import %S/Inputs/F1.c -import %S/Inputs/F2.c -expression %s
+// RUN: clang-import-test -import %S/Inputs/F.cpp -expression %s
 void expr() {
   f(2);
-  f("world");
-  S s;
-  f(s);
-}
+}
\ No newline at end of file

Removed: cfe/trunk/test/Import/forward-declared-objc-class/Inputs/S1.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Import/forward-declared-struct/Inputs/S1.c?rev=311468&view=auto
==============================================================================
--- cfe/trunk/test/Import/forward-declared-objc-class/Inputs/S1.c (original)
+++ cfe/trunk/test/Import/forward-declared-objc-class/Inputs/S1.c (removed)
@@ -1 +0,0 @@
-struct S;

Copied: cfe/trunk/test/Import/forward-declared-objc-class/Inputs/S1.m (from r311468, cfe/trunk/test/Import/forward-declared-struct/Inputs/S1.c)
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Import/forward-declared-objc-class/Inputs/S1.m?p2=cfe/trunk/test/Import/forward-declared-objc-class/Inputs/S1.m&p1=cfe/trunk/test/Import/forward-declared-struct/Inputs/S1.c&r1=311468&r2=314336&rev=314336&view=diff
==============================================================================
--- cfe/trunk/test/Import/forward-declared-struct/Inputs/S1.c (original)
+++ cfe/trunk/test/Import/forward-declared-objc-class/Inputs/S1.m Wed Sep 27 12:57:58 2017
@@ -1 +1 @@
-struct S;
+ at class MyClass;
\ No newline at end of file

Removed: cfe/trunk/test/Import/forward-declared-objc-class/Inputs/S2.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Import/forward-declared-struct/Inputs/S2.c?rev=311468&view=auto
==============================================================================
--- cfe/trunk/test/Import/forward-declared-objc-class/Inputs/S2.c (original)
+++ cfe/trunk/test/Import/forward-declared-objc-class/Inputs/S2.c (removed)
@@ -1,3 +0,0 @@
-struct S {
-  int a;
-};

Copied: cfe/trunk/test/Import/forward-declared-objc-class/Inputs/S2.m (from r311468, cfe/trunk/test/Import/forward-declared-struct/Inputs/S2.c)
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Import/forward-declared-objc-class/Inputs/S2.m?p2=cfe/trunk/test/Import/forward-declared-objc-class/Inputs/S2.m&p1=cfe/trunk/test/Import/forward-declared-struct/Inputs/S2.c&r1=311468&r2=314336&rev=314336&view=diff
==============================================================================
--- cfe/trunk/test/Import/forward-declared-struct/Inputs/S2.c (original)
+++ cfe/trunk/test/Import/forward-declared-objc-class/Inputs/S2.m Wed Sep 27 12:57:58 2017
@@ -1,3 +1,6 @@
-struct S {
-  int a;
+ at interface MyClass {
+  int j;
 };
++(MyClass*)fromInteger:(int)_j;
+-(int)getInteger;
+ at end
\ No newline at end of file

Copied: cfe/trunk/test/Import/forward-declared-objc-class/Inputs/S3.m (from r311468, cfe/trunk/test/Import/forward-declared-struct/Inputs/S1.c)
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Import/forward-declared-objc-class/Inputs/S3.m?p2=cfe/trunk/test/Import/forward-declared-objc-class/Inputs/S3.m&p1=cfe/trunk/test/Import/forward-declared-struct/Inputs/S1.c&r1=311468&r2=314336&rev=314336&view=diff
==============================================================================
--- cfe/trunk/test/Import/forward-declared-struct/Inputs/S1.c (original)
+++ cfe/trunk/test/Import/forward-declared-objc-class/Inputs/S3.m Wed Sep 27 12:57:58 2017
@@ -1 +1 @@
-struct S;
+ at class MyClass;
\ No newline at end of file

Removed: cfe/trunk/test/Import/forward-declared-objc-class/test.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Import/forward-declared-struct/test.c?rev=311468&view=auto
==============================================================================
--- cfe/trunk/test/Import/forward-declared-objc-class/test.c (original)
+++ cfe/trunk/test/Import/forward-declared-objc-class/test.c (removed)
@@ -1,5 +0,0 @@
-// RUN: clang-import-test -import %S/Inputs/S1.c --import %S/Inputs/S2.c -expression %s
-void expr() {
-  struct S MyS;
-  MyS.a = 3;
-}

Copied: cfe/trunk/test/Import/forward-declared-objc-class/test.m (from r311468, cfe/trunk/test/Import/forward-declared-struct/test.c)
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Import/forward-declared-objc-class/test.m?p2=cfe/trunk/test/Import/forward-declared-objc-class/test.m&p1=cfe/trunk/test/Import/forward-declared-struct/test.c&r1=311468&r2=314336&rev=314336&view=diff
==============================================================================
--- cfe/trunk/test/Import/forward-declared-struct/test.c (original)
+++ cfe/trunk/test/Import/forward-declared-objc-class/test.m Wed Sep 27 12:57:58 2017
@@ -1,5 +1,6 @@
-// RUN: clang-import-test -import %S/Inputs/S1.c --import %S/Inputs/S2.c -expression %s
+// RUN: clang-import-test -x objective-c++ -import %S/Inputs/S1.m --import %S/Inputs/S2.m --import %S/Inputs/S3.m -expression %s
 void expr() {
-  struct S MyS;
-  MyS.a = 3;
+  MyClass *c = [MyClass fromInteger:3];
+  const int i = [c getInteger];
+  const int j = c->j;
 }

Modified: cfe/trunk/test/Import/forward-declared-struct/test.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Import/forward-declared-struct/test.c?rev=314336&r1=314335&r2=314336&view=diff
==============================================================================
--- cfe/trunk/test/Import/forward-declared-struct/test.c (original)
+++ cfe/trunk/test/Import/forward-declared-struct/test.c Wed Sep 27 12:57:58 2017
@@ -1,4 +1,4 @@
-// RUN: clang-import-test -import %S/Inputs/S1.c --import %S/Inputs/S2.c -expression %s
+// RUN: clang-import-test -import %S/Inputs/S1.c --import %S/Inputs/S2.c --import %S/Inputs/S3.c -expression %s
 void expr() {
   struct S MyS;
   MyS.a = 3;

Modified: cfe/trunk/test/Import/local-struct-use-origins/test.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Import/local-struct-use-origins/test.cpp?rev=314336&r1=310656&r2=314336&view=diff
==============================================================================
--- cfe/trunk/test/Import/local-struct-use-origins/test.cpp (original)
+++ cfe/trunk/test/Import/local-struct-use-origins/test.cpp Wed Sep 27 12:57:58 2017
@@ -1,7 +1,6 @@
-// RUN: clang-import-test -dump-ir -import %S/Inputs/Callee.cpp -expression %s | FileCheck %s
-// XFAIL: *
+// RUN: clang-import-test -dump-ir -use-origins -import %S/Inputs/Callee.cpp -expression %s | FileCheck %s
 // CHECK: %struct.S = type { i
-// CHECK: %struct.S.0 = type { i1 }
+// CHECK: %struct.S.0 = type { i
 
 void foo() {
   return Bar().bar(3, true);

Modified: cfe/trunk/test/Import/local-struct/test.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Import/local-struct/test.cpp?rev=314336&r1=314335&r2=314336&view=diff
==============================================================================
--- cfe/trunk/test/Import/local-struct/test.cpp (original)
+++ cfe/trunk/test/Import/local-struct/test.cpp Wed Sep 27 12:57:58 2017
@@ -1,7 +1,6 @@
 // RUN: clang-import-test -dump-ir -import %S/Inputs/Callee.cpp -expression %s | FileCheck %s
-// XFAIL: *
 // CHECK: %struct.S = type { i
-// CHECK: %struct.S.0 = type { i1 }
+// CHECK: %struct.S.0 = type { i
 
 void foo() {
   return Bar().bar(3, true);

Modified: cfe/trunk/test/Import/objc-definitions-in-expression/test.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Import/objc-definitions-in-expression/test.m?rev=314336&r1=311468&r2=314336&view=diff
==============================================================================
--- cfe/trunk/test/Import/objc-definitions-in-expression/test.m (original)
+++ cfe/trunk/test/Import/objc-definitions-in-expression/test.m Wed Sep 27 12:57:58 2017
@@ -1,5 +1,21 @@
 // RUN: clang-import-test -x objective-c++ -import %S/Inputs/S.m -expression %s
+ at class D;
+
+ at interface B {
+  int x;
+  int y;
+}
+ at end
+
+ at interface D : B {
+  int z;
+}
+-(int)n;
+ at end
+
 void expr() {
   C *c;
   int i = [c m];
+  D *d;
+  int j = [d n] + d->x;
 }

Modified: cfe/trunk/test/Import/struct-and-var/Inputs/S1.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Import/struct-and-var/Inputs/S1.cpp?rev=314336&r1=310656&r2=314336&view=diff
==============================================================================
--- cfe/trunk/test/Import/struct-and-var/Inputs/S1.cpp (original)
+++ cfe/trunk/test/Import/struct-and-var/Inputs/S1.cpp Wed Sep 27 12:57:58 2017
@@ -1,6 +1 @@
-class T;
-
-class S {
-  T *t;
-  int a;
-};
+int F;

Modified: cfe/trunk/test/Import/struct-and-var/Inputs/S2.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Import/struct-and-var/Inputs/S2.cpp?rev=314336&r1=310656&r2=314336&view=diff
==============================================================================
--- cfe/trunk/test/Import/struct-and-var/Inputs/S2.cpp (original)
+++ cfe/trunk/test/Import/struct-and-var/Inputs/S2.cpp Wed Sep 27 12:57:58 2017
@@ -1,7 +1,3 @@
-class U {
-  int b;
-};
-
-class T {
-  U u;
+struct F {
+  int a;
 };

Modified: cfe/trunk/test/Import/struct-and-var/test.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Import/struct-and-var/test.cpp?rev=314336&r1=310656&r2=314336&view=diff
==============================================================================
--- cfe/trunk/test/Import/struct-and-var/test.cpp (original)
+++ cfe/trunk/test/Import/struct-and-var/test.cpp Wed Sep 27 12:57:58 2017
@@ -1,7 +1,5 @@
 // RUN: clang-import-test --import %S/Inputs/S1.cpp --import %S/Inputs/S2.cpp -expression %s
 void expr() {
-  S MyS;
-  T MyT;
-  MyS.a = 3;
-  MyT.u.b = 2;
+  struct F f;
+  int x = f.a;
 }

Modified: cfe/trunk/test/Import/template/Inputs/T.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Import/template/Inputs/T.cpp?rev=314336&r1=310656&r2=314336&view=diff
==============================================================================
--- cfe/trunk/test/Import/template/Inputs/T.cpp (original)
+++ cfe/trunk/test/Import/template/Inputs/T.cpp Wed Sep 27 12:57:58 2017
@@ -1,14 +1,5 @@
 template <typename T> struct A {
-};
-
-template <> struct A<int> {
-  struct B {
-    int f;
-  };
-};
-
-template <> struct A<bool> {
   struct B {
-    int g;
+    T f;
   };
 };

Modified: cfe/trunk/test/Import/template/test.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Import/template/test.cpp?rev=314336&r1=310656&r2=314336&view=diff
==============================================================================
--- cfe/trunk/test/Import/template/test.cpp (original)
+++ cfe/trunk/test/Import/template/test.cpp Wed Sep 27 12:57:58 2017
@@ -1,7 +1,4 @@
 // RUN: clang-import-test -import %S/Inputs/T.cpp -expression %s
-// XFAIL: *
 void expr() {
-  A<int>::B b1;
-  A<bool>::B b2;
-  b1.f + b2.g;
+  A<int>::B b;
 }

Modified: cfe/trunk/tools/clang-import-test/clang-import-test.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/tools/clang-import-test/clang-import-test.cpp?rev=314336&r1=314335&r2=314336&view=diff
==============================================================================
--- cfe/trunk/tools/clang-import-test/clang-import-test.cpp (original)
+++ cfe/trunk/tools/clang-import-test/clang-import-test.cpp Wed Sep 27 12:57:58 2017
@@ -48,7 +48,11 @@ static llvm::cl::list<std::string>
 
 static llvm::cl::opt<bool>
     Direct("direct", llvm::cl::Optional,
-             llvm::cl::desc("Use the parsed declarations without indirection"));
+           llvm::cl::desc("Use the parsed declarations without indirection"));
+
+static llvm::cl::opt<bool>
+    UseOrigins("use-origins", llvm::cl::Optional,
+           llvm::cl::desc("Use DeclContext origin information for more accurate lookups"));  
 
 static llvm::cl::list<std::string>
     ClangArgs("Xcc", llvm::cl::ZeroOrMore,
@@ -60,13 +64,11 @@ static llvm::cl::opt<std::string>
           llvm::cl::desc("The language to parse (default: c++)"),
           llvm::cl::init("c++"));
 
-static llvm::cl::opt<bool>
-DumpAST("dump-ast", llvm::cl::init(false),
-        llvm::cl::desc("Dump combined AST"));
+static llvm::cl::opt<bool> DumpAST("dump-ast", llvm::cl::init(false),
+                                   llvm::cl::desc("Dump combined AST"));
 
-static llvm::cl::opt<bool>
-DumpIR("dump-ir", llvm::cl::init(false),
-        llvm::cl::desc("Dump IR from final parse"));
+static llvm::cl::opt<bool> DumpIR("dump-ir", llvm::cl::init(false),
+                                  llvm::cl::desc("Dump IR from final parse"));
 
 namespace init_convenience {
 class TestDiagnosticConsumer : public DiagnosticConsumer {
@@ -154,8 +156,7 @@ private:
   }
 };
 
-std::unique_ptr<CompilerInstance>
-BuildCompilerInstance() {
+std::unique_ptr<CompilerInstance> BuildCompilerInstance() {
   auto Ins = llvm::make_unique<CompilerInstance>();
   auto DC = llvm::make_unique<TestDiagnosticConsumer>();
   const bool ShouldOwnClient = true;
@@ -227,29 +228,54 @@ std::unique_ptr<CodeGenerator> BuildCode
 } // end namespace
 
 namespace {
- 
-void AddExternalSource(
-    CompilerInstance &CI,
-    llvm::ArrayRef<std::unique_ptr<CompilerInstance>> Imports) {
-  ExternalASTMerger::ImporterEndpoint Target({CI.getASTContext(), CI.getFileManager()});
-  llvm::SmallVector<ExternalASTMerger::ImporterEndpoint, 3> Sources;
-  for (const std::unique_ptr<CompilerInstance> &CI : Imports) {
-    Sources.push_back({CI->getASTContext(), CI->getFileManager()});
+
+/// A container for a CompilerInstance (possibly with an ExternalASTMerger
+/// attached to its ASTContext).
+///
+/// Provides an accessor for the DeclContext origins associated with the
+/// ExternalASTMerger (or an empty list of origins if no ExternalASTMerger is
+/// attached).
+///
+/// This is the main unit of parsed source code maintained by clang-import-test.
+struct CIAndOrigins {
+  using OriginMap = clang::ExternalASTMerger::OriginMap;
+  std::unique_ptr<CompilerInstance> CI;
+
+  ASTContext &getASTContext() { return CI->getASTContext(); }
+  FileManager &getFileManager() { return CI->getFileManager(); }
+  const OriginMap &getOriginMap() {
+    static const OriginMap EmptyOriginMap;
+    if (ExternalASTSource *Source = CI->getASTContext().getExternalSource())
+      return static_cast<ExternalASTMerger *>(Source)->GetOrigins();
+    return EmptyOriginMap;
+  }
+  DiagnosticConsumer &getDiagnosticClient() {
+    return CI->getDiagnosticClient();
   }
+  CompilerInstance &getCompilerInstance() { return *CI; }
+};
+
+void AddExternalSource(CIAndOrigins &CI,
+                       llvm::MutableArrayRef<CIAndOrigins> Imports) {
+  ExternalASTMerger::ImporterTarget Target(
+      {CI.getASTContext(), CI.getFileManager()});
+  llvm::SmallVector<ExternalASTMerger::ImporterSource, 3> Sources;
+  for (CIAndOrigins &Import : Imports)
+    Sources.push_back(
+        {Import.getASTContext(), Import.getFileManager(), Import.getOriginMap()});
   auto ES = llvm::make_unique<ExternalASTMerger>(Target, Sources);
   CI.getASTContext().setExternalSource(ES.release());
   CI.getASTContext().getTranslationUnitDecl()->setHasExternalVisibleStorage();
 }
 
-std::unique_ptr<CompilerInstance> BuildIndirect(std::unique_ptr<CompilerInstance> &CI) {
-  std::unique_ptr<CompilerInstance> IndirectCI =
-      init_convenience::BuildCompilerInstance();
+CIAndOrigins BuildIndirect(CIAndOrigins &CI) {
+  CIAndOrigins IndirectCI{init_convenience::BuildCompilerInstance()};
   auto ST = llvm::make_unique<SelectorTable>();
   auto BC = llvm::make_unique<Builtin::Context>();
-  std::unique_ptr<ASTContext> AST =
-      init_convenience::BuildASTContext(*IndirectCI, *ST, *BC);
-  IndirectCI->setASTContext(AST.release());
-  AddExternalSource(*IndirectCI, CI);
+  std::unique_ptr<ASTContext> AST = init_convenience::BuildASTContext(
+      IndirectCI.getCompilerInstance(), *ST, *BC);
+  IndirectCI.getCompilerInstance().setASTContext(AST.release());
+  AddExternalSource(IndirectCI, CI);
   return IndirectCI;
 }
 
@@ -266,46 +292,53 @@ llvm::Error ParseSource(const std::strin
   return llvm::Error::success();
 }
 
-llvm::Expected<std::unique_ptr<CompilerInstance>>
-Parse(const std::string &Path,
-      llvm::ArrayRef<std::unique_ptr<CompilerInstance>> Imports,
-      bool ShouldDumpAST, bool ShouldDumpIR) {
-  std::unique_ptr<CompilerInstance> CI =
-      init_convenience::BuildCompilerInstance();
+llvm::Expected<CIAndOrigins> Parse(const std::string &Path,
+                                   llvm::MutableArrayRef<CIAndOrigins> Imports,
+                                   bool ShouldDumpAST, bool ShouldDumpIR) {
+  CIAndOrigins CI{init_convenience::BuildCompilerInstance()};
   auto ST = llvm::make_unique<SelectorTable>();
   auto BC = llvm::make_unique<Builtin::Context>();
   std::unique_ptr<ASTContext> AST =
-      init_convenience::BuildASTContext(*CI, *ST, *BC);
-  CI->setASTContext(AST.release());
+      init_convenience::BuildASTContext(CI.getCompilerInstance(), *ST, *BC);
+  CI.getCompilerInstance().setASTContext(AST.release());
   if (Imports.size())
-    AddExternalSource(*CI, Imports);
+    AddExternalSource(CI, Imports);
 
   std::vector<std::unique_ptr<ASTConsumer>> ASTConsumers;
 
   auto LLVMCtx = llvm::make_unique<llvm::LLVMContext>();
-  ASTConsumers.push_back(init_convenience::BuildCodeGen(*CI, *LLVMCtx));
-  auto &CG = *static_cast<CodeGenerator*>(ASTConsumers.back().get());
+  ASTConsumers.push_back(
+      init_convenience::BuildCodeGen(CI.getCompilerInstance(), *LLVMCtx));
+  auto &CG = *static_cast<CodeGenerator *>(ASTConsumers.back().get());
 
   if (ShouldDumpAST)
     ASTConsumers.push_back(CreateASTDumper("", true, false, false));
 
-  CI->getDiagnosticClient().BeginSourceFile(CI->getLangOpts(),
-                                            &CI->getPreprocessor());
+  CI.getDiagnosticClient().BeginSourceFile(
+      CI.getCompilerInstance().getLangOpts(),
+      &CI.getCompilerInstance().getPreprocessor());
   MultiplexConsumer Consumers(std::move(ASTConsumers));
-  Consumers.Initialize(CI->getASTContext());
+  Consumers.Initialize(CI.getASTContext());
 
-  if (llvm::Error PE = ParseSource(Path, *CI, Consumers)) {
+  if (llvm::Error PE = ParseSource(Path, CI.getCompilerInstance(), Consumers))
     return std::move(PE);
-  }
-  CI->getDiagnosticClient().EndSourceFile();
+  CI.getDiagnosticClient().EndSourceFile();
   if (ShouldDumpIR)
     CG.GetModule()->print(llvm::outs(), nullptr);
-  if (CI->getDiagnosticClient().getNumErrors()) {
+  if (CI.getDiagnosticClient().getNumErrors())
     return llvm::make_error<llvm::StringError>(
         "Errors occured while parsing the expression.", std::error_code());
-  } else {
-    return std::move(CI);
-  }
+  return std::move(CI);
+}
+
+void Forget(CIAndOrigins &CI, llvm::MutableArrayRef<CIAndOrigins> Imports) {
+  llvm::SmallVector<ExternalASTMerger::ImporterSource, 3> Sources;
+  for (CIAndOrigins &Import : Imports)
+    Sources.push_back(
+        {Import.getASTContext(), Import.getFileManager(), Import.getOriginMap()});
+  ExternalASTSource *Source = CI.CI->getASTContext().getExternalSource();
+  auto *Merger = static_cast<ExternalASTMerger *>(Source);
+  Merger->RemoveSources(Sources);
 }
 
 } // end namespace
@@ -314,31 +347,32 @@ int main(int argc, const char **argv) {
   const bool DisableCrashReporting = true;
   llvm::sys::PrintStackTraceOnErrorSignal(argv[0], DisableCrashReporting);
   llvm::cl::ParseCommandLineOptions(argc, argv);
-  std::vector<std::unique_ptr<CompilerInstance>> ImportCIs;
+  std::vector<CIAndOrigins> ImportCIs;
   for (auto I : Imports) {
-    llvm::Expected<std::unique_ptr<CompilerInstance>> ImportCI =
-      Parse(I, {}, false, false);
+    llvm::Expected<CIAndOrigins> ImportCI = Parse(I, {}, false, false);
     if (auto E = ImportCI.takeError()) {
       llvm::errs() << llvm::toString(std::move(E));
       exit(-1);
-    } else {
-      ImportCIs.push_back(std::move(*ImportCI));
     }
+    ImportCIs.push_back(std::move(*ImportCI));
   }
-  std::vector<std::unique_ptr<CompilerInstance>> IndirectCIs;
-  if (!Direct) {
+  std::vector<CIAndOrigins> IndirectCIs;
+  if (!Direct || UseOrigins) {
     for (auto &ImportCI : ImportCIs) {
-      std::unique_ptr<CompilerInstance> IndirectCI = BuildIndirect(ImportCI);
+      CIAndOrigins IndirectCI = BuildIndirect(ImportCI);
       IndirectCIs.push_back(std::move(IndirectCI));
     }
   }
-  llvm::Expected<std::unique_ptr<CompilerInstance>> ExpressionCI =
-      Parse(Expression, Direct ? ImportCIs : IndirectCIs, DumpAST, DumpIR);
+  if (UseOrigins)
+    for (auto &ImportCI : ImportCIs)
+      IndirectCIs.push_back(std::move(ImportCI));
+  llvm::Expected<CIAndOrigins> ExpressionCI =
+      Parse(Expression, (Direct && !UseOrigins) ? ImportCIs : IndirectCIs,
+            DumpAST, DumpIR);
   if (auto E = ExpressionCI.takeError()) {
     llvm::errs() << llvm::toString(std::move(E));
     exit(-1);
-  } else {
-    return 0;
   }
+  Forget(*ExpressionCI, (Direct && !UseOrigins) ? ImportCIs : IndirectCIs);
+  return 0;
 }
-




More information about the cfe-commits mailing list