From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) by sourceware.org (Postfix) with ESMTPS id 3BE6038582BE for ; Sat, 5 Nov 2022 14:02:23 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org 3BE6038582BE Authentication-Results: sourceware.org; dmarc=pass (p=none dis=none) header.from=redhat.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=redhat.com DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1667656943; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=TT5UHvl+zm5T3ky0zJqsLXMYx0jzmA8QCteGDZmXbEU=; b=SiPVgHEIXtBOT8ZELW1RQpqFR1u7y6H6zrctgNRkBX+qF8vfe08EHE0QGVIHGBgmrotsMg DvzxkDBjnse1nv69m8zqqDbiSP5HJn27k/dEkn9qLgFFWNHn4mBM5U1+bjJqTGBd6I82e6 ek3IyzJljWYaNakhJuAbWvcITjwyj80= Received: from mimecast-mx02.redhat.com (mimecast-mx02.redhat.com [66.187.233.88]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-456-9J65YmElP3mJ64uvV8HFig-1; Sat, 05 Nov 2022 10:02:19 -0400 X-MC-Unique: 9J65YmElP3mJ64uvV8HFig-1 Received: from smtp.corp.redhat.com (int-mx09.intmail.prod.int.rdu2.redhat.com [10.11.54.9]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id 3D8408027F5; Sat, 5 Nov 2022 14:02:14 +0000 (UTC) Received: from localhost (unknown [10.33.37.13]) by smtp.corp.redhat.com (Postfix) with ESMTP id 452A6477F5E; Sat, 5 Nov 2022 14:02:03 +0000 (UTC) From: Jonathan Wakely To: libstdc++@gcc.gnu.org, gcc-patches@gcc.gnu.org Subject: [committed] libstdc++: Do not use SFINAE for propagate_const conversions [PR107525] Date: Sat, 5 Nov 2022 14:01:55 +0000 Message-Id: <20221105140155.1206577-1-jwakely@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.1 on 10.11.54.9 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Content-Type: text/plain Content-Transfer-Encoding: 8bit X-Spam-Status: No, score=-12.3 required=5.0 tests=BAYES_00,DKIMWL_WL_HIGH,DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,GIT_PATCH_0,RCVD_IN_DNSWL_NONE,RCVD_IN_MSPIKE_H2,SPF_HELO_NONE,SPF_NONE,TXREP,URI_HEX autolearn=unavailable autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org List-Id: Tested x86_64-linux. Pushed to trunk. -- >8 -- 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. --- .../include/experimental/propagate_const | 88 ++++++++++++++----- .../propagate_const/observers/107525.cc | 47 ++++++++++ 2 files changed, 113 insertions(+), 22 deletions(-) create mode 100644 libstdc++-v3/testsuite/experimental/propagate_const/observers/107525.cc 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(); +} -- 2.38.1