Skip to content

Commit 90691c1

Browse files
Implement P2905R2 Runtime Format Strings (#4196)
Co-authored-by: Stephan T. Lavavej <[email protected]>
1 parent 927eb5c commit 90691c1

File tree

12 files changed

+82
-34
lines changed

12 files changed

+82
-34
lines changed

stl/inc/format

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3688,18 +3688,20 @@ _EXPORT_STD using format_args = basic_format_args<format_context>;
36883688
_EXPORT_STD using wformat_args = basic_format_args<wformat_context>;
36893689

36903690
_EXPORT_STD template <class _Context = format_context, class... _Args>
3691-
_NODISCARD auto make_format_args(_Args&&... _Vals) {
3692-
static_assert((_Formattable_with<remove_cvref_t<_Args>, _Context> && ...),
3691+
_NODISCARD auto make_format_args(_Args&... _Vals) {
3692+
// TRANSITION, should cite the new working draft
3693+
static_assert((_Formattable_with<remove_const_t<_Args>, _Context> && ...),
36933694
"Cannot format an argument. To make type T formattable, provide a formatter<T> specialization. "
3694-
"See N4950 [format.arg.store]/2 and [formatter.requirements].");
3695+
"See N4964 [format.arg.store]/2 (along with modification in P2905R2) and [formatter.requirements].");
36953696
return _Format_arg_store<_Context, _Args...>{_Vals...};
36963697
}
36973698

36983699
_EXPORT_STD template <class... _Args>
3699-
_NODISCARD auto make_wformat_args(_Args&&... _Vals) {
3700-
static_assert((_Formattable_with<remove_cvref_t<_Args>, wformat_context> && ...),
3700+
_NODISCARD auto make_wformat_args(_Args&... _Vals) {
3701+
// TRANSITION, should cite the new working draft
3702+
static_assert((_Formattable_with<remove_const_t<_Args>, wformat_context> && ...),
37013703
"Cannot format an argument. To make type T formattable, provide a formatter<T> specialization. "
3702-
"See N4950 [format.arg.store]/2 and [formatter.requirements].");
3704+
"See N4964 [format.arg.store]/2 (along with modification in P2905R2) and [formatter.requirements].");
37033705
return _Format_arg_store<wformat_context, _Args...>{_Vals...};
37043706
}
37053707

stl/inc/ostream

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1244,11 +1244,9 @@ void _Print_impl(const _Add_newline _Add_nl, ostream& _Ostr, const format_string
12441244

12451245
if constexpr (_Has_format_args) {
12461246
if constexpr (_STD _Is_ordinary_literal_encoding_utf8()) {
1247-
_STD _Vprint_unicode_impl(
1248-
_Add_nl, _Ostr, _Fmt.get(), _STD make_format_args(_STD forward<_Types>(_Args)...));
1247+
_STD _Vprint_unicode_impl(_Add_nl, _Ostr, _Fmt.get(), _STD make_format_args(_Args...));
12491248
} else {
1250-
_STD _Vprint_nonunicode_impl(
1251-
_Add_nl, _Ostr, _Fmt.get(), _STD make_format_args(_STD forward<_Types>(_Args)...));
1249+
_STD _Vprint_nonunicode_impl(_Add_nl, _Ostr, _Fmt.get(), _STD make_format_args(_Args...));
12521250
}
12531251
} else {
12541252
const string _Unescaped_str{_Unescape_braces(_Add_nl, _Fmt.get())};

stl/inc/print

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -101,11 +101,9 @@ void _Print_impl(
101101

102102
if constexpr (_Has_format_args) {
103103
if constexpr (_STD _Is_ordinary_literal_encoding_utf8()) {
104-
_STD _Vprint_unicode_impl(
105-
_Add_nl, _Stream, _Fmt.get(), _STD make_format_args(_STD forward<_Types>(_Args)...));
104+
_STD _Vprint_unicode_impl(_Add_nl, _Stream, _Fmt.get(), _STD make_format_args(_Args...));
106105
} else {
107-
_STD _Vprint_nonunicode_impl(
108-
_Add_nl, _Stream, _Fmt.get(), _STD make_format_args(_STD forward<_Types>(_Args)...));
106+
_STD _Vprint_nonunicode_impl(_Add_nl, _Stream, _Fmt.get(), _STD make_format_args(_Args...));
109107
}
110108
} else {
111109
const string _Unescaped_str{_Unescape_braces(_Add_nl, _Fmt.get())};

stl/inc/yvals_core.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -307,6 +307,7 @@
307307
// P2711R1 Making Multi-Param Constructors Of Views explicit
308308
// P2736R2 Referencing The Unicode Standard
309309
// P2770R0 Stashing Stashing Iterators For Proper Flattening
310+
// P2905R2 Runtime Format Strings
310311
// P2909R4 Fix Formatting Of Code Units As Integers
311312

312313
// _HAS_CXX20 indirectly controls:

tests/libcxx/expected_results.txt

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -308,10 +308,6 @@ std/language.support/support.limits/support.limits.general/utility.version.compi
308308
std/language.support/support.limits/support.limits.general/expected.version.compile.pass.cpp FAIL
309309
std/language.support/support.limits/support.limits.general/mdspan.version.compile.pass.cpp FAIL
310310

311-
# P2905R2 Runtime Format Strings
312-
std/utilities/format/format.arguments/format.arg.store/make_format_args.pass.cpp FAIL
313-
std/utilities/format/format.arguments/format.arg.store/make_wformat_args.pass.cpp FAIL
314-
315311
# P2918R2 Runtime Format Strings II
316312
std/utilities/format/format.fmt.string/ctor.runtime-format-string.pass.cpp FAIL
317313
std/utilities/format/format.functions/format.locale.runtime_format.pass.cpp FAIL

tests/std/include/test_format_support.hpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -161,9 +161,9 @@ struct VFormatFn {
161161
template <class... Args>
162162
[[nodiscard]] auto operator()(const std::basic_string_view<CharT> str, Args&&... args) const {
163163
if constexpr (std::same_as<CharT, char>) {
164-
return std::vformat(str, std::make_format_args(std::forward<Args>(args)...));
164+
return std::vformat(str, std::make_format_args(args...));
165165
} else {
166-
return std::vformat(str, std::make_wformat_args(std::forward<Args>(args)...));
166+
return std::vformat(str, std::make_wformat_args(args...));
167167
}
168168
}
169169
};

tests/std/tests/P0355R7_calendars_and_time_zones_formatting/test.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -213,11 +213,11 @@ bool test_parse_chrono_format_specs() {
213213
}
214214

215215
template <class charT, class... Args>
216-
auto make_testing_format_args(Args&&... vals) {
216+
auto make_testing_format_args(Args&&... vals) { // references to temporaries are risky, see P2905R2; we'll be careful
217217
if constexpr (is_same_v<charT, wchar_t>) {
218-
return make_wformat_args(forward<Args>(vals)...);
218+
return make_wformat_args(vals...);
219219
} else {
220-
return make_format_args(forward<Args>(vals)...);
220+
return make_format_args(vals...);
221221
}
222222
}
223223

tests/std/tests/P0645R10_text_formatting_args/test.cpp

Lines changed: 53 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -248,7 +248,8 @@ void test_visit_monostate() {
248248

249249
template <class Context>
250250
void test_lwg3810() {
251-
[[maybe_unused]] auto args_store = make_format_args<Context>(1, 2, 3);
251+
int args[]{1, 2, 3};
252+
[[maybe_unused]] auto args_store = make_format_args<Context>(args[0], args[1], args[2]);
252253
static_assert(same_as<decltype(basic_format_args{args_store}), basic_format_args<Context>>);
253254
}
254255

@@ -264,6 +265,54 @@ void test_lvalue_only_visitation() {
264265
visit_format_arg(lvalue_only_visitor{}, basic_format_arg<Context>{});
265266
}
266267

268+
namespace detail {
269+
constexpr bool permissive() {
270+
return false;
271+
}
272+
273+
template <class>
274+
struct DependentBase {
275+
static constexpr bool permissive() {
276+
return true;
277+
}
278+
};
279+
280+
template <class T>
281+
struct Derived : DependentBase<T> {
282+
static constexpr bool test() {
283+
return permissive();
284+
}
285+
};
286+
} // namespace detail
287+
constexpr bool is_permissive = detail::Derived<int>::test();
288+
289+
template <class Context, class... Args>
290+
concept CanMakeFormatArgs = requires(Args&&... args) { make_format_args<Context>(static_cast<Args&&>(args)...); };
291+
292+
// P2905R2 Runtime format strings (make make_(w)format_args only take lvalue references)
293+
template <class Context>
294+
void test_lvalue_reference_parameters() {
295+
using char_type = Context::char_type;
296+
297+
static_assert(CanMakeFormatArgs<Context, int&, long long&, double&, char_type&, char_type*&, const char_type*&,
298+
basic_string<char_type>&, basic_string_view<char_type>&>);
299+
static_assert(
300+
CanMakeFormatArgs<Context, const int&, const long long&, const double&, const char_type&, char_type* const&,
301+
const char_type* const&, const basic_string<char_type>&, const basic_string_view<char_type>&>);
302+
303+
static_assert(CanMakeFormatArgs<Context, const int, const long long, const double, const char_type,
304+
char_type* const, const char_type* const, const basic_string<char_type>, const basic_string_view<char_type>>);
305+
306+
static_assert(!CanMakeFormatArgs<Context, int>);
307+
static_assert(!CanMakeFormatArgs<Context, long long>);
308+
static_assert(!CanMakeFormatArgs<Context, double>);
309+
static_assert(!CanMakeFormatArgs<Context, char_type>);
310+
static_assert(!CanMakeFormatArgs<Context, char_type*>);
311+
static_assert(!CanMakeFormatArgs<Context, const char_type*>);
312+
static_assert(CanMakeFormatArgs<Context, basic_string<char_type>> == is_permissive);
313+
static_assert(CanMakeFormatArgs<Context, basic_string_view<char_type>> == is_permissive);
314+
}
315+
267316
int main() {
268317
test_basic_format_arg<format_context>();
269318
test_basic_format_arg<wformat_context>();
@@ -277,4 +326,7 @@ int main() {
277326

278327
test_lvalue_only_visitation<format_context>();
279328
test_lvalue_only_visitation<wformat_context>();
329+
330+
test_lvalue_reference_parameters<format_context>();
331+
test_lvalue_reference_parameters<wformat_context>();
280332
}

tests/std/tests/P0645R10_text_formatting_custom_formatting/test.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,11 @@ using namespace std;
1515

1616
// copied from the text_formatting_formatting test case
1717
template <class charT, class... Args>
18-
auto make_testing_format_args(Args&&... vals) {
18+
auto make_testing_format_args(Args&&... vals) { // references to temporaries are risky, see P2905R2; we'll be careful
1919
if constexpr (is_same_v<charT, wchar_t>) {
20-
return make_wformat_args(forward<Args>(vals)...);
20+
return make_wformat_args(vals...);
2121
} else {
22-
return make_format_args(forward<Args>(vals)...);
22+
return make_format_args(vals...);
2323
}
2424
}
2525

tests/std/tests/P0645R10_text_formatting_formatting/test.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -63,11 +63,11 @@ template <class CharT, class Alloc = allocator<CharT>>
6363
using alternative_basic_string = basic_string<CharT, alternative_char_traits<CharT>, Alloc>;
6464

6565
template <class charT, class... Args>
66-
auto make_testing_format_args(Args&&... vals) {
66+
auto make_testing_format_args(Args&&... vals) { // references to temporaries are risky, see P2905R2; we'll be careful
6767
if constexpr (is_same_v<charT, wchar_t>) {
68-
return make_wformat_args(forward<Args>(vals)...);
68+
return make_wformat_args(vals...);
6969
} else {
70-
return make_format_args(forward<Args>(vals)...);
70+
return make_format_args(vals...);
7171
}
7272
}
7373

0 commit comments

Comments
 (0)