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

commit r12-10470-gba57a52dbf6a64ba66f72c20064c5c0e8cc9dbbb
Author: Jason Merrill <ja...@redhat.com>
Date:   Wed Mar 27 16:14:01 2024 -0400

    c++: __is_constructible ref binding [PR100667]
    
    The requirement that a type argument be complete is excessive in the case of
    direct reference binding to the same type, which does not rely on any
    properties of the type.  This is LWG 2939.
    
            PR c++/100667
    
    gcc/cp/ChangeLog:
    
            * semantics.cc (same_type_ref_bind_p): New.
            (finish_trait_expr): Use it.
    
    gcc/testsuite/ChangeLog:
    
            * g++.dg/ext/is_constructible8.C: New test.
    
    (cherry picked from commit 8bb3ef3f6e335e8794590fb712a2661d11d21973)

Diff:
---
 gcc/cp/semantics.cc                          | 41 ++++++++++++++++++++++++++--
 gcc/testsuite/g++.dg/ext/is_constructible8.C | 16 +++++++++++
 2 files changed, 55 insertions(+), 2 deletions(-)

diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index e5db5189f33..0672d6c5b68 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12034,6 +12034,38 @@ check_trait_type (tree type)
   return !!complete_type_or_else (strip_array_types (type), NULL_TREE);
 }
 
+/* True iff the conversion (if any) would be a direct reference
+   binding, not requiring complete types.  This is LWG2939.  */
+
+static bool
+same_type_ref_bind_p (cp_trait_kind kind, tree type1, tree type2)
+{
+  tree from, to;
+  switch (kind)
+    {
+      /* These put the target type first.  */
+    case CPTK_IS_CONSTRUCTIBLE:
+    case CPTK_IS_NOTHROW_CONSTRUCTIBLE:
+    case CPTK_IS_TRIVIALLY_CONSTRUCTIBLE:
+      to = type1;
+      from = type2;
+      break;
+
+    default:
+      gcc_unreachable ();
+    }
+
+  if (TREE_CODE (to) != REFERENCE_TYPE || !from)
+    return false;
+  if (TREE_CODE (from) == TREE_VEC && TREE_VEC_LENGTH (from) == 1)
+    from = TREE_VEC_ELT (from, 0);
+  else if (TREE_CODE (from) == TREE_LIST && !TREE_CHAIN (from))
+    from = TREE_VALUE (from);
+  return (TYPE_P (from)
+         && (same_type_ignoring_top_level_qualifiers_p
+             (non_reference (to), non_reference (from))));
+}
+
 /* Process a trait expression.  */
 
 tree
@@ -12083,10 +12115,15 @@ finish_trait_expr (location_t loc, cp_trait_kind 
kind, tree type1, tree type2)
     case CPTK_IS_CONSTRUCTIBLE:
       break;
 
-    case CPTK_IS_TRIVIALLY_ASSIGNABLE:
     case CPTK_IS_TRIVIALLY_CONSTRUCTIBLE:
-    case CPTK_IS_NOTHROW_ASSIGNABLE:
     case CPTK_IS_NOTHROW_CONSTRUCTIBLE:
+      /* Don't check completeness for direct reference binding.  */;
+      if (same_type_ref_bind_p (kind, type1, type2))
+       break;
+      gcc_fallthrough ();
+
+    case CPTK_IS_NOTHROW_ASSIGNABLE:
+    case CPTK_IS_TRIVIALLY_ASSIGNABLE:
       if (!check_trait_type (type1)
          || !check_trait_type (type2))
        return error_mark_node;
diff --git a/gcc/testsuite/g++.dg/ext/is_constructible8.C 
b/gcc/testsuite/g++.dg/ext/is_constructible8.C
new file mode 100644
index 00000000000..4b8204c0768
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_constructible8.C
@@ -0,0 +1,16 @@
+// PR c++/100667
+// { dg-do compile { target c++11 } }
+
+struct T;
+
+#define SA(X) static_assert ((X), #X);
+
+SA (__is_constructible(T&&, T));
+SA (__is_constructible(const T&, T));
+SA (!__is_constructible(T&, T));
+SA (__is_nothrow_constructible(T&&, T));
+SA (__is_nothrow_constructible(const T&, T));
+SA (!__is_nothrow_constructible(T&, T));
+SA (__is_trivially_constructible(T&&, T));
+SA (__is_trivially_constructible(const T&, T));
+SA (!__is_trivially_constructible(T&, T));

Reply via email to