Skip to content

[libc++][format] P2637R3: Member visit (std::basic_format_arg) #76449

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

Merged
merged 44 commits into from
Jan 21, 2024
Merged
Show file tree
Hide file tree
Changes from 41 commits
Commits
Show all changes
44 commits
Select commit Hold shift + click to select a range
e1ab389
[libc++][format] P2637R3: Member visit
Zingam Dec 25, 2023
0764fb3
Implemented member methods + WIP tests
Zingam Dec 26, 2023
7a70aa6
Added `visit` with return type test WIP
Zingam Dec 26, 2023
fbdd8ac
WIP: visit.return_type.pass
Zingam Dec 26, 2023
91348f1
WIP: visit.return_type.pass
Zingam Dec 27, 2023
ebab5b6
Fixed formatting
Zingam Dec 27, 2023
1b8e407
Fixed formatting
Zingam Dec 27, 2023
a6e6aaa
Restored: visit_format_arg.pass.cpp + docs upate
Zingam Dec 29, 2023
9301ae0
Addressed comments
Zingam Dec 29, 2023
7f7c0c1
Fixed tests
Zingam Dec 29, 2023
ede04db
Added missing test cases
Zingam Dec 29, 2023
30ee407
Fixed implementation of `__int128/__uint128`
Zingam Dec 29, 2023
94aa9c0
Fixed deprecation warning errors
Zingam Dec 30, 2023
1ee4bde
Fixed get.pass.cpp test
Zingam Dec 30, 2023
eb0bc0b
Addressed comments
Zingam Dec 31, 2023
6e85ab6
Restored original formatting
Zingam Dec 31, 2023
d7d8eef
Merge branch 'main' into hgh/libcxx/P2637R3-member-visit-format
Zingam Dec 31, 2023
4eb32fd
Restored formatting: get.pass.cpp
Zingam Dec 31, 2023
9308255
Merge branch 'main' into hgh/libcxx/P2637R3-member-visit-format
Zingam Jan 11, 2024
8c95988
Merge branch 'main' into hgh/libcxx/P2637R3-member-visit-format
Zingam Jan 17, 2024
0007da3
Merge branch 'main' into hgh/libcxx/P2637R3-member-visit-format
H-G-Hristov Jan 17, 2024
274319f
Merge branch 'main' into hgh/libcxx/P2637R3-member-visit-format
H-G-Hristov Jan 17, 2024
87b46db
Try to fix CI
Zingam Jan 17, 2024
4e770de
Merge branch 'main' into hgh/libcxx/P2637R3-member-visit-format
H-G-Hristov Jan 17, 2024
b2200ef
Try to fix CI
Zingam Jan 17, 2024
4d9b6f3
Merge branch 'main' into hgh/libcxx/P2637R3-member-visit-format
H-G-Hristov Jan 17, 2024
e46c448
Merge branch 'main' into hgh/libcxx/P2637R3-member-visit-format
H-G-Hristov Jan 18, 2024
3ea7346
Fix AIX and ARM CI
Zingam Jan 18, 2024
3d02036
Merge branch 'hgh/libcxx/P2637R3-member-visit-format' of https://gith…
Zingam Jan 18, 2024
cd99382
Merge branch 'main' into hgh/libcxx/P2637R3-member-visit-format
H-G-Hristov Jan 18, 2024
cfd5f65
Try to fix CI
Zingam Jan 18, 2024
fb1c24c
Addressed comments
Zingam Jan 18, 2024
ffc1020
Revert Feature Test Macro (FTM) uses
Zingam Jan 18, 2024
e5228fa
Merge branch 'main' into hgh/libcxx/P2637R3-member-visit-format
H-G-Hristov Jan 18, 2024
6f7535e
Update libcxx/test/support/test_basic_format_arg.h
H-G-Hristov Jan 18, 2024
dd7f629
Added `TEST_HAS_EXPLICIT_THIS_PARAMETER` and `_LIBCPP_HAS_EXPLICIT_TH…
Zingam Jan 20, 2024
7eac0af
Quick fix
Zingam Jan 20, 2024
ed2be27
Unsupport tests on *apple-clang*
Zingam Jan 20, 2024
fa467ec
Merge branch 'main' into hgh/libcxx/P2637R3-member-visit-format
Zingam Jan 20, 2024
654afb9
Fixed formatting
Zingam Jan 20, 2024
e73184c
Fixed mistake
Zingam Jan 20, 2024
152a22b
Merge branch 'main' into hgh/libcxx/P2637R3-member-visit-format
H-G-Hristov Jan 20, 2024
c4c0639
Addressed comments
Zingam Jan 20, 2024
d8f7657
Merge branch 'main' into hgh/libcxx/P2637R3-member-visit-format
Zingam Jan 21, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions libcxx/docs/ReleaseNotes/18.rst
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ Implemented Papers
- P1759R6 - Native handles and file streams
- P2868R3 - Remove Deprecated ``std::allocator`` Typedef From C++26
- P2517R1 - Add a conditional ``noexcept`` specification to ``std::apply``
- P2637R3 - Member ``visit``
- P2447R6 - ``span`` over initializer list


Expand Down
2 changes: 1 addition & 1 deletion libcxx/docs/Status/Cxx2cPapers.csv
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
"`P0792R14 <https://wg21.link/P0792R14>`__","LWG","``function_ref``: a type-erased callable reference","Varna June 2023","","",""
"`P2874R2 <https://wg21.link/P2874R2>`__","LWG","Mandating Annex D Require No More","Varna June 2023","","",""
"`P2757R3 <https://wg21.link/P2757R3>`__","LWG","Type-checking format args","Varna June 2023","","","|format|"
"`P2637R3 <https://wg21.link/P2637R3>`__","LWG","Member ``visit``","Varna June 2023","","","|format|"
"`P2637R3 <https://wg21.link/P2637R3>`__","LWG","Member ``visit``","Varna June 2023","|Complete|","18.0",""
"`P2641R4 <https://wg21.link/P2641R4>`__","CWG, LWG","Checking if a ``union`` alternative is active","Varna June 2023","","",""
"`P1759R6 <https://wg21.link/P1759R6>`__","LWG","Native handles and file streams","Varna June 2023","|Complete|","18.0",""
"`P2697R1 <https://wg21.link/P2697R1>`__","LWG","Interfacing ``bitset`` with ``string_view``","Varna June 2023","|Complete|","18.0",""
Expand Down
2 changes: 1 addition & 1 deletion libcxx/docs/Status/FormatIssues.csv
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ Number,Name,Standard,Assignee,Status,First released version
"`P2693R1 <https://wg21.link/P2693R1>`__","Formatting ``thread::id`` and ``stacktrace``","C++23","Mark de Wever","|In Progress|"
"`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","","",
"`P2637R3 <https://wg21.link/P2637R3>`__","Member ``visit``","C++26","Hristo Hristov","|Complete|",18.0
"`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","|Complete|",18.0
Expand Down
11 changes: 11 additions & 0 deletions libcxx/include/__config
Original file line number Diff line number Diff line change
Expand Up @@ -984,6 +984,12 @@ typedef __char32_t char32_t;
# define _LIBCPP_DEPRECATED_IN_CXX23
# endif

