forked from OSchip/llvm-project
[clang] Always allow including builtin headers in [no_undeclared_headers] modules.
Previously, this would fail if the builtin headers had been "claimed" by a different module that wraps these builtin headers. libc++ does this, for example. This change adds a test demonstrating this situation; the test fails without the fix.
This commit is contained in:
parent
b3cff3c720
commit
8d74de9de6
|
@ -413,6 +413,7 @@ public:
|
|||
|
||||
/// 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) {
|
||||
|
|
|
@ -1276,14 +1276,12 @@ bool HeaderSearch::ShouldEnterIncludeFile(Preprocessor &PP,
|
|||
//
|
||||
// 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 @@ static bool suggestModule(HeaderSearch &HS, const FileEntry *File,
|
|||
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -387,13 +387,17 @@ bool ModuleMap::isBuiltinHeader(StringRef FileName) {
|
|||
.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);
|
||||
}
|
||||
|
|
|
@ -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 *
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
#include <stddef.h>
|
|
@ -0,0 +1,5 @@
|
|||
module libcxx [system] {
|
||||
header "stddef.h"
|
||||
header "stdio.h"
|
||||
export *
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
#include_next <stddef.h>
|
|
@ -0,0 +1 @@
|
|||
#include_next <stdio.h>
|
|
@ -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>
|
Loading…
Reference in New Issue