From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: by sourceware.org (Postfix, from userid 1059) id B37073948450; Fri, 28 Aug 2020 16:01:28 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org B37073948450 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gcc.gnu.org; s=default; t=1598630488; bh=8KoNrQqjyhxNVomPcczFkTB2dhzzrrqDSoTibvF2+yE=; h=From:To:Subject:Date:From; b=oxrbSpEIF2beiJYciOasgPN9B+gEB/Juq838uuRimcELXlOTz1UCNFs9FwgsIFEne G4GS3nPrG0BMcp39LqD6F3SHnWkeqjhv3iHhXQqkUjjJTW66xouATIzNTJqvJX3TkU Q7MxHLyH5y7vlScKkNTducwzHakM+m4BqX/4bhLA= Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit From: Nathan Sidwell To: gcc-cvs@gcc.gnu.org, libstdc++-cvs@gcc.gnu.org Subject: [gcc/devel/c++-modules] libstdc++: Fix iota_view::size() to avoid overflow X-Act-Checkin: gcc X-Git-Author: Jonathan Wakely X-Git-Refname: refs/heads/devel/c++-modules X-Git-Oldrev: 074436cf8cdd2a9ce75cadd36deb8301f00e55b9 X-Git-Newrev: a0e6f05d26d286f5a73007e425b109f0d327e15f Message-Id: <20200828160128.B37073948450@sourceware.org> Date: Fri, 28 Aug 2020 16:01:28 +0000 (GMT) X-BeenThere: gcc-cvs@gcc.gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gcc-cvs mailing list List-Unsubscribe: , List-Archive: List-Help: List-Subscribe: , X-List-Received-Date: Fri, 28 Aug 2020 16:01:28 -0000 https://gcc.gnu.org/g:a0e6f05d26d286f5a73007e425b109f0d327e15f commit a0e6f05d26d286f5a73007e425b109f0d327e15f Author: Jonathan Wakely Date: Mon Aug 24 16:17:04 2020 +0100 libstdc++: Fix iota_view::size() to avoid overflow This avoids the overflow that occurs when negating the most negative value of an integral type. Also prevent returning signed int when the values have lower rank and promote to int. libstdc++-v3/ChangeLog: * include/std/ranges (ranges::iota_view::size()): Perform all calculations in the right unsigned types. * testsuite/std/ranges/iota/size.cc: New test. Diff: --- libstdc++-v3/include/std/ranges | 13 +-- libstdc++-v3/testsuite/std/ranges/iota/size.cc | 110 +++++++++++++++++++++++++ 2 files changed, 117 insertions(+), 6 deletions(-) diff --git a/libstdc++-v3/include/std/ranges b/libstdc++-v3/include/std/ranges index b8023e67c9f..22184006c08 100644 --- a/libstdc++-v3/include/std/ranges +++ b/libstdc++-v3/include/std/ranges @@ -889,12 +889,13 @@ namespace ranges { using __detail::__is_integer_like; using __detail::__to_unsigned_like; - if constexpr (__is_integer_like<_Winc> && __is_integer_like<_Bound>) - return (_M_value < 0) - ? ((_M_bound < 0) - ? __to_unsigned_like(-_M_value) - __to_unsigned_like(-_M_bound) - : __to_unsigned_like(_M_bound) + __to_unsigned_like(-_M_value)) - : __to_unsigned_like(_M_bound) - __to_unsigned_like(_M_value); + if constexpr (integral<_Winc> && integral<_Bound>) + { + using _Up = make_unsigned_t; + return _Up(_M_bound) - _Up(_M_value); + } + else if constexpr (__is_integer_like<_Winc>) + return __to_unsigned_like(_M_bound) - __to_unsigned_like(_M_value); else return __to_unsigned_like(_M_bound - _M_value); } diff --git a/libstdc++-v3/testsuite/std/ranges/iota/size.cc b/libstdc++-v3/testsuite/std/ranges/iota/size.cc new file mode 100644 index 00000000000..2a9d3870c5d --- /dev/null +++ b/libstdc++-v3/testsuite/std/ranges/iota/size.cc @@ -0,0 +1,110 @@ +// Copyright (C) 2020 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// . + +// { dg-options "-std=c++2a" } +// { dg-do compile { target c++2a } } + +#include +#include + +template +constexpr bool +equal(T t, U u) requires std::same_as +{ + return t == u; +} + +template> +void +test_integer_iota() +{ + using std::numeric_limits; + + using V = std::ranges::iota_view; + static_assert( std::ranges::sized_range ); + + constexpr V zero(0, 0); + static_assert( equal(zero.size(), (S)0) ); + + constexpr V min(numeric_limits::min(), + numeric_limits::min()); + static_assert( equal(min.size(), (S)0) ); + + constexpr V max(numeric_limits::max(), + numeric_limits::max()); + static_assert( equal(max.size(), (S)0) ); + + constexpr V minmax(numeric_limits::min(), + numeric_limits::max()); + if constexpr (sizeof(W) < sizeof(S)) + { + using S2 = std::make_unsigned_t; + static_assert( equal(minmax.size(), (S)numeric_limits::max()) ); + } + else + static_assert( equal(minmax.size(), numeric_limits::max()) ); + + constexpr V pospos(20, 22); + static_assert( equal(pospos.size(), (S)2) ); + + if constexpr (std::numeric_limits::is_signed) + { + constexpr V negneg(-20, -2); + static_assert( equal(negneg.size(), (S)18) ); + + constexpr V negpos(-20, 22); + static_assert( equal(negpos.size(), (S)42) ); + } +} + +void +test01() +{ + test_integer_iota(); + test_integer_iota(); + test_integer_iota(); + test_integer_iota(); + test_integer_iota(); + test_integer_iota(); + test_integer_iota(); + test_integer_iota(); + test_integer_iota(); + test_integer_iota(); + +#ifdef __SIZEOF_INT128__ + // When the target supports __int128 it can be used in iota_view + // even in strict mode where !integral<__int128>. + // Specify the size type explicitly, because make_unsigned_t<__int128> + // is undefined when !integral<__int128>. + test_integer_iota<__int128, unsigned __int128>(); + test_integer_iota(); +#endif +} + +constexpr int arr[3] = { 1, 2, 3 }; + +void +test02() +{ + constexpr auto v = std::views::iota(std::begin(arr), std::end(arr)); + static_assert( equal(v.size(), std::make_unsigned_t(3)) ); + + constexpr auto vv = std::views::iota(v.begin(), v.end()); + constexpr auto vvsz = vv.size(); + static_assert( ! std::numeric_limits::is_signed ); + static_assert( vvsz == 3 ); +}