-
Notifications
You must be signed in to change notification settings - Fork 14.3k
[libc++] Implements Runtime format strings. #73353
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
@llvm/pr-subscribers-libcxx Author: Mark de Wever (mordante) ChangesThis change requires quite a number of changes in the tests; this is not code I expect people to use in the wild. So I don't expect breakage for users. Implements:
Patch is 20.89 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/73353.diff 20 Files Affected:
diff --git a/libcxx/docs/ReleaseNotes/18.rst b/libcxx/docs/ReleaseNotes/18.rst
index 946e9bf42475f65..fdab0ef0d29b1a0 100644
--- a/libcxx/docs/ReleaseNotes/18.rst
+++ b/libcxx/docs/ReleaseNotes/18.rst
@@ -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
+- P2905R2 - Runtime format strings
- P2918R2 - Runtime format strings II
- P2871R3 - Remove Deprecated Unicode Conversion Facets from C++26
diff --git a/libcxx/docs/Status/Cxx2cPapers.csv b/libcxx/docs/Status/Cxx2cPapers.csv
index 5e413dec59d79af..fd875a6eeeafd19 100644
--- a/libcxx/docs/Status/Cxx2cPapers.csv
+++ b/libcxx/docs/Status/Cxx2cPapers.csv
@@ -30,7 +30,7 @@
"`P0543R3 <https://wg21.link/P0543R3>`__","LWG","Saturation arithmetic","Kona November 2023","","",""
"`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|"
+"`P2905R2 <https://wg21.link/P2905R2>`__","LWG","Runtime format strings","Kona November 2023","|Complete|","18.0","|format| |DR|"
"`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","","",""
diff --git a/libcxx/docs/Status/FormatIssues.csv b/libcxx/docs/Status/FormatIssues.csv
index 14ea7c4360a373f..b3a9be31046935b 100644
--- a/libcxx/docs/Status/FormatIssues.csv
+++ b/libcxx/docs/Status/FormatIssues.csv
@@ -17,7 +17,7 @@ Number,Name,Standard,Assignee,Status,First released version
"`P2510R3 <https://wg21.link/P2510R3>`__","Formatting pointers","C++26","Mark de Wever","|Complete|",17.0
"`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|"
+"`P2905R2 <https://wg21.link/P2905R2>`__","Runtime format strings","C++26 DR","Mark de Wever","|Complete|",18.0
"`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|,
diff --git a/libcxx/include/__format/format_arg_store.h b/libcxx/include/__format/format_arg_store.h
index 15ec8eb0a7d838b..155694a19ca904b 100644
--- a/libcxx/include/__format/format_arg_store.h
+++ b/libcxx/include/__format/format_arg_store.h
@@ -202,8 +202,8 @@ _LIBCPP_HIDE_FROM_ABI basic_format_arg<_Context> __create_format_arg(_Tp& __valu
}
template <class _Context, class... _Args>
-_LIBCPP_HIDE_FROM_ABI void __create_packed_storage(uint64_t& __types, __basic_format_arg_value<_Context>* __values,
- _Args&&... __args) noexcept {
+_LIBCPP_HIDE_FROM_ABI void
+__create_packed_storage(uint64_t& __types, __basic_format_arg_value<_Context>* __values, _Args&... __args) noexcept {
int __shift = 0;
(
[&] {
@@ -220,7 +220,7 @@ _LIBCPP_HIDE_FROM_ABI void __create_packed_storage(uint64_t& __types, __basic_fo
}
template <class _Context, class... _Args>
-_LIBCPP_HIDE_FROM_ABI void __store_basic_format_arg(basic_format_arg<_Context>* __data, _Args&&... __args) noexcept {
+_LIBCPP_HIDE_FROM_ABI void __store_basic_format_arg(basic_format_arg<_Context>* __data, _Args&... __args) noexcept {
([&] { *__data++ = __format::__create_format_arg<_Context>(__args); }(), ...);
}
diff --git a/libcxx/include/__format/format_functions.h b/libcxx/include/__format/format_functions.h
index d4d36d68a98cc23..f3bd57bd7615340 100644
--- a/libcxx/include/__format/format_functions.h
+++ b/libcxx/include/__format/format_functions.h
@@ -63,14 +63,14 @@ using wformat_args = basic_format_args<wformat_context>;
#endif
template <class _Context = format_context, class... _Args>
-_LIBCPP_NODISCARD_EXT _LIBCPP_HIDE_FROM_ABI __format_arg_store<_Context, _Args...> make_format_args(_Args&&... __args) {
+_LIBCPP_NODISCARD_EXT _LIBCPP_HIDE_FROM_ABI __format_arg_store<_Context, _Args...> make_format_args(_Args&... __args) {
return _VSTD::__format_arg_store<_Context, _Args...>(__args...);
}
# ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
template <class... _Args>
_LIBCPP_NODISCARD_EXT _LIBCPP_HIDE_FROM_ABI __format_arg_store<wformat_context, _Args...>
-make_wformat_args(_Args&&... __args) {
+make_wformat_args(_Args&... __args) {
return _VSTD::__format_arg_store<wformat_context, _Args...>(__args...);
}
# endif
diff --git a/libcxx/include/format b/libcxx/include/format
index 7b8d5922cb4971e..ab9b336d0cdabee 100644
--- a/libcxx/include/format
+++ b/libcxx/include/format
@@ -177,10 +177,10 @@ namespace std {
template<class Context = format_context, class... Args>
format-arg-store<Context, Args...>
- make_format_args(Args&&... args);
+ make_format_args(Args&... args);
template<class... Args>
format-arg-store<wformat_context, Args...>
- make_wformat_args(Args&&... args);
+ make_wformat_args(Args&... args);
// [format.error], class format_error
class format_error;
diff --git a/libcxx/test/std/input.output/iostream.format/print.fun/no_file_description.pass.cpp b/libcxx/test/std/input.output/iostream.format/print.fun/no_file_description.pass.cpp
index c9297318cd5d667..f502616b677b776 100644
--- a/libcxx/test/std/input.output/iostream.format/print.fun/no_file_description.pass.cpp
+++ b/libcxx/test/std/input.output/iostream.format/print.fun/no_file_description.pass.cpp
@@ -69,7 +69,8 @@ static void test_vprint_unicode() {
FILE* file = fmemopen(buffer.data(), buffer.size(), "wb");
assert(file);
- std::vprint_unicode(file, "hello world{}", std::make_format_args('!'));
+ char c = '!';
+ std::vprint_unicode(file, "hello world{}", std::make_format_args(c));
long pos = std::ftell(file);
std::fclose(file);
@@ -83,7 +84,8 @@ static void test_vprint_nonunicode() {
FILE* file = fmemopen(buffer.data(), buffer.size(), "wb");
assert(file);
- std::vprint_nonunicode(file, "hello world{}", std::make_format_args('!'));
+ char c = '!';
+ std::vprint_nonunicode(file, "hello world{}", std::make_format_args(c));
long pos = std::ftell(file);
std::fclose(file);
diff --git a/libcxx/test/std/input.output/iostream.format/print.fun/vprint_nonunicode.sh.cpp b/libcxx/test/std/input.output/iostream.format/print.fun/vprint_nonunicode.sh.cpp
index 63e1d2ad82b74e2..c1a690f559b11e3 100644
--- a/libcxx/test/std/input.output/iostream.format/print.fun/vprint_nonunicode.sh.cpp
+++ b/libcxx/test/std/input.output/iostream.format/print.fun/vprint_nonunicode.sh.cpp
@@ -35,8 +35,12 @@
int main(int, char**) {
// The data is passed as-is so it does not depend on the encoding of the input.
- std::vprint_nonunicode("{} {} ", std::make_format_args(1234, "一二三四"));
- std::vprint_nonunicode("{} {}", std::make_format_args(true, nullptr));
+ int i = 1234;
+ const char* s = "一二三四";
+ bool b = true;
+ nullptr_t p = nullptr;
+ std::vprint_nonunicode("{} {} ", std::make_format_args(i, s));
+ std::vprint_nonunicode("{} {}", std::make_format_args(b, p));
return 0;
}
diff --git a/libcxx/test/std/input.output/iostream.format/print.fun/vprint_unicode.sh.cpp b/libcxx/test/std/input.output/iostream.format/print.fun/vprint_unicode.sh.cpp
index a9bcc33d2e014ac..198e71b55d9beb3 100644
--- a/libcxx/test/std/input.output/iostream.format/print.fun/vprint_unicode.sh.cpp
+++ b/libcxx/test/std/input.output/iostream.format/print.fun/vprint_unicode.sh.cpp
@@ -35,8 +35,12 @@
int main(int, char**) {
// The data is passed as-is so it does not depend on the encoding of the input.
- std::vprint_unicode("{} {} ", std::make_format_args(1234, "一二三四"));
- std::vprint_unicode("{} {}", std::make_format_args(true, nullptr));
+ int i = 1234;
+ const char* s = "一二三四";
+ bool b = true;
+ nullptr_t p = nullptr;
+ std::vprint_unicode("{} {} ", std::make_format_args(i, s));
+ std::vprint_unicode("{} {}", std::make_format_args(b, p));
return 0;
}
diff --git a/libcxx/test/std/utilities/format/format.arguments/format.arg.store/make_format_args.pass.cpp b/libcxx/test/std/utilities/format/format.arguments/format.arg.store/make_format_args.pass.cpp
index 72184bbd3920a74..a22660f1feea901 100644
--- a/libcxx/test/std/utilities/format/format.arguments/format.arg.store/make_format_args.pass.cpp
+++ b/libcxx/test/std/utilities/format/format.arguments/format.arg.store/make_format_args.pass.cpp
@@ -10,7 +10,7 @@
// <format>
// template<class Context = format_context, class... Args>
-// format-arg-store<Context, Args...> make_format_args(const Args&... args);
+// format-arg-store<Context, Args...> make_format_args(Args&... args);
#include <cassert>
#include <format>
@@ -21,7 +21,11 @@
#include "test_macros.h"
int main(int, char**) {
- [[maybe_unused]] auto store = std::make_format_args(42, nullptr, false, 'x');
+ int i = 1;
+ char c = 'c';
+ nullptr_t p = nullptr;
+ bool b = false;
+ [[maybe_unused]] auto store = std::make_format_args(i, p, b, c);
LIBCPP_STATIC_ASSERT(
std::same_as<decltype(store), std::__format_arg_store<std::format_context, int, nullptr_t, bool, char>>);
diff --git a/libcxx/test/std/utilities/format/format.arguments/format.arg.store/make_format_args.sh.cpp b/libcxx/test/std/utilities/format/format.arguments/format.arg.store/make_format_args.sh.cpp
index 95a94b0bff5d07b..2d5ee8349b749ff 100644
--- a/libcxx/test/std/utilities/format/format.arguments/format.arg.store/make_format_args.sh.cpp
+++ b/libcxx/test/std/utilities/format/format.arguments/format.arg.store/make_format_args.sh.cpp
@@ -24,6 +24,7 @@
#include "test_macros.h"
void test() {
+ char c = 'c';
TEST_IGNORE_NODISCARD
- std::make_format_args<std::basic_format_context<std::back_insert_iterator<std::basic_string<wchar_t>>, wchar_t>>('c');
+ std::make_format_args<std::basic_format_context<std::back_insert_iterator<std::basic_string<wchar_t>>, wchar_t>>(c);
}
diff --git a/libcxx/test/std/utilities/format/format.arguments/format.arg.store/make_format_args.verify.cpp b/libcxx/test/std/utilities/format/format.arguments/format.arg.store/make_format_args.verify.cpp
new file mode 100644
index 000000000000000..7bd9cb54f8aef1c
--- /dev/null
+++ b/libcxx/test/std/utilities/format/format.arguments/format.arg.store/make_format_args.verify.cpp
@@ -0,0 +1,19 @@
+//===----------------------------------------------------------------------===//
+// 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
+
+// <format>
+
+// template<class... Args>
+// format-arg-store<format_context, Args...>
+// make_format_args(const Args&... args);
+
+#include <format>
+
+// expected-error@*:* {{no matching function for call to 'make_format_args'}}
+[[maybe_unused]] auto store = std::make_format_args(42);
diff --git a/libcxx/test/std/utilities/format/format.arguments/format.arg.store/make_wformat_args.pass.cpp b/libcxx/test/std/utilities/format/format.arguments/format.arg.store/make_wformat_args.pass.cpp
index 22c6f031efc6f71..4afbf6d7d4d253f 100644
--- a/libcxx/test/std/utilities/format/format.arguments/format.arg.store/make_wformat_args.pass.cpp
+++ b/libcxx/test/std/utilities/format/format.arguments/format.arg.store/make_wformat_args.pass.cpp
@@ -12,7 +12,7 @@
// template<class... Args>
// format-arg-store<wformat_context, Args...>
-// make_wformat_args(const Args&... args);
+// make_wformat_args(Args&... args);
#include <cassert>
#include <format>
@@ -21,7 +21,11 @@
#include "test_macros.h"
int main(int, char**) {
- [[maybe_unused]] auto store = std::make_wformat_args(42, nullptr, false, 'x');
+ int i = 1;
+ char c = 'c';
+ nullptr_t p = nullptr;
+ bool b = false;
+ [[maybe_unused]] auto store = std::make_wformat_args(i, p, b, c);
LIBCPP_STATIC_ASSERT(
std::same_as<decltype(store), std::__format_arg_store<std::wformat_context, int, nullptr_t, bool, char>>);
diff --git a/libcxx/test/std/utilities/format/format.arguments/format.arg.store/make_wformat_args.verify.cpp b/libcxx/test/std/utilities/format/format.arguments/format.arg.store/make_wformat_args.verify.cpp
new file mode 100644
index 000000000000000..c5f4bdfe0c726f9
--- /dev/null
+++ b/libcxx/test/std/utilities/format/format.arguments/format.arg.store/make_wformat_args.verify.cpp
@@ -0,0 +1,20 @@
+//===----------------------------------------------------------------------===//
+// 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
+// UNSUPPORTED: no-wide-characters
+
+// <format>
+
+// template<class... Args>
+// format-arg-store<wformat_context, Args...>
+// make_wformat_args(const Args&... args);
+
+#include <format>
+
+// expected-error@*:* {{no matching function for call to 'make_wformat_args'}}
+[[maybe_unused]] auto store = std::make_wformat_args(42);
diff --git a/libcxx/test/std/utilities/format/format.arguments/format.args/ctad.compile.pass.cpp b/libcxx/test/std/utilities/format/format.arguments/format.args/ctad.compile.pass.cpp
index 7cadd4e76c74e0f..b87b5c774ef7e7b 100644
--- a/libcxx/test/std/utilities/format/format.arguments/format.args/ctad.compile.pass.cpp
+++ b/libcxx/test/std/utilities/format/format.arguments/format.args/ctad.compile.pass.cpp
@@ -18,12 +18,13 @@
#include "test_macros.h"
void test() {
+ int i = 1;
// Note the Standard way to create a format-arg-store is by using make_format_args.
- static_assert(std::same_as<decltype(std::basic_format_args(std::make_format_args(42))),
+ static_assert(std::same_as<decltype(std::basic_format_args(std::make_format_args(i))),
std::basic_format_args<std::format_context>>);
#ifndef TEST_HAS_NO_WIDE_CHARACTERS
- static_assert(std::same_as<decltype(std::basic_format_args(std::make_wformat_args(42))),
+ static_assert(std::same_as<decltype(std::basic_format_args(std::make_wformat_args(i))),
std::basic_format_args<std::wformat_context>>);
#endif
diff --git a/libcxx/test/std/utilities/format/format.arguments/format.args/ctor.pass.cpp b/libcxx/test/std/utilities/format/format.arguments/format.args/ctor.pass.cpp
index c2d2d19d978bbd1..c0575c545bde31f 100644
--- a/libcxx/test/std/utilities/format/format.arguments/format.args/ctor.pass.cpp
+++ b/libcxx/test/std/utilities/format/format.arguments/format.args/ctor.pass.cpp
@@ -20,6 +20,9 @@
template <class CharT>
void test() {
+ int i = 1;
+ char c = 'c';
+ nullptr_t p = nullptr;
using Context = std::basic_format_context<CharT*, CharT>;
{
ASSERT_NOEXCEPT(std::basic_format_args<Context>{});
@@ -28,14 +31,14 @@ void test() {
assert(!format_args.get(0));
}
{
- auto store = std::make_format_args<Context>(1);
+ auto store = std::make_format_args<Context>(i);
ASSERT_NOEXCEPT(std::basic_format_args<Context>{store});
std::basic_format_args<Context> format_args{store};
assert(format_args.get(0));
assert(!format_args.get(1));
}
{
- auto store = std::make_format_args<Context>(1, 'c');
+ auto store = std::make_format_args<Context>(i, c);
ASSERT_NOEXCEPT(std::basic_format_args<Context>{store});
std::basic_format_args<Context> format_args{store};
assert(format_args.get(0));
@@ -43,7 +46,7 @@ void test() {
assert(!format_args.get(2));
}
{
- auto store = std::make_format_args<Context>(1, 'c', nullptr);
+ auto store = std::make_format_args<Context>(i, c, p);
ASSERT_NOEXCEPT(std::basic_format_args<Context>{store});
std::basic_format_args<Context> format_args{store};
assert(format_args.get(0));
diff --git a/libcxx/test/std/utilities/format/format.formatter/format.context/format.context/arg.pass.cpp b/libcxx/test/std/utilities/format/format.formatter/format.context/format.context/arg.pass.cpp
index 153f8bbaa4b37f8..824813d33a519a3 100644
--- a/libcxx/test/std/utilities/format/format.formatter/format.context/format.context/arg.pass.cpp
+++ b/libcxx/test/std/utilities/format/format.formatter/format.context/format.context/arg.pass.cpp
@@ -23,9 +23,11 @@
template <class OutIt, class CharT>
void test() {
+ bool b = true;
+ CharT c = CharT('a');
+ int a = 42;
std::basic_string<CharT> string = MAKE_STRING(CharT, "string");
- auto store = std::make_format_args<std::basic_format_context<OutIt, CharT>>(
- true, CharT('a'), 42, string);
+ auto store = std::make_format_args<std::basic_format_context<OutIt, CharT>>(b, c, a, string);
std::basic_format_args args = store;
std::basic_string<CharT> output;
diff --git a/libcxx/test/std/utilities/format/format.formatter/format.context/format.context/ctor.pass.cpp b/libcxx/test/std/utilities/format/format.formatter/format.context/format.context/ctor.pass.cpp
index 5f2f6f1ae370ccb..4a5b5b773ce7549 100644
--- a/libcxx/test/std/utilities/format/format.formatter/format.context/format.context/ctor.pass.cpp
+++ b/libcxx/test/std/utilities/format/format.formatter/format.context/format.context/ctor.pass.cpp
@@ -36,11 +36,14 @@
template <class OutIt, class CharT>
void test() {
+ int a = 42;
+ bool b = true;
+ CharT c = CharT('a');
std::basic_string<CharT> string = MAKE_STRING(CharT, "string");
// The type of the object is an exposition only type. The temporary is needed
// to extend the lifetype of the object since args stores a pointer to the
// data in this object.
- auto format_arg_store = std::make_format_args<std::basic_format_context<OutIt, CharT>>(true, CharT('a'), 42, string);
+ auto format_arg_store = std::make_format_args<std::basic_format_context<OutIt, CharT>>(b, c, a, string);
std::basic_format_args args = format_arg_store;
{
diff --git a/libcxx/test/std/utilities/format/format.formatter/format.context/format.context/locale.pass.cpp b/libcxx/test/std/utilities/format/format.formatter/format.context/format.context/locale.pass.cpp
index edb0a01dc7b0b8e..8e0819037774abb 100644
--- a/libcxx/test/std/utilities/format/format.formatter/format.context/format.context/locale.pass.cpp
+++ b/libcxx/test/std/utilities/format/format.formatter/format.context/format.context/locale.pass.cpp
@@ -34,7 +34,10 @@ void test() {
// The type of the object is an exposition only type. The temporary is needed
// to extend the lifetype of the object since args stores a pointer to the
// data in this object.
- auto format_arg_store = std::make_format_args<std::basic_format_context<OutIt, CharT>>(true, CharT('a'), 42, string);
+ int a = 42;
+ bool b = true;
+ CharT c = CharT('a');
+ auto format_arg_store = std::make_format_args<std::basic_format_context<OutIt, CharT>>(b, c, a, string);
std::basic_format_args args = format_arg_store;
{
diff --git a/libcxx/test/std/utilities/format/format.formatter/format.formatter.spec/formatter.s...
[truncated]
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM with a few small comments.
libcxx/test/std/utilities/format/format.arguments/format.arg.store/make_format_args.verify.cpp
Outdated
Show resolved
Hide resolved
libcxx/test/std/utilities/format/format.arguments/format.arg.store/make_format_args.verify.cpp
Outdated
Show resolved
Hide resolved
libcxx/test/std/utilities/format/format.arguments/format.arg.store/make_wformat_args.verify.cpp
Outdated
Show resolved
Hide resolved
libcxx/test/std/utilities/format/format.arguments/format.arg.store/make_wformat_args.verify.cpp
Outdated
Show resolved
Hide resolved
This change requires quite a number of changes in the tests; this is not code I expect people to use in the wild. So I don't expect breakage for users. Implements: - P2905R2 Runtime format strings, as a Defect Report
f0ec89e
to
fda02a3
Compare
This change requires quite a number of changes in the tests; this is not code I expect people to use in the wild. So I don't expect breakage for users.
Implements: