Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
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
2 changes: 2 additions & 0 deletions libcxx/docs/ReleaseNotes/22.rst
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ What's New in Libc++ 22.0.0?
Implemented Papers
------------------

- P1317R2: Remove return type deduction in ``std::apply`` (`Github <https://github.com/llvm/llvm-project/issues/148183>`__)
(Only components in ``<type_traits>`` are implemented.)
- P2321R2: ``zip`` (`Github <https://github.com/llvm/llvm-project/issues/105169>`__) (The paper is partially implemented. ``zip_transform_view`` is implemented in this release)

Improvements and New Features
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 @@ -155,5 +155,5 @@
"`P2781R9 <https://wg21.link/P2781R9>`__","``std::constant_wrapper``","2025-06 (Sofia)","","",""
"`P3697R1 <https://wg21.link/P3697R1>`__","Minor additions to C++26 standard library hardening","2025-06 (Sofia)","","",""
"`P3552R3 <https://wg21.link/P3552R3>`__","Add a Coroutine Task Type","2025-06 (Sofia)","","",""
"`P1317R2 <https://wg21.link/P1317R2>`__","Remove return type deduction in ``std::apply``","2025-06 (Sofia)","","",""
"`P1317R2 <https://wg21.link/P1317R2>`__","Remove return type deduction in ``std::apply``","2025-06 (Sofia)","|In Progress|","",""
"","","","","",""
1 change: 1 addition & 0 deletions libcxx/include/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -819,6 +819,7 @@ set(files
__type_traits/is_aggregate.h
__type_traits/is_allocator.h
__type_traits/is_always_bitcastable.h
__type_traits/is_applicable.h
__type_traits/is_arithmetic.h
__type_traits/is_array.h
__type_traits/is_assignable.h
Expand Down
115 changes: 115 additions & 0 deletions libcxx/include/__type_traits/is_applicable.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
//===----------------------------------------------------------------------===//
//
// 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
//
//===----------------------------------------------------------------------===//

#ifndef _LIBCPP___TYPE_TRAITS_IS_APPLICABLE_H
#define _LIBCPP___TYPE_TRAITS_IS_APPLICABLE_H

#include <__config>
#include <__cstddef/size_t.h>
#include <__fwd/get.h>
#include <__tuple/tuple_like.h>
#include <__tuple/tuple_size.h>
#include <__type_traits/conjunction.h>
#include <__type_traits/integral_constant.h>
#include <__type_traits/invoke.h>
#include <__type_traits/remove_reference.h>
#include <__utility/declval.h>
#include <__utility/integer_sequence.h>
Comment on lines +14 to +22
Copy link
Contributor Author

Choose a reason for hiding this comment

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

These includes seemingly heavily break module builds. I guess we need to expand the std_core module a lot.

Copy link
Member

Choose a reason for hiding this comment

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

That's a bit problematic. I almost wonder if we should put this new stuff under __tuple instead? It clearly belongs to type_traits, but putting it inside __tuple would simplify things from a modularization perspective.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Moving to __tuple and the tuple clang module didn't work as we seemingly need to build <type_traits> as a whole into std_core...


#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
# pragma GCC system_header
#endif

_LIBCPP_BEGIN_NAMESPACE_STD

#if _LIBCPP_STD_VER >= 26

template <class _Fn, class _Tuple>
struct __apply_result_disabled_base {};

template <class _Fn, class _Tuple, class _Tp>
struct __apply_result_enabled_base {
using type _LIBCPP_NODEBUG = _Tp;
};

template <bool _Applicable, bool _Nothrow, class _Tp>
struct __applicability_traits {
static constexpr bool __applicable = true;
static constexpr bool __nothrow_applicable = _Nothrow;

template <class _Fn, class _Tuple>
using __base_type _LIBCPP_NODEBUG = __apply_result_enabled_base<_Fn, _Tuple, _Tp>;
};

template <bool _Nothrow, class _Tp>
struct __applicability_traits<false, _Nothrow, _Tp> {
static_assert(!_Nothrow, "misspecified [_Applicable = false, _Nothrow = true]");
static constexpr bool __applicable = false;
static constexpr bool __nothrow_applicable = false;

template <class _Fn, class _Tuple>
using __base_type _LIBCPP_NODEBUG = __apply_result_disabled_base<_Fn, _Tuple>;
};

template <class _Fn, class _Tuple, size_t... _Is>
concept __tuple_applicable_impl = requires(_Tuple&& __tuple) {
[](auto&&...) {}(std::get<_Is>(static_cast<_Tuple &&>(__tuple))...);
} && __is_invocable_v<_Fn, decltype(std::get<_Is>(std::declval<_Tuple>()))...>;

template <class _Fn, class _Tuple, size_t... _Is>
concept __tuple_nothrow_applicable_impl = requires(_Tuple&& __tuple) {
{
[](auto&&...) noexcept {}(std::get<_Is>(static_cast<_Tuple &&>(__tuple))...)
} noexcept;
} && __is_nothrow_invocable_v<_Fn, decltype(std::get<_Is>(std::declval<_Tuple>()))...>;

template <class _Fn, class _Tuple>
consteval auto __applicability_traits_of() {
if constexpr (__tuple_like<_Tuple>)
return []<size_t... _Is>(index_sequence<_Is...>) {
if constexpr (__tuple_applicable_impl<_Fn, _Tuple, _Is...>) {
return __applicability_traits<
true,
__tuple_nothrow_applicable_impl<_Fn, _Tuple, _Is...>,
// FIXME: Use __invoke_result_y after merging https://github.com/llvm/llvm-project/pull/151028.
typename __invoke_result<_Fn, decltype(std::get<_Is>(std::declval<_Tuple>()))...>::type>{};
} else
return __applicability_traits<false, false, void>{};
}(make_index_sequence<tuple_size_v<remove_reference_t<_Tuple>>>{});
else
return __applicability_traits<false, false, void>{};
}

template <class _Fn, class _Tuple>
struct _LIBCPP_NO_SPECIALIZATIONS is_applicable
: bool_constant<decltype(std::__applicability_traits_of<_Fn, _Tuple>())::__applicable> {};

template <class _Fn, class _Tuple>
struct _LIBCPP_NO_SPECIALIZATIONS is_nothrow_applicable
: bool_constant<decltype(std::__applicability_traits_of<_Fn, _Tuple>())::__nothrow_applicable> {};

template <class _Fn, class _Tuple>
_LIBCPP_NO_SPECIALIZATIONS inline constexpr bool is_applicable_v =
decltype(std::__applicability_traits_of<_Fn, _Tuple>())::__applicable;

template <class _Fn, class _Tuple>
_LIBCPP_NO_SPECIALIZATIONS inline constexpr bool is_nothrow_applicable_v =
decltype(std::__applicability_traits_of<_Fn, _Tuple>())::__nothrow_applicable;

template <class _Fn, class _Tuple>
struct _LIBCPP_NO_SPECIALIZATIONS apply_result
: decltype(std::__applicability_traits_of<_Fn, _Tuple>())::template __base_type<_Fn, _Tuple> {};

template <class _Fn, class _Tuple>
using apply_result_t = apply_result<_Fn, _Tuple>::type;

#endif // _LIBCPP_STD_VER >= 26

_LIBCPP_END_NAMESPACE_STD

#endif // _LIBCPP___TYPE_TRAITS_IS_APPLICABLE_H
4 changes: 4 additions & 0 deletions libcxx/include/module.modulemap.in
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,10 @@ module std_core [system] {
header "__type_traits/is_always_bitcastable.h"
export std_core.type_traits.integral_constant
}
module is_applicable {
header "__type_traits/is_applicable.h"
export std_core.type_traits.integral_constant
}
module is_arithmetic {
header "__type_traits/is_arithmetic.h"
export std_core.type_traits.integral_constant
Expand Down
16 changes: 16 additions & 0 deletions libcxx/include/type_traits
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,10 @@ namespace std
template <class R, class Fn, class... ArgTypes>
struct is_nothrow_invocable_r; // since C++17

template<class Fn, class Tuple> struct is_applicable; // since C++26
template<class Fn, class Tuple>
struct is_nothrow_applicable; // since C++26

// Alignment properties and transformations:
template <class T> struct alignment_of;
template <size_t Len, size_t Align = most_stringent_alignment_requirement>
Expand All @@ -183,6 +187,7 @@ namespace std
struct result_of<Fn(ArgTypes...)>; // deprecated in C++17; removed in C++20
template <class Fn, class... ArgTypes>
struct invoke_result; // since C++17
template<class Fn, class Tuple> struct apply_result; // since C++26

// const-volatile modifications:
template <class T>
Expand Down Expand Up @@ -265,6 +270,9 @@ namespace std
template <class Fn, class... ArgTypes>
using invoke_result_t
= typename invoke_result<Fn, ArgTypes...>::type; // since C++17
template <class Fn, class... ArgTypes>
using apply_result_t
= typename invoke_result<Fn, ArgTypes...>::type; // since C++26

template <class...>
using void_t = void; // since C++17
Expand Down Expand Up @@ -442,6 +450,10 @@ namespace std
= is_nothrow_invocable<Fn, ArgTypes...>::value; // since C++17
template <class R, class Fn, class... ArgTypes> inline constexpr bool is_nothrow_invocable_r_v
= is_nothrow_invocable_r<R, Fn, ArgTypes...>::value; // since C++17
template<class Fn, class Tuple> constexpr bool is_applicable_v
= is_applicable<Fn, Tuple>::value; // since C++26
template<class Fn, class Tuple> constexpr bool is_nothrow_applicable_v
= is_nothrow_applicable<Fn, Tuple>::value; // since C++26

// [meta.logical], logical operator traits:
template<class... B> struct conjunction; // since C++17
Expand Down Expand Up @@ -559,6 +571,10 @@ namespace std
# include <__type_traits/reference_converts_from_temporary.h>
# endif

# if _LIBCPP_STD_VER >= 26
# include <__type_traits/is_applicable.h>
# endif

# include <version>

# if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
Expand Down
18 changes: 18 additions & 0 deletions libcxx/modules/std/type_traits.inc
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,9 @@ export namespace std {
using std::rank;

// [meta.rel], type relations
#if _LIBCPP_STD_VER >= 26
using std::is_applicable;
#endif
using std::is_base_of;
#if _LIBCPP_STD_VER >= 26 && __has_builtin(__builtin_is_virtual_base_of)
using std::is_virtual_base_of;
Expand All @@ -134,6 +137,9 @@ export namespace std {
using std::is_invocable;
using std::is_invocable_r;

#if _LIBCPP_STD_VER >= 26
using std::is_nothrow_applicable;
#endif
using std::is_nothrow_invocable;
using std::is_nothrow_invocable_r;

Expand Down Expand Up @@ -183,6 +189,9 @@ export namespace std {
using std::remove_pointer_t;

// [meta.trans.other], other transformations
#if _LIBCPP_STD_VER >= 26
using std::apply_result;
#endif
using std::basic_common_reference;
using std::common_reference;
using std::common_type;
Expand All @@ -196,6 +205,9 @@ export namespace std {
using std::unwrap_ref_decay;
using std::unwrap_reference;

#if _LIBCPP_STD_VER >= 26
using std::apply_result_t;
#endif
using std::common_reference_t;
using std::common_type_t;
using std::conditional_t;
Expand Down Expand Up @@ -305,6 +317,9 @@ export namespace std {
using std::rank_v;

// [meta.rel], type relations
#if _LIBCPP_STD_VER >= 26
using std::is_applicable_v;
#endif
using std::is_base_of_v;
#if _LIBCPP_STD_VER >= 26 && __has_builtin(__builtin_is_virtual_base_of)
using std::is_virtual_base_of_v;
Expand All @@ -313,6 +328,9 @@ export namespace std {
using std::is_invocable_r_v;
using std::is_invocable_v;
// using std::is_layout_compatible_v;
#if _LIBCPP_STD_VER >= 26
using std::is_nothrow_applicable_v;
#endif
using std::is_nothrow_convertible_v;
using std::is_nothrow_invocable_r_v;
using std::is_nothrow_invocable_v;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,11 @@ SPECIALIZE_TRAIT(unwrap_reference); // expected-error {{cannot be specialized}}
SPECIALIZE_TRAIT(unwrap_ref_decay); // expected-error {{cannot be specialized}}
# endif

# if TEST_STD_VER >= 26
template <>
struct std::apply_result<S, S>; // expected-error {{cannot be specialized}}
# endif

# undef SPECIALIZE_TRAIT
# define SPECIALIZE_UTT(Trait) \
template <> \
Expand Down Expand Up @@ -165,7 +170,9 @@ SPECIALIZE_BTT(reference_converts_from_temporary); // expected-error 2 {{cannot
# endif

# if TEST_STD_VER >= 26
SPECIALIZE_BTT(is_virtual_base_of); // expected-error 2 {{cannot be specialized}}
SPECIALIZE_BTT(is_applicable); // expected-error 2 {{cannot be specialized}}
SPECIALIZE_BTT(is_nothrow_applicable); // expected-error 2 {{cannot be specialized}}
SPECIALIZE_BTT(is_virtual_base_of); // expected-error 2 {{cannot be specialized}}
# endif

# undef SPECIALIZE_UTT
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -113,4 +113,6 @@ static_assert(std::is_base_of<std::false_type, std::is_scoped_enum<int>>::value,
# if defined(__cpp_lib_is_virtual_base_of) && __cpp_lib_is_virtual_base_of >= 202406L
static_assert(std::is_base_of<std::false_type, std::is_virtual_base_of<int, int>>::value, "");
# endif
static_assert(std::is_base_of<std::false_type, std::is_applicable<int, int>>::value, "");
static_assert(std::is_base_of<std::false_type, std::is_nothrow_applicable<int, int>>::value, "");
#endif
Loading
Loading