Bootstrapped/regtested on x86_64-pc-linux-gnu, ok for trunk/16.2?
-- >8 --
This fixes two bugs:
1) crash in cp_tree_equal when comparing reflections with binfos;
cp_tree_equal doesn't handle those. We're coming from
lookup_template_class -> spec_hasher::equal -> comp_template_args
-> cp_tree_equal. We should use compare_reflections in cp_tree_equal.
2) the fix for 1) revealed that compare_reflections is buggy when
comparing two aliases: we shouldn't fall back to same_type_p
because given
using A = int;
using B = int;
^^A != ^^B should hold.
PR c++/125208
gcc/cp/ChangeLog:
* reflect.cc (compare_reflections): Use == when comparing two
aliases.
* tree.cc (cp_tree_equal) <case REFLECT_EXPR>: Use
compare_reflections.
gcc/testsuite/ChangeLog:
* g++.dg/reflect/alias3.C: New test.
* g++.dg/reflect/bases_of5.C: New test.
---
gcc/cp/reflect.cc | 5 +-
gcc/cp/tree.cc | 15 +--
gcc/testsuite/g++.dg/reflect/alias3.C | 15 +++
gcc/testsuite/g++.dg/reflect/bases_of5.C | 128 +++++++++++++++++++++++
4 files changed, 148 insertions(+), 15 deletions(-)
create mode 100644 gcc/testsuite/g++.dg/reflect/alias3.C
create mode 100644 gcc/testsuite/g++.dg/reflect/bases_of5.C
diff --git a/gcc/cp/reflect.cc b/gcc/cp/reflect.cc
index ad4c77fab3e..f03ad900f71 100644
--- a/gcc/cp/reflect.cc
+++ b/gcc/cp/reflect.cc
@@ -8940,8 +8940,11 @@ compare_reflections (tree lhs, tree rhs)
else if (TYPE_P (lhs) && TYPE_P (rhs))
{
/* Given "using A = int;", "^^int != ^^A" should hold. */
- if (typedef_variant_p (lhs) != typedef_variant_p (rhs))
+ if (typedef_variant_p (lhs) ^ typedef_variant_p (rhs))
return false;
+ /* Even if two aliases alias the same type, they're not equal. */
+ else if (typedef_variant_p (lhs))
+ return lhs == rhs;
/* This is for comparing function types. E.g.,
auto fn() -> int; type_of(^^fn) == ^^auto()->int; */
return same_type_p (lhs, rhs);
diff --git a/gcc/cp/tree.cc b/gcc/cp/tree.cc
index 2e96d65eecd..02a62f78511 100644
--- a/gcc/cp/tree.cc
+++ b/gcc/cp/tree.cc
@@ -4514,20 +4514,7 @@ cp_tree_equal (tree t1, tree t2)
return true;
case REFLECT_EXPR:
- {
- if (REFLECT_EXPR_KIND (t1) != REFLECT_EXPR_KIND (t2))
- return false;
- tree h1 = REFLECT_EXPR_HANDLE (t1);
- tree h2 = REFLECT_EXPR_HANDLE (t2);
- if (!cp_tree_equal (h1, h2))
- return false;
- /* ^^alias represents the alias itself, not the underlying type. */
- if (TYPE_P (h1)
- && (typedef_variant_p (h1) || typedef_variant_p (h2))
- && TYPE_NAME (h1) != TYPE_NAME (h2))
- return false;
- return true;
- }
+ return compare_reflections (t1, t2);
default:
break;
diff --git a/gcc/testsuite/g++.dg/reflect/alias3.C
b/gcc/testsuite/g++.dg/reflect/alias3.C
new file mode 100644
index 00000000000..802c3231c88
--- /dev/null
+++ b/gcc/testsuite/g++.dg/reflect/alias3.C
@@ -0,0 +1,15 @@
+// PR c++/125208
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+
+using A = int;
+using B = int;
+using C = A;
+static_assert (^^A == ^^A);
+static_assert (^^const A == ^^const A);
+static_assert (^^A != ^^const A);
+static_assert (^^B == ^^B);
+static_assert (^^C == ^^C);
+static_assert (^^A != ^^B);
+static_assert (^^A != ^^C);
+static_assert (^^B != ^^C);
diff --git a/gcc/testsuite/g++.dg/reflect/bases_of5.C
b/gcc/testsuite/g++.dg/reflect/bases_of5.C
new file mode 100644
index 00000000000..1c713b22cda
--- /dev/null
+++ b/gcc/testsuite/g++.dg/reflect/bases_of5.C
@@ -0,0 +1,128 @@
+// PR c++/125208
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+
+namespace std {
+template <class _E> struct initializer_list {
+ typedef _E *const_iterator;
+ _E *_M_array;
+ unsigned long _M_len;
+ constexpr long size() { return _M_len; }
+ constexpr const_iterator begin() { return _M_array; }
+ constexpr const_iterator end() { return begin() + size(); }
+};
+template <typename> struct allocator_traits;
+} // namespace std
+constexpr void *operator new(unsigned long, void *__p) { return __p; }
+namespace std {
+template <typename _Tp, typename... _Args>
+constexpr void _Construct(_Tp *__p, _Args... __args) {
+ new (__p) _Tp(__args...);
+}
+template <typename _Tp> struct __new_allocator {
+ constexpr _Tp *allocate(long __n) {
+ return static_cast<_Tp *>(__builtin_operator_new(__n * sizeof(_Tp)));
+ }
+ constexpr void deallocate(_Tp *__p, long) { __builtin_operator_delete(__p); }
+};
+template <typename _Tp> struct allocator_traits<__new_allocator<_Tp>> {
+ using allocator_type = __new_allocator<_Tp>;
+ using value_type = _Tp;
+ using pointer = _Tp *;
+ template <typename _Up> using rebind_alloc = __new_allocator<_Up>;
+ static constexpr pointer allocate(allocator_type __a, long __n) {
+ return __a.allocate(__n);
+ }
+ static constexpr void deallocate(allocator_type __a, pointer __p, long __n) {
+ __a.deallocate(__p, __n);
+ }
+};
+} // namespace std
+template <typename _Alloc>
+struct __alloc_traits : std::allocator_traits<_Alloc> {
+ typedef std::allocator_traits<_Alloc> _Base_type;
+ typedef _Base_type::value_type reference;
+ template <typename _Tp> struct rebind {
+ typedef _Base_type::template rebind_alloc<_Tp> other;
+ };
+};
+namespace std {
+template <typename _InputIterator, typename _Sentinel,
+ typename _ForwardIterator>
+constexpr void __do_uninit_copy(_InputIterator __first, _Sentinel __last,
+ _ForwardIterator __result) {
+ for (; __first != __last; ++__first, ++__result)
+ _Construct(__result, *__first);
+}
+template <typename _InputIterator, typename _ForwardIterator>
+constexpr void uninitialized_copy(_InputIterator __first, _InputIterator
__last,
+ _ForwardIterator __result) {
+ __do_uninit_copy(__first, __last, __result);
+}
+template <typename _InputIterator, typename _Sentinel,
+ typename _ForwardIterator, typename _Tp>
+constexpr void __uninitialized_copy_a(_InputIterator __first, _Sentinel __last,
+ _ForwardIterator __result, _Tp) {
+ uninitialized_copy(__first, __last, __result);
+}
+template <typename _Tp, typename _Alloc> struct _Vector_base {
+ typedef __alloc_traits<_Alloc>::template rebind<_Tp>::other _Tp_alloc_type;
+ typedef __alloc_traits<_Tp_alloc_type>::pointer pointer;
+ struct _Vector_impl : _Tp_alloc_type {
+ constexpr _Vector_impl(_Tp_alloc_type) {}
+ pointer _M_start;
+ };
+ constexpr ~_Vector_base() { _M_deallocate(_M_impl._M_start); }
+ _Vector_impl _M_impl;
+ constexpr pointer _M_allocate(long __n) {
+ return __n ? __alloc_traits<_Tp_alloc_type>::allocate(_M_impl, __n)
+ : pointer();
+ }
+ constexpr void _M_deallocate(pointer __p) {
+ __alloc_traits<_Tp_alloc_type>::deallocate(_M_impl, __p, 0);
+ }
+};
+template <typename _Tp, typename _Alloc = __new_allocator<_Tp>>
+struct vector : _Vector_base<_Tp, _Alloc> {
+ typedef _Vector_base<_Tp, _Alloc> _Base;
+ typedef _Base::_Tp_alloc_type _Tp_alloc_type;
+ typedef _Alloc allocator_type;
+ constexpr vector(initializer_list<_Tp> __l,
+ allocator_type __a = allocator_type())
+ : _Base(__a) {
+ long __trans_tmp_1 = __l.size();
+ _M_range_initialize_n(__l.begin(), __l.end(), __trans_tmp_1);
+ }
+ constexpr __alloc_traits<_Tp_alloc_type>::reference operator[](long __n) {
+ return *(this->_M_impl._M_start + __n);
+ }
+ template <typename _Iterator, typename _Sentinel>
+ constexpr void _M_range_initialize_n(_Iterator __first, _Sentinel __last,
+ long __n) {
+ typename _Base::pointer __start = this->_M_allocate(__n);
+ this->_M_impl._M_start = __start;
+ _Tp_alloc_type __trans_tmp_2;
+ __uninitialized_copy_a(__first, __last, __start, __trans_tmp_2);
+ }
+};
+namespace meta {
+using info = decltype(^^int);
+struct access_context {
+ info _M_scope;
+ info _M_designating_class;
+};
+consteval vector<info> bases_of(info, access_context);
+} // namespace meta
+} // namespace std
+template <class L> using mp_is_value_list = L;
+template <template <class> class, class...> long cx_count_if;
+template <std::meta::info> struct rf_base_desc;
+struct X1 {};
+struct X2 {};
+struct Z : X1, X2 {};
+int main() {
+ constexpr auto all = std::meta::access_context();
+ using B1 = rf_base_desc<bases_of(^^Z, all)[0]>;
+ using B2 = rf_base_desc<bases_of(^^Z, all)[1]>;
+ (void) cx_count_if<mp_is_value_list, B1, B2>;
+}
base-commit: be1da01067c898a3e3979bfb1edd05f115ab2e3e
--
2.54.0