Bug 114870 - [13 Regression] stddef.h problem with -Wsystem-headers and -std=gnu23 (which is the default since GCC 15)
Summary: [13 Regression] stddef.h problem with -Wsystem-headers and -std=gnu23 (which ...
Status: RESOLVED FIXED
Alias: None
Product: gcc
Classification: Unclassified
Component: c (show other bugs)
Version: 14.0
: P3 normal
Target Milestone: 13.4
Assignee: Jakub Jelinek
URL:
Keywords: diagnostic
Depends on:
Blocks:
 
Reported: 2024-04-26 20:46 UTC by Paul Eggert
Modified: 2026-05-03 05:15 UTC (History)
4 users (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed: 2025-02-10 00:00:00


Attachments
fix stddef.h to survive multiple includes, some with __need_size_t etc. (372 bytes, patch)
2024-04-26 20:46 UTC, Paul Eggert
Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Paul Eggert 2024-04-26 20:46:31 UTC
Created attachment 58049 [details]
fix stddef.h to survive multiple includes, some with __need_size_t etc.

I found this when trying to build GNU diffutils on Fedora 40. This is gcc (GCC) 14.0.1 20240411 (Red Hat 14.0.1-0) on x86-64. Compile the following two-line program t.c with 'gcc -std=gnu23  -Wsystem-headers -E t.c >t.i':

  #include <stddef.h>
  #include <time.h>

GCC issues the following diagnostics:

  In file included from /usr/include/time.h:29,
                   from t.c:2:
  /usr/lib/gcc/x86_64-redhat-linux/14/include/stddef.h:457:9: warning: "__STDC_VERSION_STDDEF_H__" redefined
    457 | #define __STDC_VERSION_STDDEF_H__       202311L
        |         ^~~~~~~~~~~~~~~~~~~~~~~~~
  In file included from t.c:1:
  /usr/lib/gcc/x86_64-redhat-linux/14/include/stddef.h:457:9: note: this is the location of the previous definition
    457 | #define __STDC_VERSION_STDDEF_H__       202311L
        |         ^~~~~~~~~~~~~~~~~~~~~~~~~

It seems that <stddef.h> is not properly protected against multiple includes, some with __need_size_t and __need_NULL and some without.

The attached patch to stddef.h worked around the problem for me.
Comment 1 Drea Pinski 2025-02-10 06:04:54 UTC
Confirmed. I just noticed this myself Sorry for not confirming earlier.

stddef.h is under GCC control in this case too.
Comment 2 GCC Commits 2025-02-26 18:30:24 UTC
The master branch has been updated by Jakub Jelinek <jakub@gcc.gnu.org>:

https://gcc.gnu.org/g:8d22474af76a386eed488b3c66124134f0e41363

commit r15-7718-g8d22474af76a386eed488b3c66124134f0e41363
Author: Jakub Jelinek <jakub@redhat.com>
Date:   Wed Feb 26 19:29:12 2025 +0100

    c: stddef.h C23 fixes [PR114870]
    
    The stddef.h header for C23 defines __STDC_VERSION_STDDEF_H__ and
    unreachable macros multiple times in some cases.
    The header doesn't have normal multiple inclusion guard, because it supports
    for glibc inclusion with __need_{size_t,wchar_t,ptrdiff_t,wint_t,NULL}.
    While the definition of __STDC_VERSION_STDDEF_H__ and unreachable is done
    solely in the #ifdef _STDDEF_H part, so they are defined only if stddef.h
    is included without those __need_* macros defined.  But actually once
    stddef.h is included without the __need_* macros, _STDDEF_H is then defined
    and while further stddef.h includes without __need_* macros don't do
    anything:
     #if (!defined(_STDDEF_H) && !defined(_STDDEF_H_) && !defined(_ANSI_STDDEF_H) \
          && !defined(__STDDEF_H__)) \
         || defined(__need_wchar_t) || defined(__need_size_t) \
         || defined(__need_ptrdiff_t) || defined(__need_NULL) \
         || defined(__need_wint_t)
    if one includes whole stddef.h first and then stddef.h with some of the
    __need_* macros defined, the #ifdef _STDDEF_H part is used again.
    It isn't that big deal for most cases, as it uses extra guarding macros
    like:
     #ifndef _GCC_MAX_ALIGN_T
     #define _GCC_MAX_ALIGN_T
     ...
     #endif
    etc., but for __STDC_VERSION_STDDEF_H__/unreachable nothing like that is
    used.
    
    So, either we do what the following patch does and just don't define
    __STDC_VERSION_STDDEF_H__/unreachable second time, or use #ifndef
    unreachable separately for the #define unreachable() case, or use
    new _GCC_STDC_VERSION_STDDEF_H macro to guard this (or two, one for
    __STDC_VERSION_STDDEF_H__ and one for unreachable), or rework the initial
    condition to be just
     #if !defined(_STDDEF_H) && !defined(_STDDEF_H_) && !defined(_ANSI_STDDEF_H) \
         && !defined(__STDDEF_H__)
    - I really don't understand why the header should do anything at all after
    it has been included once without __need_* macros.  But changing how this
    behaves after 35 years might be risky for various OS/libc combinations.
    
    2025-02-26  Jakub Jelinek  <jakub@redhat.com>
    
            PR c/114870
            * ginclude/stddef.h (__STDC_VERSION_STDDEF_H__, unreachable): Don't
            redefine multiple times if stddef.h is first included without __need_*
            defines and later with them.  Move nullptr_t and unreachable and
            __STDC_VERSION_STDDEF_H__ definitions into the same
            defined (__STDC_VERSION__) && __STDC_VERSION__ > 201710L #if block.
    
            * gcc.dg/c23-stddef-2.c: New test.
Comment 3 Jakub Jelinek 2025-02-26 18:34:15 UTC
Fixed on the trunk so far.
Comment 4 GCC Commits 2025-03-27 23:40:55 UTC
The releases/gcc-14 branch has been updated by Jakub Jelinek <jakub@gcc.gnu.org>:

https://gcc.gnu.org/g:a266e7354bdae713f73c9f356bb15a387fd4d1b4

commit r14-11460-ga266e7354bdae713f73c9f356bb15a387fd4d1b4
Author: Jakub Jelinek <jakub@redhat.com>
Date:   Wed Feb 26 19:29:12 2025 +0100

    c: stddef.h C23 fixes [PR114870]
    
    The stddef.h header for C23 defines __STDC_VERSION_STDDEF_H__ and
    unreachable macros multiple times in some cases.
    The header doesn't have normal multiple inclusion guard, because it supports
    for glibc inclusion with __need_{size_t,wchar_t,ptrdiff_t,wint_t,NULL}.
    While the definition of __STDC_VERSION_STDDEF_H__ and unreachable is done
    solely in the #ifdef _STDDEF_H part, so they are defined only if stddef.h
    is included without those __need_* macros defined.  But actually once
    stddef.h is included without the __need_* macros, _STDDEF_H is then defined
    and while further stddef.h includes without __need_* macros don't do
    anything:
     #if (!defined(_STDDEF_H) && !defined(_STDDEF_H_) && !defined(_ANSI_STDDEF_H) \
          && !defined(__STDDEF_H__)) \
         || defined(__need_wchar_t) || defined(__need_size_t) \
         || defined(__need_ptrdiff_t) || defined(__need_NULL) \
         || defined(__need_wint_t)
    if one includes whole stddef.h first and then stddef.h with some of the
    __need_* macros defined, the #ifdef _STDDEF_H part is used again.
    It isn't that big deal for most cases, as it uses extra guarding macros
    like:
     #ifndef _GCC_MAX_ALIGN_T
     #define _GCC_MAX_ALIGN_T
     ...
     #endif
    etc., but for __STDC_VERSION_STDDEF_H__/unreachable nothing like that is
    used.
    
    So, either we do what the following patch does and just don't define
    __STDC_VERSION_STDDEF_H__/unreachable second time, or use #ifndef
    unreachable separately for the #define unreachable() case, or use
    new _GCC_STDC_VERSION_STDDEF_H macro to guard this (or two, one for
    __STDC_VERSION_STDDEF_H__ and one for unreachable), or rework the initial
    condition to be just
     #if !defined(_STDDEF_H) && !defined(_STDDEF_H_) && !defined(_ANSI_STDDEF_H) \
         && !defined(__STDDEF_H__)
    - I really don't understand why the header should do anything at all after
    it has been included once without __need_* macros.  But changing how this
    behaves after 35 years might be risky for various OS/libc combinations.
    
    2025-02-26  Jakub Jelinek  <jakub@redhat.com>
    
            PR c/114870
            * ginclude/stddef.h (__STDC_VERSION_STDDEF_H__, unreachable): Don't
            redefine multiple times if stddef.h is first included without __need_*
            defines and later with them.  Move nullptr_t and unreachable and
            __STDC_VERSION_STDDEF_H__ definitions into the same
            defined (__STDC_VERSION__) && __STDC_VERSION__ > 201710L #if block.
    
            * gcc.dg/c23-stddef-2.c: New test.
    
    (cherry picked from commit 8d22474af76a386eed488b3c66124134f0e41363)
