public inbox for libstdc++-cvs@sourceware.org
help / color / mirror / Atom feed
* [gcc r13-3579] libstdc++-v3: <complex> support for extended floating point types
@ 2022-10-31 19:15 Jakub Jelinek
  0 siblings, 0 replies; only message in thread
From: Jakub Jelinek @ 2022-10-31 19:15 UTC (permalink / raw)
  To: gcc-cvs, libstdc++-cvs

https://gcc.gnu.org/g:db55f1dda2692c3f778ae783bc7121891c79aec4

commit r13-3579-gdb55f1dda2692c3f778ae783bc7121891c79aec4
Author: Jakub Jelinek <jakub@redhat.com>
Date:   Mon Oct 31 20:13:02 2022 +0100

    libstdc++-v3: <complex> support for extended floating point types
    
    The following patch adds <complex> support for extended floating point
    types.
    C++23 removes the float/double/long double specializations from the spec
    and instead adds explicit(bool) specifier on the converting constructor.
    The patch uses that for converting constructor of the base template as well
    as the float/double/long double specializations's converting constructors
    (e.g. so that it handles convertion construction also from complex of extended
    floating point types).  Copy ctor was already defaulted as the spec now
    requires.
    The patch also adds partial specialization for the _Float{16,32,64,128}
    and __gnu_cxx::__bfloat16_t types because the base template doesn't use
    __complex__ but a pair of floating point values.
    The g++.dg/cpp23/ testcase verifies explicit(bool) works correctly.
    
    2022-10-31  Jakub Jelinek  <jakub@redhat.com>
    
    gcc/testsuite/
            * g++.dg/cpp23/ext-floating12.C: New test.
    libstdc++-v3/
            * include/std/complex (complex::complex converting ctor): For C++23
            use explicit specifier with constant expression.  Explicitly cast
            both parts to _Tp.
            (__complex_abs, __complex_arg, __complex_cos, __complex_cosh,
            __complex_exp, __complex_log, __complex_sin, __complex_sinh,
            __complex_sqrt, __complex_tan, __complex_tanh, __complex_pow): Add
            __complex__ _Float{16,32,64,128} and __complex__ decltype(0.0bf16)
            overloads.
            (complex<float>::complex converting ctor,
            complex<double>::complex converting ctor,
            complex<long double>::complex converting ctor): For C++23 implement
            as template with explicit specifier with constant expression
            and explicit casts.
            (__complex_type): New template.
            (complex): New partial specialization for types with extended floating
            point types.
            (__complex_acos, __complex_asin, __complex_atan, __complex_acosh,
            __complex_asinh, __complex_atanh): Add __complex__ _Float{16,32,64,128}
            and __complex__ decltype(0.0bf16) overloads.
            (__complex_proj): Likewise.  Add template for complex of extended
            floating point types.
            * include/bits/cpp_type_traits.h (__is_floating): Specialize for
            _Float{16,32,64,128} and __gnu_cxx::__bfloat16_t.
            * testsuite/26_numerics/complex/ext_c++23.cc: New test.

Diff:
---
 gcc/testsuite/g++.dg/cpp23/ext-floating12.C        | 182 ++++++
 libstdc++-v3/include/bits/cpp_type_traits.h        |  45 ++
 libstdc++-v3/include/std/complex                   | 641 ++++++++++++++++++++-
 .../testsuite/26_numerics/complex/ext_c++23.cc     |  89 +++
 4 files changed, 955 insertions(+), 2 deletions(-)

