]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
c++/reflection: type traits and reference collapsing [PR125939]
authorMarek Polacek <polacek@redhat.com>
Tue, 23 Jun 2026 21:39:29 +0000 (17:39 -0400)
committerMarek Polacek <polacek@redhat.com>
Wed, 24 Jun 2026 17:17:20 +0000 (13:17 -0400)
This PR shows that some of our meta type traits don't work with
references: we emit bogus

  error: 'const' qualifiers cannot be applied to 'int&'

errors.  The problem is that build_stub_type is trying to add
const to a reference, which you can only do through a typedef,
but here we don't have a typedef.

Resolved by passing tf_ignore_bad_quals to cp_build_qualified_type.
The new build_const_lref helper is to spruce up the code a bit.

PR c++/125939

gcc/cp/ChangeLog:

* cp-tree.h (build_const_lref): Declare.
* method.cc (build_stub_type): Pass tf_ignore_bad_quals to
cp_build_qualified_type.
* reflect.cc (build_const_lref): New.
(get_range_elts): Use it.
(eval_is_copy_constructible_type): Likewise.
(eval_is_copy_assignable_type): Likewise.
(eval_is_trivially_copy_assignable_type): Likewise.
(eval_is_nothrow_copy_constructible_type): Likewise.
(eval_is_nothrow_copy_assignable_type): Likewise.
* tree.cc (trivially_copy_constructible_p): Likewise.
(handle_annotation_attribute): Likewise.

gcc/testsuite/ChangeLog:

* g++.dg/reflect/type_trait15.C: New test.

Reviewed-by: Jason Merrill <jason@redhat.com>
gcc/cp/cp-tree.h
gcc/cp/method.cc
gcc/cp/reflect.cc
gcc/cp/tree.cc
gcc/testsuite/g++.dg/reflect/type_trait15.C [new file with mode: 0644]

index 132139f9d52025416e7872ca45369cdc78eee133..76ed1e59dec348479656817513805b2570e828ea 100644 (file)
@@ -9530,6 +9530,7 @@ extern void coro_set_ramp_function                (tree, tree);
 
 /* In reflect.cc */
 extern void init_reflection ();
+WARN_UNUSED_RESULT extern tree build_const_lref (tree);
 extern tree maybe_update_function_parm (tree);
 extern bool metafunction_p (tree) ATTRIBUTE_PURE;
 extern tree direct_base_derived (tree) ATTRIBUTE_PURE;
index c511ea9a06428151a655583f7d90d561fc88967b..4c432efb56aeedbfc8a91aa0f92a87f08e617042 100644 (file)
@@ -1902,7 +1902,9 @@ maybe_synthesize_method (tree fndecl)
 tree
 build_stub_type (tree type, int quals, bool rvalue)
 {
-  tree argtype = cp_build_qualified_type (type, quals);
+  tree argtype
+    = cp_build_qualified_type (type, quals,
+                              tf_warning_or_error | tf_ignore_bad_quals);
   return cp_build_reference_type (argtype, rvalue);
 }
 
index bf1c41772d34ee8956adaa5b6808abe188eb297e..3d6d24eb23acdb9adaf302415e488b6dbe935bda 100644 (file)
@@ -324,6 +324,15 @@ maybe_update_function_parm (tree parm)
   return ret;
 }
 
+/* Build up const T &.  */
+
+tree
+build_const_lref (tree t)
+{
+  return build_stub_type (t, cp_type_quals (t) | TYPE_QUAL_CONST,
+                         /*rval=*/false);
+}
+
 /* Return true if DECL comes from std::meta.  */
 
 static bool
@@ -587,10 +596,7 @@ get_range_elts (location_t loc, const constexpr_ctx *ctx, tree call, int n,
              *non_constant_p = true;
              return NULL_TREE;
            }
