From d5977df1c1a934f9892e26a17b38065412ba31d1 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Wed, 7 Jun 2017 20:58:09 +0200 Subject: [PATCH 1/7] Add E0604 --- src/librustc_typeck/check/cast.rs | 8 ++------ src/librustc_typeck/diagnostics.rs | 17 +++++++++++++++++ src/test/compile-fail/E0604.rs | 13 +++++++++++++ .../ui/mismatched_types/cast-rfc0401.stderr | 2 +- 4 files changed, 33 insertions(+), 7 deletions(-) create mode 100644 src/test/compile-fail/E0604.rs diff --git a/src/librustc_typeck/check/cast.rs b/src/librustc_typeck/check/cast.rs index 91aeade65aa4c..cff61df52cd81 100644 --- a/src/librustc_typeck/check/cast.rs +++ b/src/librustc_typeck/check/cast.rs @@ -205,12 +205,8 @@ impl<'a, 'gcx, 'tcx> CastCheck<'tcx> { .emit(); } CastError::CastToChar => { - fcx.type_error_message(self.span, - |actual| { - format!("only `u8` can be cast as `char`, not `{}`", - actual) - }, - self.expr_ty); + struct_span_err!(fcx.tcx.sess, self.span, E0604, + "only `u8` can be cast as `char`, not `{}`", self.expr_ty).emit(); } CastError::NonScalar => { fcx.type_error_message(self.span, diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs index bc5ba4c323dc1..e750a8978448d 100644 --- a/src/librustc_typeck/diagnostics.rs +++ b/src/librustc_typeck/diagnostics.rs @@ -4208,6 +4208,23 @@ println!("{}", v[2]); ``` "##, +E0604: r##" +A cast to `char` was attempted on another type than `u8`. + +Erroneous code example: + +```compile_fail,E0604 +0u32 as char; // error: only `u8` can be cast as `char`, not `u32` +``` + +As the error message indicates, only `u8` can be casted into `char`. Example: + +``` +let c = 86u8 as char; // ok! +assert!(c, 'V'); +``` +"##, + E0609: r##" Attempted to access a non-existent field in a struct. diff --git a/src/test/compile-fail/E0604.rs b/src/test/compile-fail/E0604.rs new file mode 100644 index 0000000000000..c5bf3a77b6c8f --- /dev/null +++ b/src/test/compile-fail/E0604.rs @@ -0,0 +1,13 @@ +// Copyright 2017 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 main() { + 1u32 as char; //~ ERROR E0604 +} diff --git a/src/test/ui/mismatched_types/cast-rfc0401.stderr b/src/test/ui/mismatched_types/cast-rfc0401.stderr index 58cd130dcc253..82672d5d873ae 100644 --- a/src/test/ui/mismatched_types/cast-rfc0401.stderr +++ b/src/test/ui/mismatched_types/cast-rfc0401.stderr @@ -92,7 +92,7 @@ error[E0054]: cannot cast as `bool` | = help: compare with zero instead -error: only `u8` can be cast as `char`, not `u32` +error[E0604]: only `u8` can be cast as `char`, not `u32` --> $DIR/cast-rfc0401.rs:51:13 | 51 | let _ = 0x61u32 as char; From 0e4b8ffccdfaa48e7ec61d8f8dc06f15f31c800f Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Wed, 7 Jun 2017 22:24:15 +0200 Subject: [PATCH 2/7] Add E0605 --- src/librustc_typeck/check/cast.rs | 14 +++++----- src/librustc_typeck/diagnostics.rs | 26 +++++++++++++++++++ src/test/compile-fail/E0605.rs | 19 ++++++++++++++ .../ui/mismatched_types/cast-rfc0401.stderr | 20 ++++++++++---- .../ui/mismatched_types/issue-26480.stderr | 4 ++- 5 files changed, 70 insertions(+), 13 deletions(-) create mode 100644 src/test/compile-fail/E0605.rs diff --git a/src/librustc_typeck/check/cast.rs b/src/librustc_typeck/check/cast.rs index cff61df52cd81..69174dacaaa07 100644 --- a/src/librustc_typeck/check/cast.rs +++ b/src/librustc_typeck/check/cast.rs @@ -209,13 +209,13 @@ impl<'a, 'gcx, 'tcx> CastCheck<'tcx> { "only `u8` can be cast as `char`, not `{}`", self.expr_ty).emit(); } CastError::NonScalar => { - fcx.type_error_message(self.span, - |actual| { - format!("non-scalar cast: `{}` as `{}`", - actual, - fcx.ty_to_string(self.cast_ty)) - }, - self.expr_ty); + struct_span_err!(fcx.tcx.sess, self.span, E0605, + "non-scalar cast: `{}` as `{}`", + self.expr_ty, + fcx.ty_to_string(self.cast_ty)) + .note("an `as` expression can only be used to convert between \ + primitive types. Consider using the `From` trait") + .emit(); } CastError::IllegalCast => { fcx.type_error_message(self.span, diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs index e750a8978448d..a787aadc6781c 100644 --- a/src/librustc_typeck/diagnostics.rs +++ b/src/librustc_typeck/diagnostics.rs @@ -4225,6 +4225,32 @@ assert!(c, 'V'); ``` "##, +E0605: r##" +An invalid cast was attempted. + +Erroneous code examples: + +```compile_fail,E0605 +let x = 0u8; +x as Vec; // error: non-scalar cast: `u8` as `std::vec::Vec` + +// Another example + +let v = 0 as *const u8; // So here, `v` is a `*const u8`. +v as &u8; // error: non-scalar cast: `*const u8` as `&u8` +``` + +Only primitive types cast be casted into each others. Examples: + +``` +let x = 0u8; +x as u32; // ok! + +let v = 0 as *const u8; +v as *const i8; // ok! +``` +"##, + E0609: r##" Attempted to access a non-existent field in a struct. diff --git a/src/test/compile-fail/E0605.rs b/src/test/compile-fail/E0605.rs new file mode 100644 index 0000000000000..add3fd8fd8ac2 --- /dev/null +++ b/src/test/compile-fail/E0605.rs @@ -0,0 +1,19 @@ +// Copyright 2017 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 main() { + let x = 0u8; + x as Vec; //~ ERROR E0605 + //~| NOTE an `as` expression can only be used to convert between primitive types + + let v = 0 as *const u8; + v as &u8; //~ ERROR E0605 + //~| NOTE an `as` expression can only be used to convert between primitive types +} diff --git a/src/test/ui/mismatched_types/cast-rfc0401.stderr b/src/test/ui/mismatched_types/cast-rfc0401.stderr index 82672d5d873ae..c79d242dc5e19 100644 --- a/src/test/ui/mismatched_types/cast-rfc0401.stderr +++ b/src/test/ui/mismatched_types/cast-rfc0401.stderr @@ -20,35 +20,45 @@ error[E0609]: no field `f` on type `fn() {main}` 75 | let _ = main.f as *const u32; | ^ -error: non-scalar cast: `*const u8` as `&u8` +error[E0605]: non-scalar cast: `*const u8` as `&u8` --> $DIR/cast-rfc0401.rs:39:13 | 39 | let _ = v as &u8; | ^^^^^^^^ + | + = note: an `as` expression can only be used to convert between primitive types. Consider using the `From` trait -error: non-scalar cast: `*const u8` as `E` +error[E0605]: non-scalar cast: `*const u8` as `E` --> $DIR/cast-rfc0401.rs:40:13 | 40 | let _ = v as E; | ^^^^^^ + | + = note: an `as` expression can only be used to convert between primitive types. Consider using the `From` trait -error: non-scalar cast: `*const u8` as `fn()` +error[E0605]: non-scalar cast: `*const u8` as `fn()` --> $DIR/cast-rfc0401.rs:41:13 | 41 | let _ = v as fn(); | ^^^^^^^^^ + | + = note: an `as` expression can only be used to convert between primitive types. Consider using the `From` trait -error: non-scalar cast: `*const u8` as `(u32,)` +error[E0605]: non-scalar cast: `*const u8` as `(u32,)` --> $DIR/cast-rfc0401.rs:42:13 | 42 | let _ = v as (u32,); | ^^^^^^^^^^^ + | + = note: an `as` expression can only be used to convert between primitive types. Consider using the `From` trait -error: non-scalar cast: `std::option::Option<&*const u8>` as `*const u8` +error[E0605]: non-scalar cast: `std::option::Option<&*const u8>` as `*const u8` --> $DIR/cast-rfc0401.rs:43:13 | 43 | let _ = Some(&v) as *const u8; | ^^^^^^^^^^^^^^^^^^^^^ + | + = note: an `as` expression can only be used to convert between primitive types. Consider using the `From` trait error: casting `*const u8` as `f32` is invalid --> $DIR/cast-rfc0401.rs:45:13 diff --git a/src/test/ui/mismatched_types/issue-26480.stderr b/src/test/ui/mismatched_types/issue-26480.stderr index dc3764a376cde..06b8806900290 100644 --- a/src/test/ui/mismatched_types/issue-26480.stderr +++ b/src/test/ui/mismatched_types/issue-26480.stderr @@ -7,7 +7,7 @@ error[E0308]: mismatched types 37 | write!(hello); | -------------- in this macro invocation -error: non-scalar cast: `{integer}` as `()` +error[E0605]: non-scalar cast: `{integer}` as `()` --> $DIR/issue-26480.rs:32:19 | 32 | ($x:expr) => ($x as ()) @@ -15,6 +15,8 @@ error: non-scalar cast: `{integer}` as `()` ... 38 | cast!(2); | --------- in this macro invocation + | + = note: an `as` expression can only be used to convert between primitive types. Consider using the `From` trait error: aborting due to previous error(s) From 30effc14e4ae23a682495ceadf7f56039b02e747 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Wed, 7 Jun 2017 23:54:51 +0200 Subject: [PATCH 3/7] Add E0606 --- src/librustc_typeck/check/cast.rs | 71 ++++++++----------- src/librustc_typeck/diagnostics.rs | 19 +++++ src/test/compile-fail/E0606.rs | 13 ++++ .../ui/mismatched_types/cast-rfc0401.stderr | 44 ++++++------ 4 files changed, 83 insertions(+), 64 deletions(-) create mode 100644 src/test/compile-fail/E0606.rs diff --git a/src/librustc_typeck/check/cast.rs b/src/librustc_typeck/check/cast.rs index 69174dacaaa07..5c25536431113 100644 --- a/src/librustc_typeck/check/cast.rs +++ b/src/librustc_typeck/check/cast.rs @@ -40,9 +40,11 @@ use super::{Diverges, FnCtxt}; -use lint; +use errors::DiagnosticBuilder; use hir::def_id::DefId; +use lint; use rustc::hir; +use rustc::session::Session; use rustc::traits; use rustc::ty::{self, Ty, TypeFoldable}; use rustc::ty::cast::{CastKind, CastTy}; @@ -112,6 +114,18 @@ enum CastError { NonScalar, } +fn make_invalid_casting_error<'a, 'gcx, 'tcx>(sess: &'a Session, + span: Span, + expr_ty: Ty<'tcx>, + cast_ty: Ty<'tcx>, + fcx: &FnCtxt<'a, 'gcx, 'tcx>) + -> DiagnosticBuilder<'a> { + struct_span_err!(sess, span, E0606, + "casting `{}` as `{}` is invalid", + fcx.ty_to_string(expr_ty), + fcx.ty_to_string(cast_ty)) +} + impl<'a, 'gcx, 'tcx> CastCheck<'tcx> { pub fn new(fcx: &FnCtxt<'a, 'gcx, 'tcx>, expr: &'tcx hir::Expr, @@ -146,14 +160,9 @@ impl<'a, 'gcx, 'tcx> CastCheck<'tcx> { match e { CastError::NeedDeref => { let error_span = self.span; + let mut err = make_invalid_casting_error(fcx.tcx.sess, self.span, self.expr_ty, + self.cast_ty, fcx); let cast_ty = fcx.ty_to_string(self.cast_ty); - let mut err = fcx.type_error_struct(error_span, - |actual| { - format!("casting `{}` as `{}` is invalid", - actual, - cast_ty) - }, - self.expr_ty); err.span_label(error_span, format!("cannot cast `{}` as `{}`", fcx.ty_to_string(self.expr_ty), @@ -166,13 +175,8 @@ impl<'a, 'gcx, 'tcx> CastCheck<'tcx> { } CastError::NeedViaThinPtr | CastError::NeedViaPtr => { - let mut err = fcx.type_error_struct(self.span, - |actual| { - format!("casting `{}` as `{}` is invalid", - actual, - fcx.ty_to_string(self.cast_ty)) - }, - self.expr_ty); + let mut err = make_invalid_casting_error(fcx.tcx.sess, self.span, self.expr_ty, + self.cast_ty, fcx); if self.cast_ty.is_uint() { err.help(&format!("cast through {} first", match e { @@ -184,13 +188,7 @@ impl<'a, 'gcx, 'tcx> CastCheck<'tcx> { err.emit(); } CastError::NeedViaInt => { - fcx.type_error_struct(self.span, - |actual| { - format!("casting `{}` as `{}` is invalid", - actual, - fcx.ty_to_string(self.cast_ty)) - }, - self.expr_ty) + make_invalid_casting_error(fcx.tcx.sess, self.span, self.expr_ty, self.cast_ty, fcx) .help(&format!("cast through {} first", match e { CastError::NeedViaInt => "an integer", @@ -198,6 +196,15 @@ impl<'a, 'gcx, 'tcx> CastCheck<'tcx> { })) .emit(); } + CastError::IllegalCast => { + make_invalid_casting_error(fcx.tcx.sess, self.span, self.expr_ty, self.cast_ty, fcx) + .emit(); + } + CastError::DifferingKinds => { + make_invalid_casting_error(fcx.tcx.sess, self.span, self.expr_ty, self.cast_ty, fcx) + .note("vtable kinds may not match") + .emit(); + } CastError::CastToBool => { struct_span_err!(fcx.tcx.sess, self.span, E0054, "cannot cast as `bool`") .span_label(self.span, "unsupported cast") @@ -217,15 +224,6 @@ impl<'a, 'gcx, 'tcx> CastCheck<'tcx> { primitive types. Consider using the `From` trait") .emit(); } - CastError::IllegalCast => { - fcx.type_error_message(self.span, - |actual| { - format!("casting `{}` as `{}` is invalid", - actual, - fcx.ty_to_string(self.cast_ty)) - }, - self.expr_ty); - } CastError::SizedUnsizedCast => { fcx.type_error_message(self.span, |actual| { @@ -236,17 +234,6 @@ impl<'a, 'gcx, 'tcx> CastCheck<'tcx> { }, self.expr_ty) } - CastError::DifferingKinds => { - fcx.type_error_struct(self.span, - |actual| { - format!("casting `{}` as `{}` is invalid", - actual, - fcx.ty_to_string(self.cast_ty)) - }, - self.expr_ty) - .note("vtable kinds may not match") - .emit(); - } } } diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs index a787aadc6781c..d3138af978aa7 100644 --- a/src/librustc_typeck/diagnostics.rs +++ b/src/librustc_typeck/diagnostics.rs @@ -4251,6 +4251,25 @@ v as *const i8; // ok! ``` "##, +E0606: r##" +An incompatible cast was attempted. + +Erroneous code example: + +```compile_fail,E0606 +let x = &0u8; // Here, `x` is a `&u8`. +let y: u32 = x as u32; // error: casting `&u8` as `u32` is invalid +``` + +When casting, keep in mind that only primitive types cast be casted into each +others. Example: + +``` +let x = &0u8; +let y: u32 = *x as u32; // We dereference it first and then cast it. +``` +"##, + E0609: r##" Attempted to access a non-existent field in a struct. diff --git a/src/test/compile-fail/E0606.rs b/src/test/compile-fail/E0606.rs new file mode 100644 index 0000000000000..55071736bfe51 --- /dev/null +++ b/src/test/compile-fail/E0606.rs @@ -0,0 +1,13 @@ +// Copyright 2017 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 main() { + &0u8 as u8; //~ ERROR E0606 +} diff --git a/src/test/ui/mismatched_types/cast-rfc0401.stderr b/src/test/ui/mismatched_types/cast-rfc0401.stderr index c79d242dc5e19..b4c3106253e14 100644 --- a/src/test/ui/mismatched_types/cast-rfc0401.stderr +++ b/src/test/ui/mismatched_types/cast-rfc0401.stderr @@ -1,4 +1,4 @@ -error: casting `*const U` as `*const V` is invalid +error[E0606]: casting `*const U` as `*const V` is invalid --> $DIR/cast-rfc0401.rs:13:5 | 13 | u as *const V @@ -6,7 +6,7 @@ error: casting `*const U` as `*const V` is invalid | = note: vtable kinds may not match -error: casting `*const U` as `*const str` is invalid +error[E0606]: casting `*const U` as `*const str` is invalid --> $DIR/cast-rfc0401.rs:18:5 | 18 | u as *const str @@ -60,19 +60,19 @@ error[E0605]: non-scalar cast: `std::option::Option<&*const u8>` as `*const u8` | = note: an `as` expression can only be used to convert between primitive types. Consider using the `From` trait -error: casting `*const u8` as `f32` is invalid +error[E0606]: 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 +error[E0606]: 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 +error[E0606]: casting `&*const u8` as `usize` is invalid --> $DIR/cast-rfc0401.rs:47:13 | 47 | let _ = &v as usize; @@ -80,7 +80,7 @@ error: casting `&*const u8` as `usize` is invalid | = help: cast through a raw pointer first -error: casting `f32` as `*const u8` is invalid +error[E0606]: casting `f32` as `*const u8` is invalid --> $DIR/cast-rfc0401.rs:48:13 | 48 | let _ = f as *const u8; @@ -108,7 +108,7 @@ error[E0604]: only `u8` can be cast as `char`, not `u32` 51 | let _ = 0x61u32 as char; | ^^^^^^^^^^^^^^^ -error: casting `bool` as `f32` is invalid +error[E0606]: casting `bool` as `f32` is invalid --> $DIR/cast-rfc0401.rs:53:13 | 53 | let _ = false as f32; @@ -116,7 +116,7 @@ error: casting `bool` as `f32` is invalid | = help: cast through an integer first -error: casting `E` as `f32` is invalid +error[E0606]: casting `E` as `f32` is invalid --> $DIR/cast-rfc0401.rs:54:13 | 54 | let _ = E::A as f32; @@ -124,7 +124,7 @@ error: casting `E` as `f32` is invalid | = help: cast through an integer first -error: casting `char` as `f32` is invalid +error[E0606]: casting `char` as `f32` is invalid --> $DIR/cast-rfc0401.rs:55:13 | 55 | let _ = 'a' as f32; @@ -132,25 +132,25 @@ error: casting `char` as `f32` is invalid | = help: cast through an integer first -error: casting `bool` as `*const u8` is invalid +error[E0606]: 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 +error[E0606]: 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 +error[E0606]: 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 +error[E0606]: casting `usize` as `*const [u8]` is invalid --> $DIR/cast-rfc0401.rs:61:13 | 61 | let _ = 42usize as *const [u8]; @@ -162,37 +162,37 @@ error: cannot cast thin pointer `*const u8` to fat pointer `*const [u8]` 62 | let _ = v as *const [u8]; | ^^^^^^^^^^^^^^^^ -error: casting `&Foo` as `*const str` is invalid +error[E0606]: 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 +error[E0606]: 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 +error[E0606]: 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 +error[E0606]: 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 +error[E0606]: 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 +error[E0606]: casting `*const [i8]` as `usize` is invalid --> $DIR/cast-rfc0401.rs:69:13 | 69 | let _ = fat_sv as usize; @@ -200,7 +200,7 @@ error: casting `*const [i8]` as `usize` is invalid | = help: cast through a thin pointer first -error: casting `*const Foo` as `*const [u16]` is invalid +error[E0606]: casting `*const Foo` as `*const [u16]` is invalid --> $DIR/cast-rfc0401.rs:78:13 | 78 | let _ = cf as *const [u16]; @@ -208,7 +208,7 @@ error: casting `*const Foo` as `*const [u16]` is invalid | = note: vtable kinds may not match -error: casting `*const Foo` as `*const Bar` is invalid +error[E0606]: casting `*const Foo` as `*const Bar` is invalid --> $DIR/cast-rfc0401.rs:79:13 | 79 | let _ = cf as *const Bar; @@ -234,7 +234,7 @@ error[E0277]: the trait bound `str: std::marker::Sized` is not satisfied = help: the trait `std::marker::Sized` is not implemented for `str` = note: required for the cast to the object type `Foo` -error: casting `&{float}` as `f32` is invalid +error[E0606]: casting `&{float}` as `f32` is invalid --> $DIR/cast-rfc0401.rs:81:30 | 81 | vec![0.0].iter().map(|s| s as f32).collect::>(); From 7b8c6a2d30f7e6acee89a735ad8fd86c1e1c2370 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 8 Jun 2017 00:13:28 +0200 Subject: [PATCH 4/7] Add E0607 --- src/librustc_typeck/check/cast.rs | 12 ++++------ src/librustc_typeck/diagnostics.rs | 23 +++++++++++++++++++ src/test/compile-fail/E0607.rs | 14 +++++++++++ .../ui/mismatched_types/cast-rfc0401.stderr | 2 +- 4 files changed, 42 insertions(+), 9 deletions(-) create mode 100644 src/test/compile-fail/E0607.rs diff --git a/src/librustc_typeck/check/cast.rs b/src/librustc_typeck/check/cast.rs index 5c25536431113..52962e1e478c0 100644 --- a/src/librustc_typeck/check/cast.rs +++ b/src/librustc_typeck/check/cast.rs @@ -225,14 +225,10 @@ impl<'a, 'gcx, 'tcx> CastCheck<'tcx> { .emit(); } CastError::SizedUnsizedCast => { - fcx.type_error_message(self.span, - |actual| { - format!("cannot cast thin pointer `{}` to fat pointer \ - `{}`", - actual, - fcx.ty_to_string(self.cast_ty)) - }, - self.expr_ty) + struct_span_err!(fcx.tcx.sess, self.span, E0607, + "cannot cast thin pointer `{}` to fat pointer `{}`", + self.expr_ty, + fcx.ty_to_string(self.cast_ty)).emit(); } } } diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs index d3138af978aa7..ae13e236743dd 100644 --- a/src/librustc_typeck/diagnostics.rs +++ b/src/librustc_typeck/diagnostics.rs @@ -4270,6 +4270,29 @@ let y: u32 = *x as u32; // We dereference it first and then cast it. ``` "##, +E0607: r##" +A cast between a thin and a fat pointer was attempted. + +Erroneous code example: + +```compile_fail,E0607 +let v = 0 as *const u8; +v as *const [u8]; +``` + +First: what are thin and fat pointers? + +Thin pointers are "simple" pointers that simply reference a memory address. + +Fat pointers are pointers referencing Dynamically Sized Types (also called DST). +They don't have a statically known size, therefore they can only exist behind +some kind of pointers that contain additional information. Slices and trait +objects are DSTs. + +So in order to fix this error, don't try to cast directly between thin and fat +pointers. +"##, + E0609: r##" Attempted to access a non-existent field in a struct. diff --git a/src/test/compile-fail/E0607.rs b/src/test/compile-fail/E0607.rs new file mode 100644 index 0000000000000..fa761f2c17896 --- /dev/null +++ b/src/test/compile-fail/E0607.rs @@ -0,0 +1,14 @@ +// Copyright 2017 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 main() { + let v = 0 as *const u8; + v as *const [u8]; //~ ERROR E0607 +} diff --git a/src/test/ui/mismatched_types/cast-rfc0401.stderr b/src/test/ui/mismatched_types/cast-rfc0401.stderr index b4c3106253e14..50e1815057928 100644 --- a/src/test/ui/mismatched_types/cast-rfc0401.stderr +++ b/src/test/ui/mismatched_types/cast-rfc0401.stderr @@ -156,7 +156,7 @@ error[E0606]: casting `usize` as `*const [u8]` is invalid 61 | let _ = 42usize as *const [u8]; | ^^^^^^^^^^^^^^^^^^^^^^ -error: cannot cast thin pointer `*const u8` to fat pointer `*const [u8]` +error[E0607]: cannot cast thin pointer `*const u8` to fat pointer `*const [u8]` --> $DIR/cast-rfc0401.rs:62:13 | 62 | let _ = v as *const [u8]; From deb1eb6134a8ac22c55dc3e9713d667ff352ecf5 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 9 Jun 2017 22:04:29 +0200 Subject: [PATCH 5/7] wording improvement --- src/librustc_typeck/check/cast.rs | 2 +- src/librustc_typeck/diagnostics.rs | 27 ++++++++++--------- src/test/compile-fail/cast-from-nil.rs | 2 +- src/test/compile-fail/cast-to-bare-fn.rs | 4 +-- src/test/compile-fail/cast-to-nil.rs | 2 +- src/test/compile-fail/closure-no-fn-3.rs | 2 +- src/test/compile-fail/coerce-to-bang-cast.rs | 2 +- src/test/compile-fail/fat-ptr-cast.rs | 2 +- src/test/compile-fail/issue-10991.rs | 2 +- src/test/compile-fail/issue-22289.rs | 2 +- src/test/compile-fail/issue-22312.rs | 2 +- src/test/compile-fail/issue-2995.rs | 2 +- src/test/compile-fail/nonscalar-cast.rs | 4 +-- .../tag-variant-cast-non-nullary.rs | 4 +-- .../compile-fail/uninhabited-enum-cast.rs | 2 +- .../ui/mismatched_types/cast-rfc0401.stderr | 10 +++---- .../ui/mismatched_types/issue-26480.stderr | 2 +- 17 files changed, 35 insertions(+), 38 deletions(-) diff --git a/src/librustc_typeck/check/cast.rs b/src/librustc_typeck/check/cast.rs index 52962e1e478c0..aec9d6f16d24f 100644 --- a/src/librustc_typeck/check/cast.rs +++ b/src/librustc_typeck/check/cast.rs @@ -217,7 +217,7 @@ impl<'a, 'gcx, 'tcx> CastCheck<'tcx> { } CastError::NonScalar => { struct_span_err!(fcx.tcx.sess, self.span, E0605, - "non-scalar cast: `{}` as `{}`", + "non-primitive cast: `{}` as `{}`", self.expr_ty, fcx.ty_to_string(self.cast_ty)) .note("an `as` expression can only be used to convert between \ diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs index ae13e236743dd..f9b44f0395fc4 100644 --- a/src/librustc_typeck/diagnostics.rs +++ b/src/librustc_typeck/diagnostics.rs @@ -4209,7 +4209,7 @@ println!("{}", v[2]); "##, E0604: r##" -A cast to `char` was attempted on another type than `u8`. +A cast to `char` was attempted on a type other than `u8`. Erroneous code example: @@ -4217,11 +4217,11 @@ Erroneous code example: 0u32 as char; // error: only `u8` can be cast as `char`, not `u32` ``` -As the error message indicates, only `u8` can be casted into `char`. Example: +As the error message indicates, only `u8` can be cast into `char`. Example: ``` let c = 86u8 as char; // ok! -assert!(c, 'V'); +assert_eq!(c, 'V'); ``` "##, @@ -4232,15 +4232,15 @@ Erroneous code examples: ```compile_fail,E0605 let x = 0u8; -x as Vec; // error: non-scalar cast: `u8` as `std::vec::Vec` +x as Vec; // error: non-primitive cast: `u8` as `std::vec::Vec` // Another example let v = 0 as *const u8; // So here, `v` is a `*const u8`. -v as &u8; // error: non-scalar cast: `*const u8` as `&u8` +v as &u8; // error: non-primitive cast: `*const u8` as `&u8` ``` -Only primitive types cast be casted into each others. Examples: +Only primitive types can be cast into each other. Examples: ``` let x = 0u8; @@ -4261,8 +4261,8 @@ let x = &0u8; // Here, `x` is a `&u8`. let y: u32 = x as u32; // error: casting `&u8` as `u32` is invalid ``` -When casting, keep in mind that only primitive types cast be casted into each -others. Example: +When casting, keep in mind that only primitive types can be cast into each +other. Example: ``` let x = &0u8; @@ -4282,15 +4282,16 @@ v as *const [u8]; First: what are thin and fat pointers? -Thin pointers are "simple" pointers that simply reference a memory address. +Thin pointers are "simple" pointers: they are purely a reference to a memory +address. Fat pointers are pointers referencing Dynamically Sized Types (also called DST). -They don't have a statically known size, therefore they can only exist behind +DST don't have a statically known size, therefore they can only exist behind some kind of pointers that contain additional information. Slices and trait -objects are DSTs. +objects are DSTs. In the case of slices, the additional information the fat +pointer holds is their size. -So in order to fix this error, don't try to cast directly between thin and fat -pointers. +To fix this error, don't try to cast directly between thin and fat pointers. "##, E0609: r##" diff --git a/src/test/compile-fail/cast-from-nil.rs b/src/test/compile-fail/cast-from-nil.rs index 4c6dcaccc9aed..ab22d35248073 100644 --- a/src/test/compile-fail/cast-from-nil.rs +++ b/src/test/compile-fail/cast-from-nil.rs @@ -8,5 +8,5 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// error-pattern: non-scalar cast: `()` as `u32` +// error-pattern: non-primitive cast: `()` as `u32` fn main() { let u = (assert!(true) as u32); } diff --git a/src/test/compile-fail/cast-to-bare-fn.rs b/src/test/compile-fail/cast-to-bare-fn.rs index 7cc5c727bc7df..d5a998c6e4b6b 100644 --- a/src/test/compile-fail/cast-to-bare-fn.rs +++ b/src/test/compile-fail/cast-to-bare-fn.rs @@ -13,8 +13,8 @@ fn foo(_x: isize) { } fn main() { let v: u64 = 5; let x = foo as extern "C" fn() -> isize; - //~^ ERROR non-scalar cast + //~^ ERROR non-primitive cast let y = v as extern "Rust" fn(isize) -> (isize, isize); - //~^ ERROR non-scalar cast + //~^ ERROR non-primitive cast y(x()); } diff --git a/src/test/compile-fail/cast-to-nil.rs b/src/test/compile-fail/cast-to-nil.rs index e5fd5bb33eb90..27d9e8a42b188 100644 --- a/src/test/compile-fail/cast-to-nil.rs +++ b/src/test/compile-fail/cast-to-nil.rs @@ -8,5 +8,5 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// error-pattern: non-scalar cast: `u32` as `()` +// error-pattern: non-primitive cast: `u32` as `()` fn main() { let u = 0u32 as (); } diff --git a/src/test/compile-fail/closure-no-fn-3.rs b/src/test/compile-fail/closure-no-fn-3.rs index 85dbc899208f6..6584c16c9dec6 100644 --- a/src/test/compile-fail/closure-no-fn-3.rs +++ b/src/test/compile-fail/closure-no-fn-3.rs @@ -14,5 +14,5 @@ fn main() { let b = 0u8; let baz: fn() -> u8 = (|| { b }) as fn() -> u8; - //~^ ERROR non-scalar cast + //~^ ERROR non-primitive cast } diff --git a/src/test/compile-fail/coerce-to-bang-cast.rs b/src/test/compile-fail/coerce-to-bang-cast.rs index 57d2192e6356b..0479f5cce6537 100644 --- a/src/test/compile-fail/coerce-to-bang-cast.rs +++ b/src/test/compile-fail/coerce-to-bang-cast.rs @@ -17,7 +17,7 @@ fn cast_a() { } fn cast_b() { - let y = 22 as !; //~ ERROR non-scalar cast + let y = 22 as !; //~ ERROR non-primitive cast } fn main() { } diff --git a/src/test/compile-fail/fat-ptr-cast.rs b/src/test/compile-fail/fat-ptr-cast.rs index c62987a5b900e..bc2dc1cc5d4c8 100644 --- a/src/test/compile-fail/fat-ptr-cast.rs +++ b/src/test/compile-fail/fat-ptr-cast.rs @@ -22,7 +22,7 @@ fn main() { a as isize; //~ ERROR casting a as i16; //~ ERROR casting `&[i32]` as `i16` is invalid a as u32; //~ ERROR casting `&[i32]` as `u32` is invalid - b as usize; //~ ERROR non-scalar cast + b as usize; //~ ERROR non-primitive cast p as usize; //~^ ERROR casting //~^^ HELP cast through a thin pointer diff --git a/src/test/compile-fail/issue-10991.rs b/src/test/compile-fail/issue-10991.rs index 25060b94dcf37..2d00f339f33a0 100644 --- a/src/test/compile-fail/issue-10991.rs +++ b/src/test/compile-fail/issue-10991.rs @@ -10,5 +10,5 @@ fn main() { let nil = (); - let _t = nil as usize; //~ ERROR: non-scalar cast: `()` as `usize` + let _t = nil as usize; //~ ERROR: non-primitive cast: `()` as `usize` } diff --git a/src/test/compile-fail/issue-22289.rs b/src/test/compile-fail/issue-22289.rs index bcbc414d3534b..c23fc4f334472 100644 --- a/src/test/compile-fail/issue-22289.rs +++ b/src/test/compile-fail/issue-22289.rs @@ -9,5 +9,5 @@ // except according to those terms. fn main() { - 0 as &std::any::Any; //~ ERROR non-scalar cast + 0 as &std::any::Any; //~ ERROR non-primitive cast } diff --git a/src/test/compile-fail/issue-22312.rs b/src/test/compile-fail/issue-22312.rs index 4d6e6eded2118..2128c4206301b 100644 --- a/src/test/compile-fail/issue-22312.rs +++ b/src/test/compile-fail/issue-22312.rs @@ -19,7 +19,7 @@ pub trait Array2D: Index { } let i = y * self.columns() + x; let indexer = &(*self as &Index>::Output>); - //~^ERROR non-scalar cast + //~^ERROR non-primitive cast Some(indexer.index(i)) } } diff --git a/src/test/compile-fail/issue-2995.rs b/src/test/compile-fail/issue-2995.rs index 8fbf97411cc7d..d735e184d5cd5 100644 --- a/src/test/compile-fail/issue-2995.rs +++ b/src/test/compile-fail/issue-2995.rs @@ -9,7 +9,7 @@ // except according to those terms. fn bad (p: *const isize) { - let _q: &isize = p as &isize; //~ ERROR non-scalar cast + let _q: &isize = p as &isize; //~ ERROR non-primitive cast } fn main() { } diff --git a/src/test/compile-fail/nonscalar-cast.rs b/src/test/compile-fail/nonscalar-cast.rs index d6f274da967d1..0abbc05eef05d 100644 --- a/src/test/compile-fail/nonscalar-cast.rs +++ b/src/test/compile-fail/nonscalar-cast.rs @@ -8,13 +8,11 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// error-pattern:non-scalar cast - #[derive(Debug)] struct foo { x: isize } fn main() { - println!("{}", foo{ x: 1 } as isize); + println!("{}", foo{ x: 1 } as isize); //~ non-primitive cast: `foo` as `isize` [E0605] } diff --git a/src/test/compile-fail/tag-variant-cast-non-nullary.rs b/src/test/compile-fail/tag-variant-cast-non-nullary.rs index b01063291266c..220537633eaf1 100644 --- a/src/test/compile-fail/tag-variant-cast-non-nullary.rs +++ b/src/test/compile-fail/tag-variant-cast-non-nullary.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//error-pattern: non-scalar cast - enum non_nullary { nullary, other(isize), @@ -17,5 +15,5 @@ enum non_nullary { fn main() { let v = non_nullary::nullary; - let val = v as isize; + let val = v as isize; //~ ERROR non-primitive cast: `non_nullary` as `isize` [E0605] } diff --git a/src/test/compile-fail/uninhabited-enum-cast.rs b/src/test/compile-fail/uninhabited-enum-cast.rs index b4df5fb1e2acc..2a5d25e6b98dd 100644 --- a/src/test/compile-fail/uninhabited-enum-cast.rs +++ b/src/test/compile-fail/uninhabited-enum-cast.rs @@ -11,7 +11,7 @@ enum E {} fn f(e: E) { - println!("{}", (e as isize).to_string()); //~ ERROR non-scalar cast + println!("{}", (e as isize).to_string()); //~ ERROR non-primitive cast } fn main() {} diff --git a/src/test/ui/mismatched_types/cast-rfc0401.stderr b/src/test/ui/mismatched_types/cast-rfc0401.stderr index 50e1815057928..879acbcf9d9d1 100644 --- a/src/test/ui/mismatched_types/cast-rfc0401.stderr +++ b/src/test/ui/mismatched_types/cast-rfc0401.stderr @@ -20,7 +20,7 @@ error[E0609]: no field `f` on type `fn() {main}` 75 | let _ = main.f as *const u32; | ^ -error[E0605]: non-scalar cast: `*const u8` as `&u8` +error[E0605]: non-primitive cast: `*const u8` as `&u8` --> $DIR/cast-rfc0401.rs:39:13 | 39 | let _ = v as &u8; @@ -28,7 +28,7 @@ error[E0605]: non-scalar cast: `*const u8` as `&u8` | = note: an `as` expression can only be used to convert between primitive types. Consider using the `From` trait -error[E0605]: non-scalar cast: `*const u8` as `E` +error[E0605]: non-primitive cast: `*const u8` as `E` --> $DIR/cast-rfc0401.rs:40:13 | 40 | let _ = v as E; @@ -36,7 +36,7 @@ error[E0605]: non-scalar cast: `*const u8` as `E` | = note: an `as` expression can only be used to convert between primitive types. Consider using the `From` trait -error[E0605]: non-scalar cast: `*const u8` as `fn()` +error[E0605]: non-primitive cast: `*const u8` as `fn()` --> $DIR/cast-rfc0401.rs:41:13 | 41 | let _ = v as fn(); @@ -44,7 +44,7 @@ error[E0605]: non-scalar cast: `*const u8` as `fn()` | = note: an `as` expression can only be used to convert between primitive types. Consider using the `From` trait -error[E0605]: non-scalar cast: `*const u8` as `(u32,)` +error[E0605]: non-primitive cast: `*const u8` as `(u32,)` --> $DIR/cast-rfc0401.rs:42:13 | 42 | let _ = v as (u32,); @@ -52,7 +52,7 @@ error[E0605]: non-scalar cast: `*const u8` as `(u32,)` | = note: an `as` expression can only be used to convert between primitive types. Consider using the `From` trait -error[E0605]: non-scalar cast: `std::option::Option<&*const u8>` as `*const u8` +error[E0605]: non-primitive cast: `std::option::Option<&*const u8>` as `*const u8` --> $DIR/cast-rfc0401.rs:43:13 | 43 | let _ = Some(&v) as *const u8; diff --git a/src/test/ui/mismatched_types/issue-26480.stderr b/src/test/ui/mismatched_types/issue-26480.stderr index 06b8806900290..9da9042e78ed1 100644 --- a/src/test/ui/mismatched_types/issue-26480.stderr +++ b/src/test/ui/mismatched_types/issue-26480.stderr @@ -7,7 +7,7 @@ error[E0308]: mismatched types 37 | write!(hello); | -------------- in this macro invocation -error[E0605]: non-scalar cast: `{integer}` as `()` +error[E0605]: non-primitive cast: `{integer}` as `()` --> $DIR/issue-26480.rs:32:19 | 32 | ($x:expr) => ($x as ()) From 9137153e4725649443ac02f742424aa5737d15b6 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Mon, 12 Jun 2017 18:58:11 +0200 Subject: [PATCH 6/7] Use new macro instead --- src/librustc_typeck/check/cast.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/librustc_typeck/check/cast.rs b/src/librustc_typeck/check/cast.rs index aec9d6f16d24f..ea08f1f624e67 100644 --- a/src/librustc_typeck/check/cast.rs +++ b/src/librustc_typeck/check/cast.rs @@ -120,10 +120,10 @@ fn make_invalid_casting_error<'a, 'gcx, 'tcx>(sess: &'a Session, cast_ty: Ty<'tcx>, fcx: &FnCtxt<'a, 'gcx, 'tcx>) -> DiagnosticBuilder<'a> { - struct_span_err!(sess, span, E0606, - "casting `{}` as `{}` is invalid", - fcx.ty_to_string(expr_ty), - fcx.ty_to_string(cast_ty)) + type_error_struct!(sess, span, expr_ty, E0606, + "casting `{}` as `{}` is invalid", + fcx.ty_to_string(expr_ty), + fcx.ty_to_string(cast_ty)) } impl<'a, 'gcx, 'tcx> CastCheck<'tcx> { @@ -212,11 +212,11 @@ impl<'a, 'gcx, 'tcx> CastCheck<'tcx> { .emit(); } CastError::CastToChar => { - struct_span_err!(fcx.tcx.sess, self.span, E0604, + type_error_struct!(fcx.tcx.sess, self.span, self.expr_ty, E0604, "only `u8` can be cast as `char`, not `{}`", self.expr_ty).emit(); } CastError::NonScalar => { - struct_span_err!(fcx.tcx.sess, self.span, E0605, + type_error_struct!(fcx.tcx.sess, self.span, self.expr_ty, E0605, "non-primitive cast: `{}` as `{}`", self.expr_ty, fcx.ty_to_string(self.cast_ty)) @@ -225,7 +225,7 @@ impl<'a, 'gcx, 'tcx> CastCheck<'tcx> { .emit(); } CastError::SizedUnsizedCast => { - struct_span_err!(fcx.tcx.sess, self.span, E0607, + type_error_struct!(fcx.tcx.sess, self.span, self.expr_ty, E0607, "cannot cast thin pointer `{}` to fat pointer `{}`", self.expr_ty, fcx.ty_to_string(self.cast_ty)).emit(); From bcf0d600f3884709c5faef21219a7613e254b7e0 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sun, 25 Jun 2017 09:25:37 +0200 Subject: [PATCH 7/7] Add reference link --- src/librustc_typeck/diagnostics.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs index f9b44f0395fc4..b2fa2cc7c61d2 100644 --- a/src/librustc_typeck/diagnostics.rs +++ b/src/librustc_typeck/diagnostics.rs @@ -4223,6 +4223,9 @@ As the error message indicates, only `u8` can be cast into `char`. Example: let c = 86u8 as char; // ok! assert_eq!(c, 'V'); ``` + +For more information about casts, take a look at The Book: +https://doc.rust-lang.org/book/first-edition/casting-between-types.html "##, E0605: r##" @@ -4249,6 +4252,9 @@ x as u32; // ok! let v = 0 as *const u8; v as *const i8; // ok! ``` + +For more information about casts, take a look at The Book: +https://doc.rust-lang.org/book/first-edition/casting-between-types.html "##, E0606: r##" @@ -4268,6 +4274,9 @@ other. Example: let x = &0u8; let y: u32 = *x as u32; // We dereference it first and then cast it. ``` + +For more information about casts, take a look at The Book: +https://doc.rust-lang.org/book/first-edition/casting-between-types.html "##, E0607: r##" @@ -4292,6 +4301,9 @@ objects are DSTs. In the case of slices, the additional information the fat pointer holds is their size. To fix this error, don't try to cast directly between thin and fat pointers. + +For more information about casts, take a look at The Book: +https://doc.rust-lang.org/book/first-edition/casting-between-types.html "##, E0609: r##"