diff --git a/gcc/testsuite/g++.dg/cpp23/ext-floating12.C b/gcc/testsuite/g++.dg/cpp23/ext-floating12.C
new file mode 100644
index 00000000000..77ee4c70a93
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp23/ext-floating12.C
@@ -0,0 +1,182 @@
+// P1467R9 - Extended floating-point types and standard names.
+// { dg-do compile { target { c++23 && { i?86-*-linux* x86_64-*-linux* } } } }
+// { dg-options "" }
+
+#include <complex>
+#include <stdfloat>
+
+#if !defined(__STDCPP_FLOAT32_T__) \
+    || !defined(__STDCPP_FLOAT64_T__) || !defined(__STDCPP_FLOAT128_T__) \
+    || __FLT_MAX_EXP__ != __FLT32_MAX_EXP__ || __FLT_MANT_DIG__ != __FLT32_MANT_DIG__ \
+    || __DBL_MAX_EXP__ != __FLT64_MAX_EXP__ || __DBL_MANT_DIG__ != __FLT64_MANT_DIG__ \
+    || __LDBL_MAX_EXP__ != __FLT128_MAX_EXP__ || __LDBL_MANT_DIG__ >= __FLT128_MANT_DIG__ \
+    || !defined(__SIZEOF_FLOAT128__)
+#error Unexpected set of floating point types
+#endif
+
+using namespace std;
+
+int
+main()
+{
+  complex<float> a01(complex<float>(1.0f, 2.0f));
+  complex<float> a02 = complex<float>(1.0f, 2.0f);
+  complex<float> a03(complex<double>(1.0, 2.0));
+  complex<float> a04 = complex<double>(1.0, 2.0);			// { dg-error "conversion from 'complex<double>' to non-scalar type 'complex<float>' requested" }
+  complex<float> a05(complex<long double>(1.0L, 2.0L));
+  complex<float> a06 = complex<long double>(1.0L, 2.0L);		// { dg-error "conversion from 'complex<long double>' to non-scalar type 'complex<float>' requested" }
+  complex<float> a07(complex<float32_t>(1.0f32, 2.0f32));
+  complex<float> a08 = complex<float32_t>(1.0f32, 2.0f32);
+  complex<float> a09(complex<float64_t>(1.0f64, 2.0f64));
+  complex<float> a10 = complex<float64_t>(1.0f64, 2.0f64);		// { dg-error "conversion from 'complex<_Float64>' to non-scalar type 'complex<float>' requested" }
+  complex<float> a11(complex<float128_t>(1.0f128, 2.0f128));
+  complex<float> a12 = complex<float128_t>(1.0f128, 2.0f128);		// { dg-error "conversion from 'complex<_Float128>' to non-scalar type 'complex<float>' requested" }
+#ifdef __STDCPP_FLOAT16_T__
+  complex<float> a13(complex<float16_t>(1.0f16, 2.0f16));
+  complex<float> a14 = complex<float16_t>(1.0f16, 2.0f16);
+#endif
+#ifdef __STDCPP_BFLOAT16_T__
+  complex<float> a15(complex<bfloat16_t>(1.0bf16, 2.0bf16));
+  complex<float> a16 = complex<bfloat16_t>(1.0bf16, 2.0bf16);
+#endif
+  complex<double> b01(complex<float>(1.0f, 2.0f));
+  complex<double> b02 = complex<float>(1.0f, 2.0f);
+  complex<double> b03(complex<double>(1.0, 2.0));
+  complex<double> b04 = complex<double>(1.0, 2.0);
+  complex<double> b05(complex<long double>(1.0L, 2.0L));
+  complex<double> b06 = complex<long double>(1.0L, 2.0L);		// { dg-error "conversion from 'complex<long double>' to non-scalar type 'complex<double>' requested" }
+  complex<double> b07(complex<float32_t>(1.0f32, 2.0f32));
+  complex<double> b08 = complex<float32_t>(1.0f32, 2.0f32);
+  complex<double> b09(complex<float64_t>(1.0f64, 2.0f64));
+  complex<double> b10 = complex<float64_t>(1.0f64, 2.0f64);
+  complex<double> b11(complex<float128_t>(1.0f128, 2.0f128));
+  complex<double> b12 = complex<float128_t>(1.0f128, 2.0f128);		// { dg-error "conversion from 'complex<_Float128>' to non-scalar type 'complex<double>' requested" }
+#ifdef __STDCPP_FLOAT16_T__
+  complex<double> b13(complex<float16_t>(1.0f16, 2.0f16));
+  complex<double> b14 = complex<float16_t>(1.0f16, 2.0f16);
+#endif
+#ifdef __STDCPP_BFLOAT16_T__
+  complex<double> b15(complex<bfloat16_t>(1.0bf16, 2.0bf16));
+  complex<double> b16 = complex<bfloat16_t>(1.0bf16, 2.0bf16);
+#endif
+  complex<long double> c01(complex<float>(1.0f, 2.0f));
+  complex<long double> c02 = complex<float>(1.0f, 2.0f);
+  complex<long double> c03(complex<double>(1.0, 2.0));
+  complex<long double> c04 = complex<double>(1.0, 2.0);
+  complex<long double> c05(complex<long double>(1.0L, 2.0L));
+  complex<long double> c06 = complex<long double>(1.0L, 2.0L);
+  complex<long double> c07(complex<float32_t>(1.0f32, 2.0f32));
+  complex<long double> c08 = complex<float32_t>(1.0f32, 2.0f32);
+  complex<long double> c09(complex<float64_t>(1.0f64, 2.0f64));
+  complex<long double> c10 = complex<float64_t>(1.0f64, 2.0f64);
+  complex<long double> c11(complex<float128_t>(1.0f128, 2.0f128));
+  complex<long double> c12 = complex<float128_t>(1.0f128, 2.0f128);	// { dg-error "conversion from 'complex<_Float128>' to non-scalar type 'complex<long double>' requested" }
+#ifdef __STDCPP_FLOAT16_T__
+  complex<long double> c13(complex<float16_t>(1.0f16, 2.0f16));
+  complex<long double> c14 = complex<float16_t>(1.0f16, 2.0f16);
+#endif
+#ifdef __STDCPP_BFLOAT16_T__
+  complex<long double> c15(complex<bfloat16_t>(1.0bf16, 2.0bf16));
+  complex<long double> c16 = complex<bfloat16_t>(1.0bf16, 2.0bf16);
+#endif
+  complex<float32_t> d01(complex<float>(1.0f, 2.0f));
+  complex<float32_t> d02 = complex<float>(1.0f, 2.0f);
+  complex<float32_t> d03(complex<double>(1.0, 2.0));
+  complex<float32_t> d04 = complex<double>(1.0, 2.0);			// { dg-error "conversion from 'complex<double>' to non-scalar type 'complex<_Float32>' requested" }
+  complex<float32_t> d05(complex<long double>(1.0L, 2.0L));
+  complex<float32_t> d06 = complex<long double>(1.0L, 2.0L);		// { dg-error "conversion from 'complex<long double>' to non-scalar type 'complex<_Float32>' requested" }
+  complex<float32_t> d07(complex<float32_t>(1.0f32, 2.0f32));
+  complex<float32_t> d08 = complex<float32_t>(1.0f32, 2.0f32);
+  complex<float32_t> d09(complex<float64_t>(1.0f64, 2.0f64));
+  complex<float32_t> d10 = complex<float64_t>(1.0f64, 2.0f64);		// { dg-error "conversion from 'complex<_Float64>' to non-scalar type 'complex<_Float32>' requested" }
+  complex<float32_t> d11(complex<float128_t>(1.0f128, 2.0f128));
+  complex<float32_t> d12 = complex<float128_t>(1.0f128, 2.0f128);	// { dg-error "conversion from 'complex<_Float128>' to non-scalar type 'complex<_Float32>' requested" }
+#ifdef __STDCPP_FLOAT16_T__
+  complex<float32_t> d13(complex<float16_t>(1.0f16, 2.0f16));
+  complex<float32_t> d14 = complex<float16_t>(1.0f16, 2.0f16);
+#endif
+#ifdef __STDCPP_BFLOAT16_T__
+  complex<float32_t> d15(complex<bfloat16_t>(1.0bf16, 2.0bf16));
+  complex<float32_t> d16 = complex<bfloat16_t>(1.0bf16, 2.0bf16);
+#endif
+  complex<float64_t> e01(complex<float>(1.0f, 2.0f));
+  complex<float64_t> e02 = complex<float>(1.0f, 2.0f);
+  complex<float64_t> e03(complex<double>(1.0, 2.0));
+  complex<float64_t> e04 = complex<double>(1.0, 2.0);
+  complex<float64_t> e05(complex<long double>(1.0L, 2.0L));
+  complex<float64_t> e06 = complex<long double>(1.0L, 2.0L);		// { dg-error "conversion from 'complex<long double>' to non-scalar type 'complex<_Float64>' requested" }
+  complex<float64_t> e07(complex<float32_t>(1.0f32, 2.0f32));
+  complex<float64_t> e08 = complex<float32_t>(1.0f32, 2.0f32);
+  complex<float64_t> e09(complex<float64_t>(1.0f64, 2.0f64));
+  complex<float64_t> e10 = complex<float64_t>(1.0f64, 2.0f64);
+  complex<float64_t> e11(complex<float128_t>(1.0f128, 2.0f128));
+  complex<float64_t> e12 = complex<float128_t>(1.0f128, 2.0f128);	// { dg-error "conversion from 'complex<_Float128>' to non-scalar type 'complex<_Float64>' requested" }
+#ifdef __STDCPP_FLOAT16_T__
+  complex<float64_t> e13(complex<float16_t>(1.0f16, 2.0f16));
+  complex<float64_t> e14 = complex<float16_t>(1.0f16, 2.0f16);
+#endif
+#ifdef __STDCPP_BFLOAT16_T__
+  complex<float64_t> e15(complex<bfloat16_t>(1.0bf16, 2.0bf16));
+  complex<float64_t> e16 = complex<bfloat16_t>(1.0bf16, 2.0bf16);
+#endif
+  complex<float128_t> f01(complex<float>(1.0f, 2.0f));
+  complex<float128_t> f02 = complex<float>(1.0f, 2.0f);
+  complex<float128_t> f03(complex<double>(1.0, 2.0));
+  complex<float128_t> f04 = complex<double>(1.0, 2.0);
+  complex<float128_t> f05(complex<long double>(1.0L, 2.0L));
+  complex<float128_t> f06 = complex<long double>(1.0L, 2.0L);
+  complex<float128_t> f07(complex<float32_t>(1.0f32, 2.0f32));
+  complex<float128_t> f08 = complex<float32_t>(1.0f32, 2.0f32);
+  complex<float128_t> f09(complex<float64_t>(1.0f64, 2.0f64));
+  complex<float128_t> f10 = complex<float64_t>(1.0f64, 2.0f64);
+  complex<float128_t> f11(complex<float128_t>(1.0f128, 2.0f128));
+  complex<float128_t> f12 = complex<float128_t>(1.0f128, 2.0f128);
+#ifdef __STDCPP_FLOAT16_T__
+  complex<float128_t> f13(complex<float16_t>(1.0f16, 2.0f16));
+  complex<float128_t> f14 = complex<float16_t>(1.0f16, 2.0f16);
+#endif
+#ifdef __STDCPP_BFLOAT16_T__
+  complex<float128_t> f15(complex<bfloat16_t>(1.0bf16, 2.0bf16));
+  complex<float128_t> f16 = complex<bfloat16_t>(1.0bf16, 2.0bf16);
+#endif
+#ifdef __STDCPP_FLOAT16_T__
+  complex<float16_t> g01(complex<float>(1.0f, 2.0f));
+  complex<float16_t> g02 = complex<float>(1.0f, 2.0f);			// { dg-error "conversion from 'complex<float>' to non-scalar type 'complex<_Float16>' requested" "" { target float16 } }
+  complex<float16_t> g03(complex<double>(1.0, 2.0));
+  complex<float16_t> g04 = complex<double>(1.0, 2.0);			// { dg-error "conversion from 'complex<double>' to non-scalar type 'complex<_Float16>' requested" "" { target float16 } }
+  complex<float16_t> g05(complex<long double>(1.0L, 2.0L));
+  complex<float16_t> g06 = complex<long double>(1.0L, 2.0L);		// { dg-error "conversion from 'complex<long double>' to non-scalar type 'complex<_Float16>' requested" "" { target float16 } }
+  complex<float16_t> g07(complex<float32_t>(1.0f32, 2.0f32));
+  complex<float16_t> g08 = complex<float32_t>(1.0f32, 2.0f32);		// { dg-error "conversion from 'complex<_Float32>' to non-scalar type 'complex<_Float16>' requested" "" { target float16 } }
+  complex<float16_t> g09(complex<float64_t>(1.0f64, 2.0f64));
+  complex<float16_t> g10 = complex<float64_t>(1.0f64, 2.0f64);		// { dg-error "conversion from 'complex<_Float64>' to non-scalar type 'complex<_Float16>' requested" "" { target float16 } }
+  complex<float16_t> g11(complex<float128_t>(1.0f128, 2.0f128));
+  complex<float16_t> g12 = complex<float128_t>(1.0f128, 2.0f128);	// { dg-error "conversion from 'complex<_Float128>' to non-scalar type 'complex<_Float16>' requested" "" { target float16 } }
+  complex<float16_t> g13(complex<float16_t>(1.0f16, 2.0f16));
+  complex<float16_t> g14 = complex<float16_t>(1.0f16, 2.0f16);
+#ifdef __STDCPP_BFLOAT16_T__
+  complex<float16_t> g15(complex<bfloat16_t>(1.0bf16, 2.0bf16));
+  complex<float16_t> g16 = complex<bfloat16_t>(1.0bf16, 2.0bf16);	// { dg-error "conversion from 'complex<\[^\n\r]*>' to non-scalar type 'complex<_Float16>' requested" "" { target { float16 && bfloat16 } } }
+#endif
+#endif
+#ifdef __STDCPP_BFLOAT16_T__
+  complex<bfloat16_t> h01(complex<float>(1.0f, 2.0f));
+  complex<bfloat16_t> h02 = complex<float>(1.0f, 2.0f);			// { dg-error "conversion from 'complex<float>' to non-scalar type 'complex<\[^\n\r]*>' requested" "" { target bfloat16 } }
+  complex<bfloat16_t> h03(complex<double>(1.0, 2.0));
+  complex<bfloat16_t> h04 = complex<double>(1.0, 2.0);			// { dg-error "conversion from 'complex<double>' to non-scalar type 'complex<\[^\n\r]*>' requested" "" { target bfloat16 } }
+  complex<bfloat16_t> h05(complex<long double>(1.0L, 2.0L));
+  complex<bfloat16_t> h06 = complex<long double>(1.0L, 2.0L);		// { dg-error "conversion from 'complex<long double>' to non-scalar type 'complex<\[^\n\r]*>' requested" "" { target bfloat16 } }
+  complex<bfloat16_t> h07(complex<float32_t>(1.0f32, 2.0f32));
+  complex<bfloat16_t> h08 = complex<float32_t>(1.0f32, 2.0f32);		// { dg-error "conversion from 'complex<_Float32>' to non-scalar type 'complex<\[^\n\r]*>' requested" "" { target bfloat16 } }
+  complex<bfloat16_t> h09(complex<float64_t>(1.0f64, 2.0f64));
+  complex<bfloat16_t> h10 = complex<float64_t>(1.0f64, 2.0f64);		// { dg-error "conversion from 'complex<_Float64>' to non-scalar type 'complex<\[^\n\r]*>' requested" "" { target bfloat16 } }
+  complex<bfloat16_t> h11(complex<float128_t>(1.0f128, 2.0f128));
+  complex<bfloat16_t> h12 = complex<float128_t>(1.0f128, 2.0f128);	// { dg-error "conversion from 'complex<_Float128>' to non-scalar type 'complex<\[^\n\r]*>' requested" "" { target bfloat16 } }
+#ifdef __STDCPP_FLOAT16_T__
+  complex<bfloat16_t> h13(complex<float16_t>(1.0f16, 2.0f16));
+  complex<bfloat16_t> h14 = complex<float16_t>(1.0f16, 2.0f16);		// { dg-error "conversion from 'complex<_Float16>' to non-scalar type 'complex<\[^\n\r]*>' requested" "" { target { float16 && bfloat16 } } }
+#endif
+  complex<bfloat16_t> h15(complex<bfloat16_t>(1.0bf16, 2.0bf16));
+  complex<bfloat16_t> h16 = complex<bfloat16_t>(1.0bf16, 2.0bf16);
+#endif
+}
diff --git a/libstdc++-v3/include/bits/cpp_type_traits.h b/libstdc++-v3/include/bits/cpp_type_traits.h
index 8f91bbedbed..592673a1d11 100644
--- a/libstdc++-v3/include/bits/cpp_type_traits.h
+++ b/libstdc++-v3/include/bits/cpp_type_traits.h
@@ -315,6 +315,51 @@ __INT_N(__GLIBCXX_TYPE_INT_N_3)
       typedef __true_type __type;
     };
 
