mboehme updated this revision to Diff 267210.
mboehme added a comment.
When testing with the real libc++ and glibc, I realized that I was still
getting a cyclic dependency between the two modules because the builtin
stddef.h that glibc was including was still being ascribed to libc++.
This modified version fixes this and also updates the test to more closely
reflect the real libc++ and glibc so that my previous version of the fix also
fails with a cyclic dependency.
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D80781/new/
https://reviews.llvm.org/D80781
Files:
clang/include/clang/Lex/ModuleMap.h
clang/lib/Lex/HeaderSearch.cpp
clang/lib/Lex/ModuleMap.cpp
clang/test/Modules/Inputs/no-undeclared-includes-builtins/glibc/module.modulemap
clang/test/Modules/Inputs/no-undeclared-includes-builtins/glibc/stdio.h
clang/test/Modules/Inputs/no-undeclared-includes-builtins/libcxx/module.modulemap
clang/test/Modules/Inputs/no-undeclared-includes-builtins/libcxx/stddef.h
clang/test/Modules/Inputs/no-undeclared-includes-builtins/libcxx/stdio.h
clang/test/Modules/no-undeclared-includes-builtins.cpp
Index: clang/test/Modules/no-undeclared-includes-builtins.cpp
===================================================================
--- /dev/null
+++ clang/test/Modules/no-undeclared-includes-builtins.cpp
@@ -0,0 +1,14 @@
+// Test that a [no_undeclared_headers] module can include builtin headers, even
+// if these have been "claimed" by a different module that wraps these builtin
+// headers. libc++ does this, for example.
+//
+// The test inputs used here replicates the relationship between libc++ and
+// glibc. When modularizing glibc, [no_undeclared_headers] must be used to
+// prevent glibc from including the libc++ versions of the C standard library
+// headers.
+
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -fmodules-cache-path=%t -fmodules -fimplicit-module-maps -I %S/Inputs/no-undeclared-includes-builtins/libcxx -I %S/Inputs/no-undeclared-includes-builtins/glibc %s
+// expected-no-diagnostics
+
+#include <stddef.h>
Index: clang/test/Modules/Inputs/no-undeclared-includes-builtins/libcxx/stdio.h
===================================================================
--- /dev/null
+++ clang/test/Modules/Inputs/no-undeclared-includes-builtins/libcxx/stdio.h
@@ -0,0 +1 @@
+#include_next <stdio.h>
Index: clang/test/Modules/Inputs/no-undeclared-includes-builtins/libcxx/stddef.h
===================================================================
--- /dev/null
+++ clang/test/Modules/Inputs/no-undeclared-includes-builtins/libcxx/stddef.h
@@ -0,0 +1 @@
+#include_next <stddef.h>
Index: clang/test/Modules/Inputs/no-undeclared-includes-builtins/libcxx/module.modulemap
===================================================================
--- /dev/null
+++ clang/test/Modules/Inputs/no-undeclared-includes-builtins/libcxx/module.modulemap
@@ -0,0 +1,5 @@
+module libcxx [system] {
+ header "stddef.h"
+ header "stdio.h"
+ export *
+}
Index: clang/test/Modules/Inputs/no-undeclared-includes-builtins/glibc/stdio.h
===================================================================
--- /dev/null
+++ clang/test/Modules/Inputs/no-undeclared-includes-builtins/glibc/stdio.h
@@ -0,0 +1 @@
+#include <stddef.h>
Index: clang/test/Modules/Inputs/no-undeclared-includes-builtins/glibc/module.modulemap
===================================================================
--- /dev/null
+++ clang/test/Modules/Inputs/no-undeclared-includes-builtins/glibc/module.modulemap
@@ -0,0 +1,5 @@
+module glibc [system] [no_undeclared_includes] {
+ // glibc relies on the builtin stddef.h, so it has no stddef.h of its own.
+ header "stdio.h"
+ export *
+}
Index: clang/lib/Lex/ModuleMap.cpp
===================================================================
--- clang/lib/Lex/ModuleMap.cpp
+++ clang/lib/Lex/ModuleMap.cpp
@@ -387,13 +387,17 @@
.Default(false);
}
+bool ModuleMap::isBuiltinHeader(const FileEntry *File) {
+ return File->getDir() == BuiltinIncludeDir &&
+ ModuleMap::isBuiltinHeader(llvm::sys::path::filename(File->getName()));
+}
+
ModuleMap::HeadersMap::iterator
ModuleMap::findKnownHeader(const FileEntry *File) {
resolveHeaderDirectives(File);
HeadersMap::iterator Known = Headers.find(File);
if (HeaderInfo.getHeaderSearchOpts().ImplicitModuleMaps &&
- Known == Headers.end() && File->getDir() == BuiltinIncludeDir &&
- ModuleMap::isBuiltinHeader(llvm::sys::path::filename(File->getName()))) {
+ Known == Headers.end() && ModuleMap::isBuiltinHeader(File)) {
HeaderInfo.loadTopLevelSystemModules();
return Headers.find(File);
}
Index: clang/lib/Lex/HeaderSearch.cpp
===================================================================
--- clang/lib/Lex/HeaderSearch.cpp
+++ clang/lib/Lex/HeaderSearch.cpp
@@ -1276,14 +1276,12 @@
//
// It's common that libc++ and system modules will both define such
// submodules. Make sure cached results for a builtin header won't
- // prevent other builtin modules to potentially enter the builtin header.
- // Note that builtins are header guarded and the decision to actually
- // enter them is postponed to the controlling macros logic below.
+ // prevent other builtin modules from potentially entering the builtin
+ // header. Note that builtins are header guarded and the decision to
+ // actually enter them is postponed to the controlling macros logic below.
bool TryEnterHdr = false;
if (FileInfo.isCompilingModuleHeader && FileInfo.isModuleHeader)
- TryEnterHdr = File->getDir() == ModMap.getBuiltinDir() &&
- ModuleMap::isBuiltinHeader(
- llvm::sys::path::filename(File->getName()));
+ TryEnterHdr = ModMap.isBuiltinHeader(File);
// Textual headers can be #imported from different modules. Since ObjC
// headers find in the wild might rely only on #import and do not contain
@@ -1416,20 +1414,31 @@
ModuleMap::KnownHeader *SuggestedModule) {
ModuleMap::KnownHeader Module =
HS.findModuleForHeader(File, /*AllowTextual*/true);
- if (SuggestedModule)
- *SuggestedModule = (Module.getRole() & ModuleMap::TextualHeader)
- ? ModuleMap::KnownHeader()
- : Module;
// If this module specifies [no_undeclared_includes], we cannot find any
// file that's in a non-dependency module.
if (RequestingModule && Module && RequestingModule->NoUndeclaredIncludes) {
- HS.getModuleMap().resolveUses(RequestingModule, /*Complain*/false);
+ HS.getModuleMap().resolveUses(RequestingModule, /*Complain*/ false);
if (!RequestingModule->directlyUses(Module.getModule())) {
+ // Builtin headers are a special case. Multiple modules can use the same
+ // builtin as a modular header (see also comment in
+ // ShouldEnterIncludeFile()), so the builtin header may have been
+ // "claimed" by an unrelated module. This shouldn't prevent us from
+ // including the builtin header textually in this module.
+ if (HS.getModuleMap().isBuiltinHeader(File)) {
+ if (SuggestedModule)
+ *SuggestedModule = ModuleMap::KnownHeader();
+ return true;
+ }
return false;
}
}
+ if (SuggestedModule)
+ *SuggestedModule = (Module.getRole() & ModuleMap::TextualHeader)
+ ? ModuleMap::KnownHeader()
+ : Module;
+
return true;
}
Index: clang/include/clang/Lex/ModuleMap.h
===================================================================
--- clang/include/clang/Lex/ModuleMap.h
+++ clang/include/clang/Lex/ModuleMap.h
@@ -413,6 +413,7 @@
/// Is this a compiler builtin header?
static bool isBuiltinHeader(StringRef FileName);
+ bool isBuiltinHeader(const FileEntry *File);
/// Add a module map callback.
void addModuleMapCallbacks(std::unique_ptr<ModuleMapCallbacks> Callback) {
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits