[v3 PATCH] Implement P0307R2, Making Optional Greater Equal Again.

2016-07-11 Thread Ville Voutilainen
Tested on Linux-X64.

The test adjustments are so that the tests are kept valid, which
required adding a bunch of now-required relops to the test types. The new
transparent-but-non-synthesizing aspects of the relops are tested
separately. The constraints are a valid implementation of the
current Requires-clauses on these operators; I will file an LWG
issue suggesting that such Requires-clauses are instead made
SFINAE-constraints like in this implementation. The rationale
for that being that if such "wrapper types" are supposed to be
"transparent", it would be rather good if they are transparent
for SFINAE-querying for the existence of such relops as well, rather
than always report true and then fail to instantiate.

2016-07-11  Ville Voutilainen  

Implement P0307R2, Making Optional Greater Equal Again.
* include/std/optional (__optional_relop_t): New.
(operator==(const optional<_Tp>&, const optional<_Tp>&)): Constrain.
(operator!=(const optional<_Tp>&, const optional<_Tp>&)):
Constrain and make transparent.
(operator<(const optional<_Tp>&, const optional<_Tp>&)): Constrain.
(operator>(const optional<_Tp>&, const optional<_Tp>&)):
Constrain and make transparent.
(operator<=(const optional<_Tp>&, const optional<_Tp>&)): Likewise.
(operator>=(const optional<_Tp>&, const optional<_Tp>&)): Likewise.
(operator==(const optional<_Tp>&, const _Tp&): Constrain.
(operator==(const _Tp&, const optional<_Tp>&)): Likewise.
(operator!=(const optional<_Tp>&, _Tp const&)):
Constrain and make transparent.
(operator!=(const _Tp&, const optional<_Tp>&)): Likewise.
(operator<(const optional<_Tp>&, const _Tp&)): Constrain.
(operator<(const _Tp&, const optional<_Tp>&)): Likewise.
(operator>(const optional<_Tp>&, const _Tp&)):
Constrain and make transparent.
(operator>(const _Tp&, const optional<_Tp>&)): Likewise.
(operator<=(const optional<_Tp>&, const _Tp&)): Likewise.
(operator<=(const _Tp&, const optional<_Tp>&)): Likewise.
(operator>=(const optional<_Tp>&, const _Tp&)): Likewise.
(operator>=(const _Tp&, const optional<_Tp>&)): Likewise.
* testsuite/20_util/optional/constexpr/relops/2.cc: Adjust.
* testsuite/20_util/optional/constexpr/relops/4.cc: Likewise.
* testsuite/20_util/optional/relops/1.cc: Likewise.
* testsuite/20_util/optional/relops/2.cc: Likewise.
* testsuite/20_util/optional/relops/3.cc: Likewise.
* testsuite/20_util/optional/relops/4.cc: Likewise.
* testsuite/20_util/optional/requirements.cc: Add tests to verify
that optional's relops are transparent and don't synthesize
operators.
diff --git a/libstdc++-v3/include/std/optional 
b/libstdc++-v3/include/std/optional
index e9a86a4..1786c2c 100644
--- a/libstdc++-v3/include/std/optional
+++ b/libstdc++-v3/include/std/optional
@@ -785,41 +785,60 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
}
 };
 
+  template
+using __optional_relop_t =
+enable_if_t::value, bool>;
+
   // [X.Y.8] Comparisons between optional values.
   template
-constexpr bool
+constexpr auto
 operator==(const optional<_Tp>& __lhs, const optional<_Tp>& __rhs)
+-> __optional_relop_t() == declval<_Tp>())>
 {
   return static_cast(__lhs) == static_cast(__rhs)
 && (!__lhs || *__lhs == *__rhs);
 }
 
   template
-constexpr bool
+constexpr auto
 operator!=(const optional<_Tp>& __lhs, const optional<_Tp>& __rhs)
-{ return !(__lhs == __rhs); }
+-> __optional_relop_t() != declval<_Tp>())>
+{
+  return static_cast(__lhs) != static_cast(__rhs)
+   || (static_cast(__lhs) && *__lhs != *__rhs);
+}
 
   template
