[libc++][type_traits] Implements "A type trait to detect reference binding to temporary" (#128649)
Implements partially: [P2255R2: A type trait to detect reference binding to temporary](https://wg21.link/P2255R2) Issue: https://github.com/llvm/llvm-project/issues/105180 https://eel.is/c++draft/meta.type.synop https://eel.is/c++draft/meta.unary.prop Implented type traits: - [x] `reference_constructs_from_temporary` - [x] `reference_converts_from_temporary` Closes #129049 Minor drive-by tweak to `std::is_implicit_lifetime` tests. --------- Co-authored-by: Hristo Hristov <zingam@outlook.com>
This commit is contained in:
@@ -41,6 +41,7 @@ Implemented Papers
|
||||
- N4258: Cleaning-up noexcept in the Library (`Github <https://github.com/llvm/llvm-project/issues/99937>`__)
|
||||
- P0767R1: Deprecate POD (`Github <https://github.com/llvm/llvm-project/issues/104013>`__)
|
||||
- P1361R2: Integration of chrono with text formatting (`Github <https://github.com/llvm/llvm-project/issues/100014>`__)
|
||||
- P2255R2: A type trait to detect reference binding to temporary (implemented the type traits only) (`Github <https://github.com/llvm/llvm-project/issues/105180>`)
|
||||
|
||||
Improvements and New Features
|
||||
-----------------------------
|
||||
|
||||
@@ -43,7 +43,7 @@
|
||||
"`P0627R6 <https://wg21.link/P0627R6>`__","Function to mark unreachable code","2022-02 (Virtual)","|Complete|","15",""
|
||||
"`P1206R7 <https://wg21.link/P1206R7>`__","``ranges::to``: A function to convert any range to a container","2022-02 (Virtual)","|Complete|","17",""
|
||||
"`P1413R3 <https://wg21.link/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 <https://wg21.link/P2255R2>`__","A type trait to detect reference binding to temporary","2022-02 (Virtual)","","",""
|
||||
"`P2255R2 <https://wg21.link/P2255R2>`__","A type trait to detect reference binding to temporary","2022-02 (Virtual)","|Partial|","","Implemented the type traits only."
|
||||
"`P2273R3 <https://wg21.link/P2273R3>`__","Making ``std::unique_ptr`` constexpr","2022-02 (Virtual)","|Complete|","16",""
|
||||
"`P2387R3 <https://wg21.link/P2387R3>`__","Pipe support for user-defined range adaptors","2022-02 (Virtual)","|Complete|","19",""
|
||||
"`P2440R1 <https://wg21.link/P2440R1>`__","``ranges::iota``, ``ranges::shift_left`` and ``ranges::shift_right``","2022-02 (Virtual)","","",""
|
||||
|
||||
|
@@ -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
|
||||
|
||||
@@ -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 <class _Tp, class _Up>
|
||||
struct _LIBCPP_TEMPLATE_VIS _LIBCPP_NO_SPECIALIZATIONS reference_constructs_from_temporary
|
||||
: public bool_constant<__reference_constructs_from_temporary(_Tp, _Up)> {};
|
||||
|
||||
template <class _Tp, class _Up>
|
||||
_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
|
||||
@@ -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 <class _Tp, class _Up>
|
||||
struct _LIBCPP_TEMPLATE_VIS _LIBCPP_NO_SPECIALIZATIONS reference_converts_from_temporary
|
||||
: public bool_constant<__reference_converts_from_temporary(_Tp, _Up)> {};
|
||||
|
||||
template <class _Tp, class _Up>
|
||||
_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
|
||||
@@ -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" }
|
||||
|
||||
@@ -143,6 +143,9 @@ namespace std
|
||||
|
||||
template<class T> struct has_unique_object_representations; // C++17
|
||||
|
||||
template<class T, class U> struct reference_constructs_from_temporary; // Since C++23
|
||||
template<class T, class U> struct reference_converts_from_temporary; // Since C++23
|
||||
|
||||
// Relationships between types:
|
||||
template <class T, class U> struct is_same;
|
||||
template <class Base, class Derived> struct is_base_of;
|
||||
@@ -382,6 +385,12 @@ namespace std
|
||||
= has_virtual_destructor<T>::value; // C++17
|
||||
template<class T> inline constexpr bool has_unique_object_representations_v // C++17
|
||||
= has_unique_object_representations<T>::value;
|
||||
template<class T, class U>
|
||||
constexpr bool reference_constructs_from_temporary_v
|
||||
= reference_constructs_from_temporary<T, U>::value; // Since C++23
|
||||
template<class T, class U>
|
||||
constexpr bool reference_converts_from_temporary_v
|
||||
= reference_converts_from_temporary<T, U>::value; // Since C++23
|
||||
|
||||
// See C++14 20.10.5, type property queries
|
||||
template <class T> 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 <version>
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 T, class RefType = T&>
|
||||
class ConvertsToRef {
|
||||
public:
|
||||
operator RefType() const { return static_cast<RefType>(obj); }
|
||||
mutable T obj = 42;
|
||||
};
|
||||
template <class T, class RefType = T&>
|
||||
class ConvertsToRefPrivate {
|
||||
operator RefType() const { return static_cast<RefType>(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
|
||||
|
||||
@@ -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
|
||||
|
||||
// <type_traits>
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
// <type_traits>
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
// <type_traits>
|
||||
|
||||
// template<class T, class U> struct reference_constructs_from_temporary;
|
||||
|
||||
// template<class T, class U>
|
||||
// constexpr bool reference_constructs_from_temporary_v
|
||||
// = reference_constructs_from_temporary<T, U>::value;
|
||||
|
||||
#include <cassert>
|
||||
#include <type_traits>
|
||||
|
||||
#include "common.h"
|
||||
#include "test_macros.h"
|
||||
|
||||
template <typename T, typename U, bool Expected>
|
||||
constexpr void test_reference_constructs_from_temporary() {
|
||||
assert((std::reference_constructs_from_temporary<T, U>::value == Expected));
|
||||
assert((std::reference_constructs_from_temporary_v<T, U> == Expected));
|
||||
}
|
||||
|
||||
constexpr bool test() {
|
||||
test_reference_constructs_from_temporary<int&, int&, false>();
|
||||
test_reference_constructs_from_temporary<int&, int&, false>();
|
||||
test_reference_constructs_from_temporary<int&, int&&, false>();
|
||||
|
||||
test_reference_constructs_from_temporary<const int&, int&, false>();
|
||||
test_reference_constructs_from_temporary<const int&, const int&, false>();
|
||||
test_reference_constructs_from_temporary<const int&, int&&, false>();
|
||||
|
||||
test_reference_constructs_from_temporary<int&, long&, false>(); // doesn't construct
|
||||
|
||||
test_reference_constructs_from_temporary<const int&, long&, true>();
|
||||
test_reference_constructs_from_temporary<const int&, long&&, true>();
|
||||
test_reference_constructs_from_temporary<int&&, long&, true>();
|
||||
|
||||
assert((std::is_constructible_v<int&, ConvertsToRef<int, int&>>));
|
||||
test_reference_constructs_from_temporary<int&, ConvertsToRef<int, int&>, false>();
|
||||
|
||||
assert((std::is_constructible_v<int&&, ConvertsToRef<int, int&&>>));
|
||||
test_reference_constructs_from_temporary<int&&, ConvertsToRef<int, int&&>, false>();
|
||||
|
||||
assert((std::is_constructible_v<const int&, ConvertsToRef<int, const int&>>));
|
||||
test_reference_constructs_from_temporary<int&&, ConvertsToRef<int, const int&>, false>();
|
||||
|
||||
assert((std::is_constructible_v<const int&, ConvertsToRef<long, long&>>));
|
||||
test_reference_constructs_from_temporary<const int&, ConvertsToRef<long, long&>, true>();
|
||||
#ifndef TEST_COMPILER_GCC
|
||||
test_reference_constructs_from_temporary<const int&, ConvertsToRefPrivate<long, long&>, false>();
|
||||
#endif
|
||||
|
||||
// Test that it doesn't accept non-reference types as input.
|
||||
test_reference_constructs_from_temporary<int, long, false>();
|
||||
|
||||
test_reference_constructs_from_temporary<const int&, long, true>();
|
||||
|
||||
// Additional checks
|
||||
test_reference_constructs_from_temporary<const Base&, Derived, true>();
|
||||
test_reference_constructs_from_temporary<int&&, int, true>();
|
||||
test_reference_constructs_from_temporary<const int&, int, true>();
|
||||
test_reference_constructs_from_temporary<int&&, int&&, false>();
|
||||
test_reference_constructs_from_temporary<const int&, int&&, false>();
|
||||
test_reference_constructs_from_temporary<int&&, long&&, true>();
|
||||
test_reference_constructs_from_temporary<int&&, long, true>();
|
||||
|
||||
test_reference_constructs_from_temporary<int&, ExplicitConversionRef, false>();
|
||||
test_reference_constructs_from_temporary<const int&, ExplicitConversionRef, false>();
|
||||
test_reference_constructs_from_temporary<int&&, ExplicitConversionRvalueRef, false>();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int, char**) {
|
||||
test();
|
||||
static_assert(test());
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -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
|
||||
|
||||
// <type_traits>
|
||||
|
||||
// template<class T, class U> struct reference_converts_from_temporary;
|
||||
|
||||
// template<class T, class U>
|
||||
// constexpr bool reference_converts_from_temporary_v
|
||||
// = reference_converts_from_temporary<T, U>::value;
|
||||
|
||||
#include <cassert>
|
||||
#include <type_traits>
|
||||
|
||||
#include "common.h"
|
||||
#include "test_macros.h"
|
||||
|
||||
template <typename T, typename U, bool Expected>
|
||||
constexpr void test_reference_converts_from_temporary() {
|
||||
assert((std::reference_converts_from_temporary<T, U>::value == Expected));
|
||||
assert((std::reference_converts_from_temporary_v<T, U> == Expected));
|
||||
}
|
||||
|
||||
constexpr bool test() {
|
||||
test_reference_converts_from_temporary<int&, int&, false>();
|
||||
test_reference_converts_from_temporary<int&, int&, false>();
|
||||
test_reference_converts_from_temporary<int&, int&&, false>();
|
||||
|
||||
test_reference_converts_from_temporary<const int&, int&, false>();
|
||||
test_reference_converts_from_temporary<const int&, const int&, false>();
|
||||
test_reference_converts_from_temporary<const int&, int&&, false>();
|
||||
|
||||
test_reference_converts_from_temporary<int&, long&, false>(); // doesn't construct
|
||||
|
||||
test_reference_converts_from_temporary<const int&, long&, true>();
|
||||
test_reference_converts_from_temporary<const int&, long&&, true>();
|
||||
test_reference_converts_from_temporary<int&&, long&, true>();
|
||||
|
||||
assert((std::is_constructible_v<int&, ConvertsToRef<int, int&>>));
|
||||
test_reference_converts_from_temporary<int&, ConvertsToRef<int, int&>, false>();
|
||||
|
||||
assert((std::is_constructible_v<int&&, ConvertsToRef<int, int&&>>));
|
||||
test_reference_converts_from_temporary<int&&, ConvertsToRef<int, int&&>, false>();
|
||||
|
||||
assert((std::is_constructible_v<const int&, ConvertsToRef<int, const int&>>));
|
||||
test_reference_converts_from_temporary<int&&, ConvertsToRef<int, const int&>, false>();
|
||||
|
||||
assert((std::is_constructible_v<const int&, ConvertsToRef<long, long&>>));
|
||||
test_reference_converts_from_temporary<const int&, ConvertsToRef<long, long&>, true>();
|
||||
#ifndef TEST_COMPILER_GCC
|
||||
test_reference_converts_from_temporary<const int&, ConvertsToRefPrivate<long, long&>, false>();
|
||||
#endif
|
||||
|
||||
// Test that it doesn't accept non-reference types as input.
|
||||
test_reference_converts_from_temporary<int, long, false>();
|
||||
|
||||
test_reference_converts_from_temporary<const int&, long, true>();
|
||||
|
||||
// Additional checks
|
||||
test_reference_converts_from_temporary<const Base&, Derived, true>();
|
||||
test_reference_converts_from_temporary<int&&, int, true>();
|
||||
test_reference_converts_from_temporary<const int&, int, true>();
|
||||
test_reference_converts_from_temporary<int&&, int&&, false>();
|
||||
test_reference_converts_from_temporary<const int&, int&&, false>();
|
||||
test_reference_converts_from_temporary<int&&, long&&, true>();
|
||||
test_reference_converts_from_temporary<int&&, long, true>();
|
||||
|
||||
test_reference_converts_from_temporary<int&, ExplicitConversionRef, false>();
|
||||
test_reference_converts_from_temporary<const int&, ExplicitConversionRef, true>();
|
||||
test_reference_converts_from_temporary<int&&, ExplicitConversionRvalueRef, true>();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int, char**) {
|
||||
test();
|
||||
static_assert(test());
|
||||
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user