mirror of
https://github.com/capstone-engine/llvm-capstone.git
synced 2024-11-23 13:50:11 +00:00
[libc++] Implements Runtime format strings II. (#72543)
Implements - P2918R2 Runtime format strings II
This commit is contained in:
parent
76c4a6e310
commit
92d9f232dd
@ -50,6 +50,7 @@ Implemented Papers
|
||||
- P0053R7 - C++ Synchronized Buffered Ostream (in the experimental library)
|
||||
- P2467R1 - Support exclusive mode for fstreams
|
||||
- P0020R6 - Floating Point Atomic
|
||||
- P2918R2 - Runtime format strings II
|
||||
|
||||
|
||||
Improvements and New Features
|
||||
|
@ -31,7 +31,7 @@
|
||||
"`P2407R5 <https://wg21.link/P2407R5>`__","LWG","Freestanding Library: Partial Classes","Kona November 2023","","",""
|
||||
"`P2546R5 <https://wg21.link/P2546R5>`__","LWG","Debugging Support","Kona November 2023","","",""
|
||||
"`P2905R2 <https://wg21.link/P2905R2>`__","LWG","Runtime format strings","Kona November 2023","","","|format| |DR|"
|
||||
"`P2918R2 <https://wg21.link/P2918R2>`__","LWG","Runtime format strings II","Kona November 2023","","","|format|"
|
||||
"`P2918R2 <https://wg21.link/P2918R2>`__","LWG","Runtime format strings II","Kona November 2023","|Complete|","18.0","|format|"
|
||||
"`P2909R4 <https://wg21.link/P2909R4>`__","LWG","Fix formatting of code units as integers (Dude, where’s my ``char``?)","Kona November 2023","","","|format| |DR|"
|
||||
"`P0952R2 <https://wg21.link/P0952R2>`__","LWG","A new specification for ``std::generate_canonical``","Kona November 2023","","",""
|
||||
"`P2447R6 <https://wg21.link/P2447R6>`__","LWG","``std::span`` over an initializer list","Kona November 2023","","",""
|
||||
|
|
@ -18,7 +18,7 @@ Number,Name,Standard,Assignee,Status,First released version
|
||||
"`P2757R3 <https://wg21.link/P2757R3>`__","Type-checking format args","C++26","","",
|
||||
"`P2637R3 <https://wg21.link/P2637R3>`__","Member ``visit``","C++26","","",
|
||||
"`P2905R2 <https://wg21.link/P2905R2>`__","Runtime format strings","C++26 DR","Mark de Wever","|In Progress|"
|
||||
"`P2918R2 <https://wg21.link/P2918R2>`__","Runtime format strings II","C++26","Mark de Wever","|In Progress|"
|
||||
"`P2918R2 <https://wg21.link/P2918R2>`__","Runtime format strings II","C++26","Mark de Wever","|Complete|",18.0
|
||||
"`P2909R4 <https://wg21.link/P2909R4>`__","Fix formatting of code units as integers (Dude, where’s my ``char``?)","C++26 DR","Mark de Wever","|In Progress|"
|
||||
`P1361 <https://wg21.link/P1361>`_,"Integration of chrono with text formatting","C++20",Mark de Wever,|In Progress|,
|
||||
`P2372 <https://wg21.link/P2372>`__,"Fixing locale handling in chrono formatters","C++20",Mark de Wever,|In Progress|,
|
||||
|
Can't render this file because it has a wrong number of fields in line 8.
|
@ -338,6 +338,30 @@ __vformat_to(_ParseCtx&& __parse_ctx, _Ctx&& __ctx) {
|
||||
|
||||
} // namespace __format
|
||||
|
||||
# if _LIBCPP_STD_VER >= 26
|
||||
template <class _CharT>
|
||||
struct _LIBCPP_TEMPLATE_VIS __runtime_format_string {
|
||||
private:
|
||||
basic_string_view<_CharT> __str_;
|
||||
|
||||
template <class _Cp, class... _Args>
|
||||
friend struct _LIBCPP_TEMPLATE_VIS basic_format_string;
|
||||
|
||||
public:
|
||||
_LIBCPP_HIDE_FROM_ABI __runtime_format_string(basic_string_view<_CharT> __s) noexcept : __str_(__s) {}
|
||||
|
||||
__runtime_format_string(const __runtime_format_string&) = delete;
|
||||
__runtime_format_string& operator=(const __runtime_format_string&) = delete;
|
||||
};
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI inline __runtime_format_string<char> runtime_format(string_view __fmt) noexcept { return __fmt; }
|
||||
# ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
|
||||
_LIBCPP_HIDE_FROM_ABI inline __runtime_format_string<wchar_t> runtime_format(wstring_view __fmt) noexcept {
|
||||
return __fmt;
|
||||
}
|
||||
# endif
|
||||
# endif //_LIBCPP_STD_VER >= 26
|
||||
|
||||
template <class _CharT, class... _Args>
|
||||
struct _LIBCPP_TEMPLATE_VIS basic_format_string {
|
||||
template <class _Tp>
|
||||
@ -350,6 +374,9 @@ struct _LIBCPP_TEMPLATE_VIS basic_format_string {
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr basic_string_view<_CharT> get() const noexcept {
|
||||
return __str_;
|
||||
}
|
||||
# if _LIBCPP_STD_VER >= 26
|
||||
_LIBCPP_HIDE_FROM_ABI basic_format_string(__runtime_format_string<_CharT> __s) noexcept : __str_(__s.__str_) {}
|
||||
# endif
|
||||
|
||||
private:
|
||||
basic_string_view<_CharT> __str_;
|
||||
|
@ -31,6 +31,7 @@ namespace std {
|
||||
|
||||
public:
|
||||
template<class T> consteval basic_format_string(const T& s);
|
||||
basic_format_string(runtime-format-string<charT> s) noexcept : str(s.str) {} // since C++26
|
||||
|
||||
constexpr basic_string_view<charT> get() const noexcept { return str; }
|
||||
};
|
||||
@ -41,6 +42,24 @@ namespace std {
|
||||
using wformat_string = // since C++23, exposition only before C++23
|
||||
basic_format_string<wchar_t, type_identity_t<Args>...>;
|
||||
|
||||
template<class charT> struct runtime-format-string { // since C++26, exposition-only
|
||||
private:
|
||||
basic_string_view<charT> str; // exposition-only
|
||||
|
||||
public:
|
||||
runtime-format-string(basic_string_view<charT> s) noexcept : str(s) {}
|
||||
|
||||
runtime-format-string(const runtime-format-string&) = delete;
|
||||
runtime-format-string& operator=(const runtime-format-string&) = delete;
|
||||
};
|
||||
|
||||
runtime-format-string<char> runtime_format(string_view fmt) noexcept {
|
||||
return fmt;
|
||||
}
|
||||
runtime-format-string<wchar_t> runtime_format(wstring_view fmt) noexcept {
|
||||
return fmt;
|
||||
}
|
||||
|
||||
// [format.functions], formatting functions
|
||||
template<class... Args>
|
||||
string format(format-string<Args...> fmt, Args&&... args);
|
||||
|
@ -28,6 +28,9 @@ export namespace std {
|
||||
#ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
|
||||
using std::wformat_string;
|
||||
#endif
|
||||
#if _LIBCPP_STD_VER >= 26
|
||||
using std::runtime_format;
|
||||
#endif //_LIBCPP_STD_VER >= 26
|
||||
|
||||
// [format.functions], formatting functions
|
||||
using std::format;
|
||||
|
@ -0,0 +1,43 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20, c++23
|
||||
|
||||
// <format>
|
||||
|
||||
// template<class charT, class... Args>
|
||||
// class basic_format_string<charT, type_identity_t<Args>...>
|
||||
//
|
||||
// basic_format_string(runtime-format-string<charT> s) noexcept : str(s.str) {}
|
||||
//
|
||||
// Additional testing is done in
|
||||
// - libcxx/test/std/utilities/format/format.functions/format.runtime_format.pass.cpp
|
||||
// - libcxx/test/std/utilities/format/format.functions/format.locale.runtime_format.pass.cpp
|
||||
|
||||
#include <format>
|
||||
#include <cassert>
|
||||
|
||||
#include "test_macros.h"
|
||||
|
||||
int main(int, char**) {
|
||||
static_assert(noexcept(std::format_string<>{std::runtime_format(std::string_view{})}));
|
||||
{
|
||||
std::format_string<> s = std::runtime_format("}{invalid format string}{");
|
||||
assert(s.get() == "}{invalid format string}{");
|
||||
}
|
||||
|
||||
#ifndef TEST_HAS_NO_WIDE_CHARACTERS
|
||||
static_assert(noexcept(std::wformat_string<>{std::runtime_format(std::wstring_view{})}));
|
||||
{
|
||||
std::wformat_string<> s = std::runtime_format(L"}{invalid format string}{");
|
||||
assert(s.get() == L"}{invalid format string}{");
|
||||
}
|
||||
#endif // TEST_HAS_NO_WIDE_CHARACTERS
|
||||
|
||||
return 0;
|
||||
}
|
@ -0,0 +1,85 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
// 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20, c++23
|
||||
// UNSUPPORTED: no-localization
|
||||
// UNSUPPORTED: GCC-ALWAYS_INLINE-FIXME
|
||||
|
||||
// XFAIL: availability-fp_to_chars-missing
|
||||
|
||||
// <format>
|
||||
|
||||
// Tests the behavior of
|
||||
//
|
||||
// runtime-format-string<char> runtime_format(string_view fmt) noexcept;
|
||||
// runtime-format-string<wchar_t> runtime_format(wstring_view fmt) noexcept;
|
||||
//
|
||||
// and
|
||||
//
|
||||
// template<class charT, class... Args>
|
||||
// struct basic_format_string {
|
||||
// ...
|
||||
// basic_format_string(runtime-format-string<charT> s) noexcept : str(s.str) {}
|
||||
// ...
|
||||
// }
|
||||
//
|
||||
// This is done by testing it in the top-level functions:
|
||||
//
|
||||
// template<class... Args>
|
||||
// string format(const locale& loc, format_string<Args...> fmt, Args&&... args);
|
||||
// template<class... Args>
|
||||
// wstring format(const locale& loc, wformat_string<Args...> fmt, Args&&... args);
|
||||
//
|
||||
// The basics of runtime_format and basic_format_string's constructor are tested in
|
||||
// - libcxx/test/std/utilities/format/format.syn/runtime_format_string.pass.cpp
|
||||
// - libcxx/test/std/utilities/format/format.fmt.string/ctor.runtime-format-string.pass.cpp
|
||||
|
||||
#include <format>
|
||||
#include <cassert>
|
||||
#include <locale>
|
||||
#include <vector>
|
||||
|
||||
#include "test_macros.h"
|
||||
#include "format_tests.h"
|
||||
#include "string_literal.h"
|
||||
#include "assert_macros.h"
|
||||
#include "concat_macros.h"
|
||||
|
||||
auto test = []<class CharT, class... Args>(
|
||||
std::basic_string_view<CharT> expected, std::basic_string_view<CharT> fmt, Args&&... args) constexpr {
|
||||
std::basic_string<CharT> out = std::format(std::locale(), std::runtime_format(fmt), std::forward<Args>(args)...);
|
||||
TEST_REQUIRE(out == expected,
|
||||
TEST_WRITE_CONCATENATED(
|
||||
"\nFormat string ", fmt, "\nExpected output ", expected, "\nActual output ", out, '\n'));
|
||||
};
|
||||
|
||||
auto test_exception =
|
||||
[]<class CharT, class... Args>(
|
||||
[[maybe_unused]] std::string_view what,
|
||||
[[maybe_unused]] std::basic_string_view<CharT> fmt,
|
||||
[[maybe_unused]] Args&&... args) {
|
||||
TEST_VALIDATE_EXCEPTION(
|
||||
std::format_error,
|
||||
[&]([[maybe_unused]] const std::format_error& e) {
|
||||
TEST_LIBCPP_REQUIRE(
|
||||
e.what() == what,
|
||||
TEST_WRITE_CONCATENATED(
|
||||
"\nFormat string ", fmt, "\nExpected exception ", what, "\nActual exception ", e.what(), '\n'));
|
||||
},
|
||||
TEST_IGNORE_NODISCARD std::format(std::locale(), std::runtime_format(fmt), std::forward<Args>(args)...));
|
||||
};
|
||||
|
||||
int main(int, char**) {
|
||||
format_tests<char, execution_modus::partial>(test, test_exception);
|
||||
|
||||
#ifndef TEST_HAS_NO_WIDE_CHARACTERS
|
||||
format_tests_char_to_wchar_t(test);
|
||||
format_tests<wchar_t, execution_modus::partial>(test, test_exception);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
@ -0,0 +1,83 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
// 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20, c++23
|
||||
// UNSUPPORTED: GCC-ALWAYS_INLINE-FIXME
|
||||
|
||||
// XFAIL: availability-fp_to_chars-missing
|
||||
|
||||
// <format>
|
||||
|
||||
// Tests the behavior of
|
||||
//
|
||||
// runtime-format-string<char> runtime_format(string_view fmt) noexcept;
|
||||
// runtime-format-string<wchar_t> runtime_format(wstring_view fmt) noexcept;
|
||||
//
|
||||
// and
|
||||
//
|
||||
// template<class charT, class... Args>
|
||||
// struct basic_format_string {
|
||||
// ...
|
||||
// basic_format_string(runtime-format-string<charT> s) noexcept : str(s.str) {}
|
||||
// ...
|
||||
// }
|
||||
//
|
||||
// This is done by testing it in the top-level functions:
|
||||
//
|
||||
// template<class... Args>
|
||||
// string format(format_string<Args...> fmt, Args&&... args);
|
||||
// template<class... Args>
|
||||
// wstring format(wformat_string<Args...> fmt, Args&&... args);
|
||||
//
|
||||
// The basics of runtime_format and basic_format_string's constructor are tested in
|
||||
// - libcxx/test/std/utilities/format/format.syn/runtime_format_string.pass.cpp
|
||||
// - libcxx/test/std/utilities/format/format.fmt.string/ctor.runtime-format-string.pass.cpp
|
||||
|
||||
#include <format>
|
||||
#include <cassert>
|
||||
#include <vector>
|
||||
|
||||
#include "test_macros.h"
|
||||
#include "format_tests.h"
|
||||
#include "string_literal.h"
|
||||
#include "assert_macros.h"
|
||||
#include "concat_macros.h"
|
||||
|
||||
auto test = []<class CharT, class... Args>(
|
||||
std::basic_string_view<CharT> expected, std::basic_string_view<CharT> fmt, Args&&... args) constexpr {
|
||||
std::basic_string<CharT> out = std::format(std::runtime_format(fmt), std::forward<Args>(args)...);
|
||||
TEST_REQUIRE(out == expected,
|
||||
TEST_WRITE_CONCATENATED(
|
||||
"\nFormat string ", fmt, "\nExpected output ", expected, "\nActual output ", out, '\n'));
|
||||
};
|
||||
|
||||
auto test_exception =
|
||||
[]<class CharT, class... Args>(
|
||||
[[maybe_unused]] std::string_view what,
|
||||
[[maybe_unused]] std::basic_string_view<CharT> fmt,
|
||||
[[maybe_unused]] Args&&... args) {
|
||||
TEST_VALIDATE_EXCEPTION(
|
||||
std::format_error,
|
||||
[&]([[maybe_unused]] const std::format_error& e) {
|
||||
TEST_LIBCPP_REQUIRE(
|
||||
e.what() == what,
|
||||
TEST_WRITE_CONCATENATED(
|
||||
"\nFormat string ", fmt, "\nExpected exception ", what, "\nActual exception ", e.what(), '\n'));
|
||||
},
|
||||
TEST_IGNORE_NODISCARD std::format(std::runtime_format(fmt), std::forward<Args>(args)...));
|
||||
};
|
||||
|
||||
int main(int, char**) {
|
||||
format_tests<char, execution_modus::partial>(test, test_exception);
|
||||
|
||||
#ifndef TEST_HAS_NO_WIDE_CHARACTERS
|
||||
format_tests_char_to_wchar_t(test);
|
||||
format_tests<wchar_t, execution_modus::partial>(test, test_exception);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
@ -0,0 +1,70 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20, c++23
|
||||
|
||||
// <format>
|
||||
|
||||
// template<class charT> struct runtime-format-string { // exposition-only
|
||||
// private:
|
||||
// basic_string_view<charT> str; // exposition-only
|
||||
//
|
||||
// public:
|
||||
// runtime-format-string(basic_string_view<charT> s) noexcept : str(s) {}
|
||||
//
|
||||
// runtime-format-string(const runtime-format-string&) = delete;
|
||||
// runtime-format-string& operator=(const runtime-format-string&) = delete;
|
||||
// };
|
||||
//
|
||||
// runtime-format-string<char> runtime_format(string_view fmt) noexcept;
|
||||
// runtime-format-string<wchar_t> runtime_format(wstring_view fmt) noexcept;
|
||||
//
|
||||
// Additional testing is done in
|
||||
// - libcxx/test/std/utilities/format/format.functions/format.runtime_format.pass.cpp
|
||||
// - libcxx/test/std/utilities/format/format.functions/format.locale.runtime_format.pass.cpp
|
||||
|
||||
#include <format>
|
||||
|
||||
#include <cassert>
|
||||
#include <concepts>
|
||||
#include <string_view>
|
||||
#include <type_traits>
|
||||
|
||||
#include "test_macros.h"
|
||||
|
||||
template <class T, class CharT>
|
||||
static void test_properties() {
|
||||
static_assert(std::is_nothrow_convertible_v<std::basic_string_view<CharT>, T>);
|
||||
static_assert(std::is_nothrow_constructible_v<T, std::basic_string_view<CharT>>);
|
||||
|
||||
static_assert(!std::copy_constructible<T>);
|
||||
static_assert(!std::is_copy_assignable_v<T>);
|
||||
|
||||
static_assert(!std::move_constructible<T>);
|
||||
static_assert(!std::is_move_assignable_v<T>);
|
||||
}
|
||||
|
||||
int main(int, char**) {
|
||||
static_assert(noexcept(std::runtime_format(std::string_view{})));
|
||||
auto format_string = std::runtime_format(std::string_view{});
|
||||
|
||||
using FormatString = decltype(format_string);
|
||||
LIBCPP_ASSERT((std::same_as<FormatString, std::__runtime_format_string<char>>));
|
||||
test_properties<FormatString, char>();
|
||||
|
||||
#ifndef TEST_HAS_NO_WIDE_CHARACTERS
|
||||
static_assert(noexcept(std::runtime_format(std::wstring_view{})));
|
||||
auto wformat_string = std::runtime_format(std::wstring_view{});
|
||||
|
||||
using WFormatString = decltype(wformat_string);
|
||||
LIBCPP_ASSERT((std::same_as<WFormatString, std::__runtime_format_string<wchar_t>>));
|
||||
test_properties<WFormatString, wchar_t>();
|
||||
#endif // TEST_HAS_NO_WIDE_CHARACTERS
|
||||
|
||||
return 0;
|
||||
}
|
@ -467,7 +467,7 @@ feature_test_macros = [
|
||||
# "c++20": 202110 Not implemented P2372R3 Fixing locale handling in chrono formatters
|
||||
"c++20": 202106,
|
||||
# "c++23": 202207, Not implemented P2419R2 Clarify handling of encodings in localized formatting of chrono types
|
||||
# "c++26": 202311, Not implemented P2918R2 Runtime format strings II
|
||||
# "c++26": 202311, P2918R2 Runtime format strings II (implemented)
|
||||
},
|
||||
# Note these three papers are adopted at the June 2023 meeting and have sequential numbering
|
||||
# 202304 P2510R3 Formatting pointers (Implemented)
|
||||
|
Loading…
Reference in New Issue
Block a user