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

via libcxx-commits libcxx-commits at lists.llvm.org
Tue Oct 8 23:19:17 PDT 2024


Author: Hristo Hristov
Date: 2024-10-09T08:19:14+02:00
New Revision: a06591b4d4fb270b587fc5ef67b5a03dad752b40

URL: https://github.com/llvm/llvm-project/commit/a06591b4d4fb270b587fc5ef67b5a03dad752b40
DIFF: https://github.com/llvm/llvm-project/commit/a06591b4d4fb270b587fc5ef67b5a03dad752b40.diff

LOG: [libc++][type_traits] P2674R1: A trait for implicit lifetime types (#106870)

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

---------

Co-authored-by: Hristo Hristov <zingam at outlook.com>

Added: 
    libcxx/include/__type_traits/is_implicit_lifetime.h
    libcxx/test/std/utilities/meta/meta.unary/meta.unary.prop/is_implicit_lifetime.pass.cpp
    libcxx/test/std/utilities/meta/meta.unary/meta.unary.prop/is_implicit_lifetime.verify.cpp

Modified: 
    libcxx/docs/FeatureTestMacroTable.rst
    libcxx/docs/ReleaseNotes/20.rst
    libcxx/docs/Status/Cxx23Papers.csv
    libcxx/include/CMakeLists.txt
    libcxx/include/module.modulemap
    libcxx/include/type_traits
    libcxx/include/version
    libcxx/modules/std/type_traits.inc
    libcxx/test/std/language.support/support.limits/support.limits.general/type_traits.version.compile.pass.cpp
    libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp
    libcxx/utils/generate_feature_test_macro_components.py

Removed: 
    


################################################################################
diff  --git a/libcxx/docs/FeatureTestMacroTable.rst b/libcxx/docs/FeatureTestMacroTable.rst
index c909a4300db1a6..05b08da5215350 100644
--- a/libcxx/docs/FeatureTestMacroTable.rst
+++ b/libcxx/docs/FeatureTestMacroTable.rst
@@ -336,6 +336,8 @@ Status
     ---------------------------------------------------------- -----------------
     ``__cpp_lib_ios_noreplace``                                ``202207L``
     ---------------------------------------------------------- -----------------
+    ``__cpp_lib_is_implicit_lifetime``                         ``202302L``
+    ---------------------------------------------------------- -----------------
     ``__cpp_lib_is_scoped_enum``                               ``202011L``
     ---------------------------------------------------------- -----------------
     ``__cpp_lib_mdspan``                                       ``202207L``

diff  --git a/libcxx/docs/ReleaseNotes/20.rst b/libcxx/docs/ReleaseNotes/20.rst
index 82c8286b69e23c..dcb1102d81d641 100644
--- a/libcxx/docs/ReleaseNotes/20.rst
+++ b/libcxx/docs/ReleaseNotes/20.rst
@@ -42,6 +42,7 @@ Implemented Papers
 - P2609R3: Relaxing Ranges Just A Smidge (`Github <https://github.com/llvm/llvm-project/issues/105253>`__)
 - P2985R0: A type trait for detecting virtual base classes (`Github <https://github.com/llvm/llvm-project/issues/105432>`__)
 - ``std::jthread`` and ``<stop_token>`` are not guarded behind ``-fexperimental-library`` anymore
+- P2674R1: A trait for implicit lifetime types (`Github <https://github.com/llvm/llvm-project/issues/105259>`__)
 
 Improvements and New Features
 -----------------------------

diff  --git a/libcxx/docs/Status/Cxx23Papers.csv b/libcxx/docs/Status/Cxx23Papers.csv
index e1d7bb8f37863e..da7b5881877135 100644
--- a/libcxx/docs/Status/Cxx23Papers.csv
+++ b/libcxx/docs/Status/Cxx23Papers.csv
@@ -113,7 +113,7 @@
 "`P2572R1 <https://wg21.link/P2572R1>`__","``std::format`` fill character allowances","2023-02 (Issaquah)","|Complete|","17.0",""
 "`P2693R1 <https://wg21.link/P2693R1>`__","Formatting ``thread::id`` and ``stacktrace``","2023-02 (Issaquah)","|Partial|","","The formatter for ``stacktrace`` is not implemented, since ``stacktrace`` is not implemented yet"
 "`P2679R2 <https://wg21.link/P2679R2>`__","Fixing ``std::start_lifetime_as`` for arrays","2023-02 (Issaquah)","","",""
-"`P2674R1 <https://wg21.link/P2674R1>`__","A trait for implicit lifetime types","2023-02 (Issaquah)","","",""
+"`P2674R1 <https://wg21.link/P2674R1>`__","A trait for implicit lifetime types","2023-02 (Issaquah)","|Complete|","20.0",""
 "`P2655R3 <https://wg21.link/P2655R3>`__","``common_reference_t`` of ``reference_wrapper`` Should Be a Reference Type","2023-02 (Issaquah)","","",""
 "`P2652R2 <https://wg21.link/P2652R2>`__","Disallow User Specialization of ``allocator_traits``","2023-02 (Issaquah)","|Complete|","19.0",""
 "`P2787R1 <https://wg21.link/P2787R1>`__","``pmr::generator`` - Promise Types are not Values","2023-02 (Issaquah)","","",""

diff  --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt
index 9bd1b41b8bfac4..c2a597f49e317f 100644
--- a/libcxx/include/CMakeLists.txt
+++ b/libcxx/include/CMakeLists.txt
@@ -787,6 +787,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..2aba420bd2b59d
--- /dev/null
+++ b/libcxx/include/__type_traits/is_implicit_lifetime.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_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);
+
+#  endif
+#endif
+
+_LIBCPP_END_NAMESPACE_STD
+
+#endif // _LIBCPP___TYPE_TRAITS_IS_IMPLICIT_LIFETIME_H

