From patchwork Wed Aug 21 08:59:50 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jonathan Wakely X-Patchwork-Id: 1974773 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=a1ekxlPn; dkim-atps=neutral Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=gcc.gnu.org (client-ip=2620:52:3:1:0:246e:9693:128c; helo=server2.sourceware.org; envelope-from=gcc-patches-bounces~incoming=patchwork.ozlabs.org@gcc.gnu.org; receiver=patchwork.ozlabs.org) Received: from server2.sourceware.org (server2.sourceware.org [IPv6:2620:52:3:1:0:246e:9693:128c]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (secp384r1) server-digest SHA384) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4WpgNb5VDjz1yf6 for ; Wed, 21 Aug 2024 19:03:27 +1000 (AEST) Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id DB986385EC34 for ; Wed, 21 Aug 2024 09:03:24 +0000 (GMT) X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) by sourceware.org (Postfix) with ESMTP id E223D3857349 for ; Wed, 21 Aug 2024 09:02:57 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org E223D3857349 Authentication-Results: sourceware.org; dmarc=pass (p=none dis=none) header.from=redhat.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=redhat.com ARC-Filter: OpenARC Filter v1.0.0 sourceware.org E223D3857349 Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=170.10.129.124 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1724230979; cv=none; b=pvSXw7Gsj5+zdf8m75kxxrkWSZb2o+DwrJWlbt5tOKVchmmYEImAMPRnpKLy6N1mFzZkuxLX0lndFcL8QShsFfsqx3KOLQJr/CRWcpwwn1W/zejhwx4Vx3FzKjrVeqsUVuWGftaeW0avwHwdCrD5SoK2SSOMo/zjpvJI8hRA1E0= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1724230979; c=relaxed/simple; bh=sY2R5ryDE6qa4x3LUmbn8hxfYS4Wp4o9NQ7w4Urfp7w=; h=DKIM-Signature:From:To:Subject:Date:Message-ID:MIME-Version; b=paV50rNZFwqcI+xfize+ONovLa3PeEUFYH7vdDn1H0DxjrbiWOvd1D8v6+OL7O2nnu2DJwzZunkReNiy3gUm+lwZ5lWntAesGIfmjHDPL2kSl7xf9JpmyfK9JbLzosoaVX86T+1MvbQYdmK3vywsxPasOQB34hpvMLa3eGjiolo= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1724230977; 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=xaH55r1TBKgMcpyY/Htbjgkld7giLTVABMUOTPa9/is=; b=a1ekxlPnFOJWDIMUp0orgbunMTk/tzxkR9cfjkRNBRG2COwLYWbD/AvkibLRcwI+Smexri b4wQYR3TLnLiBIVn5Qh5u2Th8Jq8phbHidbA281m7ZMlR5OGBdyusJVcW426mp8Q6a3vyN 0yurAQdaN2Y5KDJuwnxsDLo4peZPCic= Received: from mx-prod-mc-01.mail-002.prod.us-west-2.aws.redhat.com (ec2-54-186-198-63.us-west-2.compute.amazonaws.com [54.186.198.63]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-149-sHzqW5MKNn-J3NS33AlHwA-1; Wed, 21 Aug 2024 05:02:55 -0400 X-MC-Unique: sHzqW5MKNn-J3NS33AlHwA-1 Received: from mx-prod-int-05.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-05.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.17]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-01.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 5A6481955BF6; Wed, 21 Aug 2024 09:02:53 +0000 (UTC) Received: from localhost (unknown [10.42.28.148]) by mx-prod-int-05.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 3B6F719560A3; Wed, 21 Aug 2024 09:02:51 +0000 (UTC) From: Jonathan Wakely To: libstdc++@gcc.gnu.org, gcc-patches@gcc.gnu.org Subject: [PATCH] libstdc++: Simplify C++20 implementation of std::variant Date: Wed, 21 Aug 2024 09:59:50 +0100 Message-ID: <20240821090250.352625-1-jwakely@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.0 on 10.30.177.17 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com X-Spam-Status: No, score=-10.5 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_H3, RCVD_IN_MSPIKE_WL, RCVD_IN_SBL_CSS, SPF_HELO_NONE, SPF_NONE, TXREP, T_SCC_BODY_TEXT_LINE autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org X-BeenThere: gcc-patches@gcc.gnu.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: Gcc-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: gcc-patches-bounces~incoming=patchwork.ozlabs.org@gcc.gnu.org Tested x86_64-linux. This should improve compile times for C++20 and up. I need to test this with Clang, but then I plan to push it if all goes well. -- >8 -- For C++20 the __detail::__variant::_Uninitialized primary template can be used for all types, because _Variant_union can have a non-trivially destructible union member in C++20, and the constrained user-provided destructor will ensure we don't destroy inactive objects. Since we always use the primary template for C++20, we don't need the _Uninitialized::_M_get accessors to abstract the difference between the primary template and the partial specialization. That allows us to simplify __get_n for C++20 too. Also improve the comments that explain the uses of _Uninitialized and when/why _Variant_union needs a user-provided destructor. libstdc++-v3/ChangeLog: * include/std/variant [C++20] (_Uninitialized): Always use the primary template. [C++20] (__get_n): Access the _M_storage member directly. --- libstdc++-v3/include/std/variant | 83 ++++++++++++++------------------ 1 file changed, 37 insertions(+), 46 deletions(-) diff --git a/libstdc++-v3/include/std/variant b/libstdc++-v3/include/std/variant index 5fb7770d889..08c5395b54d 100644 --- a/libstdc++-v3/include/std/variant +++ b/libstdc++-v3/include/std/variant @@ -54,10 +54,9 @@ // C++ < 20 || __cpp_concepts < 202002L || __cpp_constexpr < 201811L #if __cpp_lib_variant < 202106L -# include // Use __aligned_membuf instead of union. +# include // Use __aligned_membuf for storage. #endif - namespace std _GLIBCXX_VISIBILITY(default) { _GLIBCXX_BEGIN_NAMESPACE_VERSION @@ -209,17 +208,18 @@ namespace __variant __as(const std::variant<_Types...>&& __v) noexcept { return std::move(__v); } - // For C++17: - // _Uninitialized is guaranteed to be a trivially destructible type, - // even if T is not. - // For C++20: - // _Uninitialized is trivially destructible iff T is, so _Variant_union - // needs a constrained non-trivial destructor. +#if __cpp_lib_variant < 202106L template> struct _Uninitialized; +#else + template + struct _Uninitialized; +#endif - template - struct _Uninitialized<_Type, true> + // The primary template is used for trivially destructible types in C++17, + // and for all types in C++20. + template + struct _Uninitialized { template constexpr @@ -227,6 +227,7 @@ namespace __variant : _M_storage(std::forward<_Args>(__args)...) { } +#if __cpp_lib_variant < 202106L constexpr const _Type& _M_get() const & noexcept { return _M_storage; } @@ -238,46 +239,18 @@ namespace __variant constexpr _Type&& _M_get() && noexcept { return std::move(_M_storage); } +#endif _Type _M_storage; }; +#if __cpp_lib_variant < 202106L + // This partial specialization is used for non-trivially destructible types + // in C++17, so that _Uninitialized is trivially destructible and can be + // used as a union member in _Variadic_union. template struct _Uninitialized<_Type, false> { -#if __cpp_lib_variant >= 202106L - template - constexpr - _Uninitialized(in_place_index_t<0>, _Args&&... __args) - : _M_storage(std::forward<_Args>(__args)...) - { } - - constexpr ~_Uninitialized() { } - - _Uninitialized(const _Uninitialized&) = default; - _Uninitialized(_Uninitialized&&) = default; - _Uninitialized& operator=(const _Uninitialized&) = default; - _Uninitialized& operator=(_Uninitialized&&) = default; - - constexpr const _Type& _M_get() const & noexcept - { return _M_storage; } - - constexpr _Type& _M_get() & noexcept - { return _M_storage; } - - constexpr const _Type&& _M_get() const && noexcept - { return std::move(_M_storage); } - - constexpr _Type&& _M_get() && noexcept - { return std::move(_M_storage); } - - struct _Empty_byte { }; - - union { - _Empty_byte _M_empty; - _Type _M_storage; - }; -#else template constexpr _Uninitialized(in_place_index_t<0>, _Args&&... __args) @@ -299,7 +272,6 @@ namespace __variant { return std::move(*_M_storage._M_ptr()); } __gnu_cxx::__aligned_membuf<_Type> _M_storage; -#endif }; template @@ -316,6 +288,22 @@ namespace __variant return __variant::__get_n<_Np - 3>( std::forward<_Union>(__u)._M_rest._M_rest._M_rest); } +#else + template + constexpr auto&& + __get_n(_Union&& __u) noexcept + { + if constexpr (_Np == 0) + return std::forward<_Union>(__u)._M_first._M_storage; + else if constexpr (_Np == 1) + return std::forward<_Union>(__u)._M_rest._M_first._M_storage; + else if constexpr (_Np == 2) + return std::forward<_Union>(__u)._M_rest._M_rest._M_first._M_storage; + else + return __variant::__get_n<_Np - 3>( + std::forward<_Union>(__u)._M_rest._M_rest._M_rest); + } +#endif // Returns the typed storage for __v. template @@ -428,6 +416,9 @@ namespace __variant ~_Variadic_union() = default; + // If any alternative type is not trivially destructible then we need a + // user-provided destructor that does nothing. The active alternative + // will be destroyed by _Variant_storage::_M_reset() instead of here. constexpr ~_Variadic_union() requires (!__trivially_destructible) { } @@ -486,7 +477,7 @@ namespace __variant constexpr _Variant_storage(in_place_index_t<_Np>, _Args&&... __args) : _M_u(in_place_index<_Np>, std::forward<_Args>(__args)...), - _M_index{_Np} + _M_index{_Np} { } constexpr void @@ -532,7 +523,7 @@ namespace __variant constexpr _Variant_storage(in_place_index_t<_Np>, _Args&&... __args) : _M_u(in_place_index<_Np>, std::forward<_Args>(__args)...), - _M_index{_Np} + _M_index{_Np} { } constexpr void