https://gcc.gnu.org/g:2be174f14c0bea9c0fe979467104d7d9027fe093

commit r17-1997-g2be174f14c0bea9c0fe979467104d7d9027fe093
Author: Jakub Jelinek <[email protected]>
Date:   Tue Jun 30 09:26:29 2026 +0200

    c++: Fix up __builtin_is_implicit_lifetime [PR126007]
    
    https://eel.is/c++draft/class.prop#8.2 says that implicit lifetime
    class shall have at least one trivial eligible constructor.
    We currently walk all ctors and if it is default/copy/move ctor
    which is trivial and not deleted, return true, but as the following testcase
    shows, we should check also for unsatisfied constraints.
    
    2026-06-30  Jakub Jelinek  <[email protected]>
    
            PR c++/126007
            * tree.cc (eligible_special_member_function_p): New function.
            (implicit_lifetime_type_p): Use true instead of 1 in function 
comment.
            Add some further comments.  Use eligible_special_member_function_p
            instead of !DECL_DELETED_FN.
    
            * g++.dg/ext/is_implicit_lifetime3.C: New test.
    
    Reviewed-by: Jason Merrill <[email protected]>

Diff:
---
 gcc/cp/tree.cc                                   | 25 ++++++++++++++++++++++--
 gcc/testsuite/g++.dg/ext/is_implicit_lifetime3.C | 11 +++++++++++
 2 files changed, 34 insertions(+), 2 deletions(-)

diff --git a/gcc/cp/tree.cc b/gcc/cp/tree.cc
index dc885e47c01e..e543cf145195 100644
--- a/gcc/cp/tree.cc
+++ b/gcc/cp/tree.cc
@@ -4919,7 +4919,25 @@ trivially_copy_constructible_p (tree t)
   return is_trivially_xible (INIT_EXPR, t, arg);
 }
 
-/* Returns 1 iff type T is an implicit-lifetime type, as defined in
+/* Returns true iff FN (which is a special member function) is
+   an eligible special member function, as defined in [special]/6.
+   The "no special member function of the same kind whose associated
+   constraints, if any, are satisfied is more constrained" condition
+   is not checked, this is checked during add_method instead.  */
+
+static bool
+eligible_special_member_function_p (tree fn)
+{
+  /* The function is not deleted.  */
+  if (DECL_DELETED_FN (fn))
+    return false;
+  /* The associated constraints, if any, are satisfied.  */
+  if (!constraints_satisfied_p (fn))
+    return false;
+  return true;
+}
+
+/* Returns true iff type T is an implicit-lifetime type, as defined in
    [basic.types.general] and [class.prop].  */
 
 bool
@@ -4934,6 +4952,7 @@ implicit_lifetime_type_p (tree t)
   if (!CLASS_TYPE_P (t))
     return false;
   t = TYPE_MAIN_VARIANT (t);
+  /* It is an aggregate whose destructor is not user-provided.  */
   if (CP_AGGREGATE_TYPE_P (t)
       && (!CLASSTYPE_DESTRUCTOR (t)
          || !user_provided_p (CLASSTYPE_DESTRUCTOR (t))))
@@ -4946,6 +4965,8 @@ implicit_lifetime_type_p (tree t)
     return false;
   if (CLASSTYPE_LAZY_DESTRUCTOR (t))
     lazily_declare_fn (sfk_destructor, t);
+  /* It has at least one trivial eligible constructor and a trivial,
+     non-deleted destructor.  */
   tree fn = CLASSTYPE_DESTRUCTOR (t);
   if (!fn || DECL_DELETED_FN (fn))
     return false;
@@ -4955,7 +4976,7 @@ implicit_lifetime_type_p (tree t)
       fn = *iter;
       if ((default_ctor_p (fn) || copy_fn_p (fn) || move_fn_p (fn))
          && trivial_fn_p (fn)
-         && !DECL_DELETED_FN (fn))
+         && eligible_special_member_function_p (fn))
        return true;
     }
   return false;
diff --git a/gcc/testsuite/g++.dg/ext/is_implicit_lifetime3.C 
b/gcc/testsuite/g++.dg/ext/is_implicit_lifetime3.C
new file mode 100644
index 000000000000..c3b734e9d06e
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_implicit_lifetime3.C
@@ -0,0 +1,11 @@
+// PR c++/126007
+// { dg-do compile { target c++20 } }
+
+template <bool B>
+struct S {
+  S () requires B = default;
+  S (const S &) {}
+};
+
+static_assert (!__builtin_is_implicit_lifetime (S<false>));
+static_assert (__builtin_is_implicit_lifetime (S<true>));

Reply via email to