diff  --git a/libcxx/include/module.modulemap b/libcxx/include/module.modulemap
index dee9b0b88b7948..22a1313498e73e 100644
--- a/libcxx/include/module.modulemap
+++ b/libcxx/include/module.modulemap
@@ -200,6 +200,10 @@ module std_core [system] {
       header "__type_traits/is_fundamental.h"
       export std_core.type_traits.integral_constant
     }
+    module is_implicit_lifetime {
+      header "__type_traits/is_implicit_lifetime.h"
+      export std_core.type_traits.integral_constant
+    }
     module is_implicitly_default_constructible {
       header "__type_traits/is_implicitly_default_constructible.h"
       export std_core.type_traits.integral_constant

diff  --git a/libcxx/include/type_traits b/libcxx/include/type_traits
index 26c85f2284e2fd..baeed35ca8508b 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
@@ -516,6 +520,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/include/version b/libcxx/include/version
index 5d679caac0b3b7..88387e311636c2 100644
--- a/libcxx/include/version
+++ b/libcxx/include/version
@@ -138,6 +138,7 @@ __cpp_lib_ios_noreplace                                 202207L <ios>
 __cpp_lib_is_aggregate                                  201703L <type_traits>
 __cpp_lib_is_constant_evaluated                         201811L <type_traits>
 __cpp_lib_is_final                                      201402L <type_traits>
+__cpp_lib_is_implicit_lifetime                          202302L <type_traits>
 __cpp_lib_is_invocable                                  201703L <type_traits>
 __cpp_lib_is_layout_compatible                          201907L <type_traits>
 __cpp_lib_is_nothrow_convertible                        201806L <type_traits>
@@ -473,6 +474,9 @@ __cpp_lib_void_t                                        201411L <type_traits>
 # define __cpp_lib_forward_like                         202207L
 # define __cpp_lib_invoke_r                             202106L
 # define __cpp_lib_ios_noreplace                        202207L
+# if __has_builtin(__builtin_is_implicit_lifetime)
+#   define __cpp_lib_is_implicit_lifetime               202302L
+# endif
 # define __cpp_lib_is_scoped_enum                       202011L
 # define __cpp_lib_mdspan                               202207L
 # define __cpp_lib_modules                              202207L

diff  --git a/libcxx/modules/std/type_traits.inc b/libcxx/modules/std/type_traits.inc
index 485a5ddf63aed0..f544f95c7aaaae 100644
--- a/libcxx/modules/std/type_traits.inc
+++ b/libcxx/modules/std/type_traits.inc
@@ -98,7 +98,9 @@ export namespace std {
 
   using std::is_nothrow_destructible;
 
-  //  using std::is_implicit_lifetime;
+#if _LIBCPP_STD_VER >= 23 && __has_builtin(__builtin_is_implicit_lifetime)
+  using std::is_implicit_lifetime;
+#endif
 
   using std::has_virtual_destructor;
 
@@ -246,7 +248,9 @@ export namespace std {
   using std::is_destructible_v;
   using std::is_empty_v;
   using std::is_final_v;
-  // using std::is_implicit_lifetime_v;
+#if _LIBCPP_STD_VER >= 23 && __has_builtin(__builtin_is_implicit_lifetime)
+  using std::is_implicit_lifetime_v;
+#endif
   using std::is_move_assignable_v;
   using std::is_move_constructible_v;
   using std::is_nothrow_assignable_v;

diff  --git a/libcxx/test/std/language.support/support.limits/support.limits.general/type_traits.version.compile.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/type_traits.version.compile.pass.cpp
index 1cbf2699a95bcc..d9d698ace2b653 100644
--- a/libcxx/test/std/language.support/support.limits/support.limits.general/type_traits.version.compile.pass.cpp
+++ b/libcxx/test/std/language.support/support.limits/support.limits.general/type_traits.version.compile.pass.cpp
@@ -23,6 +23,7 @@
     __cpp_lib_is_aggregate                         201703L [C++17]
     __cpp_lib_is_constant_evaluated                201811L [C++20]
     __cpp_lib_is_final                             201402L [C++14]
+    __cpp_lib_is_implicit_lifetime                 202302L [C++23]
     __cpp_lib_is_invocable                         201703L [C++17]
     __cpp_lib_is_layout_compatible                 201907L [C++20]
     __cpp_lib_is_nothrow_convertible               201806L [C++20]
@@ -75,6 +76,10 @@
 #   error "__cpp_lib_is_final should not be defined before c++14"
 # endif
 
+# ifdef __cpp_lib_is_implicit_lifetime
+#   error "__cpp_lib_is_implicit_lifetime should not be defined before c++23"
+# endif
+
 # ifdef __cpp_lib_is_invocable
 #   error "__cpp_lib_is_invocable should not be defined before c++17"
 # endif
@@ -179,6 +184,10 @@
 #   error "__cpp_lib_is_final should have the value 201402L in c++14"
 # endif
 
+# ifdef __cpp_lib_is_implicit_lifetime
+#   error "__cpp_lib_is_implicit_lifetime should not be defined before c++23"
+# endif
+
 # ifdef __cpp_lib_is_invocable
 #   error "__cpp_lib_is_invocable should not be defined before c++17"
 # endif
@@ -301,6 +310,10 @@
 #   error "__cpp_lib_is_final should have the value 201402L in c++17"
 # endif
 
+# ifdef __cpp_lib_is_implicit_lifetime
+#   error "__cpp_lib_is_implicit_lifetime should not be defined before c++23"
+# endif
+
 # ifndef __cpp_lib_is_invocable
 #   error "__cpp_lib_is_invocable should be defined in c++17"
 # endif
@@ -444,6 +457,10 @@
 #   error "__cpp_lib_is_final should have the value 201402L in c++20"
 # endif
 
+# ifdef __cpp_lib_is_implicit_lifetime
+#   error "__cpp_lib_is_implicit_lifetime should not be defined before c++23"
+# endif
+
 # ifndef __cpp_lib_is_invocable
 #   error "__cpp_lib_is_invocable should be defined in c++20"
 # endif
@@ -614,6 +631,19 @@
 #   error "__cpp_lib_is_final should have the value 201402L in c++23"
 # endif
 
+# if __has_builtin(__builtin_is_implicit_lifetime)
+#   ifndef __cpp_lib_is_implicit_lifetime
+#     error "__cpp_lib_is_implicit_lifetime should be defined in c++23"
+#   endif
+#   if __cpp_lib_is_implicit_lifetime != 202302L
+#     error "__cpp_lib_is_implicit_lifetime should have the value 202302L in c++23"
+#   endif
+# else
+#   ifdef __cpp_lib_is_implicit_lifetime
+#     error "__cpp_lib_is_implicit_lifetime should not be defined when the requirement '__has_builtin(__builtin_is_implicit_lifetime)' is not met!"
+#   endif
+# endif
+
 # ifndef __cpp_lib_is_invocable
 #   error "__cpp_lib_is_invocable should be defined in c++23"
 # endif
@@ -796,6 +826,19 @@
 #   error "__cpp_lib_is_final should have the value 201402L in c++26"
 # endif
 
+# if __has_builtin(__builtin_is_implicit_lifetime)
+#   ifndef __cpp_lib_is_implicit_lifetime
+#     error "__cpp_lib_is_implicit_lifetime should be defined in c++26"
+#   endif
+#   if __cpp_lib_is_implicit_lifetime != 202302L
+#     error "__cpp_lib_is_implicit_lifetime should have the value 202302L in c++26"
+#   endif
+# else
+#   ifdef __cpp_lib_is_implicit_lifetime
+#     error "__cpp_lib_is_implicit_lifetime should not be defined when the requirement '__has_builtin(__builtin_is_implicit_lifetime)' is not met!"
+#   endif
+# endif
+
 # ifndef __cpp_lib_is_invocable
 #   error "__cpp_lib_is_invocable should be defined in c++26"
 # endif

diff  --git a/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp
index 985ffeffab96db..0614f64a2ef04d 100644
--- a/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp
+++ b/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp
@@ -125,6 +125,7 @@
     __cpp_lib_is_aggregate                                  201703L [C++17]
     __cpp_lib_is_constant_evaluated                         201811L [C++20]
     __cpp_lib_is_final                                      201402L [C++14]
+    __cpp_lib_is_implicit_lifetime                          202302L [C++23]
     __cpp_lib_is_invocable                                  201703L [C++17]
     __cpp_lib_is_layout_compatible                          201907L [C++20]
     __cpp_lib_is_nothrow_convertible                        201806L [C++20]
@@ -671,6 +672,10 @@
 #   error "__cpp_lib_is_final should not be defined before c++14"
 # endif
 
+# ifdef __cpp_lib_is_implicit_lifetime
+#   error "__cpp_lib_is_implicit_lifetime should not be defined before c++23"
+# endif
+
 # ifdef __cpp_lib_is_invocable
 #   error "__cpp_lib_is_invocable should not be defined before c++17"
 # endif
@@ -1550,6 +1555,10 @@
 #   error "__cpp_lib_is_final should have the value 201402L in c++14"
 # endif
 
+# ifdef __cpp_lib_is_implicit_lifetime
+#   error "__cpp_lib_is_implicit_lifetime should not be defined before c++23"
+# endif
+
 # ifdef __cpp_lib_is_invocable
 #   error "__cpp_lib_is_invocable should not be defined before c++17"
 # endif
@@ -2564,6 +2573,10 @@
 #   error "__cpp_lib_is_final should have the value 201402L in c++17"
 # endif
 
+# ifdef __cpp_lib_is_implicit_lifetime
+#   error "__cpp_lib_is_implicit_lifetime should not be defined before c++23"
+# endif
+
 # ifndef __cpp_lib_is_invocable
 #   error "__cpp_lib_is_invocable should be defined in c++17"
 # endif
@@ -3842,6 +3855,10 @@
 #   error "__cpp_lib_is_final should have the value 201402L in c++20"
 # endif
 
+# ifdef __cpp_lib_is_implicit_lifetime
+#   error "__cpp_lib_is_implicit_lifetime should not be defined before c++23"
+# endif
+
 # ifndef __cpp_lib_is_invocable
 #   error "__cpp_lib_is_invocable should be defined in c++20"
 # endif
@@ -5306,6 +5323,19 @@
 #   error "__cpp_lib_is_final should have the value 201402L in c++23"
 # endif
 
+# if __has_builtin(__builtin_is_implicit_lifetime)
+#   ifndef __cpp_lib_is_implicit_lifetime
+#     error "__cpp_lib_is_implicit_lifetime should be defined in c++23"
+#   endif
+#   if __cpp_lib_is_implicit_lifetime != 202302L
+#     error "__cpp_lib_is_implicit_lifetime should have the value 202302L in c++23"
+#   endif
+# else
+#   ifdef __cpp_lib_is_implicit_lifetime
+#     error "__cpp_lib_is_implicit_lifetime should not be defined when the requirement '__has_builtin(__builtin_is_implicit_lifetime)' is not met!"
+#   endif
+# endif
+
 # ifndef __cpp_lib_is_invocable
 #   error "__cpp_lib_is_invocable should be defined in c++23"
 # endif
@@ -7112,6 +7142,19 @@
 #   error "__cpp_lib_is_final should have the value 201402L in c++26"
 # endif
 
+# if __has_builtin(__builtin_is_implicit_lifetime)
+#   ifndef __cpp_lib_is_implicit_lifetime
+#     error "__cpp_lib_is_implicit_lifetime should be defined in c++26"
+#   endif
+#   if __cpp_lib_is_implicit_lifetime != 202302L
+#     error "__cpp_lib_is_implicit_lifetime should have the value 202302L in c++26"
+#   endif
+# else
+#   ifdef __cpp_lib_is_implicit_lifetime
+#     error "__cpp_lib_is_implicit_lifetime should not be defined when the requirement '__has_builtin(__builtin_is_implicit_lifetime)' is not met!"
+#   endif
+# endif
+
 # ifndef __cpp_lib_is_invocable
 #   error "__cpp_lib_is_invocable should be defined in c++26"
 # endif

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..a6ab77158aae1d
--- /dev/null
+++ b/libcxx/test/std/utilities/meta/meta.unary/meta.unary.prop/is_implicit_lifetime.pass.cpp
@@ -0,0 +1,237 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+
+// These compilers don't support __builtin_is_implicit_lifetime yet.
+// UNSUPPORTED: clang-17, clang-18, clang-19, gcc-14, apple-clang-15, apple-clang-16
+
+// <type_traits>
+
+// template<class T> struct is_implicit_lifetime;
+
+#include <cassert>
+#include <cstddef>
+#include <tuple>
+#include <type_traits>
+#include <utility>
+
+#include "test_macros.h"
+#include "type_algorithms.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];
+};
+
+// Test implicit-lifetime type
+template <typename T, bool Expected>
+constexpr void test_is_implicit_lifetime() {
+  assert(std::is_implicit_lifetime<T>::value == Expected);
+  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>();
+
+  // Arrays
+  test_is_implicit_lifetime<T[], true>();
+  test_is_implicit_lifetime<T[94], true>();
+}
+
+struct AritmeticTypesTest {
+  template <class T>
+  constexpr void operator()() {
+    test_is_implicit_lifetime<T>();
+  }
+};
+
+constexpr bool test() {
+  // Standard fundamental C++ types
+
+  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>();
+
+  types::for_each(types::arithmetic_types(), AritmeticTypesTest{});
+
+  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>();
+
+  // 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 C23 types
+
+#ifdef TEST_COMPILER_CLANG
+  test_is_implicit_lifetime<_BitInt(8)>();
+  test_is_implicit_lifetime<_BitInt(128)>();
+#endif
+
+  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..25bba30da612e6
--- /dev/null
+++ b/libcxx/test/std/utilities/meta/meta.unary/meta.unary.prop/is_implicit_lifetime.verify.cpp
@@ -0,0 +1,26 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+
+// These compilers don't support __builtin_is_implicit_lifetime yet.
+// UNSUPPORTED: clang-17, clang-18, clang-19, gcc-14, apple-clang-15, apple-clang-16
+
+// <type_traits>
+
+// template<class T> struct is_implicit_lifetime;
+
+#include <type_traits>
+
+struct IncompleteStruct;
+
+// expected-error@*:* {{incomplete type 'IncompleteStruct' used in type trait expression}}
+static_assert(!std::is_implicit_lifetime<IncompleteStruct>::value);
+
+// expected-error@*:* {{incomplete type 'IncompleteStruct' used in type trait expression}}
+static_assert(!std::is_implicit_lifetime_v<IncompleteStruct>);

diff  --git a/libcxx/utils/generate_feature_test_macro_components.py b/libcxx/utils/generate_feature_test_macro_components.py
index 3b8a52362ede68..db14c1781dc35a 100755
--- a/libcxx/utils/generate_feature_test_macro_components.py
+++ b/libcxx/utils/generate_feature_test_macro_components.py
@@ -742,6 +742,13 @@ 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)",
+        },
         {
             "name": "__cpp_lib_is_invocable",
             "values": {"c++17": 201703},


        


More information about the libcxx-commits mailing list