-         TREE_VEC_ELT (args, 0)
-           = build_stub_type (valuete,
-                              cp_type_quals (valuete) | TYPE_QUAL_CONST,
-                              false);
+         TREE_VEC_ELT (args, 0) = build_const_lref (valuete);
          if (!is_xible (INIT_EXPR, valuete, args))
            {
              if (!cxx_constexpr_quiet_p (ctx))
@@ -4570,8 +4576,7 @@ static tree
 eval_is_copy_constructible_type (tree type)
 {
   tree arg = make_tree_vec (1);
-  TREE_VEC_ELT (arg, 0)
-    = build_stub_type (type, cp_type_quals (type) | TYPE_QUAL_CONST, false);
+  TREE_VEC_ELT (arg, 0) = build_const_lref (type);
   if (is_xible (INIT_EXPR, type, arg))
     return boolean_true_node;
   else
@@ -4605,8 +4610,7 @@ static tree
 eval_is_copy_assignable_type (tree type)
 {
   tree type1 = cp_build_reference_type (type, /*rval=*/false);
-  tree type2 = build_stub_type (type, cp_type_quals (type) | TYPE_QUAL_CONST,
-                               false);
+  tree type2 = build_const_lref (type);
   if (is_xible (MODIFY_EXPR, type1, type2))
     return boolean_true_node;
   else
@@ -4694,8 +4698,7 @@ static tree
 eval_is_trivially_copy_assignable_type (tree type)
 {
   tree type1 = cp_build_reference_type (type, /*rval=*/false);
-  tree type2 = build_stub_type (type, cp_type_quals (type) | TYPE_QUAL_CONST,
-                               false);
+  tree type2 = build_const_lref (type);
   if (is_trivially_xible (MODIFY_EXPR, type1, type2))
     return boolean_true_node;
   else
@@ -4751,8 +4754,7 @@ static tree
 eval_is_nothrow_copy_constructible_type (tree type)
 {
   tree arg = make_tree_vec (1);
-  TREE_VEC_ELT (arg, 0)
-    = build_stub_type (type, cp_type_quals (type) | TYPE_QUAL_CONST, false);
+  TREE_VEC_ELT (arg, 0) = build_const_lref (type);
   if (is_nothrow_xible (INIT_EXPR, type, arg))
     return boolean_true_node;
   else
@@ -4786,8 +4788,7 @@ static tree
 eval_is_nothrow_copy_assignable_type (tree type)
 {
   tree type1 = cp_build_reference_type (type, /*rval=*/false);
-  tree type2 = build_stub_type (type, cp_type_quals (type) | TYPE_QUAL_CONST,
-                               false);
+  tree type2 = build_const_lref (type);
   if (is_nothrow_xible (MODIFY_EXPR, type1, type2))
     return boolean_true_node;
   else
index d9a0583b8b834920a820cad62fbffecee7631bcd..dc885e47c01ef73b2c18072d279af46afc123eb8 100644 (file)
@@ -4915,8 +4915,7 @@ bool
 trivially_copy_constructible_p (tree t)
 {
   tree arg = make_tree_vec (1);
-  TREE_VEC_ELT (arg, 0)
-    = build_stub_type (t, cp_type_quals (t) | TYPE_QUAL_CONST, false);
+  TREE_VEC_ELT (arg, 0) = build_const_lref (t);
   return is_trivially_xible (INIT_EXPR, t, arg);
 }
 
@@ -5982,9 +5981,7 @@ handle_annotation_attribute (tree *node, tree ARG_UNUSED (name),
     {
       tree arg = make_tree_vec (1);
       tree type = TREE_TYPE (TREE_VALUE (args));
-      TREE_VEC_ELT (arg, 0)
-       = build_stub_type (type, cp_type_quals (type) | TYPE_QUAL_CONST,
-                          /*rvalue=*/false);
+      TREE_VEC_ELT (arg, 0) = build_const_lref (type);
       if (!is_xible (INIT_EXPR, type, arg))
        {
          auto_diagnostic_group d;
diff --git a/gcc/testsuite/g++.dg/reflect/type_trait15.C b/gcc/testsuite/g++.dg/reflect/type_trait15.C
new file mode 100644 (file)
index 0000000..f0ce2e4
--- /dev/null
@@ -0,0 +1,133 @@
+// PR c++/125939
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+
+#include <meta>
+
+template<typename T>
+constexpr bool cct = std::meta::is_copy_constructible_type(^^T);
+
+int main() {
+    using T = int&;
+    static_assert(std::meta::is_copy_constructible_type(^^T));
+    static_assert(cct<int&>);
+}
+
+static_assert (is_copy_constructible_type (^^int));
+static_assert (std::is_copy_constructible_v<int>);
+static_assert (is_copy_constructible_type (^^const int));
+static_assert (std::is_copy_constructible_v<const int>);
+static_assert (is_copy_constructible_type (^^int &));
+static_assert (std::is_copy_constructible_v<int &>);
+static_assert (is_copy_constructible_type (^^const int &));
+static_assert (std::is_copy_constructible_v<const int &>);
+static_assert (!is_copy_constructible_type (^^int &&));
+static_assert (!std::is_copy_constructible_v<int &&>);
+static_assert (!is_copy_constructible_type (^^const int &&));
+static_assert (!std::is_copy_constructible_v<const int &&>);
+static_assert (!is_copy_constructible_type (^^void));
+static_assert (!std::is_copy_constructible_v<void>);
+static_assert (!is_copy_constructible_type (^^int() const &));
+static_assert (!std::is_copy_constructible_v<int() const &>);
+
+static_assert (is_trivially_copy_constructible_type (^^int));
+static_assert (std::is_trivially_copy_constructible_v<int>);
+static_assert (is_trivially_copy_constructible_type (^^const int));
+static_assert (std::is_trivially_copy_constructible_v<const int>);
+static_assert (is_trivially_copy_constructible_type (^^int &));
+static_assert (std::is_trivially_copy_constructible_v<int &>);
+static_assert (is_trivially_copy_constructible_type (^^const int &));
+static_assert (std::is_trivially_copy_constructible_v<const int &>);
+static_assert (!is_trivially_copy_constructible_type (^^int &&));
+static_assert (!std::is_trivially_copy_constructible_v<int &&>);
+static_assert (!is_trivially_copy_constructible_type (^^const int &&));
+static_assert (!std::is_trivially_copy_constructible_v<const int &&>);
+static_assert (!is_trivially_copy_constructible_type (^^void));
+static_assert (!std::is_trivially_copy_constructible_v<void>);
+static_assert (!is_trivially_copy_constructible_type (^^int() const &));
+static_assert (!std::is_trivially_copy_constructible_v<int() const &>);
+
+static_assert (is_nothrow_copy_constructible_type (^^int));
+static_assert (std::is_nothrow_copy_constructible_v<int>);
+static_assert (is_nothrow_copy_constructible_type (^^const int));
+static_assert (std::is_nothrow_copy_constructible_v<const int>);
+static_assert (is_nothrow_copy_constructible_type (^^int &));
+static_assert (std::is_nothrow_copy_constructible_v<int &>);
+static_assert (is_nothrow_copy_constructible_type (^^const int &));
+static_assert (std::is_nothrow_copy_constructible_v<const int &>);
+static_assert (!is_nothrow_copy_constructible_type (^^int &&));
+static_assert (!std::is_nothrow_copy_constructible_v<int &&>);
+static_assert (!is_nothrow_copy_constructible_type (^^const int &&));
+static_assert (!std::is_nothrow_copy_constructible_v<const int &&>);
+static_assert (!is_nothrow_copy_constructible_type (^^void));
+static_assert (!std::is_nothrow_copy_constructible_v<void>);
+static_assert (!is_nothrow_copy_constructible_type (^^int() const &));
+static_assert (!std::is_nothrow_copy_constructible_v<int() const &>);
+
+static_assert (!is_assignable_type (^^int, ^^int));
+static_assert (!std::is_assignable_v<int, int>);
+static_assert (!is_assignable_type (^^const int, ^^int));
+static_assert (!std::is_assignable_v<const int, int>);
+static_assert (is_assignable_type (^^int &, ^^int));
+static_assert (std::is_assignable_v<int &, int>);
+static_assert (!is_assignable_type (^^const int &, ^^int));
+static_assert (!std::is_assignable_v<const int &, int>);
+static_assert (!is_assignable_type (^^int &&, ^^int));
+static_assert (!std::is_assignable_v<int &&, int>);
+static_assert (!is_assignable_type (^^const int &&, ^^int));
+static_assert (!std::is_assignable_v<const int &&, int>);
+static_assert (!is_assignable_type (^^void, ^^int));
+static_assert (!std::is_assignable_v<void, int>);
+static_assert (!is_assignable_type (^^int() const &, ^^int));
+static_assert (!std::is_assignable_v<int() const &, int>);
+
+static_assert (is_copy_assignable_type (^^int));
+static_assert (std::is_copy_assignable_v<int>);
+static_assert (!is_copy_assignable_type (^^const int));
+static_assert (!std::is_copy_assignable_v<const int>);
+static_assert (is_copy_assignable_type (^^int &));
+static_assert (std::is_copy_assignable_v<int &>);
+static_assert (!is_copy_assignable_type (^^const int &));
+static_assert (!std::is_copy_assignable_v<const int &>);
+static_assert (is_copy_assignable_type (^^int &&));
+static_assert (std::is_copy_assignable_v<int &&>);
+static_assert (!is_copy_assignable_type (^^const int &&));
+static_assert (!std::is_copy_assignable_v<const int &&>);
+static_assert (!is_copy_assignable_type (^^void));
+static_assert (!std::is_copy_assignable_v<void>);
+static_assert (!is_copy_assignable_type (^^int() const &));
+static_assert (!std::is_copy_assignable_v<int() const &>);
+
+static_assert (is_trivially_copy_assignable_type (^^int));
+static_assert (std::is_trivially_copy_assignable_v<int>);
+static_assert (!is_trivially_copy_assignable_type (^^const int));
+static_assert (!std::is_trivially_copy_assignable_v<const int>);
+static_assert (is_trivially_copy_assignable_type (^^int &));
+static_assert (std::is_trivially_copy_assignable_v<int &>);
+static_assert (!is_trivially_copy_assignable_type (^^const int &));
+static_assert (!std::is_trivially_copy_assignable_v<const int &>);
+static_assert (is_trivially_copy_assignable_type (^^int &&));
+static_assert (std::is_trivially_copy_assignable_v<int &&>);
+static_assert (!is_trivially_copy_assignable_type (^^const int &&));
+static_assert (!std::is_trivially_copy_assignable_v<const int &&>);
+static_assert (!is_trivially_copy_assignable_type (^^void));
+static_assert (!std::is_trivially_copy_assignable_v<void>);
+static_assert (!is_trivially_copy_assignable_type (^^int() const &));
+static_assert (!std::is_trivially_copy_assignable_v<int() const &>);
+
+static_assert (is_nothrow_copy_assignable_type (^^int));
+static_assert (std::is_nothrow_copy_assignable_v<int>);
+static_assert (!is_nothrow_copy_assignable_type (^^const int));
+static_assert (!std::is_nothrow_copy_assignable_v<const int>);
+static_assert (is_nothrow_copy_assignable_type (^^int &));
+static_assert (std::is_nothrow_copy_assignable_v<int &>);
+static_assert (!is_nothrow_copy_assignable_type (^^const int &));
+static_assert (!std::is_nothrow_copy_assignable_v<const int &>);
+static_assert (is_nothrow_copy_assignable_type (^^int &&));
+static_assert (std::is_nothrow_copy_assignable_v<int &&>);
+static_assert (!is_nothrow_copy_assignable_type (^^const int &&));
+static_assert (!std::is_nothrow_copy_assignable_v<const int &&>);
+static_assert (!is_nothrow_copy_assignable_type (^^void));
+static_assert (!std::is_nothrow_copy_assignable_v<void>);
+static_assert (!is_nothrow_copy_assignable_type (^^int() const &));
+static_assert (!std::is_nothrow_copy_assignable_v<int() const &>);