Skip to content
Merged
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
38 changes: 33 additions & 5 deletions compiler/rustc_hir_typeck/src/cast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
);
Comment on lines +302 to +307
Copy link
Copy Markdown
Member

@chenyukang chenyukang Apr 27, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The current version does not imply the suggestion is not correct.
maybe this is more verbose and also give tip for type without Copy derive:

Suggested change
err.span_suggestion_verbose(
self.expr_span.shrink_to_lo(),
"dereference the expression",
"*",
Applicability::MaybeIncorrect,
);
let help = format!(
"try dereferencing before the cast{}",
if !fcx.type_is_copy_modulo_regions(fcx.param_env, inner_ty) {
format!(
", you also need to add `#[derive(Copy, Clone)]` to the enum definition",
)
} else {
String::new()
}
);
err.span_suggestion_verbose(
self.expr_span.shrink_to_lo(),
help,
"*",
Applicability::MaybeIncorrect,
);

View changes since the review

Copy link
Copy Markdown
Member

@chenyukang chenyukang Apr 27, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

or maybe this is better:

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,
    );
}

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);
Expand Down
27 changes: 27 additions & 0 deletions tests/ui/cast/cast-enum-to-int-issue-151116.rs
Original file line number Diff line number Diff line change
@@ -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,
Copy link
Copy Markdown
Member

@chenyukang chenyukang Apr 27, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

and we add a new type:

#[derive(Copy, Clone)]
#[repr(u8)]
enum CopyPriority {
    High = 255,
    Normal = 127,
    Low = 1,
}

for https://github.com/rust-lang/rust/pull/151122/changes#r3144432881

View changes since the review

Low = 1,
}

fn main() {
let priority = &Priority::Normal;
let priority = priority as u8; //~ ERROR casting `&Priority` as `u8` is invalid
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It might be a good idea to check the HELP message as well.
like

Suggested change
let priority = priority as u8; //~ ERROR casting `&Priority` as `u8` is invalid
let priority = priority as u8; //~ ERROR casting `&Priority` as `u8` is invalid
//~| HELP: dereference the expression

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It might be a good idea to check the HELP message as well. like

Ty! will add this.

Comment thread
Jaidenmagnan marked this conversation as resolved.
//~| 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
}
38 changes: 38 additions & 0 deletions tests/ui/cast/cast-enum-to-int-issue-151116.stderr
Original file line number Diff line number Diff line change
@@ -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`.
Loading