Skip to content

[cherry-pick stable/20230725][clang][modules] giving the __stddef_ headers their own modules can cause redeclaration errors with -fbuiltin-headers-in-system-modules (#84127) #8402

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 3 additions & 4 deletions clang/lib/Basic/Module.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -306,10 +306,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)
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/Headers/__stddef_null.h
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
7 changes: 6 additions & 1 deletion clang/lib/Headers/__stddef_nullptr_t.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
7 changes: 6 additions & 1 deletion clang/lib/Headers/__stddef_offsetof.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
7 changes: 6 additions & 1 deletion clang/lib/Headers/__stddef_ptrdiff_t.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
7 changes: 6 additions & 1 deletion clang/lib/Headers/__stddef_rsize_t.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
7 changes: 6 additions & 1 deletion clang/lib/Headers/__stddef_size_t.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
7 changes: 6 additions & 1 deletion clang/lib/Headers/__stddef_unreachable.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
7 changes: 6 additions & 1 deletion clang/lib/Headers/__stddef_wchar_t.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
20 changes: 9 additions & 11 deletions clang/lib/Headers/module.modulemap
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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"

Expand Down Expand Up @@ -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 *
Expand Down Expand Up @@ -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 *
Expand Down
9 changes: 6 additions & 3 deletions clang/lib/Lex/ModuleMap.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2514,9 +2514,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)
Expand Down
2 changes: 1 addition & 1 deletion clang/test/Modules/no-undeclared-includes-builtins.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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>
32 changes: 18 additions & 14 deletions clang/test/Modules/stddef.c
Original file line number Diff line number Diff line change
@@ -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;