https://gcc.gnu.org/bugzilla/show_bug.cgi?id=107795

            Bug ID: 107795
           Summary: <limits.h> recursion through <syslimits.h> breaks
                    non-GNU implementations of the C++ stdlib
           Product: gcc
           Version: 12.1.0
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: libstdc++
          Assignee: unassigned at gcc dot gnu.org
          Reporter: ldionne.2 at gmail dot com
  Target Milestone: ---

The <limits.h> header currently includes "syslimits.h", which then recursively
includes <limits.h> after defining the _GCC_NEXT_LIMITS_H macro. The <limits.h>
header seems to be generated from a bunch of stuff, including `gcc/limitx.h`,
which seems to be responsible for that recursive inclusion. Incidentally, this
seems to not have been modified in the last 30 years.

This recursive inclusion with a macro is hostile to implementations that want
to build on top of GCC's <limits.h> header, since they need to know about that
recursive inclusion trick and the _GCC_NEXT_LIMITS_H macro. For example, libc++
currently needs to know about this wrinkle and implement its own <limits.h>
header differently depending on whether it's built with GCC or another
compiler.

System headers should work such that they can be layered on top of each other
without needing this sort of trick. To reproduce the issue we're seeing with a
minimal example:

    #!/usr/bin/env bash

    rm -rf __fake_cxx_include && mkdir -p __fake_cxx_include
    cat <<EOF > __fake_cxx_include/limits.h
    #ifndef __MY_LIMITS_H
    #define __MY_LIMITS_H
    #   include_next <limits.h>
    #endif
    EOF

    cat <<EOF | g++-12 -isystem $PWD/__fake_cxx_include -nostdinc++ -v
-fsyntax-only -xc++ - -O2 -H
    #include <limits.h>
    #include <wchar.h>
    EOF

When running this script, the output is (on our Docker image):

    . /llvm/__fake_cxx_include/limits.h
    .. /usr/lib/gcc/x86_64-linux-gnu/12/include/limits.h
    ... /usr/lib/gcc/x86_64-linux-gnu/12/include/syslimits.h
    .... /llvm/__fake_cxx_include/limits.h
    . /usr/include/wchar.h
    [...]
    .. /usr/include/x86_64-linux-gnu/bits/wchar.h
    [...]
    .. /usr/include/x86_64-linux-gnu/bits/wchar2.h
    In file included from /usr/include/wchar.h:867,
                    from <stdin>:2:
    /usr/include/x86_64-linux-gnu/bits/wchar2.h:398:3: error: #error "Assumed
value of MB_LEN_MAX wrong"
    398 | # error "Assumed value of MB_LEN_MAX wrong"
        |   ^~~~~

Because this <limits.h> header does not know about the GCC-internal macro
_GCC_NEXT_LIMITS_H, we fail to recursively re-include <limits.h> and then
including <wchar.h> fails in a rather obscure way. Also note that this only
fails if we're using -O2 to compile, since -O2 seems to turn on some __fortify
stuff which leads to including <wchar2.h>.

Long story short, it would be great if GCC's <limits.h> header could be
simplified to avoid recursively including itself through <syslimits.h>.

Reply via email to