From 605938727e58c3d1176ba85e4585aa2ad8844df5 Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Sun, 26 Feb 2023 13:53:09 -0800 Subject: [PATCH 1/2] Add a deriving test case for a struct with a gazillion fields --- tests/ui/deriving/deriving-all-codegen.rs | 3 + tests/ui/deriving/deriving-all-codegen.stdout | 182 ++++++++++++++++++ 2 files changed, 185 insertions(+) diff --git a/tests/ui/deriving/deriving-all-codegen.rs b/tests/ui/deriving/deriving-all-codegen.rs index 51f9708d3cd62..402ecb91757a8 100644 --- a/tests/ui/deriving/deriving-all-codegen.rs +++ b/tests/ui/deriving/deriving-all-codegen.rs @@ -163,3 +163,6 @@ pub union Union { pub u: u32, pub i: i32, } + +#[derive(PartialEq, Eq, PartialOrd, Ord)] +pub struct TooLongForTuple(u8, u8, u8, u8, u8, u8, u8, u8, u8, u8, u8, u8, u8, u8, u8); diff --git a/tests/ui/deriving/deriving-all-codegen.stdout b/tests/ui/deriving/deriving-all-codegen.stdout index 5bca83e87f878..036e3600f677f 100644 --- a/tests/ui/deriving/deriving-all-codegen.stdout +++ b/tests/ui/deriving/deriving-all-codegen.stdout @@ -1444,3 +1444,185 @@ impl ::core::clone::Clone for Union { } #[automatically_derived] impl ::core::marker::Copy for Union { } + +pub struct TooLongForTuple(u8, u8, u8, u8, u8, u8, u8, u8, u8, u8, u8, u8, u8, + u8, u8); +#[automatically_derived] +impl ::core::marker::StructuralPartialEq for TooLongForTuple { } +#[automatically_derived] +impl ::core::cmp::PartialEq for TooLongForTuple { + #[inline] + fn eq(&self, other: &TooLongForTuple) -> bool { + self.0 == other.0 && self.1 == other.1 && self.2 == other.2 && + self.3 == other.3 && self.4 == other.4 && self.5 == other.5 + && self.6 == other.6 && self.7 == other.7 && + self.8 == other.8 && self.9 == other.9 && + self.10 == other.10 && self.11 == other.11 && + self.12 == other.12 && self.13 == other.13 && + self.14 == other.14 + } +} +#[automatically_derived] +impl ::core::marker::StructuralEq for TooLongForTuple { } +#[automatically_derived] +impl ::core::cmp::Eq for TooLongForTuple { + #[inline] + #[doc(hidden)] + #[no_coverage] + fn assert_receiver_is_total_eq(&self) -> () { + let _: ::core::cmp::AssertParamIsEq; + } +} +#[automatically_derived] +impl ::core::cmp::PartialOrd for TooLongForTuple { + #[inline] + fn partial_cmp(&self, other: &TooLongForTuple) + -> ::core::option::Option<::core::cmp::Ordering> { + match ::core::cmp::PartialOrd::partial_cmp(&self.0, &other.0) { + ::core::option::Option::Some(::core::cmp::Ordering::Equal) => + match ::core::cmp::PartialOrd::partial_cmp(&self.1, &other.1) + { + ::core::option::Option::Some(::core::cmp::Ordering::Equal) + => + match ::core::cmp::PartialOrd::partial_cmp(&self.2, + &other.2) { + ::core::option::Option::Some(::core::cmp::Ordering::Equal) + => + match ::core::cmp::PartialOrd::partial_cmp(&self.3, + &other.3) { + ::core::option::Option::Some(::core::cmp::Ordering::Equal) + => + match ::core::cmp::PartialOrd::partial_cmp(&self.4, + &other.4) { + ::core::option::Option::Some(::core::cmp::Ordering::Equal) + => + match ::core::cmp::PartialOrd::partial_cmp(&self.5, + &other.5) { + ::core::option::Option::Some(::core::cmp::Ordering::Equal) + => + match ::core::cmp::PartialOrd::partial_cmp(&self.6, + &other.6) { + ::core::option::Option::Some(::core::cmp::Ordering::Equal) + => + match ::core::cmp::PartialOrd::partial_cmp(&self.7, + &other.7) { + ::core::option::Option::Some(::core::cmp::Ordering::Equal) + => + match ::core::cmp::PartialOrd::partial_cmp(&self.8, + &other.8) { + ::core::option::Option::Some(::core::cmp::Ordering::Equal) + => + match ::core::cmp::PartialOrd::partial_cmp(&self.9, + &other.9) { + ::core::option::Option::Some(::core::cmp::Ordering::Equal) + => + match ::core::cmp::PartialOrd::partial_cmp(&self.10, + &other.10) { + ::core::option::Option::Some(::core::cmp::Ordering::Equal) + => + match ::core::cmp::PartialOrd::partial_cmp(&self.11, + &other.11) { + ::core::option::Option::Some(::core::cmp::Ordering::Equal) + => + match ::core::cmp::PartialOrd::partial_cmp(&self.12, + &other.12) { + ::core::option::Option::Some(::core::cmp::Ordering::Equal) + => + match ::core::cmp::PartialOrd::partial_cmp(&self.13, + &other.13) { + ::core::option::Option::Some(::core::cmp::Ordering::Equal) + => + ::core::cmp::PartialOrd::partial_cmp(&self.14, &other.14), + cmp => cmp, + }, + cmp => cmp, + }, + cmp => cmp, + }, + cmp => cmp, + }, + cmp => cmp, + }, + cmp => cmp, + }, + cmp => cmp, + }, + cmp => cmp, + }, + cmp => cmp, + }, + cmp => cmp, + }, + cmp => cmp, + }, + cmp => cmp, + }, + cmp => cmp, + }, + cmp => cmp, + } + } +} +#[automatically_derived] +impl ::core::cmp::Ord for TooLongForTuple { + #[inline] + fn cmp(&self, other: &TooLongForTuple) -> ::core::cmp::Ordering { + match ::core::cmp::Ord::cmp(&self.0, &other.0) { + ::core::cmp::Ordering::Equal => + match ::core::cmp::Ord::cmp(&self.1, &other.1) { + ::core::cmp::Ordering::Equal => + match ::core::cmp::Ord::cmp(&self.2, &other.2) { + ::core::cmp::Ordering::Equal => + match ::core::cmp::Ord::cmp(&self.3, &other.3) { + ::core::cmp::Ordering::Equal => + match ::core::cmp::Ord::cmp(&self.4, &other.4) { + ::core::cmp::Ordering::Equal => + match ::core::cmp::Ord::cmp(&self.5, &other.5) { + ::core::cmp::Ordering::Equal => + match ::core::cmp::Ord::cmp(&self.6, &other.6) { + ::core::cmp::Ordering::Equal => + match ::core::cmp::Ord::cmp(&self.7, &other.7) { + ::core::cmp::Ordering::Equal => + match ::core::cmp::Ord::cmp(&self.8, &other.8) { + ::core::cmp::Ordering::Equal => + match ::core::cmp::Ord::cmp(&self.9, &other.9) { + ::core::cmp::Ordering::Equal => + match ::core::cmp::Ord::cmp(&self.10, &other.10) { + ::core::cmp::Ordering::Equal => + match ::core::cmp::Ord::cmp(&self.11, &other.11) { + ::core::cmp::Ordering::Equal => + match ::core::cmp::Ord::cmp(&self.12, &other.12) { + ::core::cmp::Ordering::Equal => + match ::core::cmp::Ord::cmp(&self.13, &other.13) { + ::core::cmp::Ordering::Equal => + ::core::cmp::Ord::cmp(&self.14, &other.14), + cmp => cmp, + }, + cmp => cmp, + }, + cmp => cmp, + }, + cmp => cmp, + }, + cmp => cmp, + }, + cmp => cmp, + }, + cmp => cmp, + }, + cmp => cmp, + }, + cmp => cmp, + }, + cmp => cmp, + }, + cmp => cmp, + }, + cmp => cmp, + }, + cmp => cmp, + }, + cmp => cmp, + } + } +} From f365b6855e4a1e811dfd3906847055e7f2b35590 Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Sun, 26 Feb 2023 16:23:52 -0800 Subject: [PATCH 2/2] Derive PartialOrd::partial_cmp via tuples for mid-sized structs --- compiler/rustc_ast/src/ast.rs | 2 + .../src/deriving/cmp/partial_ord.rs | 36 +++++++++- tests/ui/deriving/deriving-all-codegen.stdout | 72 +++---------------- 3 files changed, 45 insertions(+), 65 deletions(-) diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 03c375c46668a..7406492f5bb2e 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -2695,6 +2695,8 @@ pub enum VariantData { /// Struct variant. /// /// E.g., `Bar { .. }` as in `enum Foo { Bar { .. } }`. + /// + /// The `bool` is `true` if recovery was used while parsing it. Struct(ThinVec, bool), /// Tuple variant. /// diff --git a/compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs b/compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs index 9f46247908d0d..1733e59e65701 100644 --- a/compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs +++ b/compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs @@ -5,7 +5,8 @@ use rustc_ast::{ExprKind, ItemKind, MetaItem, PatKind}; use rustc_expand::base::{Annotatable, ExtCtxt}; use rustc_span::symbol::{sym, Ident}; use rustc_span::Span; -use thin_vec::thin_vec; +use std::ops::Range; +use thin_vec::{thin_vec, ThinVec}; pub fn expand_deriving_partial_ord( cx: &mut ExtCtxt<'_>, @@ -79,6 +80,13 @@ fn cs_partial_cmp( let equal_path = cx.path_global(span, cx.std_path(&[sym::cmp, sym::Ordering, sym::Equal])); let partial_cmp_path = cx.std_path(&[sym::cmp, sym::PartialOrd, sym::partial_cmp]); + if let SubstructureFields::Struct(_vdata, field_info) = substr.fields { + const FIELD_COUNTS_TO_USE_TUPLES: Range = 3..13; + if FIELD_COUNTS_TO_USE_TUPLES.contains(&field_info.len()) { + return cs_partial_cmp_via_tuple(cx, span, field_info); + } + } + // Builds: // // match ::core::cmp::PartialOrd::partial_cmp(&self.x, &other.x) { @@ -151,3 +159,29 @@ fn cs_partial_cmp( ); BlockOrExpr::new_expr(expr) } + +fn cs_partial_cmp_via_tuple(cx: &mut ExtCtxt<'_>, span: Span, fields: &[FieldInfo]) -> BlockOrExpr { + debug_assert!(fields.len() <= 12, "This won't work for more fields than tuples support"); + + let mut lhs_exprs = ThinVec::with_capacity(fields.len()); + let mut rhs_exprs = ThinVec::with_capacity(fields.len()); + + for field in fields { + lhs_exprs.push(field.self_expr.clone()); + // if i + 1 == fields.len() { + // // The last field might need an extra indirection because unsized + // expr = cx.expr_addr_of(field.span, expr); + // }; + let [other_expr] = field.other_selflike_exprs.as_slice() else { + cx.span_bug(field.span, "not exactly 2 arguments in `derive(PartialOrd)`"); + }; + rhs_exprs.push(other_expr.clone()); + } + + let lhs = cx.expr_addr_of(span, cx.expr_tuple(span, lhs_exprs)); + let rhs = cx.expr_addr_of(span, cx.expr_tuple(span, rhs_exprs)); + + let partial_cmp_path = cx.std_path(&[sym::cmp, sym::PartialOrd, sym::partial_cmp]); + let call = cx.expr_call_global(span, partial_cmp_path, thin_vec![lhs, rhs]); + BlockOrExpr::new_expr(call) +} diff --git a/tests/ui/deriving/deriving-all-codegen.stdout b/tests/ui/deriving/deriving-all-codegen.stdout index 036e3600f677f..2047e6e786f75 100644 --- a/tests/ui/deriving/deriving-all-codegen.stdout +++ b/tests/ui/deriving/deriving-all-codegen.stdout @@ -340,47 +340,10 @@ impl ::core::cmp::PartialOrd for Big { #[inline] fn partial_cmp(&self, other: &Big) -> ::core::option::Option<::core::cmp::Ordering> { - match ::core::cmp::PartialOrd::partial_cmp(&self.b1, &other.b1) { - ::core::option::Option::Some(::core::cmp::Ordering::Equal) => - match ::core::cmp::PartialOrd::partial_cmp(&self.b2, - &other.b2) { - ::core::option::Option::Some(::core::cmp::Ordering::Equal) - => - match ::core::cmp::PartialOrd::partial_cmp(&self.b3, - &other.b3) { - ::core::option::Option::Some(::core::cmp::Ordering::Equal) - => - match ::core::cmp::PartialOrd::partial_cmp(&self.b4, - &other.b4) { - ::core::option::Option::Some(::core::cmp::Ordering::Equal) - => - match ::core::cmp::PartialOrd::partial_cmp(&self.b5, - &other.b5) { - ::core::option::Option::Some(::core::cmp::Ordering::Equal) - => - match ::core::cmp::PartialOrd::partial_cmp(&self.b6, - &other.b6) { - ::core::option::Option::Some(::core::cmp::Ordering::Equal) - => - match ::core::cmp::PartialOrd::partial_cmp(&self.b7, - &other.b7) { - ::core::option::Option::Some(::core::cmp::Ordering::Equal) - => - ::core::cmp::PartialOrd::partial_cmp(&self.b8, &other.b8), - cmp => cmp, - }, - cmp => cmp, - }, - cmp => cmp, - }, - cmp => cmp, - }, - cmp => cmp, - }, - cmp => cmp, - }, - cmp => cmp, - } + ::core::cmp::PartialOrd::partial_cmp(&(&self.b1, &self.b2, &self.b3, + &self.b4, &self.b5, &self.b6, &self.b7, &self.b8), + &(&other.b1, &other.b2, &other.b3, &other.b4, &other.b5, + &other.b6, &other.b7, &other.b8)) } } #[automatically_derived] @@ -622,16 +585,8 @@ impl #[inline] fn partial_cmp(&self, other: &Generic) -> ::core::option::Option<::core::cmp::Ordering> { - match ::core::cmp::PartialOrd::partial_cmp(&self.t, &other.t) { - ::core::option::Option::Some(::core::cmp::Ordering::Equal) => - match ::core::cmp::PartialOrd::partial_cmp(&self.ta, - &other.ta) { - ::core::option::Option::Some(::core::cmp::Ordering::Equal) - => ::core::cmp::PartialOrd::partial_cmp(&self.u, &other.u), - cmp => cmp, - }, - cmp => cmp, - } + ::core::cmp::PartialOrd::partial_cmp(&(&self.t, &self.ta, &self.u), + &(&other.t, &other.ta, &other.u)) } } #[automatically_derived] @@ -745,19 +700,8 @@ impl) -> ::core::option::Option<::core::cmp::Ordering> { - match ::core::cmp::PartialOrd::partial_cmp(&{ self.0 }, &{ other.0 }) - { - ::core::option::Option::Some(::core::cmp::Ordering::Equal) => - match ::core::cmp::PartialOrd::partial_cmp(&{ self.1 }, - &{ other.1 }) { - ::core::option::Option::Some(::core::cmp::Ordering::Equal) - => - ::core::cmp::PartialOrd::partial_cmp(&{ self.2 }, - &{ other.2 }), - cmp => cmp, - }, - cmp => cmp, - } + ::core::cmp::PartialOrd::partial_cmp(&(&{ self.0 }, &{ self.1 }, + &{ self.2 }), &(&{ other.0 }, &{ other.1 }, &{ other.2 })) } } #[automatically_derived]