Comment 5 Jakub Jelinek 2025-03-28 09:52:40 UTC
Fixed for 14.3+ as well.
Comment 6 GCC Commits 2025-04-23 13:10:27 UTC
The releases/gcc-13 branch has been updated by Jakub Jelinek <jakub@gcc.gnu.org>:

https://gcc.gnu.org/g:7980ce5dcf14eee0b3b937b9783fb02597cef384

commit r13-9593-g7980ce5dcf14eee0b3b937b9783fb02597cef384
Author: Jakub Jelinek <jakub@redhat.com>
Date:   Wed Feb 26 19:29:12 2025 +0100

    c: stddef.h C23 fixes [PR114870]
    
    The stddef.h header for C23 defines __STDC_VERSION_STDDEF_H__ and
    unreachable macros multiple times in some cases.
    The header doesn't have normal multiple inclusion guard, because it supports
    for glibc inclusion with __need_{size_t,wchar_t,ptrdiff_t,wint_t,NULL}.
    While the definition of __STDC_VERSION_STDDEF_H__ and unreachable is done
    solely in the #ifdef _STDDEF_H part, so they are defined only if stddef.h
    is included without those __need_* macros defined.  But actually once
    stddef.h is included without the __need_* macros, _STDDEF_H is then defined
    and while further stddef.h includes without __need_* macros don't do
    anything:
     #if (!defined(_STDDEF_H) && !defined(_STDDEF_H_) && !defined(_ANSI_STDDEF_H) \
          && !defined(__STDDEF_H__)) \
         || defined(__need_wchar_t) || defined(__need_size_t) \
         || defined(__need_ptrdiff_t) || defined(__need_NULL) \
         || defined(__need_wint_t)
    if one includes whole stddef.h first and then stddef.h with some of the
    __need_* macros defined, the #ifdef _STDDEF_H part is used again.
    It isn't that big deal for most cases, as it uses extra guarding macros
    like:
     #ifndef _GCC_MAX_ALIGN_T
     #define _GCC_MAX_ALIGN_T
     ...
     #endif
    etc., but for __STDC_VERSION_STDDEF_H__/unreachable nothing like that is
    used.
    
    So, either we do what the following patch does and just don't define
    __STDC_VERSION_STDDEF_H__/unreachable second time, or use #ifndef
    unreachable separately for the #define unreachable() case, or use
    new _GCC_STDC_VERSION_STDDEF_H macro to guard this (or two, one for
    __STDC_VERSION_STDDEF_H__ and one for unreachable), or rework the initial
    condition to be just
     #if !defined(_STDDEF_H) && !defined(_STDDEF_H_) && !defined(_ANSI_STDDEF_H) \
         && !defined(__STDDEF_H__)
    - I really don't understand why the header should do anything at all after
    it has been included once without __need_* macros.  But changing how this
    behaves after 35 years might be risky for various OS/libc combinations.
    
    2025-02-26  Jakub Jelinek  <jakub@redhat.com>
    
            PR c/114870
            * ginclude/stddef.h (__STDC_VERSION_STDDEF_H__, unreachable): Don't
            redefine multiple times if stddef.h is first included without __need_*
            defines and later with them.  Move nullptr_t and unreachable and
            __STDC_VERSION_STDDEF_H__ definitions into the same
            defined (__STDC_VERSION__) && __STDC_VERSION__ > 201710L #if block.
    
            * gcc.dg/c23-stddef-2.c: New test.
    
    (cherry picked from commit 8d22474af76a386eed488b3c66124134f0e41363)
Comment 7 Jakub Jelinek 2025-04-24 08:54:47 UTC
Fixed also for 13.4.