c++/reflection: propagate cv-quals for SPLICE_SCOPE [PR125096]

tsubst_splice_scope isn't propagating cv-quals from the template tree
to the result, which means wrongly failed asserts in the new test due to
a missing 'const'.  So let's add the cv-quals like we do in so many
other places in tsubst.

	PR c++/125096

gcc/cp/ChangeLog:

	* pt.cc (tsubst_splice_scope): Don't return early for
	dependent_splice_p.  Propagate cv-qualifiers from the
	SPLICE_SCOPE to the result.
	* reflect.cc (valid_splice_scope_p): Accept SPLICE_SCOPE.

gcc/testsuite/ChangeLog:

	* g++.dg/reflect/mangle4.C: Move dg-error.
	* g++.dg/reflect/dep16.C: New test.

Reviewed-by: Jason Merrill <jason@redhat.com>
This commit is contained in:
Marek Polacek
2026-04-29 17:24:19 -04:00
parent 95c8e7d2cb
commit 0727299846
4 changed files with 38 additions and 6 deletions

View File

@@ -16904,8 +16904,8 @@ tsubst_splice_scope (tree t, tree args, tsubst_flags_t complain, tree in_decl)
return r;
const bool type_p = SPLICE_SCOPE_TYPE_P (t);
if (dependent_splice_p (r))
return make_splice_scope (r, type_p);
if (type_p && ctad_template_p (r))
r = make_splice_scope (r, type_p);
else if (type_p && ctad_template_p (r))
r = make_template_placeholder (r);
if (type_p
? !valid_splice_type_p (r)
@@ -16925,6 +16925,10 @@ tsubst_splice_scope (tree t, tree args, tsubst_flags_t complain, tree in_decl)
return error_mark_node;
}
if (type_p)
r = cp_build_qualified_type (r, cp_type_quals (t) | cp_type_quals (r),
complain | tf_ignore_bad_quals);
return r;
}

View File

@@ -8912,7 +8912,8 @@ valid_splice_scope_p (const_tree t)
{
return (CLASS_TYPE_P (t)
|| TREE_CODE (t) == ENUMERAL_TYPE
|| TREE_CODE (t) == NAMESPACE_DECL);
|| TREE_CODE (t) == NAMESPACE_DECL
|| TREE_CODE (t) == SPLICE_SCOPE);
}
/* Return true if T is a valid result of the splice in a class member access,

View File

@@ -0,0 +1,28 @@
// PR c++/125096
// { dg-do compile { target c++26 } }
// { dg-additional-options "-freflection" }
#include <meta>
#include <vector>
namespace ctp {
template <class T> struct Reflect;
namespace impl {
template <class T> using custom_target = Reflect<T>::target_type;
}
template <class T>
using target = [: is_scalar_type(^^T) ? ^^T : substitute(^^impl::custom_target, {^^T}) :];
template <class T>
struct Reflect<std::vector<T>> {
using underlying = target<T> const;
using target_type = std::span<const target<T>>;
};
}
static_assert(dealias(^^ctp::target<int>) == ^^int);
static_assert(dealias(^^ctp::target<std::vector<int>>) == ^^std::span<int const>);
static_assert(dealias(^^ctp::Reflect<std::vector<int>>::underlying) == ^^int const);
static_assert(dealias(^^ctp::Reflect<std::vector<int>>::target_type) == ^^std::span<int const>);

View File

@@ -20,7 +20,6 @@ template<random_access_iterator I>
}
int main() {
// ??? It's not clear which of these should error.
std::default_accessor<int> _ = std::iterator_accessor<int*>();
std::default_accessor<const int> _ = std::iterator_accessor<int*>(); // { dg-error "conversion" }
std::default_accessor<int> _ = std::iterator_accessor<int*>(); // { dg-error "conversion" }
std::default_accessor<const int> _ = std::iterator_accessor<int*>();
}