[cfe-dev] Conflicting vs. redefined ModuleMacros

Richard Smith via cfe-dev cfe-dev at lists.llvm.org
Fri Oct 6 15:06:21 PDT 2017


Hey Jordan,

I wrote up an answer, then realised what you're probably seeing is what
happens when -fmodules-local-submodule-visibility is turned off. In that
mode, macros from, say, ConflictingA.h will leak into ConflictingB.h (as if
ConflictingB.h started by performing a private import of ConflictingA.h),
so ConflictingB.h's macro *does* override ConflictingA.h's macro, and from
clang's perspective the Conflicting and Redefined modules would then have
the same behavior -- if you import A and B, you get the macro from B.

So then I think the question is, what is the difference between the two
cases that you want to detect? (The #undef? The import of A into B prior to
the redefinition? Something else?) I think we retain sufficient information
to do this, but it's not necessarily convenient, and some of it isn't ever
read from the PCM file currently.


If you *are* using -fmodules-local-submodule-visibility, then:

On 6 October 2017 at 13:28, Jordan Rose via cfe-dev <cfe-dev at lists.llvm.org>
wrote:

> Hi, Richard. Jordan's back with another annoying ModuleMacro question for
> Swift. Let's say I have these two modules:
>
> module Conflicting {
>   explicit module A { header "ConflictingA.h" }
>   explicit module B { header "ConflictingB.h" }
> }
>
> module Redefined {
>   module A { header "RedefinedA.h" }
>   module B { header "RedefinedB.h" }
> }
>
>
> Both headers in 'Conflicting' define a macro CONFLICTING, but with
> different values; a client is only supposed to import one of them.
> 'Redefined' is a little different: RedefinedB.h includes RedefinedA.h
> before defining the new value, and the client is probably going to import
> the entire top-level module. Let's say RedefinedB.h is even polite enough
> to use #undef.*
>
> * If these examples sound bad, well, I agree, but the former is what the
> OpenGL framework on macOS has been doing for years, and the latter is how
> Clang's limits.h deals with a system limits.h.
>
> The question: using ModuleMacro, *how can I distinguish these two cases* while
> building a PCM?
>

When you say "while building a PCM", do you mean before you get to the end
of one of the headers / submodules, or after? Depending on when you ask,
you'd need to look at either the set of overridden module macros in the
preprocessor (while we're still lexing within the overriding module, before
we create a ModuleMacro) or the list of overridden module macros on the
ModuleMacro (after it's created).

We build a chain of MacroDirectives while we parse, and then convert them
to ModuleMacros at the end of each submodule. So, taking the example of
Redefined.B:

// start of RedefinedB.h, preprocessor's MacroState for CONFLICTING will be
that the ModuleMacro from Redefined.A is active and there is no
MacroDirective
#undef CONFLICTING
// now the MacroState will have Redefined.A overridden, with the
UndefMacroDirective being the current MacroDirective
#define CONFLICTING something_else
// now the MacroState will have Redefined.A overridden, with the
DefMacroDirective being the current MacroDirective

At the end of Redefined.A, we convert the DefMacroDirective to a
ModuleMacro for Redefined.B that overrides Redefined.A's macro.

The obvious correct Clang answer is "don't bother, visibility will handle
> everything when the modules get imported", but unfortunately that doesn't
> fly for Swift, because of this third example:
>
> module CrossModuleRedefinedCore {
>   header "CrossModuleRedefinedCore.h"
> }
> module CrossModuleRedefined {
>   // imports CrossModuleRedefinedCore
>   header "CrossModuleRedefined.h"
> }
>
>
> In Swift, I'm allowed to say `CrossModuleRedefinedCore.REDEFINED` to get
> the old value, and `CrossModuleRedefined.REDEFINED` to get the new value.
> I'm not *hugely* concerned about this use case if I can get the other two
> to work well, but I haven't given up on it yet.
>
> Any ideas? I already tried looking at the overrides, but that seems like
> it's represented the same in both cases.
>

That sounds wrong. Can you write a file that imports the modules and then
does:

#pragma clang __debug macro REDEFINED
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-dev/attachments/20171006/ffb92a1d/attachment.html>


More information about the cfe-dev mailing list