+#ifdef __STDCPP_FLOAT16_T__
+  template<>
+    struct __is_floating<_Float16>
+    {
+      enum { __value = 1 };
+      typedef __true_type __type;
+    };
+#endif
+
+#ifdef __STDCPP_FLOAT32_T__
+  template<>
+    struct __is_floating<_Float32>
+    {
+      enum { __value = 1 };
+      typedef __true_type __type;
+    };
+#endif
+
+#ifdef __STDCPP_FLOAT64_T__
+  template<>
+    struct __is_floating<_Float64>
+    {
+      enum { __value = 1 };
+      typedef __true_type __type;
+    };
+#endif
+
+#ifdef __STDCPP_FLOAT128_T__
+  template<>
+    struct __is_floating<_Float128>
+    {
+      enum { __value = 1 };
+      typedef __true_type __type;
+    };
+#endif
+
+#ifdef __STDCPP_BFLOAT16_T__
+  template<>
+    struct __is_floating<__gnu_cxx::__bfloat16_t>
+    {
+      enum { __value = 1 };
+      typedef __true_type __type;
+    };
+#endif
+
   //
   // Pointer types
   //
diff --git a/libstdc++-v3/include/std/complex b/libstdc++-v3/include/std/complex
index 8f9368fd7d0..da2df912ecc 100644
--- a/libstdc++-v3/include/std/complex
+++ b/libstdc++-v3/include/std/complex
@@ -142,8 +142,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
       ///  Converting constructor.
       template<typename _Up>
