Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve suggestion when casting usize to (possibly) wide pointer #92150

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 42 additions & 1 deletion compiler/rustc_typeck/src/check/cast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -522,6 +528,35 @@ impl<'a, 'tcx> CastCheck<'tcx> {
.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,
Expand Down Expand Up @@ -900,7 +935,13 @@ impl<'a, 'tcx> CastCheck<'tcx> {
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)),
}
}

Expand Down
13 changes: 11 additions & 2 deletions src/test/ui/cast/fat-ptr-cast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
34 changes: 27 additions & 7 deletions src/test/ui/cast/fat-ptr-cast.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -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`.
2 changes: 1 addition & 1 deletion src/test/ui/mismatched_types/cast-rfc0401.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
8 changes: 5 additions & 3 deletions src/test/ui/mismatched_types/cast-rfc0401.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down