Skip to content

Commit

Permalink
Unrolled build for rust-lang#120822
Browse files Browse the repository at this point in the history
Rollup merge of rust-lang#120822 - gurry:120756-terse-non-prim-cast-diag, r=petrochenkov

Emit more specific diagnostics when enums fail to cast with `as`

Fixes rust-lang#120756

Changes this diagnostic reported in the issue:
```
error[E0605]: non-primitive cast: `Bad` as `u32`
  --> src/main.rs:18:10
   |
18 |     dbg!(bad as u32);
   |          ^^^^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object
```

to this:
```
error[E0605]: non-primitive cast: `Bad` as `u32`
  --> src/main.rs:18:10
   |
18 |     dbg!(bad as u32);
   |          ^^^^^^^^^^ an `as` expression can be used to convert enum types to numeric types only if the enum type is unit-only or field-less
   |
   = note: see https://doc.rust-lang.org/reference/items/enumerations.html#casting for more information
```

This change is only for enums. The diagnostic remains unchanged for all other cases.
  • Loading branch information
rust-timer authored Feb 9, 2024
2 parents f4cfd87 + 6e37f95 commit 759993a
Show file tree
Hide file tree
Showing 5 changed files with 110 additions and 4 deletions.
26 changes: 24 additions & 2 deletions compiler/rustc_hir_typeck/src/cast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -448,13 +448,35 @@ impl<'a, 'tcx> CastCheck<'tcx> {
);
}
}
let msg = "an `as` expression can only be used to convert between primitive \
types or to coerce to a specific trait object";

let (msg, note) = if let ty::Adt(adt, _) = self.expr_ty.kind()
&& adt.is_enum()
&& self.cast_ty.is_numeric()
{
(
"an `as` expression can be used to convert enum types to numeric \
types only if the enum type is unit-only or field-less",
Some(
"see https://doc.rust-lang.org/reference/items/enumerations.html#casting for more information",
),
)
} else {
(
"an `as` expression can only be used to convert between primitive \
types or to coerce to a specific trait object",
None,
)
};

if label {
err.span_label(self.span, msg);
} else {
err.note(msg);
}

if let Some(note) = note {
err.note(note);
}
} else {
err.span_label(self.span, "invalid cast");
}
Expand Down
46 changes: 46 additions & 0 deletions tests/ui/cast/enum-to-numeric-cast.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
// Tests that `as` casts from enums to numeric types succeed
// only if the enum type is "unit-only" or "fieldless" as
// described here: https://doc.rust-lang.org/reference/items/enumerations.html#casting

pub enum UnitOnly {
Foo,
Bar,
Baz,
}

pub enum Fieldless {
Tuple(),
Struct{},
Unit,
}

pub enum NotUnitOnlyOrFieldless {
Foo,
Bar(u8),
Baz
}

fn main() {
let unit_only = UnitOnly::Foo;

let _ = unit_only as isize;
let _ = unit_only as i32;
let _ = unit_only as usize;
let _ = unit_only as u32;


let fieldless = Fieldless::Struct{};

let _ = fieldless as isize;
let _ = fieldless as i32;
let _ = fieldless as usize;
let _ = fieldless as u32;


let not_unit_only_or_fieldless = NotUnitOnlyOrFieldless::Foo;

let _ = not_unit_only_or_fieldless as isize; //~ ERROR non-primitive cast: `NotUnitOnlyOrFieldless` as `isize`
let _ = not_unit_only_or_fieldless as i32; //~ ERROR non-primitive cast: `NotUnitOnlyOrFieldless` as `i32`
let _ = not_unit_only_or_fieldless as usize; //~ ERROR non-primitive cast: `NotUnitOnlyOrFieldless` as `usize`
let _ = not_unit_only_or_fieldless as u32; //~ ERROR non-primitive cast: `NotUnitOnlyOrFieldless` as `u32`
}
35 changes: 35 additions & 0 deletions tests/ui/cast/enum-to-numeric-cast.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
error[E0605]: non-primitive cast: `NotUnitOnlyOrFieldless` as `isize`
--> $DIR/enum-to-numeric-cast.rs:42:13
|
LL | let _ = not_unit_only_or_fieldless as isize;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ an `as` expression can be used to convert enum types to numeric types only if the enum type is unit-only or field-less
|
= note: see https://doc.rust-lang.org/reference/items/enumerations.html#casting for more information

error[E0605]: non-primitive cast: `NotUnitOnlyOrFieldless` as `i32`
--> $DIR/enum-to-numeric-cast.rs:43:13
|
LL | let _ = not_unit_only_or_fieldless as i32;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ an `as` expression can be used to convert enum types to numeric types only if the enum type is unit-only or field-less
|
= note: see https://doc.rust-lang.org/reference/items/enumerations.html#casting for more information

error[E0605]: non-primitive cast: `NotUnitOnlyOrFieldless` as `usize`
--> $DIR/enum-to-numeric-cast.rs:44:13
|
LL | let _ = not_unit_only_or_fieldless as usize;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ an `as` expression can be used to convert enum types to numeric types only if the enum type is unit-only or field-less
|
= note: see https://doc.rust-lang.org/reference/items/enumerations.html#casting for more information

error[E0605]: non-primitive cast: `NotUnitOnlyOrFieldless` as `u32`
--> $DIR/enum-to-numeric-cast.rs:45:13
|
LL | let _ = not_unit_only_or_fieldless as u32;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ an `as` expression can be used to convert enum types to numeric types only if the enum type is unit-only or field-less
|
= note: see https://doc.rust-lang.org/reference/items/enumerations.html#casting for more information

error: aborting due to 4 previous errors

For more information about this error, try `rustc --explain E0605`.
4 changes: 3 additions & 1 deletion tests/ui/cast/issue-88621.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@ error[E0605]: non-primitive cast: `Kind2` as `u8`
--> $DIR/issue-88621.rs:9:13
|
LL | let _ = Kind2::Foo() as u8;
| ^^^^^^^^^^^^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object
| ^^^^^^^^^^^^^^^^^^ an `as` expression can be used to convert enum types to numeric types only if the enum type is unit-only or field-less
|
= note: see https://doc.rust-lang.org/reference/items/enumerations.html#casting for more information

error: aborting due to 1 previous error

Expand Down
3 changes: 2 additions & 1 deletion tests/ui/tag-variant-cast-non-nullary.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ error[E0605]: non-primitive cast: `NonNullary` as `isize`
LL | let val = v as isize;
| ^^^^^^^^^^ help: consider using the `From` trait instead: `isize::from(v)`
|
= note: an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object
= note: an `as` expression can be used to convert enum types to numeric types only if the enum type is unit-only or field-less
= note: see https://doc.rust-lang.org/reference/items/enumerations.html#casting for more information

error: aborting due to 1 previous error

Expand Down

0 comments on commit 759993a

Please sign in to comment.