Implement D1959R0, remove weak_equality and strong_equality.
Shortly after I finished implementing the previous semantics, the committee decided to remove the *_equality comparison categories, because they were largely obsoleted by the earlier change that separated operator== from its original dependency on operator<=>. gcc/cp/ * 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. libstdc++-v3/ * libsupc++/compare: Remove strong_equality and weak_equality. From-SVN: r277925
This commit is contained in:
parent
c38ee9a2e8
commit
4629ea5560
|
@ -1,3 +1,11 @@
|
|||
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".
|
||||
|
|
|
@ -882,8 +882,6 @@ do_build_copy_assign (tree fndecl)
|
|||
|
||||
enum comp_cat_tag
|
||||
{
|
||||
cc_weak_equality,
|
||||
cc_strong_equality,
|
||||
cc_partial_ordering,
|
||||
cc_weak_ordering,
|
||||
cc_strong_ordering,
|
||||
|
@ -901,8 +899,6 @@ struct comp_cat_info_t
|
|||
};
|
||||
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" }
|
||||
|
@ -1028,21 +1024,8 @@ spaceship_comp_cat (tree optype)
|
|||
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 ();
|
||||
}
|
||||
|
||||
|
@ -1065,35 +1048,29 @@ genericize_spaceship (tree type, tree op0, tree op1)
|
|||
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);
|
||||
|
||||
|
@ -1178,18 +1155,6 @@ common_comparison_type (vec<tree> &comps)
|
|||
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;
|
||||
|
|
|
@ -4889,7 +4889,6 @@ cp_build_binary_op (const op_location_t &location,
|
|||
|
||||
case EQ_EXPR:
|
||||
case NE_EXPR:
|
||||
case SPACESHIP_EXPR:
|
||||
if (code0 == VECTOR_TYPE && code1 == VECTOR_TYPE)
|
||||
goto vector_compare;
|
||||
if ((complain & tf_warning)
|
||||
|
@ -4966,9 +4965,7 @@ cp_build_binary_op (const op_location_t &location,
|
|||
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);
|
||||
|
@ -5172,6 +5169,7 @@ cp_build_binary_op (const op_location_t &location,
|
|||
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)
|
||||
{
|
||||
|
@ -5369,7 +5367,9 @@ cp_build_binary_op (const op_location_t &location,
|
|||
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;
|
||||
|
@ -5378,6 +5378,9 @@ cp_build_binary_op (const op_location_t &location,
|
|||
/* 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)))
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
// { 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" }
|
||||
}
|
||||
}
|
|
@ -4,9 +4,6 @@
|
|||
|
||||
#define assert(X) do { if (!(X)) __builtin_abort(); } while(0)
|
||||
|
||||
void f(){}
|
||||
void g(){}
|
||||
|
||||
int main()
|
||||
{
|
||||
{
|
||||
|
@ -66,28 +63,4 @@ 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));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,9 +4,6 @@
|
|||
|
||||
#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)
|
||||
{
|
||||
|
@ -29,13 +26,4 @@ int main()
|
|||
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));
|
||||
}
|
||||
|
|
|
@ -1,21 +1,9 @@
|
|||
// { 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" }
|
||||
}
|
||||
|
|
|
@ -1,3 +1,7 @@
|
|||
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.
|
||||
|
|
|
@ -59,103 +59,6 @@ namespace std
|
|||
};
|
||||
}
|
||||
|
||||
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;
|
||||
|
@ -183,15 +86,6 @@ namespace std
|
|||
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
|
||||
|
@ -279,15 +173,6 @@ namespace std
|
|||
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)
|
||||
|
@ -385,23 +270,6 @@ namespace std
|
|||
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)
|
||||
|
@ -494,11 +362,11 @@ namespace std
|
|||
|
||||
// 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
|
||||
|
|
Loading…
Reference in New Issue