diff --git a/libcxx/docs/Status/Cxx2bIssues.csv b/libcxx/docs/Status/Cxx2bIssues.csv --- a/libcxx/docs/Status/Cxx2bIssues.csv +++ b/libcxx/docs/Status/Cxx2bIssues.csv @@ -264,7 +264,7 @@ "`3819 `__","``reference_meows_from_temporary`` should not use ``is_meowible``","February 2023","","","" "`3821 `__","``uses_allocator_construction_args`` should have overload for ``pair-like``","February 2023","","","" "`3834 `__","Missing ``constexpr`` for ``std::intmax_t`` math functions in ````","February 2023","","","" -"`3839 `__","``range_formatter``'s ``set_separator``, ``set_brackets``, and ``underlying`` functions should be ``noexcept``","February 2023","","","|format|" +"`3839 `__","``range_formatter``'s ``set_separator``, ``set_brackets``, and ``underlying`` functions should be ``noexcept``","February 2023","|Complete|","17.0","|format|" "`3841 `__","```` should not be ""all freestanding""","February 2023","","","" "`3842 `__","Unclear wording for ``precision`` in ``chrono-format-spec``","February 2023","","","|format|" "`3848 `__","``adjacent_view``, ``adjacent_transform_view`` and ``slide_view`` missing ``base`` accessor","February 2023","","","|ranges|" diff --git a/libcxx/include/__format/formatter_tuple.h b/libcxx/include/__format/formatter_tuple.h --- a/libcxx/include/__format/formatter_tuple.h +++ b/libcxx/include/__format/formatter_tuple.h @@ -40,11 +40,11 @@ template <__fmt_char_type _CharT, class _Tuple, formattable<_CharT>... _Args> struct _LIBCPP_TEMPLATE_VIS _LIBCPP_AVAILABILITY_FORMAT __formatter_tuple { - _LIBCPP_HIDE_FROM_ABI constexpr void set_separator(basic_string_view<_CharT> __separator) { + _LIBCPP_HIDE_FROM_ABI constexpr void set_separator(basic_string_view<_CharT> __separator) noexcept { __separator_ = __separator; } _LIBCPP_HIDE_FROM_ABI constexpr void - set_brackets(basic_string_view<_CharT> __opening_bracket, basic_string_view<_CharT> __closing_bracket) { + set_brackets(basic_string_view<_CharT> __opening_bracket, basic_string_view<_CharT> __closing_bracket) noexcept { __opening_bracket_ = __opening_bracket; __closing_bracket_ = __closing_bracket; } diff --git a/libcxx/include/__format/range_default_formatter.h b/libcxx/include/__format/range_default_formatter.h --- a/libcxx/include/__format/range_default_formatter.h +++ b/libcxx/include/__format/range_default_formatter.h @@ -95,11 +95,11 @@ range_formatter>, _CharT> __underlying_; public: - _LIBCPP_HIDE_FROM_ABI constexpr void set_separator(basic_string_view<_CharT> __separator) { + _LIBCPP_HIDE_FROM_ABI constexpr void set_separator(basic_string_view<_CharT> __separator) noexcept { __underlying_.set_separator(__separator); } _LIBCPP_HIDE_FROM_ABI constexpr void - set_brackets(basic_string_view<_CharT> __opening_bracket, basic_string_view<_CharT> __closing_bracket) { + set_brackets(basic_string_view<_CharT> __opening_bracket, basic_string_view<_CharT> __closing_bracket) noexcept { __underlying_.set_brackets(__opening_bracket, __closing_bracket); } diff --git a/libcxx/include/__format/range_formatter.h b/libcxx/include/__format/range_formatter.h --- a/libcxx/include/__format/range_formatter.h +++ b/libcxx/include/__format/range_formatter.h @@ -41,17 +41,17 @@ template requires same_as, _Tp> && formattable<_Tp, _CharT> struct _LIBCPP_TEMPLATE_VIS _LIBCPP_AVAILABILITY_FORMAT range_formatter { - _LIBCPP_HIDE_FROM_ABI constexpr void set_separator(basic_string_view<_CharT> __separator) { + _LIBCPP_HIDE_FROM_ABI constexpr void set_separator(basic_string_view<_CharT> __separator) noexcept { __separator_ = __separator; } _LIBCPP_HIDE_FROM_ABI constexpr void - set_brackets(basic_string_view<_CharT> __opening_bracket, basic_string_view<_CharT> __closing_bracket) { + set_brackets(basic_string_view<_CharT> __opening_bracket, basic_string_view<_CharT> __closing_bracket) noexcept { __opening_bracket_ = __opening_bracket; __closing_bracket_ = __closing_bracket; } - _LIBCPP_HIDE_FROM_ABI constexpr formatter<_Tp, _CharT>& underlying() { return __underlying_; } - _LIBCPP_HIDE_FROM_ABI constexpr const formatter<_Tp, _CharT>& underlying() const { return __underlying_; } + _LIBCPP_HIDE_FROM_ABI constexpr formatter<_Tp, _CharT>& underlying() noexcept { return __underlying_; } + _LIBCPP_HIDE_FROM_ABI constexpr const formatter<_Tp, _CharT>& underlying() const noexcept { return __underlying_; } template _LIBCPP_HIDE_FROM_ABI constexpr typename _ParseContext::iterator parse(_ParseContext& __parse_ctx) { diff --git a/libcxx/test/std/utilities/format/format.range/format.range.fmtdef/format.pass.cpp b/libcxx/test/std/utilities/format/format.range/format.range.fmtdef/format.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/utilities/format/format.range/format.range.fmtdef/format.pass.cpp @@ -0,0 +1,72 @@ +//===----------------------------------------------------------------------===// +// 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 +// UNSUPPORTED: libcpp-has-no-incomplete-format + +// TODO FMT Fix this test using GCC, it currently times out. +// UNSUPPORTED: gcc-12 + +// This test requires the dylib support introduced in D92214. +// XFAIL: use_system_cxx_lib && target={{.+}}-apple-macosx10.{{.+}} +// XFAIL: use_system_cxx_lib && target={{.+}}-apple-macosx11.{{.+}} + +// + +// template +// struct range-default-formatter + +// template +// typename FormatContext::iterator +// format(maybe-const-r& elems, FormatContext& ctx) const; + +#include +#include +#include +#include +#include + +#include "test_format_context.h" +#include "test_macros.h" +#include "make_string.h" + +#define SV(S) MAKE_STRING_VIEW(CharT, S) + +template +void test_format(StringViewT expected, std::array arg) { + using CharT = typename StringViewT::value_type; + using String = std::basic_string; + using OutIt = std::back_insert_iterator; + using FormatCtxT = std::basic_format_context; + + std::formatter, CharT> formatter; + + String result; + OutIt out = std::back_inserter(result); + FormatCtxT format_ctx = test_format_context_create(out, std::make_format_args(arg)); + formatter.format(arg, format_ctx); + assert(result == expected); +} + +template +void test_fmt() { + test_format(SV("[1, 42]"), std::array{{1, 42}}); + test_format(SV("[0, 99]"), std::array{{0, 99}}); +} + +void test() { + test_fmt(); +#ifndef TEST_HAS_NO_WIDE_CHARACTERS + test_fmt(); +#endif +} + +int main(int, char**) { + test(); + + return 0; +} diff --git a/libcxx/test/std/utilities/format/format.tuple/set_separator.pass.cpp b/libcxx/test/std/utilities/format/format.range/format.range.fmtdef/parse.pass.cpp copy from libcxx/test/std/utilities/format/format.tuple/set_separator.pass.cpp copy to libcxx/test/std/utilities/format/format.range/format.range.fmtdef/parse.pass.cpp --- a/libcxx/test/std/utilities/format/format.tuple/set_separator.pass.cpp +++ b/libcxx/test/std/utilities/format/format.range/format.range.fmtdef/parse.pass.cpp @@ -17,43 +17,48 @@ // -// class range_formatter -// template... Ts> -// struct formatter, charT> +// template +// struct range-default-formatter -// constexpr void set_separator(basic_string_view sep); - -// Note this tests the basics of this function. It's tested in more detail in -// the format functions tests. +// template +// constexpr typename ParseContext::iterator +// parse(ParseContext& ctx); +#include +#include +#include #include -#include -#include +#include "test_format_context.h" +#include "test_macros.h" #include "make_string.h" #define SV(S) MAKE_STRING_VIEW(CharT, S) -template -constexpr void test() { - std::formatter formatter; - formatter.set_separator(SV("sep")); +template +constexpr void test_parse(StringViewT fmt) { + using CharT = typename StringViewT::value_type; + auto parse_ctx = std::basic_format_parse_context(fmt); + std::formatter, CharT> formatter; + static_assert(std::semiregular); - // Note there is no direct way to validate this function modified the object. + std::same_as auto it = formatter.parse(parse_ctx); + assert(it == fmt.end() - (!fmt.empty() && fmt.back() == '}')); } template -constexpr void test() { - test>(); - test>(); - test>(); - test>(); +constexpr void test_fmt() { + test_parse(SV("")); + test_parse(SV(":5")); + + test_parse(SV("}")); + test_parse(SV(":5}")); } constexpr bool test() { - test(); + test_fmt(); #ifndef TEST_HAS_NO_WIDE_CHARACTERS - test(); + test_fmt(); #endif return true; diff --git a/libcxx/test/std/utilities/format/format.range/format.range.formatter/set_brackets.pass.cpp b/libcxx/test/std/utilities/format/format.range/format.range.fmtdef/set_brackets.pass.cpp copy from libcxx/test/std/utilities/format/format.range/format.range.formatter/set_brackets.pass.cpp copy to libcxx/test/std/utilities/format/format.range/format.range.fmtdef/set_brackets.pass.cpp --- a/libcxx/test/std/utilities/format/format.range/format.range.formatter/set_brackets.pass.cpp +++ b/libcxx/test/std/utilities/format/format.range/format.range.fmtdef/set_brackets.pass.cpp @@ -17,15 +17,11 @@ // -// template -// requires same_as, T> && formattable -// class range_formatter +// template +// struct range-default-formatter // constexpr void constexpr void set_brackets(basic_string_view opening, -// basic_string_view closing); - -// Note this tests the basics of this function. It's tested in more detail in -// the format functions test. +// basic_string_view closing) noexcept; #include #include @@ -40,8 +36,10 @@ template constexpr void test_setter() { - std::range_formatter formatter; + std::formatter, CharT> formatter; formatter.set_brackets(SV("open"), SV("close")); + // Note the SV macro may throw, so can't use it. + static_assert(noexcept(formatter.set_brackets(std::basic_string_view{}, std::basic_string_view{}))); // Note there is no direct way to validate this function modified the object. if (!std::is_constant_evaluated()) { diff --git a/libcxx/test/std/utilities/format/format.range/format.range.formatter/set_separator.pass.cpp b/libcxx/test/std/utilities/format/format.range/format.range.fmtdef/set_separator.pass.cpp copy from libcxx/test/std/utilities/format/format.range/format.range.formatter/set_separator.pass.cpp copy to libcxx/test/std/utilities/format/format.range/format.range.fmtdef/set_separator.pass.cpp --- a/libcxx/test/std/utilities/format/format.range/format.range.formatter/set_separator.pass.cpp +++ b/libcxx/test/std/utilities/format/format.range/format.range.fmtdef/set_separator.pass.cpp @@ -17,14 +17,10 @@ // -// template -// requires same_as, T> && formattable -// class range_formatter +// template +// struct range-default-formatter -// constexpr void set_separator(basic_string_view sep); - -// Note this tests the basics of this function. It's tested in more detail in -// the format functions test. +// constexpr void set_separator(basic_string_view sep) noexcept; #include #include @@ -39,8 +35,10 @@ template constexpr void test_setter() { - std::range_formatter formatter; + std::formatter, CharT> formatter; formatter.set_separator(SV("sep")); + // Note the SV macro may throw, so can't use it. + static_assert(noexcept(formatter.set_separator(std::basic_string_view{}))); // Note there is no direct way to validate this function modified the object. if (!std::is_constant_evaluated()) { diff --git a/libcxx/test/std/utilities/format/format.range/format.range.formatter/set_brackets.pass.cpp b/libcxx/test/std/utilities/format/format.range/format.range.formatter/set_brackets.pass.cpp --- a/libcxx/test/std/utilities/format/format.range/format.range.formatter/set_brackets.pass.cpp +++ b/libcxx/test/std/utilities/format/format.range/format.range.formatter/set_brackets.pass.cpp @@ -22,7 +22,7 @@ // class range_formatter // constexpr void constexpr void set_brackets(basic_string_view opening, -// basic_string_view closing); +// basic_string_view closing) noexcept; // Note this tests the basics of this function. It's tested in more detail in // the format functions test. @@ -42,6 +42,8 @@ constexpr void test_setter() { std::range_formatter formatter; formatter.set_brackets(SV("open"), SV("close")); + // Note the SV macro may throw, so can't use it. + static_assert(noexcept(formatter.set_brackets(std::basic_string_view{}, std::basic_string_view{}))); // Note there is no direct way to validate this function modified the object. if (!std::is_constant_evaluated()) { diff --git a/libcxx/test/std/utilities/format/format.range/format.range.formatter/set_separator.pass.cpp b/libcxx/test/std/utilities/format/format.range/format.range.formatter/set_separator.pass.cpp --- a/libcxx/test/std/utilities/format/format.range/format.range.formatter/set_separator.pass.cpp +++ b/libcxx/test/std/utilities/format/format.range/format.range.formatter/set_separator.pass.cpp @@ -21,7 +21,7 @@ // requires same_as, T> && formattable // class range_formatter -// constexpr void set_separator(basic_string_view sep); +// constexpr void set_separator(basic_string_view sep) noexcept; // Note this tests the basics of this function. It's tested in more detail in // the format functions test. @@ -41,6 +41,8 @@ constexpr void test_setter() { std::range_formatter formatter; formatter.set_separator(SV("sep")); + // Note the SV macro may throw, so can't use it. + static_assert(noexcept(formatter.set_separator(std::basic_string_view{}))); // Note there is no direct way to validate this function modified the object. if (!std::is_constant_evaluated()) { diff --git a/libcxx/test/std/utilities/format/format.range/format.range.formatter/underlying.pass.cpp b/libcxx/test/std/utilities/format/format.range/format.range.formatter/underlying.pass.cpp --- a/libcxx/test/std/utilities/format/format.range/format.range.formatter/underlying.pass.cpp +++ b/libcxx/test/std/utilities/format/format.range/format.range.formatter/underlying.pass.cpp @@ -21,8 +21,8 @@ // requires same_as, T> && formattable // class range_formatter -// constexpr formatter& underlying(); -// constexpr const formatter& underlying() const; +// constexpr formatter& underlying() noexcept; +// constexpr const formatter& underlying() const noexcept; #include #include @@ -34,10 +34,12 @@ { std::range_formatter formatter; [[maybe_unused]] std::same_as&> decltype(auto) underlying = formatter.underlying(); + static_assert(noexcept(formatter.underlying())); } { const std::range_formatter formatter; [[maybe_unused]] std::same_as&> decltype(auto) underlying = formatter.underlying(); + static_assert(noexcept(formatter.underlying())); } } diff --git a/libcxx/test/std/utilities/format/format.tuple/set_brackets.pass.cpp b/libcxx/test/std/utilities/format/format.tuple/set_brackets.pass.cpp --- a/libcxx/test/std/utilities/format/format.tuple/set_brackets.pass.cpp +++ b/libcxx/test/std/utilities/format/format.tuple/set_brackets.pass.cpp @@ -21,7 +21,7 @@ // struct formatter, charT> // constexpr void constexpr void set_brackets(basic_string_view opening, -// basic_string_view closing); +// basic_string_view closing) noexcept; // Note this tests the basics of this function. It's tested in more detail in // the format functions tests. @@ -38,6 +38,8 @@ constexpr void test() { std::formatter formatter; formatter.set_brackets(SV("open"), SV("close")); + // Note the SV macro may throw, so can't use it. + static_assert(noexcept(formatter.set_brackets(std::basic_string_view{}, std::basic_string_view{}))); // Note there is no direct way to validate this function modified the object. } diff --git a/libcxx/test/std/utilities/format/format.tuple/set_separator.pass.cpp b/libcxx/test/std/utilities/format/format.tuple/set_separator.pass.cpp --- a/libcxx/test/std/utilities/format/format.tuple/set_separator.pass.cpp +++ b/libcxx/test/std/utilities/format/format.tuple/set_separator.pass.cpp @@ -21,7 +21,7 @@ // template... Ts> // struct formatter, charT> -// constexpr void set_separator(basic_string_view sep); +// constexpr void set_separator(basic_string_view sep) noexcept; // Note this tests the basics of this function. It's tested in more detail in // the format functions tests. @@ -38,6 +38,8 @@ constexpr void test() { std::formatter formatter; formatter.set_separator(SV("sep")); + // Note the SV macro may throw, so can't use it. + static_assert(noexcept(formatter.set_separator(std::basic_string_view{}))); // Note there is no direct way to validate this function modified the object. }