diff mbox series

[libstdc++] Implement P0415 More constexpr for std::complex.

Message ID 5e2b3a30-fd0c-351d-256c-b70e060d4994@verizon.net
State New
Headers show
Series [libstdc++] Implement P0415 More constexpr for std::complex. | expand

Commit Message

Ed Smith-Rowland Nov. 16, 2018, 5:13 p.m. UTC
Greetings,

This is late but I wanted to put it out there just to finish a thing.

It's fairly straightforward constexpr of operators and some simple 
functions for std::complex.

The only thing that jumped out was the norm function.  We had this:

     struct _Norm_helper<true>
     {
       template<typename _Tp>
         static inline _Tp _S_do_it(const complex<_Tp>& __z)
         {
           _Tp __res = std::abs(__z);
           return __res * __res;
         }
     };

Since abs can't be made constexpr for complex since it involves sqrt (It 
probably could but that's another story) I had to fall back to the x^2 + 
y^2.  I don't know who that will bother.  This version should be faster 
and I can't think of any useful trustworthy difference numerically 
either in terms of accuracy of stability.

Barring any feedback on that I'll clean it up and maybe rename my tests 
from constexpr_all_the_things.cc to more_constexpr.cc ;-)

It builds and tests cleanly on x86_64-linux.

Ed
2018-11-16  Edward Smith-Rowland  <3dw4rd@verizon.net>

	Implement P0415 More constexpr for std::complex.
	* include/std/complex (proj(), norm(), conj(), arg()): Constexpr.
	(real(Tp), imag(Tp)): Constexpr.
	(operator@=(Tp), operator@=(complex<Tp>)): Constexpr.
	(operator@(Tp,complex<Tp>), operator@(complex<Tp>,Tp)
	operator@(complex<Tp>,complex<Tp>)): Constexpr.
	* testsuite/26_numerics/complex/comparison_operators/
	constexpr_all_the_things.cc: New test.
	* testsuite/26_numerics/complex/operators/
	constexpr_all_the_things.cc: New test.
	* testsuite/26_numerics/complex/requirements/
	constexpr_all_the_things.cc: New test.
	* testsuite/26_numerics/complex/value_operations/
	constexpr_all_the_things.cc: New test.
	* testsuite/26_numerics/headers/complex/synopsis.cc:
	Add _GLIBCXX20_CONSTEXPR to applicable operators; Add missing proj().

Comments

Daniel Krügler Nov. 16, 2018, 5:38 p.m. UTC | #1
Am Fr., 16. Nov. 2018 um 18:13 Uhr schrieb Ed Smith-Rowland
<3dw4rd@verizon.net>:
>
> Greetings,
>
> This is late but I wanted to put it out there just to finish a thing.
>
> It's fairly straightforward constexpr of operators and some simple
> functions for std::complex.
>
> The only thing that jumped out was the norm function.  We had this:
>
>      struct _Norm_helper<true>
>      {
>        template<typename _Tp>
>          static inline _Tp _S_do_it(const complex<_Tp>& __z)
>          {
>            _Tp __res = std::abs(__z);
>            return __res * __res;
>          }
>      };
>
> Since abs can't be made constexpr for complex since it involves sqrt (It
> probably could but that's another story) I had to fall back to the x^2 +
> y^2.  I don't know who that will bother.  This version should be faster
> and I can't think of any useful trustworthy difference numerically
> either in terms of accuracy of stability.
>
> Barring any feedback on that I'll clean it up and maybe rename my tests
> from constexpr_all_the_things.cc to more_constexpr.cc ;-)
>
> It builds and tests cleanly on x86_64-linux.

Hmmh, according to the recent working draft the following complex
functions are *not* constexpr:

arg, proj

So, shouldn't their new C++20-constexpr specifiers be added
conditionally (In the sense of gcc extensions)?

- Daniel
Ed Smith-Rowland Nov. 16, 2018, 8:53 p.m. UTC | #2
On 11/16/18 12:38 PM, Daniel Krügler wrote:
> Am Fr., 16. Nov. 2018 um 18:13 Uhr schrieb Ed Smith-Rowland
> <3dw4rd@verizon.net>:
>> Greetings,
>>
>> This is late but I wanted to put it out there just to finish a thing.
>>
>> It's fairly straightforward constexpr of operators and some simple
>> functions for std::complex.
>>
>> The only thing that jumped out was the norm function.  We had this:
>>
>>       struct _Norm_helper<true>
>>       {
>>         template<typename _Tp>
>>           static inline _Tp _S_do_it(const complex<_Tp>& __z)
>>           {
>>             _Tp __res = std::abs(__z);
>>             return __res * __res;
>>           }
>>       };
>>
>> Since abs can't be made constexpr for complex since it involves sqrt (It
>> probably could but that's another story) I had to fall back to the x^2 +
>> y^2.  I don't know who that will bother.  This version should be faster
>> and I can't think of any useful trustworthy difference numerically
>> either in terms of accuracy of stability.
>>
>> Barring any feedback on that I'll clean it up and maybe rename my tests
>> from constexpr_all_the_things.cc to more_constexpr.cc ;-)
>>
>> It builds and tests cleanly on x86_64-linux.
> Hmmh, according to the recent working draft the following complex
> functions are *not* constexpr:
>
> arg, proj
>
> So, shouldn't their new C++20-constexpr specifiers be added
> conditionally (In the sense of gcc extensions)?
>
> - Daniel
>
I did not see that those were not constexpr.  I guess arg needs atan2 
and proj

I'll remove the constexpr on those and adjust everything.

Thank you.

Ed
Ed Smith-Rowland Nov. 17, 2018, 12:39 a.m. UTC | #3
On 11/16/18 3:53 PM, Ed Smith-Rowland wrote:
> On 11/16/18 12:38 PM, Daniel Krügler wrote:
>> Am Fr., 16. Nov. 2018 um 18:13 Uhr schrieb Ed Smith-Rowland
>> <3dw4rd@verizon.net>:
>>> Greetings,
>>>
>>> This is late but I wanted to put it out there just to finish a thing.
>>>
>>> It's fairly straightforward constexpr of operators and some simple
>>> functions for std::complex.
>>>
>>> The only thing that jumped out was the norm function.  We had this:
>>>
>>>       struct _Norm_helper<true>
>>>       {
>>>         template<typename _Tp>
>>>           static inline _Tp _S_do_it(const complex<_Tp>& __z)
>>>           {
>>>             _Tp __res = std::abs(__z);
>>>             return __res * __res;
>>>           }
>>>       };
>>>
>>> Since abs can't be made constexpr for complex since it involves sqrt 
>>> (It
>>> probably could but that's another story) I had to fall back to the 
>>> x^2 +
>>> y^2.  I don't know who that will bother.  This version should be faster
>>> and I can't think of any useful trustworthy difference numerically
>>> either in terms of accuracy of stability.
>>>
>>> Barring any feedback on that I'll clean it up and maybe rename my tests
>>> from constexpr_all_the_things.cc to more_constexpr.cc ;-)
>>>
>>> It builds and tests cleanly on x86_64-linux.
>> Hmmh, according to the recent working draft the following complex
>> functions are *not* constexpr:
>>
>> arg, proj
>>
>> So, shouldn't their new C++20-constexpr specifiers be added
>> conditionally (In the sense of gcc extensions)?
>>
>> - Daniel
>>
> I did not see that those were not constexpr.  I guess arg needs atan2 
> and proj
>
> I'll remove the constexpr on those and adjust everything.
>
> Thank you.
>
> Ed
>
All,

Here is the cleaned up, conformant patch.

Builds and tests cleanly on x86_64-linux.

Is this OK or should I really wait?

Ed
2018-11-17  Edward Smith-Rowland  <3dw4rd@verizon.net>

	Implement P0415 More constexpr for std::complex.
	* include/std/complex (conj(complex<Tp>), norm(complex<Tp>)): Constexpr;
	(real(Tp), imag(Tp)): Constexpr;
	(operator@=(Tp), operator@=(complex<Tp>)): Constexpr;
	(operator@(Tp,complex<Tp>), operator@(complex<Tp>,Tp)
	operator@(complex<Tp>,complex<Tp>)): Constexpr.
	* testsuite/26_numerics/complex/comparison_operators/
	more_constexpr.cc: New test.
	* testsuite/26_numerics/complex/operators/more_constexpr.cc: New test.
	* testsuite/26_numerics/complex/requirements/
	more_constexpr.cc: New test.
	* testsuite/26_numerics/complex/value_operations/
	more_constexpr.cc: New test.
	* testsuite/26_numerics/headers/complex/synopsis.cc:
	Add _GLIBCXX20_CONSTEXPR to applicable operators; Add missing proj().
Index: include/std/complex
===================================================================
--- include/std/complex	(revision 266189)
+++ include/std/complex	(working copy)
@@ -70,10 +70,11 @@
   ///  Return phase angle of @a z.
   template<typename _Tp> _Tp arg(const complex<_Tp>&);
   ///  Return @a z magnitude squared.
-  template<typename _Tp> _Tp norm(const complex<_Tp>&);
+  template<typename _Tp> _Tp _GLIBCXX20_CONSTEXPR norm(const complex<_Tp>&);
 
   ///  Return complex conjugate of @a z.
-  template<typename _Tp> complex<_Tp> conj(const complex<_Tp>&);
+  template<typename _Tp>
+    _GLIBCXX20_CONSTEXPR complex<_Tp> conj(const complex<_Tp>&);
   ///  Return complex with magnitude @a rho and angle @a theta.
   template<typename _Tp> complex<_Tp> polar(const _Tp&, const _Tp& = 0);
 
@@ -169,18 +170,18 @@
 
       // _GLIBCXX_RESOLVE_LIB_DEFECTS
       // DR 387. std::complex over-encapsulated.
-      void
+      _GLIBCXX20_CONSTEXPR void
       real(_Tp __val) { _M_real = __val; }
 
-      void
+      _GLIBCXX20_CONSTEXPR void
       imag(_Tp __val) { _M_imag = __val; }
 
       /// Assign a scalar to this complex number.
-      complex<_Tp>& operator=(const _Tp&);
+      _GLIBCXX20_CONSTEXPR complex<_Tp>& operator=(const _Tp&);
 
       /// Add a scalar to this complex number.
       // 26.2.5/1
-      complex<_Tp>&
+      _GLIBCXX20_CONSTEXPR complex<_Tp>&
       operator+=(const _Tp& __t)
       {
 	_M_real += __t;
@@ -189,7 +190,7 @@
 
       /// Subtract a scalar from this complex number.
       // 26.2.5/3
-      complex<_Tp>&
+      _GLIBCXX20_CONSTEXPR complex<_Tp>&
       operator-=(const _Tp& __t)
       {
 	_M_real -= __t;
@@ -197,30 +198,30 @@
       }
 
       /// Multiply this complex number by a scalar.
-      complex<_Tp>& operator*=(const _Tp&);
+      _GLIBCXX20_CONSTEXPR complex<_Tp>& operator*=(const _Tp&);
       /// Divide this complex number by a scalar.
-      complex<_Tp>& operator/=(const _Tp&);
+      _GLIBCXX20_CONSTEXPR complex<_Tp>& operator/=(const _Tp&);
 
       // Let the compiler synthesize the copy assignment operator
 #if __cplusplus >= 201103L
-      complex& operator=(const complex&) = default;
+      _GLIBCXX20_CONSTEXPR complex& operator=(const complex&) = default;
 #endif
 
       /// Assign another complex number to this one.
       template<typename _Up>
-        complex<_Tp>& operator=(const complex<_Up>&);
+        _GLIBCXX20_CONSTEXPR complex<_Tp>& operator=(const complex<_Up>&);
       /// Add another complex number to this one.
       template<typename _Up>
-        complex<_Tp>& operator+=(const complex<_Up>&);
+        _GLIBCXX20_CONSTEXPR complex<_Tp>& operator+=(const complex<_Up>&);
       /// Subtract another complex number from this one.
       template<typename _Up>
-        complex<_Tp>& operator-=(const complex<_Up>&);
+        _GLIBCXX20_CONSTEXPR complex<_Tp>& operator-=(const complex<_Up>&);
       /// Multiply this complex number by another.
       template<typename _Up>
-        complex<_Tp>& operator*=(const complex<_Up>&);
+        _GLIBCXX20_CONSTEXPR complex<_Tp>& operator*=(const complex<_Up>&);
       /// Divide this complex number by another.
       template<typename _Up>
-        complex<_Tp>& operator/=(const complex<_Up>&);
+        _GLIBCXX20_CONSTEXPR complex<_Tp>& operator/=(const complex<_Up>&);
 
       _GLIBCXX_CONSTEXPR complex __rep() const
       { return *this; }
@@ -231,7 +232,7 @@
     };
 
   template<typename _Tp>
