[PATCH] D120465: [clang][deps] Disable implicit module maps

Duncan P. N. Exon Smith via Phabricator via cfe-commits cfe-commits at lists.llvm.org
Fri Mar 11 12:20:21 PST 2022


dexonsmith accepted this revision.
dexonsmith added a comment.
This revision is now accepted and ready to land.

LGTM, with a suggested change for the text of the comment.



================
Comment at: clang/lib/Tooling/DependencyScanning/ModuleDepCollector.cpp:269-273
+  // However, some module maps loaded implicitly during the dependency scan can
+  // describe anti-dependencies. That happens when the current module is marked
+  // as '[no_undeclared_includes]', doesn't 'use' module from such module map,
+  // but tries to import it anyway. We need to tell the explicit build about
+  // such module map for it to have the same semantics as the implicit build.
----------------
jansvoboda11 wrote:
> dexonsmith wrote:
> > jansvoboda11 wrote:
> > > dexonsmith wrote:
> > > > Is there another long-term solution to this that could be pointed at with a FIXME? E.g., could the module map be encoded redundantly here? If so, what else would need to change to make that okay?
> > > I'm not sure I understand why this would warrant "long-term solution" or a FIXME. This code handles an existing feature that just happens to be a corner case from the dependency scanning point of view. (You can read up on the feature [[ https://clang.llvm.org/docs/Modules.html | here ]].)
> > > 
> > > What do you mean by encoding the module map redundantly?
> > Yes, I know the feature.
> > 
> > ... but I was probably wrong about how it affects the logic here.
> > 
> > I also now have two guesses at the scenario being handled here (previously I assumed (1)):
> > 
> > 1. A textual include from a module that is not marked as used. I wasn't sure what you meant by "tries to import", but I guess I thought it was just "loads the module map and finds the textual header listed there". IIUC, there's no actual attempt to import a module when the only thing referenced from it is a textual header, but I could see how parsing the module mapĀ could affect the state anyway.
> > 
> > 2. A modular include from a module that is not marked as used. Something like a `__has_include`, or a `#include` that fails but there's another search path with the same header. In this case, there'd be an actual import attempt, which would fail. And that could also affect state.
> > 
> > Can you clarify which scenario you need to handle? Or is it a 3rd?
> > 
> > > I'm not sure I understand why this would warrant "long-term solution" or a FIXME.
> > 
> > This smells like a workaround to me. IIUC, sending in module maps that aren't actually "needed" except to reproduce side effects of failed queries.
> > 
> > My intuition is that the right long-term fix would involve isolate the failed queries from the compiler state in the scanning phase so that they don't have side effects. Then there would be no side effects to reproduce in the explicit build.
> > 
> > > What do you mean by encoding the module map redundantly?
> > 
> > I think I was confused about scanning vs building, thinking that a module using a textual include (1) could be copied into each module PCM that directly imports it. (I know that this wouldn't scale right now for various reasons, but I wondered if there was some way to get there... but regardless, seems like it's totally unrelated)
> The scenario being handled is the following:
> 
> 3. Modular `#include` of B from module A, where A is marked `[no_undeclared_includes]` and doesn't `use B`. Typically, that `#include` would be guarded by `__has_include`.
> 
> With implicit module maps disabled, the presence of module map B allows us to evaluate the `__has_include` the same way as with them enabled. This is the only reason we need module map B. There are no side effects from failed queries. The query failure itself is the behavior we need to reproduce.
> 
> I'm not even thinking about "another search path with the same header" in this patch.
Thanks! I was making things way too complicated!

IIUC:
- Without the module map, a `__has_include` would succeed because it'd be textually included.
- With the module map, a `__has_include` would fail because the module map would block textual inclusion and `[no_undeclared_includes]` would block modular inclusion.

Here's some text that I'd suggest:
```
  // We usually don't need to list the module map files of our dependencies when
  // building a module explicitly: their semantics will be deserialized from PCM
  // files.
  //
  // However, some module maps loaded implicitly during the dependency scan can
  // describe anti-dependencies. That happens when this module, let's call it M1,
  // is marked as '[no_undeclared_includes]' and tries to access a header "M2/M2.h"
  // from another module, M2, but doesn't have a 'use M2;' declaration. The explicit
  // build needs the module map for M2 so that it knows that textually including
  // "M2/M2.h" is not allowed. E.g., '__has_include("M2/M2.h")' should return false,
  // but without M2's module map the explicit build would return true.
  //
  // An alternative approach would be to tell the explicit build what its textual
  // dependencies are, instead of having it re-discover its anti-dependencies. For
  // example, we could create and use an `-ivfs-overlay` with `fall-through: false`
  // that explicitly listed the dependencies. However, that's more complicated to
  // implement and harder to reason about.
```
Feel free to reword (and/or drop the `__has_include` example and/or drop the last paragraph), but something like this would have prevented my confusion!



Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D120465/new/

https://reviews.llvm.org/D120465



More information about the cfe-commits mailing list