Skip to content

Commit 7473750

Browse files
authored
Rollup merge of #92150 - compiler-errors:better_usize_to_wide_ptr_cast, r=petrochenkov
Improve suggestion when casting usize to (possibly) wide pointer I thought #92125 was a wonderful idea, so I went ahead and took a stab at it. Not sure if my approach is the best going forward, but I'm happy with the improvement in the error message. Iwill definitely address any changes if people are more opinionated with the wordings or want more features. Also, do I need to add a new error code? (Fixes #92125)
2 parents d7b282b + 814c18a commit 7473750

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)