-    complex<_Tp>&
+    _GLIBCXX20_CONSTEXPR complex<_Tp>&
     complex<_Tp>::operator=(const _Tp& __t)
     {
      _M_real = __t;
@@ -241,7 +242,7 @@
 
   // 26.2.5/5
   template<typename _Tp>
-    complex<_Tp>&
+    _GLIBCXX20_CONSTEXPR complex<_Tp>&
     complex<_Tp>::operator*=(const _Tp& __t)
     {
       _M_real *= __t;
@@ -251,7 +252,7 @@
 
   // 26.2.5/7
   template<typename _Tp>
-    complex<_Tp>&
+    _GLIBCXX20_CONSTEXPR complex<_Tp>&
     complex<_Tp>::operator/=(const _Tp& __t)
     {
       _M_real /= __t;
@@ -261,7 +262,7 @@
 
   template<typename _Tp>
     template<typename _Up>
-    complex<_Tp>&
+    _GLIBCXX20_CONSTEXPR complex<_Tp>&
     complex<_Tp>::operator=(const complex<_Up>& __z)
     {
       _M_real = __z.real();
@@ -272,7 +273,7 @@
   // 26.2.5/9
   template<typename _Tp>
     template<typename _Up>
-    complex<_Tp>&
+    _GLIBCXX20_CONSTEXPR complex<_Tp>&
     complex<_Tp>::operator+=(const complex<_Up>& __z)
     {
       _M_real += __z.real();
@@ -283,7 +284,7 @@
   // 26.2.5/11
   template<typename _Tp>
     template<typename _Up>
-    complex<_Tp>&
+    _GLIBCXX20_CONSTEXPR complex<_Tp>&
     complex<_Tp>::operator-=(const complex<_Up>& __z)
     {
       _M_real -= __z.real();
@@ -295,7 +296,7 @@
   // XXX: This is a grammar school implementation.
   template<typename _Tp>
     template<typename _Up>
-    complex<_Tp>&
+    _GLIBCXX20_CONSTEXPR complex<_Tp>&
     complex<_Tp>::operator*=(const complex<_Up>& __z)
     {
       const _Tp __r = _M_real * __z.real() - _M_imag * __z.imag();
@@ -308,7 +309,7 @@
   // XXX: This is a grammar school implementation.
   template<typename _Tp>
     template<typename _Up>
-    complex<_Tp>&
+    _GLIBCXX20_CONSTEXPR complex<_Tp>&
     complex<_Tp>::operator/=(const complex<_Up>& __z)
     {
       const _Tp __r =  _M_real * __z.real() + _M_imag * __z.imag();
@@ -322,67 +323,43 @@
   //@{
   ///  Return new complex value @a x plus @a y.
   template<typename _Tp>
-    inline complex<_Tp>
+    inline _GLIBCXX20_CONSTEXPR complex<_Tp>
     operator+(const complex<_Tp>& __x, const complex<_Tp>& __y)
-    {
-      complex<_Tp> __r = __x;
-      __r += __y;
-      return __r;
-    }
+    { return complex<_Tp>(__x.real() + __y.real(), __x.imag() + __y.imag()); }
 
   template<typename _Tp>
-    inline complex<_Tp>
+    inline _GLIBCXX20_CONSTEXPR complex<_Tp>
     operator+(const complex<_Tp>& __x, const _Tp& __y)
-    {
-      complex<_Tp> __r = __x;
-      __r += __y;
-      return __r;
-    }
+    { return complex<_Tp>(__x.real() + __y, __x.imag()); }
 
   template<typename _Tp>
-    inline complex<_Tp>
+    inline _GLIBCXX20_CONSTEXPR complex<_Tp>
     operator+(const _Tp& __x, const complex<_Tp>& __y)
-    {
-      complex<_Tp> __r = __y;
-      __r += __x;
-      return __r;
-    }
+    { return complex<_Tp>(__x + __y.real(), __y.imag()); }
   //@}
 
   //@{
   ///  Return new complex value @a x minus @a y.
   template<typename _Tp>
-    inline complex<_Tp>
+    inline _GLIBCXX20_CONSTEXPR complex<_Tp>
     operator-(const complex<_Tp>& __x, const complex<_Tp>& __y)
-    {
-      complex<_Tp> __r = __x;
-      __r -= __y;
-      return __r;
-    }
+    { return complex<_Tp>(__x.real() - __y.real(), __x.imag() - __y.imag()); }
 
   template<typename _Tp>
-    inline complex<_Tp>
+    inline _GLIBCXX20_CONSTEXPR complex<_Tp>
     operator-(const complex<_Tp>& __x, const _Tp& __y)
-    {
-      complex<_Tp> __r = __x;
-      __r -= __y;
-      return __r;
-    }
+    { return complex<_Tp>(__x.real() - __y, __x.imag()); }
 
   template<typename _Tp>
-    inline complex<_Tp>
+    inline _GLIBCXX20_CONSTEXPR complex<_Tp>
     operator-(const _Tp& __x, const complex<_Tp>& __y)
-    {
-      complex<_Tp> __r(__x, -__y.imag());
-      __r -= __y.real();
-      return __r;
-    }
+    { return complex<_Tp>(__x - __y.real(), -__y.imag()); }
   //@}
 
   //@{
   ///  Return new complex value @a x times @a y.
   template<typename _Tp>
-    inline complex<_Tp>
+    inline _GLIBCXX20_CONSTEXPR complex<_Tp>
     operator*(const complex<_Tp>& __x, const complex<_Tp>& __y)
     {
       complex<_Tp> __r = __x;
@@ -391,7 +368,7 @@
     }
 
   template<typename _Tp>
-    inline complex<_Tp>
+    inline _GLIBCXX20_CONSTEXPR complex<_Tp>
     operator*(const complex<_Tp>& __x, const _Tp& __y)
     {
       complex<_Tp> __r = __x;
@@ -400,7 +377,7 @@
     }
 
   template<typename _Tp>
-    inline complex<_Tp>
+    inline _GLIBCXX20_CONSTEXPR complex<_Tp>
     operator*(const _Tp& __x, const complex<_Tp>& __y)
     {
       complex<_Tp> __r = __y;
@@ -412,7 +389,7 @@
   //@{
   ///  Return new complex value @a x divided by @a y.
   template<typename _Tp>
-    inline complex<_Tp>
+    inline _GLIBCXX20_CONSTEXPR complex<_Tp>
     operator/(const complex<_Tp>& __x, const complex<_Tp>& __y)
     {
       complex<_Tp> __r = __x;
@@ -421,7 +398,7 @@
     }
 
   template<typename _Tp>
-    inline complex<_Tp>
+    inline _GLIBCXX20_CONSTEXPR complex<_Tp>
     operator/(const complex<_Tp>& __x, const _Tp& __y)
     {
       complex<_Tp> __r = __x;
@@ -430,7 +407,7 @@
     }
 
   template<typename _Tp>
-    inline complex<_Tp>
+    inline _GLIBCXX20_CONSTEXPR complex<_Tp>
     operator/(const _Tp& __x, const complex<_Tp>& __y)
     {
       complex<_Tp> __r = __x;
@@ -441,15 +418,15 @@
 
   ///  Return @a x.
   template<typename _Tp>
-    inline complex<_Tp>
+    inline _GLIBCXX20_CONSTEXPR complex<_Tp>
     operator+(const complex<_Tp>& __x)
     { return __x; }
 
   ///  Return complex negation of @a x.
   template<typename _Tp>
-    inline complex<_Tp>
+    inline _GLIBCXX20_CONSTEXPR complex<_Tp>
     operator-(const complex<_Tp>& __x)
-    {  return complex<_Tp>(-__x.real(), -__x.imag()); }
+    { return complex<_Tp>(-__x.real(), -__x.imag()); }
 
   //@{
   ///  Return true if @a x is equal to @a y.
@@ -658,7 +635,7 @@
     struct _Norm_helper
     {
       template<typename _Tp>
-        static inline _Tp _S_do_it(const complex<_Tp>& __z)
+        static inline _GLIBCXX_CONSTEXPR _Tp _S_do_it(const complex<_Tp>& __z)
         {
           const _Tp __x = __z.real();
           const _Tp __y = __z.imag();
@@ -670,15 +647,18 @@
     struct _Norm_helper<true>
     {
       template<typename _Tp>
-        static inline _Tp _S_do_it(const complex<_Tp>& __z)
+        static inline _GLIBCXX_CONSTEXPR _Tp _S_do_it(const complex<_Tp>& __z)
         {
-          _Tp __res = std::abs(__z);
-          return __res * __res;
+          //_Tp __res = std::abs(__z);
+          //return __res * __res;
+          const _Tp __x = __z.real();
+          const _Tp __y = __z.imag();
+          return __x * __x + __y * __y;
         }
     };
 
   template<typename _Tp>
-    inline _Tp
+    inline _GLIBCXX20_CONSTEXPR _Tp
     norm(const complex<_Tp>& __z)
     {
       return _Norm_helper<__is_floating<_Tp>::__value
@@ -694,7 +674,7 @@
     }
 
   template<typename _Tp>
-    inline complex<_Tp>
+    inline _GLIBCXX20_CONSTEXPR complex<_Tp>
     conj(const complex<_Tp>& __z)
     { return complex<_Tp>(__z.real(), -__z.imag()); }
 
@@ -1115,13 +1095,13 @@
 
       // _GLIBCXX_RESOLVE_LIB_DEFECTS
       // DR 387. std::complex over-encapsulated.
-      void
+      _GLIBCXX20_CONSTEXPR void
       real(float __val) { __real__ _M_value = __val; }
 
-      void
+      _GLIBCXX20_CONSTEXPR void
       imag(float __val) { __imag__ _M_value = __val; }
 
-      complex&
+      _GLIBCXX20_CONSTEXPR complex&
       operator=(float __f)
       {
 	_M_value = __f;
@@ -1128,7 +1108,7 @@
 	return *this;
       }
 
-      complex&
+      _GLIBCXX20_CONSTEXPR complex&
       operator+=(float __f)
       {
 	_M_value += __f;
@@ -1135,7 +1115,7 @@
 	return *this;
       }
 
-      complex&
+      _GLIBCXX20_CONSTEXPR complex&
       operator-=(float __f)
       {
 	_M_value -= __f;
@@ -1142,7 +1122,7 @@
 	return *this;
       }
 
-      complex&
+      _GLIBCXX20_CONSTEXPR complex&
       operator*=(float __f)
       {
 	_M_value *= __f;
@@ -1149,7 +1129,7 @@
 	return *this;
       }
 
-      complex&
+      _GLIBCXX20_CONSTEXPR complex&
       operator/=(float __f)
       {
 	_M_value /= __f;
@@ -1163,50 +1143,43 @@
 #endif
 
       template<typename _Tp>
-        complex&
+        _GLIBCXX20_CONSTEXPR complex&
         operator=(const complex<_Tp>&  __z)
 	{
-	  __real__ _M_value = __z.real();
-	  __imag__ _M_value = __z.imag();
+	  _M_value = __z.__rep();
 	  return *this;
 	}
 
       template<typename _Tp>
-        complex&
+        _GLIBCXX20_CONSTEXPR complex&
         operator+=(const complex<_Tp>& __z)
 	{
-	  __real__ _M_value += __z.real();
-	  __imag__ _M_value += __z.imag();
+	  _M_value += __z.__rep();
 	  return *this;
 	}
 
       template<class _Tp>
-        complex&
+        _GLIBCXX20_CONSTEXPR complex&
         operator-=(const complex<_Tp>& __z)
 	{
-	  __real__ _M_value -= __z.real();
-	  __imag__ _M_value -= __z.imag();
+	  _M_value -= __z.__rep();
 	  return *this;
 	}
 
       template<class _Tp>
-        complex&
+        _GLIBCXX20_CONSTEXPR complex&
         operator*=(const complex<_Tp>& __z)
 	{
-	  _ComplexT __t;
-	  __real__ __t = __z.real();
-	  __imag__ __t = __z.imag();
+	  const _ComplexT __t = __z.__rep();
 	  _M_value *= __t;
 	  return *this;
 	}
 
       template<class _Tp>
-        complex&
+        _GLIBCXX20_CONSTEXPR complex&
         operator/=(const complex<_Tp>& __z)
 	{
-	  _ComplexT __t;
-	  __real__ __t = __z.real();
-	  __imag__ __t = __z.imag();
+	  const _ComplexT __t = __z.__rep();
 	  _M_value /= __t;
 	  return *this;
 	}
@@ -1268,13 +1241,13 @@
 
       // _GLIBCXX_RESOLVE_LIB_DEFECTS
       // DR 387. std::complex over-encapsulated.
-      void
+      _GLIBCXX20_CONSTEXPR void
       real(double __val) { __real__ _M_value = __val; }
 
-      void
+      _GLIBCXX20_CONSTEXPR void
       imag(double __val) { __imag__ _M_value = __val; }
 
-      complex&
+      _GLIBCXX20_CONSTEXPR complex&
       operator=(double __d)
       {
 	_M_value = __d;
@@ -1281,7 +1254,7 @@
 	return *this;
       }
 
-      complex&
+      _GLIBCXX20_CONSTEXPR complex&
       operator+=(double __d)
       {
 	_M_value += __d;
@@ -1288,7 +1261,7 @@
 	return *this;
       }
 
-      complex&
+      _GLIBCXX20_CONSTEXPR complex&
       operator-=(double __d)
       {
 	_M_value -= __d;
@@ -1295,7 +1268,7 @@
 	return *this;
       }
 
-      complex&
+      _GLIBCXX20_CONSTEXPR complex&
       operator*=(double __d)
       {
 	_M_value *= __d;
@@ -1302,7 +1275,7 @@
 	return *this;
       }
 
-      complex&
+      _GLIBCXX20_CONSTEXPR complex&
       operator/=(double __d)
       {
 	_M_value /= __d;
@@ -1315,50 +1288,43 @@
 #endif
 
       template<typename _Tp>
-        complex&
+        _GLIBCXX20_CONSTEXPR complex&
         operator=(const complex<_Tp>& __z)
 	{
-	  __real__ _M_value = __z.real();
-	  __imag__ _M_value = __z.imag();
+	  _M_value = __z.__rep();
 	  return *this;
 	}
 
       template<typename _Tp>
-        complex&
+        _GLIBCXX20_CONSTEXPR complex&
         operator+=(const complex<_Tp>& __z)
 	{
-	  __real__ _M_value += __z.real();
-	  __imag__ _M_value += __z.imag();
+	  _M_value += __z.__rep();
 	  return *this;
 	}
 
       template<typename _Tp>
-        complex&
+        _GLIBCXX20_CONSTEXPR complex&
         operator-=(const complex<_Tp>& __z)
 	{
-	  __real__ _M_value -= __z.real();
-	  __imag__ _M_value -= __z.imag();
+	  _M_value -= __z.__rep();
 	  return *this;
 	}
 
       template<typename _Tp>
-        complex&
+        _GLIBCXX20_CONSTEXPR complex&
         operator*=(const complex<_Tp>& __z)
 	{
-	  _ComplexT __t;
-	  __real__ __t = __z.real();
-	  __imag__ __t = __z.imag();
+	  const _ComplexT __t = __z.__rep();
 	  _M_value *= __t;
 	  return *this;
 	}
 
       template<typename _Tp>
-        complex&
+        _GLIBCXX20_CONSTEXPR complex&
         operator/=(const complex<_Tp>& __z)
 	{
-	  _ComplexT __t;
-	  __real__ __t = __z.real();
-	  __imag__ __t = __z.imag();
+	  const _ComplexT __t = __z.__rep();
 	  _M_value /= __t;
 	  return *this;
 	}
@@ -1422,13 +1388,13 @@
 
       // _GLIBCXX_RESOLVE_LIB_DEFECTS
       // DR 387. std::complex over-encapsulated.
-      void
+      _GLIBCXX20_CONSTEXPR void
       real(long double __val) { __real__ _M_value = __val; }
 
-      void
+      _GLIBCXX20_CONSTEXPR void
       imag(long double __val) { __imag__ _M_value = __val; }
 
-      complex&
+      _GLIBCXX20_CONSTEXPR complex&
       operator=(long double __r)
       {
 	_M_value = __r;
@@ -1435,7 +1401,7 @@
 	return *this;
       }
 
-      complex&
+      _GLIBCXX20_CONSTEXPR complex&
       operator+=(long double __r)
       {
 	_M_value += __r;
@@ -1442,7 +1408,7 @@
 	return *this;
       }
 
-      complex&
+      _GLIBCXX20_CONSTEXPR complex&
       operator-=(long double __r)
       {
 	_M_value -= __r;
@@ -1449,7 +1415,7 @@
 	return *this;
       }
 
-      complex&
+      _GLIBCXX20_CONSTEXPR complex&
       operator*=(long double __r)
       {
 	_M_value *= __r;
@@ -1456,7 +1422,7 @@
 	return *this;
       }
 
-      complex&
+      _GLIBCXX20_CONSTEXPR complex&
       operator/=(long double __r)
       {
 	_M_value /= __r;
@@ -1469,50 +1435,43 @@
 #endif
 
       template<typename _Tp>
-        complex&
+        _GLIBCXX20_CONSTEXPR complex&
         operator=(const complex<_Tp>& __z)
 	{
-	  __real__ _M_value = __z.real();
-	  __imag__ _M_value = __z.imag();
+	  _M_value = __z.__rep();
 	  return *this;
 	}
 
       template<typename _Tp>
-        complex&
+        _GLIBCXX20_CONSTEXPR complex&
 	operator+=(const complex<_Tp>& __z)
 	{
-	  __real__ _M_value += __z.real();
-	  __imag__ _M_value += __z.imag();
+	  _M_value += __z.__rep();
 	  return *this;
 	}
 
       template<typename _Tp>
-        complex&
+        _GLIBCXX20_CONSTEXPR complex&
 	operator-=(const complex<_Tp>& __z)
 	{
-	  __real__ _M_value -= __z.real();
-	  __imag__ _M_value -= __z.imag();
+	  _M_value -= __z.__rep();
 	  return *this;
 	}
 
       template<typename _Tp>
-        complex&
+        _GLIBCXX20_CONSTEXPR complex&
 	operator*=(const complex<_Tp>& __z)
 	{
-	  _ComplexT __t;
-	  __real__ __t = __z.real();
-	  __imag__ __t = __z.imag();
+	  const _ComplexT __t = __z.__rep();
 	  _M_value *= __t;
 	  return *this;
 	}
 
       template<typename _Tp>
-        complex&
+        _GLIBCXX20_CONSTEXPR complex&
 	operator/=(const complex<_Tp>& __z)
 	{
-	  _ComplexT __t;
-	  __real__ __t = __z.real();
-	  __imag__ __t = __z.imag();
+	  const _ComplexT __t = __z.__rep();
 	  _M_value /= __t;
 	  return *this;
 	}
@@ -1872,7 +1831,7 @@
     { return _Tp(); }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__promote<_Tp>::__type
+    _GLIBCXX_CONSTEXPR inline typename __gnu_cxx::__promote<_Tp>::__type
     norm(_Tp __x)
     {
       typedef typename __gnu_cxx::__promote<_Tp>::__type __type;
@@ -1911,7 +1870,8 @@
 
   // Forward declarations.
   // DR 781.
-  template<typename _Tp> std::complex<_Tp> proj(const std::complex<_Tp>&);
+  template<typename _Tp>
+    std::complex<_Tp> proj(const std::complex<_Tp>&);
 
   template<typename _Tp>
     std::complex<_Tp>
@@ -1957,7 +1917,8 @@
     }
 
   template<typename _Tp>
-    inline std::complex<typename __gnu_cxx::__promote<_Tp>::__type>
+    inline _GLIBCXX20_CONSTEXPR
+	std::complex<typename __gnu_cxx::__promote<_Tp>::__type>
     conj(_Tp __x)
     {
       typedef typename __gnu_cxx::__promote<_Tp>::__type __type;
Index: testsuite/26_numerics/complex/comparison_operators/more_constexpr.cc
===================================================================
--- testsuite/26_numerics/complex/comparison_operators/more_constexpr.cc	(nonexistent)
+++ testsuite/26_numerics/complex/comparison_operators/more_constexpr.cc	(working copy)
@@ -0,0 +1,51 @@
+// { dg-do compile { target c++2a } }
+
+// Copyright (C) 2018 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/>.
+
+#include <complex>
+#include <testsuite_common_types.h>
+
+template<bool ok>
+  struct thing
+  { };
+
+// 
+template<typename _Tp>
+  void
+  test_comparison()
+  {
+    constexpr std::complex<_Tp> a{1.1, 2.2};
+    constexpr std::complex<_Tp> b{3.3, 4.4};
+    if constexpr (a == b)
+      auto c [[maybe_unused]] = a + b;
+    if constexpr (a != b)
+      auto c [[maybe_unused]] = a - b;
+
+    thing<a == b> thing1 [[maybe_unused]];
+    thing<a != b> thing2 [[maybe_unused]];
+  }
+
+int
+main()
+{
+  test_comparison<float>();
+  test_comparison<double>();
+  test_comparison<long double>();
+
+  return 0;
+}
Index: testsuite/26_numerics/complex/operators/more_constexpr.cc
===================================================================
--- testsuite/26_numerics/complex/operators/more_constexpr.cc	(nonexistent)
+++ testsuite/26_numerics/complex/operators/more_constexpr.cc	(working copy)
@@ -0,0 +1,61 @@
+// { dg-do compile { target c++2a } }
+
+// Copyright (C) 2018 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/>.
+
+#include <complex>
+#include <testsuite_common_types.h>
+
+namespace __gnu_test
+{
+  // Test constexpr symmetric complex @ real, real @ complex, complex @ complex.
+  template<typename _Tp>
+    void
+    test_operators()
+    {
+      constexpr std::complex<_Tp> a{1, 2};
+      constexpr std::complex<_Tp> b{3, 4};
+      constexpr _Tp c = 5;
+
+      constexpr auto w [[maybe_unused]] = +a;
+      constexpr auto z [[maybe_unused]] = -a;
+
+      constexpr auto apc [[maybe_unused]] = a + c;
+      constexpr auto amc [[maybe_unused]] = a - c;
+      constexpr auto atc [[maybe_unused]] = a * c;
+      constexpr auto adc [[maybe_unused]] = a / c;
+
+      constexpr auto cpa [[maybe_unused]] = c + a;
+      constexpr auto cma [[maybe_unused]] = c - a;
+      constexpr auto cta [[maybe_unused]] = c * a;
+      constexpr auto cda [[maybe_unused]] = c / a;
+
+      constexpr auto apb [[maybe_unused]] = a + b;
+      constexpr auto amb [[maybe_unused]] = a - b;
+      constexpr auto atb [[maybe_unused]] = a * b;
+      constexpr auto adb [[maybe_unused]] = a / b;
+    }
+}
+
+int main()
+{
+  __gnu_test::test_operators<float>();
+  __gnu_test::test_operators<double>();
+  __gnu_test::test_operators<long double>();
+
+  return 0;
+}
Index: testsuite/26_numerics/complex/requirements/more_constexpr.cc
===================================================================
--- testsuite/26_numerics/complex/requirements/more_constexpr.cc	(nonexistent)
+++ testsuite/26_numerics/complex/requirements/more_constexpr.cc	(working copy)
@@ -0,0 +1,170 @@
+// { dg-do compile { target c++2a } }
+
+// Copyright (C) 2018 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/>.
+
+#include <complex>
+#include <testsuite_common_types.h>
+
+namespace __gnu_test
+{
+
+  // Test constexpr real(val) imag(val).
+  template<typename _Tp, const int _Val = 42>
+    inline void
+    set_real(std::complex<_Tp>& a)
+    { a.real(_Val); }
+
+  template<typename _Tp, const int _Val = 42>
+    inline void
+    set_imag(std::complex<_Tp>& a)
+    { a.imag(_Val); }
+
+  template<typename _Tp>
+    void
+    test_members()
+    {
+      constexpr std::complex<_Tp> a{1.1, 2.2};
+
+      std::complex<_Tp> z = a;
+
+      set_real<_Tp, 33>(z);
+      set_imag<_Tp, 44>(z);
+    }
+
+  // Test operators @=complex and @=real.
+  template<typename _Tp, typename _Up>
+    constexpr std::complex<_Tp>
+    sum(const std::complex<_Tp>& z, const std::complex<_Up>& w)
+    {
+      std::complex<_Tp> x = z;
+      x += w;
+      return x;
+    }
+
+  template<typename _Tp, typename _Up>
+    constexpr std::complex<_Tp>
+    sum(const std::complex<_Tp>& z, _Up w)
+    {
+      std::complex<_Tp> x = z;
+      x += w;
+      return x;
+    }
+
+  template<typename _Tp, typename _Up>
+    constexpr std::complex<_Tp>
+    dif(const std::complex<_Tp>& z, const std::complex<_Up>& w)
+    {
+      std::complex<_Tp> x = z;
+      x -= w;
+      return x;
+    }
+
+  template<typename _Tp, typename _Up>
+    constexpr std::complex<_Tp>
+    dif(const std::complex<_Tp>& z, _Up w)
+    {
+      std::complex<_Tp> x = z;
+      x -= w;
+      return x;
+    }
+
+  template<typename _Tp, typename _Up>
+    constexpr std::complex<_Tp>
+    prod(const std::complex<_Tp>& z, const std::complex<_Up>& w)
+    {
+      std::complex<_Tp> x = z;
+      x *= w;
+      return x;
+    }
+
+  template<typename _Tp, typename _Up>
+    constexpr std::complex<_Tp>
+    prod(const std::complex<_Tp>& z, _Up w)
+    {
+      std::complex<_Tp> x = z;
+      x *= w;
+      return x;
+    }
+
+  template<typename _Tp, typename _Up>
+    constexpr std::complex<_Tp>
+    quot(const std::complex<_Tp>& z, const std::complex<_Up>& w)
+    {
+      std::complex<_Tp> x = z;
+      x /= w;
+      return x;
+    }
+
+  template<typename _Tp, typename _Up>
+    constexpr std::complex<_Tp>
+    quot(const std::complex<_Tp>& z, _Up w)
+    {
+      std::complex<_Tp> x = z;
+      x /= w;
+      return x;
+    }
+
+  template<typename _Tp, typename _Up>
+    void
+    test_operator_members()
+    {
+      constexpr std::complex<_Tp> a{10, 20};
+      constexpr std::complex<_Up> b{6, 8};
+      constexpr _Up c{10};
+
+      constexpr auto apc = sum(a, c);
+      static_assert(apc == std::complex<_Tp>{20, 20});
+      constexpr auto amc = dif(a, c);
+      static_assert(amc == std::complex<_Tp>{0, 20});
+      constexpr auto atc = prod(a, c);
+      static_assert(atc == std::complex<_Tp>{100, 200});
+      constexpr auto adc = quot(a, c);
+      static_assert(adc == std::complex<_Tp>{1, 2});
+
+      constexpr auto apb = sum(a, b);
+      static_assert(apb == std::complex<_Tp>{16, 28});
+      constexpr auto amb = dif(a, b);
+      static_assert(amb == std::complex<_Tp>{4, 12});
+      constexpr auto atb = prod(a, b);
+      static_assert(atb == std::complex<_Tp>{-100, 200});
+      constexpr auto adb = quot(a, b);
+      static_assert(adb == std::complex<_Tp>{11/_Tp{5}, 2/_Tp{5}});
+    }
+}
+
+int main()
+{
+  __gnu_test::test_members<float>();
+  __gnu_test::test_members<double>();
+  __gnu_test::test_members<long double>();
+
+  __gnu_test::test_operator_members<float, float>();
+  __gnu_test::test_operator_members<float, double>();
+  __gnu_test::test_operator_members<float, long double>();
+  __gnu_test::test_operator_members<double, float>();
+  __gnu_test::test_operator_members<double, double>();
+  __gnu_test::test_operator_members<double, long double>();
+  __gnu_test::test_operator_members<long double, float>();
+  __gnu_test::test_operator_members<long double, double>();
+  __gnu_test::test_operator_members<long double, long double>();
+
+  // Test primary template.
+  __gnu_test::test_operator_members<__float128, __float128>();
+
+  return 0;
+}
Index: testsuite/26_numerics/complex/value_operations/more_constexpr.cc
===================================================================
--- testsuite/26_numerics/complex/value_operations/more_constexpr.cc	(nonexistent)
+++ testsuite/26_numerics/complex/value_operations/more_constexpr.cc	(working copy)
@@ -0,0 +1,58 @@
+// { dg-do compile { target c++2a } }
+
+// Copyright (C) 2018 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/>.
+
+#include <complex>
+#include <testsuite_common_types.h>
+
+namespace __gnu_test
+{
+  struct constexpr_functions
+  {
+    template<typename _Ttesttype>
+      void
+      operator()()
+      {
+	struct _Concept
+	{
+	  void __constraint()
+	  { 
+	    typedef typename _Ttesttype::_ComplexT _ComplexT;
+	    constexpr _ComplexT cc = { 1.1 };
+	    constexpr _Ttesttype a(cc);
+	    constexpr auto v1 [[maybe_unused]] = norm(a);
+	    constexpr auto v2 [[maybe_unused]] = conj(a);
+	  }
+	};
+
+	_Concept c;
+	c.__constraint();
+      }
+  };
+}
+
+int main()
+{
+  __gnu_test::constexpr_functions test;
+
+  test.operator()<std::complex<float>>();
+  test.operator()<std::complex<double>>();
+  test.operator()<std::complex<long double>>();
+
+  return 0;
+}
Index: testsuite/26_numerics/headers/complex/synopsis.cc
===================================================================
--- testsuite/26_numerics/headers/complex/synopsis.cc	(revision 266189)
+++ testsuite/26_numerics/headers/complex/synopsis.cc	(working copy)
@@ -28,51 +28,71 @@
 
   // 26.2.6 operators:
   template<class T>
-    complex<T> operator+(const complex<T>&, const complex<T>&);
-  template<class T> complex<T> operator+(const complex<T>&, const T&);
-  template<class T> complex<T> operator+(const T&, const complex<T>&);
-  template<class T> complex<T> operator-
+    _GLIBCXX20_CONSTEXPR complex<T>
+    operator+(const complex<T>&, const complex<T>&);
+  template<class T>
+    _GLIBCXX20_CONSTEXPR complex<T> operator+(const complex<T>&, const T&);
+  template<class T>
+    _GLIBCXX20_CONSTEXPR complex<T> operator+(const T&, const complex<T>&);
+
+  template<class T>
+    _GLIBCXX20_CONSTEXPR complex<T>
+    operator-(const complex<T>&, const complex<T>&);
+  template<class T>
+    _GLIBCXX20_CONSTEXPR complex<T> operator-(const complex<T>&, const T&);
+  template<class T>
+    _GLIBCXX20_CONSTEXPR complex<T> operator-(const T&, const complex<T>&);
+
+  template<class T>
+    _GLIBCXX20_CONSTEXPR complex<T> operator*
     (const complex<T>&, const complex<T>&);
-  template<class T> complex<T> operator-(const complex<T>&, const T&);
-  template<class T> complex<T> operator-(const T&, const complex<T>&);
-  template<class T> complex<T> operator*
-    (const complex<T>&, const complex<T>&);
-  template<class T> complex<T> operator*(const complex<T>&, const T&);
-  template<class T> complex<T> operator*(const T&, const complex<T>&);
-  template<class T> complex<T> operator/
-    (const complex<T>&, const complex<T>&);
-  template<class T> complex<T> operator/(const complex<T>&, const T&);
-  template<class T> complex<T> operator/(const T&, const complex<T>&);
-  template<class T> complex<T> operator+(const complex<T>&);
-  template<class T> complex<T> operator-(const complex<T>&);
-  template<class T> _GLIBCXX_CONSTEXPR bool operator==
-    (const complex<T>&, const complex<T>&);
-  template<class T> _GLIBCXX_CONSTEXPR bool operator==
-    (const complex<T>&, const T&);
-  template<class T> _GLIBCXX_CONSTEXPR bool operator==
-    (const T&, const complex<T>&);
+  template<class T>
+    _GLIBCXX20_CONSTEXPR complex<T> operator*(const complex<T>&, const T&);
+  template<class T>
+    _GLIBCXX20_CONSTEXPR complex<T> operator*(const T&, const complex<T>&);
 
+  template<class T>
+    _GLIBCXX20_CONSTEXPR complex<T>
+    operator/(const complex<T>&, const complex<T>&);
+  template<class T>
+    _GLIBCXX20_CONSTEXPR complex<T> operator/(const complex<T>&, const T&);
+  template<class T>
+    _GLIBCXX20_CONSTEXPR complex<T> operator/(const T&, const complex<T>&);
 
-  template<class T> _GLIBCXX_CONSTEXPR bool operator!=
-    (const complex<T>&, const complex<T>&);
-  template<class T> _GLIBCXX_CONSTEXPR bool operator!=
-    (const complex<T>&, const T&);
-  template<class T> _GLIBCXX_CONSTEXPR bool operator!=
-    (const T&, const complex<T>&);
+  template<class T>
+    _GLIBCXX20_CONSTEXPR complex<T> operator+(const complex<T>&);
+  template<class T>
+    _GLIBCXX20_CONSTEXPR complex<T> operator-(const complex<T>&);
+
+  template<class T>
+    _GLIBCXX_CONSTEXPR bool operator==(const complex<T>&, const complex<T>&);
+  template<class T>
+     _GLIBCXX_CONSTEXPR bool operator==(const complex<T>&, const T&);
+  template<class T>
+    _GLIBCXX_CONSTEXPR bool operator==(const T&, const complex<T>&);
+
+  template<class T>
+    _GLIBCXX_CONSTEXPR bool operator!=(const complex<T>&, const complex<T>&);
+  template<class T>
+    _GLIBCXX_CONSTEXPR bool operator!=(const complex<T>&, const T&);
+  template<class T>
+    _GLIBCXX_CONSTEXPR bool operator!=(const T&, const complex<T>&);
+
   template<class T, class charT, class traits>
-  basic_istream<charT, traits>&
-  operator>>(basic_istream<charT, traits>&, complex<T>&);
+    basic_istream<charT, traits>&
+    operator>>(basic_istream<charT, traits>&, complex<T>&);
   template<class T, class charT, class traits>
-  basic_ostream<charT, traits>&
-  operator<<(basic_ostream<charT, traits>&, const complex<T>&);
+    basic_ostream<charT, traits>&
+    operator<<(basic_ostream<charT, traits>&, const complex<T>&);
 
   // 26.2.7 values:
   template<class T> _GLIBCXX_CONSTEXPR T real(const complex<T>&);
   template<class T> _GLIBCXX_CONSTEXPR T imag(const complex<T>&);
   template<class T> T abs(const complex<T>&);
-  template<class T> T arg(const complex<T>&);
-  template<class T> T norm(const complex<T>&);
-  template<class T> complex<T> conj(const complex<T>&);
+  template<class T> _GLIBCXX20_CONSTEXPR T arg(const complex<T>&);
+  template<class T> _GLIBCXX20_CONSTEXPR T norm(const complex<T>&);
+  template<class T> _GLIBCXX20_CONSTEXPR complex<T> conj(const complex<T>&);
+  template<class T> _GLIBCXX20_CONSTEXPR complex<T> proj(const complex<T>&);
   template<class T> complex<T> polar(const T& rho, const T& theta);
 
   // 26.2.8 transcendentals:
Jonathan Wakely Nov. 19, 2018, 11:13 a.m. UTC | #4
On 16/11/18 19:39 -0500, Ed Smith-Rowland wrote:
>@@ -322,67 +323,43 @@
>   //@{
>   ///  Return new complex value @a x plus @a y.
>   template<typename _Tp>
>-    inline complex<_Tp>
>+    inline _GLIBCXX20_CONSTEXPR complex<_Tp>
>     operator+(const complex<_Tp>& __x, const complex<_Tp>& __y)
>-    {
>-      complex<_Tp> __r = __x;
>-      __r += __y;
>-      return __r;
>-    }
>+    { return complex<_Tp>(__x.real() + __y.real(), __x.imag() + __y.imag()); }

Is this change (and all the similar ones) really needed?

Doesn't the fact that all the constructors and member operators of
std::complex mean that the original definition is also valid in a
constexpr function?

>@@ -1163,50 +1143,43 @@
> #endif
>
>       template<typename _Tp>
>-        complex&
>+        _GLIBCXX20_CONSTEXPR complex&
>         operator=(const complex<_Tp>&  __z)
> 	{
>-	  __real__ _M_value = __z.real();
>-	  __imag__ _M_value = __z.imag();
>+	  _M_value = __z.__rep();

These changes look OK, but I wonder if we shouldn't ask the compiler
to make it possible to use __real__ and __imag__ in constexpr
functions instead.

I assume it doesn't, and that's why you made this change. But if it
Just Worked, and the other changes I commented on above are also
unnecessary, then this patch would *mostly* just be adding
_GLIBCXX20_CONSTEXPR which is OK for stage 3 (as it doesn't affect any
dialects except C++2a).


>@@ -1872,7 +1831,7 @@
>     { return _Tp(); }
>
>   template<typename _Tp>
>-    inline typename __gnu_cxx::__promote<_Tp>::__type
>+    _GLIBCXX_CONSTEXPR inline typename __gnu_cxx::__promote<_Tp>::__type

This should be _GLIBCXX20_CONSTEXPR.

>Index: testsuite/26_numerics/complex/comparison_operators/more_constexpr.cc
>===================================================================
>--- testsuite/26_numerics/complex/comparison_operators/more_constexpr.cc	(nonexistent)
>+++ testsuite/26_numerics/complex/comparison_operators/more_constexpr.cc	(working copy)
>@@ -0,0 +1,51 @@
>+// { dg-do compile { target c++2a } }

All the tests with { target c++2a} should also have:

// { dg-options "-std=gnu++2a" }

Because otherwise they are skipped by default, and only get run when
RUNTESTFLAGS explicitly includes something like
--target_board=unix/-std=gnu++2a

The dg-options needs to come first, or it doesn't apply before the
check for { target c++2a }.
Ed Smith-Rowland Nov. 20, 2018, 10:58 p.m. UTC | #5
On 11/19/18 6:13 AM, Jonathan Wakely wrote:
> On 16/11/18 19:39 -0500, Ed Smith-Rowland wrote:
>> @@ -322,67 +323,43 @@
>>   //@{
>>   ///  Return new complex value @a x plus @a y.
>>   template<typename _Tp>
>> -    inline complex<_Tp>
>> +    inline _GLIBCXX20_CONSTEXPR complex<_Tp>
>>     operator+(const complex<_Tp>& __x, const complex<_Tp>& __y)
>> -    {
>> -      complex<_Tp> __r = __x;
>> -      __r += __y;
>> -      return __r;
>> -    }
>> +    { return complex<_Tp>(__x.real() + __y.real(), __x.imag() + 
>> __y.imag()); }
>
> Is this change (and all the similar ones) really needed?
>
> Doesn't the fact that all the constructors and member operators of
> std::complex mean that the original definition is also valid in a
> constexpr function?
These changes are rolled back. Sorry.
>> @@ -1163,50 +1143,43 @@
>> #endif
>>
>>       template<typename _Tp>
>> -        complex&
>> +        _GLIBCXX20_CONSTEXPR complex&
>>         operator=(const complex<_Tp>&  __z)
>>     {
>> -      __real__ _M_value = __z.real();
>> -      __imag__ _M_value = __z.imag();
>> +      _M_value = __z.__rep();
>
> These changes look OK, but I wonder if we shouldn't ask the compiler
> to make it possible to use __real__ and __imag__ in constexpr
> functions instead.
>
> I assume it doesn't, and that's why you made this change. But if it
> Just Worked, and the other changes I commented on above are also
> unnecessary, then this patch would *mostly* just be adding
> _GLIBCXX20_CONSTEXPR which is OK for stage 3 (as it doesn't affect any
> dialects except C++2a).

Yes, this is the issue.  I agree that constexpr _real__, __imag__would 
be better.

Do you have any idea where this change would be?  I grepped around a 
little and couldn't figure it out.  if you don't I'll look more.

Actually, looking at constexpr.c it looks like the old way ought to work...

OK, plain assignment works but not the others.  Interesting.

>
>> @@ -1872,7 +1831,7 @@
>>     { return _Tp(); }
>>
>>   template<typename _Tp>
>> -    inline typename __gnu_cxx::__promote<_Tp>::__type
>> +    _GLIBCXX_CONSTEXPR inline typename 
>> __gnu_cxx::__promote<_Tp>::__type
>
> This should be _GLIBCXX20_CONSTEXPR.
Done.
>> Index: 
>> testsuite/26_numerics/complex/comparison_operators/more_constexpr.cc
>> ===================================================================
>> --- 
>> testsuite/26_numerics/complex/comparison_operators/more_constexpr.cc 
>> (nonexistent)
>> +++ 
>> testsuite/26_numerics/complex/comparison_operators/more_constexpr.cc 
>> (working copy)
>> @@ -0,0 +1,51 @@
>> +// { dg-do compile { target c++2a } }
>
> All the tests with { target c++2a} should also have:
>
> // { dg-options "-std=gnu++2a" }
>
> Because otherwise they are skipped by default, and only get run when
> RUNTESTFLAGS explicitly includes something like
> --target_board=unix/-std=gnu++2a
>
> The dg-options needs to come first, or it doesn't apply before the
> check for { target c++2a }.
>
Thank you, done.

Updated patch attached.  I'd like to understand why

     __real__ _M_value += __z.real();

doesn't work though.

Ed
Index: include/std/complex
===================================================================
--- include/std/complex	(revision 266251)
+++ include/std/complex	(working copy)
@@ -70,10 +70,11 @@
   ///  Return phase angle of @a z.
   template<typename _Tp> _Tp arg(const complex<_Tp>&);
   ///  Return @a z magnitude squared.
-  template<typename _Tp> _Tp norm(const complex<_Tp>&);
+  template<typename _Tp> _Tp _GLIBCXX20_CONSTEXPR norm(const complex<_Tp>&);
 
   ///  Return complex conjugate of @a z.
-  template<typename _Tp> complex<_Tp> conj(const complex<_Tp>&);
+  template<typename _Tp>
+    _GLIBCXX20_CONSTEXPR complex<_Tp> conj(const complex<_Tp>&);
   ///  Return complex with magnitude @a rho and angle @a theta.
   template<typename _Tp> complex<_Tp> polar(const _Tp&, const _Tp& = 0);
 
@@ -169,18 +170,18 @@
 
       // _GLIBCXX_RESOLVE_LIB_DEFECTS
       // DR 387. std::complex over-encapsulated.
-      void
+      _GLIBCXX20_CONSTEXPR void
       real(_Tp __val) { _M_real = __val; }
 
-      void
+      _GLIBCXX20_CONSTEXPR void
       imag(_Tp __val) { _M_imag = __val; }
 
       /// Assign a scalar to this complex number.
-      complex<_Tp>& operator=(const _Tp&);
+      _GLIBCXX20_CONSTEXPR complex<_Tp>& operator=(const _Tp&);
 
       /// Add a scalar to this complex number.
       // 26.2.5/1
-      complex<_Tp>&
+      _GLIBCXX20_CONSTEXPR complex<_Tp>&
       operator+=(const _Tp& __t)
       {
 	_M_real += __t;
@@ -189,7 +190,7 @@
 
       /// Subtract a scalar from this complex number.
       // 26.2.5/3
-      complex<_Tp>&
+      _GLIBCXX20_CONSTEXPR complex<_Tp>&
       operator-=(const _Tp& __t)
       {
 	_M_real -= __t;
@@ -197,30 +198,30 @@
       }
 
       /// Multiply this complex number by a scalar.
-      complex<_Tp>& operator*=(const _Tp&);
+      _GLIBCXX20_CONSTEXPR complex<_Tp>& operator*=(const _Tp&);
       /// Divide this complex number by a scalar.
-      complex<_Tp>& operator/=(const _Tp&);
+      _GLIBCXX20_CONSTEXPR complex<_Tp>& operator/=(const _Tp&);
 
       // Let the compiler synthesize the copy assignment operator
 #if __cplusplus >= 201103L
-      complex& operator=(const complex&) = default;
+      _GLIBCXX20_CONSTEXPR complex& operator=(const complex&) = default;
 #endif
 
       /// Assign another complex number to this one.
       template<typename _Up>
-        complex<_Tp>& operator=(const complex<_Up>&);
+        _GLIBCXX20_CONSTEXPR complex<_Tp>& operator=(const complex<_Up>&);
       /// Add another complex number to this one.
       template<typename _Up>
-        complex<_Tp>& operator+=(const complex<_Up>&);
+        _GLIBCXX20_CONSTEXPR complex<_Tp>& operator+=(const complex<_Up>&);
       /// Subtract another complex number from this one.
       template<typename _Up>
-        complex<_Tp>& operator-=(const complex<_Up>&);
+        _GLIBCXX20_CONSTEXPR complex<_Tp>& operator-=(const complex<_Up>&);
       /// Multiply this complex number by another.
       template<typename _Up>
-        complex<_Tp>& operator*=(const complex<_Up>&);
+        _GLIBCXX20_CONSTEXPR complex<_Tp>& operator*=(const complex<_Up>&);
       /// Divide this complex number by another.
       template<typename _Up>
-        complex<_Tp>& operator/=(const complex<_Up>&);
+        _GLIBCXX20_CONSTEXPR complex<_Tp>& operator/=(const complex<_Up>&);
 
       _GLIBCXX_CONSTEXPR complex __rep() const
       { return *this; }
@@ -231,7 +232,7 @@
     };
 
   template<typename _Tp>
-    complex<_Tp>&
+    _GLIBCXX20_CONSTEXPR complex<_Tp>&
     complex<_Tp>::operator=(const _Tp& __t)
     {
      _M_real = __t;
@@ -241,7 +242,7 @@
 
   // 26.2.5/5
   template<typename _Tp>
-    complex<_Tp>&
+    _GLIBCXX20_CONSTEXPR complex<_Tp>&
     complex<_Tp>::operator*=(const _Tp& __t)
     {
       _M_real *= __t;
@@ -251,7 +252,7 @@
 
   // 26.2.5/7
   template<typename _Tp>
-    complex<_Tp>&
+    _GLIBCXX20_CONSTEXPR complex<_Tp>&
     complex<_Tp>::operator/=(const _Tp& __t)
     {
       _M_real /= __t;
@@ -261,7 +262,7 @@
 
   template<typename _Tp>
     template<typename _Up>
-    complex<_Tp>&
+    _GLIBCXX20_CONSTEXPR complex<_Tp>&
     complex<_Tp>::operator=(const complex<_Up>& __z)
     {
       _M_real = __z.real();
@@ -272,7 +273,7 @@
   // 26.2.5/9
   template<typename _Tp>
     template<typename _Up>
-    complex<_Tp>&
+    _GLIBCXX20_CONSTEXPR complex<_Tp>&
     complex<_Tp>::operator+=(const complex<_Up>& __z)
     {
       _M_real += __z.real();
@@ -283,7 +284,7 @@
   // 26.2.5/11
   template<typename _Tp>
     template<typename _Up>
-    complex<_Tp>&
+    _GLIBCXX20_CONSTEXPR complex<_Tp>&
     complex<_Tp>::operator-=(const complex<_Up>& __z)
     {
       _M_real -= __z.real();
@@ -295,7 +296,7 @@
   // XXX: This is a grammar school implementation.
   template<typename _Tp>
     template<typename _Up>
-    complex<_Tp>&
+    _GLIBCXX20_CONSTEXPR complex<_Tp>&
     complex<_Tp>::operator*=(const complex<_Up>& __z)
     {
       const _Tp __r = _M_real * __z.real() - _M_imag * __z.imag();
@@ -308,7 +309,7 @@
   // XXX: This is a grammar school implementation.
   template<typename _Tp>
     template<typename _Up>
-    complex<_Tp>&
+    _GLIBCXX20_CONSTEXPR complex<_Tp>&
     complex<_Tp>::operator/=(const complex<_Up>& __z)
     {
       const _Tp __r =  _M_real * __z.real() + _M_imag * __z.imag();
@@ -322,7 +323,7 @@
   //@{
   ///  Return new complex value @a x plus @a y.
   template<typename _Tp>
-    inline complex<_Tp>
+    inline _GLIBCXX20_CONSTEXPR complex<_Tp>
     operator+(const complex<_Tp>& __x, const complex<_Tp>& __y)
     {
       complex<_Tp> __r = __x;
@@ -331,7 +332,7 @@
     }
 
   template<typename _Tp>
-    inline complex<_Tp>
+    inline _GLIBCXX20_CONSTEXPR complex<_Tp>
     operator+(const complex<_Tp>& __x, const _Tp& __y)
     {
       complex<_Tp> __r = __x;
@@ -340,7 +341,7 @@
     }
 
   template<typename _Tp>
-    inline complex<_Tp>
+    inline _GLIBCXX20_CONSTEXPR complex<_Tp>
     operator+(const _Tp& __x, const complex<_Tp>& __y)
     {
       complex<_Tp> __r = __y;
@@ -352,7 +353,7 @@
   //@{
   ///  Return new complex value @a x minus @a y.
   template<typename _Tp>
-    inline complex<_Tp>
+    inline _GLIBCXX20_CONSTEXPR complex<_Tp>
     operator-(const complex<_Tp>& __x, const complex<_Tp>& __y)
     {
       complex<_Tp> __r = __x;
@@ -361,7 +362,7 @@
     }
 
   template<typename _Tp>
-    inline complex<_Tp>
+    inline _GLIBCXX20_CONSTEXPR complex<_Tp>
     operator-(const complex<_Tp>& __x, const _Tp& __y)
     {
       complex<_Tp> __r = __x;
@@ -370,11 +371,11 @@
     }
 
   template<typename _Tp>
-    inline complex<_Tp>
+    inline _GLIBCXX20_CONSTEXPR complex<_Tp>
     operator-(const _Tp& __x, const complex<_Tp>& __y)
     {
-      complex<_Tp> __r(__x, -__y.imag());
-      __r -= __y.real();
+      complex<_Tp> __r = -__y;
+      __r += __x;
       return __r;
     }
   //@}
@@ -382,7 +383,7 @@
   //@{
   ///  Return new complex value @a x times @a y.
   template<typename _Tp>
-    inline complex<_Tp>
+    inline _GLIBCXX20_CONSTEXPR complex<_Tp>
     operator*(const complex<_Tp>& __x, const complex<_Tp>& __y)
     {
       complex<_Tp> __r = __x;
@@ -391,7 +392,7 @@
     }
 
   template<typename _Tp>
-    inline complex<_Tp>
+    inline _GLIBCXX20_CONSTEXPR complex<_Tp>
     operator*(const complex<_Tp>& __x, const _Tp& __y)
     {
       complex<_Tp> __r = __x;
@@ -400,7 +401,7 @@
     }
 
   template<typename _Tp>
-    inline complex<_Tp>
+    inline _GLIBCXX20_CONSTEXPR complex<_Tp>
     operator*(const _Tp& __x, const complex<_Tp>& __y)
     {
       complex<_Tp> __r = __y;
@@ -412,7 +413,7 @@
   //@{
   ///  Return new complex value @a x divided by @a y.
   template<typename _Tp>
-    inline complex<_Tp>
+    inline _GLIBCXX20_CONSTEXPR complex<_Tp>
     operator/(const complex<_Tp>& __x, const complex<_Tp>& __y)
     {
       complex<_Tp> __r = __x;
@@ -421,7 +422,7 @@
     }
 
   template<typename _Tp>
-    inline complex<_Tp>
+    inline _GLIBCXX20_CONSTEXPR complex<_Tp>
     operator/(const complex<_Tp>& __x, const _Tp& __y)
     {
       complex<_Tp> __r = __x;
@@ -430,7 +431,7 @@
     }
 
   template<typename _Tp>
-    inline complex<_Tp>
+    inline _GLIBCXX20_CONSTEXPR complex<_Tp>
     operator/(const _Tp& __x, const complex<_Tp>& __y)
     {
       complex<_Tp> __r = __x;
@@ -441,15 +442,15 @@
 
   ///  Return @a x.
   template<typename _Tp>
-    inline complex<_Tp>
+    inline _GLIBCXX20_CONSTEXPR complex<_Tp>
     operator+(const complex<_Tp>& __x)
     { return __x; }
 
   ///  Return complex negation of @a x.
   template<typename _Tp>
-    inline complex<_Tp>
+    inline _GLIBCXX20_CONSTEXPR complex<_Tp>
     operator-(const complex<_Tp>& __x)
-    {  return complex<_Tp>(-__x.real(), -__x.imag()); }
+    { return complex<_Tp>(-__x.real(), -__x.imag()); }
 
   //@{
   ///  Return true if @a x is equal to @a y.
@@ -658,7 +659,7 @@
     struct _Norm_helper
     {
       template<typename _Tp>
-        static inline _Tp _S_do_it(const complex<_Tp>& __z)
+        static inline _GLIBCXX_CONSTEXPR _Tp _S_do_it(const complex<_Tp>& __z)
         {
           const _Tp __x = __z.real();
           const _Tp __y = __z.imag();
@@ -670,15 +671,18 @@
     struct _Norm_helper<true>
     {
       template<typename _Tp>
-        static inline _Tp _S_do_it(const complex<_Tp>& __z)
+        static inline _GLIBCXX_CONSTEXPR _Tp _S_do_it(const complex<_Tp>& __z)
         {
-          _Tp __res = std::abs(__z);
-          return __res * __res;
+          //_Tp __res = std::abs(__z);
+          //return __res * __res;
+          const _Tp __x = __z.real();
+          const _Tp __y = __z.imag();
+          return __x * __x + __y * __y;
         }
     };
 
   template<typename _Tp>
-    inline _Tp
+    inline _GLIBCXX20_CONSTEXPR _Tp
     norm(const complex<_Tp>& __z)
     {
       return _Norm_helper<__is_floating<_Tp>::__value
@@ -694,7 +698,7 @@
     }
 
   template<typename _Tp>
-    inline complex<_Tp>
+    inline _GLIBCXX20_CONSTEXPR complex<_Tp>
     conj(const complex<_Tp>& __z)
     { return complex<_Tp>(__z.real(), -__z.imag()); }
 
@@ -1115,13 +1119,13 @@
 
       // _GLIBCXX_RESOLVE_LIB_DEFECTS
       // DR 387. std::complex over-encapsulated.
-      void
+      _GLIBCXX20_CONSTEXPR void
       real(float __val) { __real__ _M_value = __val; }
 
-      void
+      _GLIBCXX20_CONSTEXPR void
       imag(float __val) { __imag__ _M_value = __val; }
 
-      complex&
+      _GLIBCXX20_CONSTEXPR complex&
       operator=(float __f)
       {
 	_M_value = __f;
@@ -1128,7 +1132,7 @@
 	return *this;
       }
 
-      complex&
+      _GLIBCXX20_CONSTEXPR complex&
       operator+=(float __f)
       {
 	_M_value += __f;
@@ -1135,7 +1139,7 @@
 	return *this;
       }
 
-      complex&
+      _GLIBCXX20_CONSTEXPR complex&
       operator-=(float __f)
       {
 	_M_value -= __f;
@@ -1142,7 +1146,7 @@
 	return *this;
       }
 
-      complex&
+      _GLIBCXX20_CONSTEXPR complex&
       operator*=(float __f)
       {
 	_M_value *= __f;
@@ -1149,7 +1153,7 @@
 	return *this;
       }
 
-      complex&
+      _GLIBCXX20_CONSTEXPR complex&
       operator/=(float __f)
       {
 	_M_value /= __f;
@@ -1163,7 +1167,7 @@
 #endif
 
       template<typename _Tp>
-        complex&
+        _GLIBCXX20_CONSTEXPR complex&
         operator=(const complex<_Tp>&  __z)
 	{
 	  __real__ _M_value = __z.real();
@@ -1172,41 +1176,35 @@
 	}
 
       template<typename _Tp>
-        complex&
+        _GLIBCXX20_CONSTEXPR complex&
         operator+=(const complex<_Tp>& __z)
 	{
-	  __real__ _M_value += __z.real();
-	  __imag__ _M_value += __z.imag();
+	  _M_value += __z.__rep();
 	  return *this;
 	}
 
       template<class _Tp>
-        complex&
+        _GLIBCXX20_CONSTEXPR complex&
         operator-=(const complex<_Tp>& __z)
 	{
-	  __real__ _M_value -= __z.real();
-	  __imag__ _M_value -= __z.imag();
+	  _M_value -= __z.__rep();
 	  return *this;
 	}
 
       template<class _Tp>
-        complex&
+        _GLIBCXX20_CONSTEXPR complex&
         operator*=(const complex<_Tp>& __z)
 	{
-	  _ComplexT __t;
-	  __real__ __t = __z.real();
-	  __imag__ __t = __z.imag();
+	  const _ComplexT __t = __z.__rep();
 	  _M_value *= __t;
 	  return *this;
 	}
 
       template<class _Tp>
-        complex&
+        _GLIBCXX20_CONSTEXPR complex&
         operator/=(const complex<_Tp>& __z)
 	{
-	  _ComplexT __t;
-	  __real__ __t = __z.real();
-	  __imag__ __t = __z.imag();
+	  const _ComplexT __t = __z.__rep();
 	  _M_value /= __t;
 	  return *this;
 	}
@@ -1268,13 +1266,13 @@
 
       // _GLIBCXX_RESOLVE_LIB_DEFECTS
       // DR 387. std::complex over-encapsulated.
-      void
+      _GLIBCXX20_CONSTEXPR void
       real(double __val) { __real__ _M_value = __val; }
 
-      void
+      _GLIBCXX20_CONSTEXPR void
       imag(double __val) { __imag__ _M_value = __val; }
 
-      complex&
+      _GLIBCXX20_CONSTEXPR complex&
       operator=(double __d)
       {
 	_M_value = __d;
@@ -1281,7 +1279,7 @@
 	return *this;
       }
 
-      complex&
+      _GLIBCXX20_CONSTEXPR complex&
       operator+=(double __d)
       {
 	_M_value += __d;
@@ -1288,7 +1286,7 @@
 	return *this;
       }
 
-      complex&
+      _GLIBCXX20_CONSTEXPR complex&
       operator-=(double __d)
       {
 	_M_value -= __d;
@@ -1295,7 +1293,7 @@
 	return *this;
       }
 
-      complex&
+      _GLIBCXX20_CONSTEXPR complex&
       operator*=(double __d)
       {
 	_M_value *= __d;
@@ -1302,7 +1300,7 @@
 	return *this;
       }
 
-      complex&
+      _GLIBCXX20_CONSTEXPR complex&
       operator/=(double __d)
       {
 	_M_value /= __d;
@@ -1315,50 +1313,43 @@
 #endif
 
       template<typename _Tp>
-        complex&
+        _GLIBCXX20_CONSTEXPR complex&
         operator=(const complex<_Tp>& __z)
 	{
-	  __real__ _M_value = __z.real();
-	  __imag__ _M_value = __z.imag();
+	  _M_value = __z.__rep();
 	  return *this;
 	}
 
       template<typename _Tp>
-        complex&
+        _GLIBCXX20_CONSTEXPR complex&
         operator+=(const complex<_Tp>& __z)
 	{
-	  __real__ _M_value += __z.real();
-	  __imag__ _M_value += __z.imag();
+	  _M_value += __z.__rep();
 	  return *this;
 	}
 
       template<typename _Tp>
-        complex&
+        _GLIBCXX20_CONSTEXPR complex&
         operator-=(const complex<_Tp>& __z)
 	{
-	  __real__ _M_value -= __z.real();
-	  __imag__ _M_value -= __z.imag();
+	  _M_value -= __z.__rep();
 	  return *this;
 	}
 
       template<typename _Tp>
-        complex&
+        _GLIBCXX20_CONSTEXPR complex&
         operator*=(const complex<_Tp>& __z)
 	{
-	  _ComplexT __t;
-	  __real__ __t = __z.real();
-	  __imag__ __t = __z.imag();
+	  const _ComplexT __t = __z.__rep();
 	  _M_value *= __t;
 	  return *this;
 	}
 
       template<typename _Tp>
-        complex&
+        _GLIBCXX20_CONSTEXPR complex&
         operator/=(const complex<_Tp>& __z)
 	{
-	  _ComplexT __t;
-	  __real__ __t = __z.real();
-	  __imag__ __t = __z.imag();
+	  const _ComplexT __t = __z.__rep();
 	  _M_value /= __t;
 	  return *this;
 	}
@@ -1422,13 +1413,13 @@
 
       // _GLIBCXX_RESOLVE_LIB_DEFECTS
       // DR 387. std::complex over-encapsulated.
-      void
+      _GLIBCXX20_CONSTEXPR void
       real(long double __val) { __real__ _M_value = __val; }
 
-      void
+      _GLIBCXX20_CONSTEXPR void
       imag(long double __val) { __imag__ _M_value = __val; }
 
-      complex&
+      _GLIBCXX20_CONSTEXPR complex&
       operator=(long double __r)
       {
 	_M_value = __r;
@@ -1435,7 +1426,7 @@
 	return *this;
       }
 
-      complex&
+      _GLIBCXX20_CONSTEXPR complex&
       operator+=(long double __r)
       {
 	_M_value += __r;
@@ -1442,7 +1433,7 @@
 	return *this;
       }
 
-      complex&
+      _GLIBCXX20_CONSTEXPR complex&
       operator-=(long double __r)
       {
 	_M_value -= __r;
@@ -1449,7 +1440,7 @@
 	return *this;
       }
 
-      complex&
+      _GLIBCXX20_CONSTEXPR complex&
       operator*=(long double __r)
       {
 	_M_value *= __r;
@@ -1456,7 +1447,7 @@
 	return *this;
       }
 
-      complex&
+      _GLIBCXX20_CONSTEXPR complex&
       operator/=(long double __r)
       {
 	_M_value /= __r;
@@ -1469,50 +1460,43 @@
 #endif
 
       template<typename _Tp>
-        complex&
+        _GLIBCXX20_CONSTEXPR complex&
         operator=(const complex<_Tp>& __z)
 	{
-	  __real__ _M_value = __z.real();
-	  __imag__ _M_value = __z.imag();
+	  _M_value = __z.__rep();
 	  return *this;
 	}
 
       template<typename _Tp>
-        complex&
+        _GLIBCXX20_CONSTEXPR complex&
 	operator+=(const complex<_Tp>& __z)
 	{
-	  __real__ _M_value += __z.real();
-	  __imag__ _M_value += __z.imag();
+	  _M_value += __z.__rep();
 	  return *this;
 	}
 
       template<typename _Tp>
-        complex&
+        _GLIBCXX20_CONSTEXPR complex&
 	operator-=(const complex<_Tp>& __z)
 	{
-	  __real__ _M_value -= __z.real();
-	  __imag__ _M_value -= __z.imag();
+	  _M_value -= __z.__rep();
 	  return *this;
 	}
 
       template<typename _Tp>
-        complex&
+        _GLIBCXX20_CONSTEXPR complex&
 	operator*=(const complex<_Tp>& __z)
 	{
-	  _ComplexT __t;
-	  __real__ __t = __z.real();
-	  __imag__ __t = __z.imag();
+	  const _ComplexT __t = __z.__rep();
 	  _M_value *= __t;
 	  return *this;
 	}
 
       template<typename _Tp>
-        complex&
+        _GLIBCXX20_CONSTEXPR complex&
 	operator/=(const complex<_Tp>& __z)
 	{
-	  _ComplexT __t;
-	  __real__ __t = __z.real();
-	  __imag__ __t = __z.imag();
+	  const _ComplexT __t = __z.__rep();
 	  _M_value /= __t;
 	  return *this;
 	}
@@ -1872,7 +1856,7 @@
     { return _Tp(); }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__promote<_Tp>::__type
+    _GLIBCXX20_CONSTEXPR inline typename __gnu_cxx::__promote<_Tp>::__type
     norm(_Tp __x)
     {
       typedef typename __gnu_cxx::__promote<_Tp>::__type __type;
@@ -1911,7 +1895,8 @@
 
   // Forward declarations.
   // DR 781.
-  template<typename _Tp> std::complex<_Tp> proj(const std::complex<_Tp>&);
+  template<typename _Tp>
+    std::complex<_Tp> proj(const std::complex<_Tp>&);
 
   template<typename _Tp>
     std::complex<_Tp>
@@ -1957,7 +1942,8 @@
     }
 
   template<typename _Tp>
-    inline std::complex<typename __gnu_cxx::__promote<_Tp>::__type>
+    inline _GLIBCXX20_CONSTEXPR
+	std::complex<typename __gnu_cxx::__promote<_Tp>::__type>
     conj(_Tp __x)
     {
       typedef typename __gnu_cxx::__promote<_Tp>::__type __type;
Index: testsuite/26_numerics/complex/comparison_operators/more_constexpr.cc
===================================================================
--- testsuite/26_numerics/complex/comparison_operators/more_constexpr.cc	(nonexistent)
+++ testsuite/26_numerics/complex/comparison_operators/more_constexpr.cc	(working copy)
@@ -0,0 +1,52 @@
+// { dg-options "-std=gnu++2a" }
+// { dg-do compile { target c++2a } }
+
+// Copyright (C) 2018 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/>.
+
+#include <complex>
+#include <testsuite_common_types.h>
+
+template<bool ok>
+  struct thing
+  { };
+
+// 
+template<typename _Tp>
+  void
+  test_comparison()
+  {
+    constexpr std::complex<_Tp> a{1.1, 2.2};
+    constexpr std::complex<_Tp> b{3.3, 4.4};
+    if constexpr (a == b)
+      auto c [[maybe_unused]] = a + b;
+    if constexpr (a != b)
+      auto c [[maybe_unused]] = a - b;
+
+    thing<a == b> thing1 [[maybe_unused]];
+    thing<a != b> thing2 [[maybe_unused]];
+  }
+
+int
+main()
+{
+  test_comparison<float>();
+  test_comparison<double>();
+  test_comparison<long double>();
+
+  return 0;
+}
Index: testsuite/26_numerics/complex/operators/more_constexpr.cc
===================================================================
--- testsuite/26_numerics/complex/operators/more_constexpr.cc	(nonexistent)
+++ testsuite/26_numerics/complex/operators/more_constexpr.cc	(working copy)
@@ -0,0 +1,62 @@
+// { dg-options "-std=gnu++2a" }
+// { dg-do compile { target c++2a } }
+
+// Copyright (C) 2018 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/>.
+
+#include <complex>
+#include <testsuite_common_types.h>
+
+namespace __gnu_test
+{
+  // Test constexpr symmetric complex @ real, real @ complex, complex @ complex.
+  template<typename _Tp>
+    void
+    test_operators()
+    {
+      constexpr std::complex<_Tp> a{1, 2};
+      constexpr std::complex<_Tp> b{3, 4};
+      constexpr _Tp c = 5;
+
+      constexpr auto w [[maybe_unused]] = +a;
+      constexpr auto z [[maybe_unused]] = -a;
+
+      constexpr auto apc [[maybe_unused]] = a + c;
+      constexpr auto amc [[maybe_unused]] = a - c;
+      constexpr auto atc [[maybe_unused]] = a * c;
+      constexpr auto adc [[maybe_unused]] = a / c;
+
+      constexpr auto cpa [[maybe_unused]] = c + a;
+      constexpr auto cma [[maybe_unused]] = c - a;
+      constexpr auto cta [[maybe_unused]] = c * a;
+      constexpr auto cda [[maybe_unused]] = c / a;
+
+      constexpr auto apb [[maybe_unused]] = a + b;
+      constexpr auto amb [[maybe_unused]] = a - b;
+      constexpr auto atb [[maybe_unused]] = a * b;
+      constexpr auto adb [[maybe_unused]] = a / b;
+    }
+}
+
+int main()
+{
+  __gnu_test::test_operators<float>();
+  __gnu_test::test_operators<double>();
+  __gnu_test::test_operators<long double>();
+
+  return 0;
+}
Index: testsuite/26_numerics/complex/requirements/more_constexpr.cc
===================================================================
--- testsuite/26_numerics/complex/requirements/more_constexpr.cc	(nonexistent)
+++ testsuite/26_numerics/complex/requirements/more_constexpr.cc	(working copy)
@@ -0,0 +1,171 @@
+// { dg-options "-std=gnu++2a" }
+// { dg-do compile { target c++2a } }
+
+// Copyright (C) 2018 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/>.
+
+#include <complex>
+#include <testsuite_common_types.h>
+
+namespace __gnu_test
+{
+
+  // Test constexpr real(val) imag(val).
+  template<typename _Tp, const int _Val = 42>
+    inline void
+    set_real(std::complex<_Tp>& a)
+    { a.real(_Val); }
+
+  template<typename _Tp, const int _Val = 42>
+    inline void
+    set_imag(std::complex<_Tp>& a)
+    { a.imag(_Val); }
+
+  template<typename _Tp>
+    void
+    test_members()
+    {
+      constexpr std::complex<_Tp> a{1.1, 2.2};
+
+      std::complex<_Tp> z = a;
+
+      set_real<_Tp, 33>(z);
+      set_imag<_Tp, 44>(z);
+    }
+
+  // Test operators @=complex and @=real.
+  template<typename _Tp, typename _Up>
+    constexpr std::complex<_Tp>
+    sum(const std::complex<_Tp>& z, const std::complex<_Up>& w)
+    {
+      std::complex<_Tp> x = z;
+      x += w;
+      return x;
+    }
+
+  template<typename _Tp, typename _Up>
+    constexpr std::complex<_Tp>
+    sum(const std::complex<_Tp>& z, _Up w)
+    {
+      std::complex<_Tp> x = z;
+      x += w;
+      return x;
+    }
+
+  template<typename _Tp, typename _Up>
+    constexpr std::complex<_Tp>
+    dif(const std::complex<_Tp>& z, const std::complex<_Up>& w)
+    {
+      std::complex<_Tp> x = z;
+      x -= w;
+      return x;
+    }
+
+  template<typename _Tp, typename _Up>
+    constexpr std::complex<_Tp>
+    dif(const std::complex<_Tp>& z, _Up w)
+    {
+      std::complex<_Tp> x = z;
+      x -= w;
+      return x;
+    }
+
+  template<typename _Tp, typename _Up>
+    constexpr std::complex<_Tp>
+    prod(const std::complex<_Tp>& z, const std::complex<_Up>& w)
+    {
+      std::complex<_Tp> x = z;
+      x *= w;
+      return x;
+    }
+
+  template<typename _Tp, typename _Up>
+    constexpr std::complex<_Tp>
+    prod(const std::complex<_Tp>& z, _Up w)
+    {
+      std::complex<_Tp> x = z;
+      x *= w;
+      return x;
+    }
+
+  template<typename _Tp, typename _Up>
+    constexpr std::complex<_Tp>
+    quot(const std::complex<_Tp>& z, const std::complex<_Up>& w)
+    {
+      std::complex<_Tp> x = z;
+      x /= w;
+      return x;
+    }
+
+  template<typename _Tp, typename _Up>
+    constexpr std::complex<_Tp>
+    quot(const std::complex<_Tp>& z, _Up w)
+    {
+      std::complex<_Tp> x = z;
+      x /= w;
+      return x;
+    }
+
+  template<typename _Tp, typename _Up>
+    void
+    test_operator_members()
+    {
+      constexpr std::complex<_Tp> a{10, 20};
+      constexpr std::complex<_Up> b{6, 8};
+      constexpr _Up c{10};
+
+      constexpr auto apc = sum(a, c);
+      static_assert(apc == std::complex<_Tp>{20, 20});
+      constexpr auto amc = dif(a, c);
+      static_assert(amc == std::complex<_Tp>{0, 20});
+      constexpr auto atc = prod(a, c);
+      static_assert(atc == std::complex<_Tp>{100, 200});
+      constexpr auto adc = quot(a, c);
+      static_assert(adc == std::complex<_Tp>{1, 2});
+
+      constexpr auto apb = sum(a, b);
+      static_assert(apb == std::complex<_Tp>{16, 28});
+      constexpr auto amb = dif(a, b);
+      static_assert(amb == std::complex<_Tp>{4, 12});
+      constexpr auto atb = prod(a, b);
+      static_assert(atb == std::complex<_Tp>{-100, 200});
+      constexpr auto adb = quot(a, b);
+      static_assert(adb == std::complex<_Tp>{11/_Tp{5}, 2/_Tp{5}});
+    }
+}
+
+int main()
+{
+  __gnu_test::test_members<float>();
+  __gnu_test::test_members<double>();
+  __gnu_test::test_members<long double>();
+
+  __gnu_test::test_operator_members<float, float>();
+  __gnu_test::test_operator_members<float, double>();
+  __gnu_test::test_operator_members<float, long double>();
+  __gnu_test::test_operator_members<double, float>();
+  __gnu_test::test_operator_members<double, double>();
+  __gnu_test::test_operator_members<double, long double>();
+  __gnu_test::test_operator_members<long double, float>();
+  __gnu_test::test_operator_members<long double, double>();
+  __gnu_test::test_operator_members<long double, long double>();
+
+  // Test primary template.
+  __gnu_test::test_operator_members<__float128, __float128>();
+
+  return 0;
+}
Index: testsuite/26_numerics/complex/value_operations/more_constexpr.cc
===================================================================
--- testsuite/26_numerics/complex/value_operations/more_constexpr.cc	(nonexistent)
+++ testsuite/26_numerics/complex/value_operations/more_constexpr.cc	(working copy)
@@ -0,0 +1,59 @@
+// { dg-options "-std=gnu++2a" }
+// { dg-do compile { target c++2a } }
+
+// Copyright (C) 2018 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/>.
+
+#include <complex>
+#include <testsuite_common_types.h>
+
+namespace __gnu_test
+{
+  struct constexpr_functions
+  {
+    template<typename _Ttesttype>
+      void
+      operator()()
+      {
+	struct _Concept
+	{
+	  void __constraint()
+	  { 
+	    typedef typename _Ttesttype::_ComplexT _ComplexT;
+	    constexpr _ComplexT cc = { 1.1 };
+	    constexpr _Ttesttype a(cc);
+	    constexpr auto v1 [[maybe_unused]] = norm(a);
+	    constexpr auto v2 [[maybe_unused]] = conj(a);
+	  }
+	};
+
+	_Concept c;
+	c.__constraint();
+      }
+  };
+}
+
+int main()
+{
+  __gnu_test::constexpr_functions test;
+
+  test.operator()<std::complex<float>>();
+  test.operator()<std::complex<double>>();
+  test.operator()<std::complex<long double>>();
+
+  return 0;
+}
Index: testsuite/26_numerics/headers/complex/synopsis.cc
===================================================================
--- testsuite/26_numerics/headers/complex/synopsis.cc	(revision 266251)
+++ testsuite/26_numerics/headers/complex/synopsis.cc	(working copy)
@@ -28,51 +28,71 @@
 
   // 26.2.6 operators:
   template<class T>
-    complex<T> operator+(const complex<T>&, const complex<T>&);
-  template<class T> complex<T> operator+(const complex<T>&, const T&);
-  template<class T> complex<T> operator+(const T&, const complex<T>&);
-  template<class T> complex<T> operator-
+    _GLIBCXX20_CONSTEXPR complex<T>
+    operator+(const complex<T>&, const complex<T>&);
+  template<class T>
+    _GLIBCXX20_CONSTEXPR complex<T> operator+(const complex<T>&, const T&);
+  template<class T>
+    _GLIBCXX20_CONSTEXPR complex<T> operator+(const T&, const complex<T>&);
+
+  template<class T>
+    _GLIBCXX20_CONSTEXPR complex<T>
+    operator-(const complex<T>&, const complex<T>&);
+  template<class T>
+    _GLIBCXX20_CONSTEXPR complex<T> operator-(const complex<T>&, const T&);
+  template<class T>
+    _GLIBCXX20_CONSTEXPR complex<T> operator-(const T&, const complex<T>&);
+
+  template<class T>
+    _GLIBCXX20_CONSTEXPR complex<T> operator*
     (const complex<T>&, const complex<T>&);
-  template<class T> complex<T> operator-(const complex<T>&, const T&);
-  template<class T> complex<T> operator-(const T&, const complex<T>&);
-  template<class T> complex<T> operator*
-    (const complex<T>&, const complex<T>&);
-  template<class T> complex<T> operator*(const complex<T>&, const T&);
-  template<class T> complex<T> operator*(const T&, const complex<T>&);
-  template<class T> complex<T> operator/
-    (const complex<T>&, const complex<T>&);
-  template<class T> complex<T> operator/(const complex<T>&, const T&);
-  template<class T> complex<T> operator/(const T&, const complex<T>&);
-  template<class T> complex<T> operator+(const complex<T>&);
-  template<class T> complex<T> operator-(const complex<T>&);
-  template<class T> _GLIBCXX_CONSTEXPR bool operator==
-    (const complex<T>&, const complex<T>&);
-  template<class T> _GLIBCXX_CONSTEXPR bool operator==
-    (const complex<T>&, const T&);
-  template<class T> _GLIBCXX_CONSTEXPR bool operator==
-    (const T&, const complex<T>&);
+  template<class T>
+    _GLIBCXX20_CONSTEXPR complex<T> operator*(const complex<T>&, const T&);
+  template<class T>
+    _GLIBCXX20_CONSTEXPR complex<T> operator*(const T&, const complex<T>&);
 
+  template<class T>
+    _GLIBCXX20_CONSTEXPR complex<T>
+    operator/(const complex<T>&, const complex<T>&);
+  template<class T>
+    _GLIBCXX20_CONSTEXPR complex<T> operator/(const complex<T>&, const T&);
+  template<class T>
+    _GLIBCXX20_CONSTEXPR complex<T> operator/(const T&, const complex<T>&);
 
-  template<class T> _GLIBCXX_CONSTEXPR bool operator!=
-    (const complex<T>&, const complex<T>&);
-  template<class T> _GLIBCXX_CONSTEXPR bool operator!=
-    (const complex<T>&, const T&);
-  template<class T> _GLIBCXX_CONSTEXPR bool operator!=
-    (const T&, const complex<T>&);
+  template<class T>
+    _GLIBCXX20_CONSTEXPR complex<T> operator+(const complex<T>&);
+  template<class T>
+    _GLIBCXX20_CONSTEXPR complex<T> operator-(const complex<T>&);
+
+  template<class T>
+    _GLIBCXX_CONSTEXPR bool operator==(const complex<T>&, const complex<T>&);
+  template<class T>
+     _GLIBCXX_CONSTEXPR bool operator==(const complex<T>&, const T&);
+  template<class T>
+    _GLIBCXX_CONSTEXPR bool operator==(const T&, const complex<T>&);
+
+  template<class T>
+    _GLIBCXX_CONSTEXPR bool operator!=(const complex<T>&, const complex<T>&);
+  template<class T>
+    _GLIBCXX_CONSTEXPR bool operator!=(const complex<T>&, const T&);
+  template<class T>
+    _GLIBCXX_CONSTEXPR bool operator!=(const T&, const complex<T>&);
+
   template<class T, class charT, class traits>
-  basic_istream<charT, traits>&
-  operator>>(basic_istream<charT, traits>&, complex<T>&);
+    basic_istream<charT, traits>&
+    operator>>(basic_istream<charT, traits>&, complex<T>&);
   template<class T, class charT, class traits>
-  basic_ostream<charT, traits>&
-  operator<<(basic_ostream<charT, traits>&, const complex<T>&);
+    basic_ostream<charT, traits>&
+    operator<<(basic_ostream<charT, traits>&, const complex<T>&);
 
   // 26.2.7 values:
   template<class T> _GLIBCXX_CONSTEXPR T real(const complex<T>&);
   template<class T> _GLIBCXX_CONSTEXPR T imag(const complex<T>&);
   template<class T> T abs(const complex<T>&);
-  template<class T> T arg(const complex<T>&);
-  template<class T> T norm(const complex<T>&);
-  template<class T> complex<T> conj(const complex<T>&);
+  template<class T> _GLIBCXX20_CONSTEXPR T arg(const complex<T>&);
+  template<class T> _GLIBCXX20_CONSTEXPR T norm(const complex<T>&);
+  template<class T> _GLIBCXX20_CONSTEXPR complex<T> conj(const complex<T>&);
+  template<class T> _GLIBCXX20_CONSTEXPR complex<T> proj(const complex<T>&);
   template<class T> complex<T> polar(const T& rho, const T& theta);
 
   // 26.2.8 transcendentals:
Jonathan Wakely Nov. 22, 2018, 9:19 a.m. UTC | #6
On 20/11/18 17:58 -0500, Ed Smith-Rowland wrote:
>On 11/19/18 6:13 AM, Jonathan Wakely wrote:
>>On 16/11/18 19:39 -0500, Ed Smith-Rowland wrote:
>>>@@ -322,67 +323,43 @@
>>>  //@{
>>>  ///  Return new complex value @a x plus @a y.
>>>  template<typename _Tp>
>>>-    inline complex<_Tp>
>>>+    inline _GLIBCXX20_CONSTEXPR complex<_Tp>
>>>    operator+(const complex<_Tp>& __x, const complex<_Tp>& __y)
>>>-    {
>>>-      complex<_Tp> __r = __x;
>>>-      __r += __y;
>>>-      return __r;
>>>-    }
>>>+    { return complex<_Tp>(__x.real() + __y.real(), __x.imag() + 
>>>__y.imag()); }
>>
>>Is this change (and all the similar ones) really needed?
>>
>>Doesn't the fact that all the constructors and member operators of
>>std::complex mean that the original definition is also valid in a
>>constexpr function?
>These changes are rolled back. Sorry.
>>>@@ -1163,50 +1143,43 @@
>>>#endif
>>>
>>>      template<typename _Tp>
>>>-        complex&
>>>+        _GLIBCXX20_CONSTEXPR complex&
>>>        operator=(const complex<_Tp>&  __z)
>>>    {
>>>-      __real__ _M_value = __z.real();
>>>-      __imag__ _M_value = __z.imag();
>>>+      _M_value = __z.__rep();
>>
>>These changes look OK, but I wonder if we shouldn't ask the compiler
>>to make it possible to use __real__ and __imag__ in constexpr
>>functions instead.
>>
>>I assume it doesn't, and that's why you made this change. But if it
>>Just Worked, and the other changes I commented on above are also
>>unnecessary, then this patch would *mostly* just be adding
>>_GLIBCXX20_CONSTEXPR which is OK for stage 3 (as it doesn't affect any
>>dialects except C++2a).
>
>Yes, this is the issue.  I agree that constexpr _real__, __imag__would 
>be better.
>
>Do you have any idea where this change would be?  I grepped around a 
>little and couldn't figure it out.  if you don't I'll look more.

No idea, sorry.

>Actually, looking at constexpr.c it looks like the old way ought to work...
>
>OK, plain assignment works but not the others.  Interesting.
>
>>
>>>@@ -1872,7 +1831,7 @@
>>>    { return _Tp(); }
>>>
>>>  template<typename _Tp>
>>>-    inline typename __gnu_cxx::__promote<_Tp>::__type
>>>+    _GLIBCXX_CONSTEXPR inline typename 
>>>__gnu_cxx::__promote<_Tp>::__type
>>
>>This should be _GLIBCXX20_CONSTEXPR.
>Done.
>>>Index: 
>>>testsuite/26_numerics/complex/comparison_operators/more_constexpr.cc
>>>===================================================================
>>>--- 
>>>testsuite/26_numerics/complex/comparison_operators/more_constexpr.cc 
>>>(nonexistent)
>>>+++ 
>>>testsuite/26_numerics/complex/comparison_operators/more_constexpr.cc 
>>>(working copy)
>>>@@ -0,0 +1,51 @@
>>>+// { dg-do compile { target c++2a } }
>>
>>All the tests with { target c++2a} should also have:
>>
>>// { dg-options "-std=gnu++2a" }
>>
>>Because otherwise they are skipped by default, and only get run when
>>RUNTESTFLAGS explicitly includes something like
>>--target_board=unix/-std=gnu++2a
>>
>>The dg-options needs to come first, or it doesn't apply before the
>>check for { target c++2a }.
>>
>Thank you, done.

OK for trunk, thanks.

>Updated patch attached.  I'd like to understand why
>
>    __real__ _M_value += __z.real();
>
>doesn't work though.

Yes, I agree it should. If you don't figure it out please file a bug
requesting that it works, so somebody else might look into it.
Christophe Lyon Nov. 26, 2018, 8:30 a.m. UTC | #7
On Thu, 22 Nov 2018 at 10:20, Jonathan Wakely <jwakely@redhat.com> wrote:
>
> On 20/11/18 17:58 -0500, Ed Smith-Rowland wrote:
> >On 11/19/18 6:13 AM, Jonathan Wakely wrote:
> >>On 16/11/18 19:39 -0500, Ed Smith-Rowland wrote:
> >>>@@ -322,67 +323,43 @@
> >>>  //@{
> >>>  ///  Return new complex value @a x plus @a y.
> >>>  template<typename _Tp>
> >>>-    inline complex<_Tp>
> >>>+    inline _GLIBCXX20_CONSTEXPR complex<_Tp>
> >>>    operator+(const complex<_Tp>& __x, const complex<_Tp>& __y)
> >>>-    {
> >>>-      complex<_Tp> __r = __x;
> >>>-      __r += __y;
> >>>-      return __r;
> >>>-    }
> >>>+    { return complex<_Tp>(__x.real() + __y.real(), __x.imag() +
> >>>__y.imag()); }
> >>
> >>Is this change (and all the similar ones) really needed?
> >>
> >>Doesn't the fact that all the constructors and member operators of
> >>std::complex mean that the original definition is also valid in a
> >>constexpr function?
> >These changes are rolled back. Sorry.
> >>>@@ -1163,50 +1143,43 @@
> >>>#endif
> >>>
> >>>      template<typename _Tp>
> >>>-        complex&
> >>>+        _GLIBCXX20_CONSTEXPR complex&
> >>>        operator=(const complex<_Tp>&  __z)
> >>>    {
> >>>-      __real__ _M_value = __z.real();
> >>>-      __imag__ _M_value = __z.imag();
> >>>+      _M_value = __z.__rep();
> >>
> >>These changes look OK, but I wonder if we shouldn't ask the compiler
> >>to make it possible to use __real__ and __imag__ in constexpr
> >>functions instead.
> >>
> >>I assume it doesn't, and that's why you made this change. But if it
> >>Just Worked, and the other changes I commented on above are also
> >>unnecessary, then this patch would *mostly* just be adding
> >>_GLIBCXX20_CONSTEXPR which is OK for stage 3 (as it doesn't affect any
> >>dialects except C++2a).
> >
> >Yes, this is the issue.  I agree that constexpr _real__, __imag__would
> >be better.
> >
> >Do you have any idea where this change would be?  I grepped around a
> >little and couldn't figure it out.  if you don't I'll look more.
>
> No idea, sorry.
>
> >Actually, looking at constexpr.c it looks like the old way ought to work...
> >
> >OK, plain assignment works but not the others.  Interesting.
> >
> >>
> >>>@@ -1872,7 +1831,7 @@
> >>>    { return _Tp(); }
> >>>
> >>>  template<typename _Tp>
> >>>-    inline typename __gnu_cxx::__promote<_Tp>::__type
> >>>+    _GLIBCXX_CONSTEXPR inline typename
> >>>__gnu_cxx::__promote<_Tp>::__type
> >>
> >>This should be _GLIBCXX20_CONSTEXPR.
> >Done.
> >>>Index:
> >>>testsuite/26_numerics/complex/comparison_operators/more_constexpr.cc
> >>>===================================================================
> >>>---
> >>>testsuite/26_numerics/complex/comparison_operators/more_constexpr.cc
> >>>(nonexistent)
> >>>+++
> >>>testsuite/26_numerics/complex/comparison_operators/more_constexpr.cc
> >>>(working copy)
> >>>@@ -0,0 +1,51 @@
> >>>+// { dg-do compile { target c++2a } }
> >>
> >>All the tests with { target c++2a} should also have:
> >>
> >>// { dg-options "-std=gnu++2a" }
> >>
> >>Because otherwise they are skipped by default, and only get run when
> >>RUNTESTFLAGS explicitly includes something like
> >>--target_board=unix/-std=gnu++2a
> >>
> >>The dg-options needs to come first, or it doesn't apply before the
> >>check for { target c++2a }.
> >>
> >Thank you, done.
>
> OK for trunk, thanks.
>
> >Updated patch attached.  I'd like to understand why
> >
> >    __real__ _M_value += __z.real();
> >
> >doesn't work though.
>
> Yes, I agree it should. If you don't figure it out please file a bug
> requesting that it works, so somebody else might look into it.
>

Hi,
I have noticed that
FAIL: 26_numerics/complex/requirements/more_constexpr.cc
on arm and aarch64
The error messages:
Excess errors:
/libstdc++-v3/testsuite/26_numerics/complex/requirements/more_constexpr.cc:168:
error: '__float128' was not declared in this scope
/libstdc++-v3/testsuite/26_numerics/complex/requirements/more_constexpr.cc:168:
error: no matching function for call to
'test_operator_members<<expression error>, __float128>()'
/libstdc++-v3/testsuite/26_numerics/complex/requirements/more_constexpr.cc:168:
error: template argument 1 is invalid

Christophe
Jonathan Wakely Nov. 26, 2018, 11:12 a.m. UTC | #8
On 26/11/18 09:30 +0100, Christophe Lyon wrote:
>On Thu, 22 Nov 2018 at 10:20, Jonathan Wakely <jwakely@redhat.com> wrote:
>>
>> On 20/11/18 17:58 -0500, Ed Smith-Rowland wrote:
>> >On 11/19/18 6:13 AM, Jonathan Wakely wrote:
>> >>On 16/11/18 19:39 -0500, Ed Smith-Rowland wrote:
>> >>>@@ -322,67 +323,43 @@
>> >>>  //@{
>> >>>  ///  Return new complex value @a x plus @a y.
>> >>>  template<typename _Tp>
>> >>>-    inline complex<_Tp>
>> >>>+    inline _GLIBCXX20_CONSTEXPR complex<_Tp>
>> >>>    operator+(const complex<_Tp>& __x, const complex<_Tp>& __y)
>> >>>-    {
>> >>>-      complex<_Tp> __r = __x;
>> >>>-      __r += __y;
>> >>>-      return __r;
>> >>>-    }
>> >>>+    { return complex<_Tp>(__x.real() + __y.real(), __x.imag() +
>> >>>__y.imag()); }
>> >>
>> >>Is this change (and all the similar ones) really needed?
>> >>
>> >>Doesn't the fact that all the constructors and member operators of
>> >>std::complex mean that the original definition is also valid in a
>> >>constexpr function?
>> >These changes are rolled back. Sorry.
>> >>>@@ -1163,50 +1143,43 @@
>> >>>#endif
>> >>>
>> >>>      template<typename _Tp>
>> >>>-        complex&
>> >>>+        _GLIBCXX20_CONSTEXPR complex&
>> >>>        operator=(const complex<_Tp>&  __z)
>> >>>    {
>> >>>-      __real__ _M_value = __z.real();
>> >>>-      __imag__ _M_value = __z.imag();
>> >>>+      _M_value = __z.__rep();
>> >>
>> >>These changes look OK, but I wonder if we shouldn't ask the compiler
>> >>to make it possible to use __real__ and __imag__ in constexpr
>> >>functions instead.
>> >>
>> >>I assume it doesn't, and that's why you made this change. But if it
>> >>Just Worked, and the other changes I commented on above are also
>> >>unnecessary, then this patch would *mostly* just be adding
>> >>_GLIBCXX20_CONSTEXPR which is OK for stage 3 (as it doesn't affect any
>> >>dialects except C++2a).
>> >
>> >Yes, this is the issue.  I agree that constexpr _real__, __imag__would
>> >be better.
>> >
>> >Do you have any idea where this change would be?  I grepped around a
>> >little and couldn't figure it out.  if you don't I'll look more.
>>
>> No idea, sorry.
>>
>> >Actually, looking at constexpr.c it looks like the old way ought to work...
>> >
>> >OK, plain assignment works but not the others.  Interesting.
>> >
>> >>
>> >>>@@ -1872,7 +1831,7 @@
>> >>>    { return _Tp(); }
>> >>>
>> >>>  template<typename _Tp>
>> >>>-    inline typename __gnu_cxx::__promote<_Tp>::__type
>> >>>+    _GLIBCXX_CONSTEXPR inline typename
>> >>>__gnu_cxx::__promote<_Tp>::__type
>> >>
>> >>This should be _GLIBCXX20_CONSTEXPR.
>> >Done.
>> >>>Index:
>> >>>testsuite/26_numerics/complex/comparison_operators/more_constexpr.cc
>> >>>===================================================================
>> >>>---
>> >>>testsuite/26_numerics/complex/comparison_operators/more_constexpr.cc
>> >>>(nonexistent)
>> >>>+++
>> >>>testsuite/26_numerics/complex/comparison_operators/more_constexpr.cc
>> >>>(working copy)
>> >>>@@ -0,0 +1,51 @@
>> >>>+// { dg-do compile { target c++2a } }
>> >>
>> >>All the tests with { target c++2a} should also have:
>> >>
>> >>// { dg-options "-std=gnu++2a" }
>> >>
>> >>Because otherwise they are skipped by default, and only get run when
>> >>RUNTESTFLAGS explicitly includes something like
>> >>--target_board=unix/-std=gnu++2a
>> >>
>> >>The dg-options needs to come first, or it doesn't apply before the
>> >>check for { target c++2a }.
>> >>
>> >Thank you, done.
>>
>> OK for trunk, thanks.
>>
>> >Updated patch attached.  I'd like to understand why
>> >
>> >    __real__ _M_value += __z.real();
>> >
>> >doesn't work though.
>>
>> Yes, I agree it should. If you don't figure it out please file a bug
>> requesting that it works, so somebody else might look into it.
>>
>
>Hi,
>I have noticed that
>FAIL: 26_numerics/complex/requirements/more_constexpr.cc
>on arm and aarch64
>The error messages:
>Excess errors:
>/libstdc++-v3/testsuite/26_numerics/complex/requirements/more_constexpr.cc:168:
>error: '__float128' was not declared in this scope
>/libstdc++-v3/testsuite/26_numerics/complex/requirements/more_constexpr.cc:168:
>error: no matching function for call to
>'test_operator_members<<expression error>, __float128>()'
>/libstdc++-v3/testsuite/26_numerics/complex/requirements/more_constexpr.cc:168:
>error: template argument 1 is invalid

Should be fixed by this patch, committed to trunk.
commit 71f24d050e9e1e4632c62c2801691151e63292b3
Author: Jonathan Wakely <jwakely@redhat.com>
Date:   Mon Nov 26 11:09:10 2018 +0000

    Only use __float128 in test if available
    
            * testsuite/26_numerics/complex/requirements/more_constexpr.cc: Fix
            failure on targets without __float128.

diff --git a/libstdc++-v3/testsuite/26_numerics/complex/requirements/more_constexpr.cc b/libstdc++-v3/testsuite/26_numerics/complex/requirements/more_constexpr.cc
index 902e7ce8e87..5e515a692db 100644
--- a/libstdc++-v3/testsuite/26_numerics/complex/requirements/more_constexpr.cc
+++ b/libstdc++-v3/testsuite/26_numerics/complex/requirements/more_constexpr.cc
@@ -164,8 +164,10 @@ int main()
   __gnu_test::test_operator_members<long double, double>();
   __gnu_test::test_operator_members<long double, long double>();
 
+#if defined(_GLIBCXX_USE_FLOAT128)
   // Test primary template.
   __gnu_test::test_operator_members<__float128, __float128>();
+#endif
 
   return 0;
 }
Christophe Lyon Nov. 27, 2018, 6:45 a.m. UTC | #9
On Mon, 26 Nov 2018 at 12:12, Jonathan Wakely <jwakely@redhat.com> wrote:
>
> On 26/11/18 09:30 +0100, Christophe Lyon wrote:
> >On Thu, 22 Nov 2018 at 10:20, Jonathan Wakely <jwakely@redhat.com> wrote:
> >>
> >> On 20/11/18 17:58 -0500, Ed Smith-Rowland wrote:
> >> >On 11/19/18 6:13 AM, Jonathan Wakely wrote:
> >> >>On 16/11/18 19:39 -0500, Ed Smith-Rowland wrote:
> >> >>>@@ -322,67 +323,43 @@
> >> >>>  //@{
> >> >>>  ///  Return new complex value @a x plus @a y.
> >> >>>  template<typename _Tp>
> >> >>>-    inline complex<_Tp>
> >> >>>+    inline _GLIBCXX20_CONSTEXPR complex<_Tp>
> >> >>>    operator+(const complex<_Tp>& __x, const complex<_Tp>& __y)
> >> >>>-    {
> >> >>>-      complex<_Tp> __r = __x;
> >> >>>-      __r += __y;
> >> >>>-      return __r;
> >> >>>-    }
> >> >>>+    { return complex<_Tp>(__x.real() + __y.real(), __x.imag() +
> >> >>>__y.imag()); }
> >> >>
> >> >>Is this change (and all the similar ones) really needed?
> >> >>
> >> >>Doesn't the fact that all the constructors and member operators of
> >> >>std::complex mean that the original definition is also valid in a
> >> >>constexpr function?
> >> >These changes are rolled back. Sorry.
> >> >>>@@ -1163,50 +1143,43 @@
> >> >>>#endif
> >> >>>
> >> >>>      template<typename _Tp>
> >> >>>-        complex&
> >> >>>+        _GLIBCXX20_CONSTEXPR complex&
> >> >>>        operator=(const complex<_Tp>&  __z)
> >> >>>    {
> >> >>>-      __real__ _M_value = __z.real();
> >> >>>-      __imag__ _M_value = __z.imag();
> >> >>>+      _M_value = __z.__rep();
> >> >>
> >> >>These changes look OK, but I wonder if we shouldn't ask the compiler
> >> >>to make it possible to use __real__ and __imag__ in constexpr
> >> >>functions instead.
> >> >>
> >> >>I assume it doesn't, and that's why you made this change. But if it
> >> >>Just Worked, and the other changes I commented on above are also
> >> >>unnecessary, then this patch would *mostly* just be adding
> >> >>_GLIBCXX20_CONSTEXPR which is OK for stage 3 (as it doesn't affect any
> >> >>dialects except C++2a).
> >> >
> >> >Yes, this is the issue.  I agree that constexpr _real__, __imag__would
> >> >be better.
> >> >
> >> >Do you have any idea where this change would be?  I grepped around a
> >> >little and couldn't figure it out.  if you don't I'll look more.
> >>
> >> No idea, sorry.
> >>
> >> >Actually, looking at constexpr.c it looks like the old way ought to work...
> >> >
> >> >OK, plain assignment works but not the others.  Interesting.
> >> >
> >> >>
> >> >>>@@ -1872,7 +1831,7 @@
> >> >>>    { return _Tp(); }
> >> >>>
> >> >>>  template<typename _Tp>
> >> >>>-    inline typename __gnu_cxx::__promote<_Tp>::__type
> >> >>>+    _GLIBCXX_CONSTEXPR inline typename
> >> >>>__gnu_cxx::__promote<_Tp>::__type
> >> >>
> >> >>This should be _GLIBCXX20_CONSTEXPR.
> >> >Done.
> >> >>>Index:
> >> >>>testsuite/26_numerics/complex/comparison_operators/more_constexpr.cc
> >> >>>===================================================================
> >> >>>---
> >> >>>testsuite/26_numerics/complex/comparison_operators/more_constexpr.cc
> >> >>>(nonexistent)
> >> >>>+++
> >> >>>testsuite/26_numerics/complex/comparison_operators/more_constexpr.cc
> >> >>>(working copy)
> >> >>>@@ -0,0 +1,51 @@
> >> >>>+// { dg-do compile { target c++2a } }
> >> >>
> >> >>All the tests with { target c++2a} should also have:
> >> >>
> >> >>// { dg-options "-std=gnu++2a" }
> >> >>
> >> >>Because otherwise they are skipped by default, and only get run when
> >> >>RUNTESTFLAGS explicitly includes something like
> >> >>--target_board=unix/-std=gnu++2a
> >> >>
> >> >>The dg-options needs to come first, or it doesn't apply before the
> >> >>check for { target c++2a }.
> >> >>
> >> >Thank you, done.
> >>
> >> OK for trunk, thanks.
> >>
> >> >Updated patch attached.  I'd like to understand why
> >> >
> >> >    __real__ _M_value += __z.real();
> >> >
> >> >doesn't work though.
> >>
> >> Yes, I agree it should. If you don't figure it out please file a bug
> >> requesting that it works, so somebody else might look into it.
> >>
> >
> >Hi,
> >I have noticed that
> >FAIL: 26_numerics/complex/requirements/more_constexpr.cc
> >on arm and aarch64
> >The error messages:
> >Excess errors:
> >/libstdc++-v3/testsuite/26_numerics/complex/requirements/more_constexpr.cc:168:
> >error: '__float128' was not declared in this scope
> >/libstdc++-v3/testsuite/26_numerics/complex/requirements/more_constexpr.cc:168:
> >error: no matching function for call to
> >'test_operator_members<<expression error>, __float128>()'
> >/libstdc++-v3/testsuite/26_numerics/complex/requirements/more_constexpr.cc:168:
> >error: template argument 1 is invalid
>
> Should be fixed by this patch, committed to trunk.
>
>
Indeed, thanks.
diff mbox series

Patch

Index: include/std/complex
===================================================================
--- include/std/complex	(revision 266189)
+++ include/std/complex	(working copy)
@@ -68,12 +68,13 @@ 
   ///  Return magnitude of @a z.
   template<typename _Tp> _Tp abs(const complex<_Tp>&);
   ///  Return phase angle of @a z.
-  template<typename _Tp> _Tp arg(const complex<_Tp>&);
+  template<typename _Tp> _Tp _GLIBCXX20_CONSTEXPR arg(const complex<_Tp>&);
   ///  Return @a z magnitude squared.
-  template<typename _Tp> _Tp norm(const complex<_Tp>&);
+  template<typename _Tp> _Tp _GLIBCXX20_CONSTEXPR norm(const complex<_Tp>&);
 
   ///  Return complex conjugate of @a z.
-  template<typename _Tp> complex<_Tp> conj(const complex<_Tp>&);
+  template<typename _Tp>
+    _GLIBCXX20_CONSTEXPR complex<_Tp> conj(const complex<_Tp>&);
   ///  Return complex with magnitude @a rho and angle @a theta.
   template<typename _Tp> complex<_Tp> polar(const _Tp&, const _Tp& = 0);
 
@@ -169,18 +170,18 @@ 
 
       // _GLIBCXX_RESOLVE_LIB_DEFECTS
       // DR 387. std::complex over-encapsulated.
-      void
+      _GLIBCXX20_CONSTEXPR void
       real(_Tp __val) { _M_real = __val; }
 
-      void
+      _GLIBCXX20_CONSTEXPR void
       imag(_Tp __val) { _M_imag = __val; }
 
       /// Assign a scalar to this complex number.
-      complex<_Tp>& operator=(const _Tp&);
+      _GLIBCXX20_CONSTEXPR complex<_Tp>& operator=(const _Tp&);
 
       /// Add a scalar to this complex number.
       // 26.2.5/1
-      complex<_Tp>&
+      _GLIBCXX20_CONSTEXPR complex<_Tp>&
       operator+=(const _Tp& __t)
       {
 	_M_real += __t;
@@ -189,7 +190,7 @@ 
 
       /// Subtract a scalar from this complex number.
       // 26.2.5/3
-      complex<_Tp>&
+      _GLIBCXX20_CONSTEXPR complex<_Tp>&
       operator-=(const _Tp& __t)
       {
 	_M_real -= __t;
@@ -197,30 +198,30 @@ 
       }
 
       /// Multiply this complex number by a scalar.
-      complex<_Tp>& operator*=(const _Tp&);
+      _GLIBCXX20_CONSTEXPR complex<_Tp>& operator*=(const _Tp&);
       /// Divide this complex number by a scalar.
-      complex<_Tp>& operator/=(const _Tp&);
+      _GLIBCXX20_CONSTEXPR complex<_Tp>& operator/=(const _Tp&);
 
       // Let the compiler synthesize the copy assignment operator
 #if __cplusplus >= 201103L
-      complex& operator=(const complex&) = default;
+      _GLIBCXX20_CONSTEXPR complex& operator=(const complex&) = default;
 #endif
 
       /// Assign another complex number to this one.
       template<typename _Up>
-        complex<_Tp>& operator=(const complex<_Up>&);
+        _GLIBCXX20_CONSTEXPR complex<_Tp>& operator=(const complex<_Up>&);
       /// Add another complex number to this one.
       template<typename _Up>
-        complex<_Tp>& operator+=(const complex<_Up>&);
+        _GLIBCXX20_CONSTEXPR complex<_Tp>& operator+=(const complex<_Up>&);
       /// Subtract another complex number from this one.
       template<typename _Up>
-        complex<_Tp>& operator-=(const complex<_Up>&);
+        _GLIBCXX20_CONSTEXPR complex<_Tp>& operator-=(const complex<_Up>&);
       /// Multiply this complex number by another.
       template<typename _Up>
-        complex<_Tp>& operator*=(const complex<_Up>&);
+        _GLIBCXX20_CONSTEXPR complex<_Tp>& operator*=(const complex<_Up>&);
       /// Divide this complex number by another.
       template<typename _Up>
-        complex<_Tp>& operator/=(const complex<_Up>&);
+        _GLIBCXX20_CONSTEXPR complex<_Tp>& operator/=(const complex<_Up>&);
 
       _GLIBCXX_CONSTEXPR complex __rep() const
       { return *this; }
@@ -231,7 +232,7 @@ 
     };
 
   template<typename _Tp>
-    complex<_Tp>&
+    _GLIBCXX20_CONSTEXPR complex<_Tp>&
     complex<_Tp>::operator=(const _Tp& __t)
     {
      _M_real = __t;
@@ -241,7 +242,7 @@ 
 
   // 26.2.5/5
   template<typename _Tp>
-    complex<_Tp>&
+    _GLIBCXX20_CONSTEXPR complex<_Tp>&
     complex<_Tp>::operator*=(const _Tp& __t)
     {
       _M_real *= __t;
@@ -251,7 +252,7 @@ 
 
   // 26.2.5/7
   template<typename _Tp>
-    complex<_Tp>&
+    _GLIBCXX20_CONSTEXPR complex<_Tp>&
     complex<_Tp>::operator/=(const _Tp& __t)
     {
       _M_real /= __t;
@@ -261,7 +262,7 @@ 
 
   template<typename _Tp>
     template<typename _Up>
-    complex<_Tp>&
+    _GLIBCXX20_CONSTEXPR complex<_Tp>&
     complex<_Tp>::operator=(const complex<_Up>& __z)
     {
       _M_real = __z.real();
@@ -272,7 +273,7 @@ 
   // 26.2.5/9
   template<typename _Tp>
     template<typename _Up>
-    complex<_Tp>&
+    _GLIBCXX20_CONSTEXPR complex<_Tp>&
     complex<_Tp>::operator+=(const complex<_Up>& __z)
     {
       _M_real += __z.real();
@@ -283,7 +284,7 @@ 
   // 26.2.5/11
   template<typename _Tp>
     template<typename _Up>
-    complex<_Tp>&
+    _GLIBCXX20_CONSTEXPR complex<_Tp>&
     complex<_Tp>::operator-=(const complex<_Up>& __z)
     {
       _M_real -= __z.real();
@@ -295,7 +296,7 @@ 
   // XXX: This is a grammar school implementation.
   template<typename _Tp>
     template<typename _Up>
-    complex<_Tp>&
+    _GLIBCXX20_CONSTEXPR complex<_Tp>&
     complex<_Tp>::operator*=(const complex<_Up>& __z)
     {
       const _Tp __r = _M_real * __z.real() - _M_imag * __z.imag();
@@ -308,7 +309,7 @@ 
   // XXX: This is a grammar school implementation.
   template<typename _Tp>
     template<typename _Up>
-    complex<_Tp>&
+    _GLIBCXX20_CONSTEXPR complex<_Tp>&
     complex<_Tp>::operator/=(const complex<_Up>& __z)
     {
       const _Tp __r =  _M_real * __z.real() + _M_imag * __z.imag();
@@ -322,67 +323,43 @@ 
   //@{
   ///  Return new complex value @a x plus @a y.
   template<typename _Tp>
-    inline complex<_Tp>
+    inline _GLIBCXX20_CONSTEXPR complex<_Tp>
     operator+(const complex<_Tp>& __x, const complex<_Tp>& __y)
-    {
-      complex<_Tp> __r = __x;
-      __r += __y;
-      return __r;
-    }
+    { return complex<_Tp>(__x.real() + __y.real(), __x.imag() + __y.imag()); }
 
   template<typename _Tp>
-    inline complex<_Tp>
+    inline _GLIBCXX20_CONSTEXPR complex<_Tp>
     operator+(const complex<_Tp>& __x, const _Tp& __y)
-    {
-      complex<_Tp> __r = __x;
-      __r += __y;
-      return __r;
-    }
+    { return complex<_Tp>(__x.real() + __y, __x.imag()); }
 
   template<typename _Tp>
-    inline complex<_Tp>
+    inline _GLIBCXX20_CONSTEXPR complex<_Tp>
     operator+(const _Tp& __x, const complex<_Tp>& __y)
-    {
-      complex<_Tp> __r = __y;
-      __r += __x;
-      return __r;
-    }
+    { return complex<_Tp>(__x + __y.real(), __y.imag()); }
   //@}
 
   //@{
   ///  Return new complex value @a x minus @a y.
   template<typename _Tp>
-    inline complex<_Tp>
+    inline _GLIBCXX20_CONSTEXPR complex<_Tp>
     operator-(const complex<_Tp>& __x, const complex<_Tp>& __y)
-    {
-      complex<_Tp> __r = __x;
-      __r -= __y;
-      return __r;
-    }
+    { return complex<_Tp>(__x.real() - __y.real(), __x.imag() - __y.imag()); }
 
   template<typename _Tp>
-    inline complex<_Tp>
+    inline _GLIBCXX20_CONSTEXPR complex<_Tp>
     operator-(const complex<_Tp>& __x, const _Tp& __y)
-    {
-      complex<_Tp> __r = __x;
-      __r -= __y;
-      return __r;
-    }
+    { return complex<_Tp>(__x.real() - __y, __x.imag()); }
 
   template<typename _Tp>
-    inline complex<_Tp>
+    inline _GLIBCXX20_CONSTEXPR complex<_Tp>
     operator-(const _Tp& __x, const complex<_Tp>& __y)
-    {
-      complex<_Tp> __r(__x, -__y.imag());
-      __r -= __y.real();
-      return __r;
-    }
+    { return complex<_Tp>(__x - __y.real(), -__y.imag()); }
   //@}
 
   //@{
   ///  Return new complex value @a x times @a y.
   template<typename _Tp>
-    inline complex<_Tp>
+    inline _GLIBCXX20_CONSTEXPR complex<_Tp>
     operator*(const complex<_Tp>& __x, const complex<_Tp>& __y)
     {
       complex<_Tp> __r = __x;
@@ -391,7 +368,7 @@ 
     }
 
   template<typename _Tp>
-    inline complex<_Tp>
+    inline _GLIBCXX20_CONSTEXPR complex<_Tp>
     operator*(const complex<_Tp>& __x, const _Tp& __y)
     {
       complex<_Tp> __r = __x;
@@ -400,7 +377,7 @@ 
     }
 
   template<typename _Tp>
-    inline complex<_Tp>
+    inline _GLIBCXX20_CONSTEXPR complex<_Tp>
     operator*(const _Tp& __x, const complex<_Tp>& __y)
     {
       complex<_Tp> __r = __y;
@@ -412,7 +389,7 @@ 
   //@{
   ///  Return new complex value @a x divided by @a y.
   template<typename _Tp>
-    inline complex<_Tp>
+    inline _GLIBCXX20_CONSTEXPR complex<_Tp>
     operator/(const complex<_Tp>& __x, const complex<_Tp>& __y)
     {
       complex<_Tp> __r = __x;
@@ -421,7 +398,7 @@ 
     }
 
   template<typename _Tp>
-    inline complex<_Tp>
+    inline _GLIBCXX20_CONSTEXPR complex<_Tp>
     operator/(const complex<_Tp>& __x, const _Tp& __y)
     {
       complex<_Tp> __r = __x;
@@ -430,7 +407,7 @@ 
     }
 
   template<typename _Tp>
-    inline complex<_Tp>
+    inline _GLIBCXX20_CONSTEXPR complex<_Tp>
     operator/(const _Tp& __x, const complex<_Tp>& __y)
     {
       complex<_Tp> __r = __x;
@@ -441,15 +418,15 @@ 
 
   ///  Return @a x.
   template<typename _Tp>
-    inline complex<_Tp>
+    inline _GLIBCXX20_CONSTEXPR complex<_Tp>
     operator+(const complex<_Tp>& __x)
     { return __x; }
 
   ///  Return complex negation of @a x.
   template<typename _Tp>
-    inline complex<_Tp>
+    inline _GLIBCXX20_CONSTEXPR complex<_Tp>
     operator-(const complex<_Tp>& __x)
-    {  return complex<_Tp>(-__x.real(), -__x.imag()); }
+    { return complex<_Tp>(-__x.real(), -__x.imag()); }
 
   //@{
   ///  Return true if @a x is equal to @a y.
@@ -625,27 +602,27 @@ 
 
   // 26.2.7/4: arg(__z): Returns the phase angle of __z.
   template<typename _Tp>
-    inline _Tp
+    inline _GLIBCXX20_CONSTEXPR _Tp
     __complex_arg(const complex<_Tp>& __z)
     { return  atan2(__z.imag(), __z.real()); }
 
 #if _GLIBCXX_USE_C99_COMPLEX
-  inline float
+  inline _GLIBCXX20_CONSTEXPR float
   __complex_arg(__complex__ float __z) { return __builtin_cargf(__z); }
 
-  inline double
+  inline _GLIBCXX20_CONSTEXPR double
   __complex_arg(__complex__ double __z) { return __builtin_carg(__z); }
 
-  inline long double
+  inline _GLIBCXX20_CONSTEXPR long double
   __complex_arg(const __complex__ long double& __z)
   { return __builtin_cargl(__z); }
 
   template<typename _Tp>
-    inline _Tp
+    inline _GLIBCXX20_CONSTEXPR _Tp
     arg(const complex<_Tp>& __z) { return __complex_arg(__z.__rep()); }
 #else
   template<typename _Tp>
-    inline _Tp
+    inline _GLIBCXX20_CONSTEXPR _Tp
     arg(const complex<_Tp>& __z) { return __complex_arg(__z); }
 #endif
 
@@ -658,7 +635,7 @@ 
     struct _Norm_helper
     {
       template<typename _Tp>
-        static inline _Tp _S_do_it(const complex<_Tp>& __z)
+        static inline _GLIBCXX_CONSTEXPR _Tp _S_do_it(const complex<_Tp>& __z)
         {
           const _Tp __x = __z.real();
           const _Tp __y = __z.imag();
@@ -670,15 +647,18 @@ 
     struct _Norm_helper<true>
     {
       template<typename _Tp>
-        static inline _Tp _S_do_it(const complex<_Tp>& __z)
+        static inline _GLIBCXX_CONSTEXPR _Tp _S_do_it(const complex<_Tp>& __z)
         {
-          _Tp __res = std::abs(__z);
-          return __res * __res;
+          //_Tp __res = std::abs(__z);
+          //return __res * __res;
+          const _Tp __x = __z.real();
+          const _Tp __y = __z.imag();
+          return __x * __x + __y * __y;
         }
     };
 
   template<typename _Tp>
-    inline _Tp
+    inline _GLIBCXX20_CONSTEXPR _Tp
     norm(const complex<_Tp>& __z)
     {
       return _Norm_helper<__is_floating<_Tp>::__value
@@ -694,7 +674,7 @@ 
     }
 
   template<typename _Tp>
-    inline complex<_Tp>
+    inline _GLIBCXX20_CONSTEXPR complex<_Tp>
     conj(const complex<_Tp>& __z)
     { return complex<_Tp>(__z.real(), -__z.imag()); }
 
@@ -1115,13 +1095,13 @@ 
 
       // _GLIBCXX_RESOLVE_LIB_DEFECTS
       // DR 387. std::complex over-encapsulated.
-      void
+      _GLIBCXX20_CONSTEXPR void
       real(float __val) { __real__ _M_value = __val; }
 
-      void
+      _GLIBCXX20_CONSTEXPR void
       imag(float __val) { __imag__ _M_value = __val; }
 
-      complex&
+      _GLIBCXX20_CONSTEXPR complex&
       operator=(float __f)
       {
 	_M_value = __f;
@@ -1128,7 +1108,7 @@ 
 	return *this;
       }
 
-      complex&
+      _GLIBCXX20_CONSTEXPR complex&
       operator+=(float __f)
       {
 	_M_value += __f;
@@ -1135,7 +1115,7 @@ 
 	return *this;
       }
 
-      complex&
+      _GLIBCXX20_CONSTEXPR complex&
       operator-=(float __f)
       {
 	_M_value -= __f;
@@ -1142,7 +1122,7 @@ 
 	return *this;
       }
 
-      complex&
+      _GLIBCXX20_CONSTEXPR complex&
       operator*=(float __f)
       {
 	_M_value *= __f;
@@ -1149,7 +1129,7 @@ 
 	return *this;
       }
 
-      complex&
+      _GLIBCXX20_CONSTEXPR complex&
       operator/=(float __f)
       {
 	_M_value /= __f;
@@ -1163,50 +1143,43 @@ 
 #endif
 
       template<typename _Tp>
-        complex&
+        _GLIBCXX20_CONSTEXPR complex&
         operator=(const complex<_Tp>&  __z)
 	{
-	  __real__ _M_value = __z.real();
-	  __imag__ _M_value = __z.imag();
+	  _M_value = __z.__rep();
 	  return *this;
 	}
 
       template<typename _Tp>
-        complex&
+        _GLIBCXX20_CONSTEXPR complex&
         operator+=(const complex<_Tp>& __z)
 	{
-	  __real__ _M_value += __z.real();
-	  __imag__ _M_value += __z.imag();
+	  _M_value += __z.__rep();
 	  return *this;
 	}
 
       template<class _Tp>
-        complex&
+        _GLIBCXX20_CONSTEXPR complex&
         operator-=(const complex<_Tp>& __z)
 	{
-	  __real__ _M_value -= __z.real();
-	  __imag__ _M_value -= __z.imag();
+	  _M_value -= __z.__rep();
 	  return *this;
 	}
 
       template<class _Tp>
-        complex&
+        _GLIBCXX20_CONSTEXPR complex&
         operator*=(const complex<_Tp>& __z)
 	{
-	  _ComplexT __t;
-	  __real__ __t = __z.real();
-	  __imag__ __t = __z.imag();
+	  const _ComplexT __t = __z.__rep();
 	  _M_value *= __t;
 	  return *this;
 	}
 
       template<class _Tp>
-        complex&
+        _GLIBCXX20_CONSTEXPR complex&
         operator/=(const complex<_Tp>& __z)
 	{
-	  _ComplexT __t;
-	  __real__ __t = __z.real();
-	  __imag__ __t = __z.imag();
+	  const _ComplexT __t = __z.__rep();
 	  _M_value /= __t;
 	  return *this;
 	}
@@ -1268,13 +1241,13 @@ 
 
       // _GLIBCXX_RESOLVE_LIB_DEFECTS
       // DR 387. std::complex over-encapsulated.
-      void
+      _GLIBCXX20_CONSTEXPR void
       real(double __val) { __real__ _M_value = __val; }
 
-      void
+      _GLIBCXX20_CONSTEXPR void
       imag(double __val) { __imag__ _M_value = __val; }
 
-      complex&
+      _GLIBCXX20_CONSTEXPR complex&
       operator=(double __d)
       {
 	_M_value = __d;
@@ -1281,7 +1254,7 @@ 
 	return *this;
       }
 
-      complex&
+      _GLIBCXX20_CONSTEXPR complex&
       operator+=(double __d)
       {
 	_M_value += __d;
@@ -1288,7 +1261,7 @@ 
 	return *this;
       }
 
-      complex&
+      _GLIBCXX20_CONSTEXPR complex&
       operator-=(double __d)
       {
 	_M_value -= __d;
@@ -1295,7 +1268,7 @@ 
 	return *this;
       }
 
-      complex&
+      _GLIBCXX20_CONSTEXPR complex&
       operator*=(double __d)
       {
 	_M_value *= __d;
@@ -1302,7 +1275,7 @@ 
 	return *this;
       }
 
-      complex&
+      _GLIBCXX20_CONSTEXPR complex&
       operator/=(double __d)
       {
 	_M_value /= __d;
@@ -1315,50 +1288,43 @@ 
 #endif
 
       template<typename _Tp>
-        complex&
+        _GLIBCXX20_CONSTEXPR complex&
         operator=(const complex<_Tp>& __z)
 	{
-	  __real__ _M_value = __z.real();
-	  __imag__ _M_value = __z.imag();
+	  _M_value = __z.__rep();
 	  return *this;
 	}
 
       template<typename _Tp>
-        complex&
+        _GLIBCXX20_CONSTEXPR complex&
         operator+=(const complex<_Tp>& __z)
 	{
-	  __real__ _M_value += __z.real();
-	  __imag__ _M_value += __z.imag();
+	  _M_value += __z.__rep();
 	  return *this;
 	}
 
       template<typename _Tp>
-        complex&
+        _GLIBCXX20_CONSTEXPR complex&
         operator-=(const complex<_Tp>& __z)
 	{
-	  __real__ _M_value -= __z.real();
-	  __imag__ _M_value -= __z.imag();
+	  _M_value -= __z.__rep();
 	  return *this;
 	}
 
       template<typename _Tp>
-        complex&
+        _GLIBCXX20_CONSTEXPR complex&
         operator*=(const complex<_Tp>& __z)
 	{
-	  _ComplexT __t;
-	  __real__ __t = __z.real();
-	  __imag__ __t = __z.imag();
+	  const _ComplexT __t = __z.__rep();
 	  _M_value *= __t;
 	  return *this;
 	}
 
       template<typename _Tp>
-        complex&
+        _GLIBCXX20_CONSTEXPR complex&
         operator/=(const complex<_Tp>& __z)
 	{
-	  _ComplexT __t;
-	  __real__ __t = __z.real();
-	  __imag__ __t = __z.imag();
+	  const _ComplexT __t = __z.__rep();
 	  _M_value /= __t;
 	  return *this;
 	}
@@ -1422,13 +1388,13 @@ 
 
       // _GLIBCXX_RESOLVE_LIB_DEFECTS
       // DR 387. std::complex over-encapsulated.
-      void
+      _GLIBCXX20_CONSTEXPR void
       real(long double __val) { __real__ _M_value = __val; }
 
-      void
+      _GLIBCXX20_CONSTEXPR void
       imag(long double __val) { __imag__ _M_value = __val; }
 
-      complex&
+      _GLIBCXX20_CONSTEXPR complex&
       operator=(long double __r)
       {
 	_M_value = __r;
@@ -1435,7 +1401,7 @@ 
 	return *this;
       }
 
-      complex&
+      _GLIBCXX20_CONSTEXPR complex&
       operator+=(long double __r)
       {
 	_M_value += __r;
@@ -1442,7 +1408,7 @@ 
 	return *this;
       }
 
-      complex&
+      _GLIBCXX20_CONSTEXPR complex&
       operator-=(long double __r)
       {
 	_M_value -= __r;
@@ -1449,7 +1415,7 @@ 
 	return *this;
       }
 
-      complex&
+      _GLIBCXX20_CONSTEXPR complex&
       operator*=(long double __r)
       {
 	_M_value *= __r;
@@ -1456,7 +1422,7 @@ 
 	return *this;
       }
 
-      complex&
+      _GLIBCXX20_CONSTEXPR complex&
       operator/=(long double __r)
       {
 	_M_value /= __r;
@@ -1469,50 +1435,43 @@ 
 #endif
 
       template<typename _Tp>
-        complex&
+        _GLIBCXX20_CONSTEXPR complex&
         operator=(const complex<_Tp>& __z)
 	{
-	  __real__ _M_value = __z.real();
-	  __imag__ _M_value = __z.imag();
+	  _M_value = __z.__rep();
 	  return *this;
 	}
 
       template<typename _Tp>
-        complex&
+        _GLIBCXX20_CONSTEXPR complex&
 	operator+=(const complex<_Tp>& __z)
 	{
-	  __real__ _M_value += __z.real();
-	  __imag__ _M_value += __z.imag();
+	  _M_value += __z.__rep();
 	  return *this;
 	}
 
       template<typename _Tp>
-        complex&
+        _GLIBCXX20_CONSTEXPR complex&
 	operator-=(const complex<_Tp>& __z)
 	{
-	  __real__ _M_value -= __z.real();
-	  __imag__ _M_value -= __z.imag();
+	  _M_value -= __z.__rep();
 	  return *this;
 	}
 
       template<typename _Tp>
-        complex&
+        _GLIBCXX20_CONSTEXPR complex&
 	operator*=(const complex<_Tp>& __z)
 	{
-	  _ComplexT __t;
-	  __real__ __t = __z.real();
-	  __imag__ __t = __z.imag();
+	  const _ComplexT __t = __z.__rep();
 	  _M_value *= __t;
 	  return *this;
 	}
 
       template<typename _Tp>
-        complex&
+        _GLIBCXX20_CONSTEXPR complex&
 	operator/=(const complex<_Tp>& __z)
 	{
-	  _ComplexT __t;
-	  __real__ __t = __z.real();
-	  __imag__ __t = __z.imag();
+	  const _ComplexT __t = __z.__rep();
 	  _M_value /= __t;
 	  return *this;
 	}
@@ -1854,7 +1813,7 @@ 
 
   /// Additional overloads [8.1.9].
   template<typename _Tp>
-    inline typename __gnu_cxx::__promote<_Tp>::__type
+    inline _GLIBCXX20_CONSTEXPR typename __gnu_cxx::__promote<_Tp>::__type
     arg(_Tp __x)
     {
       typedef typename __gnu_cxx::__promote<_Tp>::__type __type;
@@ -1872,7 +1831,7 @@ 
     { return _Tp(); }
 
   template<typename _Tp>
-    inline typename __gnu_cxx::__promote<_Tp>::__type
+    _GLIBCXX_CONSTEXPR inline typename __gnu_cxx::__promote<_Tp>::__type
     norm(_Tp __x)
     {
       typedef typename __gnu_cxx::__promote<_Tp>::__type __type;
@@ -1911,10 +1870,11 @@ 
 
   // Forward declarations.
   // DR 781.
-  template<typename _Tp> std::complex<_Tp> proj(const std::complex<_Tp>&);
+  template<typename _Tp>
+    _GLIBCXX20_CONSTEXPR std::complex<_Tp> proj(const std::complex<_Tp>&);
 
   template<typename _Tp>
-    std::complex<_Tp>
+    _GLIBCXX20_CONSTEXPR std::complex<_Tp>
     __complex_proj(const std::complex<_Tp>& __z)
     {
       const _Tp __den = (__z.real() * __z.real()
@@ -1925,31 +1885,32 @@ 
     }
 
 #if _GLIBCXX_USE_C99_COMPLEX
-  inline __complex__ float
+  inline _GLIBCXX20_CONSTEXPR __complex__ float
   __complex_proj(__complex__ float __z)
   { return __builtin_cprojf(__z); }
 
-  inline __complex__ double
+  inline _GLIBCXX20_CONSTEXPR __complex__ double
   __complex_proj(__complex__ double __z)
   { return __builtin_cproj(__z); }
 
-  inline __complex__ long double
+  inline _GLIBCXX20_CONSTEXPR __complex__ long double
   __complex_proj(const __complex__ long double& __z)
   { return __builtin_cprojl(__z); }
 
   template<typename _Tp>
-    inline std::complex<_Tp>
+    inline _GLIBCXX20_CONSTEXPR std::complex<_Tp>
     proj(const std::complex<_Tp>& __z)
     { return __complex_proj(__z.__rep()); }
 #else
   template<typename _Tp>
-    inline std::complex<_Tp>
+    inline _GLIBCXX20_CONSTEXPR std::complex<_Tp>
     proj(const std::complex<_Tp>& __z)
     { return __complex_proj(__z); }
 #endif
 
   template<typename _Tp>
-    inline std::complex<typename __gnu_cxx::__promote<_Tp>::__type>
+    inline _GLIBCXX20_CONSTEXPR
+	std::complex<typename __gnu_cxx::__promote<_Tp>::__type>
     proj(_Tp __x)
     {
       typedef typename __gnu_cxx::__promote<_Tp>::__type __type;
@@ -1957,7 +1918,8 @@ 
     }
 
   template<typename _Tp>
-    inline std::complex<typename __gnu_cxx::__promote<_Tp>::__type>
+    inline _GLIBCXX20_CONSTEXPR
+	std::complex<typename __gnu_cxx::__promote<_Tp>::__type>
     conj(_Tp __x)
     {
       typedef typename __gnu_cxx::__promote<_Tp>::__type __type;
Index: testsuite/26_numerics/headers/complex/synopsis.cc
===================================================================
--- testsuite/26_numerics/headers/complex/synopsis.cc	(revision 266189)
+++ testsuite/26_numerics/headers/complex/synopsis.cc	(working copy)
@@ -28,51 +28,71 @@ 
 
   // 26.2.6 operators:
   template<class T>
-    complex<T> operator+(const complex<T>&, const complex<T>&);
-  template<class T> complex<T> operator+(const complex<T>&, const T&);
-  template<class T> complex<T> operator+(const T&, const complex<T>&);
-  template<class T> complex<T> operator-
+    _GLIBCXX20_CONSTEXPR complex<T>
+    operator+(const complex<T>&, const complex<T>&);
+  template<class T>
+    _GLIBCXX20_CONSTEXPR complex<T> operator+(const complex<T>&, const T&);
+  template<class T>
+    _GLIBCXX20_CONSTEXPR complex<T> operator+(const T&, const complex<T>&);
+
+  template<class T>
+    _GLIBCXX20_CONSTEXPR complex<T>
+    operator-(const complex<T>&, const complex<T>&);
+  template<class T>
+    _GLIBCXX20_CONSTEXPR complex<T> operator-(const complex<T>&, const T&);
+  template<class T>
+    _GLIBCXX20_CONSTEXPR complex<T> operator-(const T&, const complex<T>&);
+
+  template<class T>
+    _GLIBCXX20_CONSTEXPR complex<T> operator*
     (const complex<T>&, const complex<T>&);
-  template<class T> complex<T> operator-(const complex<T>&, const T&);
-  template<class T> complex<T> operator-(const T&, const complex<T>&);
-  template<class T> complex<T> operator*
-    (const complex<T>&, const complex<T>&);
-  template<class T> complex<T> operator*(const complex<T>&, const T&);
-  template<class T> complex<T> operator*(const T&, const complex<T>&);
-  template<class T> complex<T> operator/
-    (const complex<T>&, const complex<T>&);
-  template<class T> complex<T> operator/(const complex<T>&, const T&);
-  template<class T> complex<T> operator/(const T&, const complex<T>&);
-  template<class T> complex<T> operator+(const complex<T>&);
-  template<class T> complex<T> operator-(const complex<T>&);
-  template<class T> _GLIBCXX_CONSTEXPR bool operator==
-    (const complex<T>&, const complex<T>&);
-  template<class T> _GLIBCXX_CONSTEXPR bool operator==
-    (const complex<T>&, const T&);
-  template<class T> _GLIBCXX_CONSTEXPR bool operator==
-    (const T&, const complex<T>&);
+  template<class T>
+    _GLIBCXX20_CONSTEXPR complex<T> operator*(const complex<T>&, const T&);
+  template<class T>
+    _GLIBCXX20_CONSTEXPR complex<T> operator*(const T&, const complex<T>&);
 
+  template<class T>
+    _GLIBCXX20_CONSTEXPR complex<T>
+    operator/(const complex<T>&, const complex<T>&);
+  template<class T>
+    _GLIBCXX20_CONSTEXPR complex<T> operator/(const complex<T>&, const T&);
+  template<class T>
+    _GLIBCXX20_CONSTEXPR complex<T> operator/(const T&, const complex<T>&);
 
-  template<class T> _GLIBCXX_CONSTEXPR bool operator!=
-    (const complex<T>&, const complex<T>&);
-  template<class T> _GLIBCXX_CONSTEXPR bool operator!=
-    (const complex<T>&, const T&);
-  template<class T> _GLIBCXX_CONSTEXPR bool operator!=
-    (const T&, const complex<T>&);
+  template<class T>
+    _GLIBCXX20_CONSTEXPR complex<T> operator+(const complex<T>&);
+  template<class T>
+    _GLIBCXX20_CONSTEXPR complex<T> operator-(const complex<T>&);
+
+  template<class T>
+    _GLIBCXX_CONSTEXPR bool operator==(const complex<T>&, const complex<T>&);
+  template<class T>
+     _GLIBCXX_CONSTEXPR bool operator==(const complex<T>&, const T&);
+  template<class T>
+    _GLIBCXX_CONSTEXPR bool operator==(const T&, const complex<T>&);
+
+  template<class T>
+    _GLIBCXX_CONSTEXPR bool operator!=(const complex<T>&, const complex<T>&);
+  template<class T>
+    _GLIBCXX_CONSTEXPR bool operator!=(const complex<T>&, const T&);
+  template<class T>
+    _GLIBCXX_CONSTEXPR bool operator!=(const T&, const complex<T>&);
+
   template<class T, class charT, class traits>
-  basic_istream<charT, traits>&
-  operator>>(basic_istream<charT, traits>&, complex<T>&);
+    basic_istream<charT, traits>&
+    operator>>(basic_istream<charT, traits>&, complex<T>&);
   template<class T, class charT, class traits>
-  basic_ostream<charT, traits>&
-  operator<<(basic_ostream<charT, traits>&, const complex<T>&);
+    basic_ostream<charT, traits>&
+    operator<<(basic_ostream<charT, traits>&, const complex<T>&);
 
   // 26.2.7 values:
   template<class T> _GLIBCXX_CONSTEXPR T real(const complex<T>&);
   template<class T> _GLIBCXX_CONSTEXPR T imag(const complex<T>&);
   template<class T> T abs(const complex<T>&);
-  template<class T> T arg(const complex<T>&);
-  template<class T> T norm(const complex<T>&);
-  template<class T> complex<T> conj(const complex<T>&);
+  template<class T> _GLIBCXX20_CONSTEXPR T arg(const complex<T>&);
+  template<class T> _GLIBCXX20_CONSTEXPR T norm(const complex<T>&);
+  template<class T> _GLIBCXX20_CONSTEXPR complex<T> conj(const complex<T>&);
+  template<class T> _GLIBCXX20_CONSTEXPR complex<T> proj(const complex<T>&);
   template<class T> complex<T> polar(const T& rho, const T& theta);
 
   // 26.2.8 transcendentals:
Index: testsuite/26_numerics/complex/comparison_operators/constexpr_all_the_things.cc
===================================================================
--- testsuite/26_numerics/complex/comparison_operators/constexpr_all_the_things.cc	(nonexistent)
+++ testsuite/26_numerics/complex/comparison_operators/constexpr_all_the_things.cc	(working copy)
@@ -0,0 +1,51 @@ 
+// { dg-do compile { target c++2a } }
+
+// Copyright (C) 2018 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/>.
+
+#include <complex>
+#include <testsuite_common_types.h>
+
+template<bool ok>
+  struct thing
+  { };
+
+// 
+template<typename _Tp>
+  void
+  test_comparison()
+  {
+    constexpr std::complex<_Tp> a{1.1, 2.2};
+    constexpr std::complex<_Tp> b{3.3, 4.4};
+    if constexpr (a == b)
+      auto c [[maybe_unused]] = a + b;
+    if constexpr (a != b)
+      auto c [[maybe_unused]] = a - b;
+
+    thing<a == b> thing1 [[maybe_unused]];
+    thing<a != b> thing2 [[maybe_unused]];
+  }
+
+int
+main()
+{
+  test_comparison<float>();
+  test_comparison<double>();
+  test_comparison<long double>();
+
+  return 0;
+}
Index: testsuite/26_numerics/complex/operators/constexpr_all_the_things.cc
===================================================================
--- testsuite/26_numerics/complex/operators/constexpr_all_the_things.cc	(nonexistent)
+++ testsuite/26_numerics/complex/operators/constexpr_all_the_things.cc	(working copy)
@@ -0,0 +1,61 @@ 
+// { dg-do compile { target c++2a } }
+
+// Copyright (C) 2018 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/>.
+
+#include <complex>
+#include <testsuite_common_types.h>
+
+namespace __gnu_test
+{
+  // Test constexpr symmetric complex @ real, real @ complex, complex @ complex.
+  template<typename _Tp>
+    void
+    test_operators()
+    {
+      constexpr std::complex<_Tp> a{1, 2};
+      constexpr std::complex<_Tp> b{3, 4};
+      constexpr _Tp c = 5;
+
+      constexpr auto w [[maybe_unused]] = +a;
+      constexpr auto z [[maybe_unused]] = -a;
+
+      constexpr auto apc [[maybe_unused]] = a + c;
+      constexpr auto amc [[maybe_unused]] = a - c;
+      constexpr auto atc [[maybe_unused]] = a * c;
+      constexpr auto adc [[maybe_unused]] = a / c;
+
+      constexpr auto cpa [[maybe_unused]] = c + a;
+      constexpr auto cma [[maybe_unused]] = c - a;
+      constexpr auto cta [[maybe_unused]] = c * a;
+      constexpr auto cda [[maybe_unused]] = c / a;
+
+      constexpr auto apb [[maybe_unused]] = a + b;
+      constexpr auto amb [[maybe_unused]] = a - b;
+      constexpr auto atb [[maybe_unused]] = a * b;
+      constexpr auto adb [[maybe_unused]] = a / b;
+    }
+}
+
+int main()
+{
+  __gnu_test::test_operators<float>();
+  __gnu_test::test_operators<double>();
+  __gnu_test::test_operators<long double>();
+
+  return 0;
+}
Index: testsuite/26_numerics/complex/requirements/constexpr_all_the_things.cc
===================================================================
--- testsuite/26_numerics/complex/requirements/constexpr_all_the_things.cc	(nonexistent)
+++ testsuite/26_numerics/complex/requirements/constexpr_all_the_things.cc	(working copy)
@@ -0,0 +1,170 @@ 
+// { dg-do compile { target c++2a } }
+
+// Copyright (C) 2018 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/>.
+
+#include <complex>
+#include <testsuite_common_types.h>
+
+namespace __gnu_test
+{
+
+  // Test constexpr real(val) imag(val).
+  template<typename _Tp, const int _Val = 42>
+    inline void
+    set_real(std::complex<_Tp>& a)
+    { a.real(_Val); }
+
+  template<typename _Tp, const int _Val = 42>
+    inline void
+    set_imag(std::complex<_Tp>& a)
+    { a.imag(_Val); }
+
+  template<typename _Tp>
+    void
+    test_members()
+    {
+      constexpr std::complex<_Tp> a{1.1, 2.2};
+
+      std::complex<_Tp> z = a;
+
+      set_real<_Tp, 33>(z);
+      set_imag<_Tp, 44>(z);
+    }
+
+  // Test operators @=complex and @=real.
+  template<typename _Tp, typename _Up>
+    constexpr std::complex<_Tp>
+    sum(const std::complex<_Tp>& z, const std::complex<_Up>& w)
+    {
+      std::complex<_Tp> x = z;
+      x += w;
+      return x;
+    }
+
+  template<typename _Tp, typename _Up>
+    constexpr std::complex<_Tp>
+    sum(const std::complex<_Tp>& z, _Up w)
+    {
+      std::complex<_Tp> x = z;
+      x += w;
+      return x;
+    }
+
+  template<typename _Tp, typename _Up>
+    constexpr std::complex<_Tp>
+    dif(const std::complex<_Tp>& z, const std::complex<_Up>& w)
+    {
+      std::complex<_Tp> x = z;
+      x -= w;
+      return x;
+    }
+
+  template<typename _Tp, typename _Up>
+    constexpr std::complex<_Tp>
+    dif(const std::complex<_Tp>& z, _Up w)
+    {
+      std::complex<_Tp> x = z;
+      x -= w;
+      return x;
+    }
+
+  template<typename _Tp, typename _Up>
+    constexpr std::complex<_Tp>
+    prod(const std::complex<_Tp>& z, const std::complex<_Up>& w)
+    {
+      std::complex<_Tp> x = z;
+      x *= w;
+      return x;
+    }
+
+  template<typename _Tp, typename _Up>
+    constexpr std::complex<_Tp>
+    prod(const std::complex<_Tp>& z, _Up w)
+    {
+      std::complex<_Tp> x = z;
+      x *= w;
+      return x;
+    }
+
+  template<typename _Tp, typename _Up>
+    constexpr std::complex<_Tp>
+    quot(const std::complex<_Tp>& z, const std::complex<_Up>& w)
+    {
+      std::complex<_Tp> x = z;
+      x /= w;
+      return x;
+    }
+
+  template<typename _Tp, typename _Up>
+    constexpr std::complex<_Tp>
+    quot(const std::complex<_Tp>& z, _Up w)
+    {
+      std::complex<_Tp> x = z;
+      x /= w;
+      return x;
+    }
+
+  template<typename _Tp, typename _Up>
+    void
+    test_operator_members()
+    {
+      constexpr std::complex<_Tp> a{10, 20};
+      constexpr std::complex<_Up> b{6, 8};
+      constexpr _Up c{10};
+
+      constexpr auto apc = sum(a, c);
+      static_assert(apc == std::complex<_Tp>{20, 20});
+      constexpr auto amc = dif(a, c);
+      static_assert(amc == std::complex<_Tp>{0, 20});
+      constexpr auto atc = prod(a, c);
+      static_assert(atc == std::complex<_Tp>{100, 200});
+      constexpr auto adc = quot(a, c);
+      static_assert(adc == std::complex<_Tp>{1, 2});
+
+      constexpr auto apb = sum(a, b);
+      static_assert(apb == std::complex<_Tp>{16, 28});
+      constexpr auto amb = dif(a, b);
+      static_assert(amb == std::complex<_Tp>{4, 12});
+      constexpr auto atb = prod(a, b);
+      static_assert(atb == std::complex<_Tp>{-100, 200});
+      constexpr auto adb = quot(a, b);
+      static_assert(adb == std::complex<_Tp>{11/_Tp{5}, 2/_Tp{5}});
+    }
+}
+
+int main()
+{
+  __gnu_test::test_members<float>();
+  __gnu_test::test_members<double>();
+  __gnu_test::test_members<long double>();
+
+  __gnu_test::test_operator_members<float, float>();
+  __gnu_test::test_operator_members<float, double>();
+  __gnu_test::test_operator_members<float, long double>();
+  __gnu_test::test_operator_members<double, float>();
+  __gnu_test::test_operator_members<double, double>();
+  __gnu_test::test_operator_members<double, long double>();
+  __gnu_test::test_operator_members<long double, float>();
+  __gnu_test::test_operator_members<long double, double>();
+  __gnu_test::test_operator_members<long double, long double>();
+
+  // Test primary template.
+  __gnu_test::test_operator_members<__float128, __float128>();
+
+  return 0;
+}
Index: testsuite/26_numerics/complex/value_operations/constexpr_all_the_things.cc
===================================================================
--- testsuite/26_numerics/complex/value_operations/constexpr_all_the_things.cc	(nonexistent)
+++ testsuite/26_numerics/complex/value_operations/constexpr_all_the_things.cc	(working copy)
@@ -0,0 +1,60 @@ 
+// { dg-do compile { target c++2a } }
+
+// Copyright (C) 2018 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/>.
+
+#include <complex>
+#include <testsuite_common_types.h>
+
+namespace __gnu_test
+{
+  struct constexpr_functions
+  {
+    template<typename _Ttesttype>
+      void
+      operator()()
+      {
+	struct _Concept
+	{
+	  void __constraint()
+	  { 
+	    typedef typename _Ttesttype::_ComplexT _ComplexT;
+	    constexpr _ComplexT cc = { 1.1 };
+	    constexpr _Ttesttype a(cc);
+	    constexpr auto v1 [[maybe_unused]] = norm(a);
+	    constexpr auto v2 [[maybe_unused]] = conj(a);
+	    constexpr auto v3 [[maybe_unused]] = proj(a);
+	    constexpr auto v4 [[maybe_unused]] = arg(a);
+	  }
+	};
+
+	_Concept c;
+	c.__constraint();
+      }
+  };
+}
+
+int main()
+{
+  __gnu_test::constexpr_functions test;
+
+  test.operator()<std::complex<float>>();
+  test.operator()<std::complex<double>>();
+  test.operator()<std::complex<long double>>();
+
+  return 0;
+}