From 50686fff88433fa6c644da8704a14463f051d5fb Mon Sep 17 00:00:00 2001 From: Waffle Lapkin Date: Mon, 6 Apr 2026 19:08:23 +0200 Subject: [PATCH 1/3] add a test for deriving traits on adt with never field --- .../builtin_derives_on_adts_with_never.rs | 26 +++++++ .../builtin_derives_on_adts_with_never.stderr | 68 +++++++++++++++++++ 2 files changed, 94 insertions(+) create mode 100644 tests/ui/never_type/regress/builtin_derives_on_adts_with_never.rs create mode 100644 tests/ui/never_type/regress/builtin_derives_on_adts_with_never.stderr 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..89d2ee8f0f5be --- /dev/null +++ b/tests/ui/never_type/regress/builtin_derives_on_adts_with_never.rs @@ -0,0 +1,26 @@ +// Regression test for . +// +//@ check-pass +#![feature(never_type)] +#![crate_type = "lib"] +#![warn(unreachable_code)] + +#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] +//~^ warn: unreachable +pub struct S(!); +//~^ warn: unreachable + +#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] +//~^ warn: unreachable +pub struct S2 { + f: !, + //~^ warn: unreachable +} + +#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] +//~^ warn: unreachable +//~| warn: unreachable +pub enum E { + E2(!), + E3 { f: ! }, +} diff --git a/tests/ui/never_type/regress/builtin_derives_on_adts_with_never.stderr b/tests/ui/never_type/regress/builtin_derives_on_adts_with_never.stderr new file mode 100644 index 0000000000000..74b7db712c66b --- /dev/null +++ b/tests/ui/never_type/regress/builtin_derives_on_adts_with_never.stderr @@ -0,0 +1,68 @@ +warning: unreachable call + --> $DIR/builtin_derives_on_adts_with_never.rs:8:10 + | +LL | #[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] + | ^^^^^ unreachable call +LL | +LL | pub struct S(!); + | - any code following this expression is unreachable + | +note: the lint level is defined here + --> $DIR/builtin_derives_on_adts_with_never.rs:6:9 + | +LL | #![warn(unreachable_code)] + | ^^^^^^^^^^^^^^^^ + +warning: unreachable expression + --> $DIR/builtin_derives_on_adts_with_never.rs:10:14 + | +LL | #[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] + | --------- in this derive macro expansion +LL | +LL | pub struct S(!); + | ^ + | | + | unreachable expression + | any code following this expression is unreachable + +warning: unreachable expression + --> $DIR/builtin_derives_on_adts_with_never.rs:13:10 + | +LL | #[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] + | ^^^^^ unreachable expression +... +LL | f: !, + | ---- any code following this expression is unreachable + +warning: unreachable expression + --> $DIR/builtin_derives_on_adts_with_never.rs:16:5 + | +LL | #[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] + | --------- in this derive macro expansion +... +LL | f: !, + | ^^^^ + | | + | unreachable expression + | any code following this expression is unreachable + +warning: unreachable call + --> $DIR/builtin_derives_on_adts_with_never.rs:20:10 + | +LL | #[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] + | ^^^^^ unreachable call +... +LL | E2(!), + | - any code following this expression is unreachable + +warning: unreachable expression + --> $DIR/builtin_derives_on_adts_with_never.rs:20:10 + | +LL | #[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] + | ^^^^^ unreachable expression +... +LL | E3 { f: ! }, + | ---- any code following this expression is unreachable + +warning: 6 warnings emitted + From dd19e0116566f2218eaa05fcb5382e71551d38bc Mon Sep 17 00:00:00 2001 From: Waffle Lapkin Date: Mon, 6 Apr 2026 19:08:23 +0200 Subject: [PATCH 2/3] drive-by cleanup --- .../src/deriving/cmp/partial_eq.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) 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, From ddf9d4cfd5a4b20ad5bfaffd36fb8f4624a61ac8 Mon Sep 17 00:00:00 2001 From: Waffle Lapkin Date: Mon, 6 Apr 2026 19:08:23 +0200 Subject: [PATCH 3/3] suppress unreachable code lint in automatically derived impls This is relevant for `derive(Clone, PartialEq)` on adts with fields of type never. --- .../rustc_hir_typeck/src/fn_ctxt/_impl.rs | 6 ++ .../builtin_derives_on_adts_with_never.rs | 6 -- .../builtin_derives_on_adts_with_never.stderr | 68 ------------------- 3 files changed, 6 insertions(+), 74 deletions(-) delete mode 100644 tests/ui/never_type/regress/builtin_derives_on_adts_with_never.stderr 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 index 89d2ee8f0f5be..2a57c6023adce 100644 --- 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 @@ -6,20 +6,14 @@ #![warn(unreachable_code)] #[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] -//~^ warn: unreachable pub struct S(!); -//~^ warn: unreachable #[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] -//~^ warn: unreachable pub struct S2 { f: !, - //~^ warn: unreachable } #[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] -//~^ warn: unreachable -//~| warn: unreachable pub enum E { E2(!), E3 { f: ! }, diff --git a/tests/ui/never_type/regress/builtin_derives_on_adts_with_never.stderr b/tests/ui/never_type/regress/builtin_derives_on_adts_with_never.stderr deleted file mode 100644 index 74b7db712c66b..0000000000000 --- a/tests/ui/never_type/regress/builtin_derives_on_adts_with_never.stderr +++ /dev/null @@ -1,68 +0,0 @@ -warning: unreachable call - --> $DIR/builtin_derives_on_adts_with_never.rs:8:10 - | -LL | #[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] - | ^^^^^ unreachable call -LL | -LL | pub struct S(!); - | - any code following this expression is unreachable - | -note: the lint level is defined here - --> $DIR/builtin_derives_on_adts_with_never.rs:6:9 - | -LL | #![warn(unreachable_code)] - | ^^^^^^^^^^^^^^^^ - -warning: unreachable expression - --> $DIR/builtin_derives_on_adts_with_never.rs:10:14 - | -LL | #[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] - | --------- in this derive macro expansion -LL | -LL | pub struct S(!); - | ^ - | | - | unreachable expression - | any code following this expression is unreachable - -warning: unreachable expression - --> $DIR/builtin_derives_on_adts_with_never.rs:13:10 - | -LL | #[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] - | ^^^^^ unreachable expression -... -LL | f: !, - | ---- any code following this expression is unreachable - -warning: unreachable expression - --> $DIR/builtin_derives_on_adts_with_never.rs:16:5 - | -LL | #[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] - | --------- in this derive macro expansion -... -LL | f: !, - | ^^^^ - | | - | unreachable expression - | any code following this expression is unreachable - -warning: unreachable call - --> $DIR/builtin_derives_on_adts_with_never.rs:20:10 - | -LL | #[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] - | ^^^^^ unreachable call -... -LL | E2(!), - | - any code following this expression is unreachable - -warning: unreachable expression - --> $DIR/builtin_derives_on_adts_with_never.rs:20:10 - | -LL | #[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] - | ^^^^^ unreachable expression -... -LL | E3 { f: ! }, - | ---- any code following this expression is unreachable - -warning: 6 warnings emitted -