-constexpr bool
+constexpr auto
 operator<(const optional<_Tp>& __lhs, const optional<_Tp>& __rhs)
+-> __optional_relop_t() < declval<_Tp>())>
 {
   return static_cast(__rhs) && (!__lhs || *__lhs < *__rhs);
 }
 
   template
-constexpr bool
+constexpr auto
 operator>(const optional<_Tp>& __lhs, const optional<_Tp>& __rhs)
-{ return __rhs < __lhs; }
+-> __optional_relop_t() > declval<_Tp>())>
+{
+  return static_cast(__lhs) && (!__rhs || *__lhs > *__rhs);
+}
 
   template
-constexpr bool
+constexpr auto
 operator<=(const optional<_Tp>& __lhs, const optional<_Tp>& __rhs)
-{ return !(__rhs < __lhs); }
+-> __optional_relop_t() <= declval<_Tp>())>
+{
+  return !__lhs || (static_cast(__rhs) && *__lhs <= *__rhs);
+}
 
   template
-constexpr bool
+constexpr auto
 operator>=(const optional<_Tp>& __lhs, const optional<_Tp>& __rhs)
-{ return !(__lhs < __rhs); }
+-> __optional_relop_t() >= declval<_Tp>())>
+{
+  return !__rhs || (static_cast(__lhs) && *__lhs >= *__rhs);
+}
 
   // [X.Y.9] Comparisons with nullopt.
   template
@@ -884,64 +903,76 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
   // [X.Y.10] Comparisons with value type.
   template
-constexpr bool
+constexpr auto
 ope

Re: [v3 PATCH] Implement P0307R2, Making Optional Greater Equal Again.

2016-07-12 Thread Jonathan Wakely

On 11/07/16 23:41 +0300, Ville Voutilainen wrote:

@@ -785,41 +785,60 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
}
};

+  template
+using __optional_relop_t =
+enable_if_t::value, bool>;


Should this be is_convertible<_Tp, bool> instead?


  template
-constexpr bool
+constexpr auto
operator!=(const optional<_Tp>& __lhs, _Tp const& __rhs)


Dunno why this has _Tp const& rather than const _Tp&, could you fix it
while you're in the file anyway? It's a bit confusing to have one
place using a different style.



Re: [v3 PATCH] Implement P0307R2, Making Optional Greater Equal Again.

2016-07-13 Thread Ville Voutilainen
On 13 July 2016 at 01:31, Jonathan Wakely  wrote:
> On 11/07/16 23:41 +0300, Ville Voutilainen wrote:
>>
>> @@ -785,41 +785,60 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>> }
>> };
>>
>> +  template
>> +using __optional_relop_t =
>> +enable_if_t::value, bool>;
>
>
> Should this be is_convertible<_Tp, bool> instead?

Yeah.. it would be more reasonable to return a type explicitly
convertible to bool from a relop
if a non-bool is returned, but since built-in operators are not
contextually-convertible-to-bool,
that "protection" wouldn't buy much. And since the implementation
doesn't really do bool-wrappings
everywhere, let's go with is_convertible and change that if someone complains.

>
>>   template
>> -constexpr bool
>> +constexpr auto
>> operator!=(const optional<_Tp>& __lhs, _Tp const& __rhs)
>
>
> Dunno why this has _Tp const& rather than const _Tp&, could you fix it
> while you're in the file anyway? It's a bit confusing to have one
> place using a different style.

Ha, that was indeed in just one place.

I made the above changes and also made converting assignment operators
SFINAE. That SFINAE
seems consistent with how constructors and relops work. And yes, there
are still some members like
emplace that static_assert rather than SFINAE, but I think that's ok for now.

2016-07-13  Ville Voutilainen  

Implement P0307R2, Making Optional Greater Equal Again.
* include/std/optional (operator=(_Up&&)): Constrain.
(operator=(const optional<_Up>&)): Likewise.
(operator=(optional<_Up>&&)): Likewise.
(__optional_relop_t): New.
(operator==(const optional<_Tp>&, const optional<_Tp>&)): Constrain.
(operator!=(const optional<_Tp>&, const optional<_Tp>&)):
Constrain and make transparent.
(operator<(const optional<_Tp>&, const optional<_Tp>&)): Constrain.
(operator>(const optional<_Tp>&, const optional<_Tp>&)):
Constrain and make transparent.
(operator<=(const optional<_Tp>&, const optional<_Tp>&)): Likewise.
(operator>=(const optional<_Tp>&, const optional<_Tp>&)): Likewise.
(operator==(const optional<_Tp>&, const _Tp&): Constrain.
(operator==(const _Tp&, const optional<_Tp>&)): Likewise.
(operator!=(const optional<_Tp>&, _Tp const&)):
Constrain and make transparent.
(operator!=(const _Tp&, const optional<_Tp>&)): Likewise.
(operator<(const optional<_Tp>&, const _Tp&)): Constrain.
(operator<(const _Tp&, const optional<_Tp>&)): Likewise.
(operator>(const optional<_Tp>&, const _Tp&)):
Constrain and make transparent.
(operator>(const _Tp&, const optional<_Tp>&)): Likewise.
(operator<=(const optional<_Tp>&, const _Tp&)): Likewise.
(operator<=(const _Tp&, const optional<_Tp>&)): Likewise.
(operator>=(const optional<_Tp>&, const _Tp&)): Likewise.
(operator>=(const _Tp&, const optional<_Tp>&)): Likewise.
* testsuite/20_util/optional/constexpr/relops/2.cc: Adjust.
* testsuite/20_util/optional/constexpr/relops/4.cc: Likewise.
* testsuite/20_util/optional/relops/1.cc: Likewise.
* testsuite/20_util/optional/relops/2.cc: Likewise.
* testsuite/20_util/optional/relops/3.cc: Likewise.
* testsuite/20_util/optional/relops/4.cc: Likewise.
* testsuite/20_util/optional/requirements.cc: Add tests to verify
that optional's relops are transparent and don't synthesize
operators. Also test that assignment sfinaes.
diff --git a/libstdc++-v3/include/std/optional 
b/libstdc++-v3/include/std/optional
index e9a86a4..45929c7 100644
--- a/libstdc++-v3/include/std/optional
+++ b/libstdc++-v3/include/std/optional
@@ -132,7 +132,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 *
 * Practically speaking this detects the presence of such an operator when
 * called on a const-qualified lvalue (i.e.
-* declval<_Tp * const&>().operator&()).
+* declval().operator&()).
 */
   template
 struct _Has_addressof
@@ -577,16 +577,14 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
   template,
+  is_assignable<_Tp&, _Up>,
   __not_>,
   __not_<__is_optional<_Up>>>::value,
 bool> = true>
 optional&
 operator=(_Up&& __u)
 {
-  static_assert(__and_,
-  is_assignable<_Tp&, _Up>>(),
-"Cannot assign to value type from argument");
-
   if (this->_M_is_engaged())
 this->_M_get() = std::forward<_Up>(__u);
   else
@@ -597,15 +595,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
   template>>::value,
-  bool> = true>
+  is_constructible<_Tp, _Up>,
+  is_assignable<_Tp&, _Up>,
+  __not_>>::value,
+bool> = true>
 optional&
 operator=(const optional<_Up>& __u)
 {
-  static_assert(__and_,
-  is_assignable<_Tp&, _Up>>(),
-

Re: [v3 PATCH] Implement P0307R2, Making Optional Greater Equal Again.

2016-07-13 Thread Ville Voutilainen
On 13 July 2016 at 13:05, Ville Voutilainen  wrote:
>> Dunno why this has _Tp const& rather than const _Tp&, could you fix it
>> while you're in the file anyway? It's a bit confusing to have one
>> place using a different style.
>
> Ha, that was indeed in just one place.


Well, technically two, the other was in a comment. The patch changes that, too.


Re: [v3 PATCH] Implement P0307R2, Making Optional Greater Equal Again.

2016-07-13 Thread Jonathan Wakely

On 13/07/16 13:05 +0300, Ville Voutilainen wrote:

Ha, that was indeed in just one place.


See below.


I made the above changes and also made converting assignment operators
SFINAE. That SFINAE
seems consistent with how constructors and relops work. And yes, there
are still some members like
emplace that static_assert rather than SFINAE, but I think that's ok for now.
   operators. Also test that assignment sfinaes.


OK.


diff --git a/libstdc++-v3/include/std/optional 
b/libstdc++-v3/include/std/optional
index e9a86a4..45929c7 100644
--- a/libstdc++-v3/include/std/optional
+++ b/libstdc++-v3/include/std/optional
@@ -132,7 +132,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
*
* Practically speaking this detects the presence of such an operator when
* called on a const-qualified lvalue (i.e.
-* declval<_Tp * const&>().operator&()).
+* declval().operator&()).
*/
  template
struct _Has_addressof


That comment was wrong anyway, it says _Tp* const& when it should have
been _Tp const&.

declval<_Tp * const&>().operator&() doesn't make any sense. Not sure
why I've never spotted that until now.

Please change it to const _Tp& and change "i.e." to "e.g." (because
since my change last year it detects both members and non-members).

OK for trunk with that tweak, thanks.

I'll make the same change to the comment in .



Re: [v3 PATCH] Implement P0307R2, Making Optional Greater Equal Again.

2016-07-13 Thread Daniel Krügler
2016-07-13 12:05 GMT+02:00 Ville Voutilainen :
> On 13 July 2016 at 01:31, Jonathan Wakely  wrote:
>> On 11/07/16 23:41 +0300, Ville Voutilainen wrote:
>>>
>>> @@ -785,41 +785,60 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>>> }
>>> };
>>>
>>> +  template
>>> +using __optional_relop_t =
>>> +enable_if_t::value, bool>;
>>
>>
>> Should this be is_convertible<_Tp, bool> instead?
>
> Yeah.. it would be more reasonable to return a type explicitly
> convertible to bool from a relop
> if a non-bool is returned, but since built-in operators are not
> contextually-convertible-to-bool,
> that "protection" wouldn't buy much. And since the implementation
> doesn't really do bool-wrappings
> everywhere, let's go with is_convertible and change that if someone complains.

How would you feel about the introduction of an internal trait
__is_boolean_testable, that would test both is_convertible and is_constructible for now, so that we could
reuse that at places like these and others pointed out by LWG 2114?

If you like that idea, I would work on a contribution.

Thanks,

- Daniel


Re: [v3 PATCH] Implement P0307R2, Making Optional Greater Equal Again.

2016-07-13 Thread Ville Voutilainen
On 13 July 2016 at 21:25, Daniel Krügler  wrote:
> How would you feel about the introduction of an internal trait
> __is_boolean_testable, that would test both is_convertible bool> and is_constructible for now, so that we could
> reuse that at places like these and others pointed out by LWG 2114?
>
> If you like that idea, I would work on a contribution.


Sounds like an excellent idea to me.


Re: [v3 PATCH] Implement P0307R2, Making Optional Greater Equal Again.

2016-07-16 Thread Daniel Krügler
2016-07-13 20:32 GMT+02:00 Ville Voutilainen :
> On 13 July 2016 at 21:25, Daniel Krügler  wrote:
>> How would you feel about the introduction of an internal trait
>> __is_boolean_testable, that would test both is_convertible> bool> and is_constructible for now, so that we could
>> reuse that at places like these and others pointed out by LWG 2114?
>>
>> If you like that idea, I would work on a contribution.
>
> Sounds like an excellent idea to me.

I have opened an enhancement request and have now a (actually two)
proposal(s) for this. I would appreciate if you could express your
opinion here:

https://gcc.gnu.org/bugzilla/show_bug.cgi?id=71899#c1

Thanks,

- Daniel