Re: [PATCH, libstdc++/61166] overflow when parse number in std::duration operator
On 15/05/14 22:54 -0400, Ed Smith-Rowland wrote: On 05/15/2014 03:03 PM, Jonathan Wakely wrote: Here's a finished patch to simplify bits/parse_numbers.h Tested x86_64-linux. Ed, any objection to this version? This looks great, thanks! I committed that to trunk, I'll put it on the 4.9 branch too. Having done that should we actually stop using it as suggested in the bug trail? ;-) I was going to do that, then realised that there's a defect in the standard where it requires overflow in duration integer literals to be diagnosed. That's only possible with literal operator templates, so I think we should keep your _Parse_int code, but apply the attached change to detect overflow. As the TODO comment says, it should be sufficient to simply instantiate integral_constant_Rep, _Val::value to give a diagnostic when _Rep{_Value::value} is narrowing, but GCC only gives a warning for it, and that's suppressed in a system header, so I do an explicit static_assert. That could be replaced with ... #pragma GCC diagnostic push #pragma GCC diagnostic error -Woverflow #pragma GCC diagnostic error -Wsystem-headers templatetypename _Dur, char... _Digits constexpr _Dur __check_overflow() { using _Val = __parse_int::_Parse_int_Digits...; using _Rep = typename _Dur::rep; return _Dur{integral_constant_Rep, _Val::value::value}; } #pragma GCC diagnostic pop ... but I have plans to do that sort of thing more widely, which I'll deal with another time as part of https://gcc.gnu.org/PR50871 and/or https://gcc.gnu.org/PR58876 (what do other people think about using diagnostic pragmas to locally re-enable diagnostics in our headers?) Tested x86_64-linux, committed to trunk. commit 361c9b79e0b1c7f2435f5b0b369a139b216dee90 Author: Jonathan Wakely jwak...@redhat.com Date: Fri May 16 10:31:38 2014 +0100 * include/bits/parse_numbers.h (__parse_int::_Number_help): Check for overflow. * include/std/chrono (chrono_literals::__select_type::_Select_type): Remove. (chrono_literals::_Checked_integral_constant): Define. Simplify UDL operator templates and check for overflow. * testsuite/20_util/duration/literals/range.cc: New. diff --git a/libstdc++-v3/include/bits/parse_numbers.h b/libstdc++-v3/include/bits/parse_numbers.h index 0a42381a..a29d127 100644 --- a/libstdc++-v3/include/bits/parse_numbers.h +++ b/libstdc++-v3/include/bits/parse_numbers.h @@ -193,6 +193,7 @@ namespace __parse_int _Pow / (_Base * __valid_digit::value), _Digs...; using type = __ull_constant_Pow * __digit::value + __next::type::value; + static_assert((type::value / _Pow) == __digit::value, overflow); }; templateunsigned _Base, unsigned long long _Pow, char _Dig diff --git a/libstdc++-v3/include/std/chrono b/libstdc++-v3/include/std/chrono index b114e02..39ad5e3 100644 --- a/libstdc++-v3/include/std/chrono +++ b/libstdc++-v3/include/std/chrono @@ -787,117 +787,79 @@ _GLIBCXX_END_NAMESPACE_VERSION inline namespace chrono_literals { -namespace __select_type -{ - - using namespace __parse_int; - - templateunsigned long long _Val, typename _Dur - struct _Select_type - : conditional - _Val = static_castunsigned long long - (numeric_limitstypename _Dur::rep::max()), - _Dur, void - { - static constexpr typename _Select_type::type - value{static_casttypename _Select_type::type(_Val)}; - }; - - templateunsigned long long _Val, typename _Dur - constexpr typename _Select_type_Val, _Dur::type - _Select_type_Val, _Dur::value; +templatetypename _Rep, unsigned long long _Val + struct _Checked_integral_constant + : integral_constant_Rep, static_cast_Rep(_Val) + { + static_assert(_Checked_integral_constant::value 0 + _Checked_integral_constant::value == _Val, + literal value cannot be represented by duration type); + }; -} // __select_type +templatetypename _Dur, char... _Digits + constexpr _Dur __check_overflow() + { + using _Val = __parse_int::_Parse_int_Digits...; + using _Rep = typename _Dur::rep; + // TODO: should be simply integral_constant_Rep, _Val::value + // but GCC doesn't reject narrowing conversions to _Rep. + using _CheckedVal = _Checked_integral_constant_Rep, _Val::value; + return _Dur{_CheckedVal::value}; + } constexpr chrono::durationlong double, ratio3600,1 operatorh(long double __hours) { return chrono::durationlong double, ratio3600,1{__hours}; } template char... _Digits - constexpr typename - __select_type::_Select_type__select_int::_Select_int_Digits...::value, - chrono::hours::type + constexpr chrono::hours operatorh() - { - return __select_type::_Select_type - __select_int::_Select_int_Digits...::value, - chrono::hours::value; - } + { return __check_overflowchrono::hours, _Digits...(); } constexpr chrono::durationlong double, ratio60,1
Re: [PATCH, libstdc++/61166] overflow when parse number in std::duration operator
Here's a finished patch to simplify bits/parse_numbers.h Tested x86_64-linux. Ed, any objection to this version? commit 87d26af2fc07f0c45a0a6676161ae1db1d7541b7 Author: Jonathan Wakely jwak...@redhat.com Date: Wed May 14 16:35:20 2014 +0100 2014-05-15 Ed Smith-Rowland 3dw...@verizon.net Jonathan Wakely jwak...@redhat.com PR libstdc++/61166 * include/bits/parse_numbers.h: Use integral_constant to remove duplication and simplify. * testsuite/20_util/duration/literals/61166.cc: New. diff --git a/libstdc++-v3/include/bits/parse_numbers.h b/libstdc++-v3/include/bits/parse_numbers.h index 91a127c..0a42381a 100644 --- a/libstdc++-v3/include/bits/parse_numbers.h +++ b/libstdc++-v3/include/bits/parse_numbers.h @@ -27,8 +27,8 @@ * Do not attempt to use it directly. @headername{chrono} */ -#ifndef _PARSE_NUMBERS_H -#define _PARSE_NUMBERS_H 1 +#ifndef _GLIBCXX_PARSE_NUMBERS_H +#define _GLIBCXX_PARSE_NUMBERS_H 1 #pragma GCC system_header @@ -36,289 +36,181 @@ #if __cplusplus 201103L +#include limits + namespace std _GLIBCXX_VISIBILITY(default) { _GLIBCXX_BEGIN_NAMESPACE_VERSION -namespace __parse_int { - +namespace __parse_int +{ templateunsigned _Base, char _Dig struct _Digit; templateunsigned _Base -struct _Digit_Base, '0' +struct _Digit_Base, '0' : integral_constantunsigned, 0 { - static constexpr bool valid{true}; - static constexpr unsigned value{0}; + using __valid = true_type; }; templateunsigned _Base -struct _Digit_Base, '1' +struct _Digit_Base, '1' : integral_constantunsigned, 1 { - static constexpr bool valid{true}; - static constexpr unsigned value{1}; + using __valid = true_type; }; - templateunsigned _Base -struct _Digit_Base, '2' + templateunsigned _Base, unsigned _Val +struct _Digit_impl : integral_constantunsigned, _Val { - static_assert(_Base 2, invalid digit); - static constexpr bool valid{true}; - static constexpr unsigned value{2}; + static_assert(_Base _Val, invalid digit); + using __valid = true_type; }; templateunsigned _Base -struct _Digit_Base, '3' -{ - static_assert(_Base 3, invalid digit); - static constexpr bool valid{true}; - static constexpr unsigned value{3}; -}; +struct _Digit_Base, '2' : _Digit_impl_Base, 2 +{ }; templateunsigned _Base -struct _Digit_Base, '4' -{ - static_assert(_Base 4, invalid digit); - static constexpr bool valid{true}; - static constexpr unsigned value{4}; -}; +struct _Digit_Base, '3' : _Digit_impl_Base, 3 +{ }; templateunsigned _Base -struct _Digit_Base, '5' -{ - static_assert(_Base 5, invalid digit); - static constexpr bool valid{true}; - static constexpr unsigned value{5}; -}; +struct _Digit_Base, '4' : _Digit_impl_Base, 4 +{ }; templateunsigned _Base -struct _Digit_Base, '6' -{ - static_assert(_Base 6, invalid digit); - static constexpr bool valid{true}; - static constexpr unsigned value{6}; -}; +struct _Digit_Base, '5' : _Digit_impl_Base, 5 +{ }; templateunsigned _Base -struct _Digit_Base, '7' -{ - static_assert(_Base 7, invalid digit); - static constexpr bool valid{true}; - static constexpr unsigned value{7}; -}; +struct _Digit_Base, '6' : _Digit_impl_Base, 6 +{ }; templateunsigned _Base -struct _Digit_Base, '8' -{ - static_assert(_Base 8, invalid digit); - static constexpr bool valid{true}; - static constexpr unsigned value{8}; -}; +struct _Digit_Base, '7' : _Digit_impl_Base, 7 +{ }; templateunsigned _Base -struct _Digit_Base, '9' -{ - static_assert(_Base 9, invalid digit); - static constexpr bool valid{true}; - static constexpr unsigned value{9}; -}; +struct _Digit_Base, '8' : _Digit_impl_Base, 8 +{ }; templateunsigned _Base -struct _Digit_Base, 'a' -{ - static_assert(_Base 0xa, invalid digit); - static constexpr bool valid{true}; - static constexpr unsigned value{0xa}; -}; +struct _Digit_Base, '9' : _Digit_impl_Base, 9 +{ }; templateunsigned _Base -struct _Digit_Base, 'A' -{ - static_assert(_Base 0xa, invalid digit); - static constexpr bool valid{true}; - static constexpr unsigned value{0xa}; -}; +struct _Digit_Base, 'a' : _Digit_impl_Base, 0xa +{ }; templateunsigned _Base -struct _Digit_Base, 'b' -{ - static_assert(_Base 0xb, invalid digit); - static constexpr bool valid{true}; - static constexpr unsigned value{0xb}; -}; +struct _Digit_Base, 'A' : _Digit_impl_Base, 0xa +{ }; templateunsigned _Base -struct _Digit_Base, 'B' -{ - static_assert(_Base 0xb, invalid digit); - static constexpr bool valid{true}; - static constexpr
Re: [PATCH, libstdc++/61166] overflow when parse number in std::duration operator
On 05/15/2014 03:03 PM, Jonathan Wakely wrote: Here's a finished patch to simplify bits/parse_numbers.h Tested x86_64-linux. Ed, any objection to this version? This looks great, thanks! Having done that should we actually stop using it as suggested in the bug trail? ;-)
[PATCH, libstdc++/61166] overflow when parse number in std::duration operator
Make the machinery in bits/parse_number.h unsigned long long. I had actually noticed this a while back but we were in stage 4. Then I forgot.. :-/ Built and tested on x84_64-linux. OK? 2014-05-14 Ed Smith-Rowland 3dw...@verizon.net libstdc++/61166 overflow when parse number in std::duration operator * include/bits/parse_numbers.h: Make the machinery unsigned long long. * testsuite/20_util/duration/literals/pr61166.cc: New. Index: include/bits/parse_numbers.h === --- include/bits/parse_numbers.h(revision 210315) +++ include/bits/parse_numbers.h(working copy) @@ -27,8 +27,8 @@ * Do not attempt to use it directly. @headername{chrono} */ -#ifndef _PARSE_NUMBERS_H -#define _PARSE_NUMBERS_H 1 +#ifndef _GLIBCXX_PARSE_NUMBERS_H +#define _GLIBCXX_PARSE_NUMBERS_H 1 #pragma GCC system_header @@ -36,262 +36,278 @@ #if __cplusplus 201103L +#include limits + namespace std _GLIBCXX_VISIBILITY(default) { _GLIBCXX_BEGIN_NAMESPACE_VERSION -namespace __parse_int { +namespace __parse_int +{ - templateunsigned _Base, char _Dig + templateunsigned long long _Base, char _Dig struct _Digit; - templateunsigned _Base + templateunsigned long long _Base struct _Digit_Base, '0' { static constexpr bool valid{true}; - static constexpr unsigned value{0}; + static constexpr unsigned long long value{0}; }; - templateunsigned _Base + templateunsigned long long _Base struct _Digit_Base, '1' { static constexpr bool valid{true}; - static constexpr unsigned value{1}; + static constexpr unsigned long long value{1}; }; - templateunsigned _Base + templateunsigned long long _Base struct _Digit_Base, '2' { static_assert(_Base 2, invalid digit); static constexpr bool valid{true}; - static constexpr unsigned value{2}; + static constexpr unsigned long long value{2}; }; - templateunsigned _Base + templateunsigned long long _Base struct _Digit_Base, '3' { static_assert(_Base 3, invalid digit); static constexpr bool valid{true}; - static constexpr unsigned value{3}; + static constexpr unsigned long long value{3}; }; - templateunsigned _Base + templateunsigned long long _Base struct _Digit_Base, '4' { static_assert(_Base 4, invalid digit); static constexpr bool valid{true}; - static constexpr unsigned value{4}; + static constexpr unsigned long long value{4}; }; - templateunsigned _Base + templateunsigned long long _Base struct _Digit_Base, '5' { static_assert(_Base 5, invalid digit); static constexpr bool valid{true}; - static constexpr unsigned value{5}; + static constexpr unsigned long long value{5}; }; - templateunsigned _Base + templateunsigned long long _Base struct _Digit_Base, '6' { static_assert(_Base 6, invalid digit); static constexpr bool valid{true}; - static constexpr unsigned value{6}; + static constexpr unsigned long long value{6}; }; - templateunsigned _Base + templateunsigned long long _Base struct _Digit_Base, '7' { static_assert(_Base 7, invalid digit); static constexpr bool valid{true}; - static constexpr unsigned value{7}; + static constexpr unsigned long long value{7}; }; - templateunsigned _Base + templateunsigned long long _Base struct _Digit_Base, '8' { static_assert(_Base 8, invalid digit); static constexpr bool valid{true}; - static constexpr unsigned value{8}; + static constexpr unsigned long long value{8}; }; - templateunsigned _Base + templateunsigned long long _Base struct _Digit_Base, '9' { static_assert(_Base 9, invalid digit); static constexpr bool valid{true}; - static constexpr unsigned value{9}; + static constexpr unsigned long long value{9}; }; - templateunsigned _Base + templateunsigned long long _Base struct _Digit_Base, 'a' { static_assert(_Base 0xa, invalid digit); static constexpr bool valid{true}; - static constexpr unsigned value{0xa}; + static constexpr unsigned long long value{0xa}; }; - templateunsigned _Base + templateunsigned long long _Base struct _Digit_Base, 'A' { static_assert(_Base 0xa, invalid digit); static constexpr bool valid{true}; - static constexpr unsigned value{0xa}; + static constexpr unsigned long long value{0xa}; }; - templateunsigned _Base + templateunsigned long long _Base struct _Digit_Base, 'b' { static_assert(_Base 0xb, invalid digit); static constexpr bool valid{true}; - static constexpr unsigned value{0xb}; + static constexpr unsigned long long value{0xb}; }; - templateunsigned _Base +
Re: [PATCH, libstdc++/61166] overflow when parse number in std::duration operator
2014-05-14 15:38 GMT+02:00 Ed Smith-Rowland 3dw...@verizon.net: Make the machinery in bits/parse_number.h unsigned long long. I had actually noticed this a while back but we were in stage 4. Then I forgot.. :-/ Built and tested on x84_64-linux. OK? I understand the reason why the corresponding static members value got type unsigned long long, but why did the template parameter _Base also require the same update? Another question: Presumably value indded requires no uglification, but what about the member valid? I would expect that this is no name reserved by the library. - Daniel -- SavedURI :Show URLShow URLSavedURI : SavedURI :Hide URLHide URLSavedURI : https://mail.google.com/_/scs/mail-static/_/js/k=gmail.main.de.LEt2fN4ilLE.O/m=m_i,t,it/am=OCMOBiHj9kJxhnelj6j997_NLil29vVAOBGeBBRgJwD-m_0_8B_AD-qOEw/rt=h/d=1/rs=AItRSTODy9wv1JKZMABIG3Ak8ViC4kuOWA?random=1395770800154https://mail.google.com/_/scs/mail-static/_/js/k=gmail.main.de.LEt2fN4ilLE.O/m=m_i,t,it/am=OCMOBiHj9kJxhnelj6j997_NLil29vVAOBGeBBRgJwD-m_0_8B_AD-qOEw/rt=h/d=1/rs=AItRSTODy9wv1JKZMABIG3Ak8ViC4kuOWA?random=1395770800154
Re: [PATCH, libstdc++/61166] overflow when parse number in std::duration operator
On 14 May 2014 14:59, Daniel Krügler wrote: 2014-05-14 15:38 GMT+02:00 Ed Smith-Rowland 3dw...@verizon.net: Make the machinery in bits/parse_number.h unsigned long long. I had actually noticed this a while back but we were in stage 4. Then I forgot.. :-/ Built and tested on x84_64-linux. OK? I understand the reason why the corresponding static members value got type unsigned long long, but why did the template parameter _Base also require the same update? Another question: Presumably value indded requires no uglification, but what about the member valid? I would expect that this is no name reserved by the library. Good point. (It's a member function in at least future, but we shouldn't be reserving it elsewhere). Any time I see a static const member of integral type called value I wonder if the type should derive from a specialization of std::integral_constant. You could probably also do: using __valid = true_type;
Re: [PATCH, libstdc++/61166] overflow when parse number in std::duration operator
On 05/14/2014 09:59 AM, Daniel Krügler wrote: 2014-05-14 15:38 GMT+02:00 Ed Smith-Rowland 3dw...@verizon.net: Make the machinery in bits/parse_number.h unsigned long long. I had actually noticed this a while back but we were in stage 4. Then I forgot.. :-/ Built and tested on x84_64-linux. OK? I understand the reason why the corresponding static members value got type unsigned long long, but why did the template parameter _Base also require the same update? Another question: Presumably value indded requires no uglification, but what about the member valid? I would expect that this is no name reserved by the library. - Daniel You're right, _Base doesn't need that - only 2, 8, 10, 16 allowed (could do base64 someday, but still). Change all got me. I should uglify the valid members. But in keeping with, say, our extension type traits and such maybe i should uglify value as well.
Re: [PATCH, libstdc++/61166] overflow when parse number in std::duration operator
On 14 May 2014 15:25, Ed Smith-Rowland wrote: But in keeping with, say, our extension type traits and such maybe i should uglify value as well. No, just derive from std::integral_constant and you get value for free. You already use integral_constant in that file, so the name value is already used.
Re: [PATCH, libstdc++/61166] overflow when parse number in std::duration operator
On 14 May 2014 15:36, Jonathan Wakely wrote: On 14 May 2014 15:25, Ed Smith-Rowland wrote: But in keeping with, say, our extension type traits and such maybe i should uglify value as well. No, just derive from std::integral_constant and you get value for free. You already use integral_constant in that file, so the name value is already used. That also has the advantage that _DigitB, 'f' and _DigitB, 'F' share the same base class, so you don't end up with two different static members with the same value (and if you make __valid a typedef as I suggested you don't have any static members for that either). Do we really need _Digit::value to be unsigned long long, or is it only the results in _Power_help and _Number_help that need to be 64-bit?
Re: [PATCH, libstdc++/61166] overflow when parse number in std::duration operator
On 14/05/14 15:41 +0100, Jonathan Wakely wrote: On 14 May 2014 15:36, Jonathan Wakely wrote: On 14 May 2014 15:25, Ed Smith-Rowland wrote: But in keeping with, say, our extension type traits and such maybe i should uglify value as well. No, just derive from std::integral_constant and you get value for free. You already use integral_constant in that file, so the name value is already used. That also has the advantage that _DigitB, 'f' and _DigitB, 'F' share the same base class, so you don't end up with two different static members with the same value (and if you make __valid a typedef as I suggested you don't have any static members for that either). I've attached a first pass at doing it that way, using integral_constant base classes and working with types not values as much as possible. This gets rid of all static const members except in _Digits (where is that used?) Do we really need _Digit::value to be unsigned long long, or is it only the results in _Power_help and _Number_help that need to be 64-bit? Because I made _Digit derive from integral_constantunsigned that means the partial specialization of _Number_help for single digits has _Number_help::type as integral_constantunsigned, where the other specializations have integral_constantunsigned long long. That's inconsistent, but works. Maybe we'd want to be consistent though, and use this instead of typename _DigitBase, _Dig::type: using type = integral_constantunsigned long long, _Digit_Base, _Dig::value; (Also, I wonder if we could use std::ratio for the power/base arithmetic, but it might not help.) diff --git a/libstdc++-v3/include/bits/parse_numbers.h b/libstdc++-v3/include/bits/parse_numbers.h index 91a127c..055058e 100644 --- a/libstdc++-v3/include/bits/parse_numbers.h +++ b/libstdc++-v3/include/bits/parse_numbers.h @@ -46,185 +46,109 @@ namespace __parse_int { struct _Digit; templateunsigned _Base -struct _Digit_Base, '0' +struct _Digit_Base, '0' : integral_constantunsigned, 0 { - static constexpr bool valid{true}; - static constexpr unsigned value{0}; + using __valid = true_type; }; templateunsigned _Base -struct _Digit_Base, '1' +struct _Digit_Base, '1' : integral_constantunsigned, 1 { - static constexpr bool valid{true}; - static constexpr unsigned value{1}; + using __valid = true_type; }; - templateunsigned _Base -struct _Digit_Base, '2' + templateunsigned _Base, unsigned _Val +struct _Digit_impl : integral_constantunsigned, _Val { - static_assert(_Base 2, invalid digit); - static constexpr bool valid{true}; - static constexpr unsigned value{2}; + static_assert(_Base _Val, invalid digit); + using __valid = true_type; }; templateunsigned _Base -struct _Digit_Base, '3' -{ - static_assert(_Base 3, invalid digit); - static constexpr bool valid{true}; - static constexpr unsigned value{3}; -}; +struct _Digit_Base, '2' : _Digit_impl_Base, 2 +{ }; templateunsigned _Base -struct _Digit_Base, '4' -{ - static_assert(_Base 4, invalid digit); - static constexpr bool valid{true}; - static constexpr unsigned value{4}; -}; +struct _Digit_Base, '3' : _Digit_impl_Base, 3 +{ }; templateunsigned _Base -struct _Digit_Base, '5' -{ - static_assert(_Base 5, invalid digit); - static constexpr bool valid{true}; - static constexpr unsigned value{5}; -}; +struct _Digit_Base, '4' : _Digit_impl_Base, 4 +{ }; templateunsigned _Base -struct _Digit_Base, '6' -{ - static_assert(_Base 6, invalid digit); - static constexpr bool valid{true}; - static constexpr unsigned value{6}; -}; +struct _Digit_Base, '5' : _Digit_impl_Base, 5 +{ }; templateunsigned _Base -struct _Digit_Base, '7' -{ - static_assert(_Base 7, invalid digit); - static constexpr bool valid{true}; - static constexpr unsigned value{7}; -}; +struct _Digit_Base, '6' : _Digit_impl_Base, 6 +{ }; templateunsigned _Base -struct _Digit_Base, '8' -{ - static_assert(_Base 8, invalid digit); - static constexpr bool valid{true}; - static constexpr unsigned value{8}; -}; +struct _Digit_Base, '7' : _Digit_impl_Base, 7 +{ }; templateunsigned _Base -struct _Digit_Base, '9' -{ - static_assert(_Base 9, invalid digit); - static constexpr bool valid{true}; - static constexpr unsigned value{9}; -}; +struct _Digit_Base, '8' : _Digit_impl_Base, 8 +{ }; templateunsigned _Base -struct _Digit_Base, 'a' -{ - static_assert(_Base 0xa, invalid digit); - static constexpr bool valid{true}; - static constexpr unsigned value{0xa}; -}; +struct _Digit_Base, '9' : _Digit_impl_Base, 9 +{ }; templateunsigned _Base -struct _Digit_Base, 'A' -