From patchwork Fri Oct 1 19:40:38 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jonathan Wakely X-Patchwork-Id: 1535501 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: bilbo.ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=gcc.gnu.org header.i=@gcc.gnu.org header.a=rsa-sha256 header.s=default header.b=Z8Juogf/; dkim-atps=neutral Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=gcc.gnu.org (client-ip=8.43.85.97; helo=sourceware.org; envelope-from=gcc-patches-bounces+incoming=patchwork.ozlabs.org@gcc.gnu.org; receiver=) Received: from sourceware.org (server2.sourceware.org [8.43.85.97]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by bilbo.ozlabs.org (Postfix) with ESMTPS id 4HLghm3J8Mz9t14 for ; Sat, 2 Oct 2021 05:51:04 +1000 (AEST) Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 8B75A3857403 for ; Fri, 1 Oct 2021 19:51:01 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 8B75A3857403 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gcc.gnu.org; s=default; t=1633117861; bh=L+B4hxe+66S71/aM3g7y2jBsa2rPauy7Fo9bhPo7wDw=; h=Date:To:Subject:List-Id:List-Unsubscribe:List-Archive:List-Post: List-Help:List-Subscribe:From:Reply-To:From; b=Z8Juogf/XTRIysuXcNm3niHG586UIdKdBiIm16+clyVOX0MloqbxY+T32yimlcTEH UBTARXKhPUFmj0di5OTU6dF8x287CUp3uyj/U3idc50EQm5rOAPBL0PjWveltXWITZ 0FAe25Tiv04hV91Pgmjf74DSYTRMNUmQlVrw0obo= 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 [216.205.24.124]) by sourceware.org (Postfix) with ESMTP id B75FE3857810 for ; Fri, 1 Oct 2021 19:40:42 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org B75FE3857810 Received: from mimecast-mx01.redhat.com (mimecast-mx01.redhat.com [209.132.183.4]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-299-Um4LJ5qbNpmbzps2ej4Xhw-1; Fri, 01 Oct 2021 15:40:41 -0400 X-MC-Unique: Um4LJ5qbNpmbzps2ej4Xhw-1 Received: from smtp.corp.redhat.com (int-mx05.intmail.prod.int.phx2.redhat.com [10.5.11.15]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx01.redhat.com (Postfix) with ESMTPS id 1647ECC622; Fri, 1 Oct 2021 19:40:40 +0000 (UTC) Received: from localhost (unknown [10.33.36.47]) by smtp.corp.redhat.com (Postfix) with ESMTP id B89645D6B1; Fri, 1 Oct 2021 19:40:39 +0000 (UTC) Date: Fri, 1 Oct 2021 20:40:38 +0100 To: libstdc++@gcc.gnu.org, gcc-patches@gcc.gnu.org Subject: [committed] libstdc++: Use conditional noexcept in std::reverse_iterator [PR 94418] Message-ID: MIME-Version: 1.0 X-Clacks-Overhead: GNU Terry Pratchett X-Scanned-By: MIMEDefang 2.79 on 10.5.11.15 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Content-Disposition: inline X-Spam-Status: No, score=-13.8 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_LOW, RCVD_IN_MSPIKE_H2, SPF_HELO_NONE, SPF_NONE, TXREP autolearn=ham autolearn_force=no version=3.4.4 X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) on server2.sourceware.org X-BeenThere: gcc-patches@gcc.gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gcc-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-Patchwork-Original-From: Jonathan Wakely via Gcc-patches From: Jonathan Wakely Reply-To: Jonathan Wakely Errors-To: gcc-patches-bounces+incoming=patchwork.ozlabs.org@gcc.gnu.org Sender: "Gcc-patches" This adds a noexcept-specifier to each constructor and assignment operator of std::reverse_iterator so that they are noexcept when the corresponding operation on the underlying iterator is noexcept. The std::reverse_iterator class template already requires that the operations on the underlying type are valid, so we don't need to use the std::is_nothrow_xxx traits to protect against errors when the expression isn't even valid. We can just use a noexcept operator to test if the expression can throw, without the overhead of redundantly checking if the initialization/assignment would be valid. Signed-off-by: Jonathan Wakely libstdc++-v3/ChangeLog: PR libstdc++/94418 * include/bits/stl_iterator.h (reverse_iterator): Use conditional noexcept on constructors and assignment operators. * testsuite/24_iterators/reverse_iterator/noexcept.cc: New test. Tested powerpc64le-linux. Committed to trunk. commit d335d73889d897d073b987b4323db05317fccad3 Author: Jonathan Wakely Date: Wed Apr 28 11:40:47 2021 libstdc++: Use conditional noexcept in std::reverse_iterator [PR 94418] This adds a noexcept-specifier to each constructor and assignment operator of std::reverse_iterator so that they are noexcept when the corresponding operation on the underlying iterator is noexcept. The std::reverse_iterator class template already requires that the operations on the underlying type are valid, so we don't need to use the std::is_nothrow_xxx traits to protect against errors when the expression isn't even valid. We can just use a noexcept operator to test if the expression can throw, without the overhead of redundantly checking if the initialization/assignment would be valid. Signed-off-by: Jonathan Wakely libstdc++-v3/ChangeLog: PR libstdc++/94418 * include/bits/stl_iterator.h (reverse_iterator): Use conditional noexcept on constructors and assignment operators. * testsuite/24_iterators/reverse_iterator/noexcept.cc: New test. diff --git a/libstdc++-v3/include/bits/stl_iterator.h b/libstdc++-v3/include/bits/stl_iterator.h index 004d767224d..4973f792b56 100644 --- a/libstdc++-v3/include/bits/stl_iterator.h +++ b/libstdc++-v3/include/bits/stl_iterator.h @@ -174,20 +174,28 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION // 235 No specification of default ctor for reverse_iterator // 1012. reverse_iterator default ctor should value initialize _GLIBCXX17_CONSTEXPR - reverse_iterator() : current() { } + reverse_iterator() + _GLIBCXX_NOEXCEPT_IF(noexcept(_Iterator())) + : current() + { } /** * This %iterator will move in the opposite direction that @p x does. */ explicit _GLIBCXX17_CONSTEXPR - reverse_iterator(iterator_type __x) : current(__x) { } + reverse_iterator(iterator_type __x) + _GLIBCXX_NOEXCEPT_IF(noexcept(_Iterator(__x))) + : current(__x) + { } /** * The copy constructor is normal. */ _GLIBCXX17_CONSTEXPR reverse_iterator(const reverse_iterator& __x) - : current(__x.current) { } + _GLIBCXX_NOEXCEPT_IF(noexcept(_Iterator(__x.current))) + : current(__x.current) + { } #if __cplusplus >= 201103L reverse_iterator& operator=(const reverse_iterator&) = default; @@ -203,7 +211,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION #endif _GLIBCXX17_CONSTEXPR reverse_iterator(const reverse_iterator<_Iter>& __x) - : current(__x.current) { } + _GLIBCXX_NOEXCEPT_IF(noexcept(_Iterator(__x.current))) + : current(__x.current) + { } #if __cplusplus >= 201103L template @@ -214,6 +224,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION _GLIBCXX17_CONSTEXPR reverse_iterator& operator=(const reverse_iterator<_Iter>& __x) + _GLIBCXX_NOEXCEPT_IF(noexcept(current = __x.current)) { current = __x.current; return *this; @@ -226,6 +237,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION _GLIBCXX_NODISCARD _GLIBCXX17_CONSTEXPR iterator_type base() const + _GLIBCXX_NOEXCEPT_IF(noexcept(_Iterator(current))) { return current; } /** diff --git a/libstdc++-v3/testsuite/24_iterators/reverse_iterator/noexcept.cc b/libstdc++-v3/testsuite/24_iterators/reverse_iterator/noexcept.cc new file mode 100644 index 00000000000..df4b1b0763d --- /dev/null +++ b/libstdc++-v3/testsuite/24_iterators/reverse_iterator/noexcept.cc @@ -0,0 +1,92 @@ +// { dg-do compile { target c++11 } } + +#include + +template +struct bidi +{ + using value_type = T; + using pointer = T*; + using reference = T&; + using difference_type = std::ptrdiff_t; + using iterator_category = std::bidirectional_iterator_tag; + + T* ptr; + + bidi(T* ptr = nullptr) noexcept(Nothrow) : ptr(ptr) { } + + bidi(const bidi& iter) noexcept(Nothrow) : ptr(iter.ptr) { } + + template + bidi(const bidi& iter) noexcept(Nothrow) : ptr(iter.ptr) { } + + bidi& operator=(const bidi& iter) noexcept(Nothrow) + { + ptr = iter.ptr; + return *this; + } + + template + bidi& operator=(const bidi& iter) noexcept(Nothrow) + { + ptr = iter.ptr; + return *this; + } + + bidi& operator++() { ++ptr; return *this; } + bidi& operator--() { --ptr; return *this; } + bidi operator++(int) { bidi tmp = *this; ++ptr; return tmp; } + bidi operator--(int) { bidi tmp = *this; --ptr; return tmp; } + + reference operator*() const { return *ptr; } + pointer operator->() const { return ptr; } +}; + +void +test01() +{ + using B1 = bidi; + using R1 = std::reverse_iterator; + static_assert( std::is_nothrow_default_constructible(), "" ); + static_assert( std::is_nothrow_copy_constructible(), "" ); + static_assert( std::is_nothrow_move_constructible(), "" ); + static_assert( std::is_nothrow_copy_assignable(), "" ); + static_assert( std::is_nothrow_move_assignable(), "" ); + static_assert( std::is_nothrow_constructible(), "" ); + static_assert( std::is_nothrow_constructible(), "" ); + + using B2 = bidi; + using R2 = std::reverse_iterator; + // Test conversions from reverse_iterator to reverse_iterator. + static_assert( std::is_nothrow_constructible(), "" ); + static_assert( std::is_nothrow_assignable(), "" ); + // And from B1 to reverse_iterator. + static_assert( std::is_nothrow_constructible(), "" ); + static_assert( std::is_nothrow_constructible(), "" ); + static_assert( std::is_nothrow_constructible(), "" ); + static_assert( std::is_nothrow_constructible(), "" ); + + using B3 = bidi; + using R3 = std::reverse_iterator; + static_assert( ! std::is_nothrow_default_constructible(), "" ); + static_assert( ! std::is_nothrow_copy_constructible(), "" ); + static_assert( ! std::is_nothrow_move_constructible(), "" ); + static_assert( ! std::is_nothrow_copy_assignable(), "" ); + static_assert( ! std::is_nothrow_move_assignable(), "" ); + static_assert( ! std::is_nothrow_constructible(), "" ); + static_assert( ! std::is_nothrow_constructible(), "" ); + + using B4 = bidi; + using R4 = std::reverse_iterator; + // Test conversions from reverse_iterator to reverse_iterator. + static_assert( ! std::is_nothrow_constructible(), "" ); + static_assert( ! std::is_nothrow_assignable(), "" ); + // And from B3 to reverse_iterator. + static_assert( ! std::is_nothrow_constructible(), "" ); + static_assert( ! std::is_nothrow_constructible(), "" ); + static_assert( ! std::is_nothrow_constructible(), "" ); + static_assert( ! std::is_nothrow_constructible(), "" ); + + static_assert( noexcept(std::declval().base()), "" ); + static_assert( ! noexcept(std::declval().base()), "" ); +}