-        _GLIBCXX_CONSTEXPR complex(const complex<_Up>& __z)
-	: _M_real(__z.real()), _M_imag(__z.imag()) { }
+#if __cplusplus > 202002L
+	explicit(!requires(_Up __u) { _Tp{__u}; })
+#endif
+	_GLIBCXX_CONSTEXPR complex(const complex<_Up>& __z)
+	: _M_real(_Tp(__z.real())), _M_imag(_Tp(__z.imag())) { }
 
 #if __cplusplus >= 201103L
       // _GLIBCXX_RESOLVE_LIB_DEFECTS
@@ -1077,6 +1080,264 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 	                 : std::pow(complex<_Tp>(__x), __y);
     }
 
+#if _GLIBCXX_USE_C99_COMPLEX
+#if defined(__STDCPP_FLOAT16_T__) && defined(_GLIBCXX_FLOAT_IS_IEEE_BINARY32)
+  inline _Float16
+  __complex_abs(__complex__ _Float16 __z)
+  { return _Float16(__builtin_cabsf(__z)); }
+
+  inline _Float16
+  __complex_arg(__complex__ _Float16 __z)
+  { return _Float16(__builtin_cargf(__z)); }
+
+  inline __complex__ _Float16
+  __complex_cos(__complex__ _Float16 __z)
+  { return static_cast<__complex__ _Float16>(__builtin_ccosf(__z)); }
+
+  inline __complex__ _Float16
+  __complex_cosh(__complex__ _Float16 __z)
+  { return static_cast<__complex__ _Float16>(__builtin_ccoshf(__z)); }
+
+  inline __complex__ _Float16
+  __complex_exp(__complex__ _Float16 __z)
+  { return static_cast<__complex__ _Float16>(__builtin_cexpf(__z)); }
+
+  inline __complex__ _Float16
+  __complex_log(__complex__ _Float16 __z)
+  { return static_cast<__complex__ _Float16>(__builtin_clogf(__z)); }
+
+  inline __complex__ _Float16
+  __complex_sin(__complex__ _Float16 __z)
+  { return static_cast<__complex__ _Float16>(__builtin_csinf(__z)); }
+
+  inline __complex__ _Float16
+  __complex_sinh(__complex__ _Float16 __z)
+  { return static_cast<__complex__ _Float16>(__builtin_csinhf(__z)); }
+
+  inline __complex__ _Float16
+  __complex_sqrt(__complex__ _Float16 __z)
+  { return static_cast<__complex__ _Float16>(__builtin_csqrtf(__z)); }
+
+  inline __complex__ _Float16
+  __complex_tan(__complex__ _Float16 __z)
+  { return static_cast<__complex__ _Float16>(__builtin_ctanf(__z)); }
+
+  inline __complex__ _Float16
+  __complex_tanh(__complex__ _Float16 __z)
+  { return static_cast<__complex__ _Float16>(__builtin_ctanhf(__z)); }
+
+  inline __complex__ _Float16
+  __complex_pow(__complex__ _Float16 __x, __complex__ _Float16 __y)
+  { return static_cast<__complex__ _Float16>(__builtin_cpowf(__x, __y)); }
+#endif
+
+#if defined(__STDCPP_FLOAT32_T__) && defined(_GLIBCXX_FLOAT_IS_IEEE_BINARY32)
+  inline _Float32
+  __complex_abs(__complex__ _Float32 __z) { return __builtin_cabsf(__z); }
+
+  inline _Float32
+  __complex_arg(__complex__ _Float32 __z) { return __builtin_cargf(__z); }
+
+  inline __complex__ _Float32
+  __complex_cos(__complex__ _Float32 __z) { return __builtin_ccosf(__z); }
+
+  inline __complex__ _Float32
+  __complex_cosh(__complex__ _Float32 __z) { return __builtin_ccoshf(__z); }
+
+  inline __complex__ _Float32
+  __complex_exp(__complex__ _Float32 __z) { return __builtin_cexpf(__z); }
+
+  inline __complex__ _Float32
+  __complex_log(__complex__ _Float32 __z) { return __builtin_clogf(__z); }
+
+  inline __complex__ _Float32
+  __complex_sin(__complex__ _Float32 __z) { return __builtin_csinf(__z); }
+
+  inline __complex__ _Float32
+  __complex_sinh(__complex__ _Float32 __z) { return __builtin_csinhf(__z); }
+
+  inline __complex__ _Float32
+  __complex_sqrt(__complex__ _Float32 __z) { return __builtin_csqrtf(__z); }
+
+  inline __complex__ _Float32
+  __complex_tan(__complex__ _Float32 __z) { return __builtin_ctanf(__z); }
+
+  inline __complex__ _Float32
+  __complex_tanh(__complex__ _Float32 __z) { return __builtin_ctanhf(__z); }
+
+  inline __complex__ _Float32
+  __complex_pow(__complex__ _Float32 __x, __complex__ _Float32 __y)
+  { return __builtin_cpowf(__x, __y); }
+#endif
+
+#if defined(__STDCPP_FLOAT64_T__) && defined(_GLIBCXX_DOUBLE_IS_IEEE_BINARY64)
+  inline _Float64
+  __complex_abs(__complex__ _Float64 __z) { return __builtin_cabs(__z); }
+
+  inline _Float64
+  __complex_arg(__complex__ _Float64 __z) { return __builtin_carg(__z); }
+
+  inline __complex__ _Float64
+  __complex_cos(__complex__ _Float64 __z) { return __builtin_ccos(__z); }
+
+  inline __complex__ _Float64
+  __complex_cosh(__complex__ _Float64 __z) { return __builtin_ccosh(__z); }
+
+  inline __complex__ _Float64
+  __complex_exp(__complex__ _Float64 __z) { return __builtin_cexp(__z); }
+
+  inline __complex__ _Float64
+  __complex_log(__complex__ _Float64 __z) { return __builtin_clog(__z); }
+
+  inline __complex__ _Float64
+  __complex_sin(__complex__ _Float64 __z) { return __builtin_csin(__z); }
+
+  inline __complex__ _Float64
+  __complex_sinh(__complex__ _Float64 __z) { return __builtin_csinh(__z); }
+
+  inline __complex__ _Float64
+  __complex_sqrt(__complex__ _Float64 __z) { return __builtin_csqrt(__z); }
+
+  inline __complex__ _Float64
+  __complex_tan(__complex__ _Float64 __z) { return __builtin_ctan(__z); }
+
+  inline __complex__ _Float64
+  __complex_tanh(__complex__ _Float64 __z) { return __builtin_ctanh(__z); }
+
+  inline __complex__ _Float64
+  __complex_pow(__complex__ _Float64 __x, __complex__ _Float64 __y)
+  { return __builtin_cpow(__x, __y); }
+#endif
+
+#if defined(__STDCPP_FLOAT128_T__) && defined(_GLIBCXX_LDOUBLE_IS_IEEE_BINARY128)
+  inline _Float128
+  __complex_abs(__complex__ _Float128 __z) { return __builtin_cabsl(__z); }
+
+  inline _Float128
+  __complex_arg(__complex__ _Float128 __z) { return __builtin_cargl(__z); }
+
+  inline __complex__ _Float128
+  __complex_cos(__complex__ _Float128 __z) { return __builtin_ccosl(__z); }
+
+  inline __complex__ _Float128
+  __complex_cosh(__complex__ _Float128 __z) { return __builtin_ccoshl(__z); }
+
+  inline __complex__ _Float128
+  __complex_exp(__complex__ _Float128 __z) { return __builtin_cexpl(__z); }
+
+  inline __complex__ _Float128
+  __complex_log(__complex__ _Float128 __z) { return __builtin_clogl(__z); }
+
+  inline __complex__ _Float128
+  __complex_sin(__complex__ _Float128 __z) { return __builtin_csinl(__z); }
+
+  inline __complex__ _Float128
+  __complex_sinh(__complex__ _Float128 __z) { return __builtin_csinhl(__z); }
+
+  inline __complex__ _Float128
+  __complex_sqrt(__complex__ _Float128 __z) { return __builtin_csqrtl(__z); }
+
+  inline __complex__ _Float128
+  __complex_tan(__complex__ _Float128 __z) { return __builtin_ctanl(__z); }
+
+  inline __complex__ _Float128
+  __complex_tanh(__complex__ _Float128 __z) { return __builtin_ctanhl(__z); }
+
+  inline __complex__ _Float128
+  __complex_pow(__complex__ _Float128 __x, __complex__ _Float128 __y)
+  { return __builtin_cpowl(__x, __y); }
+#elif defined(__STDCPP_FLOAT128_T__) && defined(_GLIBCXX_HAVE_FLOAT128_MATH)
+  inline _Float128
+  __complex_abs(__complex__ _Float128 __z) { return __builtin_cabsf128(__z); }
+
+  inline _Float128
+  __complex_arg(__complex__ _Float128 __z) { return __builtin_cargf128(__z); }
+
+  inline __complex__ _Float128
+  __complex_cos(__complex__ _Float128 __z) { return __builtin_ccosf128(__z); }
+
+  inline __complex__ _Float128
+  __complex_cosh(__complex__ _Float128 __z) { return __builtin_ccoshf128(__z); }
+
+  inline __complex__ _Float128
+  __complex_exp(__complex__ _Float128 __z) { return __builtin_cexpf128(__z); }
+
+  inline __complex__ _Float128
+  __complex_log(__complex__ _Float128 __z) { return __builtin_clogf128(__z); }
+
+  inline __complex__ _Float128
+  __complex_sin(__complex__ _Float128 __z) { return __builtin_csinf128(__z); }
+
+  inline __complex__ _Float128
+  __complex_sinh(__complex__ _Float128 __z) { return __builtin_csinhf128(__z); }
+
+  inline __complex__ _Float128
+  __complex_sqrt(__complex__ _Float128 __z) { return __builtin_csqrtf128(__z); }
+
+  inline __complex__ _Float128
+  __complex_tan(__complex__ _Float128 __z) { return __builtin_ctanf128(__z); }
+
+  inline __complex__ _Float128
+  __complex_tanh(__complex__ _Float128 __z) { return __builtin_ctanhf128(__z); }
+
+  inline __complex__ _Float128
+  __complex_pow(__complex__ _Float128 __x, __complex__ _Float128 __y)
+  { return __builtin_cpowf128(__x, __y); }
+#endif
+
+#if defined(__STDCPP_BFLOAT16_T__) && defined(_GLIBCXX_FLOAT_IS_IEEE_BINARY32)
+  inline __gnu_cxx::__bfloat16_t
+  __complex_abs(__complex__ decltype(0.0bf16) __z)
+  { return __gnu_cxx::__bfloat16_t(__builtin_cabsf(__z)); }
+
+  inline __gnu_cxx::__bfloat16_t
+  __complex_arg(__complex__ decltype(0.0bf16) __z)
+  { return __gnu_cxx::__bfloat16_t(__builtin_cargf(__z)); }
+
+  inline __complex__ decltype(0.0bf16)
+  __complex_cos(__complex__ decltype(0.0bf16) __z)
+  { return static_cast<__complex__ decltype(0.0bf16)>(__builtin_ccosf(__z)); }
+
+  inline __complex__ decltype(0.0bf16)
+  __complex_cosh(__complex__ decltype(0.0bf16) __z)
+  { return static_cast<__complex__ decltype(0.0bf16)>(__builtin_ccoshf(__z)); }
+
+  inline __complex__ decltype(0.0bf16)
+  __complex_exp(__complex__ decltype(0.0bf16) __z)
+  { return static_cast<__complex__ decltype(0.0bf16)>(__builtin_cexpf(__z)); }
+
+  inline __complex__ decltype(0.0bf16)
+  __complex_log(__complex__ decltype(0.0bf16) __z)
+  { return static_cast<__complex__ decltype(0.0bf16)>(__builtin_clogf(__z)); }
+
+  inline __complex__ decltype(0.0bf16)
+  __complex_sin(__complex__ decltype(0.0bf16) __z)
+  { return static_cast<__complex__ decltype(0.0bf16)>(__builtin_csinf(__z)); }
+
+  inline __complex__ decltype(0.0bf16)
+  __complex_sinh(__complex__ decltype(0.0bf16) __z)
+  { return static_cast<__complex__ decltype(0.0bf16)>(__builtin_csinhf(__z)); }
+
+  inline __complex__ decltype(0.0bf16)
+  __complex_sqrt(__complex__ decltype(0.0bf16) __z)
+  { return static_cast<__complex__ decltype(0.0bf16)>(__builtin_csqrtf(__z)); }
+
+  inline __complex__ decltype(0.0bf16)
+  __complex_tan(__complex__ decltype(0.0bf16) __z)
+  { return static_cast<__complex__ decltype(0.0bf16)>(__builtin_ctanf(__z)); }
+
+  inline __complex__ decltype(0.0bf16)
+  __complex_tanh(__complex__ decltype(0.0bf16) __z)
+  { return static_cast<__complex__ decltype(0.0bf16)>(__builtin_ctanhf(__z)); }
+
+  inline __complex__ decltype(0.0bf16)
+  __complex_pow(__complex__ decltype(0.0bf16) __x,
+		__complex__ decltype(0.0bf16) __y)
+  { return static_cast<__complex__ decltype(0.0bf16)>(__builtin_cpowf(__x,
+								      __y)); }
+#endif
+#endif
+
   /// 26.2.3  complex specializations
   /// complex<float> specialization
   template<>
