Skip to content

Commit 814c18a

Browse files
better suggestion for int to wide ptr cast
1 parent 458262b commit 814c18a

File tree

5 files changed

+86
-14
lines changed

5 files changed

+86
-14
lines changed

compiler/rustc_typeck/src/check/cast.rs

+42-1
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,12 @@ pub enum CastError {
165165
NonScalar,
166166
UnknownExprPtrKind,
167167
UnknownCastPtrKind,
168+
/// Cast of int to (possibly) fat raw pointer.
169+
///
170+
/// Argument is the specific name of the metadata in plain words, such as "a vtable"
171+
/// or "a length". If this argument is None, then the metadata is unknown, for example,
172+
/// when we're typechecking a type parameter with a ?Sized bound.
173+
IntToFatCast(Option<&'static str>),
168174
}
169175

170176
impl From<ErrorGuaranteed> for CastError {
@@ -522,6 +528,35 @@ impl<'a, 'tcx> CastCheck<'tcx> {
522528
.diagnostic()
523529
.emit();
524530
}
531+
CastError::IntToFatCast(known_metadata) => {
532+
let mut err = struct_span_err!(
533+
fcx.tcx.sess,
534+
self.cast_span,
535+
E0606,
536+
"cannot cast `{}` to a pointer that {} wide",
537+
fcx.ty_to_string(self.expr_ty),
538+
if known_metadata.is_some() { "is" } else { "may be" }
539+
);
540+
541+
err.span_label(
542+
self.cast_span,
543+
format!(
544+
"creating a `{}` requires both an address and {}",
545+
self.cast_ty,
546+
known_metadata.unwrap_or("type-specific metadata"),
547+
),
548+
);
549+
550+
if fcx.tcx.sess.is_nightly_build() {
551+
err.span_label(
552+
self.expr.span,
553+
"consider casting this expression to `*const ()`, \
554+
then using `core::ptr::from_raw_parts`",
555+
);
556+
}
557+
558+
err.emit();
559+
}
525560
CastError::UnknownCastPtrKind | CastError::UnknownExprPtrKind => {
526561
let unknown_cast_to = match e {
527562
CastError::UnknownCastPtrKind => true,
@@ -900,7 +935,13 @@ impl<'a, 'tcx> CastCheck<'tcx> {
900935
match fcx.pointer_kind(m_cast.ty, self.span)? {
901936
None => Err(CastError::UnknownCastPtrKind),
902937
Some(PointerKind::Thin) => Ok(CastKind::AddrPtrCast),
903-
_ => Err(CastError::IllegalCast),
938+
Some(PointerKind::Vtable(_)) => Err(CastError::IntToFatCast(Some("a vtable"))),
939+
Some(PointerKind::Length) => Err(CastError::IntToFatCast(Some("a length"))),
940+
Some(
941+
PointerKind::OfProjection(_)
942+
| PointerKind::OfOpaque(_, _)
943+
| PointerKind::OfParam(_),
944+
) => Err(CastError::IntToFatCast(None)),
904945
}
905946
}
906947

src/test/ui/cast/fat-ptr-cast.rs

+11-2
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,15 @@ fn main() {
1919
q as *const [i32]; //~ ERROR cannot cast
2020

2121
// #21397
22-
let t: *mut (dyn Trait + 'static) = 0 as *mut _; //~ ERROR casting
23-
let mut fail: *const str = 0 as *const str; //~ ERROR casting
22+
let t: *mut (dyn Trait + 'static) = 0 as *mut _;
23+
//~^ ERROR cannot cast `usize` to a pointer that is wide
24+
let mut fail: *const str = 0 as *const str;
25+
//~^ ERROR cannot cast `usize` to a pointer that is wide
26+
let mut fail2: *const str = 0isize as *const str;
27+
//~^ ERROR cannot cast `isize` to a pointer that is wide
28+
}
29+
30+
fn foo<T: ?Sized>() {
31+
let s = 0 as *const T;
32+
//~^ ERROR cannot cast `usize` to a pointer that may be wide
2433
}

src/test/ui/cast/fat-ptr-cast.stderr

+27-7
Original file line numberDiff line numberDiff line change
@@ -50,19 +50,39 @@ error[E0607]: cannot cast thin pointer `*const i32` to fat pointer `*const [i32]
5050
LL | q as *const [i32];
5151
| ^^^^^^^^^^^^^^^^^
5252

53-
error[E0606]: casting `usize` as `*mut (dyn Trait + 'static)` is invalid
54-
--> $DIR/fat-ptr-cast.rs:22:41
53+
error[E0606]: cannot cast `usize` to a pointer that is wide
54+
--> $DIR/fat-ptr-cast.rs:22:46
5555
|
5656
LL | let t: *mut (dyn Trait + 'static) = 0 as *mut _;
57-
| ^^^^^^^^^^^
57+
| - ^^^^^^ creating a `*mut (dyn Trait + 'static)` requires both an address and a vtable
58+
| |
59+
| consider casting this expression to `*const ()`, then using `core::ptr::from_raw_parts`
5860

59-
error[E0606]: casting `usize` as `*const str` is invalid
60-
--> $DIR/fat-ptr-cast.rs:23:32
61+
error[E0606]: cannot cast `usize` to a pointer that is wide
62+
--> $DIR/fat-ptr-cast.rs:24:37
6163
|
6264
LL | let mut fail: *const str = 0 as *const str;
63-
| ^^^^^^^^^^^^^^^
65+
| - ^^^^^^^^^^ creating a `*const str` requires both an address and a length
66+
| |
67+
| consider casting this expression to `*const ()`, then using `core::ptr::from_raw_parts`
6468

65-
error: aborting due to 9 previous errors
69+
error[E0606]: cannot cast `isize` to a pointer that is wide
70+
--> $DIR/fat-ptr-cast.rs:26:43
71+
|
72+
LL | let mut fail2: *const str = 0isize as *const str;
73+
| ------ ^^^^^^^^^^ creating a `*const str` requires both an address and a length
74+
| |
75+
| consider casting this expression to `*const ()`, then using `core::ptr::from_raw_parts`
76+
77+
error[E0606]: cannot cast `usize` to a pointer that may be wide
78+
--> $DIR/fat-ptr-cast.rs:31:18
79+
|
80+
LL | let s = 0 as *const T;
81+
| - ^^^^^^^^ creating a `*const T` requires both an address and type-specific metadata
82+
| |
83+
| consider casting this expression to `*const ()`, then using `core::ptr::from_raw_parts`
84+
85+
error: aborting due to 11 previous errors
6686

6787
Some errors have detailed explanations: E0605, E0606, E0607.
6888
For more information about an error, try `rustc --explain E0605`.

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ fn main()
4848
let _ = E::A as *const u8; //~ ERROR is invalid
4949
let _ = 'a' as *const u8; //~ ERROR is invalid
5050

51-
let _ = 42usize as *const [u8]; //~ ERROR is invalid
51+
let _ = 42usize as *const [u8]; //~ ERROR cannot cast `usize` to a pointer that is wide
5252
let _ = v as *const [u8]; //~ ERROR cannot cast
5353
let _ = fat_v as *const dyn Foo; //~ ERROR the size for values of type
5454
let _ = foo as *const str; //~ ERROR is invalid

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

+5-3
Original file line numberDiff line numberDiff line change
@@ -148,11 +148,13 @@ error[E0606]: casting `char` as `*const u8` is invalid
148148
LL | let _ = 'a' as *const u8;
149149
| ^^^^^^^^^^^^^^^^
150150

151-
error[E0606]: casting `usize` as `*const [u8]` is invalid
152-
--> $DIR/cast-rfc0401.rs:51:13
151+
error[E0606]: cannot cast `usize` to a pointer that is wide
152+
--> $DIR/cast-rfc0401.rs:51:24
153153
|
154154
LL | let _ = 42usize as *const [u8];
155-
| ^^^^^^^^^^^^^^^^^^^^^^
155+
| ------- ^^^^^^^^^^^ creating a `*const [u8]` requires both an address and a length
156+
| |
157+
| consider casting this expression to `*const ()`, then using `core::ptr::from_raw_parts`
156158

157159
error[E0607]: cannot cast thin pointer `*const u8` to fat pointer `*const [u8]`
158160
--> $DIR/cast-rfc0401.rs:52:13

0 commit comments

Comments
 (0)