Skip to content

[DO NOT MERGE] I wonder if this helps the derive... #137847

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 9 additions & 3 deletions compiler/rustc_ast/src/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -906,6 +906,10 @@ pub enum BinOpKind {
Ge,
/// The `>` operator (greater than)
Gt,
/// The `<=>` operator (Ord::cmp)
Cmp,
/// The `<==>` operator (PartialOrd::partial_cmp)
CmpPartial,
}

impl BinOpKind {
Expand All @@ -930,6 +934,8 @@ impl BinOpKind {
Ne => "!=",
Ge => ">=",
Gt => ">",
Cmp => "<=>",
CmpPartial => "<==>",
}
}

Expand All @@ -946,7 +952,7 @@ impl BinOpKind {
BitAnd => ExprPrecedence::BitAnd,
BitXor => ExprPrecedence::BitXor,
BitOr => ExprPrecedence::BitOr,
Lt | Gt | Le | Ge | Eq | Ne => ExprPrecedence::Compare,
Lt | Gt | Le | Ge | Eq | Ne | Cmp | CmpPartial => ExprPrecedence::Compare,
And => ExprPrecedence::LAnd,
Or => ExprPrecedence::LOr,
}
Expand All @@ -955,7 +961,7 @@ impl BinOpKind {
pub fn fixity(&self) -> Fixity {
use BinOpKind::*;
match self {
Eq | Ne | Lt | Le | Gt | Ge => Fixity::None,
Eq | Ne | Lt | Le | Gt | Ge | Cmp | CmpPartial => Fixity::None,
Add | Sub | Mul | Div | Rem | And | Or | BitXor | BitAnd | BitOr | Shl | Shr => {
Fixity::Left
}
Expand All @@ -965,7 +971,7 @@ impl BinOpKind {
pub fn is_comparison(self) -> bool {
use BinOpKind::*;
match self {
Eq | Ne | Lt | Le | Gt | Ge => true,
Eq | Ne | Lt | Le | Gt | Ge | Cmp | CmpPartial => true,
Add | Sub | Mul | Div | Rem | And | Or | BitXor | BitAnd | BitOr | Shl | Shr => false,
}
}
Expand Down
23 changes: 19 additions & 4 deletions compiler/rustc_builtin_macros/src/deriving/cmp/ord.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use rustc_ast::MetaItem;
use rustc_ast::ptr::P;
use rustc_ast::{BinOpKind, BorrowKind, Expr, ExprKind, MetaItem, Mutability};
use rustc_expand::base::{Annotatable, ExtCtxt};
use rustc_span::{Ident, Span, sym};
use thin_vec::thin_vec;
Expand Down Expand Up @@ -42,7 +43,6 @@ pub(crate) fn expand_deriving_ord(
pub(crate) fn cs_cmp(cx: &ExtCtxt<'_>, span: Span, substr: &Substructure<'_>) -> BlockOrExpr {
let test_id = Ident::new(sym::cmp, span);
let equal_path = cx.path_global(span, cx.std_path(&[sym::cmp, sym::Ordering, sym::Equal]));
let cmp_path = cx.std_path(&[sym::cmp, sym::Ord, sym::cmp]);

// Builds:
//
Expand All @@ -63,8 +63,23 @@ pub(crate) fn cs_cmp(cx: &ExtCtxt<'_>, span: Span, substr: &Substructure<'_>) ->
let [other_expr] = &field.other_selflike_exprs[..] else {
cx.dcx().span_bug(field.span, "not exactly 2 arguments in `derive(Ord)`");
};
let args = thin_vec![field.self_expr.clone(), other_expr.clone()];
cx.expr_call_global(field.span, cmp_path.clone(), args)
let convert = |expr: &P<Expr>| {
if let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, inner) = &expr.kind {
if let ExprKind::Block(..) = &inner.kind {
// `&{ x }` form: remove the `&`, add parens.
cx.expr_paren(field.span, inner.clone())
} else {
// `&x` form: remove the `&`.
inner.clone()
}
} else {
cx.expr_deref(field.span, expr.clone())
}
};

let lhs = convert(&field.self_expr);
let rhs = convert(&other_expr);
cx.expr_binary(field.span, BinOpKind::Cmp, lhs, rhs)
}
CsFold::Combine(span, expr1, expr2) => {
let eq_arm = cx.arm(span, cx.pat_path(span, equal_path.clone()), expr1);
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_hir/src/lang_items.rs
Original file line number Diff line number Diff line change
Expand Up @@ -277,6 +277,7 @@ language_item_table! {
OrderingEnum, sym::Ordering, ordering_enum, Target::Enum, GenericRequirement::Exact(0);
PartialEq, sym::eq, eq_trait, Target::Trait, GenericRequirement::Exact(1);
PartialOrd, sym::partial_ord, partial_ord_trait, Target::Trait, GenericRequirement::Exact(1);
Ord, sym::Ord, ord_trait, Target::Trait, GenericRequirement::Exact(0);
CVoid, sym::c_void, c_void, Target::Enum, GenericRequirement::None;

// A number of panic-related lang items. The `panic` item corresponds to divide-by-zero and
Expand Down
30 changes: 28 additions & 2 deletions compiler/rustc_hir_typeck/src/op.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
use rustc_data_structures::packed::Pu128;
use rustc_errors::codes::*;
use rustc_errors::{Applicability, Diag, struct_span_code_err};
use rustc_hir::LangItem;
use rustc_infer::traits::ObligationCauseCode;
use rustc_middle::ty::adjustment::{
Adjust, Adjustment, AllowTwoPhase, AutoBorrow, AutoBorrowMutability,
Expand Down Expand Up @@ -194,6 +195,19 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
self.demand_suptype(rhs_span, lhs_ty, rhs_ty);
tcx.types.bool
}

BinOpCategory::ThreeWayComparison => {
// both LHS and RHS and result will have the same type
self.demand_suptype(rhs_span, lhs_ty, rhs_ty);
tcx.ty_ordering_enum(Some(lhs_span))
}

BinOpCategory::ThreeWayComparisonPartial => {
// both LHS and RHS and result will have the same type
self.demand_suptype(rhs_span, lhs_ty, rhs_ty);
let ordering_ty = tcx.ty_ordering_enum(Some(lhs_span));
Ty::new_lang_item(tcx, ordering_ty, LangItem::Option).unwrap()
}
}
}

Expand Down Expand Up @@ -1006,7 +1020,9 @@ fn lang_item_for_op(
| hir::BinOpKind::Eq
| hir::BinOpKind::Ne
| hir::BinOpKind::And
| hir::BinOpKind::Or => {
| hir::BinOpKind::Or
| hir::BinOpKind::Cmp
| hir::BinOpKind::CmpPartial => {
span_bug!(span, "impossible assignment operation: {}=", op.node.as_str())
}
}
Expand All @@ -1027,6 +1043,8 @@ fn lang_item_for_op(
hir::BinOpKind::Ge => (sym::ge, lang.partial_ord_trait()),
hir::BinOpKind::Gt => (sym::gt, lang.partial_ord_trait()),
hir::BinOpKind::Eq => (sym::eq, lang.eq_trait()),
hir::BinOpKind::Cmp => (sym::cmp, lang.ord_trait()),
hir::BinOpKind::CmpPartial => (sym::partial_cmp, lang.partial_ord_trait()),
hir::BinOpKind::Ne => (sym::ne, lang.eq_trait()),
hir::BinOpKind::And | hir::BinOpKind::Or => {
span_bug!(span, "&& and || are not overloadable")
Expand Down Expand Up @@ -1062,6 +1080,9 @@ enum BinOpCategory {
/// ==, !=, etc -- takes equal types, produces bools, except for simd,
/// which produce the input type
Comparison,

ThreeWayComparison,
ThreeWayComparisonPartial,
}

impl BinOpCategory {
Expand All @@ -1086,6 +1107,9 @@ impl BinOpCategory {
| hir::BinOpKind::Ge
| hir::BinOpKind::Gt => BinOpCategory::Comparison,

hir::BinOpKind::Cmp => BinOpCategory::ThreeWayComparison,
hir::BinOpKind::CmpPartial => BinOpCategory::ThreeWayComparisonPartial,

hir::BinOpKind::And | hir::BinOpKind::Or => BinOpCategory::Shortcircuit,
}
}
Expand Down Expand Up @@ -1157,7 +1181,9 @@ fn is_builtin_binop<'tcx>(lhs: Ty<'tcx>, rhs: Ty<'tcx>, op: hir::BinOp) -> bool
|| lhs.is_bool() && rhs.is_bool()
}

BinOpCategory::Comparison => {
BinOpCategory::Comparison
| BinOpCategory::ThreeWayComparison
| BinOpCategory::ThreeWayComparisonPartial => {
lhs.references_error() || rhs.references_error() || lhs.is_scalar() && rhs.is_scalar()
}
}
Expand Down
4 changes: 3 additions & 1 deletion compiler/rustc_lint/src/unused.rs
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,9 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults {
| hir::BinOpKind::Le
| hir::BinOpKind::Ne
| hir::BinOpKind::Ge
| hir::BinOpKind::Gt => Some("comparison"),
| hir::BinOpKind::Gt
| hir::BinOpKind::Cmp
| hir::BinOpKind::CmpPartial => Some("comparison"),
hir::BinOpKind::Add
| hir::BinOpKind::Sub
| hir::BinOpKind::Div
Expand Down
5 changes: 4 additions & 1 deletion compiler/rustc_mir_build/src/thir/cx/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1329,6 +1329,9 @@ fn bin_op(op: hir::BinOpKind) -> BinOp {
hir::BinOpKind::Ne => BinOp::Ne,
hir::BinOpKind::Ge => BinOp::Ge,
hir::BinOpKind::Gt => BinOp::Gt,
_ => bug!("no equivalent for ast binop {:?}", op),
hir::BinOpKind::Cmp => BinOp::Cmp,
hir::BinOpKind::And | hir::BinOpKind::Or | hir::BinOpKind::CmpPartial => {
bug!("no equivalent for ast binop {:?}", op)
}
}
}
2 changes: 1 addition & 1 deletion compiler/rustc_mir_transform/src/validate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1105,7 +1105,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
check_kinds!(
x,
"Cannot three-way compare non-integer type {:?}",
ty::Char | ty::Uint(..) | ty::Int(..)
ty::Char | ty::Uint(..) | ty::Int(..) | ty::Bool
)
}
}
Expand Down
2 changes: 0 additions & 2 deletions compiler/rustc_parse/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -210,8 +210,6 @@ pub(crate) enum InvalidComparisonOperatorSub {
invalid: String,
correct: String,
},
#[label(parse_spaceship_operator_invalid)]
Spaceship(#[primary_span] Span),
}

#[derive(Diagnostic)]
Expand Down
13 changes: 12 additions & 1 deletion compiler/rustc_parse/src/parser/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,16 @@ impl<'a> Parser<'a> {
}

self.expected_token_types.insert(TokenType::Operator);
while let Some(op) = self.check_assoc_op() {
while let Some(mut op) = self.check_assoc_op() {
// Look for `<=>`
if op.node == AssocOp::Binary(BinOpKind::Le) && self.look_ahead(1, |t| *t == token::Gt) {
//let sp = op.span.to(self.token.span);
//op = source_map::respan(sp, AssocOp::Cmp);
op.node = AssocOp::Binary(BinOpKind::Cmp);
self.bump();
}
let op = op;

let lhs_span = self.interpolated_or_expr_span(&lhs);
let cur_op_span = self.token.span;
let restrictions = if op.node.is_assign_like() {
Expand Down Expand Up @@ -225,6 +234,7 @@ impl<'a> Parser<'a> {
self.bump();
}

/*
// Look for C++'s `<=>` and recover
if op.node == AssocOp::Binary(BinOpKind::Le)
&& self.token == token::Gt
Expand All @@ -238,6 +248,7 @@ impl<'a> Parser<'a> {
});
self.bump();
}
*/

if self.prev_token == token::BinOp(token::Plus)
&& self.token == token::BinOp(token::Plus)
Expand Down
1 change: 1 addition & 0 deletions library/core/src/cmp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -937,6 +937,7 @@ impl<T: Clone> Clone for Reverse<T> {
/// [`PartialOrd`] and [`PartialEq`] to disagree.
///
/// [`cmp`]: Ord::cmp
#[cfg_attr(not(bootstrap), lang = "Ord")]
#[doc(alias = "<")]
#[doc(alias = ">")]
#[doc(alias = "<=")]
Expand Down
27 changes: 27 additions & 0 deletions tests/mir-opt/building/spaceship.bar.built.after.mir
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// MIR for `bar` after built

fn bar(_1: (i32, u32), _2: (i32, u32)) -> std::cmp::Ordering {
debug a => _1;
debug b => _2;
let mut _0: std::cmp::Ordering;
let mut _3: &(i32, u32);
let mut _4: &(i32, u32);

bb0: {
StorageLive(_3);
_3 = &_1;
StorageLive(_4);
_4 = &_2;
_0 = <(i32, u32) as Ord>::cmp(move _3, move _4) -> [return: bb1, unwind: bb2];
}

bb1: {
StorageDead(_4);
StorageDead(_3);
return;
}

bb2 (cleanup): {
resume;
}
}
20 changes: 20 additions & 0 deletions tests/mir-opt/building/spaceship.foo.built.after.mir
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// MIR for `foo` after built

fn foo(_1: i32, _2: i32) -> std::cmp::Ordering {
debug a => _1;
debug b => _2;
let mut _0: std::cmp::Ordering;
let mut _3: i32;
let mut _4: i32;

bb0: {
StorageLive(_3);
_3 = copy _1;
StorageLive(_4);
_4 = copy _2;
_0 = Cmp(move _3, move _4);
StorageDead(_4);
StorageDead(_3);
return;
}
}
21 changes: 21 additions & 0 deletions tests/mir-opt/building/spaceship.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
//@ compile-flags: -C opt-level=0 -Z mir-opt-level=0
use std::cmp::Ordering;

// EMIT_MIR spaceship.foo.built.after.mir
// EMIT_MIR spaceship.bar.built.after.mir

fn foo(a: i32, b: i32) -> Ordering {
// CHECK: [[A:_.+]] = copy _1;
// CHECK: [[B:_.+]] = copy _2;
// CHECK: _0 = Cmp(move [[A]], move [[B]]);
a <=> b
}

fn bar(a: (i32, u32), b: (i32, u32)) -> Ordering {
// CHECK: [[A:_.+]] = &_1;
// CHECK: [[B:_.+]] = &_2;
// CHECK: _0 = <(i32, u32) as Ord>::cmp(move [[A]], move [[B]])
a <=> b
}

fn main() {}
3 changes: 2 additions & 1 deletion tests/mir-opt/pre-codegen/derived_ord.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@

#![crate_type = "lib"]

#[derive(PartialOrd, PartialEq)]
#[derive(PartialOrd, PartialEq, Ord, Eq)]
pub struct MultiField(char, i16);

// EMIT_MIR derived_ord.{impl#0}-partial_cmp.PreCodegen.after.mir
// EMIT_MIR derived_ord.{impl#3}-cmp.PreCodegen.after.mir
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
// MIR for `<impl at $DIR/derived_ord.rs:6:33: 6:36>::cmp` after PreCodegen

fn <impl at $DIR/derived_ord.rs:6:33: 6:36>::cmp(_1: &MultiField, _2: &MultiField) -> std::cmp::Ordering {
debug self => _1;
debug other => _2;
let mut _0: std::cmp::Ordering;
let mut _3: char;
let mut _4: char;
let mut _5: std::cmp::Ordering;
let mut _6: i8;
let mut _7: i16;
let mut _8: i16;
scope 1 {
debug cmp => _5;
}

bb0: {
StorageLive(_3);
_3 = copy ((*_1).0: char);
StorageLive(_4);
_4 = copy ((*_2).0: char);
_5 = Cmp(move _3, move _4);
StorageDead(_4);
StorageDead(_3);
_6 = discriminant(_5);
switchInt(move _6) -> [0: bb1, otherwise: bb2];
}

bb1: {
StorageLive(_7);
_7 = copy ((*_1).1: i16);
StorageLive(_8);
_8 = copy ((*_2).1: i16);
_0 = Cmp(move _7, move _8);
StorageDead(_8);
StorageDead(_7);
goto -> bb3;
}

bb2: {
_0 = copy _5;
goto -> bb3;
}

bb3: {
return;
}
}
Loading
Loading