From 868fb030cc565bc3c0204433eebf90808b21e41f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Thu, 8 Dec 2016 11:06:18 -0800 Subject: [PATCH] When cast needs a dereference point at full cast After the fix of #37453 in PR #37369, instead of pointing at only the cast type, point at the full cast span when a cast needs a dereference: ``` error: casting `&{float}` as `f32` is invalid --> ../../../src/test/ui/mismatched_types/cast-rfc0401.rs:81:30 | 81 | vec![0.0].iter().map(|s| s as f32).collect::>(); | ^^^^^^^^ cannot cast `&{float}` as `f32` | help: did you mean `*s`? --> ../../../src/test/ui/mismatched_types/cast-rfc0401.rs:81:30 | 81 | vec![0.0].iter().map(|s| s as f32).collect::>(); | ^ ``` instead of ``` error: casting `&{float}` as `f32` is invalid --> ../../../src/test/ui/mismatched_types/cast-rfc0401.rs:81:35 | 81 | vec![0.0].iter().map(|s| s as f32).collect::>(); | - ^^^ | | | | | did you mean `*s`? | cannot cast `&{float}` as `f32` ``` --- src/librustc_typeck/check/cast.rs | 7 +- src/test/compile-fail/cast-rfc0401.rs | 123 --------- src/test/ui/mismatched_types/cast-rfc0401.rs | 82 ++++++ .../ui/mismatched_types/cast-rfc0401.stderr | 240 ++++++++++++++++++ 4 files changed, 326 insertions(+), 126 deletions(-) delete mode 100644 src/test/compile-fail/cast-rfc0401.rs create mode 100644 src/test/ui/mismatched_types/cast-rfc0401.rs create mode 100644 src/test/ui/mismatched_types/cast-rfc0401.stderr diff --git a/src/librustc_typeck/check/cast.rs b/src/librustc_typeck/check/cast.rs index f2c8ef46a7e25..265dcada1f810 100644 --- a/src/librustc_typeck/check/cast.rs +++ b/src/librustc_typeck/check/cast.rs @@ -142,20 +142,21 @@ impl<'a, 'gcx, 'tcx> CastCheck<'tcx> { fn report_cast_error(&self, fcx: &FnCtxt<'a, 'gcx, 'tcx>, e: CastError) { match e { CastError::NeedDeref => { + let error_span = self.span; let cast_ty = fcx.ty_to_string(self.cast_ty); - let mut err = fcx.type_error_struct(self.cast_span, + let mut err = fcx.type_error_struct(error_span, |actual| { format!("casting `{}` as `{}` is invalid", actual, cast_ty) }, self.expr_ty); - err.span_label(self.expr.span, + err.span_label(error_span, &format!("cannot cast `{}` as `{}`", fcx.ty_to_string(self.expr_ty), cast_ty)); if let Ok(snippet) = fcx.sess().codemap().span_to_snippet(self.expr.span) { - err.span_label(self.expr.span, + err.span_help(self.expr.span, &format!("did you mean `*{}`?", snippet)); } err.emit(); diff --git a/src/test/compile-fail/cast-rfc0401.rs b/src/test/compile-fail/cast-rfc0401.rs deleted file mode 100644 index b98f464c90227..0000000000000 --- a/src/test/compile-fail/cast-rfc0401.rs +++ /dev/null @@ -1,123 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -fn illegal_cast(u: *const U) -> *const V -{ - u as *const V - //~^ ERROR casting - //~^^ NOTE vtable kinds -} - -fn illegal_cast_2(u: *const U) -> *const str -{ - u as *const str - //~^ ERROR casting - //~^^ NOTE vtable kinds -} - -trait Foo { fn foo(&self) {} } -impl Foo for T {} - -trait Bar { fn foo(&self) {} } -impl Bar for T {} - -enum E { - A, B -} - -fn main() -{ - let f: f32 = 1.2; - let v = 0 as *const u8; - let fat_v : *const [u8] = unsafe { &*(0 as *const [u8; 1])}; - let fat_sv : *const [i8] = unsafe { &*(0 as *const [i8; 1])}; - let foo: &Foo = &f; - - let _ = v as &u8; //~ ERROR non-scalar - let _ = v as E; //~ ERROR non-scalar - let _ = v as fn(); //~ ERROR non-scalar - let _ = v as (u32,); //~ ERROR non-scalar - let _ = Some(&v) as *const u8; //~ ERROR non-scalar - - let _ = v as f32; - //~^ ERROR casting - let _ = main as f64; - //~^ ERROR casting - let _ = &v as usize; - //~^ ERROR casting - //~^^ HELP through a raw pointer first - let _ = f as *const u8; - //~^ ERROR casting - let _ = 3_i32 as bool; - //~^ ERROR cannot cast as `bool` [E0054] - //~| unsupported cast - //~| HELP compare with zero - let _ = E::A as bool; - //~^ ERROR cannot cast as `bool` [E0054] - //~| unsupported cast - //~| HELP compare with zero - let _ = 0x61u32 as char; //~ ERROR only `u8` can be cast - - let _ = false as f32; - //~^ ERROR casting - //~^^ HELP through an integer first - let _ = E::A as f32; - //~^ ERROR casting - //~^^ HELP through an integer first - let _ = 'a' as f32; - //~^ ERROR casting - //~^^ HELP through an integer first - - let _ = false as *const u8; - //~^ ERROR casting - let _ = E::A as *const u8; - //~^ ERROR casting - let _ = 'a' as *const u8; - //~^ ERROR casting - - let _ = 42usize as *const [u8]; //~ ERROR casting - let _ = v as *const [u8]; //~ ERROR cannot cast - let _ = fat_v as *const Foo; - //~^ ERROR the trait bound `[u8]: std::marker::Sized` is not satisfied - //~| NOTE the trait `std::marker::Sized` is not implemented for `[u8]` - //~| NOTE `[u8]` does not have a constant size known at compile-time - //~| NOTE required for the cast to the object type `Foo` - let _ = foo as *const str; //~ ERROR casting - let _ = foo as *mut str; //~ ERROR casting - let _ = main as *mut str; //~ ERROR casting - let _ = &f as *mut f32; //~ ERROR casting - let _ = &f as *const f64; //~ ERROR casting - let _ = fat_sv as usize; - //~^ ERROR casting - //~^^ HELP through a thin pointer first - - let a : *const str = "hello"; - let _ = a as *const Foo; - //~^ ERROR the trait bound `str: std::marker::Sized` is not satisfied - //~| NOTE the trait `std::marker::Sized` is not implemented for `str` - //~| NOTE `str` does not have a constant size known at compile-time - //~| NOTE required for the cast to the object type `Foo` - - // check no error cascade - let _ = main.f as *const u32; //~ no field `f` on type `fn() {main}` - - let cf: *const Foo = &0; - let _ = cf as *const [u16]; - //~^ ERROR casting - //~^^ NOTE vtable kinds - let _ = cf as *const Bar; - //~^ ERROR casting - //~^^ NOTE vtable kinds - - vec![0.0].iter().map(|s| s as f32).collect::>(); - //~^ ERROR casting `&{float}` as `f32` is invalid - //~| NOTE cannot cast `&{float}` as `f32` - //~| NOTE did you mean `*s`? -} diff --git a/src/test/ui/mismatched_types/cast-rfc0401.rs b/src/test/ui/mismatched_types/cast-rfc0401.rs new file mode 100644 index 0000000000000..f72be0d7054db --- /dev/null +++ b/src/test/ui/mismatched_types/cast-rfc0401.rs @@ -0,0 +1,82 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +fn illegal_cast(u: *const U) -> *const V +{ + u as *const V +} + +fn illegal_cast_2(u: *const U) -> *const str +{ + u as *const str +} + +trait Foo { fn foo(&self) {} } +impl Foo for T {} + +trait Bar { fn foo(&self) {} } +impl Bar for T {} + +enum E { + A, B +} + +fn main() +{ + let f: f32 = 1.2; + let v = 0 as *const u8; + let fat_v : *const [u8] = unsafe { &*(0 as *const [u8; 1])}; + let fat_sv : *const [i8] = unsafe { &*(0 as *const [i8; 1])}; + let foo: &Foo = &f; + + let _ = v as &u8; + let _ = v as E; + let _ = v as fn(); + let _ = v as (u32,); + let _ = Some(&v) as *const u8; + + let _ = v as f32; + let _ = main as f64; + let _ = &v as usize; + let _ = f as *const u8; + let _ = 3_i32 as bool; + let _ = E::A as bool; + let _ = 0x61u32 as char; + + let _ = false as f32; + let _ = E::A as f32; + let _ = 'a' as f32; + + let _ = false as *const u8; + let _ = E::A as *const u8; + let _ = 'a' as *const u8; + + let _ = 42usize as *const [u8]; + let _ = v as *const [u8]; + let _ = fat_v as *const Foo; + let _ = foo as *const str; + let _ = foo as *mut str; + let _ = main as *mut str; + let _ = &f as *mut f32; + let _ = &f as *const f64; + let _ = fat_sv as usize; + + let a : *const str = "hello"; + let _ = a as *const Foo; + + // check no error cascade + let _ = main.f as *const u32; + + let cf: *const Foo = &0; + let _ = cf as *const [u16]; + let _ = cf as *const Bar; + + vec![0.0].iter().map(|s| s as f32).collect::>(); +} diff --git a/src/test/ui/mismatched_types/cast-rfc0401.stderr b/src/test/ui/mismatched_types/cast-rfc0401.stderr new file mode 100644 index 0000000000000..7fd10f3cb6891 --- /dev/null +++ b/src/test/ui/mismatched_types/cast-rfc0401.stderr @@ -0,0 +1,240 @@ +error: casting `*const U` as `*const V` is invalid + --> $DIR/cast-rfc0401.rs:13:5 + | +13 | u as *const V + | ^^^^^^^^^^^^^ + | + = note: vtable kinds may not match + +error: casting `*const U` as `*const str` is invalid + --> $DIR/cast-rfc0401.rs:18:5 + | +18 | u as *const str + | ^^^^^^^^^^^^^^^ + | + = note: vtable kinds may not match + +error: no field `f` on type `fn() {main}` + --> $DIR/cast-rfc0401.rs:75:18 + | +75 | let _ = main.f as *const u32; + | ^ + +error: non-scalar cast: `*const u8` as `&u8` + --> $DIR/cast-rfc0401.rs:39:13 + | +39 | let _ = v as &u8; + | ^^^^^^^^ + +error: non-scalar cast: `*const u8` as `E` + --> $DIR/cast-rfc0401.rs:40:13 + | +40 | let _ = v as E; + | ^^^^^^ + +error: non-scalar cast: `*const u8` as `fn()` + --> $DIR/cast-rfc0401.rs:41:13 + | +41 | let _ = v as fn(); + | ^^^^^^^^^ + +error: non-scalar cast: `*const u8` as `(u32,)` + --> $DIR/cast-rfc0401.rs:42:13 + | +42 | let _ = v as (u32,); + | ^^^^^^^^^^^ + +error: non-scalar cast: `std::option::Option<&*const u8>` as `*const u8` + --> $DIR/cast-rfc0401.rs:43:13 + | +43 | let _ = Some(&v) as *const u8; + | ^^^^^^^^^^^^^^^^^^^^^ + +error: casting `*const u8` as `f32` is invalid + --> $DIR/cast-rfc0401.rs:45:13 + | +45 | let _ = v as f32; + | ^^^^^^^^ + +error: casting `fn() {main}` as `f64` is invalid + --> $DIR/cast-rfc0401.rs:46:13 + | +46 | let _ = main as f64; + | ^^^^^^^^^^^ + +error: casting `&*const u8` as `usize` is invalid + --> $DIR/cast-rfc0401.rs:47:13 + | +47 | let _ = &v as usize; + | ^^^^^^^^^^^ + | + = help: cast through a raw pointer first + +error: casting `f32` as `*const u8` is invalid + --> $DIR/cast-rfc0401.rs:48:13 + | +48 | let _ = f as *const u8; + | ^^^^^^^^^^^^^^ + +error[E0054]: cannot cast as `bool` + --> $DIR/cast-rfc0401.rs:49:13 + | +49 | let _ = 3_i32 as bool; + | ^^^^^^^^^^^^^ unsupported cast + | + = help: compare with zero instead + +error[E0054]: cannot cast as `bool` + --> $DIR/cast-rfc0401.rs:50:13 + | +50 | let _ = E::A as bool; + | ^^^^^^^^^^^^ unsupported cast + | + = help: compare with zero instead + +error: only `u8` can be cast as `char`, not `u32` + --> $DIR/cast-rfc0401.rs:51:13 + | +51 | let _ = 0x61u32 as char; + | ^^^^^^^^^^^^^^^ + +error: casting `bool` as `f32` is invalid + --> $DIR/cast-rfc0401.rs:53:13 + | +53 | let _ = false as f32; + | ^^^^^^^^^^^^ + | + = help: cast through an integer first + +error: casting `E` as `f32` is invalid + --> $DIR/cast-rfc0401.rs:54:13 + | +54 | let _ = E::A as f32; + | ^^^^^^^^^^^ + | + = help: cast through an integer first + +error: casting `char` as `f32` is invalid + --> $DIR/cast-rfc0401.rs:55:13 + | +55 | let _ = 'a' as f32; + | ^^^^^^^^^^ + | + = help: cast through an integer first + +error: casting `bool` as `*const u8` is invalid + --> $DIR/cast-rfc0401.rs:57:13 + | +57 | let _ = false as *const u8; + | ^^^^^^^^^^^^^^^^^^ + +error: casting `E` as `*const u8` is invalid + --> $DIR/cast-rfc0401.rs:58:13 + | +58 | let _ = E::A as *const u8; + | ^^^^^^^^^^^^^^^^^ + +error: casting `char` as `*const u8` is invalid + --> $DIR/cast-rfc0401.rs:59:13 + | +59 | let _ = 'a' as *const u8; + | ^^^^^^^^^^^^^^^^ + +error: casting `usize` as `*const [u8]` is invalid + --> $DIR/cast-rfc0401.rs:61:13 + | +61 | let _ = 42usize as *const [u8]; + | ^^^^^^^^^^^^^^^^^^^^^^ + +error: cannot cast thin pointer `*const u8` to fat pointer `*const [u8]` + --> $DIR/cast-rfc0401.rs:62:13 + | +62 | let _ = v as *const [u8]; + | ^^^^^^^^^^^^^^^^ + +error: casting `&Foo` as `*const str` is invalid + --> $DIR/cast-rfc0401.rs:64:13 + | +64 | let _ = foo as *const str; + | ^^^^^^^^^^^^^^^^^ + +error: casting `&Foo` as `*mut str` is invalid + --> $DIR/cast-rfc0401.rs:65:13 + | +65 | let _ = foo as *mut str; + | ^^^^^^^^^^^^^^^ + +error: casting `fn() {main}` as `*mut str` is invalid + --> $DIR/cast-rfc0401.rs:66:13 + | +66 | let _ = main as *mut str; + | ^^^^^^^^^^^^^^^^ + +error: casting `&f32` as `*mut f32` is invalid + --> $DIR/cast-rfc0401.rs:67:13 + | +67 | let _ = &f as *mut f32; + | ^^^^^^^^^^^^^^ + +error: casting `&f32` as `*const f64` is invalid + --> $DIR/cast-rfc0401.rs:68:13 + | +68 | let _ = &f as *const f64; + | ^^^^^^^^^^^^^^^^ + +error: casting `*const [i8]` as `usize` is invalid + --> $DIR/cast-rfc0401.rs:69:13 + | +69 | let _ = fat_sv as usize; + | ^^^^^^^^^^^^^^^ + | + = help: cast through a thin pointer first + +error: casting `*const Foo` as `*const [u16]` is invalid + --> $DIR/cast-rfc0401.rs:78:13 + | +78 | let _ = cf as *const [u16]; + | ^^^^^^^^^^^^^^^^^^ + | + = note: vtable kinds may not match + +error: casting `*const Foo` as `*const Bar` is invalid + --> $DIR/cast-rfc0401.rs:79:13 + | +79 | let _ = cf as *const Bar; + | ^^^^^^^^^^^^^^^^ + | + = note: vtable kinds may not match + +error[E0277]: the trait bound `[u8]: std::marker::Sized` is not satisfied + --> $DIR/cast-rfc0401.rs:63:13 + | +63 | let _ = fat_v as *const Foo; + | ^^^^^ the trait `std::marker::Sized` is not implemented for `[u8]` + | + = note: `[u8]` does not have a constant size known at compile-time + = note: required for the cast to the object type `Foo` + +error[E0277]: the trait bound `str: std::marker::Sized` is not satisfied + --> $DIR/cast-rfc0401.rs:72:13 + | +72 | let _ = a as *const Foo; + | ^ the trait `std::marker::Sized` is not implemented for `str` + | + = note: `str` does not have a constant size known at compile-time + = note: required for the cast to the object type `Foo` + +error: casting `&{float}` as `f32` is invalid + --> $DIR/cast-rfc0401.rs:81:30 + | +81 | vec![0.0].iter().map(|s| s as f32).collect::>(); + | ^^^^^^^^ cannot cast `&{float}` as `f32` + | +help: did you mean `*s`? + --> $DIR/cast-rfc0401.rs:81:30 + | +81 | vec![0.0].iter().map(|s| s as f32).collect::>(); + | ^ + +error: aborting due to 34 previous errors +