summary refs log tree commit diff
diff options
context:
space:
mode:
authorMichael Goulet <michael@errs.io>2022-03-09 15:24:14 -0800
committerMichael Goulet <michael@errs.io>2022-03-09 15:34:39 -0800
commit814c18a6dc60ae1ce70ee6da3b10fb59e936e3c5 (patch)
treec001d9f173a80c47c4fb61a536ecd30da169e75d
parent458262b1315e0de7be940fe95e111bb045e4a2a4 (diff)
downloadrust-814c18a6dc60ae1ce70ee6da3b10fb59e936e3c5.tar.gz
rust-814c18a6dc60ae1ce70ee6da3b10fb59e936e3c5.zip
better suggestion for int to wide ptr cast
-rw-r--r--compiler/rustc_typeck/src/check/cast.rs43
-rw-r--r--src/test/ui/cast/fat-ptr-cast.rs13
-rw-r--r--src/test/ui/cast/fat-ptr-cast.stderr34
-rw-r--r--src/test/ui/mismatched_types/cast-rfc0401.rs2
-rw-r--r--src/test/ui/mismatched_types/cast-rfc0401.stderr8
5 files changed, 86 insertions, 14 deletions
diff --git a/compiler/rustc_typeck/src/check/cast.rs b/compiler/rustc_typeck/src/check/cast.rs
index 3d0f76f7a93..d3e9820834a 100644
--- a/compiler/rustc_typeck/src/check/cast.rs
+++ b/compiler/rustc_typeck/src/check/cast.rs
@@ -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 @@ 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,
@@ -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)),
         }
     }
 
diff --git a/src/test/ui/cast/fat-ptr-cast.rs b/src/test/ui/cast/fat-ptr-cast.rs
index a0fad583a16..b5276dc619b 100644
--- a/src/test/ui/cast/fat-ptr-cast.rs
+++ b/src/test/ui/cast/fat-ptr-cast.rs
@@ -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
 }
diff --git a/src/test/ui/cast/fat-ptr-cast.stderr b/src/test/ui/cast/fat-ptr-cast.stderr
index 0b0c288fe3b..18e7b68ff3c 100644
--- a/src/test/ui/cast/fat-ptr-cast.stderr
+++ b/src/test/ui/cast/fat-ptr-cast.stderr
@@ -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`.
diff --git a/src/test/ui/mismatched_types/cast-rfc0401.rs b/src/test/ui/mismatched_types/cast-rfc0401.rs
index b8d12fb9809..57222f45947 100644
--- a/src/test/ui/mismatched_types/cast-rfc0401.rs
+++ b/src/test/ui/mismatched_types/cast-rfc0401.rs
@@ -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
diff --git a/src/test/ui/mismatched_types/cast-rfc0401.stderr b/src/test/ui/mismatched_types/cast-rfc0401.stderr
index 6dbf24baf23..5f11e4ded80 100644
--- a/src/test/ui/mismatched_types/cast-rfc0401.stderr
+++ b/src/test/ui/mismatched_types/cast-rfc0401.stderr
@@ -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