[modules] Remove redundant import of lexical decls when building a lookup table
authorRichard Smith <richard-llvm@metafoo.co.uk>
Mon, 23 Mar 2015 03:25:59 +0000 (03:25 +0000)
committerRichard Smith <richard-llvm@metafoo.co.uk>
Mon, 23 Mar 2015 03:25:59 +0000 (03:25 +0000)
for a DeclContext, and fix propagation of exception specifications along
redeclaration chains.

This reverts r232905, r232907, and r232907, which reverted r232793, r232853,
and r232853.

One additional change is present here to resolve issues with LLDB: distinguish
between whether lexical decls missing from the lookup table are local or are
provided by the external AST source, and still look in the external source if
that's where they came from.

llvm-svn: 232928

19 files changed:
clang/include/clang/AST/DeclBase.h
clang/include/clang/Serialization/ASTReader.h
clang/lib/AST/ASTContext.cpp
clang/lib/AST/DeclBase.cpp
clang/lib/Sema/IdentifierResolver.cpp
clang/lib/Sema/SemaExceptionSpec.cpp
clang/lib/Sema/SemaLookup.cpp
clang/lib/Serialization/ASTReader.cpp
clang/lib/Serialization/ASTReaderDecl.cpp
clang/lib/Serialization/ASTWriter.cpp
clang/test/Modules/Inputs/update-exception-spec/a.h [new file with mode: 0644]
clang/test/Modules/Inputs/update-exception-spec/b.h [new file with mode: 0644]
clang/test/Modules/Inputs/update-exception-spec/c.h [new file with mode: 0644]
clang/test/Modules/Inputs/update-exception-spec/module.modulemap [new file with mode: 0644]
clang/test/Modules/cxx-templates.cpp
clang/test/Modules/linkage-merge.cpp
clang/test/Modules/odr.cpp
clang/test/Modules/redecl-add-after-load.cpp
clang/test/Modules/update-exception-spec.cpp [new file with mode: 0644]

