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

Reply via email to