@@ -1098,8 +1359,15 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       }
 #endif
 
+#if __cplusplus > 202002L
+      template<typename _Up>
+	explicit(!requires(_Up __u) { value_type{__u}; })
+	constexpr complex(const complex<_Up>& __z)
+	: _M_value{ value_type(__z.real()), value_type(__z.imag()) } { }
+#else
       explicit _GLIBCXX_CONSTEXPR complex(const complex<double>&);
       explicit _GLIBCXX_CONSTEXPR complex(const complex<long double>&);
+#endif
 
 #if __cplusplus >= 201103L
       // _GLIBCXX_RESOLVE_LIB_DEFECTS
@@ -1244,10 +1512,17 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       }
 #endif
 
+#if __cplusplus > 202002L
+      template<typename _Up>
+	explicit(!requires(_Up __u) { value_type{__u}; })
+	constexpr complex(const complex<_Up>& __z)
+	: _M_value{ value_type(__z.real()), value_type(__z.imag()) } { }
+#else
       _GLIBCXX_CONSTEXPR complex(const complex<float>& __z)
       : _M_value(__z.__rep()) { }
 
       explicit _GLIBCXX_CONSTEXPR complex(const complex<long double>&);
+#endif
 
 #if __cplusplus >= 201103L
       // _GLIBCXX_RESOLVE_LIB_DEFECTS
