# endif
 #endif
 
+// Define if float has the IEEE binary32 format.
+#if __FLT_MANT_DIG__ == 24 \
+  && __FLT_MIN_EXP__ == -125 \
+  && __FLT_MAX_EXP__ == 128
+# define _GLIBCXX_FLOAT_IS_IEEE_BINARY32 1
+#endif
+
+// Define if double has the IEEE binary64 format.
+#if __DBL_MANT_DIG__ == 53 \
+  && __DBL_MIN_EXP__ == -1021 \
+  && __DBL_MAX_EXP__ == 1024
+# define _GLIBCXX_DOUBLE_IS_IEEE_BINARY64 1
+#endif
+
 #ifdef __has_builtin
 # ifdef __is_identifier
 // Intel and older Clang require !__is_identifier for some built-ins:
 
             chars_format __fmt = chars_format::general) noexcept;
 #endif
 
+#if _GLIBCXX_FLOAT_IS_IEEE_BINARY32 && _GLIBCXX_DOUBLE_IS_IEEE_BINARY64
   // Floating-point std::to_chars
 
   // Overloads for float.
                           chars_format __fmt) noexcept;
   to_chars_result to_chars(char* __first, char* __last, long double __value,
                           chars_format __fmt, int __precision) noexcept;
+#endif
 
 _GLIBCXX_END_NAMESPACE_VERSION
 } // namespace std
 
 #include <string_view>
 #include <type_traits>
 
+// This implementation crucially assumes float/double have the
+// IEEE binary32/binary64 formats.
+#if _GLIBCXX_FLOAT_IS_IEEE_BINARY32 && _GLIBCXX_DOUBLE_IS_IEEE_BINARY64
+
 // Determine the binary format of 'long double'.
 
 // We support the binary64, float80 (i.e. x86 80-bit extended precision),
   template<>
     struct floating_type_traits<float>
     {
-      // We (and Ryu) assume float has the IEEE binary32 format.
-      static_assert(__FLT_MANT_DIG__ == 24);
       static constexpr int mantissa_bits = 23;
       static constexpr int exponent_bits = 8;
       static constexpr bool has_implicit_leading_bit = true;
   template<>
     struct floating_type_traits<double>
     {
-      // We (and Ryu) assume double has the IEEE binary64 format.
-      static_assert(__DBL_MANT_DIG__ == 53);
       static constexpr int mantissa_bits = 52;
       static constexpr int exponent_bits = 11;
       static constexpr bool has_implicit_leading_bit = true;
 
 _GLIBCXX_END_NAMESPACE_VERSION
 } // namespace std
+
+#endif // _GLIBCXX_FLOAT_IS_IEEE_BINARY32 && _GLIBCXX_DOUBLE_IS_IEEE_BINARY64
 
 // DEALINGS IN THE SOFTWARE.
 
 // { dg-do run { target c++17 } }
+// { dg-require-effective-target ieee-floats }
 
 #include <charconv>
 
 
 // DEALINGS IN THE SOFTWARE.
 
 // { dg-do run { target c++17 } }
+// { dg-require-effective-target ieee-floats }
 
 #include <charconv>
 
 
 // hexadecimal floating-point literals.
 // { dg-do run { target c++17 } }
 // { dg-xfail-run-if "Ryu needs __int128" { large_long_double && { ! int128 } } }
+// { dg-require-effective-target ieee-floats }
 
 #include <charconv>
 
 
     }]
 }
 
+# Return 1 if float and double have the IEEE binary32 and binary64 formats.
+proc check_effective_target_ieee-floats { } {
+    return [check_v3_target_prop_cached et_ieee_floats {
+       set cond "_GLIBCXX_FLOAT_IS_IEEE_BINARY32 && _GLIBCXX_DOUBLE_IS_IEEE_BINARY64"
+       return [v3_check_preprocessor_condition ieee_floats $cond]
+    }]
+}
+
 set additional_prunes ""
 
 if { [info exists env(GCC_RUNTEST_PARALLELIZE_DIR)] \