Skip to content

Commit 6e37f95

Browse files
committed
Emit more specific diagnostics when enums fail to cast with as
1 parent 384b02c commit 6e37f95

File tree

5 files changed

+110
-4
lines changed

5 files changed

+110
-4
lines changed

compiler/rustc_hir_typeck/src/cast.rs

+24-2
Original file line numberDiff line numberDiff line change
@@ -448,13 +448,35 @@ impl<'a, 'tcx> CastCheck<'tcx> {
448448
);
449449
}
450450
}
451-
let msg = "an `as` expression can only be used to convert between primitive \
452-
types or to coerce to a specific trait object";
451+
452+
let (msg, note) = if let ty::Adt(adt, _) = self.expr_ty.kind()
453+
&& adt.is_enum()
454+
&& self.cast_ty.is_numeric()
455+
{
456+
(
457+
"an `as` expression can be used to convert enum types to numeric \
458+
types only if the enum type is unit-only or field-less",
459+
Some(
460+
"see https://doc.rust-lang.org/reference/items/enumerations.html#casting for more information",
461+
),
462+
)
463+
} else {
464+
(
465+
"an `as` expression can only be used to convert between primitive \
466+
types or to coerce to a specific trait object",
467+
None,
468+
)
469+
};
470+
453471
if label {
454472
err.span_label(self.span, msg);
455473
} else {
456474
err.note(msg);
457475
}
476+
477+
if let Some(note) = note {
478+
err.note(note);
479+
}
458480
} else {
459481
err.span_label(self.span, "invalid cast");
460482
}

tests/ui/cast/enum-to-numeric-cast.rs

+46
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
// Tests that `as` casts from enums to numeric types succeed
2+
// only if the enum type is "unit-only" or "fieldless" as
3+
// described here: https://doc.rust-lang.org/reference/items/enumerations.html#casting
4+
5+
pub enum UnitOnly {
6+
Foo,
7+
Bar,
8+
Baz,
9+
}
10+
11+
pub enum Fieldless {
12+
Tuple(),
13+
Struct{},
14+
Unit,
15+
}
16+
17+
pub enum NotUnitOnlyOrFieldless {
18+
Foo,
19+
Bar(u8),
20+
Baz
21+
}
22+
23+
fn main() {
24+
let unit_only = UnitOnly::Foo;
25+
26+
let _ = unit_only as isize;
27+
let _ = unit_only as i32;
28+
let _ = unit_only as usize;
29+
let _ = unit_only as u32;
30+
31+
32+
let fieldless = Fieldless::Struct{};
33+
34+
let _ = fieldless as isize;
35+
let _ = fieldless as i32;
36+
let _ = fieldless as usize;
37+
let _ = fieldless as u32;
38+
39+
40+
let not_unit_only_or_fieldless = NotUnitOnlyOrFieldless::Foo;
41+
42+
let _ = not_unit_only_or_fieldless as isize; //~ ERROR non-primitive cast: `NotUnitOnlyOrFieldless` as `isize`
43+
let _ = not_unit_only_or_fieldless as i32; //~ ERROR non-primitive cast: `NotUnitOnlyOrFieldless` as `i32`
44+
let _ = not_unit_only_or_fieldless as usize; //~ ERROR non-primitive cast: `NotUnitOnlyOrFieldless` as `usize`
45+
let _ = not_unit_only_or_fieldless as u32; //~ ERROR non-primitive cast: `NotUnitOnlyOrFieldless` as `u32`
46+
}
+35
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
error[E0605]: non-primitive cast: `NotUnitOnlyOrFieldless` as `isize`
2+
--> $DIR/enum-to-numeric-cast.rs:42:13
3+
|
4+
LL | let _ = not_unit_only_or_fieldless as isize;
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ an `as` expression can be used to convert enum types to numeric types only if the enum type is unit-only or field-less
6+
|
7+
= note: see https://doc.rust-lang.org/reference/items/enumerations.html#casting for more information
8+
9+
error[E0605]: non-primitive cast: `NotUnitOnlyOrFieldless` as `i32`
10+
--> $DIR/enum-to-numeric-cast.rs:43:13
11+
|
12+
LL | let _ = not_unit_only_or_fieldless as i32;
13+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ an `as` expression can be used to convert enum types to numeric types only if the enum type is unit-only or field-less
14+
|
15+
= note: see https://doc.rust-lang.org/reference/items/enumerations.html#casting for more information
16+
17+
error[E0605]: non-primitive cast: `NotUnitOnlyOrFieldless` as `usize`
18+
--> $DIR/enum-to-numeric-cast.rs:44:13
19+
|
20+
LL | let _ = not_unit_only_or_fieldless as usize;
21+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ an `as` expression can be used to convert enum types to numeric types only if the enum type is unit-only or field-less
22+
|
23+
= note: see https://doc.rust-lang.org/reference/items/enumerations.html#casting for more information
24+
25+
error[E0605]: non-primitive cast: `NotUnitOnlyOrFieldless` as `u32`
26+
--> $DIR/enum-to-numeric-cast.rs:45:13
27+
|
28+
LL | let _ = not_unit_only_or_fieldless as u32;
29+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ an `as` expression can be used to convert enum types to numeric types only if the enum type is unit-only or field-less
30+
|
31+
= note: see https://doc.rust-lang.org/reference/items/enumerations.html#casting for more information
32+
33+
error: aborting due to 4 previous errors
34+
35+
For more information about this error, try `rustc --explain E0605`.

tests/ui/cast/issue-88621.stderr

+3-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@ error[E0605]: non-primitive cast: `Kind2` as `u8`
22
--> $DIR/issue-88621.rs:9:13
33
|
44
LL | let _ = Kind2::Foo() as u8;
5-
| ^^^^^^^^^^^^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object
5+
| ^^^^^^^^^^^^^^^^^^ an `as` expression can be used to convert enum types to numeric types only if the enum type is unit-only or field-less
6+
|
7+
= note: see https://doc.rust-lang.org/reference/items/enumerations.html#casting for more information
68

79
error: aborting due to 1 previous error
810

tests/ui/tag-variant-cast-non-nullary.stderr

+2-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@ error[E0605]: non-primitive cast: `NonNullary` as `isize`
44
LL | let val = v as isize;
55
| ^^^^^^^^^^ help: consider using the `From` trait instead: `isize::from(v)`
66
|
7-
= note: an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object
7+
= 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
8+
= note: see https://doc.rust-lang.org/reference/items/enumerations.html#casting for more information
89

910
error: aborting due to 1 previous error
1011

0 commit comments

Comments
 (0)