diff --git a/compiler/rustc_hir_typeck/src/cast.rs b/compiler/rustc_hir_typeck/src/cast.rs index 93275f62dcc17..40315e8270e12 100644 --- a/compiler/rustc_hir_typeck/src/cast.rs +++ b/compiler/rustc_hir_typeck/src/cast.rs @@ -291,12 +291,40 @@ impl<'a, 'tcx> CastCheck<'tcx> { CastError::NeedViaThinPtr | CastError::NeedViaPtr => { let mut err = make_invalid_casting_error(self.span, self.expr_ty, self.cast_ty, fcx); + if self.cast_ty.is_integral() { - err.help(format!("cast through {} first", match e { - CastError::NeedViaPtr => "a raw pointer", - CastError::NeedViaThinPtr => "a thin pointer", - e => unreachable!("control flow means we should never encounter a {e:?}"), - })); + if !matches!(self.expr.kind, ExprKind::AddrOf(..)) + && let ty::Ref(_, inner_ty, _) = *self.expr_ty.kind() + && let ty::Adt(adt_def, _) = *inner_ty.kind() + && adt_def.is_enum() + && adt_def.is_payloadfree() + { + err.span_suggestion_verbose( + self.expr_span.shrink_to_lo(), + "try dereferencing before the cast", + "*", + Applicability::MaybeIncorrect, + ); + if !fcx.type_is_copy_modulo_regions(fcx.param_env, inner_ty) { + err.span_suggestion_verbose( + fcx.tcx.def_span(adt_def.did()).shrink_to_lo(), + "add `#[derive(Copy, Clone)]` to the enum definition", + "#[derive(Copy, Clone)]\n", + Applicability::MaybeIncorrect, + ); + } + } else { + err.help(format!( + "cast through {} first", + match e { + CastError::NeedViaPtr => "a raw pointer", + CastError::NeedViaThinPtr => "a thin pointer", + e => unreachable!( + "control flow means we should never encounter a {e:?}" + ), + } + )); + } } self.try_suggest_collection_to_bool(fcx, &mut err); diff --git a/tests/ui/cast/cast-enum-to-int-issue-151116.rs b/tests/ui/cast/cast-enum-to-int-issue-151116.rs new file mode 100644 index 0000000000000..26da80bcf2774 --- /dev/null +++ b/tests/ui/cast/cast-enum-to-int-issue-151116.rs @@ -0,0 +1,27 @@ +#[repr(u8)] +enum Priority { //~ HELP: add `#[derive(Copy, Clone)]` to the enum definition + High = 255, + Normal = 127, + Low = 1, +} + +#[repr(u8)] +#[derive(Copy, Clone)] +enum CopyPriority { + High = 255, + Normal = 127, + Low = 1, +} + +fn main() { + let priority = &Priority::Normal; + let priority = priority as u8; //~ ERROR casting `&Priority` as `u8` is invalid + //~| HELP: try dereferencing before the cast + + let priority = &Priority::Normal as u8; //~ ERROR casting `&Priority` as `u8` is invalid + //~| HELP: cast through a raw pointer first + + let priority = &CopyPriority::Normal; + let priority = priority as u8; //~ ERROR casting `&CopyPriority` as `u8` is invalid + //~| HELP: try dereferencing before the cast +} diff --git a/tests/ui/cast/cast-enum-to-int-issue-151116.stderr b/tests/ui/cast/cast-enum-to-int-issue-151116.stderr new file mode 100644 index 0000000000000..63baef70585de --- /dev/null +++ b/tests/ui/cast/cast-enum-to-int-issue-151116.stderr @@ -0,0 +1,38 @@ +error[E0606]: casting `&Priority` as `u8` is invalid + --> $DIR/cast-enum-to-int-issue-151116.rs:18:20 + | +LL | let priority = priority as u8; + | ^^^^^^^^^^^^^^ + | +help: try dereferencing before the cast + | +LL | let priority = *priority as u8; + | + +help: add `#[derive(Copy, Clone)]` to the enum definition + | +LL + #[derive(Copy, Clone)] +LL | enum Priority { + | + +error[E0606]: casting `&Priority` as `u8` is invalid + --> $DIR/cast-enum-to-int-issue-151116.rs:21:20 + | +LL | let priority = &Priority::Normal as u8; + | ^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: cast through a raw pointer first + +error[E0606]: casting `&CopyPriority` as `u8` is invalid + --> $DIR/cast-enum-to-int-issue-151116.rs:25:20 + | +LL | let priority = priority as u8; + | ^^^^^^^^^^^^^^ + | +help: try dereferencing before the cast + | +LL | let priority = *priority as u8; + | + + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0606`.