Module macro semantics with #undef's

Hi everyone,

The modules documentation (http://clang.llvm.org/docs/Modules.html#macros) says this about importing multiple definitions of the same macro:

For example, suppose:
  - <stdio.h> defines a macro getc (and exports its #define)
  - <cstdio> imports the <stdio.h> module and undefines the macro (and exports its #undef)
The #undef overrides the #define, and a source file that imports both modules in any order will not see getc defined as a macro.

I've been writing some test cases, and I've confirmed this behavior in a trivial test case. However, when I import two modules that both define a macro, that macro still seems to be defined even in the presence of another macro that #undef's it. Here are two test cases that demonstrate the divergent behavior:

$ cat undef.c
#include "Module/UndefFoo.h"
#include "Module/DefineFoo.h"

#ifdef FOO
#error FOO was defined
#endif
$ cat redef-undef.c
#include "Module/UndefFoo.h"
#include "Module/DefineFoo.h"
#include "Module/RedefineFoo.h"

#ifdef FOO
#error FOO was defined
#endif
$

And here's the contents of the module itself:

$ ls Module/
DefineFoo.h module.modulemap RedefineFoo.h UndefFoo.h
$ cat Module/module.modulemap
module Module {
  module DefineFoo {
    header "DefineFoo.h"
  }
  module UndefFoo {
    header "UndefFoo.h"
  }
  module RedefineFoo {
    header "RedefineFoo.h"
  }
}
$ cat Module/DefineFoo.h
#define FOO 1
$ cat Module/RedefineFoo.h
#define FOO 1
$ cat Module/UndefFoo.h
#undef FOO
$

Now, when I run these test cases:

$ /opt/pkg/clang-3.9.0/bin/clang -fmodules -c undef.c
$ /opt/pkg/clang-3.9.0/bin/clang -fmodules -c redef-undef.c
redef-undef.c:6:2: error: FOO was defined
#error FOO was defined
^
1 error generated.
$

The documentation seems to suggest that the latter case should also pass without errors. Is this inconsistency a bug or is there some subtlety I'm missing here?

Thanks!
- Tim

Hi everyone,

The modules documentation (http://clang.llvm.org/docs/Modules.html#macros) says this about importing multiple definitions of the same macro:

For example, suppose:
- <stdio.h> defines a macro getc (and exports its #define)
- <cstdio> imports the <stdio.h> module and undefines the macro (and exports its #undef)
The #undef overrides the #define, and a source file that imports both modules in any order will not see getc defined as a macro.

In this specific case, #undef in cstdio overrides the #define in the imported <stdio.h> module.
See the document:
  • A #define X or #undef X directive overrides all definitions of X that are visible at the point of the directive.
  • A #define or #undef directive is active if it is visible and no visible directive overrides it.

I've been writing some test cases, and I've confirmed this behavior in a trivial test case. However, when I import two modules that both define a macro, that macro still seems to be defined even in the presence of another macro that #undef's it.

The module has 3 macros, the macro owned by Module.UndefFoo overrides the macro in Module.DefineFoo. The set of macros a given macro overrides depends on the order in your module map file, I think. That is why the macro in RedefineFoo is still active.

Here are two test cases that demonstrate the divergent behavior:

$ cat undef.c
#include "Module/UndefFoo.h"
#include "Module/DefineFoo.h”

Since the macro from Module.DefineFoo is overridden, FOO is undefined.

#ifdef FOO
#error FOO was defined
#endif
$ cat redef-undef.c
#include "Module/UndefFoo.h"
#include "Module/DefineFoo.h"
#include "Module/RedefineFoo.h”

The macro from RedefineFoo is active, and FOO is defined here.

Manman

Right. In the default mode, names defined in an earlier header in a top-level module are visible in later headers within that top-level module, so the order matters. (With -fmodules-local-submodule-visibility, this name leakage is turned off and each submodule starts with a clean slate, but that’s not well supported in C yet.)