Skip to content

Commit 026776f

Browse files
authored
[libc++] Refactor the creation of the global and classic locales (#72581)
The creation of the global and the classic locales was pretty twisty. This patch refactors how this is done to reduce the amount of indirections and prepare the terrain for a future where GCC implements the no_destroy attribute.
1 parent 97952aa commit 026776f

File tree

3 files changed

+40
-39
lines changed

3 files changed

+40
-39
lines changed

libcxx/include/__locale

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,10 @@ private:
127127
class __imp;
128128
__imp* __locale_;
129129

130+
template <class> friend struct __no_destroy;
131+
struct __private_tag { };
132+
_LIBCPP_HIDE_FROM_ABI explicit locale(__private_tag, __imp* __loc) : __locale_(__loc) {}
133+
130134
void __install_ctor(const locale&, facet*, long);
131135
static locale& __global();
132136
bool has_facet(id&) const;

libcxx/src/locale.cpp

Lines changed: 23 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66
//
77
//===----------------------------------------------------------------------===//
88

9-
#include <__utility/unreachable.h>
109
#include <algorithm>
1110
#include <clocale>
1211
#include <codecvt>
@@ -15,9 +14,11 @@
1514
#include <cstdlib>
1615
#include <cstring>
1716
#include <locale>
17+
#include <new>
1818
#include <string>
1919
#include <type_traits>
2020
#include <typeinfo>
21+
#include <utility>
2122
#include <vector>
2223

2324
#ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
@@ -154,8 +155,6 @@ class _LIBCPP_HIDDEN locale::__imp
154155
{return static_cast<size_t>(id) < facets_.size() && facets_[static_cast<size_t>(id)];}
155156
const locale::facet* use_facet(long id) const;
156157

157-
static const locale& make_classic();
158-
static locale& make_global();
159158
private:
160159
void install(facet* f, long id);
161160
template <class F> void install(F* f) {install(f, f->id.__get());}
@@ -538,37 +537,31 @@ locale::__imp::use_facet(long id) const
538537

539538
// locale
540539

541-
const locale&
542-
locale::__imp::make_classic()
543-
{
544-
// only one thread can get in here and it only gets in once
545-
alignas(locale) static std::byte buf[sizeof(locale)];
546-
locale* c = reinterpret_cast<locale*>(&buf);
547-
c->__locale_ = &make<__imp>(1u);
548-
return *c;
549-
}
540+
// This class basically implements __attribute__((no_destroy)), which isn't supported
541+
// by GCC as of writing this.
542+
template <class T>
543+
struct __no_destroy {
544+
template <class... Args>
545+
explicit __no_destroy(Args&&... args) {
546+
T* obj = reinterpret_cast<T*>(&buf);
547+
new (obj) T(std::forward<Args>(args)...);
548+
}
550549

551-
const locale&
552-
locale::classic()
553-
{
554-
static const locale& c = __imp::make_classic();
555-
return c;
556-
}
550+
T& get() { return *reinterpret_cast<T*>(&buf); }
551+
T const& get() const { return *reinterpret_cast<T const*>(&buf); }
557552

558-
locale&
559-
locale::__imp::make_global()
560-
{
561-
// only one thread can get in here and it only gets in once
562-
alignas(locale) static std::byte buf[sizeof(locale)];
563-
auto *obj = ::new (&buf) locale(locale::classic());
564-
return *obj;
553+
private:
554+
alignas(T) byte buf[sizeof(T)];
555+
};
556+
557+
const locale& locale::classic() {
558+
static const __no_destroy<locale> c(__private_tag{}, &make<__imp>(1u));
559+
return c.get();
565560
}
566561

567-
locale&
568-
locale::__global()
569-
{
570-
static locale& g = __imp::make_global();
571-
return g;
562+
locale& locale::__global() {
563+
static __no_destroy<locale> g(locale::classic());
564+
return g.get();
572565
}
573566

574567
locale::locale() noexcept

libcxx/test/std/localization/locales/locale/locale.cons/char_pointer.pass.cpp

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -81,21 +81,25 @@ int main(int, char**)
8181
assert(!(loc == loc3));
8282
assert(loc != loc3);
8383
#ifndef TEST_HAS_NO_EXCEPTIONS
84-
try
85-
{
84+
try {
8685
std::locale((const char*)0);
8786
assert(false);
87+
} catch (std::runtime_error&) {
88+
// pass
8889
}
89-
catch (std::runtime_error&)
90-
{
90+
91+
try {
92+
std::locale(nullptr);
93+
assert(false);
94+
} catch (std::runtime_error&) {
95+
// pass
9196
}
92-
try
93-
{
97+
98+
try {
9499
std::locale("spazbot");
95100
assert(false);
96-
}
97-
catch (std::runtime_error&)
98-
{
101+
} catch (std::runtime_error&) {
102+
// pass
99103
}
100104
#endif
101105
std::locale ok("");

0 commit comments

Comments
 (0)