* tests/test-fenv-env-1.c: New file.
* tests/test-fenv-env-2.c: New file.
* tests/test-fenv-env-3.c: New file.
* tests/test-fenv-env-4.c: New file.
* tests/test-fenv-env-5.sh: New file.
* tests/test-fenv-env-5.c: New file.
* modules/fenv-environment-tests: New file.
2023-11-05 Bruno Haible <bruno@clisp.org>
+ fenv-environment: Add tests.
+ * tests/test-fenv-env-1.c: New file.
+ * tests/test-fenv-env-2.c: New file.
+ * tests/test-fenv-env-3.c: New file.
+ * tests/test-fenv-env-4.c: New file.
+ * tests/test-fenv-env-5.sh: New file.
+ * tests/test-fenv-env-5.c: New file.
+ * modules/fenv-environment-tests: New file.
+
fenv-environment: New module.
* lib/fenv.in.h (fenv_t) [hppa]: Remove the __exception field.
(FE_DFL_ENV): Override if <fenv.h> exists but HAVE_FE_DFL_ENV is not
--- /dev/null
+Files:
+tests/test-fenv-env-1.c
+tests/test-fenv-env-2.c
+tests/test-fenv-env-3.c
+tests/test-fenv-env-4.c
+tests/test-fenv-env-5.sh
+tests/test-fenv-env-5.c
+tests/macros.h
+m4/musl.m4
+
+Depends-on:
+fenv-rounding
+fenv-exceptions-tracking-c99
+fenv-exceptions-trapping
+fpe-trapping
+
+configure.ac:
+gl_MUSL_LIBC
+
+Makefile.am:
+TESTS += \
+ test-fenv-env-1 \
+ test-fenv-env-2 \
+ test-fenv-env-3 \
+ test-fenv-env-4 \
+ test-fenv-env-5.sh
+check_PROGRAMS += \
+ test-fenv-env-1 \
+ test-fenv-env-2 \
+ test-fenv-env-3 \
+ test-fenv-env-4 \
+ test-fenv-env-5
+test_fenv_env_1_LDADD = $(LDADD) @FENV_ENVIRONMENT_LIBM@ $(FENV_EXCEPTIONS_TRACKING_LIBM) $(FENV_ROUNDING_LIBM) $(FPE_TRAPPING_LIBM)
+test_fenv_env_2_LDADD = $(LDADD) @FENV_ENVIRONMENT_LIBM@ $(FENV_EXCEPTIONS_TRACKING_LIBM) $(FENV_ROUNDING_LIBM) $(FPE_TRAPPING_LIBM)
+test_fenv_env_3_LDADD = $(LDADD) @FENV_ENVIRONMENT_LIBM@ $(FENV_EXCEPTIONS_TRACKING_LIBM) $(FENV_ROUNDING_LIBM) $(FPE_TRAPPING_LIBM)
+test_fenv_env_4_LDADD = $(LDADD) @FENV_ENVIRONMENT_LIBM@ $(FENV_EXCEPTIONS_TRACKING_LIBM) $(FENV_ROUNDING_LIBM) $(FPE_TRAPPING_LIBM)
+test_fenv_env_5_LDADD = $(LDADD) @FENV_ENVIRONMENT_LIBM@ $(FENV_EXCEPTIONS_TRACKING_LIBM) $(FPE_TRAPPING_LIBM)
--- /dev/null
+/* Test of controlling the floating-point environment.
+ Copyright (C) 2023 Free Software Foundation, Inc.
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <https://www.gnu.org/licenses/>. */
+
+/* Written by Bruno Haible <bruno@clisp.org>, 2023. */
+
+#include <config.h>
+
+/* Specification. */
+#include <fenv.h>
+
+#include "macros.h"
+
+/* Test the combination of fegetenv() with fesetenv(). */
+
+int
+main ()
+{
+#if defined __GLIBC__ && defined __arm__ && defined __SOFTFP__
+ fputs ("Skipping test: no floating-point environment exists on this machine\n", stderr);
+ return 77;
+#else
+ fenv_t env1, env2;
+
+ /* Get to a known initial state. */
+ ASSERT (feclearexcept (FE_ALL_EXCEPT) == 0);
+
+ /* Save the current environment in env1. */
+ ASSERT (fegetenv (&env1) == 0);
+
+ /* Modify the current environment. */
+ fesetround (FE_UPWARD);
+ int supports_tracking = (feraiseexcept (FE_INVALID | FE_OVERFLOW | FE_INEXACT) == 0);
+ int supports_trapping = (feenableexcept (FE_DIVBYZERO) != -1);
+
+ /* Save the current environment in env2. */
+ ASSERT (fegetenv (&env2) == 0);
+
+ /* Check that the exception flags are unmodified. */
+ ASSERT (fetestexcept (FE_ALL_EXCEPT) == (supports_tracking ? FE_INVALID | FE_OVERFLOW | FE_INEXACT : 0));
+ /* Check that the exception trap bits are unmodified. */
+ ASSERT (fegetexcept () == (supports_trapping ? FE_DIVBYZERO : 0));
+
+ /* Go back to env1. */
+ ASSERT (fesetenv (&env1) == 0);
+
+ /* Check that the rounding direction has been restored. */
+ ASSERT (fegetround () == FE_TONEAREST);
+ /* Check that the exception flags have been restored. */
+ ASSERT (fetestexcept (FE_ALL_EXCEPT) == 0);
+ /* Check that the exception trap bits have been restored. */
+ ASSERT (fegetexcept () == 0);
+
+ /* Modify the rounding direction, the exception flags, and the exception
+ trap bits again. */
+ fesetround (FE_DOWNWARD);
+ ASSERT (fegetround () == FE_DOWNWARD);
+ feclearexcept (FE_OVERFLOW);
+ feraiseexcept (FE_UNDERFLOW | FE_INEXACT);
+ ASSERT (fetestexcept (FE_ALL_EXCEPT) == (supports_tracking ? FE_UNDERFLOW | FE_INEXACT : 0));
+ feenableexcept (FE_INVALID);
+ ASSERT (fegetexcept () == (supports_trapping ? FE_INVALID : 0));
+
+ /* Go back to env2. */
+ ASSERT (fesetenv (&env2) == 0);
+
+ /* Check that the rounding direction has been restored. */
+ ASSERT (fegetround () == FE_UPWARD);
+ /* Check that the exception flags have been restored. */
+ ASSERT (fetestexcept (FE_ALL_EXCEPT) == (supports_tracking ? FE_INVALID | FE_OVERFLOW | FE_INEXACT : 0));
+ /* Check that the exception trap bits have been restored. */
+ ASSERT (fegetexcept () == (supports_trapping ? FE_DIVBYZERO : 0));
+
+ /* ======================================================================== */
+ /* FE_DFL_ENV */
+
+ /* Enable trapping on FE_INVALID. */
+ feclearexcept (FE_INVALID);
+ feenableexcept (FE_INVALID);
+ ASSERT (fetestexcept (FE_ALL_EXCEPT) == (supports_tracking ? FE_OVERFLOW | FE_INEXACT : 0));
+
+ /* Go back to the default environment. */
+ ASSERT (fesetenv (FE_DFL_ENV) == 0);
+
+ /* Check its contents. */
+ ASSERT (fegetround () == FE_TONEAREST);
+ ASSERT (fetestexcept (FE_ALL_EXCEPT) == 0);
+
+ /* Check that it has trapping on FE_INVALID disabled. */
+ ASSERT (fegetexcept () == 0);
+ {
+ double volatile a;
+ _GL_UNUSED double volatile b;
+ a = 0; b = a / a;
+ }
+
+ /* ======================================================================== */
+ /* Check that fesetenv restores the trapping behaviour. */
+
+ /* Enable trapping on FE_INVALID. */
+ feclearexcept (FE_INVALID);
+ feenableexcept (FE_INVALID);
+
+ /* Go back to env1. */
+ ASSERT (fesetenv (&env1) == 0);
+
+ /* Check that it has disabled trapping on FE_INVALID. */
+ ASSERT (fegetexcept () == 0);
+ {
+ double volatile a;
+ _GL_UNUSED double volatile b;
+ a = 0; b = a / a;
+ }
+
+ return 0;
+#endif
+}
--- /dev/null
+/* Test of controlling the floating-point environment.
+ Copyright (C) 2023 Free Software Foundation, Inc.
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <https://www.gnu.org/licenses/>. */
+
+/* Written by Bruno Haible <bruno@clisp.org>, 2023. */
+
+#include <config.h>
+
+/* Specification. */
+#include <fenv.h>
+
+#include "macros.h"
+
+/* Test the combination of fegetenv() with feupdateenv(). */
+
+int
+main ()
+{
+#if defined __GLIBC__ && defined __arm__ && defined __SOFTFP__
+ fputs ("Skipping test: no floating-point environment exists on this machine\n", stderr);
+ return 77;
+#else
+ fenv_t env1, env2;
+
+ /* Get to a known initial state. */
+ ASSERT (feclearexcept (FE_ALL_EXCEPT) == 0);
+
+ /* Save the current environment in env1. */
+ ASSERT (fegetenv (&env1) == 0);
+
+ /* Modify the current environment. */
+ fesetround (FE_UPWARD);
+ int supports_tracking = (feraiseexcept (FE_INVALID | FE_OVERFLOW | FE_INEXACT) == 0);
+ int supports_trapping = (feenableexcept (FE_DIVBYZERO) != -1);
+
+ /* Save the current environment in env2. */
+ ASSERT (fegetenv (&env2) == 0);
+
+ /* Check that the exception flags are unmodified. */
+ ASSERT (fetestexcept (FE_ALL_EXCEPT) == (supports_tracking ? FE_INVALID | FE_OVERFLOW | FE_INEXACT : 0));
+ /* Check that the exception trap bits are unmodified. */
+ ASSERT (fegetexcept () == (supports_trapping ? FE_DIVBYZERO : 0));
+
+ /* Go back to env1. */
+ ASSERT (feupdateenv (&env1) == 0);
+
+ /* Check that the rounding direction has been restored. */
+ ASSERT (fegetround () == FE_TONEAREST);
+ /* Check that the exception flags are the union of the saved and of the
+ current exception flags. (The saved exception flags happen to be none
+ in this case.) */
+ ASSERT (fetestexcept (FE_ALL_EXCEPT) == (supports_tracking ? FE_INVALID | FE_OVERFLOW | FE_INEXACT : 0));
+ /* Check that the exception trap bits have been restored. */
+ ASSERT (fegetexcept () == 0);
+
+ /* Modify the rounding direction, the exception flags, and the exception
+ trap bits again. */
+ fesetround (FE_DOWNWARD);
+ ASSERT (fegetround () == FE_DOWNWARD);
+ feclearexcept (FE_INVALID | FE_OVERFLOW);
+ feraiseexcept (FE_UNDERFLOW | FE_INEXACT);
+ ASSERT (fetestexcept (FE_ALL_EXCEPT) == (supports_tracking ? FE_UNDERFLOW | FE_INEXACT : 0));
+ feenableexcept (FE_INVALID);
+ ASSERT (fegetexcept () == (supports_trapping ? FE_INVALID : 0));
+
+ /* Go back to env2. */
+ ASSERT (feupdateenv (&env2) == 0);
+
+ /* Check that the rounding direction has been restored. */
+ ASSERT (fegetround () == FE_UPWARD);
+ /* Check that the exception flags are the union of the saved and of the
+ current exception flags. */
+ ASSERT (fetestexcept (FE_ALL_EXCEPT) == (supports_tracking ? FE_INVALID | FE_OVERFLOW | FE_UNDERFLOW | FE_INEXACT : 0));
+ /* Check that the exception trap bits have been restored. */
+ ASSERT (fegetexcept () == (supports_trapping ? FE_DIVBYZERO : 0));
+
+ /* ======================================================================== */
+ /* FE_DFL_ENV */
+
+ /* Go back to the default environment. */
+ ASSERT (feupdateenv (FE_DFL_ENV) == 0);
+
+ /* Check that the rounding direction has been restored,
+ whereas the exception flags are unmodified. */
+ ASSERT (fegetround () == FE_TONEAREST);
+ ASSERT (fetestexcept (FE_ALL_EXCEPT) == (supports_tracking ? FE_INVALID | FE_OVERFLOW | FE_UNDERFLOW | FE_INEXACT : 0));
+
+ /* Enable trapping on FE_INVALID. */
+ feclearexcept (FE_INVALID);
+ feenableexcept (FE_INVALID);
+ ASSERT (fetestexcept (FE_ALL_EXCEPT) == (supports_tracking ? FE_OVERFLOW | FE_UNDERFLOW | FE_INEXACT : 0));
+
+ /* Go back to the default environment. */
+ ASSERT (feupdateenv (FE_DFL_ENV) == 0);
+
+ /* Check that the rounding direction has been restored,
+ whereas the exception flags are unmodified. */
+ ASSERT (fegetround () == FE_TONEAREST);
+ ASSERT (fetestexcept (FE_ALL_EXCEPT) == (supports_tracking ? FE_OVERFLOW | FE_UNDERFLOW | FE_INEXACT : 0));
+
+ /* Check that it has trapping on FE_INVALID disabled. */
+ ASSERT (fegetexcept () == 0);
+ {
+ double volatile a;
+ _GL_UNUSED double volatile b;
+ a = 0; b = a / a;
+ }
+
+ /* ======================================================================== */
+ /* Check that feupdateenv restores the trapping behaviour. */
+
+ /* Enable trapping on FE_INVALID. */
+ feclearexcept (FE_INVALID);
+ feenableexcept (FE_INVALID);
+
+ /* Go back to env1. */
+ ASSERT (feupdateenv (&env1) == 0);
+
+ /* Check that it has disabled trapping on FE_INVALID. */
+ ASSERT (fegetexcept () == 0);
+ {
+ double volatile a;
+ _GL_UNUSED double volatile b;
+ a = 0; b = a / a;
+ }
+
+ return 0;
+#endif
+}
--- /dev/null
+/* Test of controlling the floating-point environment.
+ Copyright (C) 2023 Free Software Foundation, Inc.
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <https://www.gnu.org/licenses/>. */
+
+/* Written by Bruno Haible <bruno@clisp.org>, 2023. */
+
+#include <config.h>
+
+/* Specification. */
+#include <fenv.h>
+
+#include "macros.h"
+
+/* Test the combination of feholdexcept() with fesetenv(). */
+
+int
+main ()
+{
+#if defined __GLIBC__ && defined __arm__ && defined __SOFTFP__
+ fputs ("Skipping test: no floating-point environment exists on this machine\n", stderr);
+ return 77;
+#else
+ fenv_t env1, env2;
+
+ /* Get to a known initial state. */
+ ASSERT (feclearexcept (FE_ALL_EXCEPT) == 0);
+
+ /* Save the current environment in env1. */
+ ASSERT (feholdexcept (&env1) == 0);
+
+ /* Modify the current environment. */
+ fesetround (FE_UPWARD);
+ int supports_tracking = (feraiseexcept (FE_INVALID | FE_OVERFLOW | FE_INEXACT) == 0);
+ int supports_trapping = (feenableexcept (FE_DIVBYZERO) != -1);
+
+ /* Save the current environment in env2. */
+ ASSERT (feholdexcept (&env2) == 0);
+
+ /* Check that the exception flags are cleared. */
+ ASSERT (fetestexcept (FE_ALL_EXCEPT) == 0);
+ /* Check that the exception trap bits are cleared. */
+ ASSERT (fegetexcept () == 0);
+
+ /* Go back to env1. */
+ ASSERT (fesetenv (&env1) == 0);
+
+ /* Check that the rounding direction has been restored. */
+ ASSERT (fegetround () == FE_TONEAREST);
+ /* Check that the exception flags have been restored. */
+ ASSERT (fetestexcept (FE_ALL_EXCEPT) == 0);
+ /* Check that the exception trap bits have been restored. */
+ ASSERT (fegetexcept () == 0);
+
+ /* Modify the rounding direction, the exception flags, and the exception
+ trap bits again. */
+ fesetround (FE_DOWNWARD);
+ ASSERT (fegetround () == FE_DOWNWARD);
+ feclearexcept (FE_OVERFLOW);
+ feraiseexcept (FE_UNDERFLOW | FE_INEXACT);
+ ASSERT (fetestexcept (FE_ALL_EXCEPT) == (supports_tracking ? FE_UNDERFLOW | FE_INEXACT : 0));
+ feenableexcept (FE_INVALID);
+ ASSERT (fegetexcept () == (supports_trapping ? FE_INVALID : 0));
+
+ /* Go back to env2. */
+ ASSERT (fesetenv (&env2) == 0);
+
+ /* Check that the rounding direction has been restored. */
+ ASSERT (fegetround () == FE_UPWARD);
+ /* Check that the exception flags have been restored. */
+ ASSERT (fetestexcept (FE_ALL_EXCEPT) == (supports_tracking ? FE_INVALID | FE_OVERFLOW | FE_INEXACT : 0));
+ /* Check that the exception trap bits have been restored. */
+ ASSERT (fegetexcept () == (supports_trapping ? FE_DIVBYZERO : 0));
+
+ /* ======================================================================== */
+ /* FE_DFL_ENV */
+
+ /* Enable trapping on FE_INVALID. */
+ feclearexcept (FE_INVALID);
+ feenableexcept (FE_INVALID);
+ ASSERT (fetestexcept (FE_ALL_EXCEPT) == (supports_tracking ? FE_OVERFLOW | FE_INEXACT : 0));
+
+ /* Go back to the default environment. */
+ ASSERT (fesetenv (FE_DFL_ENV) == 0);
+
+ /* Check its contents. */
+ ASSERT (fegetround () == FE_TONEAREST);
+ ASSERT (fetestexcept (FE_ALL_EXCEPT) == 0);
+
+ /* Check that it has trapping on FE_INVALID disabled. */
+ ASSERT (fegetexcept () == 0);
+ {
+ double volatile a;
+ _GL_UNUSED double volatile b;
+ a = 0; b = a / a;
+ }
+
+ /* ======================================================================== */
+ /* Check that feholdexcept, unlike fegetenv, disables trapping. */
+
+ /* musl libc does not support floating-point exception trapping, even where
+ the hardware supports it. See
+ <https://wiki.musl-libc.org/functional-differences-from-glibc.html> */
+# if !MUSL_LIBC || GNULIB_FEENABLEEXCEPT
+ /* Enable trapping on FE_INVALID. */
+ feclearexcept (FE_INVALID);
+ if (feenableexcept (FE_INVALID) != -1)
+ {
+ /* Call feholdexcept. */
+ ASSERT (feholdexcept (&env1) == 0);
+
+ /* Check that it has disabled trapping on FE_INVALID. */
+ ASSERT (fegetexcept () == 0);
+ {
+ double volatile a;
+ _GL_UNUSED double volatile b;
+ a = 0; b = a / a;
+ }
+ }
+# endif
+
+ return 0;
+#endif
+}
--- /dev/null
+/* Test of controlling the floating-point environment.
+ Copyright (C) 2023 Free Software Foundation, Inc.
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <https://www.gnu.org/licenses/>. */
+
+/* Written by Bruno Haible <bruno@clisp.org>, 2023. */
+
+#include <config.h>
+
+/* Specification. */
+#include <fenv.h>
+
+#include "macros.h"
+
+/* Test the combination of feholdexcept() with feupdateenv(). */
+
+int
+main ()
+{
+#if defined __GLIBC__ && defined __arm__ && defined __SOFTFP__
+ fputs ("Skipping test: no floating-point environment exists on this machine\n", stderr);
+ return 77;
+#else
+ fenv_t env1, env2;
+
+ /* Get to a known initial state. */
+ ASSERT (feclearexcept (FE_ALL_EXCEPT) == 0);
+
+ /* Save the current environment in env1. */
+ ASSERT (feholdexcept (&env1) == 0);
+
+ /* Modify the current environment. */
+ fesetround (FE_UPWARD);
+ int supports_tracking = (feraiseexcept (FE_INVALID | FE_OVERFLOW | FE_INEXACT) == 0);
+ int supports_trapping = (feenableexcept (FE_DIVBYZERO) != -1);
+
+ /* Save the current environment in env2. */
+ ASSERT (feholdexcept (&env2) == 0);
+
+ /* Check that the exception flags are cleared. */
+ ASSERT (fetestexcept (FE_ALL_EXCEPT) == 0);
+ /* Check that the exception trap bits are cleared. */
+ ASSERT (fegetexcept () == 0);
+
+ /* Go back to env1. */
+ ASSERT (feupdateenv (&env1) == 0);
+
+ /* Check that the rounding direction has been restored. */
+ ASSERT (fegetround () == FE_TONEAREST);
+ /* Check that the exception flags are the union of the saved and of the
+ current exception flags. (The saved exception flags and the current
+ exception flags both happen to be none in this case.) */
+ ASSERT (fetestexcept (FE_ALL_EXCEPT) == 0);
+ /* Check that the exception trap bits have been restored. */
+ ASSERT (fegetexcept () == 0);
+
+ /* Modify the rounding direction, the exception flags, and the exception
+ trap bits again. */
+ fesetround (FE_DOWNWARD);
+ ASSERT (fegetround () == FE_DOWNWARD);
+ feclearexcept (FE_OVERFLOW);
+ feraiseexcept (FE_UNDERFLOW | FE_INEXACT);
+ ASSERT (fetestexcept (FE_ALL_EXCEPT) == (supports_tracking ? FE_UNDERFLOW | FE_INEXACT : 0));
+ feenableexcept (FE_INVALID);
+ ASSERT (fegetexcept () == (supports_trapping ? FE_INVALID : 0));
+
+ /* Go back to env2. */
+ ASSERT (feupdateenv (&env2) == 0);
+
+ /* Check that the rounding direction has been restored. */
+ ASSERT (fegetround () == FE_UPWARD);
+ /* Check that the exception flags are the union of the saved and of the
+ current exception flags. */
+ ASSERT (fetestexcept (FE_ALL_EXCEPT) == (supports_tracking ? FE_INVALID | FE_OVERFLOW | FE_UNDERFLOW | FE_INEXACT : 0));
+ /* Check that the exception trap bits have been restored. */
+ ASSERT (fegetexcept () == (supports_trapping ? FE_DIVBYZERO : 0));
+
+ /* ======================================================================== */
+ /* FE_DFL_ENV */
+
+ /* Go back to the default environment. */
+ ASSERT (feupdateenv (FE_DFL_ENV) == 0);
+
+ /* Check that the rounding direction has been restored,
+ whereas the exception flags are unmodified. */
+ ASSERT (fegetround () == FE_TONEAREST);
+ ASSERT (fetestexcept (FE_ALL_EXCEPT) == (supports_tracking ? FE_INVALID | FE_OVERFLOW | FE_UNDERFLOW | FE_INEXACT : 0));
+
+ /* Enable trapping on FE_INVALID. */
+ feclearexcept (FE_INVALID);
+ feenableexcept (FE_INVALID);
+ ASSERT (fetestexcept (FE_ALL_EXCEPT) == (supports_tracking ? FE_OVERFLOW | FE_UNDERFLOW | FE_INEXACT : 0));
+
+ /* Go back to the default environment. */
+ ASSERT (feupdateenv (FE_DFL_ENV) == 0);
+
+ /* Check that the rounding direction has been restored,
+ whereas the exception flags are unmodified. */
+ ASSERT (fegetround () == FE_TONEAREST);
+ ASSERT (fetestexcept (FE_ALL_EXCEPT) == (supports_tracking ? FE_OVERFLOW | FE_UNDERFLOW | FE_INEXACT : 0));
+
+ /* Check that it has trapping on FE_INVALID disabled. */
+ ASSERT (fegetexcept () == 0);
+ {
+ double volatile a;
+ _GL_UNUSED double volatile b;
+ a = 0; b = a / a;
+ }
+
+ /* ======================================================================== */
+ /* Check that feholdexcept, unlike fegetenv, disables trapping. */
+
+ /* musl libc does not support floating-point exception trapping, even where
+ the hardware supports it. See
+ <https://wiki.musl-libc.org/functional-differences-from-glibc.html> */
+# if !MUSL_LIBC || GNULIB_FEENABLEEXCEPT
+ /* Enable trapping on FE_INVALID. */
+ feclearexcept (FE_INVALID);
+ if (feenableexcept (FE_INVALID) != -1)
+ {
+ /* Call feholdexcept. */
+ ASSERT (feholdexcept (&env1) == 0);
+
+ /* Check that it has disabled trapping on FE_INVALID. */
+ ASSERT (fegetexcept () == 0);
+ {
+ double volatile a;
+ _GL_UNUSED double volatile b;
+ a = 0; b = a / a;
+ }
+ }
+# endif
+
+ return 0;
+#endif
+}
--- /dev/null
+/* Test of controlling the floating-point environment.
+ Copyright (C) 2023 Free Software Foundation, Inc.
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <https://www.gnu.org/licenses/>. */
+
+/* Written by Bruno Haible <bruno@clisp.org>, 2023. */
+
+#include <config.h>
+
+/* Specification. */
+#include <fenv.h>
+
+#include "fpe-trapping.h"
+#include "macros.h"
+
+/* musl libc does not support floating-point exception trapping, even where
+ the hardware supports it. See
+ <https://wiki.musl-libc.org/functional-differences-from-glibc.html> */
+#if HAVE_FPE_TRAPPING && (!MUSL_LIBC || GNULIB_FEENABLEEXCEPT)
+
+/* Test that feupdateenv(), unlike fesetenv(), can trigger traps. */
+
+int
+main ()
+{
+ fenv_t env1;
+
+ /* Get to a known initial state. */
+ ASSERT (feclearexcept (FE_ALL_EXCEPT) == 0);
+
+ /* Enable trapping on FE_INVALID. */
+ if (sigfpe_on_invalid () < 0)
+ {
+ fputs ("Skipping test: trapping floating-point exceptions are not supported on this machine.\n", stderr);
+ return 77;
+ }
+
+ /* Save the current environment in env1. */
+ ASSERT (fegetenv (&env1) == 0);
+
+ /* Go back to the default environment. */
+ ASSERT (fesetenv (FE_DFL_ENV) == 0);
+
+ /* Modify the current environment. */
+ ASSERT (feraiseexcept (FE_INVALID) == 0);
+
+ /* Go back to env1.
+ Since the exceptions flag FE_INVALID is currently set, and since
+ env1 has trapping on FE_INVALID enabled, this should trap. */
+ ASSERT (feupdateenv (&env1) == 0);
+
+ return 0;
+}
+
+#else
+
+int
+main ()
+{
+ fputs ("Skipping test: feenableexcept not available\n", stderr);
+ return 77;
+}
+
+#endif
--- /dev/null
+#!/bin/sh
+
+# Test that feupdateenv() can trigger a trap.
+
+final_rc=0
+
+${CHECKER} ./test-fenv-env-5${EXEEXT}
+rc=$?
+if test $rc = 77; then
+ final_rc=77
+else
+ if test $rc = 0; then
+ echo "Failed: ./test-fenv-env-5" 1>&2
+ exit 1
+ fi
+fi
+
+exit $final_rc