diff --git a/compiler/rustc_error_codes/src/error_codes/E0604.md b/compiler/rustc_error_codes/src/error_codes/E0604.md index adbf76509ed..806f0001c60 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0604.md +++ b/compiler/rustc_error_codes/src/error_codes/E0604.md @@ -6,11 +6,16 @@ Erroneous code example: 0u32 as char; // error: only `u8` can be cast as `char`, not `u32` ``` -As the error message indicates, only `u8` can be cast into `char`. Example: +`char` is a Unicode Scalar Value, an integer value from 0 to 0xD7FF and +0xE000 to 0x10FFFF. (The gap is for surrogate pairs.) Only `u8` always fits in +those ranges so only `u8` may be cast to `char`. + +To allow larger values, use `char::from_u32`, which checks the value is valid. ``` -let c = 86u8 as char; // ok! -assert_eq!(c, 'V'); +assert_eq!(86u8 as char, 'V'); // ok! +assert_eq!(char::from_u32(0x3B1), Some('α')); // ok! +assert_eq!(char::from_u32(0xD800), None); // not a USV. ``` For more information about casts, take a look at the Type cast section in diff --git a/compiler/rustc_typeck/src/check/cast.rs b/compiler/rustc_typeck/src/check/cast.rs index a397ee771af..be0b7733579 100644 --- a/compiler/rustc_typeck/src/check/cast.rs +++ b/compiler/rustc_typeck/src/check/cast.rs @@ -328,16 +328,28 @@ impl<'a, 'tcx> CastCheck<'tcx> { err.emit(); } CastError::CastToChar => { - type_error_struct!( + let mut err = type_error_struct!( fcx.tcx.sess, self.span, self.expr_ty, E0604, "only `u8` can be cast as `char`, not `{}`", self.expr_ty - ) - .span_label(self.span, "invalid cast") - .emit(); + ); + err.span_label(self.span, "invalid cast"); + if self.expr_ty.is_numeric() { + err.span_help( + self.span, + if self.expr_ty == fcx.tcx.types.i8 { + "try casting from `u8` instead" + } else if self.expr_ty == fcx.tcx.types.u32 { + "try `char::from_u32` instead" + } else { + "try `char::from_u32` instead (via a `u32`)" + }, + ); + } + err.emit(); } CastError::NonScalar => { let mut err = type_error_struct!( diff --git a/src/test/ui/consts/const-eval/const-eval-overflow-4b.stderr b/src/test/ui/consts/const-eval/const-eval-overflow-4b.stderr index 1e181c465db..f59ff329d18 100644 --- a/src/test/ui/consts/const-eval/const-eval-overflow-4b.stderr +++ b/src/test/ui/consts/const-eval/const-eval-overflow-4b.stderr @@ -17,6 +17,12 @@ error[E0604]: only `u8` can be cast as `char`, not `i8` | LL | : [u32; 5i8 as char as usize] | ^^^^^^^^^^^ invalid cast + | +help: try casting from `u8` instead + --> $DIR/const-eval-overflow-4b.rs:22:13 + | +LL | : [u32; 5i8 as char as usize] + | ^^^^^^^^^^^ error: aborting due to 3 previous errors diff --git a/src/test/ui/error-codes/E0604.stderr b/src/test/ui/error-codes/E0604.stderr index 18835310bd5..d715d28b73c 100644 --- a/src/test/ui/error-codes/E0604.stderr +++ b/src/test/ui/error-codes/E0604.stderr @@ -3,6 +3,12 @@ error[E0604]: only `u8` can be cast as `char`, not `u32` | LL | 1u32 as char; | ^^^^^^^^^^^^ invalid cast + | +help: try `char::from_u32` instead + --> $DIR/E0604.rs:2:5 + | +LL | 1u32 as char; + | ^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/error-festival.stderr b/src/test/ui/error-festival.stderr index b8cd7b7464a..0ddb6fc99b0 100644 --- a/src/test/ui/error-festival.stderr +++ b/src/test/ui/error-festival.stderr @@ -58,6 +58,12 @@ error[E0604]: only `u8` can be cast as `char`, not `u32` | LL | 0u32 as char; | ^^^^^^^^^^^^ invalid cast + | +help: try `char::from_u32` instead + --> $DIR/error-festival.rs:25:5 + | +LL | 0u32 as char; + | ^^^^^^^^^^^^ error[E0605]: non-primitive cast: `u8` as `Vec` --> $DIR/error-festival.rs:29:5 diff --git a/src/test/ui/mismatched_types/cast-rfc0401.stderr b/src/test/ui/mismatched_types/cast-rfc0401.stderr index 7f91d5ed42c..6dbf24baf23 100644 --- a/src/test/ui/mismatched_types/cast-rfc0401.stderr +++ b/src/test/ui/mismatched_types/cast-rfc0401.stderr @@ -99,6 +99,12 @@ error[E0604]: only `u8` can be cast as `char`, not `u32` | LL | let _ = 0x61u32 as char; | ^^^^^^^^^^^^^^^ invalid cast + | +help: try `char::from_u32` instead + --> $DIR/cast-rfc0401.rs:41:13 + | +LL | let _ = 0x61u32 as char; + | ^^^^^^^^^^^^^^^ error[E0606]: casting `bool` as `f32` is invalid --> $DIR/cast-rfc0401.rs:43:13