index 121bd00..7088e4a 100644 (file)
@@ -1096,14 +1096,21 @@ class DeclContext {
   /// another lookup.
   mutable bool NeedToReconcileExternalVisibleStorage : 1;
 
+  /// \brief If \c true, this context may have local lexical declarations
+  /// that are missing from the lookup table.
+  mutable bool HasLazyLocalLexicalLookups : 1;
+
+  /// \brief If \c true, the external source may have lexical declarations
+  /// that are missing from the lookup table.
+  mutable bool HasLazyExternalLexicalLookups : 1;
+
   /// \brief Pointer to the data structure used to lookup declarations
   /// within this context (or a DependentStoredDeclsMap if this is a
-  /// dependent context), and a bool indicating whether we have lazily
-  /// omitted any declarations from the map. We maintain the invariant
-  /// that, if the map contains an entry for a DeclarationName (and we
-  /// haven't lazily omitted anything), then it contains all relevant
-  /// entries for that name.
-  mutable llvm::PointerIntPair<StoredDeclsMap*, 1, bool> LookupPtr;
+  /// dependent context). We maintain the invariant that, if the map
+  /// contains an entry for a DeclarationName (and we haven't lazily
+  /// omitted anything), then it contains all relevant entries for that
+  /// name (modulo the hasExternalDecls() flag).
+  mutable StoredDeclsMap *LookupPtr;
 
 protected:
   /// FirstDecl - The first declaration stored within this declaration
@@ -1129,8 +1136,9 @@ protected:
   DeclContext(Decl::Kind K)
       : DeclKind(K), ExternalLexicalStorage(false),
         ExternalVisibleStorage(false),
-        NeedToReconcileExternalVisibleStorage(false), LookupPtr(nullptr, false),
-        FirstDecl(nullptr), LastDecl(nullptr) {}
+        NeedToReconcileExternalVisibleStorage(false),
+        HasLazyLocalLexicalLookups(false), HasLazyExternalLexicalLookups(false),
+        LookupPtr(nullptr), FirstDecl(nullptr), LastDecl(nullptr) {}
 
 public:
   ~DeclContext();
@@ -1656,17 +1664,22 @@ public:
   inline ddiag_range ddiags() const;
 
   // Low-level accessors
-    
-  /// \brief Mark the lookup table as needing to be built.  This should be
-  /// used only if setHasExternalLexicalStorage() has been called on any
-  /// decl context for which this is the primary context.
+
+  /// \brief Mark that there are external lexical declarations that we need
+  /// to include in our lookup table (and that are not available as external
+  /// visible lookups). These extra lookup results will be found by walking
+  /// the lexical declarations of this context. This should be used only if
+  /// setHasExternalLexicalStorage() has been called on any decl context for
+  /// which this is the primary context.
   void setMustBuildLookupTable() {
-    LookupPtr.setInt(true);
+    assert(this == getPrimaryContext() &&
+           "should only be called on primary context");
+    HasLazyExternalLexicalLookups = true;
   }
 
   /// \brief Retrieve the internal representation of the lookup structure.
   /// This may omit some names if we are lazily building the structure.
-  StoredDeclsMap *getLookupPtr() const { return LookupPtr.getPointer(); }
+  StoredDeclsMap *getLookupPtr() const { return LookupPtr; }
 
   /// \brief Ensure the lookup structure is fully-built and return it.
   StoredDeclsMap *buildLookup();
@@ -1689,7 +1702,7 @@ public:
   /// declarations visible in this context.
   void setHasExternalVisibleStorage(bool ES = true) {
     ExternalVisibleStorage = ES;
-    if (ES && LookupPtr.getPointer())
+    if (ES && LookupPtr)
       NeedToReconcileExternalVisibleStorage = true;
   }
 
@@ -1722,8 +1735,6 @@ private:
   friend class DependentDiagnostic;
   StoredDeclsMap *CreateStoredDeclsMap(ASTContext &C) const;
 
-  template<decl_iterator (DeclContext::*Begin)() const,
-           decl_iterator (DeclContext::*End)() const>
   void buildLookupImpl(DeclContext *DCtx, bool Internal);
   void makeDeclVisibleInContextWithFlags(NamedDecl *D, bool Internal,
                                          bool Rediscoverable);
index 55fe0ef..c631059 100644 (file)
@@ -446,6 +446,12 @@ private:
   /// that we needed but hadn't loaded yet.
   llvm::DenseMap<void *, PendingFakeDefinitionKind> PendingFakeDefinitionData;
 
+  /// \brief Exception specification updates that have been loaded but not yet
+  /// propagated across the relevant redeclaration chain. The map key is the
+  /// canonical declaration (used only for deduplication) and the value is a
+  /// declaration that has an exception specification.
+  llvm::SmallMapVector<Decl *, FunctionDecl *, 4> PendingExceptionSpecUpdates;
+
   struct ReplacedDeclInfo {
     ModuleFile *Mod;
     uint64_t Offset;
@@ -948,6 +954,11 @@ private:
   llvm::MapVector<IdentifierInfo *, SmallVector<uint32_t, 4> >
     PendingIdentifierInfos;
 
+  /// \brief The set of lookup results that we have faked in order to support
+  /// merging of partially deserialized decls but that we have not yet removed.
+  llvm::SmallMapVector<IdentifierInfo *, SmallVector<NamedDecl*, 2>, 16>
+    PendingFakeLookupResults;
+
   /// \brief The generation number of each identifier, which keeps track of
   /// the last time we loaded information about this identifier.
   llvm::DenseMap<IdentifierInfo *, unsigned> IdentifierGeneration;
@@ -1174,6 +1185,18 @@ private:
   /// merged into its redecl chain.
   Decl *getMostRecentExistingDecl(Decl *D);
 
+  template <typename Fn>
+  void forEachFormerlyCanonicalImportedDecl(const Decl *D, Fn Visit) {
+    D = D->getCanonicalDecl();
+    if (D->isFromASTFile())
+      Visit(D);
+
+    auto It = MergedDecls.find(const_cast<Decl*>(D));
+    if (It != MergedDecls.end())
+      for (auto ID : It->second)
+        Visit(GetExistingDecl(ID));
+  }
+
   RecordLocation DeclCursorForID(serialization::DeclID ID,
                                  unsigned &RawLocation);
   void loadDeclUpdateRecords(serialization::DeclID ID, Decl *D);
index 89e1d52..57621a7 100644 (file)
@@ -7946,7 +7946,7 @@ static GVALinkage basicGVALinkageForVariable(const ASTContext &Context,
     while (LexicalContext && !isa<FunctionDecl>(LexicalContext))
       LexicalContext = LexicalContext->getLexicalParent();
 
-    // Let the static local variable inherit it's linkage from the nearest
+    // Let the static local variable inherit its linkage from the nearest
     // enclosing function.
     if (LexicalContext)
       StaticLocalLinkage =
index a8e151c..1f08a64 100644 (file)
@@ -1011,10 +1011,10 @@ DeclContext::BuildDeclChain(ArrayRef<Decl*> Decls,
 /// built a lookup map. For every name in the map, pull in the new names from
 /// the external storage.
 void DeclContext::reconcileExternalVisibleStorage() const {
-  assert(NeedToReconcileExternalVisibleStorage && LookupPtr.getPointer());
+  assert(NeedToReconcileExternalVisibleStorage && LookupPtr);
   NeedToReconcileExternalVisibleStorage = false;
 
-  for (auto &Lookup : *LookupPtr.getPointer())
+  for (auto &Lookup : *LookupPtr)
     Lookup.second.setHasExternalDecls();
 }
 
@@ -1027,10 +1027,13 @@ DeclContext::LoadLexicalDeclsFromExternalStorage() const {
 
   // Notify that we have a DeclContext that is initializing.
   ExternalASTSource::Deserializing ADeclContext(Source);
-  
+
+  ExternalLexicalStorage = false;
+  bool HadLazyExternalLexicalLookups = HasLazyExternalLexicalLookups;
+  HasLazyExternalLexicalLookups = false;
+
   // Load the external declarations, if any.
   SmallVector<Decl*, 64> Decls;
-  ExternalLexicalStorage = false;
   switch (Source->FindExternalLexicalDecls(this, Decls)) {
   case ELR_Success:
     break;
@@ -1043,6 +1046,9 @@ DeclContext::LoadLexicalDeclsFromExternalStorage() const {
   if (Decls.empty())
     return;
 
+  if (HadLazyExternalLexicalLookups)
+    HasLazyLocalLexicalLookups = true;
+
   // We may have already loaded just the fields of this record, in which case
   // we need to ignore them.
   bool FieldsAlreadyLoaded = false;
@@ -1065,7 +1071,7 @@ ExternalASTSource::SetNoExternalVisibleDeclsForName(const DeclContext *DC,
                                                     DeclarationName Name) {
   ASTContext &Context = DC->getParentASTContext();
   StoredDeclsMap *Map;
-  if (!(Map = DC->LookupPtr.getPointer()))
+  if (!(Map = DC->LookupPtr))
     Map = DC->CreateStoredDeclsMap(Context);
   if (DC->NeedToReconcileExternalVisibleStorage)
     DC->reconcileExternalVisibleStorage();
@@ -1081,7 +1087,7 @@ ExternalASTSource::SetExternalVisibleDeclsForName(const DeclContext *DC,
                                                   ArrayRef<NamedDecl*> Decls) {
   ASTContext &Context = DC->getParentASTContext();
   StoredDeclsMap *Map;
-  if (!(Map = DC->LookupPtr.getPointer()))
+  if (!(Map = DC->LookupPtr))
     Map = DC->CreateStoredDeclsMap(Context);
   if (DC->NeedToReconcileExternalVisibleStorage)
     DC->reconcileExternalVisibleStorage();
@@ -1175,7 +1181,7 @@ void DeclContext::removeDecl(Decl *D) {
     // Remove only decls that have a name
     if (!ND->getDeclName()) return;
 
-    StoredDeclsMap *Map = getPrimaryContext()->LookupPtr.getPointer();
+    StoredDeclsMap *Map = getPrimaryContext()->LookupPtr;
     if (!Map) return;
 
     StoredDeclsMap::iterator Pos = Map->find(ND->getDeclName());
@@ -1263,32 +1269,28 @@ static bool shouldBeHidden(NamedDecl *D) {
 StoredDeclsMap *DeclContext::buildLookup() {
   assert(this == getPrimaryContext() && "buildLookup called on non-primary DC");
 
-  // FIXME: Should we keep going if hasExternalVisibleStorage?
-  if (!LookupPtr.getInt())
-    return LookupPtr.getPointer();
+  if (!HasLazyLocalLexicalLookups && !HasLazyExternalLexicalLookups)
+    return LookupPtr;
+
+  if (HasLazyExternalLexicalLookups)
+    LoadLexicalDeclsFromExternalStorage();
 
   SmallVector<DeclContext *, 2> Contexts;
   collectAllContexts(Contexts);
   for (unsigned I = 0, N = Contexts.size(); I != N; ++I)
-    buildLookupImpl<&DeclContext::decls_begin,
-                    &DeclContext::decls_end>(Contexts[I], false);
+    buildLookupImpl(Contexts[I], hasExternalVisibleStorage());
 
   // We no longer have any lazy decls.
-  LookupPtr.setInt(false);
-  return LookupPtr.getPointer();
+  HasLazyLocalLexicalLookups = false;
+  return LookupPtr;
 }
 
 /// buildLookupImpl - Build part of the lookup data structure for the
 /// declarations contained within DCtx, which will either be this
 /// DeclContext, a DeclContext linked to it, or a transparent context
 /// nested within it.
-template<DeclContext::decl_iterator (DeclContext::*Begin)() const,
-         DeclContext::decl_iterator (DeclContext::*End)() const>
 void DeclContext::buildLookupImpl(DeclContext *DCtx, bool Internal) {
-  for (decl_iterator I = (DCtx->*Begin)(), E = (DCtx->*End)();
-       I != E; ++I) {
-    Decl *D = *I;
-
+  for (Decl *D : DCtx->noload_decls()) {
     // Insert this declaration into the lookup structure, but only if
     // it's semantically within its decl context. Any other decls which
     // should be found in this context are added eagerly.
@@ -1309,7 +1311,7 @@ void DeclContext::buildLookupImpl(DeclContext *DCtx, bool Internal) {
     // context (recursively).
     if (DeclContext *InnerCtx = dyn_cast<DeclContext>(D))
       if (InnerCtx->isTransparentContext() || InnerCtx->isInlineNamespace())
-        buildLookupImpl<Begin, End>(InnerCtx, Internal);
+        buildLookupImpl(InnerCtx, Internal);
   }
 }
 
@@ -1337,9 +1339,9 @@ DeclContext::lookup(DeclarationName Name) const {
     if (NeedToReconcileExternalVisibleStorage)
       reconcileExternalVisibleStorage();
 
-    StoredDeclsMap *Map = LookupPtr.getPointer();
+    StoredDeclsMap *Map = LookupPtr;
 
-    if (LookupPtr.getInt())
+    if (HasLazyLocalLexicalLookups || HasLazyExternalLexicalLookups)
       // FIXME: Make buildLookup const?
       Map = const_cast<DeclContext*>(this)->buildLookup();
 
@@ -1353,7 +1355,7 @@ DeclContext::lookup(DeclarationName Name) const {
       return R.first->second.getLookupResult();
 
     if (Source->FindExternalVisibleDeclsByName(this, Name) || !R.second) {
-      if (StoredDeclsMap *Map = LookupPtr.getPointer()) {
+      if (StoredDeclsMap *Map = LookupPtr) {
         StoredDeclsMap::iterator I = Map->find(Name);
         if (I != Map->end())
           return I->second.getLookupResult();
@@ -1363,8 +1365,8 @@ DeclContext::lookup(DeclarationName Name) const {
     return lookup_result();
   }
 
-  StoredDeclsMap *Map = LookupPtr.getPointer();
-  if (LookupPtr.getInt())
+  StoredDeclsMap *Map = LookupPtr;
+  if (HasLazyLocalLexicalLookups || HasLazyExternalLexicalLookups)
     Map = const_cast<DeclContext*>(this)->buildLookup();
 
   if (!Map)
@@ -1388,26 +1390,18 @@ DeclContext::noload_lookup(DeclarationName Name) {
   if (PrimaryContext != this)
     return PrimaryContext->noload_lookup(Name);
 
-  StoredDeclsMap *Map = LookupPtr.getPointer();
-  if (LookupPtr.getInt()) {
-    // Carefully build the lookup map, without deserializing anything.
+  // If we have any lazy lexical declarations not in our lookup map, add them
+  // now. Don't import any external declarations, not even if we know we have
+  // some missing from the external visible lookups.
+  if (HasLazyLocalLexicalLookups) {
     SmallVector<DeclContext *, 2> Contexts;
     collectAllContexts(Contexts);
     for (unsigned I = 0, N = Contexts.size(); I != N; ++I)
-      buildLookupImpl<&DeclContext::noload_decls_begin,
-                      &DeclContext::noload_decls_end>(Contexts[I], true);
-
-    // We no longer have any lazy decls.
-    LookupPtr.setInt(false);
-
-    // There may now be names for which we have local decls but are
-    // missing the external decls. FIXME: Just set the hasExternalDecls
-    // flag on those names that have external decls.
-    NeedToReconcileExternalVisibleStorage = true;
-
-    Map = LookupPtr.getPointer();
+      buildLookupImpl(Contexts[I], hasExternalVisibleStorage());
+    HasLazyLocalLexicalLookups = false;
   }
 
+  StoredDeclsMap *Map = LookupPtr;
   if (!Map)
     return lookup_result();
 
@@ -1429,8 +1423,9 @@ void DeclContext::localUncachedLookup(DeclarationName Name,
   }
 
   // If we have a lookup table, check there first. Maybe we'll get lucky.
-  if (Name && !LookupPtr.getInt()) {
-    if (StoredDeclsMap *Map = LookupPtr.getPointer()) {
+  // FIXME: Should we be checking these flags on the primary context?
+  if (Name && !HasLazyLocalLexicalLookups && !HasLazyExternalLexicalLookups) {
+    if (StoredDeclsMap *Map = LookupPtr) {
       StoredDeclsMap::iterator Pos = Map->find(Name);
       if (Pos != Map->end()) {
         Results.insert(Results.end(),
@@ -1443,6 +1438,8 @@ void DeclContext::localUncachedLookup(DeclarationName Name,
 
   // Slow case: grovel through the declarations in our chain looking for 
   // matches.
+  // FIXME: If we have lazy external declarations, this will not find them!
+  // FIXME: Should we CollectAllContexts and walk them all here?
   for (Decl *D = FirstDecl; D; D = D->getNextDeclInContext()) {
     if (NamedDecl *ND = dyn_cast<NamedDecl>(D))
       if (ND->getDeclName() == Name)
@@ -1523,7 +1520,7 @@ void DeclContext::makeDeclVisibleInContextWithFlags(NamedDecl *D, bool Internal,
   // FIXME: As a performance hack, don't add such decls into the translation
   // unit unless we're in C++, since qualified lookup into the TU is never
   // performed.
-  if (LookupPtr.getPointer() || hasExternalVisibleStorage() ||
+  if (LookupPtr || hasExternalVisibleStorage() ||
       ((!Recoverable || D->getDeclContext() != D->getLexicalDeclContext()) &&
        (getParentASTContext().getLangOpts().CPlusPlus ||
         !isTranslationUnit()))) {
@@ -1533,7 +1530,7 @@ void DeclContext::makeDeclVisibleInContextWithFlags(NamedDecl *D, bool Internal,
     buildLookup();
     makeDeclVisibleInContextImpl(D, Internal);
   } else {
-    LookupPtr.setInt(true);
+    HasLazyLocalLexicalLookups = true;
   }
 
   // If we are a transparent context or inline namespace, insert into our
@@ -1551,7 +1548,7 @@ void DeclContext::makeDeclVisibleInContextWithFlags(NamedDecl *D, bool Internal,
 
 void DeclContext::makeDeclVisibleInContextImpl(NamedDecl *D, bool Internal) {
   // Find or create the stored declaration map.
-  StoredDeclsMap *Map = LookupPtr.getPointer();
+  StoredDeclsMap *Map = LookupPtr;
   if (!Map) {
     ASTContext *C = &getParentASTContext();
     Map = CreateStoredDeclsMap(*C);
@@ -1613,7 +1610,7 @@ DeclContext::udir_range DeclContext::using_directives() const {
 //===----------------------------------------------------------------------===//
 
 StoredDeclsMap *DeclContext::CreateStoredDeclsMap(ASTContext &C) const {
-  assert(!LookupPtr.getPointer() && "context already has a decls map");
+  assert(!LookupPtr && "context already has a decls map");
   assert(getPrimaryContext() == this &&
          "creating decls map on non-primary context");
 
@@ -1625,7 +1622,7 @@ StoredDeclsMap *DeclContext::CreateStoredDeclsMap(ASTContext &C) const {
     M = new StoredDeclsMap();
   M->Previous = C.LastSDM;
   C.LastSDM = llvm::PointerIntPair<StoredDeclsMap*,1>(M, Dependent);
-  LookupPtr.setPointer(M);
+  LookupPtr = M;
   return M;
 }
 
@@ -1657,11 +1654,11 @@ DependentDiagnostic *DependentDiagnostic::Create(ASTContext &C,
   assert(Parent->isDependentContext()
          && "cannot iterate dependent diagnostics of non-dependent context");
   Parent = Parent->getPrimaryContext();
-  if (!Parent->LookupPtr.getPointer())
+  if (!Parent->LookupPtr)
     Parent->CreateStoredDeclsMap(C);
 
-  DependentStoredDeclsMap *Map
-    = static_cast<DependentStoredDeclsMap*>(Parent->LookupPtr.getPointer());
+  DependentStoredDeclsMap *Map =
+      static_cast<DependentStoredDeclsMap *>(Parent->LookupPtr);
 
   // Allocate the copy of the PartialDiagnostic via the ASTContext's
   // BumpPtrAllocator, rather than the ASTContext itself.
index a6efe96..53263ba 100644 (file)
@@ -98,7 +98,7 @@ bool IdentifierResolver::isDeclInScope(Decl *D, DeclContext *Ctx, Scope *S,
                                        bool AllowInlineNamespace) const {
   Ctx = Ctx->getRedeclContext();
 
-  if (Ctx->isFunctionOrMethod() || S->isFunctionPrototypeScope()) {
+  if (Ctx->isFunctionOrMethod() || (S && S->isFunctionPrototypeScope())) {
     // Ignore the scopes associated within transparent declaration contexts.
     while (S->getEntity() && S->getEntity()->isTransparentContext())
       S = S->getParent();
index 41abd49..51d6ace 100644 (file)
@@ -167,13 +167,13 @@ Sema::ResolveExceptionSpec(SourceLocation Loc, const FunctionProtoType *FPT) {
 void
 Sema::UpdateExceptionSpec(FunctionDecl *FD,
                           const FunctionProtoType::ExceptionSpecInfo &ESI) {
-  for (auto *Redecl : FD->redecls())
-    Context.adjustExceptionSpec(cast<FunctionDecl>(Redecl), ESI);
-
   // If we've fully resolved the exception specification, notify listeners.
   if (!isUnresolvedExceptionSpec(ESI.Type))
     if (auto *Listener = getASTMutationListener())
       Listener->ResolvedExceptionSpec(FD);
+
+  for (auto *Redecl : FD->redecls())
+    Context.adjustExceptionSpec(cast<FunctionDecl>(Redecl), ESI);
 }
 
 /// Determine whether a function has an implicitly-generated exception
index e15e532..0b40618 100644 (file)
@@ -3021,17 +3021,45 @@ static void LookupVisibleDecls(DeclContext *Ctx, LookupResult &Result,
   if (Visited.visitedContext(Ctx->getPrimaryContext()))
     return;
 
+  // Outside C++, lookup results for the TU live on identifiers.
+  if (isa<TranslationUnitDecl>(Ctx) &&
+      !Result.getSema().getLangOpts().CPlusPlus) {
+    auto &S = Result.getSema();
+    auto &Idents = S.Context.Idents;
+
+    // Ensure all external identifiers are in the identifier table.
+    if (IdentifierInfoLookup *External = Idents.getExternalIdentifierLookup()) {
+      std::unique_ptr<IdentifierIterator> Iter(External->getIdentifiers());
+      for (StringRef Name = Iter->Next(); !Name.empty(); Name = Iter->Next())
+        Idents.get(Name);
+    }
+
+    // Walk all lookup results in the TU for each identifier.
+    for (const auto &Ident : Idents) {
+      for (auto I = S.IdResolver.begin(Ident.getValue()),
+                E = S.IdResolver.end();
+           I != E; ++I) {
+        if (S.IdResolver.isDeclInScope(*I, Ctx)) {
+          if (NamedDecl *ND = Result.getAcceptableDecl(*I)) {
+            Consumer.FoundDecl(ND, Visited.checkHidden(ND), Ctx, InBaseClass);
+            Visited.add(ND);
+          }
+        }
+      }
+    }
+
+    return;
+  }
+
   if (CXXRecordDecl *Class = dyn_cast<CXXRecordDecl>(Ctx))
     Result.getSema().ForceDeclarationOfImplicitMembers(Class);
 
   // Enumerate all of the results in this context.
   for (const auto &R : Ctx->lookups()) {
-    for (auto *I : R) {
-      if (NamedDecl *ND = dyn_cast<NamedDecl>(I)) {
-        if ((ND = Result.getAcceptableDecl(ND))) {
-          Consumer.FoundDecl(ND, Visited.checkHidden(ND), Ctx, InBaseClass);
-          Visited.add(ND);
-        }
+    for (auto *D : R) {
+      if (auto *ND = Result.getAcceptableDecl(D)) {
+        Consumer.FoundDecl(ND, Visited.checkHidden(ND), Ctx, InBaseClass);
+        Visited.add(ND);
       }
     }
   }
index f4b4c4b..a26f251 100644 (file)
@@ -1,4 +1,4 @@
-//===--- ASTReader.cpp - AST File Reader ----------------------------------===//
+//===-- ASTReader.cpp - AST File Reader ----------------------------------===//
 //
 //                     The LLVM Compiler Infrastructure
 //
@@ -2835,6 +2835,8 @@ ASTReader::ReadASTBlock(ModuleFile &F, unsigned ClientLoadCapabilities) {
     }
 
     case EAGERLY_DESERIALIZED_DECLS:
+      // FIXME: Skip reading this record if our ASTConsumer doesn't care
+      // about "interesting" decls (for instance, if we're building a module).
       for (unsigned I = 0, N = Record.size(); I != N; ++I)
         EagerlyDeserializedDecls.push_back(getGlobalDeclID(F, Record[I]));
       break;
@@ -6832,6 +6834,12 @@ void ASTReader::PassInterestingDeclsToConsumer() {
   SaveAndRestore<bool> GuardPassingDeclsToConsumer(PassingDeclsToConsumer,
                                                    true);
 
+  // Ensure that we've loaded all potentially-interesting declarations
+  // that need to be eagerly loaded.
+  for (auto ID : EagerlyDeserializedDecls)
+    GetDecl(ID);
+  EagerlyDeserializedDecls.clear();
+
   while (!InterestingDecls.empty()) {
     Decl *D = InterestingDecls.front();
     InterestingDecls.pop_front();
@@ -6850,17 +6858,8 @@ void ASTReader::PassInterestingDeclToConsumer(Decl *D) {
 void ASTReader::StartTranslationUnit(ASTConsumer *Consumer) {
   this->Consumer = Consumer;
 
-  if (!Consumer)
-    return;
-
-  for (unsigned I = 0, N = EagerlyDeserializedDecls.size(); I != N; ++I) {
-    // Force deserialization of this decl, which will cause it to be queued for
-    // passing to the consumer.
-    GetDecl(EagerlyDeserializedDecls[I]);
-  }
-  EagerlyDeserializedDecls.clear();
-
-  PassInterestingDeclsToConsumer();
+  if (Consumer)
+    PassInterestingDeclsToConsumer();
 
   if (DeserializationListener)
     DeserializationListener->ReaderInitialized(this);
@@ -8618,6 +8617,13 @@ void ASTReader::FinishedDeserializing() {
   --NumCurrentElementsDeserializing;
 
   if (NumCurrentElementsDeserializing == 0) {
+    // Propagate exception specification updates along redeclaration chains.
+    for (auto Update : PendingExceptionSpecUpdates) {
+      auto *FPT = Update.second->getType()->castAs<FunctionProtoType>();
+      SemaObj->UpdateExceptionSpec(Update.second,
+                                   FPT->getExtProtoInfo().ExceptionSpec);
+    }
+
     diagnoseOdrViolations();
 
     // We are not in recursive loading, so it's safe to pass the "interesting"
@@ -8628,7 +8634,15 @@ void ASTReader::FinishedDeserializing() {
 }
 
 void ASTReader::pushExternalDeclIntoScope(NamedDecl *D, DeclarationName Name) {
-  D = D->getMostRecentDecl();
+  if (IdentifierInfo *II = Name.getAsIdentifierInfo()) {
+    // Remove any fake results before adding any real ones.
+    auto It = PendingFakeLookupResults.find(II);
+    if (It != PendingFakeLookupResults.end()) {
+      for (auto *ND : PendingFakeLookupResults[II])
+        SemaObj->IdResolver.RemoveDecl(ND);
+      PendingFakeLookupResults.erase(It);
+    }
+  }
 
   if (SemaObj->IdResolver.tryAddTopLevelDecl(D, Name) && SemaObj->TUScope) {
     SemaObj->TUScope->AddDecl(D);
index 83882a8..5c6820f 100644 (file)
@@ -228,9 +228,11 @@ namespace clang {
 
     template <typename DeclT>
     static void attachPreviousDeclImpl(ASTReader &Reader,
-                                       Redeclarable<DeclT> *D, Decl *Previous);
+                                       Redeclarable<DeclT> *D, Decl *Previous,
+                                       Decl *Canon);
     static void attachPreviousDeclImpl(ASTReader &Reader, ...);
-    static void attachPreviousDecl(ASTReader &Reader, Decl *D, Decl *Previous);
+    static void attachPreviousDecl(ASTReader &Reader, Decl *D, Decl *Previous,
+                                   Decl *Canon);
 
     template <typename DeclT>
     static void attachLatestDeclImpl(Redeclarable<DeclT> *D, Decl *Latest);
@@ -2621,8 +2623,11 @@ ASTDeclReader::FindExistingResult::~FindExistingResult() {
   if (needsAnonymousDeclarationNumber(New)) {
     setAnonymousDeclForMerging(Reader, New->getLexicalDeclContext(),
                                AnonymousDeclNumber, New);
-  } else if (DC->isTranslationUnit() && Reader.SemaObj) {
-    Reader.SemaObj->IdResolver.tryAddTopLevelDecl(New, Name);
+  } else if (DC->isTranslationUnit() && Reader.SemaObj &&
+             !Reader.getContext().getLangOpts().CPlusPlus) {
+    if (Reader.SemaObj->IdResolver.tryAddTopLevelDecl(New, Name))
+      Reader.PendingFakeLookupResults[Name.getAsIdentifierInfo()]
+            .push_back(New);
   } else if (DeclContext *MergeDC = getPrimaryContextForMerging(Reader, DC)) {
     // Add the declaration to its redeclaration context so later merging
     // lookups will find it.
@@ -2727,7 +2732,8 @@ ASTDeclReader::FindExistingResult ASTDeclReader::findExisting(NamedDecl *D) {
       if (isSameEntity(Existing, D))
         return FindExistingResult(Reader, D, Existing, AnonymousDeclNumber,
                                   TypedefNameForLinkage);
-  } else if (DC->isTranslationUnit() && Reader.SemaObj) {
+  } else if (DC->isTranslationUnit() && Reader.SemaObj &&
+             !Reader.getContext().getLangOpts().CPlusPlus) {
     IdentifierResolver &IdResolver = Reader.SemaObj->IdResolver;
 
     // Temporarily consider the identifier to be up-to-date. We don't want to
@@ -2816,14 +2822,14 @@ Decl *ASTReader::getMostRecentExistingDecl(Decl *D) {
 template<typename DeclT>
 void ASTDeclReader::attachPreviousDeclImpl(ASTReader &Reader,
                                            Redeclarable<DeclT> *D,
-                                           Decl *Previous) {
+                                           Decl *Previous, Decl *Canon) {
   D->RedeclLink.setPrevious(cast<DeclT>(Previous));
 }
 namespace clang {
 template<>
 void ASTDeclReader::attachPreviousDeclImpl(ASTReader &Reader,
                                            Redeclarable<FunctionDecl> *D,
-                                           Decl *Previous) {
+                                           Decl *Previous, Decl *Canon) {
   FunctionDecl *FD = static_cast<FunctionDecl*>(D);
   FunctionDecl *PrevFD = cast<FunctionDecl>(Previous);
 
@@ -2850,25 +2856,17 @@ void ASTDeclReader::attachPreviousDeclImpl(ASTReader &Reader,
     FD->IsInline = true;
   }
 
-  // If this declaration has an unresolved exception specification but the
-  // previous declaration had a resolved one, resolve the exception
-  // specification now. If this declaration has a resolved exception
-  // specification but the previous declarations did not, apply our exception
-  // specification to all prior ones now.
+  // If we need to propagate an exception specification along the redecl
+  // chain, make a note of that so that we can do so later.
   auto *FPT = FD->getType()->getAs<FunctionProtoType>();
   auto *PrevFPT = PrevFD->getType()->getAs<FunctionProtoType>();
   if (FPT && PrevFPT) {
-    bool WasUnresolved = isUnresolvedExceptionSpec(FPT->getExceptionSpecType());
-    bool IsUnresolved = isUnresolvedExceptionSpec(PrevFPT->getExceptionSpecType());
-    if (WasUnresolved && !IsUnresolved) {
-      Reader.Context.adjustExceptionSpec(
-          FD, PrevFPT->getExtProtoInfo().ExceptionSpec);
-    } else if (!WasUnresolved && IsUnresolved) {
-      FunctionProtoType::ExtProtoInfo EPI = FPT->getExtProtoInfo();
-      for (FunctionDecl *PrevFDToUpdate = PrevFD; PrevFDToUpdate;
-           PrevFDToUpdate = PrevFDToUpdate->getPreviousDecl())
-         Reader.Context.adjustExceptionSpec(PrevFDToUpdate, EPI.ExceptionSpec);
-    }
+    bool IsUnresolved = isUnresolvedExceptionSpec(FPT->getExceptionSpecType());
+    bool WasUnresolved =
+        isUnresolvedExceptionSpec(PrevFPT->getExceptionSpecType());
+    if (IsUnresolved != WasUnresolved)
+      Reader.PendingExceptionSpecUpdates.insert(
+          std::make_pair(Canon, IsUnresolved ? PrevFD : FD));
   }
 }
 }
@@ -2877,14 +2875,14 @@ void ASTDeclReader::attachPreviousDeclImpl(ASTReader &Reader, ...) {
 }
 
 void ASTDeclReader::attachPreviousDecl(ASTReader &Reader, Decl *D,
-                                       Decl *Previous) {
+                                       Decl *Previous, Decl *Canon) {
   assert(D && Previous);
 
   switch (D->getKind()) {
 #define ABSTRACT_DECL(TYPE)
-#define DECL(TYPE, BASE)                                           \
-  case Decl::TYPE:                                                 \
-    attachPreviousDeclImpl(Reader, cast<TYPE##Decl>(D), Previous); \
+#define DECL(TYPE, BASE)                                                  \
+  case Decl::TYPE:                                                        \
+    attachPreviousDeclImpl(Reader, cast<TYPE##Decl>(D), Previous, Canon); \
     break;
 #include "clang/AST/DeclNodes.inc"
   }
@@ -3388,7 +3386,7 @@ void ASTReader::loadPendingDeclChain(Decl *CanonDecl) {
     if (Chain[I] == CanonDecl)
       continue;
 
-    ASTDeclReader::attachPreviousDecl(*this, Chain[I], MostRecent);
+    ASTDeclReader::attachPreviousDecl(*this, Chain[I], MostRecent, CanonDecl);
     MostRecent = Chain[I];
   }
   ASTDeclReader::attachLatestDecl(CanonDecl, MostRecent);
@@ -3732,23 +3730,24 @@ void ASTDeclReader::UpdateDecl(Decl *D, ModuleFile &ModuleFile,
     }
 
     case UPD_CXX_RESOLVED_EXCEPTION_SPEC: {
-      // FIXME: This doesn't send the right notifications if there are
-      // ASTMutationListeners other than an ASTWriter.
       FunctionProtoType::ExceptionSpecInfo ESI;
       SmallVector<QualType, 8> ExceptionStorage;
       Reader.readExceptionSpec(ModuleFile, ExceptionStorage, ESI, Record, Idx);
-      for (auto *Redecl : merged_redecls(D)) {
-        auto *FD = cast<FunctionDecl>(Redecl);
-        auto *FPT = FD->getType()->castAs<FunctionProtoType>();
-        if (!isUnresolvedExceptionSpec(FPT->getExceptionSpecType())) {
-          // AST invariant: if any exception spec in the redecl chain is
-          // resolved, all are resolved. We don't need to go any further.
-          // FIXME: If the exception spec is resolved, check that it matches.
-          break;
-        }
+
+      // Update this declaration's exception specification, if needed.
+      auto *FD = cast<FunctionDecl>(D);
+      auto *FPT = FD->getType()->castAs<FunctionProtoType>();
+      // FIXME: If the exception specification is already present, check that it
+      // matches.
+      if (isUnresolvedExceptionSpec(FPT->getExceptionSpecType())) {
         FD->setType(Reader.Context.getFunctionType(
             FPT->getReturnType(), FPT->getParamTypes(),
             FPT->getExtProtoInfo().withExceptionSpec(ESI)));
+
+        // When we get to the end of deserializing, see if there are other decls
+        // that we need to propagate this exception specification onto.
+        Reader.PendingExceptionSpecUpdates.insert(
+            std::make_pair(FD->getCanonicalDecl(), FD));
       }
       break;
     }
index a8e92b8..e992685 100644 (file)
@@ -3731,7 +3731,9 @@ void ASTWriter::AddUpdatedDeclContext(const DeclContext *DC) {
 uint32_t
 ASTWriter::GenerateNameLookupTable(const DeclContext *DC,
                                    llvm::SmallVectorImpl<char> &LookupTable) {
-  assert(!DC->LookupPtr.getInt() && "must call buildLookups first");
+  assert(!DC->HasLazyLocalLexicalLookups &&
+         !DC->HasLazyExternalLexicalLookups &&
+         "must call buildLookups first");
 
   llvm::OnDiskChainedHashTableGenerator<ASTDeclContextNameLookupTrait>
       Generator;
@@ -5804,37 +5806,36 @@ void ASTWriter::AddedCXXTemplateSpecialization(const FunctionTemplateDecl *TD,
 }
 
 void ASTWriter::ResolvedExceptionSpec(const FunctionDecl *FD) {
-  assert(!WritingAST && "Already writing the AST!");
-  FD = FD->getCanonicalDecl();
-  if (!FD->isFromASTFile())
-    return; // Not a function declared in PCH and defined outside.
-
-  DeclUpdates[FD].push_back(UPD_CXX_RESOLVED_EXCEPTION_SPEC);
+  assert(!DoneWritingDeclsAndTypes && "Already done writing updates!");
+  if (!Chain) return;
+  Chain->forEachFormerlyCanonicalImportedDecl(FD, [&](const Decl *D) {
+    // If we don't already know the exception specification for this redecl
+    // chain, add an update record for it.
+    if (isUnresolvedExceptionSpec(cast<FunctionDecl>(D)
+                                      ->getType()
+                                      ->castAs<FunctionProtoType>()
+                                      ->getExceptionSpecType()))
+      DeclUpdates[D].push_back(UPD_CXX_RESOLVED_EXCEPTION_SPEC);
+  });
 }
 
 void ASTWriter::DeducedReturnType(const FunctionDecl *FD, QualType ReturnType) {
   assert(!WritingAST && "Already writing the AST!");
-  FD = FD->getCanonicalDecl();
-  if (!FD->isFromASTFile())
-    return; // Not a function declared in PCH and defined outside.
-
-  DeclUpdates[FD].push_back(DeclUpdate(UPD_CXX_DEDUCED_RETURN_TYPE, ReturnType));
+  if (!Chain) return;
+  Chain->forEachFormerlyCanonicalImportedDecl(FD, [&](const Decl *D) {
+    DeclUpdates[D].push_back(
+        DeclUpdate(UPD_CXX_DEDUCED_RETURN_TYPE, ReturnType));
+  });
 }
 
 void ASTWriter::ResolvedOperatorDelete(const CXXDestructorDecl *DD,
                                        const FunctionDecl *Delete) {
   assert(!WritingAST && "Already writing the AST!");
   assert(Delete && "Not given an operator delete");
-  for (auto *D : DD->redecls()) {
-    if (D->isFromASTFile()) {
-      // We added an operator delete that some imported destructor didn't
-      // know about. Add an update record to let importers of us and that
-      // declaration know about it.
-      DeclUpdates[DD].push_back(
-          DeclUpdate(UPD_CXX_RESOLVED_DTOR_DELETE, Delete));
-      return;
-    }
-  }
+  if (!Chain) return;
+  Chain->forEachFormerlyCanonicalImportedDecl(DD, [&](const Decl *D) {
+    DeclUpdates[D].push_back(DeclUpdate(UPD_CXX_RESOLVED_DTOR_DELETE, Delete));
+  });
 }
 
 void ASTWriter::CompletedImplicitDefinition(const FunctionDecl *D) {
@@ -5851,8 +5852,7 @@ void ASTWriter::FunctionDefinitionInstantiated(const FunctionDecl *D) {
   if (!D->isFromASTFile())
     return;
 
-  DeclUpdates[D].push_back(
-      DeclUpdate(UPD_CXX_ADDED_FUNCTION_DEFINITION));
+  DeclUpdates[D].push_back(DeclUpdate(UPD_CXX_ADDED_FUNCTION_DEFINITION));
 }
 
 void ASTWriter::StaticDataMemberInstantiated(const VarDecl *D) {
diff --git a/clang/test/Modules/Inputs/update-exception-spec/a.h b/clang/test/Modules/Inputs/update-exception-spec/a.h
new file mode 100644 (file)
index 0000000..078ebf9
--- /dev/null
@@ -0,0 +1,2 @@
+struct A { ~A() throw(int); };
+struct B { A a; };
diff --git a/clang/test/Modules/Inputs/update-exception-spec/b.h b/clang/test/Modules/Inputs/update-exception-spec/b.h
new file mode 100644 (file)
index 0000000..f75b559
--- /dev/null
@@ -0,0 +1,3 @@
+struct A { ~A() throw(int); };
+struct B { A a; };
+inline void f(B *p) { p->~B(); }
diff --git a/clang/test/Modules/Inputs/update-exception-spec/c.h b/clang/test/Modules/Inputs/update-exception-spec/c.h
new file mode 100644 (file)
index 0000000..067dbb6
--- /dev/null
@@ -0,0 +1,3 @@
+#include "a.h"
+#include "b.h"
+inline void g(B *p) { p->~B(); }
diff --git a/clang/test/Modules/Inputs/update-exception-spec/module.modulemap b/clang/test/Modules/Inputs/update-exception-spec/module.modulemap
new file mode 100644 (file)
index 0000000..880ae38
--- /dev/null
@@ -0,0 +1,3 @@
+module a { header "a.h" }
+module b { header "b.h" }
+module c { header "c.h" }
index 46c2f33..41b0f2c 100644 (file)
@@ -1,7 +1,7 @@
 // RUN: rm -rf %t
 // RUN: not %clang_cc1 -x objective-c++ -fmodules -fno-modules-error-recovery -fmodules-cache-path=%t -I %S/Inputs %s -std=c++11 -ast-dump-lookups | FileCheck %s --check-prefix=CHECK-GLOBAL
 // RUN: not %clang_cc1 -x objective-c++ -fmodules -fno-modules-error-recovery -fmodules-cache-path=%t -I %S/Inputs %s -std=c++11 -ast-dump-lookups -ast-dump-filter N | FileCheck %s --check-prefix=CHECK-NAMESPACE-N
-// RUN: not %clang_cc1 -x objective-c++ -fmodules -fno-modules-error-recovery -fmodules-cache-path=%t -I %S/Inputs %s -std=c++11 -ast-dump | FileCheck %s --check-prefix=CHECK-DUMP
+// RUN: not %clang_cc1 -x objective-c++ -fmodules -fno-modules-error-recovery -fmodules-cache-path=%t -I %S/Inputs %s -std=c++11 -ast-dump -ast-dump-filter SomeTemplate | FileCheck %s --check-prefix=CHECK-DUMP
 // RUN: %clang_cc1 -x objective-c++ -fmodules -fno-modules-error-recovery -fmodules-cache-path=%t -I %S/Inputs %s -verify -std=c++11
 // RUN: %clang_cc1 -x objective-c++ -fmodules -fno-modules-error-recovery -fmodules-cache-path=%t -I %S/Inputs %s -verify -std=c++11 -DEARLY_IMPORT
 
@@ -125,9 +125,10 @@ void g() {
 static_assert(Outer<int>::Inner<int>::f() == 1, "");
 static_assert(Outer<int>::Inner<int>::g() == 2, "");
 
-#ifndef EARLY_IMPORT
-// FIXME: The textual inclusion above shouldn't cause this to fail!
-static_assert(MergeTemplateDefinitions<int>::f() == 1, "");
+// FIXME: We're too lazy in merging class definitions to find the definition
+// of this function.
+static_assert(MergeTemplateDefinitions<int>::f() == 1, ""); // expected-error {{constant expression}} expected-note {{undefined}}
+// expected-note@cxx-templates-c.h:10 {{here}}
 static_assert(MergeTemplateDefinitions<int>::g() == 2, "");
 
 RedeclaredAsFriend<int> raf1;
@@ -140,7 +141,6 @@ MergeSpecializations<int[]>::partially_specialized_in_c spec_in_c_1;
 MergeSpecializations<char>::explicitly_specialized_in_a spec_in_a_2;
 MergeSpecializations<double>::explicitly_specialized_in_b spec_in_b_2;
 MergeSpecializations<bool>::explicitly_specialized_in_c spec_in_c_2;
-#endif
 
 MergeAnonUnionMember<> maum_main;
 typedef DontWalkPreviousDeclAfterMerging<int> dwpdam_typedef_2;
index 9991789..3ac8053 100644 (file)
@@ -11,6 +11,5 @@ static void g(int);
 // happen to find lookup results for 'g'; LookupResult::resolveKind needs to
 // be taught to prefer a visible result over a non-visible one.
 //
-// FIXME-error@-1 {{functions that differ only in their return type cannot be overloaded}}
-// FIXME-note@Inputs/linkage-merge-foo.h:2 {{previous declaration is here}}
-// expected-no-diagnostics
+// expected-error@9 {{functions that differ only in their return type cannot be overloaded}}
+// expected-note@Inputs/linkage-merge-foo.h:2 {{previous declaration is here}}
index 120ca20..4ac257c 100644 (file)
@@ -15,9 +15,9 @@ bool b = F<int>{0} == F<int>{1};
 int x = f() + g();
 
 // expected-note@a.h:5 {{definition has no member 'e2'}}
-// expected-note@a.h:3 {{declaration of 'f' does not match}}
-// expected-note@a.h:1 {{definition has no member 'm'}}
+// expected-note@b.h:3 {{declaration of 'f' does not match}}
+// expected-note@b.h:1 {{definition has no member 'n'}}
 
 // expected-error@b.h:5 {{'E::e2' from module 'b' is not present in definition of 'E' in module 'a'}}
-// expected-error@b.h:3 {{'Y::f' from module 'b' is not present in definition of 'Y' in module 'a'}}
-// expected-error@b.h:2 {{'Y::m' from module 'b' is not present in definition of 'Y' in module 'a'}}
+// expected-error@a.h:3 {{'Y::f' from module 'a' is not present in definition of 'Y' in module 'b'}}
+// expected-error@a.h:2 {{'Y::n' from module 'a' is not present in definition of 'Y' in module 'b'}}
index 68deaf8..53e54c8 100644 (file)
@@ -29,7 +29,7 @@ struct D {
   static constexpr int function(); // expected-note {{here}}
 };
 typedef D::A DB;
-constexpr int D_test(bool b) { return b ? D::variable : D::function(); } // expected-note {{subexpression}} expected-note {{undefined}}
+constexpr int D_test(bool b) { return b ? D::variable : D::function(); } // expected-note {{undefined}}
 #endif
 
 @import redecl_add_after_load;
@@ -54,6 +54,6 @@ constexpr int merged_struct_variable_test = D_test(true);
 constexpr int merged_struct_function_test = D_test(false);
 #ifndef IMPORT_DECLS
 // expected-error@-4 {{incomplete}}
-// expected-error@-4 {{constant}} expected-note@-4 {{in call to}}
+// @-4: definition of D::variable must be emitted, so it gets imported eagerly
 // expected-error@-4 {{constant}} expected-note@-4 {{in call to}}
 #endif
diff --git a/clang/test/Modules/update-exception-spec.cpp b/clang/test/Modules/update-exception-spec.cpp
new file mode 100644 (file)
index 0000000..bccdddc
--- /dev/null
@@ -0,0 +1,6 @@
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -fexceptions -fcxx-exceptions -fmodules -fmodules-cache-path=%t -I%S/Inputs/update-exception-spec -emit-llvm-only %s
+#include "a.h"
+void use(B *p);
+#include "c.h"
+void use(B *p) { g(p); }