https://gcc.gnu.org/g:d7f33a35bffe7b331b0f8475e52c2dcc1c5d2ea8

commit r16-1054-gd7f33a35bffe7b331b0f8475e52c2dcc1c5d2ea8
Author: Jason Merrill <ja...@redhat.com>
Date:   Mon Jun 2 10:09:07 2025 -0400

    c++: __is_destructible fixes [PR107600]
    
    destructible_expr was wrongly assuming that TO is a class type.
    
    When is_xible_helper was added in r8-742 it returned early for abstract
    class types, which is correct for __is_constructible, but not
    __is_assignable or (now) __is_destructible.
    
            PR c++/107600
    
    gcc/cp/ChangeLog:
    
            * method.cc (destructible_expr): Handle non-classes.
            (constructible_expr): Check for abstract class here...
            (is_xible_helper): ...not here.
    
    gcc/testsuite/ChangeLog:
    
            * g++.dg/ext/is_destructible2.C: New test.

Diff:
---
 gcc/cp/method.cc                            | 21 ++++++++++++++++-----
 gcc/testsuite/g++.dg/ext/is_destructible2.C | 15 +++++++++++++++
 2 files changed, 31 insertions(+), 5 deletions(-)

diff --git a/gcc/cp/method.cc b/gcc/cp/method.cc
index 3a675d9f8723..bb6790f13cdb 100644
--- a/gcc/cp/method.cc
+++ b/gcc/cp/method.cc
@@ -2251,6 +2251,8 @@ constructible_expr (tree to, tree from)
   const int len = TREE_VEC_LENGTH (from);
   if (CLASS_TYPE_P (to))
     {
+      if (ABSTRACT_CLASS_TYPE_P (to))
+       return error_mark_node;
       tree ctype = to;
       vec<tree, va_gc> *args = NULL;
       if (!TYPE_REF_P (to))
@@ -2337,10 +2339,19 @@ destructible_expr (tree to)
 {
   cp_unevaluated cp_uneval_guard;
   int flags = LOOKUP_NORMAL|LOOKUP_DESTRUCTOR;
-  to = build_trait_object (to);
-  tree r = build_delete (input_location, TREE_TYPE (to), to,
-                        sfk_complete_destructor, flags, 0, tf_none);
-  return r;
+  to = strip_array_types (to);
+  if (CLASS_TYPE_P (to))
+    {
+      to = build_trait_object (to);
+      return build_delete (input_location, TREE_TYPE (to), to,
+                            sfk_complete_destructor, flags, 0, tf_none);
+    }
+  /* [expr.prim.id.dtor] If the id-expression names a pseudo-destructor, T
+     shall be a scalar type.... */
+  else if (scalarish_type_p (to))
+    return void_node;
+  else
+    return error_mark_node;
 }
 
 /* Returns a tree iff TO is assignable (if CODE is MODIFY_EXPR) or
@@ -2352,7 +2363,7 @@ is_xible_helper (enum tree_code code, tree to, tree from, 
bool trivial)
 {
   to = complete_type (to);
   deferring_access_check_sentinel acs (dk_no_deferred);
-  if (VOID_TYPE_P (to) || ABSTRACT_CLASS_TYPE_P (to)
+  if (VOID_TYPE_P (to)
       || (from && FUNC_OR_METHOD_TYPE_P (from)
          && (TYPE_READONLY (from) || FUNCTION_REF_QUALIFIED (from))))
     return error_mark_node;
diff --git a/gcc/testsuite/g++.dg/ext/is_destructible2.C 
b/gcc/testsuite/g++.dg/ext/is_destructible2.C
new file mode 100644
index 000000000000..7f15fc786848
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_destructible2.C
@@ -0,0 +1,15 @@
+// PR c++/107600
+// { dg-additional-options -Wno-c++17-extensions }
+// { dg-do compile { target c++11 } }
+
+struct A
+{
+  A& operator= (const A&);
+  virtual ~A() = 0;
+};
+
+static_assert( __is_destructible(A) );
+static_assert( __is_assignable(A, A) );
+static_assert( not __is_destructible(int()) );
+static_assert( not __is_nothrow_destructible(int()) );
+static_assert( not __is_trivially_destructible(int()) );

Reply via email to