@@ -1391,11 +1666,18 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       }
 #endif
 
+#if __cplusplus > 202002L
+      template<typename _Up>
+	explicit(!requires(_Up __u) { value_type{__u}; })
+	constexpr complex(const complex<_Up>& __z)
+	: _M_value{ value_type(__z.real()), value_type(__z.imag()) } { }
+#else
       _GLIBCXX_CONSTEXPR complex(const complex<float>& __z)
       : _M_value(__z.__rep()) { }
 
       _GLIBCXX_CONSTEXPR complex(const complex<double>& __z)
       : _M_value(__z.__rep()) { }
+#endif
 
 #if __cplusplus >= 201103L
       // _GLIBCXX_RESOLVE_LIB_DEFECTS
@@ -1517,6 +1799,161 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       _ComplexT _M_value;
     };
 
+#if __cplusplus > 202002L
+  template<typename _Tp>
+    struct __complex_type
+    { };
+
+#ifdef __STDCPP_FLOAT16_T__
+  template<>
+    struct __complex_type<_Float16>
+    { typedef __complex__ _Float16 type; };
+#endif
+
+#ifdef __STDCPP_FLOAT32_T__
+  template<>
+    struct __complex_type<_Float32>
+    { typedef __complex__ _Float32 type; };
+#endif
+
+#ifdef __STDCPP_FLOAT64_T__
+  template<>
+    struct __complex_type<_Float64>
+    { typedef __complex__ _Float64 type; };
+#endif
+
+#ifdef __STDCPP_FLOAT128_T__
+  template<>
+    struct __complex_type<_Float128>
+    { typedef __complex__ _Float128 type; };
+#endif
+
+#ifdef __STDCPP_BFLOAT16_T__
+  template<>
+    struct __complex_type<__gnu_cxx::__bfloat16_t>
+    { typedef __complex__ decltype(0.0bf16) type; };
+#endif
+
+  template<typename _Tp>
+    requires(__complex_type<_Tp>::type)
+    class complex<_Tp>
+    {
+    public:
+      typedef _Tp value_type;
+      typedef std::__complex_type<_Tp>::type _ComplexT;
+
+      constexpr complex(_ComplexT __z) : _M_value(__z) { }
+
+      constexpr complex(_Tp __r = _Tp(), _Tp __i = _Tp())
+      : _M_value{ __r, __i } { }
+
+      template<typename _Up>
+	explicit(!requires(_Up __u) { value_type{__u}; })
+	constexpr complex(const complex<_Up>& __z)
+	: _M_value{ value_type(__z.real()), value_type(__z.imag()) } { }
+
+      constexpr _Tp
+      real() const { return __real__ _M_value; }
+
+      constexpr _Tp
+      imag() const { return __imag__ _M_value; }
+
+      constexpr void
+      real(_Tp __val) { __real__ _M_value = __val; }
+
+      constexpr void
+      imag(_Tp __val) { __imag__ _M_value = __val; }
+
+      constexpr complex&
+      operator=(_Tp __f)
+      {
+	_M_value = __f;
+	return *this;
+      }
+
+      constexpr complex&
+      operator+=(_Tp __f)
+      {
+	_M_value += __f;
+	return *this;
+      }
+
+      constexpr complex&
+      operator-=(_Tp __f)
+      {
+	_M_value -= __f;
+	return *this;
+      }
+
+      constexpr complex&
+      operator*=(_Tp __f)
+      {
+	_M_value *= __f;
+	return *this;
+      }
+
+      constexpr complex&
+      operator/=(_Tp __f)
+      {
+	_M_value /= __f;
+	return *this;
+      }
+
+      // Let the compiler synthesize the copy and assignment
+      // operator.  It always does a pretty good job.
+      constexpr complex& operator=(const complex&) = default;
+
+      template<typename _Up>
+	constexpr complex&
+	operator=(const complex<_Up>&  __z)
+	{
+	  __real__ _M_value = __z.real();
+	  __imag__ _M_value = __z.imag();
+	  return *this;
+	}
+
+      template<typename _Up>
+	constexpr complex&
+	operator+=(const complex<_Up>& __z)
+	{
+	  _M_value += __z.__rep();
+	  return *this;
+	}
+
+      template<class _Up>
+	constexpr complex&
+	operator-=(const complex<_Up>& __z)
+	{
+	  _M_value -= __z.__rep();
+	  return *this;
+	}
+
+      template<class _Up>
+	constexpr complex&
+	operator*=(const complex<_Up>& __z)
+	{
+	  const _ComplexT __t = __z.__rep();
+	  _M_value *= __t;
+	  return *this;
+	}
+
+      template<class _Up>
+	constexpr complex&
+	operator/=(const complex<_Up>& __z)
+	{
+	  const _ComplexT __t = __z.__rep();
+	  _M_value /= __t;
+	  return *this;
+	}
+
+      constexpr _ComplexT __rep() const { return _M_value; }
+
+    private:
+      _ComplexT _M_value;
+    };
+#endif
+
+#if __cplusplus <= 202002L
   // These bits have to be at the end of this file, so that the
   // specializations have all been defined.
   inline _GLIBCXX_CONSTEXPR
