Repair Fingerprint Lookup Across Modules

Cross-module incremental builds require a stable source of fingerprint
information for iterable decl contexts. This is provided by the
incremental frontends when they produce partial swift module files.
Embedded in these files is a table of fingerprints, which are consumed
by merge-modules to construct a module-wide dependency graph that is
then serialized into the final merged swift module file. Unfortunately,
the implementation here iterated through the files in the module and
asked for the first fingerprint that would load for a particular
iterable decl context. If (more likely, when) the DeclID for that
serialized iterable decl context collided with another DeclID in the
wrong file, we would load that fingerprint instead.

Locate up to the module-scope context for an iterable decl context and
only load the fingerprint from there. This ensures that the fingerprints
in the partial modules matches the fingerprints in the merged modules.

rdar://77005039
This commit is contained in:
Robert Widmann
2021-04-27 17:44:55 -07:00
parent 5900a0fdac
commit 43a9f54b0f
6 changed files with 45 additions and 14 deletions

View File

@@ -52,6 +52,8 @@ ParseMembersRequest::evaluate(Evaluator &evaluator,
IterableDeclContext *idc) const {
SourceFile *sf = idc->getAsGenericContext()->getParentSourceFile();
ASTContext &ctx = idc->getDecl()->getASTContext();
auto fileUnit
= dyn_cast<FileUnit>(idc->getAsGenericContext()->getModuleScopeContext());
if (!sf) {
// If there is no parent source file, this is a deserialized or synthesized
// declaration context, in which case `getMembers()` has all of the members.
@@ -64,8 +66,8 @@ ParseMembersRequest::evaluate(Evaluator &evaluator,
}
Optional<Fingerprint> fp = None;
if (!idc->getDecl()->isImplicit()) {
fp = idc->getDecl()->getModuleContext()->loadFingerprint(idc);
if (!idc->getDecl()->isImplicit() && fileUnit) {
fp = fileUnit->loadFingerprint(idc);
}
return FingerprintAndMembers{fp, ctx.AllocateCopy(members)};
}