libstdc++-v3: <complex> support for extended floating point types

Message ID Y1LBm4u+R3Ka28Dj@tucnak
State Unresolved
Headers
Series libstdc++-v3: <complex> support for extended floating point types |

Checks

Context Check Description
snail/gcc-patch-check warning Git am fail log

Commit Message

Jakub Jelinek Oct. 21, 2022, 3:58 p.m. UTC
  Hi!

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.
This patch is on top of
https://gcc.gnu.org/pipermail/libstdc++/2022-October/054849.html
(and if
https://gcc.gnu.org/pipermail/libstdc++/2022-October/054862.html
is also applied, then
https://gcc.gnu.org/pipermail/gcc-patches/2022-October/603665.html                                                                                                                    
https://gcc.gnu.org/pipermail/gcc-patches/2022-October/604080.html                                                                                                                    
https://gcc.gnu.org/pipermail/gcc-patches/2022-October/604134.html
are needed as well).
The g++.dg/cpp23/ testcase verifies explicit(bool) works correctly.

Tested on x86_64-linux, ok for trunk?

2022-10-21  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 and 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.


	Jakub
  

Comments

Jonathan Wakely Oct. 31, 2022, 10:26 a.m. UTC | #1
On Fri, 21 Oct 2022 at 16:58, Jakub Jelinek <jakub@redhat.com> wrote:
>
> Hi!
>
> 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.
> This patch is on top of
> https://gcc.gnu.org/pipermail/libstdc++/2022-October/054849.html
> (and if
> https://gcc.gnu.org/pipermail/libstdc++/2022-October/054862.html
> is also applied, then
> https://gcc.gnu.org/pipermail/gcc-patches/2022-October/603665.html
> https://gcc.gnu.org/pipermail/gcc-patches/2022-October/604080.html
> https://gcc.gnu.org/pipermail/gcc-patches/2022-October/604134.html
> are needed as well).
> The g++.dg/cpp23/ testcase verifies explicit(bool) works correctly.
>
> Tested on x86_64-linux, ok for trunk?
>
> 2022-10-21  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 and 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.
>
> --- libstdc++-v3/include/std/complex.jj 2022-10-21 08:55:43.037675332 +0200
> +++ libstdc++-v3/include/std/complex    2022-10-21 17:05:36.802243229 +0200
> @@ -142,8 +142,14 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>
>        ///  Converting constructor.
>        template<typename _Up>
> +#if __cplusplus > 202002L
> +       explicit(!requires(_Up __u) { _Tp{__u}; })
> +       constexpr complex(const complex<_Up>& __z)
> +       : _M_real(_Tp(__z.real())), _M_imag(_Tp(__z.imag())) { }

Do these casts to _Tp do anything? The _M_real and _M_imag members are
already of type _Tp and we're using () initialization not {} so
there's no narrowing concern. _M_real(__z.real()) is already an
explicit conversion from decltype(__z.real()) to decltype(_M_real) so
the extra _Tp is redundant.

I think the diff between C++23 and older standards would be smaller
done like this:

      ///  Converting constructor.
      template<typename _Up>
#if __cplusplus > 202002L
       explicit(!requires(_Up __u) { _Tp{__u}; })
#endif
        _GLIBCXX_CONSTEXPR complex(const complex<_Up>& __z)
       : _M_real(__z.real()), _M_imag(__z.imag()) { }


This also means the constructor body is always defined on the same
line, which avoids warnings from ld.gold's -Wodr-violations which IIRC
is based on simple heuristics like the line where the function is
defined.

Otherwise this looks great. If the above alternative works, please use
that, but OK for trunk either way (once all the other patches it
depends on are in).
  
Jakub Jelinek Oct. 31, 2022, 4:57 p.m. UTC | #2
On Mon, Oct 31, 2022 at 10:26:11AM +0000, Jonathan Wakely wrote:
> > --- libstdc++-v3/include/std/complex.jj 2022-10-21 08:55:43.037675332 +0200
> > +++ libstdc++-v3/include/std/complex    2022-10-21 17:05:36.802243229 +0200
> > @@ -142,8 +142,14 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
> >
> >        ///  Converting constructor.
> >        template<typename _Up>
> > +#if __cplusplus > 202002L
> > +       explicit(!requires(_Up __u) { _Tp{__u}; })
> > +       constexpr complex(const complex<_Up>& __z)
> > +       : _M_real(_Tp(__z.real())), _M_imag(_Tp(__z.imag())) { }
> 
> Do these casts to _Tp do anything? The _M_real and _M_imag members are
> already of type _Tp and we're using () initialization not {} so
> there's no narrowing concern. _M_real(__z.real()) is already an
> explicit conversion from decltype(__z.real()) to decltype(_M_real) so
> the extra _Tp is redundant.

If I use just
       : _M_real(__z.real()), _M_imag(__z.imag()) { }
then without -Wsystem-headers there are no regressions, but compiling
g++.dg/cpp23/ext-floating12.C with additional -Wsystem-headers
-pedantic-errors results in lots of extra errors on that line:
.../x86_64-pc-linux-gnu/libstdc++-v3/include/complex:149:27: error: converting to ‘_Float32’ from ‘double’ with greater conversion rank
.../x86_64-pc-linux-gnu/libstdc++-v3/include/complex:149:48: error: converting to ‘_Float32’ from ‘double’ with greater conversion rank
.../x86_64-pc-linux-gnu/libstdc++-v3/include/complex:149:27: error: converting to ‘_Float32’ from ‘long double’ with greater conversion rank
.../x86_64-pc-linux-gnu/libstdc++-v3/include/complex:149:48: error: converting to ‘_Float32’ from ‘long double’ with greater conversion rank
.../x86_64-pc-linux-gnu/libstdc++-v3/include/complex:149:27: error: converting to ‘_Float32’ from ‘_Float64’ with greater conversion rank
.../x86_64-pc-linux-gnu/libstdc++-v3/include/complex:149:48: error: converting to ‘_Float32’ from ‘_Float64’ with greater conversion rank
.../x86_64-pc-linux-gnu/libstdc++-v3/include/complex:149:27: error: converting to ‘_Float32’ from ‘_Float128’ with greater conversion rank
.../x86_64-pc-linux-gnu/libstdc++-v3/include/complex:149:48: error: converting to ‘_Float32’ from ‘_Float128’ with greater conversion rank
.../x86_64-pc-linux-gnu/libstdc++-v3/include/complex:149:27: error: converting to ‘_Float64’ from ‘long double’ with greater conversion rank
.../x86_64-pc-linux-gnu/libstdc++-v3/include/complex:149:48: error: converting to ‘_Float64’ from ‘long double’ with greater conversion rank
.../x86_64-pc-linux-gnu/libstdc++-v3/include/complex:149:27: error: converting to ‘_Float64’ from ‘_Float128’ with greater conversion rank
.../x86_64-pc-linux-gnu/libstdc++-v3/include/complex:149:48: error: converting to ‘_Float64’ from ‘_Float128’ with greater conversion rank
.../x86_64-pc-linux-gnu/libstdc++-v3/include/complex:149:27: error: converting to ‘_Float16’ from ‘float’ with greater conversion rank
.../x86_64-pc-linux-gnu/libstdc++-v3/include/complex:149:48: error: converting to ‘_Float16’ from ‘float’ with greater conversion rank
.../x86_64-pc-linux-gnu/libstdc++-v3/include/complex:149:27: error: converting to ‘_Float16’ from ‘double’ with greater conversion rank
.../x86_64-pc-linux-gnu/libstdc++-v3/include/complex:149:48: error: converting to ‘_Float16’ from ‘double’ with greater conversion rank
.../x86_64-pc-linux-gnu/libstdc++-v3/include/complex:149:27: error: converting to ‘_Float16’ from ‘long double’ with greater conversion rank
.../x86_64-pc-linux-gnu/libstdc++-v3/include/complex:149:48: error: converting to ‘_Float16’ from ‘long double’ with greater conversion rank
.../x86_64-pc-linux-gnu/libstdc++-v3/include/complex:149:27: error: converting to ‘_Float16’ from ‘_Float32’ with greater conversion rank
.../x86_64-pc-linux-gnu/libstdc++-v3/include/complex:149:48: error: converting to ‘_Float16’ from ‘_Float32’ with greater conversion rank
.../x86_64-pc-linux-gnu/libstdc++-v3/include/complex:149:27: error: converting to ‘_Float16’ from ‘_Float64’ with greater conversion rank
.../x86_64-pc-linux-gnu/libstdc++-v3/include/complex:149:48: error: converting to ‘_Float16’ from ‘_Float64’ with greater conversion rank
.../x86_64-pc-linux-gnu/libstdc++-v3/include/complex:149:27: error: converting to ‘_Float16’ from ‘_Float128’ with greater conversion rank
.../x86_64-pc-linux-gnu/libstdc++-v3/include/complex:149:48: error: converting to ‘_Float16’ from ‘_Float128’ with greater conversion rank
.../x86_64-pc-linux-gnu/libstdc++-v3/include/complex:149:27: error: converting to ‘_Float16’ from ‘__bf16’ with unordered conversion ranks
.../x86_64-pc-linux-gnu/libstdc++-v3/include/complex:149:48: error: converting to ‘_Float16’ from ‘__bf16’ with unordered conversion ranks
.../x86_64-pc-linux-gnu/libstdc++-v3/include/complex:149:27: error: converting to ‘__bf16’ from ‘float’ with greater conversion rank
.../x86_64-pc-linux-gnu/libstdc++-v3/include/complex:149:48: error: converting to ‘__bf16’ from ‘float’ with greater conversion rank
.../x86_64-pc-linux-gnu/libstdc++-v3/include/complex:149:27: error: converting to ‘__bf16’ from ‘double’ with greater conversion rank
.../x86_64-pc-linux-gnu/libstdc++-v3/include/complex:149:48: error: converting to ‘__bf16’ from ‘double’ with greater conversion rank
.../x86_64-pc-linux-gnu/libstdc++-v3/include/complex:149:27: error: converting to ‘__bf16’ from ‘long double’ with greater conversion rank
.../x86_64-pc-linux-gnu/libstdc++-v3/include/complex:149:48: error: converting to ‘__bf16’ from ‘long double’ with greater conversion rank
.../x86_64-pc-linux-gnu/libstdc++-v3/include/complex:149:27: error: converting to ‘__bf16’ from ‘_Float32’ with greater conversion rank
.../x86_64-pc-linux-gnu/libstdc++-v3/include/complex:149:48: error: converting to ‘__bf16’ from ‘_Float32’ with greater conversion rank
.../x86_64-pc-linux-gnu/libstdc++-v3/include/complex:149:27: error: converting to ‘__bf16’ from ‘_Float64’ with greater conversion rank
.../x86_64-pc-linux-gnu/libstdc++-v3/include/complex:149:48: error: converting to ‘__bf16’ from ‘_Float64’ with greater conversion rank
.../x86_64-pc-linux-gnu/libstdc++-v3/include/complex:149:27: error: converting to ‘__bf16’ from ‘_Float128’ with greater conversion rank
.../x86_64-pc-linux-gnu/libstdc++-v3/include/complex:149:48: error: converting to ‘__bf16’ from ‘_Float128’ with greater conversion rank
.../x86_64-pc-linux-gnu/libstdc++-v3/include/complex:149:27: error: converting to ‘__bf16’ from ‘_Float16’ with unordered conversion ranks
.../x86_64-pc-linux-gnu/libstdc++-v3/include/complex:149:48: error: converting to ‘__bf16’ from ‘_Float16’ with unordered conversion ranks