@@ -1530,6 +1967,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   inline _GLIBCXX_CONSTEXPR
   complex<double>::complex(const complex<long double>& __z)
   : _M_value(__z.__rep()) { }
+#endif
 
   // Inhibit implicit instantiations for required instantiations,
   // which are defined via explicit instantiations elsewhere.
@@ -1809,6 +2247,162 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     { return __complex_atanh(__z); }
 #endif
 
+#if _GLIBCXX_USE_C99_COMPLEX_TR1
+#if defined(__STDCPP_FLOAT16_T__) && defined(_GLIBCXX_FLOAT_IS_IEEE_BINARY32)
+  inline __complex__ _Float16
+  __complex_acos(__complex__ _Float16 __z)
+  { return static_cast<__complex__ _Float16>(__builtin_cacosf(__z)); }
+
+  inline __complex__ _Float16
+  __complex_asin(__complex__ _Float16 __z)
+  { return static_cast<__complex__ _Float16>(__builtin_casinf(__z)); }
+
+  inline __complex__ _Float16
+  __complex_atan(__complex__ _Float16 __z)
+  { return static_cast<__complex__ _Float16>(__builtin_catanf(__z)); }
+
+  inline __complex__ _Float16
+  __complex_acosh(__complex__ _Float16 __z)
+  { return static_cast<__complex__ _Float16>(__builtin_cacoshf(__z)); }
+
+  inline __complex__ _Float16
+  __complex_asinh(__complex__ _Float16 __z)
+  { return static_cast<__complex__ _Float16>(__builtin_casinhf(__z)); }
+
+  inline __complex__ _Float16
+  __complex_atanh(__complex__ _Float16 __z)
+  { return static_cast<__complex__ _Float16>(__builtin_catanhf(__z)); }
+#endif
+
+#if defined(__STDCPP_FLOAT32_T__) && defined(_GLIBCXX_FLOAT_IS_IEEE_BINARY32)
+  inline __complex__ _Float32
+  __complex_acos(__complex__ _Float32 __z)
+  { return __builtin_cacosf(__z); }
+
+  inline __complex__ _Float32
+  __complex_asin(__complex__ _Float32 __z)
+  { return __builtin_casinf(__z); }
+
+  inline __complex__ _Float32
+  __complex_atan(__complex__ _Float32 __z)
+  { return __builtin_catanf(__z); }
+
+  inline __complex__ _Float32
+  __complex_acosh(__complex__ _Float32 __z)
+  { return __builtin_cacoshf(__z); }
+
+  inline __complex__ _Float32
+  __complex_asinh(__complex__ _Float32 __z)
+  { return __builtin_casinhf(__z); }
+
+  inline __complex__ _Float32
+  __complex_atanh(__complex__ _Float32 __z)
+  { return __builtin_catanhf(__z); }
+#endif
+
+#if defined(__STDCPP_FLOAT64_T__) && defined(_GLIBCXX_DOUBLE_IS_IEEE_BINARY64)
+  inline __complex__ _Float64
+  __complex_acos(__complex__ _Float64 __z)
+  { return __builtin_cacos(__z); }
+
+  inline __complex__ _Float64
+  __complex_asin(__complex__ _Float64 __z)
+  { return __builtin_casin(__z); }
+
+  inline __complex__ _Float64
+  __complex_atan(__complex__ _Float64 __z)
+  { return __builtin_catan(__z); }
+
+  inline __complex__ _Float64
+  __complex_acosh(__complex__ _Float64 __z)
+  { return __builtin_cacosh(__z); }
+
+  inline __complex__ _Float64
+  __complex_asinh(__complex__ _Float64 __z)
+  { return __builtin_casinh(__z); }
+
+  inline __complex__ _Float64
+  __complex_atanh(__complex__ _Float64 __z)
+  { return __builtin_catanh(__z); }
+#endif
+
+#if defined(__STDCPP_FLOAT128_T__) && defined(_GLIBCXX_LDOUBLE_IS_IEEE_BINARY128)
+  inline __complex__ _Float128
+  __complex_acos(__complex__ _Float128 __z)
+  { return __builtin_cacosl(__z); }
+
+  inline __complex__ _Float128
+  __complex_asin(__complex__ _Float128 __z)
+  { return __builtin_casinl(__z); }
+
+  inline __complex__ _Float128
+  __complex_atan(__complex__ _Float128 __z)
+  { return __builtin_catanl(__z); }
+
+  inline __complex__ _Float128
+  __complex_acosh(__complex__ _Float128 __z)
+  { return __builtin_cacoshl(__z); }
+
+  inline __complex__ _Float128
+  __complex_asinh(__complex__ _Float128 __z)
+  { return __builtin_casinhl(__z); }
+
+  inline __complex__ _Float128
+  __complex_atanh(__complex__ _Float128 __z)
+  { return __builtin_catanhl(__z); }
+#elif defined(__STDCPP_FLOAT128_T__) && defined(_GLIBCXX_HAVE_FLOAT128_MATH)
+  inline __complex__ _Float128
+  __complex_acos(__complex__ _Float128 __z)
+  { return __builtin_cacosf128(__z); }
+
+  inline __complex__ _Float128
+  __complex_asin(__complex__ _Float128 __z)
+  { return __builtin_casinf128(__z); }
+
+  inline __complex__ _Float128
+  __complex_atan(__complex__ _Float128 __z)
+  { return __builtin_catanf128(__z); }
+
+  inline __complex__ _Float128
+  __complex_acosh(__complex__ _Float128 __z)
+  { return __builtin_cacoshf128(__z); }
+
+  inline __complex__ _Float128
+  __complex_asinh(__complex__ _Float128 __z)
+  { return __builtin_casinhf128(__z); }
+
+  inline __complex__ _Float128
+  __complex_atanh(__complex__ _Float128 __z)
+  { return __builtin_catanhf128(__z); }
+#endif
+
+#if defined(__STDCPP_BFLOAT16_T__) && defined(_GLIBCXX_FLOAT_IS_IEEE_BINARY32)
+  inline __complex__ decltype(0.0bf16)
+  __complex_acos(__complex__ decltype(0.0bf16) __z)
+  { return static_cast<__complex__ decltype(0.0bf16)>(__builtin_cacosf(__z)); }
+
+  inline __complex__ decltype(0.0bf16)
+  __complex_asin(__complex__ decltype(0.0bf16) __z)
+  { return static_cast<__complex__ decltype(0.0bf16)>(__builtin_casinf(__z)); }
+
+  inline __complex__ decltype(0.0bf16)
+  __complex_atan(__complex__ decltype(0.0bf16) __z)
+  { return static_cast<__complex__ decltype(0.0bf16)>(__builtin_catanf(__z)); }
+
+  inline __complex__ decltype(0.0bf16)
+  __complex_acosh(__complex__ decltype(0.0bf16) __z)
+  { return static_cast<__complex__ decltype(0.0bf16)>(__builtin_cacoshf(__z)); }
+
+  inline __complex__ decltype(0.0bf16)
+  __complex_asinh(__complex__ decltype(0.0bf16) __z)
+  { return static_cast<__complex__ decltype(0.0bf16)>(__builtin_casinhf(__z)); }
+
+  inline __complex__ decltype(0.0bf16)
+  __complex_atanh(__complex__ decltype(0.0bf16) __z)
+  { return static_cast<__complex__ decltype(0.0bf16)>(__builtin_catanhf(__z)); }
+#endif
+#endif
+
   template<typename _Tp>
     inline _Tp
     /// fabs(__z) [8.1.8].
