Subject: bug#43579: g++ does not provide std::fegetround

From: Ludovic Courtès <[email-masked]>
Date: Sat, 03 Oct 2020 12:02:18 +0200

Hi,

(Cc’ing Maxim who’s looked into this before.)

Andreas Enge <[email-masked]> skribis:

> well, just put these lines into a file called "round.cpp" (as attached),
> and then
>    gcc round.cpp

Ah yes, I wasn’t sure if this was ‘gcc-toolchain’ or not.  Only 7.x (the
current ‘gcc-final’) works:

--8<---------------cut here---------------start------------->8---
$ cat t.cpp
#include <cfenv>
int main () {
   return std::fegetround ();
}

$ guix environment -C --ad-hoc gcc-toolchain@7 -- g++ -Wall -c t.cpp
$ guix environment -C --ad-hoc gcc-toolchain -- g++ -Wall -c t.cpp
t.cpp: In function 'int main()':
t.cpp:3:16: error: 'fegetround' is not a member of 'std'; did you mean 'fegetround'?
    3 |    return std::fegetround ();
      |                ^~~~~~~~~~
In file included from /gnu/store/maa9v3r0l3kzi9y20mz5m5c1f83m75n5-profile/include/c++/fenv.h:36,
                 from /gnu/store/maa9v3r0l3kzi9y20mz5m5c1f83m75n5-profile/include/c++/cfenv:41,
                 from t.cpp:1:
/gnu/store/maa9v3r0l3kzi9y20mz5m5c1f83m75n5-profile/include/fenv.h:104:12: note: 'fegetround' declared here
  104 | extern int fegetround (void) __THROW __attribute_pure__;
      |            ^~~~~~~~~~
$ guix describe
Generacio 162   Oct 01 2020 00:23:38    (nuna)
  guix 7607ace
    repository URL: https://git.savannah.gnu.org/git/guix.git
    branch: master
    commit: 7607ace5091aea0157ba5c8a508129cc5fc4f931
--8<---------------cut here---------------end--------------->8---

It’s the same story as <https://issues.guix.gnu.org/42392>.

> The difference to the Opensuse headers is that in bits/c++config.h,
> they define _GLIBCXX_USE_C99_FENV_TR1, which, as I understand it,
> removes the fe* functions from the global namespace to put them back into
> the std:: namespace.

Indeed, the build log of ‘gcc-10’ for instance has this:

--8<---------------cut here---------------start------------->8---
checking fenv.h usability... yes
checking fenv.h presence... yes
checking for fenv.h... yes
checking for complex.h... (cached) yes
checking for complex.h... (cached) yes
checking for ISO C99 support to TR1 in <complex.h>... yes
checking for ISO C99 support to TR1 in <ctype.h>... yes
checking for fenv.h... (cached) yes
checking for ISO C99 support to TR1 in <fenv.h>... no
--8<---------------cut here---------------end--------------->8---

Here’s the ‘prev-x86_64-unknown-linux-gnu/libstdc++-v3/config.log’
excerpt:

--8<---------------cut here---------------start------------->8---
configure:16448: checking for fenv.h
configure:16448: result: yes
configure:16462: checking for ISO C99 support to TR1 in <fenv.h>
configure:16490:  /tmp/guix-build-gcc-10.2.0.drv-0/build/./gcc/xgcc -shared-libgcc -B/tmp/guix-build-gcc-10.2.0.drv-0/build/./gcc -nostdinc++ -L/tmp/guix-build-gcc-10.2.0.drv-0/build/x86_64-unknown-linux-gnu/libstdc++-v3/src -L/tmp/guix-build-gcc-10.2.0.drv-0/build/x86_64-unknown-linux-gnu/libstdc++-v3/src/.libs -L/tmp/guix-build-gcc-10.2.0.drv-0/build/x86_64-unknown-linux-gnu/libstdc++-v3/libsupc++/.libs -B/gnu/store/xpdy9vvqym9xv7praqkwsm3gdzn2kv1p-gcc-10.2.0/x86_64-unknown-linux-gnu/bin/ -B/gnu/store/xpdy9vvqym9xv7praqkwsm3gdzn2kv1p-gcc-10.2.0/x86_64-unknown-linux-gnu/lib/ -isystem /gnu/store/xpdy9vvqym9xv7praqkwsm3gdzn2kv1p-gcc-10.2.0/x86_64-unknown-linux-gnu/include -isystem /gnu/store/xpdy9vvqym9xv7praqkwsm3gdzn2kv1p-gcc-10.2.0/x86_64-unknown-linux-gnu/sys-include   -fno-checking -c -g -O2 -D_GNU_SOURCE -std=c++98  conftest.cpp >&5
conftest.cpp: In function 'int main()':
conftest.cpp:102:7: error: 'fexcept_t' was not declared in this scope; did you mean 'except'?
  102 |       fexcept_t* pflag;
      |       ^~~~~~~~~
      |       except
