diff --git a/compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs b/compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs index 03ee270d66ba1..c8ec5deb92c43 100644 --- a/compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs +++ b/compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs @@ -129,23 +129,23 @@ fn get_substructure_equality_expr( EnumMatching(.., fields) | Struct(.., fields) => { let combine = move |acc, field| { let rhs = get_field_equality_expr(cx, field); - if let Some(lhs) = acc { + match acc { // Combine the previous comparison with the current field // using logical AND. - return Some(cx.expr_binary(field.span, BinOpKind::And, lhs, rhs)); + Some(lhs) => Some(cx.expr_binary(field.span, BinOpKind::And, lhs, rhs)), + // Start the chain with the first field's comparison. + None => Some(rhs), } - // Start the chain with the first field's comparison. - Some(rhs) }; // First compare scalar fields, then compound fields, combining all // with logical AND. - return fields + fields .iter() .filter(|field| !field.maybe_scalar) .fold(fields.iter().filter(|field| field.maybe_scalar).fold(None, combine), combine) // If there are no fields, treat as always equal. - .unwrap_or_else(|| cx.expr_bool(span, true)); + .unwrap_or_else(|| cx.expr_bool(span, true)) } EnumDiscr(disc, match_expr) => { let lhs = get_field_equality_expr(cx, disc); @@ -154,7 +154,7 @@ fn get_substructure_equality_expr( }; // Compare the discriminant first (cheaper), then the rest of the // fields. - return cx.expr_binary(disc.span, BinOpKind::And, lhs, match_expr.clone()); + cx.expr_binary(disc.span, BinOpKind::And, lhs, match_expr.clone()) } StaticEnum(..) => cx.dcx().span_bug( span, diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs index d50ac8dbaa742..6b8dcf1258d45 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs @@ -119,6 +119,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { _ => {} } + // Don't emit the lint if we are in an impl marked as `#[automatically_derive]`. + // This is relevant for deriving `Clone` and `PartialEq` on types containing `!`. + if self.tcx.is_automatically_derived(self.tcx.parent(id.owner.def_id.into())) { + return; + } + // Don't warn twice. self.diverges.set(Diverges::WarnedAlways); diff --git a/tests/ui/never_type/regress/builtin_derives_on_adts_with_never.rs b/tests/ui/never_type/regress/builtin_derives_on_adts_with_never.rs new file mode 100644 index 0000000000000..2a57c6023adce --- /dev/null +++ b/tests/ui/never_type/regress/builtin_derives_on_adts_with_never.rs @@ -0,0 +1,20 @@ +// Regression test for . +// +//@ check-pass +#![feature(never_type)] +#![crate_type = "lib"] +#![warn(unreachable_code)] + +#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] +pub struct S(!); + +#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] +pub struct S2 { + f: !, +} + +#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] +pub enum E { + E2(!), + E3 { f: ! }, +}