@@ -1897,6 +2491,49 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   inline complex<long double>
   __complex_proj(const complex<long double>& __z)
   { return __builtin_cprojl(__z.__rep()); }
+
+#if __cplusplus > 202002L
+#if defined(__STDCPP_FLOAT16_T__) && defined(_GLIBCXX_FLOAT_IS_IEEE_BINARY32)
+  inline __complex__ _Float16
+  __complex_proj(__complex__ _Float16 __z)
+  { return static_cast<__complex__ _Float16>(__builtin_cprojf(__z)); }
+#endif
+
+#if defined(__STDCPP_FLOAT32_T__) && defined(_GLIBCXX_FLOAT_IS_IEEE_BINARY32)
+  inline __complex__ _Float32
+  __complex_proj(__complex__ _Float32 __z)
+  { return __builtin_cprojf(__z); }
+#endif
+
+#if defined(__STDCPP_FLOAT64_T__) && defined(_GLIBCXX_DOUBLE_IS_IEEE_BINARY64)
+  inline __complex__ _Float64
+  __complex_proj(__complex__ _Float64 __z)
+  { return __builtin_cproj(__z); }
+#endif
+
+#if defined(__STDCPP_FLOAT128_T__) && defined(_GLIBCXX_LDOUBLE_IS_IEEE_BINARY128)
+  inline __complex__ _Float128
+  __complex_proj(__complex__ _Float128 __z)
+  { return __builtin_cprojl(__z); }
+#elif defined(__STDCPP_FLOAT128_T__) && defined(_GLIBCXX_HAVE_FLOAT128_MATH)
+  inline __complex__ _Float128
+  __complex_proj(__complex__ _Float128 __z)
+  { return __builtin_cprojf128(__z); }
+#endif
+
+#if defined(__STDCPP_BFLOAT16_T__) && defined(_GLIBCXX_FLOAT_IS_IEEE_BINARY32)
+  inline __complex__ decltype(0.0bf16)
+  __complex_proj(__complex__ decltype(0.0bf16) __z)
+  { return static_cast<__complex__ decltype(0.0bf16)>(__builtin_cprojf(__z)); }
+#endif
+
+  template<typename _Tp>
+    requires(__complex_type<_Tp>::type)
+    inline complex<_Tp>
+    __complex_proj(const complex<_Tp>& __z)
+    { return __complex_proj(__z.__rep()); }
+#endif
+
 #elif defined _GLIBCXX_USE_C99_MATH_TR1
   inline complex<float>
   __complex_proj(const complex<float>& __z)
diff --git a/libstdc++-v3/testsuite/26_numerics/complex/ext_c++23.cc b/libstdc++-v3/testsuite/26_numerics/complex/ext_c++23.cc
new file mode 100644
index 00000000000..bdc9af016c7
--- /dev/null
+++ b/libstdc++-v3/testsuite/26_numerics/complex/ext_c++23.cc
@@ -0,0 +1,89 @@
+// Copyright (C) 2022 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library 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, or (at your option)
+// any later version.
+
+// This library 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 library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2b" }
+// { dg-do link { target c++23 } }
+
+#include <stdfloat>
+#include <complex>
+
+template <typename T>
+__attribute__((__noipa__)) void
+test_functions(T *p, std::complex<T> *q)
+{
+  p[0] = std::abs(q[0]);
+  p[1] = std::arg(q[1]);
+  q[2] = std::cos(q[2]);
+  q[3] = std::cosh(q[3]);
+  q[4] = std::exp(q[4]);
+  q[5] = std::log(q[5]);
+  q[6] = std::sin(q[6]);
+  q[7] = std::sinh(q[7]);
+  q[8] = std::sqrt(q[8]);
+  q[9] = std::tan(q[9]);
+  q[10] = std::tanh(q[10]);
+  q[11] = std::pow(q[11], q[19]);
+  q[12] = std::acos(q[12]);
+  q[13] = std::asin(q[13]);
+  q[14] = std::atan(q[14]);
+  q[15] = std::acosh(q[15]);
+  q[16] = std::asinh(q[16]);
+  q[17] = std::atanh(q[17]);
+  q[18] = std::proj(q[18]);
+}
+
+int
+main()
+{
+#if defined(__STDCPP_FLOAT16_T__) && defined(_GLIBCXX_FLOAT_IS_IEEE_BINARY32)
+  {
+    std::float16_t p[2] = {};
+    std::complex<std::float16_t> q[20] = {};
+    test_functions(p, q);
+  }
+#endif
+#if defined(__STDCPP_FLOAT32_T__) && defined(_GLIBCXX_FLOAT_IS_IEEE_BINARY32)
+  {
+    std::float32_t p[2] = {};
+    std::complex<std::float32_t> q[20] = {};
+    test_functions(p, q);
+  }
+#endif
+#if defined(__STDCPP_FLOAT64_T__) && defined(_GLIBCXX_DOUBLE_IS_IEEE_BINARY64)
+  {
+    std::float64_t p[2] = {};
+    std::complex<std::float64_t> q[20] = {};
+    test_functions(p, q);
+  }
+#endif
+#if defined(__STDCPP_FLOAT128_T__) \
+    && (defined(_GLIBCXX_DOUBLE_IS_IEEE_BINARY128) \
+	|| defined(_GLIBCXX_HAVE_FLOAT128_MATH))
+  {
+    std::float128_t p[2] = {};
+    std::complex<std::float128_t> q[20] = {};
+    test_functions(p, q);
+  }
+#endif
+#if defined(__STDCPP_BFLOAT16_T__) && defined(_GLIBCXX_FLOAT_IS_IEEE_BINARY32)
+  {
+    std::bfloat16_t p[2] = {};
+    std::complex<std::bfloat16_t> q[20] = {};
+    test_functions(p, q);
+  }
+#endif
+}

^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2022-10-31 19:15 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-10-31 19:15 [gcc r13-3579] libstdc++-v3: <complex> support for extended floating point types Jakub Jelinek

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).