Open mhjacobson opened 2 years ago
This is the change I made:
diff --git a/libcxx/include/module.modulemap.in b/libcxx/include/module.modulemap.in
index 897c2c8c583f..f2de2dc2a677 100644
--- a/libcxx/include/module.modulemap.in
+++ b/libcxx/include/module.modulemap.in
@@ -30,6 +30,13 @@ module std [system] {
export *
}
// <float.h> provided by compiler or C library.
+ module stdint_h {
+ header "stdint.h"
+ export *
+ // FIXME: This module only exists on OS X and for some reason the
+ // wildcard above doesn't export it.
+ export Darwin.C.stdint
+ }
module inttypes_h {
header "inttypes.h"
export stdint_h
@@ -64,13 +71,6 @@ module std [system] {
// <stddef.h>'s __need_* macros require textual inclusion.
textual header "stddef.h"
}
- module stdint_h {
- header "stdint.h"
- export *
- // FIXME: This module only exists on OS X and for some reason the
- // wildcard above doesn't export it.
- export Darwin.C.stdint
- }
module stdio_h {
// <stdio.h>'s __need_* macros require textual inclusion.
textual header "stdio.h"
@llvm/issue-subscribers-clang-modules
OK, slowly educating myself here. The reason why /usr/include/stdint.h
gets "assigned" to std.depr.inttypes_h
isn't some special module magic. It just boils down to the fact that /usr/include/stdint.h
has a standard preprocessor header guard.
First, std.depr.inttypes_h
is compiled. It transitively includes /usr/include/stdint.h
, which places all of that header's declarations in std.depr.inttypes_h
. That also defines _SYS_STDINT_H_
.
Later, std.depr.stdint_h
is compiled. It also transitively includes /usr/include/stdint.h
. Since preprocessor state from earlier submodules is still visible, /usr/include/stdint.h
early-outs.
Clang's modules documentation makes a reference to this style of problem:
Entities within a submodule that has already been built are visible when building later submodules in that module. This can lead to fragile modules that depend on the build order used for the submodules of the module, and should not be relied upon. This behavior is subject to change.
FreeBSD 13.1-RELEASE / x86_64
With
-fmodules
on in C++ mode, attempting to#include <stdint.h>
and use one of its typedefs (likeint64_t
) fails. See below for example compilation failure.This appears to be a quirk of how libc++'s modulemap is ordered. The modulemap includes these submodule definitions:
If I understand correctly, this is the problem:
The submodule
std.depr.inttypes_h
is built first. libc++'sinttypes.h
includes<stdint.h>
, which ultimately pulls in the system/usr/include/stdint.h
. This causes/usr/include/stdint.h
to get "assigned" to the submodulestd.depr.inttypes_h
.Then, when the submodule
std.depr.stdint_h
is built, it does not pick up declarations from/usr/include/stdint.h
, because those have already been "assigned" tostd.depr.inttypes_h
.When the main program imports
std.depr.stdint_h
(whether explicitly or through translation of an#include
), the modulestd
is loaded, but only AST content "assigned" tostd.depr.stdint_h
is visible. Since typedefint64_t
was assigned tostd.depr.inttypes_h
, the program fails to compile.I tried moving the
module stdint_h {}
block abovemodule inttypes_h {}
in the modulemap file, and that did indeed fix the problem. Additionally, I verified that, even with that change, importingstd.depr.inttypes_h
(which reexportsstdint_h
) allows access toint64_t
.Example failure: