From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: by sourceware.org (Postfix, from userid 2181) id 6912E3858426; Sat, 5 Nov 2022 14:01:42 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 6912E3858426 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gcc.gnu.org; s=default; t=1667656902; bh=ZXg0eTXQFuOjUVxxNlCM2Ca3ye9wFzAZwjXKvX/w4iM=; h=From:To:Subject:Date:From; b=iAZJ4Z3ljbRou+mOJWVKkKuGjSrQmUbTe6z+LRuK7oHLZ3Z9iw0NtzA8PEB8P2p5R W6JO9ouJi8Wy1mrwdFTqLIdv3eATD6/ZzN8ErmY0QQEnRdckUbfBhHC4sBVvjaxbVS jL6iYYbYTJ2tI9FyJ829zg/HUxKVCF+NpJe6L1zs= MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Content-Type: text/plain; charset="utf-8" From: Jonathan Wakely To: gcc-cvs@gcc.gnu.org, libstdc++-cvs@gcc.gnu.org Subject: [gcc r13-3695] libstdc++: Do not use SFINAE for propagate_const conversions [PR107525] X-Act-Checkin: gcc X-Git-Author: Jonathan Wakely X-Git-Refname: refs/heads/master X-Git-Oldrev: e50ea3a42f058c14ee29327d5277ab0435e3d36b X-Git-Newrev: 7c6008e75df80607f8104e665e0448a0a9cbf85a Message-Id: <20221105140142.6912E3858426@sourceware.org> Date: Sat, 5 Nov 2022 14:01:42 +0000 (GMT) List-Id: https://gcc.gnu.org/g:7c6008e75df80607f8104e665e0448a0a9cbf85a commit r13-3695-g7c6008e75df80607f8104e665e0448a0a9cbf85a Author: Jonathan Wakely Date: Fri Nov 4 15:05:41 2022 +0000 libstdc++: Do not use SFINAE for propagate_const conversions [PR107525] As the PR notes, the current conversion operators are defined as function templates so that we can use SFINAE. But this changes how they are considered for overload resolution. This moves those operators into base classes that can be specialized so the operators are obsent unless the constraints are satisfied. libstdc++-v3/ChangeLog: PR libstdc++/107525 * include/experimental/propagate_const (operator element_type*()): Move into base class that can be partially specilized to iompose constraints. (operator const element_type*()): Likewise. * testsuite/experimental/propagate_const/observers/107525.cc: New test. Diff: --- libstdc++-v3/include/experimental/propagate_const | 88 ++++++++++++++++------ .../propagate_const/observers/107525.cc | 47 ++++++++++++ 2 files changed, 113 insertions(+), 22 deletions(-) diff --git a/libstdc++-v3/include/experimental/propagate_const b/libstdc++-v3/include/experimental/propagate_const index 258ef6fdd44..12b0f27462a 100644 --- a/libstdc++-v3/include/experimental/propagate_const +++ b/libstdc++-v3/include/experimental/propagate_const @@ -50,6 +50,48 @@ namespace experimental { inline namespace fundamentals_v2 { + template + using __propagate_const_elem_type + = remove_reference_t())>; + + template, + bool = is_convertible::value> + struct __propagate_const_conversion_c + { }; + + template + struct __propagate_const_conversion_c<_Tp, _Elem, true> + { + constexpr operator const _Elem*() const; + }; + + template, + bool = is_convertible<_Tp, _Elem*>::value> + struct __propagate_const_conversion_nc + { }; + + template + struct __propagate_const_conversion_nc<_Tp, _Elem, true> + { + constexpr operator _Elem*(); + }; + + // Base class of propagate_const when T is a class type. + template + struct __propagate_const_conversions + : __propagate_const_conversion_c<_Tp>, __propagate_const_conversion_nc<_Tp> + { }; + + // Base class of propagate_const when T is a pointer type. + template + struct __propagate_const_conversions<_Tp*> + { + constexpr operator const _Tp*() const noexcept; + constexpr operator _Tp*() noexcept; + }; + /** * @defgroup propagate_const Const-propagating wrapper * @ingroup libfund-ts @@ -63,10 +105,10 @@ inline namespace fundamentals_v2 /// Const-propagating wrapper. template - class propagate_const + class propagate_const : public __propagate_const_conversions<_Tp> { public: - typedef remove_reference_t())> element_type; + using element_type = __propagate_const_elem_type<_Tp>; private: template @@ -186,16 +228,6 @@ inline namespace fundamentals_v2 return get(); } - template , - is_convertible<_Up, - const element_type*> - >::value, bool>::type = true> - constexpr operator const element_type*() const - { - return get(); - } - constexpr const element_type& operator*() const { return *get(); @@ -212,16 +244,6 @@ inline namespace fundamentals_v2 return get(); } - template , - is_convertible<_Up, - const element_type*> - >::value, bool>::type = true> - constexpr operator element_type*() - { - return get(); - } - constexpr element_type& operator*() { return *get(); @@ -430,6 +452,28 @@ inline namespace fundamentals_v2 return __pt._M_t; } + template + constexpr + __propagate_const_conversions<_Tp*>::operator const _Tp*() const noexcept + { return static_cast*>(this)->get(); } + + template + constexpr + __propagate_const_conversions<_Tp*>::operator _Tp*() noexcept + { return static_cast*>(this)->get(); } + + template + constexpr + __propagate_const_conversion_c<_Tp, _Elem, true>:: + operator const _Elem*() const + { return static_cast*>(this)->get(); } + + template + constexpr + __propagate_const_conversion_nc<_Tp, _Elem, true>:: + operator _Elem*() + { return static_cast*>(this)->get(); } + /// @} group propagate_const } // namespace fundamentals_v2 } // namespace experimental diff --git a/libstdc++-v3/testsuite/experimental/propagate_const/observers/107525.cc b/libstdc++-v3/testsuite/experimental/propagate_const/observers/107525.cc new file mode 100644 index 00000000000..e7ecff73c1a --- /dev/null +++ b/libstdc++-v3/testsuite/experimental/propagate_const/observers/107525.cc @@ -0,0 +1,47 @@ +// { dg-do run { target c++14 } } + +#include +#include + +using std::experimental::propagate_const; + +void +test_base_conversion() +{ + struct Base { }; + struct Derived : Base { }; + + static_assert(std::is_convertible, Base*>::value, + "PR libstdc++/107525 - SFINAE breaks conversion operators"); + static_assert(std::is_convertible, const Base*>::value, + "PR libstdc++/107525 - SFINAE breaks conversion operators"); +} + +void +test_const_conversion() +{ + struct X + { + int* p = nullptr; + + int& operator*() const { return *p; } + int* operator->() const { return p; } + int* get() const { return p; } + + operator int*() { return p; } + operator const int*() const = delete; + }; + + static_assert(!std::is_convertible_v, + "Cannot convert const X to const int*"); + // So should not be able to convert const propagate_const to const int*. + static_assert(!std::is_convertible_v, const int*>, + "So should not be able to convert const propagate_const to " + "const int* (although this is not what LFTSv3 says)"); +} + +int main() +{ + test_base_conversion(); + test_const_conversion(); +}