Skip to content

Commit 9a31fbc

Browse files
[libc++] LWG2381: Inconsistency in parsing floating point numbers
This PR implements LWG2381 by rejecting 'i', 'I', 'n', 'N' in FP parsing, as inf and NaN are intendedly rejected by that LWG issue. Also replaces magic numbers 26 and 28 (formerly 32) with named constants. As a driven-by change, some parts of get_long_double.pass.cpp are guarded with `LDBL_MANT_DIG >= 64`, because these parts fail on platforms where long double is of binary64 format (e.g. MSVC).
1 parent 8887178 commit 9a31fbc

File tree

5 files changed

+73
-67
lines changed

5 files changed

+73
-67
lines changed

libcxx/docs/Status/Cxx23Issues.csv

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@
9898
`3555 <https://wg21.link/LWG3555>`__,"``{transform,elements}_view::iterator::iterator_concept`` should consider const-qualification of the underlying range","June 2021","","","|ranges|"
9999
"","","","","",""
100100
`2191 <https://wg21.link/LWG2191>`__,"Incorrect specification of ``match_results(match_results&&)``","October 2021","|Nothing To Do|",""
101-
`2381 <https://wg21.link/LWG2381>`__,"Inconsistency in parsing floating point numbers","October 2021","",""
101+
`2381 <https://wg21.link/LWG2381>`__,"Inconsistency in parsing floating point numbers","October 2021","|Complete|","18.0"
102102
`2762 <https://wg21.link/LWG2762>`__,"``unique_ptr operator*()`` should be ``noexcept``","October 2021","",""
103103
`3121 <https://wg21.link/LWG3121>`__,"``tuple`` constructor constraints for ``UTypes&&...`` overloads","October 2021","",""
104104
`3123 <https://wg21.link/LWG3123>`__,"``duration`` constructor from representation shouldn't be effectively non-throwing","October 2021","","","|chrono|"

