Skip to content

Commit 8cdf44a

Browse files
authored
Rollup merge of rust-lang#91939 - GKFX:feature-91866, r=cjgillot
Clarify error on casting larger integers to char Closes rust-lang#91836 with changes to E0604.md and a `span_help`.
2 parents 291bf94 + badb81a commit 8cdf44a

File tree

6 files changed

+48
-7
lines changed

6 files changed

+48
-7
lines changed

compiler/rustc_error_codes/src/error_codes/E0604.md

+8-3
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,16 @@ Erroneous code example:
66
0u32 as char; // error: only `u8` can be cast as `char`, not `u32`
77
```
88

9-
As the error message indicates, only `u8` can be cast into `char`. Example:
9+
`char` is a Unicode Scalar Value, an integer value from 0 to 0xD7FF and
10+
0xE000 to 0x10FFFF. (The gap is for surrogate pairs.) Only `u8` always fits in
11+
those ranges so only `u8` may be cast to `char`.
12+
13+
To allow larger values, use `char::from_u32`, which checks the value is valid.
1014

1115
```
12-
let c = 86u8 as char; // ok!
13-
assert_eq!(c, 'V');
16+
assert_eq!(86u8 as char, 'V'); // ok!
17+
assert_eq!(char::from_u32(0x3B1), Some('α')); // ok!
18+
assert_eq!(char::from_u32(0xD800), None); // not a USV.
1419
```
1520

1621
For more information about casts, take a look at the Type cast section in

compiler/rustc_typeck/src/check/cast.rs

+16-4
Original file line numberDiff line numberDiff line change
@@ -328,16 +328,28 @@ impl<'a, 'tcx> CastCheck<'tcx> {
328328
err.emit();
329329
}
330330
CastError::CastToChar => {
331-
type_error_struct!(
331+
let mut err = type_error_struct!(
332332
fcx.tcx.sess,
333333
self.span,
334334
self.expr_ty,
335335
E0604,
336336
"only `u8` can be cast as `char`, not `{}`",
337337
self.expr_ty
338-
)
339-
.span_label(self.span, "invalid cast")
340-
.emit();
338+
);
339+
err.span_label(self.span, "invalid cast");
340+
if self.expr_ty.is_numeric() {
341+
err.span_help(
342+
self.span,
343+
if self.expr_ty == fcx.tcx.types.i8 {
344+
"try casting from `u8` instead"
345+
} else if self.expr_ty == fcx.tcx.types.u32 {
346+
"try `char::from_u32` instead"
347+
} else {
348+
"try `char::from_u32` instead (via a `u32`)"
349+
},
350+
);
351+
}
352+
err.emit();
341353
}
342354
CastError::NonScalar => {
343355
let mut err = type_error_struct!(

src/test/ui/consts/const-eval/const-eval-overflow-4b.stderr

+6
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,12 @@ error[E0604]: only `u8` can be cast as `char`, not `i8`
1717
|
1818
LL | : [u32; 5i8 as char as usize]
1919
| ^^^^^^^^^^^ invalid cast
20+
|
21+
help: try casting from `u8` instead
22+
--> $DIR/const-eval-overflow-4b.rs:22:13
23+
|
24+
LL | : [u32; 5i8 as char as usize]
25+
| ^^^^^^^^^^^
2026

2127
error: aborting due to 3 previous errors
2228

src/test/ui/error-codes/E0604.stderr

+6
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,12 @@ error[E0604]: only `u8` can be cast as `char`, not `u32`
33
|
44
LL | 1u32 as char;
55
| ^^^^^^^^^^^^ invalid cast
6+
|
7+
help: try `char::from_u32` instead
8+
--> $DIR/E0604.rs:2:5
9+
|
10+
LL | 1u32 as char;
11+
| ^^^^^^^^^^^^
612

713
error: aborting due to previous error
814

src/test/ui/error-festival.stderr

+6
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,12 @@ error[E0604]: only `u8` can be cast as `char`, not `u32`
5858
|
5959
LL | 0u32 as char;
6060
| ^^^^^^^^^^^^ invalid cast
61+
|
62+
help: try `char::from_u32` instead
63+
--> $DIR/error-festival.rs:25:5
64+
|
65+
LL | 0u32 as char;
66+
| ^^^^^^^^^^^^
6167

6268
error[E0605]: non-primitive cast: `u8` as `Vec<u8>`
6369
--> $DIR/error-festival.rs:29:5

src/test/ui/mismatched_types/cast-rfc0401.stderr

+6
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,12 @@ error[E0604]: only `u8` can be cast as `char`, not `u32`
9999
|
100100
LL | let _ = 0x61u32 as char;
101101
| ^^^^^^^^^^^^^^^ invalid cast
102+
|
103+
help: try `char::from_u32` instead
104+
--> $DIR/cast-rfc0401.rs:41:13
105+
|
106+
LL | let _ = 0x61u32 as char;
107+
| ^^^^^^^^^^^^^^^
102108

103109
error[E0606]: casting `bool` as `f32` is invalid
104110
--> $DIR/cast-rfc0401.rs:43:13

0 commit comments

Comments
 (0)