[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
diff --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp
index b35bd7b..d4bcdac 100644
--- a/clang/lib/Serialization/ASTReader.cpp
+++ b/clang/lib/Serialization/ASTReader.cpp
@@ -2691,6 +2691,8 @@
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::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 @@
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);
diff --git a/clang/lib/Serialization/ASTReaderDecl.cpp b/clang/lib/Serialization/ASTReaderDecl.cpp
index 5442399..21db402 100644
--- a/clang/lib/Serialization/ASTReaderDecl.cpp
+++ b/clang/lib/Serialization/ASTReaderDecl.cpp
@@ -3462,6 +3462,13 @@
}
assert(Idx == Record.size());
+ // If we have deserialized a declaration that has a definition the
+ // AST consumer might need to know about, queue it.
+ // We don't pass it to the consumer immediately because we may be in recursive
+ // loading, and some declarations may still be initializing.
+ if (isConsumerInterestedIn(D, Reader.hasPendingBody()))
+ addInterestingDecl(D);
+
// Load any relevant update records.
PendingUpdateRecords.push_back(std::make_pair(ID, D));
@@ -3470,13 +3477,6 @@
if (Class->isThisDeclarationADefinition())
loadObjCCategories(ID, Class);
- // If we have deserialized a declaration that has a definition the
- // AST consumer might need to know about, queue it.
- // We don't pass it to the consumer immediately because we may be in recursive
- // loading, and some declarations may still be initializing.
- if (isConsumerInterestedIn(D, Reader.hasPendingBody()))
- InterestingDecls.push_back(D);
-
return D;
}
@@ -3511,7 +3511,7 @@
// we need to hand it off to the consumer.
if (!WasInteresting &&
isConsumerInterestedIn(D, Reader.hasPendingBody())) {
- InterestingDecls.push_back(D);
+ addInterestingDecl(D);
WasInteresting = true;
}
}
@@ -3945,6 +3945,7 @@
// The declaration is now visible.
Exported->Hidden = false;
}
+ Reader.addInterestingDecl(Exported, Owner);
break;
}
diff --git a/clang/lib/Serialization/ASTWriterDecl.cpp b/clang/lib/Serialization/ASTWriterDecl.cpp
index 0940dd2..6bc7d72 100644
--- a/clang/lib/Serialization/ASTWriterDecl.cpp
+++ b/clang/lib/Serialization/ASTWriterDecl.cpp
@@ -2124,7 +2124,7 @@
// ImportDecl is used by codegen to determine the set of imported modules to
// search for inputs for automatic linking; include it if it has a semantic
// effect.
- if (isa<ImportDecl>(D) && !WritingModule)
+ if (isa<ImportDecl>(D))
return true;
return Context.DeclMustBeEmitted(D);