summaryrefslogtreecommitdiffstats
path: root/clang/lib/Serialization/ASTReader.cpp
diff options
context:
space:
mode:
authorRichard Smith <richard-llvm@metafoo.co.uk>2016-07-14 21:50:09 +0000
committerRichard Smith <richard-llvm@metafoo.co.uk>2016-07-14 21:50:09 +0000
commit6c35b2dea457cdcf5360d3ff8caf99868f2666c1 (patch)
treeec3e1fa70c8c40c5f3c0506c21ecda26d951b3d9 /clang/lib/Serialization/ASTReader.cpp
parent765aa2d1c20f273fac60b12832e76466a92444af (diff)
downloadbcm5719-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.cpp90
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);
OpenPOWER on IntegriCloud