+2019-11-07 Jason Merrill <jason@redhat.com>
+
+ Implement D1959R0, remove weak_equality and strong_equality.
+ * method.c (enum comp_cat_tag, comp_cat_info): Remove *_equality.
+ (genericize_spaceship, common_comparison_type): Likewise.
+ * typeck.c (cp_build_binary_op): Move SPACESHIP_EXPR to be with the
+ relational operators, exclude other types no longer supported.
+
2019-11-06 Jason Merrill <jason@redhat.com>
Implement D1907R1 "structural type".
enum comp_cat_tag
{
- cc_weak_equality,
- cc_strong_equality,
cc_partial_ordering,
cc_weak_ordering,
cc_strong_ordering,
};
static const comp_cat_info_t comp_cat_info[cc_last]
= {
- { "weak_equality", "equivalent", "nonequivalent" },
- { "strong_equality", "equal", "nonequal" },
{ "partial_ordering", "equivalent", "greater", "less", "unordered" },
{ "weak_ordering", "equivalent", "greater", "less" },
{ "strong_ordering", "equal", "greater", "less" }
return cc_strong_ordering;
else if (TREE_CODE (optype) == REAL_TYPE)
return cc_partial_ordering;
- else if (TYPE_PTRFN_P (optype) || TYPE_PTRMEM_P (optype)
- || NULLPTR_TYPE_P (optype))
- return cc_strong_equality;
- else if (TREE_CODE (optype) == COMPLEX_TYPE)
- {
- tree intype = optype;
- while (TREE_CODE (intype) == COMPLEX_TYPE)
- intype = TREE_TYPE (intype);
- if (TREE_CODE (intype) == REAL_TYPE)
- return cc_weak_equality;
- else
- return cc_strong_equality;
- }
- /* FIXME should vector <=> produce a vector of one of the above? */
+ /* ??? should vector <=> produce a vector of one of the above? */
gcc_unreachable ();
}
comp_cat_tag tag = cat_tag_for (type);
gcc_checking_assert (tag < cc_last);
- tree eq = lookup_comparison_result (tag, type, 0);
- tree negt = lookup_comparison_result (tag, type, 1);
-
- if (tag == cc_strong_equality || tag == cc_weak_equality)
- {
- tree comp = fold_build2 (EQ_EXPR, boolean_type_node, op0, op1);
- return fold_build3 (COND_EXPR, type, comp, eq, negt);
- }
-
tree r;
op0 = save_expr (op0);
op1 = save_expr (op1);
+ tree gt = lookup_comparison_result (tag, type, 1);
+
if (tag == cc_partial_ordering)
{
/* op0 == op1 ? equivalent : op0 < op1 ? less :
op0 > op1 ? greater : unordered */
tree uo = lookup_comparison_result (tag, type, 3);
tree comp = fold_build2 (GT_EXPR, boolean_type_node, op0, op1);
- r = fold_build3 (COND_EXPR, type, comp, negt, uo);
+ r = fold_build3 (COND_EXPR, type, comp, gt, uo);
}
else
/* op0 == op1 ? equal : op0 < op1 ? less : greater */
- r = negt;
+ r = gt;
tree lt = lookup_comparison_result (tag, type, 2);
tree comp = fold_build2 (LT_EXPR, boolean_type_node, op0, op1);
r = fold_build3 (COND_EXPR, type, comp, lt, r);
+ tree eq = lookup_comparison_result (tag, type, 0);
comp = fold_build2 (EQ_EXPR, boolean_type_node, op0, op1);
r = fold_build3 (COND_EXPR, type, comp, eq, r);
return void_type_node;
}
- /* Otherwise, if at least one T i is std::weak_equality, or at least one T i
- is std::strong_equality and at least one T j is std::partial_ordering or
- std::weak_ordering, U is std::weak_equality. */
- if (tree t = seen[cc_weak_equality]) return t;
- if (seen[cc_strong_equality]
- && (seen[cc_partial_ordering] || seen[cc_weak_ordering]))
- return lookup_comparison_category (cc_weak_equality);
-
- /* Otherwise, if at least one T i is std::strong_equality, U is
- std::strong_equality. */
- if (tree t = seen[cc_strong_equality]) return t;
-
/* Otherwise, if at least one T i is std::partial_ordering, U is
std::partial_ordering. */
if (tree t = seen[cc_partial_ordering]) return t;
case EQ_EXPR:
case NE_EXPR:
- case SPACESHIP_EXPR:
if (code0 == VECTOR_TYPE && code1 == VECTOR_TYPE)
goto vector_compare;
if ((complain & tf_warning)
warn_for_null_address (location, op1, complain);
}
else if ((code0 == POINTER_TYPE && code1 == POINTER_TYPE)
- || (code == SPACESHIP_EXPR
- ? TYPE_PTRMEM_P (type0) && TYPE_PTRMEM_P (type1)
- : TYPE_PTRDATAMEM_P (type0) && TYPE_PTRDATAMEM_P (type1)))
+ || (TYPE_PTRDATAMEM_P (type0) && TYPE_PTRDATAMEM_P (type1)))
result_type = composite_pointer_type (location,
type0, type1, op0, op1,
CPO_COMPARISON, complain);
case GE_EXPR:
case LT_EXPR:
case GT_EXPR:
+ case SPACESHIP_EXPR:
if (TREE_CODE (orig_op0) == STRING_CST
|| TREE_CODE (orig_op1) == STRING_CST)
{
tree_code orig_code0 = TREE_CODE (orig_type0);
tree orig_type1 = TREE_TYPE (orig_op1);
tree_code orig_code1 = TREE_CODE (orig_type1);
- if ((orig_code0 == BOOLEAN_TYPE) != (orig_code1 == BOOLEAN_TYPE))
+ if (!result_type)
+ /* Nope. */;
+ else if ((orig_code0 == BOOLEAN_TYPE) != (orig_code1 == BOOLEAN_TYPE))
/* "If one of the operands is of type bool and the other is not, the
program is ill-formed." */
result_type = NULL_TREE;
/* We only do array/function-to-pointer conversion if "at least one of
the operands is of pointer type". */
result_type = NULL_TREE;
+ else if (TYPE_PTRFN_P (result_type) || NULLPTR_TYPE_P (result_type))
+ /* <=> no longer supports equality relations. */
+ result_type = NULL_TREE;
else if (orig_code0 == ENUMERAL_TYPE && orig_code1 == ENUMERAL_TYPE
&& !(same_type_ignoring_top_level_qualifiers_p
(orig_type0, orig_type1)))
--- /dev/null
+// { dg-do run { target c++2a } }
+
+#include <compare>
+
+#define assert(X) do { if (!(X)) __builtin_abort(); } while(0)
+
+void f(){}
+void g(){}
+
+int main()
+{
+ {
+ const auto v = &f <=> &g; // { dg-error "invalid operands" }
+ }
+
+ {
+ struct A { int i; int j; };
+ constexpr auto v = &A::i <=> &A::j; // { dg-error "invalid operands" }
+ }
+
+ {
+ struct A { void f(); };
+ constexpr auto v = &A::f <=> &A::f; // { dg-error "invalid operands" }
+ }
+}
#define assert(X) do { if (!(X)) __builtin_abort(); } while(0)
-void f(){}
-void g(){}
-
int main()
{
{
static_assert (!is_gt (v));
static_assert (is_gteq (v));
}
-
- {
- // GCC doesn't consider &f == &g to be a constant expression (PR 69681)
- const auto v = &f <=> &g;
- static_assert (__is_same_as (decltype (v), const std::strong_equality));
- assert (!is_eq (v));
- assert (is_neq (v));
- }
-
- {
- struct A { int i; int j; };
- constexpr auto v = &A::i <=> &A::j;
- static_assert (__is_same_as (decltype (v), const std::strong_equality));
- static_assert (!is_eq (v));
- static_assert (is_neq (v));
- }
-
- {
- struct A { void f(); };
- constexpr auto v = &A::f <=> &A::f;
- static_assert (__is_same_as (decltype (v), const std::strong_equality));
- static_assert (is_eq (v));
- static_assert (!is_neq (v));
- }
}
#define assert(X) do { if (!(X)) __builtin_abort(); } while(0)
-void f(){}
-void g(){}
-
template <class T, class U, class R>
constexpr bool check(T a, U b, R expected)
{
static_assert (check (&ar[1], &ar[0], std::strong_ordering::greater));
static_assert (check (3.14, 3.14, std::partial_ordering::equivalent));
-
- // GCC doesn't consider &f == &g to be a constant expression (PR 69681)
- assert (check (&f, &g, std::strong_equality::nonequal));
-
- struct A { int i; int j; };
- static_assert (check (&A::i, &A::j, std::strong_equality::nonequal));
-
- struct A2 { void f(); };
- static_assert (check (&A2::f, &A2::f, std::strong_equality::equal));
}
-// { dg-do run { target c++2a } }
+// { dg-do compile { target c++2a } }
// { dg-options "-fext-numeric-literals" }
-#include <compare>
-
int main()
{
// GCC complex literal extension
- {
- constexpr auto v = 1 <=> 1i;
- static_assert (__is_same_as (decltype (v), const std::strong_equality));
- static_assert (!is_eq (v));
- static_assert (is_neq (v));
- }
- {
- constexpr auto v = 1i <=> 1.0i;
- static_assert (__is_same_as (decltype (v), const std::weak_equality));
- static_assert (is_eq (v));
- static_assert (!is_neq (v));
- }
+ { constexpr auto v = 1 <=> 1i; } // { dg-error "invalid operands" }
+ { constexpr auto v = 1i <=> 1.0i; } // { dg-error "invalid operands" }
}
+2019-11-07 Jason Merrill <jason@redhat.com>
+
+ * libsupc++/compare: Remove strong_equality and weak_equality.
+
2019-11-06 Jonathan Wakely <jwakely@redhat.com>
* include/Makefile.in: Regenerate.
};
}
- class weak_equality
- {
- int _M_value;
-
- constexpr explicit
- weak_equality(__cmp_cat::_Eq __val) noexcept
- : _M_value(int(__val))
- { }
-
- public:
- // valid values
-
- static const weak_equality equivalent;
- static const weak_equality nonequivalent;
-
- // comparisons
-
- friend constexpr bool
- operator==(weak_equality __v, __cmp_cat::__unspec) noexcept
- { return __v._M_value == 0; }
-
- friend constexpr bool
- operator==(weak_equality, weak_equality) noexcept = default;
-
- friend constexpr weak_equality
- operator<=>(weak_equality __v, __cmp_cat::__unspec) noexcept
- { return __v; }
-
- friend constexpr weak_equality
- operator<=>(__cmp_cat::__unspec, weak_equality __v) noexcept
- { return __v; }
- };
-
- // valid values' definitions
- inline constexpr weak_equality
- weak_equality::equivalent(__cmp_cat::_Eq::equivalent);
-
- inline constexpr weak_equality
- weak_equality::nonequivalent(__cmp_cat::_Eq::nonequivalent);
-
- class strong_equality
- {
- int _M_value;
-
- constexpr explicit
- strong_equality(__cmp_cat::_Eq __val) noexcept
- : _M_value(int(__val))
- { }
-
- public:
- // valid values
-
- static const strong_equality equal;
- static const strong_equality nonequal;
- static const strong_equality equivalent;
- static const strong_equality nonequivalent;
-
- // conversion
- constexpr operator weak_equality() const noexcept
- {
- if (_M_value == 0)
- return weak_equality::equivalent;
- else
- return weak_equality::nonequivalent;
- }
-
- // comparisons
-
- friend constexpr bool
- operator==(strong_equality __v, __cmp_cat::__unspec) noexcept
- { return __v._M_value == 0; }
-
- friend constexpr bool
- operator==(strong_equality, strong_equality) noexcept = default;
-
- friend constexpr strong_equality
- operator<=>(strong_equality __v, __cmp_cat::__unspec) noexcept
- { return __v; }
-
- friend constexpr strong_equality
- operator<=>(__cmp_cat::__unspec, strong_equality __v) noexcept
- { return __v; }
- };
-
- // valid values' definitions
- inline constexpr strong_equality
- strong_equality::equal(__cmp_cat::_Eq::equal);
-
- inline constexpr strong_equality
- strong_equality::nonequal(__cmp_cat::_Eq::nonequal);
-
- inline constexpr strong_equality
- strong_equality::equivalent(__cmp_cat::_Eq::equivalent);
-
- inline constexpr strong_equality
- strong_equality::nonequivalent(__cmp_cat::_Eq::nonequivalent);
-
class partial_ordering
{
int _M_value;
static const partial_ordering greater;
static const partial_ordering unordered;
- // conversion
- constexpr operator weak_equality() const noexcept
- {
- if (_M_value == 0)
- return weak_equality::equivalent;
- else
- return weak_equality::nonequivalent;
- }
-
// comparisons
friend constexpr bool
operator==(partial_ordering __v, __cmp_cat::__unspec) noexcept
static const weak_ordering equivalent;
static const weak_ordering greater;
- // conversions
- constexpr operator weak_equality() const noexcept
- {
- if (_M_value == 0)
- return weak_equality::equivalent;
- else
- return weak_equality::nonequivalent;
- }
-
constexpr operator partial_ordering() const noexcept
{
if (_M_value == 0)
static const strong_ordering equivalent;
static const strong_ordering greater;
- // conversions
- constexpr operator weak_equality() const noexcept
- {
- if (_M_value == 0)
- return weak_equality::equivalent;
- else
- return weak_equality::nonequivalent;
- }
-
- constexpr operator strong_equality() const noexcept
- {
- if (_M_value == 0)
- return strong_equality::equal;
- else
- return strong_equality::nonequal;
- }
-
constexpr operator partial_ordering() const noexcept
{
if (_M_value == 0)
// named comparison functions
constexpr bool
- is_eq(weak_equality __cmp) noexcept
+ is_eq(partial_ordering __cmp) noexcept
{ return __cmp == 0; }
constexpr bool
- is_neq(weak_equality __cmp) noexcept
+ is_neq(partial_ordering __cmp) noexcept
{ return __cmp != 0; }
constexpr bool