Skip to content

Commit 2b8a19b

Browse files
Test coverage and precondition checking for LWG-2295 Locale name when the provided Facet is a nullptr (#3823)
Co-authored-by: Stephan T. Lavavej <[email protected]>
1 parent df4dc31 commit 2b8a19b

File tree

2 files changed

+129
-2
lines changed

2 files changed

+129
-2
lines changed

stl/inc/xlocale

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -280,6 +280,7 @@ public:
280280
locale(const locale& _Loc, const locale& _Other, category _Cat) : _Ptr(_Locimp::_New_Locimp(*_Loc._Ptr)) {
281281
// construct a locale by copying named facets
282282
if (_Cat != none) { // worth adding, do it
283+
_STL_ASSERT((_Cat & all) == _Cat, "the bitmask value specifying category must be valid");
283284
_Facet_guard _Guard{_Ptr};
284285
_BEGIN_LOCINFO(_Lobj)
285286
_Locimp::_Makeloc(_Lobj, _Cat, _Ptr, &_Other);
@@ -294,6 +295,7 @@ public:
294295

295296
private:
296297
void _Construct(const string& _Str, category _Cat) {
298+
_STL_ASSERT((_Cat & all) == _Cat, "the bitmask value specifying category must be valid");
297299
// construct a locale with named facets
298300
bool _Bad = false;
299301
_Init();

tests/std/tests/Dev09_056375_locale_cleanup/test.cpp

Lines changed: 127 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
// Copyright (c) Microsoft Corporation.
22
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
33

4+
#define _SILENCE_CXX20_CODECVT_FACETS_DEPRECATION_WARNING
5+
46
#include <cassert>
57
#include <cstdio>
68
#include <locale>
@@ -11,8 +13,8 @@ using namespace std;
1113

1214
#define STATIC_ASSERT(...) static_assert(__VA_ARGS__, #__VA_ARGS__)
1315

14-
STATIC_ASSERT(noexcept(locale{} == locale{}));
15-
STATIC_ASSERT(noexcept(locale{} != locale{}));
16+
STATIC_ASSERT(noexcept(locale{} == locale{})); // strengthened
17+
STATIC_ASSERT(noexcept(locale{} != locale{})); // strengthened
1618

1719
void test_dll() {
1820
puts("Calling dll");
@@ -50,8 +52,131 @@ void test_exe_part2() {
5052
assert(!isspace(L'Z', locale()));
5153
}
5254

55+
#ifndef _M_CEE_PURE
56+
locale make_unnamed_locale() {
57+
locale result{locale{"C"}, &use_facet<numpunct<char>>(locale{"C"})};
58+
assert(result.name() == "*");
59+
return result;
60+
}
61+
62+
template <class Facet>
63+
void test_locale_name_with_facet_pointer_one() {
64+
{
65+
locale result{locale{"C"}, static_cast<Facet*>(nullptr)};
66+
assert(result.name() == "C");
67+
}
68+
{
69+
locale result{make_unnamed_locale(), static_cast<Facet*>(nullptr)};
70+
assert(result.name() == "*");
71+
}
72+
{
73+
locale le{"C"};
74+
locale result{le, &use_facet<Facet>(le)};
75+
assert(result.name() == "*");
76+
}
77+
{
78+
locale lunnamed{make_unnamed_locale()};
79+
locale result{lunnamed, &use_facet<Facet>(lunnamed)};
80+
assert(result.name() == "*");
81+
}
82+
}
83+
84+
void test_locale_name_with_facet_pointer_all() {
85+
test_locale_name_with_facet_pointer_one<collate<char>>();
86+
test_locale_name_with_facet_pointer_one<collate<wchar_t>>();
87+
88+
test_locale_name_with_facet_pointer_one<ctype<char>>();
89+
test_locale_name_with_facet_pointer_one<ctype<wchar_t>>();
90+
test_locale_name_with_facet_pointer_one<codecvt<char, char, mbstate_t>>();
91+
test_locale_name_with_facet_pointer_one<codecvt<char16_t, char, mbstate_t>>();
92+
test_locale_name_with_facet_pointer_one<codecvt<char32_t, char, mbstate_t>>();
93+
#ifdef __cpp_char8_t
94+
test_locale_name_with_facet_pointer_one<codecvt<char16_t, char8_t, mbstate_t>>();
95+
test_locale_name_with_facet_pointer_one<codecvt<char32_t, char8_t, mbstate_t>>();
96+
#endif // __cpp_char8_t
97+
test_locale_name_with_facet_pointer_one<codecvt<wchar_t, char, mbstate_t>>();
98+
99+
test_locale_name_with_facet_pointer_one<moneypunct<char>>();
100+
test_locale_name_with_facet_pointer_one<moneypunct<wchar_t>>();
101+
test_locale_name_with_facet_pointer_one<moneypunct<char, true>>();
102+
test_locale_name_with_facet_pointer_one<moneypunct<wchar_t, true>>();
103+
test_locale_name_with_facet_pointer_one<money_get<char>>();
104+
test_locale_name_with_facet_pointer_one<money_get<wchar_t>>();
105+
test_locale_name_with_facet_pointer_one<money_put<char>>();
106+
test_locale_name_with_facet_pointer_one<money_put<wchar_t>>();
107+
108+
test_locale_name_with_facet_pointer_one<numpunct<char>>();
109+
test_locale_name_with_facet_pointer_one<numpunct<wchar_t>>();
110+
test_locale_name_with_facet_pointer_one<num_get<char>>();
111+
test_locale_name_with_facet_pointer_one<num_get<wchar_t>>();
112+
test_locale_name_with_facet_pointer_one<num_put<char>>();
113+
test_locale_name_with_facet_pointer_one<num_put<wchar_t>>();
114+
115+
test_locale_name_with_facet_pointer_one<time_get<char>>();
116+
test_locale_name_with_facet_pointer_one<time_get<wchar_t>>();
117+
test_locale_name_with_facet_pointer_one<time_put<char>>();
118+
test_locale_name_with_facet_pointer_one<time_put<wchar_t>>();
119+
120+
test_locale_name_with_facet_pointer_one<messages<char>>();
121+
test_locale_name_with_facet_pointer_one<messages<wchar_t>>();
122+
}
123+
124+
void test_locale_name_with_another_locale_and_cats() {
125+
locale lc{"C"};
126+
locale lunnamed{make_unnamed_locale()};
127+
{
128+
locale result{lc, lc, locale::none};
129+
assert(result.name() != "*");
130+
}
131+
{
132+
locale result{lc, lunnamed, locale::none};
133+
assert(result.name() != "*");
134+
}
135+
{
136+
locale result{lunnamed, lc, locale::none};
137+
assert(result.name() == "*");
138+
}
139+
{
140+
locale result{lunnamed, lunnamed, locale::none};
141+
assert(result.name() == "*");
142+
}
143+
144+
constexpr int cats_masks_count = 6; // collate | ctype | monetary | numeric | time | messages
145+
for (int precats = 1; precats < (1 << cats_masks_count); ++precats) {
146+
const locale::category cats = ((precats & (1 << 0)) != 0 ? locale::collate : locale::none)
147+
| ((precats & (1 << 1)) != 0 ? locale::ctype : locale::none)
148+
| ((precats & (1 << 2)) != 0 ? locale::monetary : locale::none)
149+
| ((precats & (1 << 3)) != 0 ? locale::numeric : locale::none)
150+
| ((precats & (1 << 4)) != 0 ? locale::time : locale::none)
151+
| ((precats & (1 << 5)) != 0 ? locale::messages : locale::none);
152+
{
153+
locale result{lc, lc, cats};
154+
assert(result.name() != "*");
155+
}
156+
{
157+
locale result{lc, lunnamed, cats};
158+
assert(result.name() == "*");
159+
}
160+
{
161+
locale result{lunnamed, lc, cats};
162+
assert(result.name() == "*");
163+
}
164+
{
165+
locale result{lunnamed, lunnamed, cats};
166+
assert(result.name() == "*");
167+
}
168+
}
169+
}
170+
#endif // _M_CEE_PURE
171+
53172
int main() {
54173
test_exe_part1();
55174
test_dll();
56175
test_exe_part2();
176+
177+
#ifndef _M_CEE_PURE
178+
// test coverage for LWG-2295
179+
test_locale_name_with_facet_pointer_all();
180+
test_locale_name_with_another_locale_and_cats();
181+
#endif // _M_CEE_PURE
57182
}

0 commit comments

Comments
 (0)