Skip to content

Commit

Permalink
Implement P2905R2 Runtime Format Strings
Browse files Browse the repository at this point in the history
(Make `make_(w)format_args` only take lvalue references)
  • Loading branch information
frederick-vs-ja committed Nov 15, 2023
1 parent 46843b3 commit afcc7e3
Show file tree
Hide file tree
Showing 12 changed files with 66 additions and 22 deletions.
14 changes: 8 additions & 6 deletions stl/inc/format
Original file line number Diff line number Diff line change
Expand Up @@ -3824,18 +3824,20 @@ _EXPORT_STD using format_args = basic_format_args<format_context>;
_EXPORT_STD using wformat_args = basic_format_args<wformat_context>;

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

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

Expand Down
4 changes: 2 additions & 2 deletions stl/inc/ostream
Original file line number Diff line number Diff line change
Expand Up @@ -1245,10 +1245,10 @@ void _Print_impl(const _Add_newline _Add_nl, ostream& _Ostr, const format_string
if constexpr (_Has_format_args) {
if constexpr (_STD _Is_ordinary_literal_encoding_utf8()) {
_STD _Vprint_unicode_impl(
_Add_nl, _Ostr, _Fmt.get(), _STD make_format_args(_STD forward<_Types>(_Args)...));
_Add_nl, _Ostr, _Fmt.get(), _STD make_format_args(_Args...));
} else {
_STD _Vprint_nonunicode_impl(
_Add_nl, _Ostr, _Fmt.get(), _STD make_format_args(_STD forward<_Types>(_Args)...));
_Add_nl, _Ostr, _Fmt.get(), _STD make_format_args(_Args...));
}
} else {
const string _Unescaped_str{_Unescape_braces(_Add_nl, _Fmt.get())};
Expand Down
4 changes: 2 additions & 2 deletions stl/inc/print
Original file line number Diff line number Diff line change
Expand Up @@ -102,10 +102,10 @@ void _Print_impl(
if constexpr (_Has_format_args) {
if constexpr (_STD _Is_ordinary_literal_encoding_utf8()) {
_STD _Vprint_unicode_impl(
_Add_nl, _Stream, _Fmt.get(), _STD make_format_args(_STD forward<_Types>(_Args)...));
_Add_nl, _Stream, _Fmt.get(), _STD make_format_args(_Args...));
} else {
_STD _Vprint_nonunicode_impl(
_Add_nl, _Stream, _Fmt.get(), _STD make_format_args(_STD forward<_Types>(_Args)...));
_Add_nl, _Stream, _Fmt.get(), _STD make_format_args(_Args...));
}
} else {
const string _Unescaped_str{_Unescape_braces(_Add_nl, _Fmt.get())};
Expand Down
1 change: 1 addition & 0 deletions stl/inc/yvals_core.h
Original file line number Diff line number Diff line change
Expand Up @@ -306,6 +306,7 @@
// P2711R1 Making Multi-Param Constructors Of Views explicit
// P2736R2 Referencing The Unicode Standard
// P2770R0 Stashing Stashing Iterators For Proper Flattening
// P2905R2 Runtime Format Strings

// _HAS_CXX20 indirectly controls:
// P0619R4 Removing C++17-Deprecated Features
Expand Down
10 changes: 10 additions & 0 deletions tests/libcxx/expected_results.txt
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,16 @@ std/ranges/range.adaptors/range.join.view/sentinel/eq.pass.cpp FAIL
std/re/re.iter/re.regiter/iterator_concept_conformance.compile.pass.cpp FAIL
std/re/re.iter/re.tokiter/iterator_concept_conformance.compile.pass.cpp FAIL

# libc++ doesn't implement P2905R2 "Runtime Format Strings"
std/utilities/format/format.arguments/format.arg.store/make_format_args.pass.cpp FAIL
std/utilities/format/format.arguments/format.arg.store/make_format_args.sh.cpp FAIL
std/utilities/format/format.arguments/format.arg.store/make_wformat_args.pass.cpp FAIL
std/utilities/format/format.arguments/format.args/ctor.pass.cpp FAIL
std/utilities/format/format.formatter/format.context/format.context/arg.pass.cpp FAIL
std/utilities/format/format.formatter/format.context/format.context/ctor.pass.cpp FAIL
std/utilities/format/format.formatter/format.context/format.context/locale.pass.cpp FAIL
std/utilities/format/format.formatter/format.formatter.spec/formatter.string.pass.cpp FAIL


# *** INTERACTIONS WITH CONTEST / C1XX THAT UPSTREAM LIKELY WON'T FIX ***
# Tracked by VSO-593630 "<filesystem> Enable libcxx filesystem tests"
Expand Down
4 changes: 2 additions & 2 deletions tests/std/include/test_format_support.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -161,9 +161,9 @@ struct VFormatFn {
template <class... Args>
[[nodiscard]] auto operator()(const std::basic_string_view<CharT> str, Args&&... args) const {
if constexpr (std::same_as<CharT, char>) {
return std::vformat(str, std::make_format_args(std::forward<Args>(args)...));
return std::vformat(str, std::make_format_args(args...));
} else {
return std::vformat(str, std::make_wformat_args(std::forward<Args>(args)...));
return std::vformat(str, std::make_wformat_args(args...));
}
}
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -215,9 +215,9 @@ bool test_parse_chrono_format_specs() {
template <class charT, class... Args>
auto make_testing_format_args(Args&&... vals) {
if constexpr (is_same_v<charT, wchar_t>) {
return make_wformat_args(forward<Args>(vals)...);
return make_wformat_args(vals...);
} else {
return make_format_args(forward<Args>(vals)...);
return make_format_args(vals...);
}
}

Expand Down
32 changes: 31 additions & 1 deletion tests/std/tests/P0645R10_text_formatting_args/test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -248,7 +248,8 @@ void test_visit_monostate() {

template <class Context>
void test_lwg3810() {
[[maybe_unused]] auto args_store = make_format_args<Context>(1, 2, 3);
int args[]{1, 2, 3};
[[maybe_unused]] auto args_store = make_format_args<Context>(args[0], args[1], args[2]);
static_assert(same_as<decltype(basic_format_args{args_store}), basic_format_args<Context>>);
}

Expand All @@ -264,6 +265,32 @@ void test_lvalue_only_visitation() {
visit_format_arg(lvalue_only_visitor{}, basic_format_arg<Context>{});
}

template <class Context, class... Args>
concept CanMakeFormatArgs = requires(Args&&... args) { make_format_args<Context>(static_cast<Args&&>(args)...); };

// P2905R2 Runtime format strings (make make_(w)format_args only take lvalue references)
template <class Context>
void test_lvalue_reference_parameters() { // COMPILE-ONLY
using char_type = Context::char_type;

static_assert(CanMakeFormatArgs<Context, int&, long long&, double&, char_type&, char_type*&, const char_type*&,
basic_string<char_type>&, basic_string_view<char_type>&>);
static_assert(
CanMakeFormatArgs<Context, const int&, const long long&, const double&, const char_type&, char_type* const&,
const char_type* const&, const basic_string<char_type>&, const basic_string_view<char_type>&>);

static_assert(CanMakeFormatArgs<Context, const int, const long long, const double, const char_type,
char_type* const, const char_type* const, const basic_string<char_type>, const basic_string_view<char_type>>);

static_assert(!CanMakeFormatArgs<Context, int>);
static_assert(!CanMakeFormatArgs<Context, long long>);
static_assert(!CanMakeFormatArgs<Context, double>);
static_assert(!CanMakeFormatArgs<Context, char_type>);
static_assert(!CanMakeFormatArgs<Context, const char_type*>);
static_assert(!CanMakeFormatArgs<Context, basic_string<char_type>>);
static_assert(!CanMakeFormatArgs<Context, basic_string_view<char_type>>);
}

int main() {
test_basic_format_arg<format_context>();
test_basic_format_arg<wformat_context>();
Expand All @@ -277,4 +304,7 @@ int main() {

test_lvalue_only_visitation<format_context>();
test_lvalue_only_visitation<wformat_context>();

test_lvalue_reference_parameters<format_context>();
test_lvalue_reference_parameters<wformat_context>();
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,9 @@ using namespace std;
template <class charT, class... Args>
auto make_testing_format_args(Args&&... vals) {
if constexpr (is_same_v<charT, wchar_t>) {
return make_wformat_args(forward<Args>(vals)...);
return make_wformat_args(vals...);
} else {
return make_format_args(forward<Args>(vals)...);
return make_format_args(vals...);
}
}

Expand Down
4 changes: 2 additions & 2 deletions tests/std/tests/P0645R10_text_formatting_formatting/test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -65,9 +65,9 @@ using alternative_basic_string = basic_string<CharT, alternative_char_traits<Cha
template <class charT, class... Args>
auto make_testing_format_args(Args&&... vals) {
if constexpr (is_same_v<charT, wchar_t>) {
return make_wformat_args(forward<Args>(vals)...);
return make_wformat_args(vals...);
} else {
return make_format_args(forward<Args>(vals)...);
return make_format_args(vals...);
}
}

Expand Down
3 changes: 2 additions & 1 deletion tests/std/tests/P0645R10_text_formatting_utf8/test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,8 @@ void test_multibyte_format_strings() {
{
try {
// Bad fill character encoding: missing lead byte before \x9f
(void) vformat("{:\x9f\x8f\x88<10}"sv, make_format_args(42));
int arg = 42;
(void) vformat("{:\x9f\x8f\x88<10}"sv, make_format_args(arg));
assert(false);
} catch (const format_error&) {
}
Expand Down
4 changes: 2 additions & 2 deletions tests/std/tests/P2286R8_text_formatting_escaping/test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,9 @@ template <typename CharT>
template <class charT, class... Args>
auto make_testing_format_args(Args&&... vals) {
if constexpr (is_same_v<charT, wchar_t>) {
return make_wformat_args(forward<Args>(vals)...);
return make_wformat_args(vals...);
} else {
return make_format_args(forward<Args>(vals)...);
return make_format_args(vals...);
}
}

Expand Down

0 comments on commit afcc7e3

Please sign in to comment.