On Wed, Jun 24, 2026 at 01:16:25PM -0400, Jason Merrill wrote:
> On 6/24/26 12:05 PM, Marek Polacek wrote:
> > On Wed, Jun 24, 2026 at 10:41:54AM -0400, Jason Merrill wrote:
> > > On 6/23/26 6:53 PM, Marek Polacek wrote:
> > > > Bootstrapped/regtested on x86_64-pc-linux-gnu, ok for trunk/16?
> > > > 
> > > > -- >8 --
> > > > 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.
> > > 
> > > tsubst uses tf_ignore_bad_quals to avoid this problem with template 
> > > argument
> > > substitution.  Maybe build_stub_type should use it as well?
> > 
> > Sounds good too.  I would like to keep the new helper to hide all those
> > cp_type_quals (t) | TYPE_QUAL_CONST.
> > 
> > dg.exp passed, full testing running.  OK for trunk/16 once it passes?
> 
> OK.

Thanks.  For GCC 16 I pushed this minimal version:

-- >8 --
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.

        PR c++/125939

gcc/cp/ChangeLog:

        * method.cc (build_stub_type): Pass tf_ignore_bad_quals to
        cp_build_qualified_type.

gcc/testsuite/ChangeLog:

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

Reviewed-by: Jason Merrill <[email protected]>

diff --git a/gcc/cp/method.cc b/gcc/cp/method.cc
index fe26b5130ff..6272ed3aa9b 100644
--- a/gcc/cp/method.cc
+++ b/gcc/cp/method.cc
@@ -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);
 }
 
diff --git a/gcc/testsuite/g++.dg/reflect/type_trait15.C 
b/gcc/testsuite/g++.dg/reflect/type_trait15.C
new file mode 100644
index 00000000000..f0ce2e41e0b
--- /dev/null
+++ b/gcc/testsuite/g++.dg/reflect/type_trait15.C
@@ -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 &>);

Reply via email to