Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions stl/inc/xlocale
Original file line number Diff line number Diff line change
Expand Up @@ -280,6 +280,7 @@ public:
locale(const locale& _Loc, const locale& _Other, category _Cat) : _Ptr(_Locimp::_New_Locimp(*_Loc._Ptr)) {
// construct a locale by copying named facets
if (_Cat != none) { // worth adding, do it
_STL_ASSERT((_Cat & all) == _Cat, "the bitmask value specifying category must be valid");
_Facet_guard _Guard{_Ptr};
_BEGIN_LOCINFO(_Lobj)
_Locimp::_Makeloc(_Lobj, _Cat, _Ptr, &_Other);
Expand All @@ -294,6 +295,7 @@ public:

private:
void _Construct(const string& _Str, category _Cat) {
_STL_ASSERT((_Cat & all) == _Cat, "the bitmask value specifying category must be valid");
// construct a locale with named facets
bool _Bad = false;
_Init();
Expand Down
126 changes: 124 additions & 2 deletions tests/std/tests/Dev09_056375_locale_cleanup/test.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
// Copyright (c) Microsoft Corporation.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception

#define _SILENCE_CXX20_CODECVT_FACETS_DEPRECATION_WARNING

#include <cassert>
#include <cstdio>
#include <locale>
Expand All @@ -11,8 +13,8 @@ using namespace std;

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

STATIC_ASSERT(noexcept(locale{} == locale{}));
STATIC_ASSERT(noexcept(locale{} != locale{}));
STATIC_ASSERT(noexcept(locale{} == locale{})); // strengthened
STATIC_ASSERT(noexcept(locale{} != locale{})); // strengthened

void test_dll() {
puts("Calling dll");
Expand Down Expand Up @@ -50,8 +52,128 @@ void test_exe_part2() {
assert(!isspace(L'Z', locale()));
}


locale make_unnamed_locale() {
locale result{locale{"C"}, &use_facet<numpunct<char>>(locale{"C"})};
assert(result.name() == "*");
return result;
}

template <class Facet>
void test_locale_name_with_facet_pointer_one() {
{
locale result{locale{"C"}, static_cast<Facet*>(nullptr)};
assert(result.name() == "C");
}
{
locale result{make_unnamed_locale(), static_cast<Facet*>(nullptr)};
assert(result.name() == "*");
}
{
locale le{"C"};
locale result{le, &use_facet<Facet>(le)};
assert(result.name() == "*");
}
{
locale lunnamed{make_unnamed_locale()};
locale result{lunnamed, &use_facet<Facet>(lunnamed)};
assert(result.name() == "*");
}
}

void test_locale_name_with_facet_pointer_all() {
test_locale_name_with_facet_pointer_one<collate<char>>();
test_locale_name_with_facet_pointer_one<collate<wchar_t>>();

test_locale_name_with_facet_pointer_one<ctype<char>>();
test_locale_name_with_facet_pointer_one<ctype<wchar_t>>();
test_locale_name_with_facet_pointer_one<codecvt<char, char, mbstate_t>>();
test_locale_name_with_facet_pointer_one<codecvt<char16_t, char, mbstate_t>>();
test_locale_name_with_facet_pointer_one<codecvt<char32_t, char, mbstate_t>>();
#ifdef __cpp_char8_t
test_locale_name_with_facet_pointer_one<codecvt<char16_t, char8_t, mbstate_t>>();
test_locale_name_with_facet_pointer_one<codecvt<char32_t, char8_t, mbstate_t>>();
#endif // __cpp_char8_t
test_locale_name_with_facet_pointer_one<codecvt<wchar_t, char, mbstate_t>>();

test_locale_name_with_facet_pointer_one<moneypunct<char>>();
test_locale_name_with_facet_pointer_one<moneypunct<wchar_t>>();
test_locale_name_with_facet_pointer_one<moneypunct<char, true>>();
test_locale_name_with_facet_pointer_one<moneypunct<wchar_t, true>>();
test_locale_name_with_facet_pointer_one<money_get<char>>();
test_locale_name_with_facet_pointer_one<money_get<wchar_t>>();
test_locale_name_with_facet_pointer_one<money_put<char>>();
test_locale_name_with_facet_pointer_one<money_put<wchar_t>>();

test_locale_name_with_facet_pointer_one<numpunct<char>>();
test_locale_name_with_facet_pointer_one<numpunct<wchar_t>>();
test_locale_name_with_facet_pointer_one<num_get<char>>();
test_locale_name_with_facet_pointer_one<num_get<wchar_t>>();
test_locale_name_with_facet_pointer_one<num_put<char>>();
test_locale_name_with_facet_pointer_one<num_put<wchar_t>>();

test_locale_name_with_facet_pointer_one<time_get<char>>();
test_locale_name_with_facet_pointer_one<time_get<wchar_t>>();
test_locale_name_with_facet_pointer_one<time_put<char>>();
test_locale_name_with_facet_pointer_one<time_put<wchar_t>>();

test_locale_name_with_facet_pointer_one<messages<char>>();
test_locale_name_with_facet_pointer_one<messages<wchar_t>>();
}

void test_locale_name_with_another_locale_and_cats() {
locale lc{"C"};
locale lunnamed{make_unnamed_locale()};
{
locale result{lc, lc, locale::none};
assert(result.name() != "*");
}
{
locale result{lc, lunnamed, locale::none};
assert(result.name() != "*");
}
{
locale result{lunnamed, lc, locale::none};
assert(result.name() == "*");
}
{
locale result{lunnamed, lunnamed, locale::none};
assert(result.name() == "*");
}

constexpr int cats_masks_count = 6; // collate | ctype | monetary | numeric | time | messages
for (int precats = 1; precats < (1 << cats_masks_count); ++precats) {
const locale::category cats = ((precats & (1 << 0)) != 0 ? locale::collate : locale::none)
| ((precats & (1 << 1)) != 0 ? locale::ctype : locale::none)
| ((precats & (1 << 2)) != 0 ? locale::monetary : locale::none)
| ((precats & (1 << 3)) != 0 ? locale::numeric : locale::none)
| ((precats & (1 << 4)) != 0 ? locale::time : locale::none)
| ((precats & (1 << 5)) != 0 ? locale::messages : locale::none);
{
locale result{lc, lc, cats};
assert(result.name() != "*");
}
{
locale result{lc, lunnamed, cats};
assert(result.name() == "*");
}
{
locale result{lunnamed, lc, cats};
assert(result.name() == "*");
}
{
locale result{lunnamed, lunnamed, cats};
assert(result.name() == "*");
}
}
}

int main() {
test_exe_part1();
test_dll();
test_exe_part2();

// test coverage for LWG-2295
test_locale_name_with_facet_pointer_all();
test_locale_name_with_another_locale_and_cats();
}