Skip to content

Commit

Permalink
[libc++] Make bsd_locale_fallbacks.h modular and move it into __local…
Browse files Browse the repository at this point in the history
…e/locale_base_api/

This is a first step towards granularizing `<locale>`.

Reviewed By: ldionne, #libc

Spies: arichardson, libcxx-commits, mikhail.ramalho

Differential Revision: https://reviews.llvm.org/D146397
  • Loading branch information
philnik777 committed Apr 21, 2023
1 parent 596d87c commit c847b8e
Show file tree
Hide file tree
Showing 20 changed files with 178 additions and 75 deletions.
5 changes: 3 additions & 2 deletions libcxx/include/CMakeLists.txt
Expand Up @@ -222,8 +222,6 @@ set(files
__bit/popcount.h
__bit/rotate.h
__bit_reference
__bsd_locale_defaults.h
__bsd_locale_fallbacks.h
__charconv/chars_format.h
__charconv/from_chars_integral.h
__charconv/from_chars_result.h
Expand Down Expand Up @@ -439,6 +437,9 @@ set(files
__iterator/unreachable_sentinel.h
__iterator/wrap_iter.h
__locale
__locale_dir/locale_base_api/bsd_locale_defaults.h
__locale_dir/locale_base_api/bsd_locale_fallbacks.h
__locale_dir/locale_base_api/locale_guard.h
__mbstate_t.h
__memory/addressof.h
__memory/align.h
Expand Down
63 changes: 5 additions & 58 deletions libcxx/include/__locale
Expand Up @@ -13,16 +13,20 @@
#include <__availability>
#include <__config>
#include <cctype>
#include <clocale>
#include <cstdint>
#include <cstdlib>
#include <locale.h>
#include <mutex>
#include <string>

// Some platforms require more includes than others. Keep the includes on all plaforms for now.
#include <cstddef>
#include <cstring>

#ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
# include <cwchar>
#endif

#if defined(_LIBCPP_MSVCRT_LIKE)
# include <__support/win32/locale_win32.h>
#elif defined(_AIX) || defined(__MVS__)
Expand Down Expand Up @@ -53,63 +57,6 @@

_LIBCPP_BEGIN_NAMESPACE_STD

#if !defined(_LIBCPP_LOCALE__L_EXTENSIONS)
struct __libcpp_locale_guard {
_LIBCPP_INLINE_VISIBILITY
__libcpp_locale_guard(locale_t& __loc) : __old_loc_(uselocale(__loc)) {}

_LIBCPP_INLINE_VISIBILITY
~__libcpp_locale_guard() {
if (__old_loc_)
uselocale(__old_loc_);
}

locale_t __old_loc_;
private:
__libcpp_locale_guard(__libcpp_locale_guard const&);
__libcpp_locale_guard& operator=(__libcpp_locale_guard const&);
};
#elif defined(_LIBCPP_MSVCRT_LIKE)
struct __libcpp_locale_guard {
__libcpp_locale_guard(locale_t __l) :
__status(_configthreadlocale(_ENABLE_PER_THREAD_LOCALE)) {
// Setting the locale can be expensive even when the locale given is
// already the current locale, so do an explicit check to see if the
// current locale is already the one we want.
const char* __lc = __setlocale(nullptr);
// If every category is the same, the locale string will simply be the
// locale name, otherwise it will be a semicolon-separated string listing
// each category. In the second case, we know at least one category won't
// be what we want, so we only have to check the first case.
if (_VSTD::strcmp(__l.__get_locale(), __lc) != 0) {
__locale_all = _strdup(__lc);
if (__locale_all == nullptr)
__throw_bad_alloc();
__setlocale(__l.__get_locale());
}
}
~__libcpp_locale_guard() {
// The CRT documentation doesn't explicitly say, but setlocale() does the
// right thing when given a semicolon-separated list of locale settings
// for the different categories in the same format as returned by
// setlocale(LC_ALL, nullptr).
if (__locale_all != nullptr) {
__setlocale(__locale_all);
free(__locale_all);
}
_configthreadlocale(__status);
}
static const char* __setlocale(const char* __locale) {
const char* __new_locale = setlocale(LC_ALL, __locale);
if (__new_locale == nullptr)
__throw_bad_alloc();
return __new_locale;
}
int __status;
char* __locale_all = nullptr;
};
#endif

class _LIBCPP_TYPE_VIS locale;

template <class _Facet>
Expand Down
Expand Up @@ -11,8 +11,8 @@
// we will define the mapping from an internal macro to the real BSD symbol.
//===----------------------------------------------------------------------===//

#ifndef _LIBCPP___BSD_LOCALE_DEFAULTS_H
#define _LIBCPP___BSD_LOCALE_DEFAULTS_H
#ifndef _LIBCPP___LOCALE_LOCALE_BASE_API_BSD_LOCALE_DEFAULTS_H
#define _LIBCPP___LOCALE_LOCALE_BASE_API_BSD_LOCALE_DEFAULTS_H

#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
# pragma GCC system_header
Expand All @@ -33,4 +33,4 @@
#define __libcpp_asprintf_l(...) asprintf_l(__VA_ARGS__)
#define __libcpp_sscanf_l(...) sscanf_l(__VA_ARGS__)

#endif // _LIBCPP___BSD_LOCALE_DEFAULTS_H
#endif // _LIBCPP___LOCALE_LOCALE_BASE_API_BSD_LOCALE_DEFAULTS_H
Expand Up @@ -10,12 +10,18 @@
// of those functions for non-BSD platforms.
//===----------------------------------------------------------------------===//

#ifndef _LIBCPP___BSD_LOCALE_FALLBACKS_H
#define _LIBCPP___BSD_LOCALE_FALLBACKS_H
#ifndef _LIBCPP___LOCALE_LOCALE_BASE_API_BSD_LOCALE_FALLBACKS_H
#define _LIBCPP___LOCALE_LOCALE_BASE_API_BSD_LOCALE_FALLBACKS_H

#include <__locale_dir/locale_base_api/locale_guard.h>
#include <cstdio>
#include <stdarg.h>
#include <stdlib.h>

#ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
# include <cwchar>
#endif

#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
# pragma GCC system_header
#endif
Expand Down Expand Up @@ -139,4 +145,4 @@ int __libcpp_sscanf_l(const char *__s, locale_t __l, const char *__format, ...)

_LIBCPP_END_NAMESPACE_STD

#endif // _LIBCPP___BSD_LOCALE_FALLBACKS_H
#endif // _LIBCPP___LOCALE_LOCALE_BASE_API_BSD_LOCALE_FALLBACKS_H
79 changes: 79 additions & 0 deletions libcxx/include/__locale_dir/locale_base_api/locale_guard.h
@@ -0,0 +1,79 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#ifndef _LIBCPP___LOCALE_LOCALE_BASE_API_LOCALE_GUARD_H
#define _LIBCPP___LOCALE_LOCALE_BASE_API_LOCALE_GUARD_H

#include <__config>
#include <clocale>

#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
# pragma GCC system_header
#endif

_LIBCPP_BEGIN_NAMESPACE_STD

#if !defined(_LIBCPP_LOCALE__L_EXTENSIONS)
struct __libcpp_locale_guard {
_LIBCPP_INLINE_VISIBILITY __libcpp_locale_guard(locale_t& __loc) : __old_loc_(uselocale(__loc)) {}

_LIBCPP_INLINE_VISIBILITY ~__libcpp_locale_guard() {
if (__old_loc_)
uselocale(__old_loc_);
}

locale_t __old_loc_;

private:
__libcpp_locale_guard(__libcpp_locale_guard const&);
__libcpp_locale_guard& operator=(__libcpp_locale_guard const&);
};
#elif defined(_LIBCPP_MSVCRT_LIKE)
struct __libcpp_locale_guard {
__libcpp_locale_guard(locale_t __l) :
__status(_configthreadlocale(_ENABLE_PER_THREAD_LOCALE)) {
// Setting the locale can be expensive even when the locale given is
// already the current locale, so do an explicit check to see if the
// current locale is already the one we want.
const char* __lc = __setlocale(nullptr);
// If every category is the same, the locale string will simply be the
// locale name, otherwise it will be a semicolon-separated string listing
// each category. In the second case, we know at least one category won't
// be what we want, so we only have to check the first case.
if (_VSTD::strcmp(__l.__get_locale(), __lc) != 0) {
__locale_all = _strdup(__lc);
if (__locale_all == nullptr)
__throw_bad_alloc();
__setlocale(__l.__get_locale());
}
}
~__libcpp_locale_guard() {
// The CRT documentation doesn't explicitly say, but setlocale() does the
// right thing when given a semicolon-separated list of locale settings
// for the different categories in the same format as returned by
// setlocale(LC_ALL, nullptr).
if (__locale_all != nullptr) {
__setlocale(__locale_all);
free(__locale_all);
}
_configthreadlocale(__status);
}
static const char* __setlocale(const char* __locale) {
const char* __new_locale = setlocale(LC_ALL, __locale);
if (__new_locale == nullptr)
__throw_bad_alloc();
return __new_locale;
}
int __status;
char* __locale_all = nullptr;
};
#endif

_LIBCPP_END_NAMESPACE_STD

#endif // _LIBCPP___LOCALE_LOCALE_BASE_API_LOCALE_GUARD_H
1 change: 1 addition & 0 deletions libcxx/include/libcxx.imp
Expand Up @@ -32,6 +32,7 @@
{ include: [ "@<__fwd/.*>", "private", "<fwd>", "public" ] },
{ include: [ "@<__ios/.*>", "private", "<ios>", "public" ] },
{ include: [ "@<__iterator/.*>", "private", "<iterator>", "public" ] },
{ include: [ "@<__locale_dir/.*>", "private", "<locale>", "public" ] },
{ include: [ "@<__memory/.*>", "private", "<memory>", "public" ] },
{ include: [ "@<__memory_resource/.*>", "private", "<memory_resource>", "public" ] },
{ include: [ "@<__mutex/.*>", "private", "<mutex>", "public" ] },
Expand Down
4 changes: 2 additions & 2 deletions libcxx/include/locale
Expand Up @@ -225,9 +225,9 @@ template <class charT> class messages_byname;
#endif

#ifdef _LIBCPP_LOCALE__L_EXTENSIONS
#include <__bsd_locale_defaults.h>
# include <__locale_dir/locale_base_api/bsd_locale_defaults.h>
#else
#include <__bsd_locale_fallbacks.h>
# include <__locale_dir/locale_base_api/bsd_locale_fallbacks.h>
#endif

#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
Expand Down
4 changes: 4 additions & 0 deletions libcxx/src/iostream.cpp
Expand Up @@ -11,6 +11,10 @@
#include <new>
#include <string>

#ifdef _LIBCPP_MSVCRT_LIKE
# include <__locale_dir/locale_base_api/locale_guard.h>
#endif

#define _str(s) #s
#define str(s) _str(s)
#define _LIBCPP_ABI_NAMESPACE_STR str(_LIBCPP_ABI_NAMESPACE)
Expand Down
2 changes: 2 additions & 0 deletions libcxx/src/support/win32/locale_win32.cpp
Expand Up @@ -11,6 +11,8 @@
#include <memory>
#include <type_traits>

#include <__locale_dir/locale_base_api/locale_guard.h>

int __libcpp_vasprintf(char **sptr, const char *__restrict fmt, va_list ap);

using std::__libcpp_locale_guard;
Expand Down
2 changes: 1 addition & 1 deletion libcxx/test/libcxx/lint/lint_modulemap.sh.py
Expand Up @@ -23,7 +23,7 @@
if re.match(r'^\s*module (\w+)\s+[{] private header "\1(.h)?"\s+export [*] [}]', line):
# It's a top-level private header, such as <__bit_reference>.
pass
elif re.match(r'^\s*module (\w+)\s+[{] private header "__\w+/\1[.]h" [}]', line):
elif re.match(r'^\s*module (\w+)\s+[{] private (textual )?header "__(\w+/)*\1[.]h" [}]', line):
# It's a private submodule, such as <__utility/swap.h>.
pass
elif re.match(r'^\s*module (\w+)_fwd\s+[{] private header "__fwd/\1[.]h" [}]', line):
Expand Down
4 changes: 4 additions & 0 deletions libcxx/test/libcxx/private_headers.verify.cpp
Expand Up @@ -23,6 +23,10 @@ for header in private_headers:
if header.startswith('__support'):
continue
# Skip the locale API headers, since they are platform-specific and thus inherently non-modular
if 'locale_base_api' in header:
continue
print("{ifdef}#{indent}include <{header}> // {expected_error}@*:* {{{{use of private header from outside its module: '{header}'}}}}{endif}".format(
ifdef='#if ' + header_restrictions[header] + '\n' if header in header_restrictions else '',
indent=' ' if header in header_restrictions else '',
Expand Down
10 changes: 10 additions & 0 deletions libcxx/test/libcxx/transitive_includes/cxx03.csv
Expand Up @@ -127,11 +127,13 @@ cmath type_traits
cmath version
codecvt atomic
codecvt cctype
codecvt clocale
codecvt concepts
codecvt cstddef
codecvt cstdint
codecvt cstdlib
codecvt cstring
codecvt cwchar
codecvt initializer_list
codecvt iosfwd
codecvt limits
Expand Down Expand Up @@ -354,12 +356,14 @@ forward_list typeinfo
forward_list version
fstream atomic
fstream cctype
fstream clocale
fstream concepts
fstream cstddef
fstream cstdint
fstream cstdio
fstream cstdlib
fstream cstring
fstream cwchar
fstream filesystem
fstream initializer_list
fstream iosfwd
Expand Down Expand Up @@ -420,11 +424,13 @@ iomanip istream
iomanip version
ios atomic
ios cctype
ios clocale
ios concepts
ios cstddef
ios cstdint
ios cstdlib
ios cstring
ios cwchar
ios initializer_list
ios iosfwd
ios limits
Expand Down Expand Up @@ -496,6 +502,7 @@ list version
locale atomic
locale cctype
locale cerrno
locale clocale
locale concepts
locale cstdarg
locale cstddef
Expand All @@ -504,6 +511,7 @@ locale cstdio
locale cstdlib
locale cstring
locale ctime
locale cwchar
locale initializer_list
locale ios
locale iosfwd
Expand Down Expand Up @@ -681,12 +689,14 @@ ratio type_traits
ratio version
regex atomic
regex cctype
regex clocale
regex compare
regex concepts
regex cstddef
regex cstdint
regex cstdlib
regex cstring
regex cwchar
regex deque
regex initializer_list
regex iosfwd
Expand Down

0 comments on commit c847b8e

Please sign in to comment.