libcxx/include/locale

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -366,9 +366,11 @@ _LIBCPP_HIDE_FROM_ABI _ForwardIterator __scan_keyword(
366366

367367
struct _LIBCPP_EXPORTED_FROM_ABI __num_get_base {
368368
static const int __num_get_buf_sz = 40;
369+
static const size_t __int_chr_cnt = 26;
370+
static const size_t __fp_chr_cnt = 28;
369371

370372
static int __get_base(ios_base&);
371-
static const char __src[33];
373+
static const char __src[33]; // "0123456789abcdefABCDEFxX+-pPiInN"
372374
};
373375

374376
_LIBCPP_EXPORTED_FROM_ABI void
@@ -431,7 +433,7 @@ private:
431433
template <typename _Tp>
432434
const _Tp* __do_widen_p(ios_base& __iob, _Tp* __atoms) const {
433435
locale __loc = __iob.getloc();
434-
use_facet<ctype<_Tp> >(__loc).widen(__src, __src + 26, __atoms);
436+
use_facet<ctype<_Tp> >(__loc).widen(__src, __src + __int_chr_cnt, __atoms);
435437
return __atoms;
436438
}
437439

@@ -447,7 +449,7 @@ private:
447449
template <class _CharT>
448450
string __num_get<_CharT>::__stage2_int_prep(ios_base& __iob, _CharT* __atoms, _CharT& __thousands_sep) {
449451
locale __loc = __iob.getloc();
450-
std::use_facet<ctype<_CharT> >(__loc).widen(__src, __src + 26, __atoms);
452+
std::use_facet<ctype<_CharT> >(__loc).widen(__src, __src + __int_chr_cnt, __atoms);
451453
const numpunct<_CharT>& __np = std::use_facet<numpunct<_CharT> >(__loc);
452454
__thousands_sep = __np.thousands_sep();
453455
return __np.grouping();
@@ -458,7 +460,7 @@ template <class _CharT>
458460
string __num_get<_CharT>::__stage2_float_prep(
459461
ios_base& __iob, _CharT* __atoms, _CharT& __decimal_point, _CharT& __thousands_sep) {
460462
locale __loc = __iob.getloc();
461-
std::use_facet<ctype<_CharT> >(__loc).widen(__src, __src + 32, __atoms);
463+
std::use_facet<ctype<_CharT> >(__loc).widen(__src, __src + __fp_chr_cnt, __atoms);
462464
const numpunct<_CharT>& __np = std::use_facet<numpunct<_CharT> >(__loc);
463465
__decimal_point = __np.decimal_point();
464466
__thousands_sep = __np.thousands_sep();
@@ -490,7 +492,7 @@ __num_get<_CharT>::__stage2_int_loop(_CharT __ct, int __base, char* __a, char*&
490492
}
491493
return 0;
492494
}
493-
ptrdiff_t __f = std::find(__atoms, __atoms + 26, __ct) - __atoms;
495+
ptrdiff_t __f = std::find(__atoms, __atoms + __int_chr_cnt, __ct) - __atoms;
494496
if (__f >= 24)
495497
return -1;
496498
switch (__base) {
@@ -546,8 +548,8 @@ int __num_get<_CharT>::__stage2_float_loop(
546548
}
547549
return 0;
548550
}
549-
ptrdiff_t __f = std::find(__atoms, __atoms + 32, __ct) - __atoms;
550-
if (__f >= 32)
551+
ptrdiff_t __f = std::find(__atoms, __atoms + __num_get_base::__fp_chr_cnt, __ct) - __atoms;
552+
if (__f >= __num_get_base::__fp_chr_cnt)
551553
return -1;
552554
char __x = __src[__f];
553555
if (__x == '-' || __x == '+') {
@@ -846,7 +848,7 @@ _InputIterator num_get<_CharT, _InputIterator>::__do_get_signed(
846848
int __base = this->__get_base(__iob);
847849
// Stage 2
848850
char_type __thousands_sep;
849-
const int __atoms_size = 26;
851+
const int __atoms_size = __num_get_base::__int_chr_cnt;
850852
#ifdef _LIBCPP_ABI_OPTIMIZED_LOCALE_NUM_GET
851853
char_type __atoms1[__atoms_size];
852854
const char_type* __atoms = this->__do_widen(__iob, __atoms1);
@@ -895,7 +897,7 @@ _InputIterator num_get<_CharT, _InputIterator>::__do_get_unsigned(
895897
int __base = this->__get_base(__iob);
896898
// Stage 2
897899
char_type __thousands_sep;
898-
const int __atoms_size = 26;
900+
const int __atoms_size = __num_get_base::__int_chr_cnt;
899901
#ifdef _LIBCPP_ABI_OPTIMIZED_LOCALE_NUM_GET
900902
char_type __atoms1[__atoms_size];
901903
const char_type* __atoms = this->__do_widen(__iob, __atoms1);
@@ -942,7 +944,7 @@ _InputIterator num_get<_CharT, _InputIterator>::__do_get_floating_point(
942944
iter_type __b, iter_type __e, ios_base& __iob, ios_base::iostate& __err, _Fp& __v) const {
943945
// Stage 1, nothing to do
944946
// Stage 2
945-
char_type __atoms[32];
947+
char_type __atoms[__num_get_base::__fp_chr_cnt];
946948
char_type __decimal_point;
947949
char_type __thousands_sep;
948950
string __grouping = this->__stage2_float_prep(__iob, __atoms, __decimal_point, __thousands_sep);
@@ -996,10 +998,11 @@ _InputIterator num_get<_CharT, _InputIterator>::do_get(
996998
// Stage 1
997999
int __base = 16;
9981000
// Stage 2
999-
char_type __atoms[26];
1001+
char_type __atoms[__num_get_base::__int_chr_cnt];
10001002
char_type __thousands_sep = char_type();
10011003
string __grouping;
1002-
std::use_facet<ctype<_CharT> >(__iob.getloc()).widen(__num_get_base::__src, __num_get_base::__src + 26, __atoms);
1004+
std::use_facet<ctype<_CharT> >(__iob.getloc())
1005+
.widen(__num_get_base::__src, __num_get_base::__src + __num_get_base::__int_chr_cnt, __atoms);
10031006
string __buf;
10041007
__buf.resize(__buf.capacity());
10051008
char* __a = &__buf[0];

libcxx/test/std/localization/locale.categories/category.numeric/locale.num.get/facet.num.get.members/get_double.pass.cpp

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -116,9 +116,9 @@ int main(int, char**)
116116
f.get(cpp17_input_iterator<const char*>(str),
117117
cpp17_input_iterator<const char*>(str+sizeof(str)),
118118
ios, err, v);
119-
assert(base(iter) == str+sizeof(str)-1);
120-
assert(err == ios.goodbit);
121-
assert(v == INFINITY);
119+
assert(base(iter) == str);
120+
assert(err == ios.failbit);
121+
assert(v == 0.0);
122122
}
123123
{
124124
const char str[] = "INF";
@@ -128,9 +128,9 @@ int main(int, char**)
128128
f.get(cpp17_input_iterator<const char*>(str),
129129
cpp17_input_iterator<const char*>(str+sizeof(str)),
130130
ios, err, v);
131-
assert(base(iter) == str+sizeof(str)-1);
132-
assert(err == ios.goodbit);
133-
assert(v == INFINITY);
131+
assert(base(iter) == str);
132+
assert(err == ios.failbit);
133+
assert(v == 0.0);
134134
}
135135
{
136136
const char str[] = "-inf";
@@ -140,9 +140,9 @@ int main(int, char**)
140140
f.get(cpp17_input_iterator<const char*>(str),
141141
cpp17_input_iterator<const char*>(str+sizeof(str)),
142142
ios, err, v);
143-
assert(base(iter) == str+sizeof(str)-1);
144-
assert(err == ios.goodbit);
145-
assert(v == -INFINITY);
143+
assert(base(iter) == str + 1);
144+
assert(err == ios.failbit);
145+
assert(v == 0.0);
146146
}
147147
{
148148
const char str[] = "-INF";
@@ -152,9 +152,9 @@ int main(int, char**)
152152
f.get(cpp17_input_iterator<const char*>(str),
153153
cpp17_input_iterator<const char*>(str+sizeof(str)),
154154
ios, err, v);
155-
assert(base(iter) == str+sizeof(str)-1);
156-
assert(err == ios.goodbit);
157-
assert(v == -INFINITY);
155+
assert(base(iter) == str + 1);
156+
assert(err == ios.failbit);
157+
assert(v == 0.0);
158158
}
159159
{
160160
const char str[] = "nan";
@@ -164,9 +164,9 @@ int main(int, char**)
164164
f.get(cpp17_input_iterator<const char*>(str),
165165
cpp17_input_iterator<const char*>(str+sizeof(str)),
166166
ios, err, v);
167-
assert(base(iter) == str+sizeof(str)-1);
168-
assert(err == ios.goodbit);
169-
assert(std::isnan(v));
167+
assert(base(iter) == str);
168+
assert(err == ios.failbit);
169+
assert(v = 0.0);
170170
}
171171
{
172172
const char str[] = "NAN";
@@ -176,9 +176,9 @@ int main(int, char**)
176176
f.get(cpp17_input_iterator<const char*>(str),
177177
cpp17_input_iterator<const char*>(str+sizeof(str)),
178178
ios, err, v);
179-
assert(base(iter) == str+sizeof(str)-1);
180-
assert(err == ios.goodbit);
181-
assert(std::isnan(v));
179+
assert(base(iter) == str);
180+
assert(err == ios.failbit);
181+
assert(v = 0.0);
182182
}
183183
{
184184
v = -1;

libcxx/test/std/localization/locale.categories/category.numeric/locale.num.get/facet.num.get.members/get_float.pass.cpp

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -105,9 +105,9 @@ int main(int, char**)
105105
f.get(cpp17_input_iterator<const char*>(str),
106106
cpp17_input_iterator<const char*>(str+sizeof(str)),
107107
ios, err, v);
108-
assert(base(iter) == str+sizeof(str)-1);
109-
assert(err == ios.goodbit);
110-
assert(v == INFINITY);
108+
assert(base(iter) == str);
109+
assert(err == ios.failbit);
110+
assert(v == 0.0f);
111111
}
112112
{
113113
const char str[] = "INF";
@@ -117,9 +117,9 @@ int main(int, char**)
117117
f.get(cpp17_input_iterator<const char*>(str),
118118
cpp17_input_iterator<const char*>(str+sizeof(str)),
119119
ios, err, v);
120-
assert(base(iter) == str+sizeof(str)-1);
121-
assert(err == ios.goodbit);
122-
assert(v == INFINITY);
120+
assert(base(iter) == str);
121+
assert(err == ios.failbit);
122+
assert(v == 0.0f);
123123
}
124124
{
125125
const char str[] = "-inf";
@@ -129,9 +129,9 @@ int main(int, char**)
129129
f.get(cpp17_input_iterator<const char*>(str),
130130
cpp17_input_iterator<const char*>(str+sizeof(str)),
131131
ios, err, v);
132-
assert(base(iter) == str+sizeof(str)-1);
133-
assert(err == ios.goodbit);
134-
assert(v == -INFINITY);
132+
assert(base(iter) == str + 1);
133+
assert(err == ios.failbit);
134+
assert(v == 0.0f);
135135
}
136136
{
137137
const char str[] = "-INF";
@@ -141,9 +141,9 @@ int main(int, char**)
141141
f.get(cpp17_input_iterator<const char*>(str),
142142
cpp17_input_iterator<const char*>(str+sizeof(str)),
143143
ios, err, v);
144-
assert(base(iter) == str+sizeof(str)-1);
145-
assert(err == ios.goodbit);
146-
assert(v == -INFINITY);
144+
assert(base(iter) == str + 1);
145+
assert(err == ios.failbit);
146+
assert(v == 0.0f);
147147
}
148148
{
149149
const char str[] = "nan";
@@ -153,9 +153,9 @@ int main(int, char**)
153153
f.get(cpp17_input_iterator<const char*>(str),
154154
cpp17_input_iterator<const char*>(str+sizeof(str)),
155155
ios, err, v);
156-
assert(base(iter) == str+sizeof(str)-1);
157-
assert(err == ios.goodbit);
158-
assert(std::isnan(v));
156+
assert(base(iter) == str);
157+
assert(err == ios.failbit);
158+
assert(v == 0.0f);
159159
}
160160
{
161161
const char str[] = "NAN";
@@ -165,9 +165,9 @@ int main(int, char**)
165165
f.get(cpp17_input_iterator<const char*>(str),
166166
cpp17_input_iterator<const char*>(str+sizeof(str)),
167167
ios, err, v);
168-
assert(base(iter) == str+sizeof(str)-1);
169-
assert(err == ios.goodbit);
170-
assert(std::isnan(v));
168+
assert(base(iter) == str);
169+
assert(err == ios.failbit);
170+
assert(v == 0.0f);
171171
}
172172
{
173173
v = -1;

libcxx/test/std/localization/locale.categories/category.numeric/locale.num.get/facet.num.get.members/get_long_double.pass.cpp

Lines changed: 21 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#include <locale>
1717
#include <ios>
1818
#include <cassert>
19+
#include <cfloat>
1920
#include <streambuf>
2021
#include <cmath>
2122
#include "test_macros.h"
@@ -105,9 +106,9 @@ int main(int, char**)
105106
f.get(cpp17_input_iterator<const char*>(str),
106107
cpp17_input_iterator<const char*>(str+sizeof(str)),
107108
ios, err, v);
108-
assert(base(iter) == str+sizeof(str)-1);
109-
assert(err == ios.goodbit);
110-
assert(v == INFINITY);
109+
assert(base(iter) == str);
110+
assert(err == ios.failbit);
111+
assert(v == 0.0l);
111112
}
112113
{
113114
const char str[] = "INF";
@@ -117,9 +118,9 @@ int main(int, char**)
117118
f.get(cpp17_input_iterator<const char*>(str),
118119
cpp17_input_iterator<const char*>(str+sizeof(str)),
119120
ios, err, v);
120-
assert(base(iter) == str+sizeof(str)-1);
121-
assert(err == ios.goodbit);
122-
assert(v == INFINITY);
121+
assert(base(iter) == str);
122+
assert(err == ios.failbit);
123+
assert(v == 0.0l);
123124
}
124125
{
125126
const char str[] = "-inf";
@@ -129,9 +130,9 @@ int main(int, char**)
129130
f.get(cpp17_input_iterator<const char*>(str),
130131
cpp17_input_iterator<const char*>(str+sizeof(str)),
131132
ios, err, v);
132-
assert(base(iter) == str+sizeof(str)-1);
133-
assert(err == ios.goodbit);
134-
assert(v == -INFINITY);
133+
assert(base(iter) == str + 1);
134+
assert(err == ios.failbit);
135+
assert(v == 0.0l);
135136
}
136137
{
137138
const char str[] = "-INF";
@@ -141,9 +142,9 @@ int main(int, char**)
141142
f.get(cpp17_input_iterator<const char*>(str),
142143
cpp17_input_iterator<const char*>(str+sizeof(str)),
143144
ios, err, v);
144-
assert(base(iter) == str+sizeof(str)-1);
145-
assert(err == ios.goodbit);
146-
assert(v == -INFINITY);
145+
assert(base(iter) == str + 1);
146+
assert(err == ios.failbit);
147+
assert(v == 0.0l);
147148
}
148149
{
149150
const char str[] = "nan";
@@ -153,9 +154,9 @@ int main(int, char**)
153154
f.get(cpp17_input_iterator<const char*>(str),
154155
cpp17_input_iterator<const char*>(str+sizeof(str)),
155156
ios, err, v);
156-
assert(base(iter) == str+sizeof(str)-1);
157-
assert(err == ios.goodbit);
158-
assert(std::isnan(v));
157+
assert(base(iter) == str);
158+
assert(err == ios.failbit);
159+
assert(v == 0.0l);
159160
}
160161
{
161162
const char str[] = "NAN";
@@ -165,10 +166,11 @@ int main(int, char**)
165166
f.get(cpp17_input_iterator<const char*>(str),
166167
cpp17_input_iterator<const char*>(str+sizeof(str)),
167168
ios, err, v);
168-
assert(base(iter) == str+sizeof(str)-1);
169-
assert(err == ios.goodbit);
170-
assert(std::isnan(v));
169+
assert(base(iter) == str);
170+
assert(err == ios.failbit);
171+
assert(v == 0.0l);
171172
}
173+
#if LDBL_MANT_DIG >= 64
172174
{
173175
const char str[] = "1.189731495357231765021264e+49321";
174176
std::ios_base::iostate err = ios.goodbit;
@@ -229,6 +231,7 @@ int main(int, char**)
229231
assert(err != ios.failbit);
230232
assert(v == 304888344611713860501504000000.0L);
231233
}
234+
#endif // LDBL_MANT_DIG >= 64
232235
{
233236
v = -1;
234237
const char str[] = "1.19973e+4933"; // unrepresentable

0 commit comments

Comments
 (0)