__z doesn't have _Tp type, but _Up, which is some other floating
point type.  For the conversion constructors where we have
explicit(false) all is fine, we've tested in the requires that
_Up is implicitly convertable to _Tp.
But if explicit(true), it is fine without the explicit casts only
for long double -> float, long double -> double and double -> float
casts which are ok for implicit casts but not in narrowing conversions
with non-constants.
Otherwise it results in the above diagnostics.

> I think the diff between C++23 and older standards would be smaller
> done like this:
> 
>       ///  Converting constructor.
>       template<typename _Up>
> #if __cplusplus > 202002L
>        explicit(!requires(_Up __u) { _Tp{__u}; })
> #endif
>         _GLIBCXX_CONSTEXPR complex(const complex<_Up>& __z)
>        : _M_real(__z.real()), _M_imag(__z.imag()) { }

I could go for this with the _Tp() casts everywhere, or
make also that line (perhaps except for { }) also conditional on
#if __cplusplus > 202002L.

> This also means the constructor body is always defined on the same
> line, which avoids warnings from ld.gold's -Wodr-violations which IIRC
> is based on simple heuristics like the line where the function is
> defined.
> 
> Otherwise this looks great. If the above alternative works, please use
> that, but OK for trunk either way (once all the other patches it
> depends on are in).