conftest.cpp:102:18: error: 'pflag' was not declared in this scope
  102 |       fexcept_t* pflag;
      |                  ^~~~~
conftest.cpp:103:7: error: 'fenv_t' was not declared in this scope
  103 |       fenv_t* penv;
      |       ^~~~~~
conftest.cpp:103:15: error: 'penv' was not declared in this scope
  103 |       fenv_t* penv;
      |               ^~~~
conftest.cpp:105:13: error: 'feclearexcept' was not declared in this scope
  105 |       ret = feclearexcept(except);
      |             ^~~~~~~~~~~~~
conftest.cpp:106:13: error: 'fegetexceptflag' was not declared in this scope
  106 |       ret = fegetexceptflag(pflag, except);
      |             ^~~~~~~~~~~~~~~
conftest.cpp:107:13: error: 'feraiseexcept' was not declared in this scope
  107 |       ret = feraiseexcept(except);
      |             ^~~~~~~~~~~~~
conftest.cpp:108:13: error: 'fesetexceptflag' was not declared in this scope
  108 |       ret = fesetexceptflag(pflag, except);
      |             ^~~~~~~~~~~~~~~
conftest.cpp:109:13: error: 'fetestexcept' was not declared in this scope
  109 |       ret = fetestexcept(except);
      |             ^~~~~~~~~~~~
conftest.cpp:110:13: error: 'fegetround' was not declared in this scope
  110 |       ret = fegetround();
      |             ^~~~~~~~~~
conftest.cpp:111:13: error: 'fesetround' was not declared in this scope
  111 |       ret = fesetround(mode);
      |             ^~~~~~~~~~
conftest.cpp:112:13: error: 'fegetenv' was not declared in this scope
  112 |       ret = fegetenv(penv);
      |             ^~~~~~~~
conftest.cpp:113:13: error: 'feholdexcept' was not declared in this scope
  113 |       ret = feholdexcept(penv);
      |             ^~~~~~~~~~~~
conftest.cpp:114:13: error: 'fesetenv' was not declared in this scope
  114 |       ret = fesetenv(penv);
      |             ^~~~~~~~
conftest.cpp:115:13: error: 'feupdateenv' was not declared in this scope
  115 |       ret = feupdateenv(penv);
      |             ^~~~~~~~~~~
