[libcxx-commits] [libcxx] [libc++][type_traits] P2647R1: A trait for implicit lifetime types (PR #106870)

Hristo Hristov via libcxx-commits libcxx-commits at lists.llvm.org
Sat Aug 31 13:39:16 PDT 2024


https://github.com/H-G-Hristov updated https://github.com/llvm/llvm-project/pull/106870

>From 87c907ec2febceebae6bd959477e20d6f8cf6508 Mon Sep 17 00:00:00 2001
From: Hristo Hristov <hghristov.rmm at gmail.com>
Date: Sat, 24 Aug 2024 23:52:42 +0300
Subject: [PATCH 1/2] [libc++][type_traits] P2647R1: A trait for implicit
 lifetime types

Implements P2674R1: https://wg21.link/P2674R1

- https://eel.is/c++draft/type.traits
  - https://eel.is/c++draft/meta.type.synop
  - https://eel.is/c++draft/meta.unary.prop
- https://eel.is/c++draft/support.limits
  - https://eel.is/c++draft/version.syn

Implementation details:
- Uses compiler intrinsic `__builtin_is_implicit_lifetime`:
  - https://github.com/llvm/llvm-project/pull/101807
- Tests based on:
    - https://github.com/llvm/llvm-project/blob/d213981c80626698a07b11ce872acba098a863d4/clang/test/SemaCXX/type-traits.cpp#L1989

References:
- Implicit-lifetime
  - Implicit-lifetime types [basic.types.general]/9: https://eel.is/c++draft/basic.types.general
  - Implicit-lifetime class [class.prop]/9: https://eel.is/c++draft/class.prop
- P0593R6 Implicit creation of objects for low-level object manipulation: https://wg21.link/P0593R6
- P1010R1 Container support for implicit lifetime types: https://wg21.link/P1010R1
- P0593R6 Implicit creation of objects for low-level object manipulation: https://wg21.link/P0593R6

Closes: #105259
---
 libcxx/include/CMakeLists.txt                 |   1 +
 .../__type_traits/is_implicit_lifetime.h      |  50 +++
 libcxx/include/type_traits                    |   8 +
 .../is_implicit_lifetime.pass.cpp             | 361 ++++++++++++++++++
 .../is_implicit_lifetime.verify.cpp           |  37 ++
 5 files changed, 457 insertions(+)
 create mode 100644 libcxx/include/__type_traits/is_implicit_lifetime.h
 create mode 100644 libcxx/test/std/utilities/meta/meta.unary/meta.unary.prop/is_implicit_lifetime.pass.cpp
 create mode 100644 libcxx/test/std/utilities/meta/meta.unary/meta.unary.prop/is_implicit_lifetime.verify.cpp

diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt
index 32579272858a8e..6c755e90214b44 100644
--- a/libcxx/include/CMakeLists.txt
+++ b/libcxx/include/CMakeLists.txt
@@ -778,6 +778,7 @@ set(files
   __type_traits/is_floating_point.h
   __type_traits/is_function.h
   __type_traits/is_fundamental.h
+  __type_traits/is_implicit_lifetime.h
   __type_traits/is_implicitly_default_constructible.h
   __type_traits/is_integral.h
   __type_traits/is_literal_type.h
diff --git a/libcxx/include/__type_traits/is_implicit_lifetime.h b/libcxx/include/__type_traits/is_implicit_lifetime.h
new file mode 100644
index 00000000000000..4cd593ebdbda60
--- /dev/null
+++ b/libcxx/include/__type_traits/is_implicit_lifetime.h
@@ -0,0 +1,50 @@
+//===----------------------------------------------------------------------===//
+//
+// 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_IMPLICIT_LIFETIME_H
+#define _LIBCPP___TYPE_TRAITS_IS_IMPLICIT_LIFETIME_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
+#  if __has_builtin(__builtin_is_implicit_lifetime)
+
+template <class _Tp>
+struct _LIBCPP_TEMPLATE_VIS is_implicit_lifetime : public bool_constant<__builtin_is_implicit_lifetime(_Tp)> {};
+
+template <class _Tp>
+inline constexpr bool is_implicit_lifetime_v = __builtin_is_implicit_lifetime(_Tp);
+
+#  else
+
+template <typename _Tp>
+struct is_implicit_lifetime
+    : std::disjunction< std::is_scalar<_Tp>,
+                        std::is_array<_Tp>,
+                        std::is_aggregate<_Tp>,
+                        std::conjunction< std::is_trivially_destructible<_Tp>,
+                                          std::disjunction< std::is_trivially_default_constructible<_Tp>,
+                                                            std::is_trivially_copy_constructible<_Tp>,
+                                                            std::is_trivially_move_constructible<_Tp>>>> {};
+
+template <class _Tp>
+inline constexpr bool is_implicit_lifetime_v = is_implicit_lifetime<_Tp>::value;
+
+#  endif
+#endif
+
+_LIBCPP_END_NAMESPACE_STD
+
+#endif // _LIBCPP___TYPE_TRAITS_IS_IMPLICIT_LIFETIME_H
diff --git a/libcxx/include/type_traits b/libcxx/include/type_traits
index 5937d4fdc9e1a7..d29721a371c39a 100644
--- a/libcxx/include/type_traits
+++ b/libcxx/include/type_traits
@@ -137,6 +137,8 @@ namespace std
     template <class T>                struct is_nothrow_swappable;      // C++17
     template <class T>                struct is_nothrow_destructible;
 
+    template<class T> struct is_implicit_lifetime;                     // Since C++23
+
     template <class T> struct has_virtual_destructor;
 
     template<class T> struct has_unique_object_representations;         // C++17
@@ -374,6 +376,8 @@ namespace std
         = is_nothrow_swappable<T>::value;                               // C++17
       template <class T> inline constexpr bool is_nothrow_destructible_v
         = is_nothrow_destructible<T>::value;                             // C++17
+      template<class T>
+        constexpr bool is_implicit_lifetime_v = is_implicit_lifetime<T>::value;   // Since C++23
       template <class T> inline constexpr bool has_virtual_destructor_v
         = has_virtual_destructor<T>::value;                              // C++17
       template<class T> inline constexpr bool has_unique_object_representations_v // C++17
@@ -517,6 +521,10 @@ namespace std
 #  include <__type_traits/unwrap_ref.h>
 #endif
 
+#if _LIBCPP_STD_VER >= 23
+#  include <__type_traits/is_implicit_lifetime.h>
+#endif
+
 #include <version>
 
 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
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
new file mode 100644
index 00000000000000..7a6af8ba28d80d
--- /dev/null
+++ b/libcxx/test/std/utilities/meta/meta.unary/meta.unary.prop/is_implicit_lifetime.pass.cpp
@@ -0,0 +1,361 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+
+// <type_traits>
+
+// template<class T> struct is_implicit_lifetime;
+
+#include <cassert>
+#include <cstddef>
+#include <tuple>
+#include <type_traits>
+#include <utility>
+
+#include "test_macros.h"
+
+enum Enum { EV };
+enum SignedEnum : signed int {};
+enum UnsignedEnum : unsigned int {};
+
+enum class EnumClass { EV };
+enum class SignedEnumClass : signed int {};
+enum class UnsignedEnumClass : unsigned int {};
+
+struct EmptyStruct {};
+struct IncompleteStruct;
+
+struct NoEligibleTrivialContructor {
+  NoEligibleTrivialContructor() {};
+  NoEligibleTrivialContructor(const NoEligibleTrivialContructor&) {}
+  NoEligibleTrivialContructor(NoEligibleTrivialContructor&&) {}
+};
+
+struct OnlyDefaultConstructorIsTrivial {
+  OnlyDefaultConstructorIsTrivial() = default;
+  OnlyDefaultConstructorIsTrivial(const OnlyDefaultConstructorIsTrivial&) {}
+  OnlyDefaultConstructorIsTrivial(OnlyDefaultConstructorIsTrivial&&) {}
+};
+
+struct AllContstructorsAreTrivial {
+  AllContstructorsAreTrivial()                                  = default;
+  AllContstructorsAreTrivial(const AllContstructorsAreTrivial&) = default;
+  AllContstructorsAreTrivial(AllContstructorsAreTrivial&&)      = default;
+};
+
+struct InheritedNoEligibleTrivialConstructor : NoEligibleTrivialContructor {
+  using NoEligibleTrivialContructor::NoEligibleTrivialContructor;
+};
+
+struct InheritedOnlyDefaultConstructorIsTrivial : OnlyDefaultConstructorIsTrivial {
+  using OnlyDefaultConstructorIsTrivial::OnlyDefaultConstructorIsTrivial;
+};
+
+struct InheritedAllContstructorsAreTrivial : AllContstructorsAreTrivial {
+  using AllContstructorsAreTrivial::AllContstructorsAreTrivial;
+};
+
+struct UserDeclaredDestructor {
+  ~UserDeclaredDestructor() = default;
+};
+
+struct UserProvidedDestructor {
+  ~UserProvidedDestructor() {}
+};
+
+struct UserDeletedDestructorInAggregate {
+  ~UserDeletedDestructorInAggregate() = delete;
+};
+
+struct UserDeletedDestructorInNonAggregate {
+  virtual void NonAggregate();
+  ~UserDeletedDestructorInNonAggregate() = delete;
+};
+
+struct DeletedDestructorViaBaseInAggregate : UserDeletedDestructorInAggregate {};
+struct DeletedDestructorViaBaseInNonAggregate : UserDeletedDestructorInNonAggregate {};
+
+template <bool B>
+struct ConstrainedUserDeclaredDefaultConstructor {
+  ConstrainedUserDeclaredDefaultConstructor()
+    requires B
+  = default;
+  ConstrainedUserDeclaredDefaultConstructor(const ConstrainedUserDeclaredDefaultConstructor&) {}
+};
+
+template <bool B>
+struct ConstrainedUserProvidedDestructor {
+  ~ConstrainedUserProvidedDestructor() = default;
+  ~ConstrainedUserProvidedDestructor()
+    requires B
+  {}
+};
+
+struct StructWithFlexibleArrayMember {
+  int arr[];
+};
+
+struct StructWithZeroSizedArray {
+  int arr[0];
+};
+
+#ifdef TEST_COMPILER_CLANG
+// typedef int *align_value_int __attribute__((align_value(16)));
+using AlignValueInt = int* __attribute__((align_value(16)));
+// typedef float float4 __attribute__((ext_vector_type(4)));
+using Float4 = float __attribute__((ext_vector_type(4)));
+
+struct [[clang::enforce_read_only_placement]] EnforceReadOnlyPlacement {};
+struct [[clang::type_visibility("hidden")]] TypeVisibility {};
+#endif
+
+// Test implicit-lifetime type
+template <typename T, bool Expected>
+constexpr void test_is_implicit_lifetime() {
+  static_assert(std::is_implicit_lifetime<T>::value == Expected);
+
+  // Runtime check
+  assert(std::is_implicit_lifetime_v<T> == Expected);
+}
+
+// Test pointer, reference, array, etc. types
+template <typename T>
+constexpr void test_is_implicit_lifetime() {
+  test_is_implicit_lifetime<T, true>();
+
+  // cv-qualified
+  test_is_implicit_lifetime<const T, true>();
+  test_is_implicit_lifetime<volatile T, true>();
+
+  test_is_implicit_lifetime<T&, false>();
+  test_is_implicit_lifetime<T&&, false>();
+
+  // Pointer types
+  test_is_implicit_lifetime<T*, true>();
+  test_is_implicit_lifetime<T* __restrict, true>();
+
+  // Arrays
+  test_is_implicit_lifetime<T[], true>();
+  test_is_implicit_lifetime<T[0], true>();
+  test_is_implicit_lifetime<T[94], true>();
+}
+
+// #ifdef TEST_COMPILER_CLANG
+// // Test language extensions: attributes
+// template <typename T>
+// constexpr void test_is_implicit_lifetime_with_attributes() {
+//   test_is_implicit_lifetime<T [[clang::annotate_type("category2")]]*, true>();
+//   test_is_implicit_lifetime<T __attribute__((btf_type_tag("user")))*, true>();
+//   static_assert(__builtin_is_implicit_lifetime(int __attribute__((btf_type_tag("user"))) *));
+
+//   test_is_implicit_lifetime<T __attribute__((noderef))*, true>();
+
+//   test_is_implicit_lifetime<T* _Nonnull, true>();
+//   test_is_implicit_lifetime<T* _Null_unspecified, true>();
+//   test_is_implicit_lifetime<T* _Nullable, true>();
+// }
+// #endif // TEST_COMPILER_CLANG
+
+constexpr bool test() {
+  // Standard fundamental C++ types
+
+  test_is_implicit_lifetime<decltype(nullptr), true>();
+  test_is_implicit_lifetime<std::nullptr_t, true>();
+
+  test_is_implicit_lifetime<void, false>();
+  test_is_implicit_lifetime<const void, false>();
+  test_is_implicit_lifetime<volatile void, false>();
+
+  test_is_implicit_lifetime<bool>();
+
+  test_is_implicit_lifetime<char>();
+  test_is_implicit_lifetime<signed char>();
+  test_is_implicit_lifetime<unsigned char>();
+
+#if !defined(TEST_HAS_NO_WIDE_CHARACTERS)
+  test_is_implicit_lifetime<wchar_t>();
+#endif
+
+#if !defined(TEST_HAS_NO_CHAR8_T)
+  test_is_implicit_lifetime<char8_t>();
+#endif
+  test_is_implicit_lifetime<char16_t>();
+  test_is_implicit_lifetime<char32_t>();
+
+  // test_is_implicit_lifetime<int, true>();
+  // test_is_implicit_lifetime<int&, false>();
+  // test_is_implicit_lifetime<int&&, false>();
+
+  // test_is_implicit_lifetime<int*, true>();
+  // test_is_implicit_lifetime<int[], true>();
+  // test_is_implicit_lifetime<int[0], true>();
+  // test_is_implicit_lifetime<int[94], true>();
+  test_is_implicit_lifetime<short>();
+  test_is_implicit_lifetime<short int>();
+  test_is_implicit_lifetime<signed short>();
+  test_is_implicit_lifetime<signed short int>();
+  test_is_implicit_lifetime<unsigned short>();
+  test_is_implicit_lifetime<unsigned short int>();
+  test_is_implicit_lifetime<int>();
+  test_is_implicit_lifetime<signed>();
+  test_is_implicit_lifetime<signed int>();
+  test_is_implicit_lifetime<unsigned>();
+  test_is_implicit_lifetime<unsigned int>();
+  test_is_implicit_lifetime<long>();
+  test_is_implicit_lifetime<long int>();
+  test_is_implicit_lifetime<signed long>();
+  test_is_implicit_lifetime<signed long int>();
+  test_is_implicit_lifetime<unsigned long>();
+  test_is_implicit_lifetime<unsigned long int>();
+  test_is_implicit_lifetime<long long>();
+  test_is_implicit_lifetime<long long int>();
+  test_is_implicit_lifetime<signed long long>();
+  test_is_implicit_lifetime<signed long long int>();
+  test_is_implicit_lifetime<unsigned long long>();
+  test_is_implicit_lifetime<unsigned long long int>();
+
+  test_is_implicit_lifetime<float>();
+  test_is_implicit_lifetime<double>();
+  test_is_implicit_lifetime<long double>();
+
+  test_is_implicit_lifetime<Enum>();
+  test_is_implicit_lifetime<SignedEnum>();
+  test_is_implicit_lifetime<UnsignedEnum>();
+
+  test_is_implicit_lifetime<EnumClass>();
+  test_is_implicit_lifetime<SignedEnumClass>();
+  test_is_implicit_lifetime<UnsignedEnumClass>();
+
+  test_is_implicit_lifetime<void(), false>();
+  test_is_implicit_lifetime<void()&, false>();
+  test_is_implicit_lifetime<void() const, false>();
+  test_is_implicit_lifetime<void (&)(), false>();
+  test_is_implicit_lifetime<void (*)(), true>();
+
+  // test_is_implicit_lifetime<int UserDeclaredDestructor::*, true>();
+  // test_is_implicit_lifetime<int (UserDeclaredDestructor::*)(), true>();
+  // test_is_implicit_lifetime<int (UserDeclaredDestructor::*)() const, true>();
+  // test_is_implicit_lifetime<int (UserDeclaredDestructor::*)()&, true>();
+  // test_is_implicit_lifetime<int (UserDeclaredDestructor::*)()&&, true>();
+
+  // Implicit-lifetime class types
+
+  test_is_implicit_lifetime<EmptyStruct>();
+  test_is_implicit_lifetime<int EmptyStruct::*, true>(); // Pointer-to-member
+  test_is_implicit_lifetime<int (EmptyStruct::*)(), true>();
+  test_is_implicit_lifetime<int (EmptyStruct::*)() const, true>();
+  test_is_implicit_lifetime<int (EmptyStruct::*)()&, true>();
+  test_is_implicit_lifetime<int (EmptyStruct::*)()&&, true>();
+
+  test_is_implicit_lifetime<IncompleteStruct[], true>();
+  test_is_implicit_lifetime<IncompleteStruct[82], true>();
+
+  test_is_implicit_lifetime<UserDeclaredDestructor>();
+
+  test_is_implicit_lifetime<UserProvidedDestructor, false>();
+
+  test_is_implicit_lifetime<NoEligibleTrivialContructor, false>();
+
+  test_is_implicit_lifetime<OnlyDefaultConstructorIsTrivial, true>();
+
+  test_is_implicit_lifetime<AllContstructorsAreTrivial, true>();
+
+  test_is_implicit_lifetime<InheritedNoEligibleTrivialConstructor, false>();
+
+  test_is_implicit_lifetime<InheritedOnlyDefaultConstructorIsTrivial, true>();
+
+  test_is_implicit_lifetime<InheritedAllContstructorsAreTrivial, true>();
+
+  test_is_implicit_lifetime<UserDeletedDestructorInAggregate, true>();
+
+  test_is_implicit_lifetime<UserDeletedDestructorInNonAggregate, false>();
+
+  test_is_implicit_lifetime<DeletedDestructorViaBaseInAggregate, true>();
+
+  test_is_implicit_lifetime<DeletedDestructorViaBaseInNonAggregate, false>();
+
+  test_is_implicit_lifetime<ConstrainedUserDeclaredDefaultConstructor<true>, true>();
+  test_is_implicit_lifetime<ConstrainedUserDeclaredDefaultConstructor<false>, false>();
+
+  test_is_implicit_lifetime<ConstrainedUserProvidedDestructor<true>, false>();
+  test_is_implicit_lifetime<ConstrainedUserProvidedDestructor<false>, true>();
+
+  test_is_implicit_lifetime<StructWithFlexibleArrayMember, true>();
+
+  test_is_implicit_lifetime<StructWithZeroSizedArray, true>();
+
+  // C++ standard library types
+
+  test_is_implicit_lifetime<std::pair<int, float>>();
+  test_is_implicit_lifetime<std::tuple<int, float>>();
+
+  // Standard C types
+
+  test_is_implicit_lifetime<_Complex float>();
+  test_is_implicit_lifetime<_Complex double>();
+  test_is_implicit_lifetime<_Complex long double>();
+
+  // test_is_implicit_lifetime<_Imaginary float>();
+  // test_is_implicit_lifetime<_Imaginary double>();
+  // test_is_implicit_lifetime<_Imaginary long double>();
+
+  // Standard C23 types
+
+#ifdef TEST_COMPILER_CLANG
+  test_is_implicit_lifetime<_BitInt(8)>();
+  test_is_implicit_lifetime<_BitInt(128)>();
+#endif
+
+  // Language extensions: Types
+
+#if !defined(TEST_HAS_NO_INT128)
+  test_is_implicit_lifetime<__int128_t>();
+  test_is_implicit_lifetime<__uint128_t>();
+#endif
+
+  // #if  __STDC_VERSION__ >= 20
+  // #endif
+
+#ifdef TEST_COMPILER_CLANG
+  // https://clang.llvm.org/docs/LanguageExtensions.html#half-precision-floating-point
+  test_is_implicit_lifetime<__fp16>();
+  test_is_implicit_lifetime<__bf16>();
+#endif // TEST_COMPILER_CLANG
+
+  // Language extensions: Attributes
+
+#ifdef TEST_COMPILER_CLANG
+  test_is_implicit_lifetime<AlignValueInt, true>();
+  test_is_implicit_lifetime<Float4, true>();
+
+  test_is_implicit_lifetime<EnforceReadOnlyPlacement, true>();
+  test_is_implicit_lifetime<TypeVisibility, true>();
+
+  // test_is_implicit_lifetime_with_attributes<int>();
+  // test_is_implicit_lifetime_with_attributes<float>();
+
+  test_is_implicit_lifetime<int [[clang::annotate_type("category2")]]*, true>();
+  test_is_implicit_lifetime<int __attribute__((btf_type_tag("user")))*, true>();
+
+  test_is_implicit_lifetime<int __attribute__((noderef))*, true>();
+
+  test_is_implicit_lifetime<int* _Nonnull, true>();
+  test_is_implicit_lifetime<int* _Null_unspecified, true>();
+  test_is_implicit_lifetime<int* _Nullable, true>();
+#endif // TEST_COMPILER_CLANG
+
+  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/is_implicit_lifetime.verify.cpp b/libcxx/test/std/utilities/meta/meta.unary/meta.unary.prop/is_implicit_lifetime.verify.cpp
new file mode 100644
index 00000000000000..c557731b91a67f
--- /dev/null
+++ b/libcxx/test/std/utilities/meta/meta.unary/meta.unary.prop/is_implicit_lifetime.verify.cpp
@@ -0,0 +1,37 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+
+// <type_traits>
+
+// template<class T> struct is_implicit_lifetime;
+
+#include <cassert>
+#include <cstddef>
+#include <type_traits>
+
+#include "test_macros.h"
+
+struct IncompleteStruct;
+
+// expected-error@*:* {{incomplete type 'IncompleteStruct' used in type trait expression}}
+static_assert(!std::is_implicit_lifetime<IncompleteStruct>::value);
+
+// expected-error@*:* {{atomic types are not supported in '__builtin_is_implicit_lifetime'}}
+static_assert(!std::is_implicit_lifetime<_Atomic int>::value);
+
+#if 0
+// FIXME: "variable length arrays in C++ are a Clang extension"
+void test(int n) {
+  int varArr[n];
+  using VarArrT = decltype(varArr);
+  // expected-error@*:* {{variable length arrays are not supported in '__builtin_is_implicit_lifetime'}}
+  static_assert(std::is_implicit_lifetime<VarArrT>::value);
+}
+#endif

>From 0ab51dc3bb07d6cc9627193bfc0a4d57bac7b4c6 Mon Sep 17 00:00:00 2001
From: Hristo Hristov <hghristov.rmm at gmail.com>
Date: Sat, 31 Aug 2024 23:18:20 +0300
Subject: [PATCH 2/2] Cleanup + FTM

---
 .../is_implicit_lifetime.pass.cpp             | 41 +------------------
 .../is_implicit_lifetime.verify.cpp           | 10 -----
 .../generate_feature_test_macro_components.py |  8 ++++
 3 files changed, 9 insertions(+), 50 deletions(-)

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 7a6af8ba28d80d..2b98b724e6e2e0 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
@@ -106,10 +106,8 @@ struct StructWithZeroSizedArray {
 };
 
 #ifdef TEST_COMPILER_CLANG
-// typedef int *align_value_int __attribute__((align_value(16)));
 using AlignValueInt = int* __attribute__((align_value(16)));
-// typedef float float4 __attribute__((ext_vector_type(4)));
-using Float4 = float __attribute__((ext_vector_type(4)));
+using Float4        = float __attribute__((ext_vector_type(4)));
 
 struct [[clang::enforce_read_only_placement]] EnforceReadOnlyPlacement {};
 struct [[clang::type_visibility("hidden")]] TypeVisibility {};
@@ -146,22 +144,6 @@ constexpr void test_is_implicit_lifetime() {
   test_is_implicit_lifetime<T[94], true>();
 }
 
-// #ifdef TEST_COMPILER_CLANG
-// // Test language extensions: attributes
-// template <typename T>
-// constexpr void test_is_implicit_lifetime_with_attributes() {
-//   test_is_implicit_lifetime<T [[clang::annotate_type("category2")]]*, true>();
-//   test_is_implicit_lifetime<T __attribute__((btf_type_tag("user")))*, true>();
-//   static_assert(__builtin_is_implicit_lifetime(int __attribute__((btf_type_tag("user"))) *));
-
-//   test_is_implicit_lifetime<T __attribute__((noderef))*, true>();
-
-//   test_is_implicit_lifetime<T* _Nonnull, true>();
-//   test_is_implicit_lifetime<T* _Null_unspecified, true>();
-//   test_is_implicit_lifetime<T* _Nullable, true>();
-// }
-// #endif // TEST_COMPILER_CLANG
-
 constexpr bool test() {
   // Standard fundamental C++ types
 
@@ -188,14 +170,6 @@ constexpr bool test() {
   test_is_implicit_lifetime<char16_t>();
   test_is_implicit_lifetime<char32_t>();
 
-  // test_is_implicit_lifetime<int, true>();
-  // test_is_implicit_lifetime<int&, false>();
-  // test_is_implicit_lifetime<int&&, false>();
-
-  // test_is_implicit_lifetime<int*, true>();
-  // test_is_implicit_lifetime<int[], true>();
-  // test_is_implicit_lifetime<int[0], true>();
-  // test_is_implicit_lifetime<int[94], true>();
   test_is_implicit_lifetime<short>();
   test_is_implicit_lifetime<short int>();
   test_is_implicit_lifetime<signed short>();
@@ -238,12 +212,6 @@ constexpr bool test() {
   test_is_implicit_lifetime<void (&)(), false>();
   test_is_implicit_lifetime<void (*)(), true>();
 
-  // test_is_implicit_lifetime<int UserDeclaredDestructor::*, true>();
-  // test_is_implicit_lifetime<int (UserDeclaredDestructor::*)(), true>();
-  // test_is_implicit_lifetime<int (UserDeclaredDestructor::*)() const, true>();
-  // test_is_implicit_lifetime<int (UserDeclaredDestructor::*)()&, true>();
-  // test_is_implicit_lifetime<int (UserDeclaredDestructor::*)()&&, true>();
-
   // Implicit-lifetime class types
 
   test_is_implicit_lifetime<EmptyStruct>();
@@ -301,10 +269,6 @@ constexpr bool test() {
   test_is_implicit_lifetime<_Complex double>();
   test_is_implicit_lifetime<_Complex long double>();
 
-  // test_is_implicit_lifetime<_Imaginary float>();
-  // test_is_implicit_lifetime<_Imaginary double>();
-  // test_is_implicit_lifetime<_Imaginary long double>();
-
   // Standard C23 types
 
 #ifdef TEST_COMPILER_CLANG
@@ -337,9 +301,6 @@ constexpr bool test() {
   test_is_implicit_lifetime<EnforceReadOnlyPlacement, true>();
   test_is_implicit_lifetime<TypeVisibility, true>();
 
-  // test_is_implicit_lifetime_with_attributes<int>();
-  // test_is_implicit_lifetime_with_attributes<float>();
-
   test_is_implicit_lifetime<int [[clang::annotate_type("category2")]]*, true>();
   test_is_implicit_lifetime<int __attribute__((btf_type_tag("user")))*, true>();
 
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 c557731b91a67f..41d6ad254cd7b0 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
@@ -25,13 +25,3 @@ static_assert(!std::is_implicit_lifetime<IncompleteStruct>::value);
 
 // expected-error@*:* {{atomic types are not supported in '__builtin_is_implicit_lifetime'}}
 static_assert(!std::is_implicit_lifetime<_Atomic int>::value);
-
-#if 0
-// FIXME: "variable length arrays in C++ are a Clang extension"
-void test(int n) {
-  int varArr[n];
-  using VarArrT = decltype(varArr);
-  // expected-error@*:* {{variable length arrays are not supported in '__builtin_is_implicit_lifetime'}}
-  static_assert(std::is_implicit_lifetime<VarArrT>::value);
-}
-#endif
diff --git a/libcxx/utils/generate_feature_test_macro_components.py b/libcxx/utils/generate_feature_test_macro_components.py
index 3bdd3adad15b4e..6e687906e22cb7 100755
--- a/libcxx/utils/generate_feature_test_macro_components.py
+++ b/libcxx/utils/generate_feature_test_macro_components.py
@@ -742,6 +742,14 @@ def add_version_header(tc):
             "values": {"c++14": 201402},
             "headers": ["type_traits"],
         },
+        {
+            "name": "__cpp_lib_is_implicit_lifetime",
+            "values": {"c++23": 202302},
+            "headers": ["type_traits"],
+            "test_suite_guard": "__has_builtin(__builtin_is_implicit_lifetime)",
+            "libcxx_guard": "__has_builtin(__builtin_is_implicit_lifetime)",
+            "unimplemented": True,
+        },    
         {
             "name": "__cpp_lib_is_invocable",
             "values": {"c++17": 201703},



More information about the libcxx-commits mailing list