diff --git a/libcxx/docs/ReleaseNotes/21.rst b/libcxx/docs/ReleaseNotes/21.rst index c45adbaec3953..a1100f0630382 100644 --- a/libcxx/docs/ReleaseNotes/21.rst +++ b/libcxx/docs/ReleaseNotes/21.rst @@ -41,6 +41,7 @@ Implemented Papers - N4258: Cleaning-up noexcept in the Library (`Github `__) - P0767R1: Deprecate POD (`Github `__) - P1361R2: Integration of chrono with text formatting (`Github `__) +- P2255R2: A type trait to detect reference binding to temporary (implemented the type traits only) (`Github `) Improvements and New Features ----------------------------- diff --git a/libcxx/docs/Status/Cxx23Papers.csv b/libcxx/docs/Status/Cxx23Papers.csv index bfaa63a7c224e..0f3db57788b49 100644 --- a/libcxx/docs/Status/Cxx23Papers.csv +++ b/libcxx/docs/Status/Cxx23Papers.csv @@ -43,7 +43,7 @@ "`P0627R6 `__","Function to mark unreachable code","2022-02 (Virtual)","|Complete|","15","" "`P1206R7 `__","``ranges::to``: A function to convert any range to a container","2022-02 (Virtual)","|Complete|","17","" "`P1413R3 `__","Deprecate ``std::aligned_storage`` and ``std::aligned_union``","2022-02 (Virtual)","|Complete|","","``std::aligned_storage_t`` and ``std::aligned_union_t`` are marked deprecated, but clang doesn't issue a diagnostic for deprecated using template declarations." -"`P2255R2 `__","A type trait to detect reference binding to temporary","2022-02 (Virtual)","","","" +"`P2255R2 `__","A type trait to detect reference binding to temporary","2022-02 (Virtual)","|Partial|","","Implemented the type traits only." "`P2273R3 `__","Making ``std::unique_ptr`` constexpr","2022-02 (Virtual)","|Complete|","16","" "`P2387R3 `__","Pipe support for user-defined range adaptors","2022-02 (Virtual)","|Complete|","19","" "`P2440R1 `__","``ranges::iota``, ``ranges::shift_left`` and ``ranges::shift_right``","2022-02 (Virtual)","","","" diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt index ee1d7b872b364..d7c36d6b438fb 100644 --- a/libcxx/include/CMakeLists.txt +++ b/libcxx/include/CMakeLists.txt @@ -867,6 +867,8 @@ set(files __type_traits/negation.h __type_traits/promote.h __type_traits/rank.h + __type_traits/reference_constructs_from_temporary.h + __type_traits/reference_converts_from_temporary.h __type_traits/remove_all_extents.h __type_traits/remove_const.h __type_traits/remove_const_ref.h diff --git a/libcxx/include/__type_traits/reference_constructs_from_temporary.h b/libcxx/include/__type_traits/reference_constructs_from_temporary.h new file mode 100644 index 0000000000000..1666032b89bed --- /dev/null +++ b/libcxx/include/__type_traits/reference_constructs_from_temporary.h @@ -0,0 +1,35 @@ +//===----------------------------------------------------------------------===// +// +// 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_REFERENCE_CONSTRUCTS_FROM_TEMPORARY_H +#define _LIBCPP___TYPE_TRAITS_REFERENCE_CONSTRUCTS_FROM_TEMPORARY_H + +#include <__config> +#include <__type_traits/integral_constant.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER >= 23 && __has_builtin(__reference_constructs_from_temporary) + +template +struct _LIBCPP_TEMPLATE_VIS _LIBCPP_NO_SPECIALIZATIONS reference_constructs_from_temporary + : public bool_constant<__reference_constructs_from_temporary(_Tp, _Up)> {}; + +template +_LIBCPP_NO_SPECIALIZATIONS inline constexpr bool reference_constructs_from_temporary_v = + __reference_constructs_from_temporary(_Tp, _Up); + +#endif + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___TYPE_TRAITS_REFERENCE_CONSTRUCTS_FROM_TEMPORARY_H diff --git a/libcxx/include/__type_traits/reference_converts_from_temporary.h b/libcxx/include/__type_traits/reference_converts_from_temporary.h new file mode 100644 index 0000000000000..043bdbf38dada --- /dev/null +++ b/libcxx/include/__type_traits/reference_converts_from_temporary.h @@ -0,0 +1,35 @@ +//===----------------------------------------------------------------------===// +// +// 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_REFERENCE_CONVERTS_FROM_TEMPORARY_H +#define _LIBCPP___TYPE_TRAITS_REFERENCE_CONVERTS_FROM_TEMPORARY_H + +#include <__config> +#include <__type_traits/integral_constant.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER >= 23 && __has_builtin(__reference_converts_from_temporary) + +template +struct _LIBCPP_TEMPLATE_VIS _LIBCPP_NO_SPECIALIZATIONS reference_converts_from_temporary + : public bool_constant<__reference_converts_from_temporary(_Tp, _Up)> {}; + +template +_LIBCPP_NO_SPECIALIZATIONS inline constexpr bool reference_converts_from_temporary_v = + __reference_converts_from_temporary(_Tp, _Up); + +#endif + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___TYPE_TRAITS_REFERENCE_CONVERTS_FROM_TEMPORARY_H diff --git a/libcxx/include/module.modulemap b/libcxx/include/module.modulemap index 81c7378d9e3b8..b9964dac84acd 100644 --- a/libcxx/include/module.modulemap +++ b/libcxx/include/module.modulemap @@ -369,6 +369,14 @@ module std_core [system] { module negation { header "__type_traits/negation.h" } module promote { header "__type_traits/promote.h" } module rank { header "__type_traits/rank.h" } + module reference_constructs_from_temporary { + header "__type_traits/reference_constructs_from_temporary.h" + export std_core.type_traits.integral_constant + } + module reference_converts_from_temporary { + header "__type_traits/reference_converts_from_temporary.h" + export std_core.type_traits.integral_constant + } module remove_all_extents { header "__type_traits/remove_all_extents.h" } module remove_const_ref { header "__type_traits/remove_const_ref.h" } module remove_const { header "__type_traits/remove_const.h" } diff --git a/libcxx/include/type_traits b/libcxx/include/type_traits index 772e4cb876469..e09a911eeb313 100644 --- a/libcxx/include/type_traits +++ b/libcxx/include/type_traits @@ -143,6 +143,9 @@ namespace std template struct has_unique_object_representations; // C++17 + template struct reference_constructs_from_temporary; // Since C++23 + template struct reference_converts_from_temporary; // Since C++23 + // Relationships between types: template struct is_same; template struct is_base_of; @@ -382,6 +385,12 @@ namespace std = has_virtual_destructor::value; // C++17 template inline constexpr bool has_unique_object_representations_v // C++17 = has_unique_object_representations::value; + template + constexpr bool reference_constructs_from_temporary_v + = reference_constructs_from_temporary::value; // Since C++23 + template + constexpr bool reference_converts_from_temporary_v + = reference_converts_from_temporary::value; // Since C++23 // See C++14 20.10.5, type property queries template inline constexpr size_t alignment_of_v @@ -523,6 +532,8 @@ namespace std # if _LIBCPP_STD_VER >= 23 # include <__type_traits/is_implicit_lifetime.h> +# include <__type_traits/reference_constructs_from_temporary.h> +# include <__type_traits/reference_converts_from_temporary.h> # endif # include diff --git a/libcxx/modules/std/type_traits.inc b/libcxx/modules/std/type_traits.inc index f544f95c7aaaa..6823c86ed153b 100644 --- a/libcxx/modules/std/type_traits.inc +++ b/libcxx/modules/std/type_traits.inc @@ -106,8 +106,14 @@ export namespace std { using std::has_unique_object_representations; - // using std::reference_constructs_from_temporary; - // using std::reference_converts_from_temporary; +#if _LIBCPP_STD_VER >= 23 +# if __has_builtin(__reference_constructs_from_temporary) + using std::reference_constructs_from_temporary; +# endif +# if __has_builtin(__reference_converts_from_temporary) + using std::reference_converts_from_temporary; +# endif +#endif // [meta.unary.prop.query], type property queries using std::alignment_of; @@ -284,8 +290,14 @@ export namespace std { using std::is_unbounded_array_v; using std::is_unsigned_v; using std::is_volatile_v; - // using std::reference_constructs_from_temporary_v; - // using std::reference_converts_from_temporary_v; +#if _LIBCPP_STD_VER >= 23 +# if __has_builtin(__reference_constructs_from_temporary) + using std::reference_constructs_from_temporary_v; +# endif +# if __has_builtin(__reference_converts_from_temporary) + using std::reference_converts_from_temporary_v; +# endif +#endif // [meta.unary.prop.query], type property queries using std::alignment_of_v; diff --git a/libcxx/test/std/utilities/meta/meta.unary/meta.unary.prop/common.h b/libcxx/test/std/utilities/meta/meta.unary/meta.unary.prop/common.h index be9149de89a6c..b51444915a5c5 100644 --- a/libcxx/test/std/utilities/meta/meta.unary/meta.unary.prop/common.h +++ b/libcxx/test/std/utilities/meta/meta.unary/meta.unary.prop/common.h @@ -39,9 +39,52 @@ struct A { A& operator=(const A&); }; -class Abstract -{ - virtual ~Abstract() = 0; +class Abstract { + virtual ~Abstract() = 0; }; +// Types for reference_{constructs/converts}_from_temporary + +#if TEST_STD_VER >= 23 + +class NonPODClass { +public: + NonPODClass(int); +}; +enum Enum { EV }; +struct Base { + Enum e; + int i; + float f; + NonPODClass* p; +}; +// Not PODs +struct Derived : Base {}; + +template +class ConvertsToRef { +public: + operator RefType() const { return static_cast(obj); } + mutable T obj = 42; +}; +template +class ConvertsToRefPrivate { + operator RefType() const { return static_cast(obj); } + mutable T obj = 42; +}; + +class ExplicitConversionRvalueRef { +public: + operator int(); + explicit operator int&&(); +}; + +class ExplicitConversionRef { +public: + operator int(); + explicit operator int&(); +}; + +#endif + #endif // TEST_META_UNARY_COMP_COMMON_H diff --git a/libcxx/test/std/utilities/meta/meta.unary/meta.unary.prop/is_implicit_lifetime.pass.cpp b/libcxx/test/std/utilities/meta/meta.unary/meta.unary.prop/is_implicit_lifetime.pass.cpp index 681ad13a07dfd..24adec37431e7 100644 --- a/libcxx/test/std/utilities/meta/meta.unary/meta.unary.prop/is_implicit_lifetime.pass.cpp +++ b/libcxx/test/std/utilities/meta/meta.unary/meta.unary.prop/is_implicit_lifetime.pass.cpp @@ -9,7 +9,7 @@ // UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 // These compilers don't support __builtin_is_implicit_lifetime yet. -// UNSUPPORTED: clang-18, clang-19, gcc-14, apple-clang-15, apple-clang-16, apple-clang-17 +// UNSUPPORTED: clang-18, clang-19, gcc-14, apple-clang-15, apple-clang-16 // diff --git a/libcxx/test/std/utilities/meta/meta.unary/meta.unary.prop/is_implicit_lifetime.verify.cpp b/libcxx/test/std/utilities/meta/meta.unary/meta.unary.prop/is_implicit_lifetime.verify.cpp index 34462f9bf0ec6..4bcb10d0b7579 100644 --- a/libcxx/test/std/utilities/meta/meta.unary/meta.unary.prop/is_implicit_lifetime.verify.cpp +++ b/libcxx/test/std/utilities/meta/meta.unary/meta.unary.prop/is_implicit_lifetime.verify.cpp @@ -9,7 +9,7 @@ // UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 // These compilers don't support __builtin_is_implicit_lifetime yet. -// UNSUPPORTED: clang-18, clang-19, gcc-14, apple-clang-15, apple-clang-16, apple-clang-17 +// UNSUPPORTED: clang-18, clang-19, gcc-14, apple-clang-15, apple-clang-16 // diff --git a/libcxx/test/std/utilities/meta/meta.unary/meta.unary.prop/reference_constructs_from_temporary.pass.cpp b/libcxx/test/std/utilities/meta/meta.unary/meta.unary.prop/reference_constructs_from_temporary.pass.cpp new file mode 100644 index 0000000000000..5b3753c67381f --- /dev/null +++ b/libcxx/test/std/utilities/meta/meta.unary/meta.unary.prop/reference_constructs_from_temporary.pass.cpp @@ -0,0 +1,90 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +// REQUIRES: std-at-least-c++23 + +// These compilers don't support std::reference_converts_from_temporary yet. +// UNSUPPORTED: android, apple-clang-15, apple-clang-16, clang-19.1 + +// + +// template struct reference_constructs_from_temporary; + +// template +// constexpr bool reference_constructs_from_temporary_v +// = reference_constructs_from_temporary::value; + +#include +#include + +#include "common.h" +#include "test_macros.h" + +template +constexpr void test_reference_constructs_from_temporary() { + assert((std::reference_constructs_from_temporary::value == Expected)); + assert((std::reference_constructs_from_temporary_v == Expected)); +} + +constexpr bool test() { + test_reference_constructs_from_temporary(); + test_reference_constructs_from_temporary(); + test_reference_constructs_from_temporary(); + + test_reference_constructs_from_temporary(); + test_reference_constructs_from_temporary(); + test_reference_constructs_from_temporary(); + + test_reference_constructs_from_temporary(); // doesn't construct + + test_reference_constructs_from_temporary(); + test_reference_constructs_from_temporary(); + test_reference_constructs_from_temporary(); + + assert((std::is_constructible_v>)); + test_reference_constructs_from_temporary, false>(); + + assert((std::is_constructible_v>)); + test_reference_constructs_from_temporary, false>(); + + assert((std::is_constructible_v>)); + test_reference_constructs_from_temporary, false>(); + + assert((std::is_constructible_v>)); + test_reference_constructs_from_temporary, true>(); +#ifndef TEST_COMPILER_GCC + test_reference_constructs_from_temporary, false>(); +#endif + + // Test that it doesn't accept non-reference types as input. + test_reference_constructs_from_temporary(); + + test_reference_constructs_from_temporary(); + + // Additional checks + test_reference_constructs_from_temporary(); + test_reference_constructs_from_temporary(); + test_reference_constructs_from_temporary(); + test_reference_constructs_from_temporary(); + test_reference_constructs_from_temporary(); + test_reference_constructs_from_temporary(); + test_reference_constructs_from_temporary(); + + test_reference_constructs_from_temporary(); + test_reference_constructs_from_temporary(); + test_reference_constructs_from_temporary(); + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + + return 0; +} diff --git a/libcxx/test/std/utilities/meta/meta.unary/meta.unary.prop/reference_converts_from_temporary.pass.cpp b/libcxx/test/std/utilities/meta/meta.unary/meta.unary.prop/reference_converts_from_temporary.pass.cpp new file mode 100644 index 0000000000000..849e286c8cdab --- /dev/null +++ b/libcxx/test/std/utilities/meta/meta.unary/meta.unary.prop/reference_converts_from_temporary.pass.cpp @@ -0,0 +1,90 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +// REQUIRES: std-at-least-c++23 + +// These compilers don't support std::reference_converts_from_temporary yet. +// UNSUPPORTED: android, apple-clang-15, apple-clang-16, clang-18, clang-19.1 + +// + +// template struct reference_converts_from_temporary; + +// template +// constexpr bool reference_converts_from_temporary_v +// = reference_converts_from_temporary::value; + +#include +#include + +#include "common.h" +#include "test_macros.h" + +template +constexpr void test_reference_converts_from_temporary() { + assert((std::reference_converts_from_temporary::value == Expected)); + assert((std::reference_converts_from_temporary_v == Expected)); +} + +constexpr bool test() { + test_reference_converts_from_temporary(); + test_reference_converts_from_temporary(); + test_reference_converts_from_temporary(); + + test_reference_converts_from_temporary(); + test_reference_converts_from_temporary(); + test_reference_converts_from_temporary(); + + test_reference_converts_from_temporary(); // doesn't construct + + test_reference_converts_from_temporary(); + test_reference_converts_from_temporary(); + test_reference_converts_from_temporary(); + + assert((std::is_constructible_v>)); + test_reference_converts_from_temporary, false>(); + + assert((std::is_constructible_v>)); + test_reference_converts_from_temporary, false>(); + + assert((std::is_constructible_v>)); + test_reference_converts_from_temporary, false>(); + + assert((std::is_constructible_v>)); + test_reference_converts_from_temporary, true>(); +#ifndef TEST_COMPILER_GCC + test_reference_converts_from_temporary, false>(); +#endif + + // Test that it doesn't accept non-reference types as input. + test_reference_converts_from_temporary(); + + test_reference_converts_from_temporary(); + + // Additional checks + test_reference_converts_from_temporary(); + test_reference_converts_from_temporary(); + test_reference_converts_from_temporary(); + test_reference_converts_from_temporary(); + test_reference_converts_from_temporary(); + test_reference_converts_from_temporary(); + test_reference_converts_from_temporary(); + + test_reference_converts_from_temporary(); + test_reference_converts_from_temporary(); + test_reference_converts_from_temporary(); + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + + return 0; +}