better suggestion for int to wide ptr cast

This commit is contained in:
Michael Goulet 2022-03-09 15:24:14 -08:00
parent 458262b131
commit 814c18a6dc
5 changed files with 86 additions and 14 deletions

View File

@ -165,6 +165,12 @@ pub enum CastError {
NonScalar,
UnknownExprPtrKind,
UnknownCastPtrKind,
/// Cast of int to (possibly) fat raw pointer.
///
/// Argument is the specific name of the metadata in plain words, such as "a vtable"
/// or "a length". If this argument is None, then the metadata is unknown, for example,
/// when we're typechecking a type parameter with a ?Sized bound.
IntToFatCast(Option<&'static str>),
}
impl From<ErrorGuaranteed> for CastError {
@ -522,6 +528,35 @@ fn report_cast_error(&self, fcx: &FnCtxt<'a, 'tcx>, e: CastError) {
.diagnostic()
.emit();
}
CastError::IntToFatCast(known_metadata) => {
let mut err = struct_span_err!(
fcx.tcx.sess,
self.cast_span,
E0606,
"cannot cast `{}` to a pointer that {} wide",
fcx.ty_to_string(self.expr_ty),
if known_metadata.is_some() { "is" } else { "may be" }
);
err.span_label(
self.cast_span,
format!(
"creating a `{}` requires both an address and {}",
self.cast_ty,
known_metadata.unwrap_or("type-specific metadata"),
),
);
if fcx.tcx.sess.is_nightly_build() {
err.span_label(
self.expr.span,
"consider casting this expression to `*const ()`, \
then using `core::ptr::from_raw_parts`",
);
}
err.emit();
}
CastError::UnknownCastPtrKind | CastError::UnknownExprPtrKind => {
let unknown_cast_to = match e {
CastError::UnknownCastPtrKind => true,
@ -900,7 +935,13 @@ fn check_addr_ptr_cast(
match fcx.pointer_kind(m_cast.ty, self.span)? {
None => Err(CastError::UnknownCastPtrKind),
Some(PointerKind::Thin) => Ok(CastKind::AddrPtrCast),
_ => Err(CastError::IllegalCast),
Some(PointerKind::Vtable(_)) => Err(CastError::IntToFatCast(Some("a vtable"))),
Some(PointerKind::Length) => Err(CastError::IntToFatCast(Some("a length"))),
Some(
PointerKind::OfProjection(_)
| PointerKind::OfOpaque(_, _)
| PointerKind::OfParam(_),
) => Err(CastError::IntToFatCast(None)),
}
}

View File

@ -19,6 +19,15 @@ fn main() {
q as *const [i32]; //~ ERROR cannot cast
// #21397
let t: *mut (dyn Trait + 'static) = 0 as *mut _; //~ ERROR casting
let mut fail: *const str = 0 as *const str; //~ ERROR casting
let t: *mut (dyn Trait + 'static) = 0 as *mut _;
//~^ ERROR cannot cast `usize` to a pointer that is wide
let mut fail: *const str = 0 as *const str;
//~^ ERROR cannot cast `usize` to a pointer that is wide
let mut fail2: *const str = 0isize as *const str;
//~^ ERROR cannot cast `isize` to a pointer that is wide
}
fn foo<T: ?Sized>() {
let s = 0 as *const T;
//~^ ERROR cannot cast `usize` to a pointer that may be wide
}

View File

@ -50,19 +50,39 @@ error[E0607]: cannot cast thin pointer `*const i32` to fat pointer `*const [i32]
LL | q as *const [i32];
| ^^^^^^^^^^^^^^^^^
error[E0606]: casting `usize` as `*mut (dyn Trait + 'static)` is invalid
--> $DIR/fat-ptr-cast.rs:22:41
error[E0606]: cannot cast `usize` to a pointer that is wide
--> $DIR/fat-ptr-cast.rs:22:46
|
LL | let t: *mut (dyn Trait + 'static) = 0 as *mut _;
| ^^^^^^^^^^^
| - ^^^^^^ creating a `*mut (dyn Trait + 'static)` requires both an address and a vtable
| |
| consider casting this expression to `*const ()`, then using `core::ptr::from_raw_parts`
error[E0606]: casting `usize` as `*const str` is invalid
--> $DIR/fat-ptr-cast.rs:23:32
error[E0606]: cannot cast `usize` to a pointer that is wide
--> $DIR/fat-ptr-cast.rs:24:37
|
LL | let mut fail: *const str = 0 as *const str;
| ^^^^^^^^^^^^^^^
| - ^^^^^^^^^^ creating a `*const str` requires both an address and a length
| |
| consider casting this expression to `*const ()`, then using `core::ptr::from_raw_parts`
error: aborting due to 9 previous errors
error[E0606]: cannot cast `isize` to a pointer that is wide
--> $DIR/fat-ptr-cast.rs:26:43
|
LL | let mut fail2: *const str = 0isize as *const str;
| ------ ^^^^^^^^^^ creating a `*const str` requires both an address and a length
| |
| consider casting this expression to `*const ()`, then using `core::ptr::from_raw_parts`
error[E0606]: cannot cast `usize` to a pointer that may be wide
--> $DIR/fat-ptr-cast.rs:31:18
|
LL | let s = 0 as *const T;
| - ^^^^^^^^ creating a `*const T` requires both an address and type-specific metadata
| |
| consider casting this expression to `*const ()`, then using `core::ptr::from_raw_parts`
error: aborting due to 11 previous errors
Some errors have detailed explanations: E0605, E0606, E0607.
For more information about an error, try `rustc --explain E0605`.

View File

@ -48,7 +48,7 @@ fn main()
let _ = E::A as *const u8; //~ ERROR is invalid
let _ = 'a' as *const u8; //~ ERROR is invalid
let _ = 42usize as *const [u8]; //~ ERROR is invalid
let _ = 42usize as *const [u8]; //~ ERROR cannot cast `usize` to a pointer that is wide
let _ = v as *const [u8]; //~ ERROR cannot cast
let _ = fat_v as *const dyn Foo; //~ ERROR the size for values of type
let _ = foo as *const str; //~ ERROR is invalid

View File

@ -148,11 +148,13 @@ error[E0606]: casting `char` as `*const u8` is invalid
LL | let _ = 'a' as *const u8;
| ^^^^^^^^^^^^^^^^
error[E0606]: casting `usize` as `*const [u8]` is invalid
--> $DIR/cast-rfc0401.rs:51:13
error[E0606]: cannot cast `usize` to a pointer that is wide
--> $DIR/cast-rfc0401.rs:51:24
|
LL | let _ = 42usize as *const [u8];
| ^^^^^^^^^^^^^^^^^^^^^^
| ------- ^^^^^^^^^^^ creating a `*const [u8]` requires both an address and a length
| |
| consider casting this expression to `*const ()`, then using `core::ptr::from_raw_parts`
error[E0607]: cannot cast thin pointer `*const u8` to fat pointer `*const [u8]`
--> $DIR/cast-rfc0401.rs:52:13