# if _LIBCPP_STD_VER >= 26
# define _LIBCPP_DEPRECATED_IN_CXX26 _LIBCPP_DEPRECATED
# else
# define _LIBCPP_DEPRECATED_IN_CXX26
# endif

# if !defined(_LIBCPP_HAS_NO_CHAR8_T)
# define _LIBCPP_DEPRECATED_WITH_CHAR8_T _LIBCPP_DEPRECATED
# else
Expand Down Expand Up @@ -1513,6 +1519,11 @@ __sanitizer_verify_double_ended_contiguous_container(const void*, const void*, c
# define _LIBCPP_DISABLE_UBSAN_UNSIGNED_INTEGER_CHECK
# endif

// Clang-18 has support for deducing this, but it does not set the FTM.
#if defined(__cpp_explicit_this_parameter) || (defined(_LIBCPP_CLANG_VER ) &&_LIBCPP_CLANG_VER >= 1800)
# define _LIBCPP_HAS_EXPLICIT_THIS_PARAMETER
#endif

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please make sure merging this patch does not duplicate this entry.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Of course!

#endif // __cplusplus

#endif // _LIBCPP___CONFIG
109 changes: 106 additions & 3 deletions libcxx/include/__format/format_arg.h
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ _LIBCPP_HIDE_FROM_ABI constexpr __arg_t __get_packed_type(uint64_t __types, size

} // namespace __format

// This function is not user obervable, so it can directly use the non-standard
// This function is not user observable, so it can directly use the non-standard
// types of the "variant". See __arg_t for more details.
template <class _Visitor, class _Context>
_LIBCPP_HIDE_FROM_ABI decltype(auto) __visit_format_arg(_Visitor&& __vis, basic_format_arg<_Context> __arg) {
Expand Down Expand Up @@ -144,6 +144,59 @@ _LIBCPP_HIDE_FROM_ABI decltype(auto) __visit_format_arg(_Visitor&& __vis, basic_
__libcpp_unreachable();
}

# if _LIBCPP_STD_VER >= 26 && defined(_LIBCPP_HAS_EXPLICIT_THIS_PARAMETER)

template <class _Rp, class _Visitor, class _Context>
_LIBCPP_HIDE_FROM_ABI _Rp __visit_format_arg(_Visitor&& __vis, basic_format_arg<_Context> __arg) {
switch (__arg.__type_) {
case __format::__arg_t::__none:
return std::invoke_r<_Rp>(std::forward<_Visitor>(__vis), __arg.__value_.__monostate_);
case __format::__arg_t::__boolean:
return std::invoke_r<_Rp>(std::forward<_Visitor>(__vis), __arg.__value_.__boolean_);
case __format::__arg_t::__char_type:
return std::invoke_r<_Rp>(std::forward<_Visitor>(__vis), __arg.__value_.__char_type_);
case __format::__arg_t::__int:
return std::invoke_r<_Rp>(std::forward<_Visitor>(__vis), __arg.__value_.__int_);
case __format::__arg_t::__long_long:
return std::invoke_r<_Rp>(std::forward<_Visitor>(__vis), __arg.__value_.__long_long_);
case __format::__arg_t::__i128:
# ifndef _LIBCPP_HAS_NO_INT128
return std::invoke_r<_Rp>(std::forward<_Visitor>(__vis), __arg.__value_.__i128_);
# else
__libcpp_unreachable();
# endif
case __format::__arg_t::__unsigned:
return std::invoke_r<_Rp>(std::forward<_Visitor>(__vis), __arg.__value_.__unsigned_);
case __format::__arg_t::__unsigned_long_long:
return std::invoke_r<_Rp>(std::forward<_Visitor>(__vis), __arg.__value_.__unsigned_long_long_);
case __format::__arg_t::__u128:
# ifndef _LIBCPP_HAS_NO_INT128
return std::invoke_r<_Rp>(std::forward<_Visitor>(__vis), __arg.__value_.__u128_);
# else
__libcpp_unreachable();
# endif
case __format::__arg_t::__float:
return std::invoke_r<_Rp>(std::forward<_Visitor>(__vis), __arg.__value_.__float_);
case __format::__arg_t::__double:
return std::invoke_r<_Rp>(std::forward<_Visitor>(__vis), __arg.__value_.__double_);
case __format::__arg_t::__long_double:
return std::invoke_r<_Rp>(std::forward<_Visitor>(__vis), __arg.__value_.__long_double_);
case __format::__arg_t::__const_char_type_ptr:
return std::invoke_r<_Rp>(std::forward<_Visitor>(__vis), __arg.__value_.__const_char_type_ptr_);
case __format::__arg_t::__string_view:
return std::invoke_r<_Rp>(std::forward<_Visitor>(__vis), __arg.__value_.__string_view_);
case __format::__arg_t::__ptr:
return std::invoke_r<_Rp>(std::forward<_Visitor>(__vis), __arg.__value_.__ptr_);
case __format::__arg_t::__handle:
return std::invoke_r<_Rp>(
std::forward<_Visitor>(__vis), typename basic_format_arg<_Context>::handle{__arg.__value_.__handle_});
}

__libcpp_unreachable();
}

# endif // _LIBCPP_STD_VER >= 26 && defined(_LIBCPP_HAS_EXPLICIT_THIS_PARAMETER)

/// Contains the values used in basic_format_arg.
///
/// This is a separate type so it's possible to store the values and types in
Expand Down Expand Up @@ -227,6 +280,52 @@ class _LIBCPP_TEMPLATE_VIS basic_format_arg {

_LIBCPP_HIDE_FROM_ABI explicit operator bool() const noexcept { return __type_ != __format::__arg_t::__none; }

# if _LIBCPP_STD_VER >= 26 && defined(_LIBCPP_HAS_EXPLICIT_THIS_PARAMETER)

// This function is user facing, so it must wrap the non-standard types of
// the "variant" in a handle to stay conforming. See __arg_t for more details.
template <class _Visitor>
_LIBCPP_HIDE_FROM_ABI decltype(auto) visit(this basic_format_arg __arg, _Visitor&& __vis) {
switch (__arg.__type_) {
# ifndef _LIBCPP_HAS_NO_INT128
case __format::__arg_t::__i128: {
typename __basic_format_arg_value<_Context>::__handle __h{__arg.__value_.__i128_};
return std::invoke(std::forward<_Visitor>(__vis), typename basic_format_arg<_Context>::handle{__h});
}

case __format::__arg_t::__u128: {
typename __basic_format_arg_value<_Context>::__handle __h{__arg.__value_.__u128_};
return std::invoke(std::forward<_Visitor>(__vis), typename basic_format_arg<_Context>::handle{__h});
}
# endif
default:
return std::__visit_format_arg(std::forward<_Visitor>(__vis), __arg);
}
}

// This function is user facing, so it must wrap the non-standard types of
// the "variant" in a handle to stay conforming. See __arg_t for more details.
template <class _Rp, class _Visitor>
_LIBCPP_HIDE_FROM_ABI _Rp visit(this basic_format_arg __arg, _Visitor&& __vis) {
switch (__arg.__type_) {
# ifndef _LIBCPP_HAS_NO_INT128
case __format::__arg_t::__i128: {
typename __basic_format_arg_value<_Context>::__handle __h{__arg.__value_.__i128_};
return std::invoke_r<_Rp>(std::forward<_Visitor>(__vis), typename basic_format_arg<_Context>::handle{__h});
}

case __format::__arg_t::__u128: {
typename __basic_format_arg_value<_Context>::__handle __h{__arg.__value_.__u128_};
return std::invoke_r<_Rp>(std::forward<_Visitor>(__vis), typename basic_format_arg<_Context>::handle{__h});
}
# endif
default:
return std::__visit_format_arg<_Rp>(std::forward<_Visitor>(__vis), __arg);
}
}

# endif // _LIBCPP_STD_VER >= 26 && defined(_LIBCPP_HAS_EXPLICIT_THIS_PARAMETER)

private:
using char_type = typename _Context::char_type;

Expand Down Expand Up @@ -267,7 +366,11 @@ class _LIBCPP_TEMPLATE_VIS basic_format_arg<_Context>::handle {
// This function is user facing, so it must wrap the non-standard types of
// the "variant" in a handle to stay conforming. See __arg_t for more details.
template <class _Visitor, class _Context>
_LIBCPP_HIDE_FROM_ABI decltype(auto) visit_format_arg(_Visitor&& __vis, basic_format_arg<_Context> __arg) {
# if _LIBCPP_STD_VER >= 26 && defined(_LIBCPP_HAS_EXPLICIT_THIS_PARAMETER)
_LIBCPP_DEPRECATED_IN_CXX26
# endif
_LIBCPP_HIDE_FROM_ABI decltype(auto)
visit_format_arg(_Visitor&& __vis, basic_format_arg<_Context> __arg) {
switch (__arg.__type_) {
# ifndef _LIBCPP_HAS_NO_INT128
case __format::__arg_t::__i128: {
Expand All @@ -279,7 +382,7 @@ _LIBCPP_HIDE_FROM_ABI decltype(auto) visit_format_arg(_Visitor&& __vis, basic_fo
typename __basic_format_arg_value<_Context>::__handle __h{__arg.__value_.__u128_};
return std::invoke(std::forward<_Visitor>(__vis), typename basic_format_arg<_Context>::handle{__h});
}
# endif
# endif // _LIBCPP_STD_VER >= 26 && defined(_LIBCPP_HAS_EXPLICIT_THIS_PARAMETER)
default:
return std::__visit_format_arg(std::forward<_Visitor>(__vis), __arg);
}
Expand Down
33 changes: 19 additions & 14 deletions libcxx/include/__format/format_context.h
Original file line number Diff line number Diff line change
Expand Up @@ -163,20 +163,25 @@ class _LIBCPP_TEMPLATE_VIS basic_format_context<typename __format::__retarget_bu
# endif
__ctx_(std::addressof(__ctx)),
__arg_([](void* __c, size_t __id) {
return std::visit_format_arg(
[&](auto __arg) -> basic_format_arg<basic_format_context> {
if constexpr (same_as<decltype(__arg), monostate>)
return {};
else if constexpr (same_as<decltype(__arg), typename basic_format_arg<_Context>::handle>)
// At the moment it's not possible for formatting to use a re-targeted handle.
// TODO FMT add this when support is needed.
std::__throw_format_error("Re-targeting handle not supported");
else
return basic_format_arg<basic_format_context>{
__format::__determine_arg_t<basic_format_context, decltype(__arg)>(),
__basic_format_arg_value<basic_format_context>(__arg)};
},
static_cast<_Context*>(__c)->arg(__id));
auto __visitor = [&](auto __arg) -> basic_format_arg<basic_format_context> {
if constexpr (same_as<decltype(__arg), monostate>)
return {};
else if constexpr (same_as<decltype(__arg), typename basic_format_arg<_Context>::handle>)
// At the moment it's not possible for formatting to use a re-targeted handle.
// TODO FMT add this when support is needed.
std::__throw_format_error("Re-targeting handle not supported");
else
return basic_format_arg<basic_format_context>{
__format::__determine_arg_t<basic_format_context, decltype(__arg)>(),
__basic_format_arg_value<basic_format_context>(__arg)};
};
# if _LIBCPP_STD_VER >= 26 && defined(_LIBCPP_HAS_EXPLICIT_THIS_PARAMETER)
return static_cast<_Context*>(__c)->arg(__id).visit(std::move(__visitor));
# else
_LIBCPP_SUPPRESS_DEPRECATED_PUSH
return std::visit_format_arg(std::move(__visitor), static_cast<_Context*>(__c)->arg(__id));
_LIBCPP_SUPPRESS_DEPRECATED_POP
# endif // _LIBCPP_STD_VER >= 26 && defined(_LIBCPP_HAS_EXPLICIT_THIS_PARAMETER)
}) {
}

Expand Down
2 changes: 1 addition & 1 deletion libcxx/include/format
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,7 @@ namespace std {
template<class Context> class basic_format_arg;

template<class Visitor, class Context>
see below visit_format_arg(Visitor&& vis, basic_format_arg<Context> arg);
see below visit_format_arg(Visitor&& vis, basic_format_arg<Context> arg); // Deprecated in C++26

// [format.arg.store], class template format-arg-store
template<class Context, class... Args> struct format-arg-store; // exposition only
Expand Down
Loading