The <cmath> and <cstdlib> headers need their counter parts <math.h> and
<stdlib.h> from the libc respectively, but libstdc++ wraps these
headers. Now <cmath> and <cstdlib> include these headers using

$ echo '#include <cstdlib>' | g++ -x c++ -E - -isystem /usr/include >/dev/null
In file included from <stdin>:1:
/usr/include/c++/9/cstdlib:75:15: fatal error: stdlib.h: No such file or 
directory
   75 | #include_next <stdlib.h>
      |               ^~~~~~~~~~
compilation terminated.
$

What happens here is that g++ includes
libstdc++-v3/include/c_global/cstdlib. That header temporarily #defines
_GLIBCXX_INCLUDE_NEXT_C_HEADERS and then does #include_next <stdlib.h>.
libstdc++-v3's replacement libstdc++-v3/include/c_comaptibility/stdlib.h
happens to come earlier and is not considered.  Unfortunately, the
-isystem above inserted glibc's header before the location containing
<cstdlib>, so the #include_next continues searching and fails to find
<stdlib.h>.

Now you are probably going to say that "-isystem /usr/include" is a bad
idea and that you shouldn't do that. I'm inclined to agree. This isn't a
problem just yet. Debian wants to move /usr/include/stdlib.h to
/usr/include/<multiarch>/stdlib.h. After that move, the problematic flag
becomes "-isystem /usr/include/<multiarch>". Unfortunately, around 30
Debian packages[1] do pass exactly that flag. Regardless whether doing
so is a bad idea, I guess we will have to support that.

I am proposing to replace those two #include_next with plain #include.
That'll solve the problem described above, but it is not entirely
obvious that doing so doesn't break something else.

After switching those #include_next to #include,
libstdc++-v3/include/c_global/cstdlib will continue to temporarily
will #include <stdlib.h>. Now, it'll search all include directories. It
may find libstdc++-v3/include/c_comaptibility/stdlib.h or the libc's
version. We cannot tell which. If it finds the one from libstdc++-v3,
the header will notice the _GLIBCXX_INCLUDE_NEXT_C_HEADERS macro and
immediately #include_next <stdlib.h> skipping the rest of the header.
That in turn will find the libc version. So in both cases, it ends up
using the right one. Precisely what we wanted. #include_next is simply
not useful here.

The #include_next was originally added via PRs libstdc++/14608 and
libstdc++/60401. At that time, the _GLIBCXX_INCLUDE_NEXT_C_HEADERS guard
macro was also added. It seems like the #include_next was a meant as an
extra safe-guard, but actually breaks a practical use case.

For these reasons, I think that using #include_next here is harmful and
that replacing it with plain #include solves the problem without
introducing regressions.

[1] Including but not limited chromium-browser, inkscape, various kde
    packages, opencv, and vtk.

libstdc++-v3/ChangeLog:

        * include/c_global/cmath: Don't use #include_next.
        * include/c_global/cstdlib: Likewise.
---
 libstdc++-v3/include/c_global/cmath   | 2 +-
 libstdc++-v3/include/c_global/cstdlib | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

Given the patch's size, I think that the copyright dance is not
necessary. The issue affects at least gcc-8 to gcc-10. Please Cc me in
replies.

Helmut

diff --git a/libstdc++-v3/include/c_global/cmath 
b/libstdc++-v3/include/c_global/cmath
index b99aaf8df40..8b2bb7c0785 100644
--- a/libstdc++-v3/include/c_global/cmath
+++ b/libstdc++-v3/include/c_global/cmath
@@ -42,7 +42,7 @@
 #include <bits/cpp_type_traits.h>
 #include <ext/type_traits.h>
 #define _GLIBCXX_INCLUDE_NEXT_C_HEADERS
-#include_next <math.h>
+#include <math.h>
 #undef _GLIBCXX_INCLUDE_NEXT_C_HEADERS
 #include <bits/std_abs.h>
 
diff --git a/libstdc++-v3/include/c_global/cstdlib 
b/libstdc++-v3/include/c_global/cstdlib
index f42db41fc51..80b39f6144f 100644
--- a/libstdc++-v3/include/c_global/cstdlib
+++ b/libstdc++-v3/include/c_global/cstdlib
@@ -72,7 +72,7 @@ namespace std
 // Need to ensure this finds the C library's <stdlib.h> not a libstdc++
 // wrapper that might already be installed later in the include search path.
 #define _GLIBCXX_INCLUDE_NEXT_C_HEADERS
-#include_next <stdlib.h>
+#include <stdlib.h>
 #undef _GLIBCXX_INCLUDE_NEXT_C_HEADERS
 #include <bits/std_abs.h>
 
-- 
2.26.0

Reply via email to