All the builtins patches are in since today, and the
"Small extended float support tweaks" patch is in too (it had a small
testsuite conflict due to the
https://gcc.gnu.org/pipermail/libstdc++/2022-October/054849.html
patch still pending, but I've just resolved that conflict).
I think this patch doesn't depend on anything anymore.

OT, I also get on the same testcase with -Wsystem-headers -pedantic-errors
.../x86_64-pc-linux-gnu/libstdc++-v3/include/cmath:47:2: error: #include_next is a GCC extension
.../x86_64-pc-linux-gnu/libstdc++-v3/include/bits/std_abs.h:38:2: error: #include_next is a GCC extension
.../x86_64-pc-linux-gnu/libstdc++-v3/include/numbers:223:1: error: non-standard suffix on floating constant [-Wpedantic]
.../x86_64-pc-linux-gnu/libstdc++-v3/include/numbers:223:1: error: non-standard suffix on floating constant [-Wpedantic]
.../x86_64-pc-linux-gnu/libstdc++-v3/include/numbers:223:1: error: non-standard suffix on floating constant [-Wpedantic]
.../x86_64-pc-linux-gnu/libstdc++-v3/include/numbers:223:1: error: non-standard suffix on floating constant [-Wpedantic]
.../x86_64-pc-linux-gnu/libstdc++-v3/include/numbers:223:1: error: non-standard suffix on floating constant [-Wpedantic]
.../x86_64-pc-linux-gnu/libstdc++-v3/include/numbers:223:1: error: non-standard suffix on floating constant [-Wpedantic]
.../x86_64-pc-linux-gnu/libstdc++-v3/include/numbers:223:1: error: non-standard suffix on floating constant [-Wpedantic]
.../x86_64-pc-linux-gnu/libstdc++-v3/include/numbers:223:1: error: non-standard suffix on floating constant [-Wpedantic]
.../x86_64-pc-linux-gnu/libstdc++-v3/include/numbers:223:1: error: non-standard suffix on floating constant [-Wpedantic]
.../x86_64-pc-linux-gnu/libstdc++-v3/include/numbers:223:1: error: non-standard suffix on floating constant [-Wpedantic]
.../x86_64-pc-linux-gnu/libstdc++-v3/include/numbers:223:1: error: non-standard suffix on floating constant [-Wpedantic]
.../x86_64-pc-linux-gnu/libstdc++-v3/include/numbers:223:1: error: non-standard suffix on floating constant [-Wpedantic]
.../x86_64-pc-linux-gnu/libstdc++-v3/include/numbers:223:1: error: non-standard suffix on floating constant [-Wpedantic]
.../x86_64-pc-linux-gnu/libstdc++-v3/include/cstdlib:79:2: error: #include_next is a GCC extension
.../libstdc++-v3/libsupc++/compare:844:45: error: ISO C++ does not support ‘__int128’ for ‘type name’ [-Wpedantic]
.../x86_64-pc-linux-gnu/libstdc++-v3/include/cstddef:91:36: error: ISO C++ does not support ‘__int128’ for ‘type name’ [-Wpedantic]
.../x86_64-pc-linux-gnu/libstdc++-v3/include/cstddef:93:45: error: ISO C++ does not support ‘__int128’ for ‘type name’ [-Wpedantic]
For the numbers case (__float128 in there), wonder if we can wrap it in __extension__ or
use __extension__ __float128 as the type (apparently e.g. type_traits uses
__extension__ before the template keyword of the specializations), for the __int128 cases perhaps
too, no idea about #include_next though.

	Jakub
  
Jonathan Wakely Oct. 31, 2022, 5:04 p.m. UTC | #3
On Mon, 31 Oct 2022 at 16:57, Jakub Jelinek <jakub@redhat.com> wrote:
>
> On Mon, Oct 31, 2022 at 10:26:11AM +0000, Jonathan Wakely wrote:
> > > --- libstdc++-v3/include/std/complex.jj 2022-10-21 08:55:43.037675332 +0200
> > > +++ libstdc++-v3/include/std/complex    2022-10-21 17:05:36.802243229 +0200
> > > @@ -142,8 +142,14 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
> > >
> > >        ///  Converting constructor.
> > >        template<typename _Up>
> > > +#if __cplusplus > 202002L
> > > +       explicit(!requires(_Up __u) { _Tp{__u}; })
> > > +       constexpr complex(const complex<_Up>& __z)
> > > +       : _M_real(_Tp(__z.real())), _M_imag(_Tp(__z.imag())) { }
> >
> > Do these casts to _Tp do anything? The _M_real and _M_imag members are
> > already of type _Tp and we're using () initialization not {} so
> > there's no narrowing concern. _M_real(__z.real()) is already an
> > explicit conversion from decltype(__z.real()) to decltype(_M_real) so
> > the extra _Tp is redundant.
>
> If I use just
>        : _M_real(__z.real()), _M_imag(__z.imag()) { }
> then without -Wsystem-headers there are no regressions, but compiling
> g++.dg/cpp23/ext-floating12.C with additional -Wsystem-headers
> -pedantic-errors results in lots of extra errors on that line:
> .../x86_64-pc-linux-gnu/libstdc++-v3/include/complex:149:27: error: converting to ‘_Float32’ from ‘double’ with greater conversion rank
> .../x86_64-pc-linux-gnu/libstdc++-v3/include/complex:149:48: error: converting to ‘_Float32’ from ‘double’ with greater conversion rank
> .../x86_64-pc-linux-gnu/libstdc++-v3/include/complex:149:27: error: converting to ‘_Float32’ from ‘long double’ with greater conversion rank
> .../x86_64-pc-linux-gnu/libstdc++-v3/include/complex:149:48: error: converting to ‘_Float32’ from ‘long double’ with greater conversion rank
> .../x86_64-pc-linux-gnu/libstdc++-v3/include/complex:149:27: error: converting to ‘_Float32’ from ‘_Float64’ with greater conversion rank
> .../x86_64-pc-linux-gnu/libstdc++-v3/include/complex:149:48: error: converting to ‘_Float32’ from ‘_Float64’ with greater conversion rank
> .../x86_64-pc-linux-gnu/libstdc++-v3/include/complex:149:27: error: converting to ‘_Float32’ from ‘_Float128’ with greater conversion rank
> .../x86_64-pc-linux-gnu/libstdc++-v3/include/complex:149:48: error: converting to ‘_Float32’ from ‘_Float128’ with greater conversion rank
> .../x86_64-pc-linux-gnu/libstdc++-v3/include/complex:149:27: error: converting to ‘_Float64’ from ‘long double’ with greater conversion rank
> .../x86_64-pc-linux-gnu/libstdc++-v3/include/complex:149:48: error: converting to ‘_Float64’ from ‘long double’ with greater conversion rank
> .../x86_64-pc-linux-gnu/libstdc++-v3/include/complex:149:27: error: converting to ‘_Float64’ from ‘_Float128’ with greater conversion rank
> .../x86_64-pc-linux-gnu/libstdc++-v3/include/complex:149:48: error: converting to ‘_Float64’ from ‘_Float128’ with greater conversion rank
> .../x86_64-pc-linux-gnu/libstdc++-v3/include/complex:149:27: error: converting to ‘_Float16’ from ‘float’ with greater conversion rank
> .../x86_64-pc-linux-gnu/libstdc++-v3/include/complex:149:48: error: converting to ‘_Float16’ from ‘float’ with greater conversion rank
> .../x86_64-pc-linux-gnu/libstdc++-v3/include/complex:149:27: error: converting to ‘_Float16’ from ‘double’ with greater conversion rank
> .../x86_64-pc-linux-gnu/libstdc++-v3/include/complex:149:48: error: converting to ‘_Float16’ from ‘double’ with greater conversion rank
> .../x86_64-pc-linux-gnu/libstdc++-v3/include/complex:149:27: error: converting to ‘_Float16’ from ‘long double’ with greater conversion rank
> .../x86_64-pc-linux-gnu/libstdc++-v3/include/complex:149:48: error: converting to ‘_Float16’ from ‘long double’ with greater conversion rank
> .../x86_64-pc-linux-gnu/libstdc++-v3/include/complex:149:27: error: converting to ‘_Float16’ from ‘_Float32’ with greater conversion rank
> .../x86_64-pc-linux-gnu/libstdc++-v3/include/complex:149:48: error: converting to ‘_Float16’ from ‘_Float32’ with greater conversion rank
> .../x86_64-pc-linux-gnu/libstdc++-v3/include/complex:149:27: error: converting to ‘_Float16’ from ‘_Float64’ with greater conversion rank
> .../x86_64-pc-linux-gnu/libstdc++-v3/include/complex:149:48: error: converting to ‘_Float16’ from ‘_Float64’ with greater conversion rank
> .../x86_64-pc-linux-gnu/libstdc++-v3/include/complex:149:27: error: converting to ‘_Float16’ from ‘_Float128’ with greater conversion rank
> .../x86_64-pc-linux-gnu/libstdc++-v3/include/complex:149:48: error: converting to ‘_Float16’ from ‘_Float128’ with greater conversion rank
> .../x86_64-pc-linux-gnu/libstdc++-v3/include/complex:149:27: error: converting to ‘_Float16’ from ‘__bf16’ with unordered conversion ranks
> .../x86_64-pc-linux-gnu/libstdc++-v3/include/complex:149:48: error: converting to ‘_Float16’ from ‘__bf16’ with unordered conversion ranks
> .../x86_64-pc-linux-gnu/libstdc++-v3/include/complex:149:27: error: converting to ‘__bf16’ from ‘float’ with greater conversion rank
> .../x86_64-pc-linux-gnu/libstdc++-v3/include/complex:149:48: error: converting to ‘__bf16’ from ‘float’ with greater conversion rank
> .../x86_64-pc-linux-gnu/libstdc++-v3/include/complex:149:27: error: converting to ‘__bf16’ from ‘double’ with greater conversion rank
> .../x86_64-pc-linux-gnu/libstdc++-v3/include/complex:149:48: error: converting to ‘__bf16’ from ‘double’ with greater conversion rank
> .../x86_64-pc-linux-gnu/libstdc++-v3/include/complex:149:27: error: converting to ‘__bf16’ from ‘long double’ with greater conversion rank
> .../x86_64-pc-linux-gnu/libstdc++-v3/include/complex:149:48: error: converting to ‘__bf16’ from ‘long double’ with greater conversion rank
> .../x86_64-pc-linux-gnu/libstdc++-v3/include/complex:149:27: error: converting to ‘__bf16’ from ‘_Float32’ with greater conversion rank
> .../x86_64-pc-linux-gnu/libstdc++-v3/include/complex:149:48: error: converting to ‘__bf16’ from ‘_Float32’ with greater conversion rank
> .../x86_64-pc-linux-gnu/libstdc++-v3/include/complex:149:27: error: converting to ‘__bf16’ from ‘_Float64’ with greater conversion rank
> .../x86_64-pc-linux-gnu/libstdc++-v3/include/complex:149:48: error: converting to ‘__bf16’ from ‘_Float64’ with greater conversion rank
> .../x86_64-pc-linux-gnu/libstdc++-v3/include/complex:149:27: error: converting to ‘__bf16’ from ‘_Float128’ with greater conversion rank
> .../x86_64-pc-linux-gnu/libstdc++-v3/include/complex:149:48: error: converting to ‘__bf16’ from ‘_Float128’ with greater conversion rank
> .../x86_64-pc-linux-gnu/libstdc++-v3/include/complex:149:27: error: converting to ‘__bf16’ from ‘_Float16’ with unordered conversion ranks
> .../x86_64-pc-linux-gnu/libstdc++-v3/include/complex:149:48: error: converting to ‘__bf16’ from ‘_Float16’ with unordered conversion ranks
>
> __z doesn't have _Tp type, but _Up, which is some other floating

Right.

> point type.  For the conversion constructors where we have
> explicit(false) all is fine, we've tested in the requires that
> _Up is implicitly convertable to _Tp.
> But if explicit(true), it is fine without the explicit casts only
> for long double -> float, long double -> double and double -> float
> casts which are ok for implicit casts but not in narrowing conversions
> with non-constants.
> Otherwise it results in the above diagnostics.

That seems like a compiler bug.

I don't see any reason for val(x) to be different from val(T(x)) when
T is decltype(val). They are both direct-initialization of T from x.



>
> > I think the diff between C++23 and older standards would be smaller
> > done like this:
> >
> >       ///  Converting constructor.
> >       template<typename _Up>
> > #if __cplusplus > 202002L
> >        explicit(!requires(_Up __u) { _Tp{__u}; })
> > #endif
> >         _GLIBCXX_CONSTEXPR complex(const complex<_Up>& __z)
> >        : _M_real(__z.real()), _M_imag(__z.imag()) { }
>
> I could go for this with the _Tp() casts everywhere, or
> make also that line (perhaps except for { }) also conditional on
> #if __cplusplus > 202002L.
>
> > This also means the constructor body is always defined on the same
> > line, which avoids warnings from ld.gold's -Wodr-violations which IIRC
> > is based on simple heuristics like the line where the function is
> > defined.
> >
> > Otherwise this looks great. If the above alternative works, please use
> > that, but OK for trunk either way (once all the other patches it
> > depends on are in).
>
> All the builtins patches are in since today, and the
> "Small extended float support tweaks" patch is in too (it had a small
> testsuite conflict due to the
> https://gcc.gnu.org/pipermail/libstdc++/2022-October/054849.html
> patch still pending, but I've just resolved that conflict).
> I think this patch doesn't depend on anything anymore.
>
> OT, I also get on the same testcase with -Wsystem-headers -pedantic-errors
> .../x86_64-pc-linux-gnu/libstdc++-v3/include/cmath:47:2: error: #include_next is a GCC extension
> .../x86_64-pc-linux-gnu/libstdc++-v3/include/bits/std_abs.h:38:2: error: #include_next is a GCC extension
> .../x86_64-pc-linux-gnu/libstdc++-v3/include/numbers:223:1: error: non-standard suffix on floating constant [-Wpedantic]
> .../x86_64-pc-linux-gnu/libstdc++-v3/include/numbers:223:1: error: non-standard suffix on floating constant [-Wpedantic]
> .../x86_64-pc-linux-gnu/libstdc++-v3/include/numbers:223:1: error: non-standard suffix on floating constant [-Wpedantic]
> .../x86_64-pc-linux-gnu/libstdc++-v3/include/numbers:223:1: error: non-standard suffix on floating constant [-Wpedantic]
> .../x86_64-pc-linux-gnu/libstdc++-v3/include/numbers:223:1: error: non-standard suffix on floating constant [-Wpedantic]
> .../x86_64-pc-linux-gnu/libstdc++-v3/include/numbers:223:1: error: non-standard suffix on floating constant [-Wpedantic]
> .../x86_64-pc-linux-gnu/libstdc++-v3/include/numbers:223:1: error: non-standard suffix on floating constant [-Wpedantic]
> .../x86_64-pc-linux-gnu/libstdc++-v3/include/numbers:223:1: error: non-standard suffix on floating constant [-Wpedantic]
> .../x86_64-pc-linux-gnu/libstdc++-v3/include/numbers:223:1: error: non-standard suffix on floating constant [-Wpedantic]
> .../x86_64-pc-linux-gnu/libstdc++-v3/include/numbers:223:1: error: non-standard suffix on floating constant [-Wpedantic]
> .../x86_64-pc-linux-gnu/libstdc++-v3/include/numbers:223:1: error: non-standard suffix on floating constant [-Wpedantic]
> .../x86_64-pc-linux-gnu/libstdc++-v3/include/numbers:223:1: error: non-standard suffix on floating constant [-Wpedantic]
> .../x86_64-pc-linux-gnu/libstdc++-v3/include/numbers:223:1: error: non-standard suffix on floating constant [-Wpedantic]
> .../x86_64-pc-linux-gnu/libstdc++-v3/include/cstdlib:79:2: error: #include_next is a GCC extension
> .../libstdc++-v3/libsupc++/compare:844:45: error: ISO C++ does not support ‘__int128’ for ‘type name’ [-Wpedantic]
> .../x86_64-pc-linux-gnu/libstdc++-v3/include/cstddef:91:36: error: ISO C++ does not support ‘__int128’ for ‘type name’ [-Wpedantic]
> .../x86_64-pc-linux-gnu/libstdc++-v3/include/cstddef:93:45: error: ISO C++ does not support ‘__int128’ for ‘type name’ [-Wpedantic]
> For the numbers case (__float128 in there), wonder if we can wrap it in __extension__ or
> use __extension__ __float128 as the type (apparently e.g. type_traits uses
> __extension__ before the template keyword of the specializations), for the __int128 cases perhaps
> too, no idea about #include_next though.

Yeah, __extension__ works in some places, although I think I've found
places it doesn't help.

The #include_next one has no way to disable it, which is annoying.
  

Patch

--- libstdc++-v3/include/std/complex.jj	2022-10-21 08:55:43.037675332 +0200
+++ libstdc++-v3/include/std/complex	2022-10-21 17:05:36.802243229 +0200
@@ -142,8 +142,14 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
       ///  Converting constructor.
       template<typename _Up>
+#if __cplusplus > 202002L
+	explicit(!requires(_Up __u) { _Tp{__u}; })
+	constexpr complex(const complex<_Up>& __z)
+	: _M_real(_Tp(__z.real())), _M_imag(_Tp(__z.imag())) { }
+#else
         _GLIBCXX_CONSTEXPR complex(const complex<_Up>& __z)
 	: _M_real(__z.real()), _M_imag(__z.imag()) { }
+#endif
 
 #if __cplusplus >= 201103L
       // _GLIBCXX_RESOLVE_LIB_DEFECTS
@@ -1077,6 +1083,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 +1362,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 +1515,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 +1669,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 +1802,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 +1970,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 +2250,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 +2494,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)
--- libstdc++-v3/include/bits/cpp_type_traits.h.jj	2022-01-11 23:11:24.144265506 +0100
+++ libstdc++-v3/include/bits/cpp_type_traits.h	2022-10-21 11:06:07.059777783 +0200
@@ -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
   //
--- libstdc++-v3/testsuite/26_numerics/complex/ext_c++23.cc.jj	2022-10-21 16:24:24.337657605 +0200
+++ libstdc++-v3/testsuite/26_numerics/complex/ext_c++23.cc	2022-10-21 17:20:47.300853616 +0200
@@ -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
+}
--- gcc/testsuite/g++.dg/cpp23/ext-floating12.C.jj	2022-10-21 15:12:38.119671632 +0200
+++ gcc/testsuite/g++.dg/cpp23/ext-floating12.C	2022-10-21 16:13:27.021501628 +0200
@@ -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
+}