Tested x86_64-linux. Pushed to trunk. Probably a good idea to backport it to 13 and 14, for consistency.
-- >8 -- Users are not supposed to create objects of this type, and there's no reason it needs to be copyable. LWG 4061 makes it non-copyable and non-default constructible. libstdc++-v3/ChangeLog: PR libstdc++/114387 * include/std/format (basic_format_context): Define copy operations as deleted, as per LWG 4061. * testsuite/std/format/context.cc: New test. --- libstdc++-v3/include/std/format | 7 +++- libstdc++-v3/testsuite/std/format/context.cc | 36 ++++++++++++++++++++ 2 files changed, 42 insertions(+), 1 deletion(-) create mode 100644 libstdc++-v3/testsuite/std/format/context.cc diff --git a/libstdc++-v3/include/std/format b/libstdc++-v3/include/std/format index 48deba2bcb2..16cee0d3c74 100644 --- a/libstdc++-v3/include/std/format +++ b/libstdc++-v3/include/std/format @@ -3851,6 +3851,12 @@ namespace __format : _M_args(__args), _M_out(std::move(__out)), _M_loc(__loc) { } + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 4061. Should std::basic_format_context be + // default-constructible/copyable/movable? + basic_format_context(const basic_format_context&) = delete; + basic_format_context& operator=(const basic_format_context&) = delete; + template<typename _Out2, typename _CharT2, typename _Context2> friend _Out2 __format::__do_vformat_to(_Out2, basic_string_view<_CharT2>, @@ -3858,7 +3864,6 @@ namespace __format const locale*); public: - basic_format_context() = default; ~basic_format_context() = default; using iterator = _Out; diff --git a/libstdc++-v3/testsuite/std/format/context.cc b/libstdc++-v3/testsuite/std/format/context.cc new file mode 100644 index 00000000000..5cc5e9c9ba2 --- /dev/null +++ b/libstdc++-v3/testsuite/std/format/context.cc @@ -0,0 +1,36 @@ +// { dg-do compile { target c++20 } } + +#include <format> + +template<typename Context> +concept format_context_reqs = std::is_destructible_v<Context> + && (!std::is_default_constructible_v<Context>) + && (!std::is_copy_constructible_v<Context>) + && (!std::is_move_constructible_v<Context>) + && (!std::is_copy_assignable_v<Context>) + && (!std::is_move_assignable_v<Context>) + && requires (Context& ctx, const Context& cctx) { + typename Context::iterator; + typename Context::char_type; + requires std::same_as<typename Context::template formatter_type<int>, + std::formatter<int, typename Context::char_type>>; + { ctx.locale() } -> std::same_as<std::locale>; + { ctx.out() } -> std::same_as<typename Context::iterator>; + { ctx.advance_to(ctx.out()) } -> std::same_as<void>; + { cctx.arg(1) } -> std::same_as<std::basic_format_arg<Context>>; + }; + +template<typename Out, typename charT> +constexpr bool +check(std::basic_format_context<Out, charT>*) +{ + using context = std::basic_format_context<Out, charT>; + static_assert( format_context_reqs<context> ); + static_assert( std::is_same_v<typename context::iterator, Out> ); + static_assert( std::is_same_v<typename context::char_type, charT> ); + return true; +} + +static_assert( check( (std::format_context*)nullptr) ); +static_assert( check( (std::wformat_context*)nullptr) ); +static_assert( check( (std::basic_format_context<char*, char>*)nullptr) ); -- 2.45.2