2025-06-25 Jakub Jelinek <ja...@redhat.com>
gcc/cp/
* cp-trait.def: Implement C++26 P2830R10 - Constexpr Type Ordering.
(TYPE_ORDER): New.
* method.cc (type_order_value): Define.
* cp-tree.h (type_order_value): Declare.
* semantics.cc (trait_expr_value): Use gcc_unreachable also
for CPTK_TYPE_ORDER, adjust comment.
(finish_trait_expr): Handle CPTK_TYPE_ORDER.
* constraint.cc (diagnose_trait_expr): Likewise.
gcc/testsuite/
* g++.dg/cpp26/type-order1.C: New test.
* g++.dg/cpp26/type-order2.C: New test.
* g++.dg/cpp26/type-order3.C: New test.
libstdc++-v3/
* include/bits/version.def (type_order): New.
* include/bits/version.h: Regenerate.
* libsupc++/compare: Define __glibcxx_want_type_order before
including bits/version.h.
(std::type_order, std::type_order_v): New trait and template variable.
* testsuite/18_support/comparisons/type_order/1.cc: New test.
--- gcc/cp/method.cc.jj 2025-06-25 16:04:51.611158952 +0200
+++ gcc/cp/method.cc 2025-06-25 16:09:32.017556551 +0200
@@ -3951,5 +3951,26 @@ num_artificial_parms_for (const_tree fn)
return count;
}
+/* Return value of the __builtin_type_order trait. */
+
+tree
+type_order_value (tree type1, tree type2)
+{
+ tree rettype = lookup_comparison_category (cc_strong_ordering);
+ if (rettype == error_mark_node)
+ return rettype;
+ int ret;
+ if (type1 == type2)
+ ret = 0;
+ else
+ {
+ const char *name1 = ASTRDUP (mangle_type_string (type1));
+ const char *name2 = mangle_type_string (type2);
+ ret = strcmp (name1, name2);
+ }
+ return lookup_comparison_result (cc_strong_ordering, rettype,
+ ret == 0 ? 0 : ret > 0 ? 1 : 2);
+}
+
#include "gt-cp-method.h"
--- gcc/cp/cp-tree.h.jj 2025-06-25 16:04:51.610158965 +0200
+++ gcc/cp/cp-tree.h 2025-06-25 16:09:32.019556525 +0200
@@ -7557,6 +7557,8 @@ extern bool ctor_omit_inherited_parms (
extern tree locate_ctor (tree);
extern tree implicitly_declare_fn (special_function_kind, tree,
bool, tree, tree);
+extern tree type_order_value (tree, tree);
+
/* In module.cc */
class module_state; /* Forward declare. */
inline bool modules_p () { return flag_modules != 0; }
--- gcc/cp/semantics.cc.jj 2025-06-25 16:04:51.633158669 +0200
+++ gcc/cp/semantics.cc 2025-06-25 16:09:32.021556500 +0200
@@ -13593,8 +13593,10 @@ trait_expr_value (cp_trait_kind kind, tr
case CPTK_IS_DEDUCIBLE:
return type_targs_deducible_from (type1, type2);
- /* __array_rank is handled in finish_trait_expr. */
+ /* __array_rank and __builtin_type_order are handled in
+ finish_trait_expr. */
case CPTK_RANK:
+ case CPTK_TYPE_ORDER:
gcc_unreachable ();
#define DEFTRAIT_TYPE(CODE, NAME, ARITY) \
@@ -13724,6 +13726,12 @@ finish_trait_expr (location_t loc, cp_tr
tree trait_expr = make_node (TRAIT_EXPR);
if (kind == CPTK_RANK)
TREE_TYPE (trait_expr) = size_type_node;
+ else if (kind == CPTK_TYPE_ORDER)
+ {
+ tree val = type_order_value (type1, type1);
+ if (val != error_mark_node)
+ TREE_TYPE (trait_expr) = TREE_TYPE (val);
+ }
else
TREE_TYPE (trait_expr) = boolean_type_node;
TRAIT_EXPR_TYPE1 (trait_expr) = type1;
@@ -13831,6 +13839,7 @@ finish_trait_expr (location_t loc, cp_tr
case CPTK_IS_UNION:
case CPTK_IS_VOLATILE:
case CPTK_RANK:
+ case CPTK_TYPE_ORDER:
break;
case CPTK_IS_LAYOUT_COMPATIBLE:
@@ -13870,6 +13879,8 @@ finish_trait_expr (location_t loc, cp_tr
++rank;
val = build_int_cst (size_type_node, rank);
}
+ else if (kind == CPTK_TYPE_ORDER)
+ val = type_order_value (type1, type2);
else
val = (trait_expr_value (kind, type1, type2)
? boolean_true_node : boolean_false_node);
--- gcc/cp/constraint.cc.jj 2025-06-18 17:24:03.973867379 +0200
+++ gcc/cp/constraint.cc 2025-06-25 17:20:58.458202011 +0200
@@ -3266,6 +3266,9 @@ diagnose_trait_expr (tree expr, tree arg
case CPTK_RANK:
inform (loc, " %qT cannot yield a rank", t1);
break;
+ case CPTK_TYPE_ORDER:
+ inform (loc, " %qT and %qT cannot be ordered", t1, t2);
+ break;
case CPTK_REF_CONSTRUCTS_FROM_TEMPORARY:
inform (loc, " %qT is not a reference that binds to a temporary "
"object of type %qT (direct-initialization)", t1, t2);
--- gcc/cp/cp-trait.def.jj 2025-06-25 16:04:51.609158978 +0200
+++ gcc/cp/cp-trait.def 2025-06-25 16:09:32.021556500 +0200
@@ -114,6 +114,7 @@ DEFTRAIT_TYPE (REMOVE_CVREF, "__remove_c
DEFTRAIT_TYPE (REMOVE_EXTENT, "__remove_extent", 1)
DEFTRAIT_TYPE (REMOVE_POINTER, "__remove_pointer", 1)
DEFTRAIT_TYPE (REMOVE_REFERENCE, "__remove_reference", 1)
+DEFTRAIT_EXPR (TYPE_ORDER, "__builtin_type_order", 2)
DEFTRAIT_TYPE (TYPE_PACK_ELEMENT, "__type_pack_element", -1)
DEFTRAIT_TYPE (UNDERLYING_TYPE, "__underlying_type", 1)
--- gcc/testsuite/g++.dg/cpp26/type-order1.C.jj 2025-06-25 16:09:32.021556500 +0200
+++ gcc/testsuite/g++.dg/cpp26/type-order1.C 2025-06-25 16:10:16.909979822
+0200
@@ -0,0 +1,94 @@
+// C++26 P2830R10 - Constexpr Type Ordering
+// { dg-do compile { target c++26 } }
+
+namespace std {
+ using type = enum _Ord { equivalent = 0, less = -1, greater = 1 };
+ struct strong_ordering {
+ type _M_value;
+ constexpr strong_ordering (_Ord x) : _M_value (x) {}
+ static const strong_ordering less;
+ static const strong_ordering equal;
+ static const strong_ordering greater;
+ constexpr bool operator== (const strong_ordering &x) const { return
_M_value == x._M_value; }
+ constexpr bool operator!= (const strong_ordering &x) const { return
_M_value != x._M_value; }
+ };
+ constexpr strong_ordering strong_ordering::equal (_Ord::equivalent);
+ constexpr strong_ordering strong_ordering::less (_Ord::less);
+ constexpr strong_ordering strong_ordering::greater (_Ord::greater);
+
+ template <typename T, typename U>
+ struct type_order
+ {
+ static constexpr strong_ordering value = __builtin_type_order (T, U);
+ };
+
+ template <typename T, typename U>
+ inline constexpr strong_ordering type_order_v = __builtin_type_order (T, U);
+}
+
+struct S;
+struct T;
+template <typename T>
+struct U
+{
+};
+typedef int int2;
+struct V {};
+namespace
+{
+ struct W {};
+}
+
+template <typename T, typename U>
+struct eq
+{
+ constexpr eq ()
+ {
+ static_assert (std::type_order <T, U>::value ==
std::strong_ordering::equal);
+ static_assert (std::type_order <U, T>::value ==
std::strong_ordering::equal);
+ static_assert (std::type_order_v <T, U> == std::strong_ordering::equal);
+ static_assert (std::type_order_v <U, T> == std::strong_ordering::equal);
+ }
+};
+template <typename T, typename U>
+struct ne
+{
+ constexpr ne ()
+ {
+ static_assert (std::type_order <T, U>::value !=
std::strong_ordering::equal);
+ static_assert (std::type_order <U, T>::value !=
std::strong_ordering::equal);
+ static_assert (std::type_order <T, U>::value ==
std::strong_ordering::greater
+ ? std::type_order <U, T>::value == std::strong_ordering::less
+ : std::type_order <U, T>::value ==
std::strong_ordering::greater);
+ static_assert (std::type_order_v <T, U> != std::strong_ordering::equal);
+ static_assert (std::type_order_v <U, T> != std::strong_ordering::equal);
+ static_assert (std::type_order_v <T, U> == std::strong_ordering::greater
+ ? std::type_order_v <U, T> == std::strong_ordering::less
+ : std::type_order_v <U, T> == std::strong_ordering::greater);
+ }
+};
+
+constexpr eq <void, void> a;
+constexpr eq <const void, const void> b;
+constexpr eq <int, int> c;
+constexpr eq <long int, long int> d;
+constexpr eq <const volatile unsigned, const volatile unsigned> e;
+constexpr eq <S, S> f;
+constexpr eq <U <int>, U <int>> g;
+constexpr eq <unsigned[2], unsigned[2]> h;
+constexpr eq <int, int2> i;
+constexpr eq <int (*) (int, long), int (*) (int, long)> j;
+constexpr ne <int, long> k;
+constexpr ne <const int, int> l;
+constexpr ne <S, T> m;
+constexpr ne <int &, int &&> n;
+constexpr ne <U <S>, U <T>> o;
+constexpr ne <U <short>, U <char>> p;
+static_assert (std::type_order_v <S, T> != std::strong_ordering::less
+ || std::type_order_v <T, V> != std::strong_ordering::less
+ || std::type_order_v <S, V> == std::strong_ordering::less);
+constexpr ne <int (*) (int, long), int (*) (int, int)> q;
+constexpr eq <W, W> r;
+constexpr ne <V, W> s;
+constexpr eq <U <W>, U <W>> t;
+constexpr ne <U <V>, U <W>> u;
--- gcc/testsuite/g++.dg/cpp26/type-order2.C.jj 2025-06-25 16:09:32.021556500
+0200
+++ gcc/testsuite/g++.dg/cpp26/type-order2.C 2025-06-25 16:09:32.021556500
+0200
@@ -0,0 +1,4 @@
+// C++26 P2830R10 - Constexpr Type Ordering
+// { dg-do compile { target c++26 } }
+
+constexpr auto a = __builtin_type_order (int, long); // { dg-error
"'strong_ordering' is not a member of 'std'" }
--- gcc/testsuite/g++.dg/cpp26/type-order3.C.jj 2025-06-25 16:09:32.021556500
+0200
+++ gcc/testsuite/g++.dg/cpp26/type-order3.C 2025-06-25 16:09:32.021556500
+0200
@@ -0,0 +1,8 @@
+// C++26 P2830R10 - Constexpr Type Ordering
+// { dg-do compile { target c++26 } }
+
+namespace std {
+ struct strong_ordering {
+ };
+}
+constexpr auto a = __builtin_type_order (int, long); // { dg-error
"'(equal|greater|less)' is not a member of 'std::strong_ordering'" }
--- libstdc++-v3/include/bits/version.def.jj 2025-06-25 16:04:51.679158078
+0200
+++ libstdc++-v3/include/bits/version.def 2025-06-25 16:18:51.690372255
+0200
@@ -2012,6 +2012,16 @@ ftms = {
};
};
+ftms = {
+ name = type_order;
+ values = {
+ v = 202506;
+ cxxmin = 26;
+ extra_cond = "__has_builtin(__builtin_type_order) "
+ "&& __cpp_lib_three_way_comparison >= 201907L";
+ };
+};
+
// Standard test specifications.
stds[97] = ">= 199711L";
stds[03] = ">= 199711L";
--- libstdc++-v3/include/bits/version.h.jj 2025-06-25 16:04:51.679158078
+0200
+++ libstdc++-v3/include/bits/version.h 2025-06-25 16:18:57.480477517 +0200
@@ -2253,4 +2253,14 @@
#endif /* !defined(__cpp_lib_sstream_from_string_view) &&
defined(__glibcxx_want_sstream_from_string_view) */
#undef __glibcxx_want_sstream_from_string_view
+#if !defined(__cpp_lib_type_order)
+# if (__cplusplus > 202302L) && (__has_builtin(__builtin_type_order) &&
__cpp_lib_three_way_comparison >= 201907L)
+# define __glibcxx_type_order 202506L
+# if defined(__glibcxx_want_all) || defined(__glibcxx_want_type_order)
+# define __cpp_lib_type_order 202506L
+# endif
+# endif
+#endif /* !defined(__cpp_lib_type_order) && defined(__glibcxx_want_type_order)
*/
+#undef __glibcxx_want_type_order
+
#undef __glibcxx_want_all
--- libstdc++-v3/libsupc++/compare.jj 2025-06-24 18:53:13.759807726 +0200
+++ libstdc++-v3/libsupc++/compare 2025-06-25 16:18:25.221710493 +0200
@@ -35,6 +35,7 @@
#endif
#define __glibcxx_want_three_way_comparison
+#define __glibcxx_want_type_order
#include <bits/version.h>
#if __cplusplus > 201703L && __cpp_impl_three_way_comparison >= 201907L
@@ -1261,6 +1262,24 @@ namespace std _GLIBCXX_VISIBILITY(defaul
std::declval<_Up&>()));
} // namespace __detail
/// @endcond
+
+#if __glibcxx_type_order >= 202506L // C++ >= 26
+ /// Total ordering of types.
+ /// @since C++26
+
+ template<typename _Tp, typename _Up>
+ struct type_order
+ {
+ static constexpr strong_ordering value = __builtin_type_order(_Tp, _Up);
+ };
+
+ /// @ingroup variable_templates
+ /// @since C++26
+ template<typename _Tp, typename _Up>
+ inline constexpr strong_ordering type_order_v
+ = __builtin_type_order(_Tp, _Up);
+#endif // __glibcxx_type_order >= 202506L
+
#endif // __cpp_lib_three_way_comparison >= 201907L
} // namespace std
--- libstdc++-v3/testsuite/18_support/comparisons/type_order/1.cc.jj 2025-06-25 16:09:32.036556306 +0200
+++ libstdc++-v3/testsuite/18_support/comparisons/type_order/1.cc
2025-06-25 16:34:13.070598266 +0200
@@ -0,0 +1,95 @@
+// Copyright (C) 2025 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-do compile { target c++26 } }
+
+#include <compare>
+
+#if __cpp_lib_type_order != 202506L
+# error "__cpp_lib_type_order != 202506"
+#endif
+
+static_assert (std::is_same_v <decltype (std::type_order <int, int>::value),
+ const std::strong_ordering>);
+static_assert (std::is_same_v <decltype (std::type_order_v <char, short>),
+ const std::strong_ordering>);
+struct S;
+struct T;
+template <typename T>
+struct U
+{
+};
+typedef int int2;
+struct V {};
+namespace
+{
+ struct W {};
+}
+
+template <typename T, typename U>
+struct eq
+{
+ constexpr eq ()
+ {
+ static_assert (std::type_order <T, U>::value ==
std::strong_ordering::equal);
+ static_assert (std::type_order <U, T>::value ==
std::strong_ordering::equal);
+ static_assert (std::type_order_v <T, U> == std::strong_ordering::equal);
+ static_assert (std::type_order_v <U, T> == std::strong_ordering::equal);
+ }
+};
+template <typename T, typename U>
+struct ne
+{
+ constexpr ne ()
+ {
+ static_assert (std::type_order <T, U>::value !=
std::strong_ordering::equal);
+ static_assert (std::type_order <U, T>::value !=
std::strong_ordering::equal);
+ static_assert (std::type_order <T, U>::value ==
std::strong_ordering::greater
+ ? std::type_order <U, T>::value == std::strong_ordering::less
+ : std::type_order <U, T>::value ==
std::strong_ordering::greater);
+ static_assert (std::type_order_v <T, U> != std::strong_ordering::equal);
+ static_assert (std::type_order_v <U, T> != std::strong_ordering::equal);
+ static_assert (std::type_order_v <T, U> == std::strong_ordering::greater
+ ? std::type_order_v <U, T> == std::strong_ordering::less
+ : std::type_order_v <U, T> == std::strong_ordering::greater);
+ }
+};
+
+constexpr eq <void, void> a;
+constexpr eq <const void, const void> b;
+constexpr eq <int, int> c;
+constexpr eq <long int, long int> d;
+constexpr eq <const volatile unsigned, const volatile unsigned> e;
+constexpr eq <S, S> f;
+constexpr eq <U <int>, U <int>> g;
+constexpr eq <unsigned[2], unsigned[2]> h;
+constexpr eq <int, int2> i;
+constexpr eq <int (*) (int, long), int (*) (int, long)> j;
+constexpr ne <int, long> k;
+constexpr ne <const int, int> l;
+constexpr ne <S, T> m;
+constexpr ne <int &, int &&> n;
+constexpr ne <U <S>, U <T>> o;
+constexpr ne <U <short>, U <char>> p;
+static_assert (std::type_order_v <S, T> != std::strong_ordering::less
+ || std::type_order_v <T, V> != std::strong_ordering::less
+ || std::type_order_v <S, V> == std::strong_ordering::less);
+constexpr ne <int (*) (int, long), int (*) (int, int)> q;
+constexpr eq <W, W> r;
+constexpr ne <V, W> s;
+constexpr eq <U <W>, U <W>> t;
+constexpr ne <U <V>, U <W>> u;
Jakub