public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [PATCH] c++: __is_constructible ref binding [PR100667]
@ 2024-03-28 18:25 Jason Merrill
  0 siblings, 0 replies; only message in thread
From: Jason Merrill @ 2024-03-28 18:25 UTC (permalink / raw)
  To: gcc-patches; +Cc: Jonathan Wakely

Tested x86_64-pc-linux-gnu, applying to trunk.

-- 8< --

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.
---
 gcc/cp/semantics.cc                          | 54 +++++++++++++++++---
 gcc/testsuite/g++.dg/ext/is_constructible8.C | 31 +++++++++++
 2 files changed, 78 insertions(+), 7 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/ext/is_constructible8.C

diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index adb1ba48d29..9838331d2a9 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12607,6 +12607,45 @@ check_trait_type (tree type, int kind = 1)
   return true;
 }
 
+/* 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:
+    case CPTK_REF_CONSTRUCTS_FROM_TEMPORARY:
+    case CPTK_REF_CONVERTS_FROM_TEMPORARY:
+      to = type1;
+      from = type2;
+      break;
+
+      /* These put it second.  */
+    case CPTK_IS_CONVERTIBLE:
+    case CPTK_IS_NOTHROW_CONVERTIBLE:
+      to = type2;
+      from = type1;
+      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);
+  return (TYPE_P (from)
+	  && (same_type_ignoring_top_level_qualifiers_p
+	      (non_reference (to), non_reference (from))));
+}
+
 /* Process a trait expression.  */
 
 tree
@@ -12666,20 +12705,21 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
 	return error_mark_node;
       break;
 
-    case CPTK_IS_ASSIGNABLE:
     case CPTK_IS_CONSTRUCTIBLE:
-      if (!check_trait_type (type1))
-	return error_mark_node;
-      break;
-
     case CPTK_IS_CONVERTIBLE:
-    case CPTK_IS_NOTHROW_ASSIGNABLE:
     case CPTK_IS_NOTHROW_CONSTRUCTIBLE:
     case CPTK_IS_NOTHROW_CONVERTIBLE:
-    case CPTK_IS_TRIVIALLY_ASSIGNABLE:
     case CPTK_IS_TRIVIALLY_CONSTRUCTIBLE:
     case CPTK_REF_CONSTRUCTS_FROM_TEMPORARY:
     case CPTK_REF_CONVERTS_FROM_TEMPORARY:
+      /* Don't check completeness for direct reference binding.  */;
+      if (same_type_ref_bind_p (kind, type1, type2))
+	break;
+      gcc_fallthrough ();
+
+    case CPTK_IS_ASSIGNABLE:
+    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..a27ec6eddd7
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_constructible8.C
@@ -0,0 +1,31 @@
+// 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));
+
+SA (__is_convertible(T, T&&));
+SA (__is_convertible(T, const T&));
+SA (!__is_convertible(T, T&));
+SA (__is_nothrow_convertible(T, T&&));
+SA (__is_nothrow_convertible(T, const T&));
+SA (!__is_nothrow_convertible(T, T&));
+
+// All false because either the conversion fails or it doesn't bind a temporary
+SA (!__reference_constructs_from_temporary (T&&, T));
+SA (!__reference_constructs_from_temporary (const T&, T));
+SA (!__reference_constructs_from_temporary (T&, T));
+SA (!__reference_converts_from_temporary (T&&, T));
+SA (!__reference_converts_from_temporary (const T&, T));
+SA (!__reference_converts_from_temporary (T&, T));

base-commit: bbb7c513dddc5c9b2d5e9b78bc1c2f85a0cfe07e
-- 
2.44.0


^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2024-03-28 18:26 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2024-03-28 18:25 [PATCH] c++: __is_constructible ref binding [PR100667] Jason Merrill

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).