diff options
author | Richard Smith <richard-llvm@metafoo.co.uk> | 2016-07-14 21:50:09 +0000 |
---|---|---|
committer | Richard Smith <richard-llvm@metafoo.co.uk> | 2016-07-14 21:50:09 +0000 |
commit | 6c35b2dea457cdcf5360d3ff8caf99868f2666c1 (patch) | |
tree | ec3e1fa70c8c40c5f3c0506c21ecda26d951b3d9 /clang/lib/Serialization/ASTReader.cpp | |
parent | 765aa2d1c20f273fac60b12832e76466a92444af (diff) | |
download | bcm5719-llvm-6c35b2dea457cdcf5360d3ff8caf99868f2666c1.tar.gz bcm5719-llvm-6c35b2dea457cdcf5360d3ff8caf99868f2666c1.zip |
[modules] Don't pass interesting decls to the consumer for a module file that's
passed on the command line but never actually used. We consider a (top-level)
module to be used if any part of it is imported, either by the current
translation unit, or by any part of a top-level module that is itself used.
(Put another way, a module is used if an implicit modules build would have
loaded its .pcm file.)
llvm-svn: 275481
Diffstat (limited to 'clang/lib/Serialization/ASTReader.cpp')
-rw-r--r-- | clang/lib/Serialization/ASTReader.cpp | 90 |
1 files changed, 90 insertions, 0 deletions
diff --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp index b35bd7bd329..d4bcdac5989 100644 --- a/clang/lib/Serialization/ASTReader.cpp +++ b/clang/lib/Serialization/ASTReader.cpp @@ -2691,6 +2691,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). + // FIXME: Store this somewhere per-module and defer until + // markModuleReferenced is called. for (unsigned I = 0, N = Record.size(); I != N; ++I) EagerlyDeserializedDecls.push_back(getGlobalDeclID(F, Record[I])); break; @@ -3361,6 +3363,9 @@ void ASTReader::makeNamesVisible(const HiddenNames &Names, Module *Owner) { void ASTReader::makeModuleVisible(Module *Mod, Module::NameVisibilityKind NameVisibility, SourceLocation ImportLoc) { + // If we import anything from the module in any way, then it is used. + markModuleUsed(Mod); + llvm::SmallPtrSet<Module *, 4> Visited; SmallVector<Module *, 4> Stack; Stack.push_back(Mod); @@ -6727,10 +6732,95 @@ void ASTReader::PassInterestingDeclsToConsumer() { Decl *D = InterestingDecls.front(); InterestingDecls.pop_front(); + // If we have found an interesting ImportDecl, then its imported module + // is considered used. + if (auto *ID = dyn_cast<ImportDecl>(D)) + markModuleUsed(ID->getImportedModule()); + PassInterestingDeclToConsumer(D); } } +void ASTReader::markModuleUsed(Module *M) { + M = M->getTopLevelModule(); + // Mark that interesting decls in this module should now be passed to the + // consumer, and pass any pending decls. + auto MInterestingDecls = + UnimportedModuleInterestingDecls.insert(std::make_pair(M, nullptr)).first; + if (auto *Decls = MInterestingDecls->second) { + MInterestingDecls->second = nullptr; + for (auto *D : *Decls) { + Module *Owner = D->getImportedOwningModule(); + if (Owner) + Owner = Owner->getTopLevelModule(); + if (Owner != M) { + // Mark that this decl has been handed to the consumer in its original + // module, and stop if it's already been removed from there. + auto OwnerIt = UnimportedModuleInterestingDecls.find(Owner); + if (OwnerIt == UnimportedModuleInterestingDecls.end() || + !OwnerIt->second) + continue; + auto NewEnd = + std::remove(OwnerIt->second->begin(), OwnerIt->second->end(), D); + if (NewEnd == OwnerIt->second->end()) + continue; + OwnerIt->second->erase(NewEnd, OwnerIt->second->end()); + } + InterestingDecls.push_back(D); + } + } +} + +void ASTReader::addInterestingDecl(Decl *D, + llvm::Optional<Module *> OwnerOverride) { + Module *Owner = D->getImportedOwningModule(); + if (Owner) + Owner = Owner->getTopLevelModule(); + Module *ExportedBy = OwnerOverride ? *OwnerOverride : Owner; + if (ExportedBy) + ExportedBy = ExportedBy->getTopLevelModule(); + + auto It = ExportedBy ? UnimportedModuleInterestingDecls.find(ExportedBy) + : UnimportedModuleInterestingDecls.end(); + if (It == UnimportedModuleInterestingDecls.end()) + It = UnimportedModuleInterestingDecls.insert( + std::make_pair(ExportedBy, new (Context) ModuleInterestingDecls)) + .first; + ModuleInterestingDecls *Interesting = It->second; + + // If this declaration's module has been imported, hand it to the consumer. + if (!ExportedBy || !Interesting) { + if (Owner != ExportedBy) { + // Mark that this decl has been handed to the consumer in its original + // module, and stop if it's already been removed from there. + auto OwnerIt = UnimportedModuleInterestingDecls.find(Owner); + if (OwnerIt == UnimportedModuleInterestingDecls.end() || !OwnerIt->second) + return; + auto NewEnd = + std::remove(OwnerIt->second->begin(), OwnerIt->second->end(), D); + if (NewEnd == OwnerIt->second->end()) + return; + OwnerIt->second->erase(NewEnd, OwnerIt->second->end()); + } + InterestingDecls.push_back(D); + return; + } + assert(Owner && "re-export of unowned decl"); + + // If this is a re-export of another module's decl, check whether the decl + // has already been handed to the consumer. + if (Owner != ExportedBy) { + auto OwnerIt = UnimportedModuleInterestingDecls.find(Owner); + if (OwnerIt != UnimportedModuleInterestingDecls.end() && + (!OwnerIt->second || + std::find(OwnerIt->second->begin(), OwnerIt->second->end(), D) == + OwnerIt->second->end())) + return; + } + + Interesting->push_back(D); +} + void ASTReader::PassInterestingDeclToConsumer(Decl *D) { if (ObjCImplDecl *ImplD = dyn_cast<ObjCImplDecl>(D)) PassObjCImplDeclToConsumer(ImplD, Consumer); |