diff --git a/stl/inc/xlocale b/stl/inc/xlocale index 107e80d0a5a..326a0db4703 100644 --- a/stl/inc/xlocale +++ b/stl/inc/xlocale @@ -3242,8 +3242,11 @@ protected: }; // FUNCTION TEMPLATE _Getloctxt -template -int __CRTDECL _Getloctxt(_InIt& _First, _InIt& _Last, size_t _Numfields, const _Elem* _Ptr) { +enum class _Case_sensitive : bool { _No, _Yes }; + +template +int __CRTDECL _Getloctxt( + _InIt& _First, _InIt& _Last, size_t _Numfields, const _Elem* _Ptr, const _Case_sensitive _Matching) { // find field at _Ptr that matches longest in [_First, _Last) for (size_t _Off = 0; _Ptr[_Off] != _Elem{}; ++_Off) { if (_Ptr[_Off] == _Ptr[0]) { @@ -3271,7 +3274,10 @@ int __CRTDECL _Getloctxt(_InIt& _First, _InIt& _Last, size_t _Numfields, const _ || _Ptr[_Off] == _Elem{}) { // matched all of field, save as possible answer _Str[_Field] = static_cast(_Column < 127 ? _Column : 127); // save skip count if small enough _Ans = static_cast(_Field); // save answer - } else if (_First == _Last || _CType.tolower(_Ptr[_Off]) != _CType.tolower(static_cast<_Elem>(*_First))) { + } else if (_First == _Last + || (_Matching == _Case_sensitive::_Yes + ? _Ptr[_Off] != *_First + : _CType.tolower(_Ptr[_Off]) != _CType.tolower(static_cast<_Elem>(*_First)))) { _Str[_Field] = static_cast(_Column < 127 ? _Column : 127); // no match, just save skip count } else { _Prefix = true; // still a valid prefix diff --git a/stl/inc/xlocnum b/stl/inc/xlocnum index 89d33a7d02f..2643b4cbe56 100644 --- a/stl/inc/xlocnum +++ b/stl/inc/xlocnum @@ -369,7 +369,7 @@ protected: _Str += _Punct_fac.falsename(); _Str.push_back(_Elem{}); _Str += _Punct_fac.truename(); // construct "\0false\0true" - switch (_Getloctxt(_First, _Last, 2, _Str.c_str())) { + switch (_Getloctxt(_First, _Last, 2, _Str.c_str(), _Case_sensitive::_Yes)) { case 0: _Val = false; break; diff --git a/stl/inc/xloctime b/stl/inc/xloctime index 55cb9f0df2d..6edfeb10649 100644 --- a/stl/inc/xloctime +++ b/stl/inc/xloctime @@ -326,7 +326,7 @@ protected: virtual _InIt __CLR_OR_THIS_CALL do_get_weekday(_InIt _First, _InIt _Last, ios_base&, ios_base::iostate& _State, tm* _Pt) const { // get weekday from [_First, _Last) into _Pt - int _Num = _Getloctxt(_First, _Last, 0, _Days); + int _Num = _Getloctxt(_First, _Last, 0, _Days, _Case_sensitive::_No); if (_Num < 0) { _State |= ios_base::failbit; } else { @@ -338,7 +338,7 @@ protected: virtual _InIt __CLR_OR_THIS_CALL do_get_monthname(_InIt _First, _InIt _Last, ios_base&, ios_base::iostate& _State, tm* _Pt) const { // get month from [_First, _Last) into _Pt - int _Num = _Getloctxt(_First, _Last, 0, _Months); + int _Num = _Getloctxt(_First, _Last, 0, _Months, _Case_sensitive::_No); if (_Num < 0) { _State |= ios_base::failbit; @@ -444,7 +444,7 @@ protected: break; case 'p': - _Ans = _Getloctxt(_First, _Last, 0, ":AM:am:PM:pm"); + _Ans = _Getloctxt(_First, _Last, 0, ":AM:am:PM:pm", _Case_sensitive::_No); if (_Ans < 0) { _State |= ios_base::failbit; } else if (1 < _Ans) { diff --git a/tests/std/test.lst b/tests/std/test.lst index 3d71f043206..acdf8d9b478 100644 --- a/tests/std/test.lst +++ b/tests/std/test.lst @@ -172,6 +172,7 @@ tests\GH_001103_countl_zero_correctness tests\GH_001105_custom_streambuf_throws tests\GH_001123_random_cast_out_of_range tests\GH_001411_core_headers +tests\GH_001541_case_sensitive_boolalpha tests\LWG2597_complex_branch_cut tests\LWG3018_shared_ptr_function tests\P0019R8_atomic_ref diff --git a/tests/std/tests/GH_001541_case_sensitive_boolalpha/env.lst b/tests/std/tests/GH_001541_case_sensitive_boolalpha/env.lst new file mode 100644 index 00000000000..19f025bd0e6 --- /dev/null +++ b/tests/std/tests/GH_001541_case_sensitive_boolalpha/env.lst @@ -0,0 +1,4 @@ +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +RUNALL_INCLUDE ..\usual_matrix.lst diff --git a/tests/std/tests/GH_001541_case_sensitive_boolalpha/test.cpp b/tests/std/tests/GH_001541_case_sensitive_boolalpha/test.cpp new file mode 100644 index 00000000000..42cdbdc11d5 --- /dev/null +++ b/tests/std/tests/GH_001541_case_sensitive_boolalpha/test.cpp @@ -0,0 +1,41 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#include +#include +using namespace std; + +enum class Parse { Success, Failure }; + +struct TestCase { + const char* str; + ios_base::fmtflags flags; + Parse expected; + bool result; +}; + +// clang-format off +constexpr TestCase test_cases[] = { + {"0", ios_base::fmtflags{}, Parse::Success, false}, + {"1", ios_base::fmtflags{}, Parse::Success, true }, + {"2", ios_base::fmtflags{}, Parse::Failure, true }, // N4868 [facet.num.get.virtuals]/6 + {"WOOF", ios_base::fmtflags{}, Parse::Failure, false}, // N4868 [facet.num.get.virtuals]/3.6 + {"false", ios_base::boolalpha, Parse::Success, false}, + {"true", ios_base::boolalpha, Parse::Success, true }, + {"WOOF", ios_base::boolalpha, Parse::Failure, false}, // N4868 [facet.num.get.virtuals]/7 + {"FALSE", ios_base::boolalpha, Parse::Failure, false}, // GH-1541 + {"TRUE", ios_base::boolalpha, Parse::Failure, false}, // GH-1541 +}; +// clang-format on + +int main() { + for (const auto& test : test_cases) { + bool val = !test.result; + istringstream iss(test.str); + iss.setf(test.flags); + iss >> val; + assert(iss.fail() == (test.expected == Parse::Failure)); + assert(val == test.result); + } +}