configure:16490: $? = 1
configure: failed program was:
| /* confdefs.h */
| #define PACKAGE_NAME "package-unused"
| #define PACKAGE_TARNAME "libstdc++"
| #define PACKAGE_VERSION "version-unused"
| #define PACKAGE_STRING "package-unused version-unused"
| #define PACKAGE_BUGREPORT ""
| #define PACKAGE_URL ""
| #define STDC_HEADERS 1
| #define HAVE_SYS_TYPES_H 1
| #define HAVE_SYS_STAT_H 1
| #define HAVE_STDLIB_H 1
| #define HAVE_STRING_H 1
| #define HAVE_MEMORY_H 1
| #define HAVE_STRINGS_H 1
| #define HAVE_INTTYPES_H 1
| #define HAVE_STDINT_H 1
| #define HAVE_UNISTD_H 1
| #define HAVE_DLFCN_H 1
| #define LT_OBJDIR ".libs/"
| #define _GLIBCXX_HOSTED 1
| #define _GLIBCXX_VERBOSE 1
| #define _GLIBCXX_ATOMIC_BUILTINS 1
| #define HAVE_ATOMIC_LOCK_POLICY 1
| #define _GLIBCXX_USE_DECIMAL_FLOAT 1
| #define _GLIBCXX_USE_INT128 1
| #define HAVE_STRXFRM_L 1
| #define HAVE_STRERROR_L 1
| #define HAVE_STRERROR_R 1
| #define _GLIBCXX_USE_LONG_LONG 1
| #define HAVE_WCHAR_H 1
| #define HAVE_MBSTATE_T 1
| #define HAVE_WCTYPE_H 1
| #define _GLIBCXX_USE_WCHAR_T 1
| #define _GLIBCXX98_USE_C99_MATH 1
| #define HAVE_TGMATH_H 1
| #define HAVE_COMPLEX_H 1
| #define _GLIBCXX98_USE_C99_COMPLEX 1
| #define _GLIBCXX98_USE_C99_STDIO 1
| #define _GLIBCXX98_USE_C99_STDLIB 1
| #define HAVE_VFWSCANF 1
| #define HAVE_VSWSCANF 1
| #define HAVE_VWSCANF 1
| #define HAVE_WCSTOF 1
| #define HAVE_ISWBLANK 1
| #define _GLIBCXX98_USE_C99_WCHAR 1
| #define _GLIBCXX_USE_C99 1
| #define _GLIBCXX11_USE_C99_MATH 1
| #define HAVE_TGMATH_H 1
| #define HAVE_COMPLEX_H 1
| #define _GLIBCXX11_USE_C99_COMPLEX 1
| #define _GLIBCXX11_USE_C99_STDIO 1
| #define _GLIBCXX11_USE_C99_STDLIB 1
| #define HAVE_VFWSCANF 1
| #define HAVE_VSWSCANF 1
| #define HAVE_VWSCANF 1
| #define HAVE_WCSTOF 1
| #define HAVE_ISWBLANK 1
| #define _GLIBCXX11_USE_C99_WCHAR 1
| #define _GLIBCXX_FULLY_DYNAMIC_STRING 0
| #define HAVE_GETS 1
| #define HAVE_EOWNERDEAD 1
| #define HAVE_ENOTRECOVERABLE 1
| #define HAVE_ENOLINK 1
| #define HAVE_EPROTO 1
| #define HAVE_ENODATA 1
| #define HAVE_ENOSR 1
| #define HAVE_ENOSTR 1
| #define HAVE_ETIME 1
| #define HAVE_EBADMSG 1
| #define HAVE_ECANCELED 1
| #define HAVE_EOVERFLOW 1
| #define HAVE_ENOTSUP 1
| #define HAVE_EIDRM 1
| #define HAVE_ETXTBSY 1
| #define HAVE_ECHILD 1
| #define HAVE_ENOSPC 1
| #define HAVE_EPERM 1
| #define HAVE_ETIMEDOUT 1
| #define HAVE_EWOULDBLOCK 1
| #define HAVE_UCHAR_H 1
| #define _GLIBCXX_USE_C11_UCHAR_CXX11 1
| #define HAVE_INT64_T 1
| #define HAVE_INT64_T_LONG 1
| #define _GLIBCXX_USE_LFS 1
| #define HAVE_SYS_IOCTL_H 1
| #define HAVE_POLL 1
| #define HAVE_S_ISREG 1
| #define HAVE_SYS_UIO_H 1
| #define HAVE_WRITEV 1
| #define HAVE_FENV_H 1
| #define HAVE_COMPLEX_H 1
| #define HAVE_COMPLEX_H 1
| #define _GLIBCXX_USE_C99_COMPLEX_TR1 1
| #define _GLIBCXX_USE_C99_CTYPE_TR1 1
| #define HAVE_FENV_H 1
| /* end confdefs.h.  */
| #include <fenv.h>
| int
| main ()
| {
| int except, mode;
| 		    fexcept_t* pflag;
| 		    fenv_t* penv;
| 		    int ret;
| 		    ret = feclearexcept(except);
| 		    ret = fegetexceptflag(pflag, except);
| 		    ret = feraiseexcept(except);
| 		    ret = fesetexceptflag(pflag, except);
| 		    ret = fetestexcept(except);
| 		    ret = fegetround();
| 		    ret = fesetround(mode);
| 		    ret = fegetenv(penv);
| 		    ret = feholdexcept(penv);
| 		    ret = fesetenv(penv);
| 		    ret = feupdateenv(penv);
| 
|   ;
|   return 0;
| }
configure:16497: result: no
--8<---------------cut here---------------end--------------->8---

The same program builds fine outside.

Turns out GCC provides <fenv.h>, too:

--8<---------------cut here---------------start------------->8---
$ find /tmp/guix-build-gcc-10.2.0.drv-0/ -name fenv.h
/tmp/guix-build-gcc-10.2.0.drv-0/gcc-10.2.0/fixincludes/tests/base/bits/fenv.h
/tmp/guix-build-gcc-10.2.0.drv-0/gcc-10.2.0/libstdc++-v3/include/tr1/fenv.h
/tmp/guix-build-gcc-10.2.0.drv-0/gcc-10.2.0/libstdc++-v3/include/c_compatibility/fenv.h
/tmp/guix-build-gcc-10.2.0.drv-0/build/prev-x86_64-unknown-linux-gnu/libstdc++-v3/include/tr1/fenv.h
/tmp/guix-build-gcc-10.2.0.drv-0/build/prev-x86_64-unknown-linux-gnu/libstdc++-v3/include/fenv.h
--8<---------------cut here---------------end--------------->8---

So this is again #include_next not picking the right <fenv.h> due to
search path ordering issues and/or duplicate entries.

Thoughts anyone?

I think we need a proper fix but the feedback we got from GCC folks last
time didn’t give me much insight as to what we should do.

> This should happen somewhere in a configure phase inside the gcc build, but
> I do not know how to obtain the config.log file easily (short of adding a
> phase "(const #f)" to the build recipe and doing a "guix build -K").

I do:

  guix build -e '(@ (gnu packages gcc) gcc-10)' --no-grafts --check -K

Then I hit C-c once the relevant ‘configure’ has run (you can check
what’s in /tmp/guix-build-gcc-10*).  :-)

Thanks,
Ludo’.