[clang][modules] giving the __stddef_ headers their own modules can cause redeclaration errors with -fbuiltin-headers-in-system-modules (#84127)

On Apple platforms, some of the stddef.h types are also declared in
system headers. In particular NULL has a conflicting declaration in
<sys/_types/_null.h>. When that's in a different module from
<__stddef_null.h>, redeclaration errors can occur.

Make the \_\_stddef_ headers be non-modular in
-fbuiltin-headers-in-system-modules and restore them back to not
respecting their header guards. Still define the header guards though.
__stddef_max_align_t.h was in _Builtin_stddef_max_align_t prior to the
addition of _Builtin_stddef, and it needs to stay in a module because
struct's can't be type merged. __stddef_wint_t.h didn't used to have a
module, but leave it in it current module since it doesn't really belong
to stddef.h.

(cherry picked from commit f50d3582b4844b86ad86372028e44b52c560ec7d)
This commit is contained in:
Ian Anderson 2024-03-13 11:15:41 -07:00 committed by Tom Stellard
parent 12a3bf3515
commit a649e0a6e8
13 changed files with 80 additions and 41 deletions

View File

@ -301,10 +301,9 @@ bool Module::directlyUses(const Module *Requested) {
if (Requested->isSubModuleOf(Use))
return true;
// Anyone is allowed to use our builtin stdarg.h and stddef.h and their
// accompanying modules.
if (Requested->getTopLevelModuleName() == "_Builtin_stdarg" ||
Requested->getTopLevelModuleName() == "_Builtin_stddef")
// Anyone is allowed to use our builtin stddef.h and its accompanying modules.
if (Requested->fullModuleNameIs({"_Builtin_stddef", "max_align_t"}) ||
Requested->fullModuleNameIs({"_Builtin_stddef_wint_t"}))
return true;
if (NoUndeclaredIncludes)

View File

@ -7,7 +7,7 @@
*===-----------------------------------------------------------------------===
*/
#if !defined(NULL) || !__has_feature(modules)
#if !defined(NULL) || !__building_module(_Builtin_stddef)
/* linux/stddef.h will define NULL to 0. glibc (and other) headers then define
* __need_NULL and rely on stddef.h to redefine NULL to the correct value again.

View File

@ -7,7 +7,12 @@
*===-----------------------------------------------------------------------===
*/
#ifndef _NULLPTR_T
/*
* When -fbuiltin-headers-in-system-modules is set this is a non-modular header
* and needs to behave as if it was textual.
*/
#if !defined(_NULLPTR_T) || \
(__has_feature(modules) && !__building_module(_Builtin_stddef))
#define _NULLPTR_T
#ifdef __cplusplus

View File

@ -7,6 +7,11 @@
*===-----------------------------------------------------------------------===
*/
#ifndef offsetof
/*
* When -fbuiltin-headers-in-system-modules is set this is a non-modular header
* and needs to behave as if it was textual.
*/
#if !defined(offsetof) || \
(__has_feature(modules) && !__building_module(_Builtin_stddef))
#define offsetof(t, d) __builtin_offsetof(t, d)
#endif

View File

@ -7,7 +7,12 @@
*===-----------------------------------------------------------------------===
*/
#ifndef _PTRDIFF_T
/*
* When -fbuiltin-headers-in-system-modules is set this is a non-modular header
* and needs to behave as if it was textual.
*/
#if !defined(_PTRDIFF_T) || \
(__has_feature(modules) && !__building_module(_Builtin_stddef))
#define _PTRDIFF_T
typedef __PTRDIFF_TYPE__ ptrdiff_t;

View File

@ -7,7 +7,12 @@
*===-----------------------------------------------------------------------===
*/
#ifndef _RSIZE_T
/*
* When -fbuiltin-headers-in-system-modules is set this is a non-modular header
* and needs to behave as if it was textual.
*/
#if !defined(_RSIZE_T) || \
(__has_feature(modules) && !__building_module(_Builtin_stddef))
#define _RSIZE_T
typedef __SIZE_TYPE__ rsize_t;

View File

@ -7,7 +7,12 @@
*===-----------------------------------------------------------------------===
*/
#ifndef _SIZE_T
/*
* When -fbuiltin-headers-in-system-modules is set this is a non-modular header
* and needs to behave as if it was textual.
*/
#if !defined(_SIZE_T) || \
(__has_feature(modules) && !__building_module(_Builtin_stddef))
#define _SIZE_T
typedef __SIZE_TYPE__ size_t;

View File

@ -7,6 +7,11 @@
*===-----------------------------------------------------------------------===
*/
#ifndef unreachable
/*
* When -fbuiltin-headers-in-system-modules is set this is a non-modular header
* and needs to behave as if it was textual.
*/
#if !defined(unreachable) || \
(__has_feature(modules) && !__building_module(_Builtin_stddef))
#define unreachable() __builtin_unreachable()
#endif

View File

@ -9,7 +9,12 @@
#if !defined(__cplusplus) || (defined(_MSC_VER) && !_NATIVE_WCHAR_T_DEFINED)
#ifndef _WCHAR_T
/*
* When -fbuiltin-headers-in-system-modules is set this is a non-modular header
* and needs to behave as if it was textual.
*/
#if !defined(_WCHAR_T) || \
(__has_feature(modules) && !__building_module(_Builtin_stddef))
#define _WCHAR_T
#ifdef _MSC_EXTENSIONS

View File

@ -155,9 +155,9 @@ module _Builtin_intrinsics [system] [extern_c] {
// Start -fbuiltin-headers-in-system-modules affected modules
// The following modules all ignore their top level headers
// when -fbuiltin-headers-in-system-modules is passed, and
// most of those headers join system modules when present.
// The following modules all ignore their headers when
// -fbuiltin-headers-in-system-modules is passed, and many of
// those headers join system modules when present.
// e.g. if -fbuiltin-headers-in-system-modules is passed, then
// float.h will not be in the _Builtin_float module (that module
@ -190,11 +190,6 @@ module _Builtin_stdalign [system] {
export *
}
// When -fbuiltin-headers-in-system-modules is passed, only
// the top level headers are removed, the implementation headers
// will always be in their submodules. That means when stdarg.h
// is included, it will still import this module and make the
// appropriate submodules visible.
module _Builtin_stdarg [system] {
textual header "stdarg.h"
@ -237,6 +232,8 @@ module _Builtin_stdbool [system] {
module _Builtin_stddef [system] {
textual header "stddef.h"
// __stddef_max_align_t.h is always in this module, even if
// -fbuiltin-headers-in-system-modules is passed.
explicit module max_align_t {
header "__stddef_max_align_t.h"
export *
@ -283,9 +280,10 @@ module _Builtin_stddef [system] {
}
}
/* wint_t is provided by <wchar.h> and not <stddef.h>. It's here
* for compatibility, but must be explicitly requested. Therefore
* __stddef_wint_t.h is not part of _Builtin_stddef. */
// wint_t is provided by <wchar.h> and not <stddef.h>. It's here
// for compatibility, but must be explicitly requested. Therefore
// __stddef_wint_t.h is not part of _Builtin_stddef. It is always in
// this module even if -fbuiltin-headers-in-system-modules is passed.
module _Builtin_stddef_wint_t [system] {
header "__stddef_wint_t.h"
export *

View File

@ -2498,9 +2498,12 @@ void ModuleMapParser::parseHeaderDecl(MMToken::TokenKind LeadingToken,
}
bool NeedsFramework = false;
// Don't add the top level headers to the builtin modules if the builtin headers
// belong to the system modules.
if (!Map.LangOpts.BuiltinHeadersInSystemModules || ActiveModule->isSubModule() || !isBuiltInModuleName(ActiveModule->Name))
// Don't add headers to the builtin modules if the builtin headers belong to
// the system modules, with the exception of __stddef_max_align_t.h which
// always had its own module.
if (!Map.LangOpts.BuiltinHeadersInSystemModules ||
!isBuiltInModuleName(ActiveModule->getTopLevelModuleName()) ||
ActiveModule->fullModuleNameIs({"_Builtin_stddef", "max_align_t"}))
Map.addUnresolvedHeader(ActiveModule, std::move(Header), NeedsFramework);
if (NeedsFramework)

View File

@ -8,7 +8,7 @@
// 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
// RUN: %clang_cc1 -fmodules-cache-path=%t -fmodules -fbuiltin-headers-in-system-modules -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>

View File

@ -1,29 +1,33 @@
// RUN: rm -rf %t
// RUN: %clang_cc1 -fmodules -fimplicit-module-maps -fbuiltin-headers-in-system-modules -fmodules-cache-path=%t -I%S/Inputs/StdDef %s -verify -fno-modules-error-recovery
// RUN: %clang_cc1 -fmodules -fimplicit-module-maps -fbuiltin-headers-in-system-modules -fmodules-cache-path=%t -I%S/Inputs/StdDef %s -verify=builtin-headers-in-system-modules -fno-modules-error-recovery
// RUN: rm -rf %t
// RUN: %clang_cc1 -fmodules -fimplicit-module-maps -fmodules-cache-path=%t -I%S/Inputs/StdDef %s -verify -fno-modules-error-recovery
// RUN: %clang_cc1 -fmodules -fimplicit-module-maps -fmodules-cache-path=%t -I%S/Inputs/StdDef %s -verify=no-builtin-headers-in-system-modules -fno-modules-error-recovery
#include "ptrdiff_t.h"
ptrdiff_t pdt;
// size_t is declared in both size_t.h and __stddef_size_t.h, both of which are
// modular headers. Regardless of whether stddef.h joins the StdDef test module
// or is in its _Builtin_stddef module, __stddef_size_t.h will be in
// _Builtin_stddef.size_t. It's not defined which module will win as the expected
// provider of size_t. For the purposes of this test it doesn't matter which header
// gets reported, just as long as it isn't other.h or include_again.h.
size_t st; // expected-error-re {{missing '#include "{{size_t|__stddef_size_t}}.h"'; 'size_t' must be declared before it is used}}
// expected-note@size_t.h:* 0+ {{here}}
// expected-note@__stddef_size_t.h:* 0+ {{here}}
// size_t is declared in both size_t.h and __stddef_size_t.h. If
// -fbuiltin-headers-in-system-modules is set, then __stddef_size_t.h is a
// non-modular header that will be transitively pulled in the StdDef test module
// by include_again.h. Otherwise it will be in the _Builtin_stddef module. In
// any case it's not defined which module will win as the expected provider of
// size_t. For the purposes of this test it doesn't matter which of the two
// providing headers get reported.
size_t st; // builtin-headers-in-system-modules-error-re {{missing '#include "{{size_t|include_again}}.h"'; 'size_t' must be declared before it is used}} \
no-builtin-headers-in-system-modules-error-re {{missing '#include "{{size_t|__stddef_size_t}}.h"'; 'size_t' must be declared before it is used}}
// builtin-headers-in-system-modules-note@size_t.h:* 0+ {{here}} \
no-builtin-headers-in-system-modules-note@size_t.h:* 0+ {{here}}
// builtin-headers-in-system-modules-note@__stddef_size_t.h:* 0+ {{here}} \
no-builtin-headers-in-system-modules-note@__stddef_size_t.h:* 0+ {{here}}
#include "include_again.h"
// Includes <stddef.h> which includes <__stddef_size_t.h> which imports the
// _Builtin_stddef.size_t module.
// Includes <stddef.h> which includes <__stddef_size_t.h>.
size_t st2;
#include "size_t.h"
// Redeclares size_t, but the type merger should figure it out.
// Redeclares size_t when -fbuiltin-headers-in-system-modules is not passed, but
// the type merger should figure it out.
size_t st3;