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 &>);