Skip to content

Create more error codes #42519

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 7 commits into from
Jun 27, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
105 changes: 42 additions & 63 deletions src/librustc_typeck/check/cast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand Down Expand Up @@ -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> {
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> {
pub fn new(fcx: &FnCtxt<'a, 'gcx, 'tcx>,
expr: &'tcx hir::Expr,
Expand Down Expand Up @@ -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),
Expand All @@ -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 {
Expand All @@ -184,72 +188,47 @@ 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",
_ => bug!(),
}))
.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")
.help("compare with zero instead")
.emit();
}
CastError::CastToChar => {
fcx.type_error_message(self.span,
|actual| {
format!("only `u8` can be cast as `char`, not `{}`",
actual)
},
self.expr_ty);
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 => {
fcx.type_error_message(self.span,
|actual| {
format!("non-scalar cast: `{}` as `{}`",
actual,
fcx.ty_to_string(self.cast_ty))
},
self.expr_ty);
}
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);
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))
.note("an `as` expression can only be used to convert between \
primitive types. Consider using the `From` trait")
.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)
}
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();
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();
}
}
}
Expand Down
98 changes: 98 additions & 0 deletions src/librustc_typeck/diagnostics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4208,6 +4208,104 @@ println!("{}", v[2]);
```
"##,

E0604: r##"
A cast to `char` was attempted on a type other 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 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##"
An invalid cast was attempted.

Erroneous code examples:

```compile_fail,E0605
let x = 0u8;
x as Vec<u8>; // error: non-primitive cast: `u8` as `std::vec::Vec<u8>`

// Another example

let v = 0 as *const u8; // So here, `v` is a `*const u8`.
v as &u8; // error: non-primitive cast: `*const u8` as `&u8`
```

Only primitive types can be cast into each other. Examples:

```
let x = 0u8;
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##"
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 can be cast into each
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##"
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: they are purely a reference to a memory
address.

Fat pointers are pointers referencing Dynamically Sized Types (also called DST).
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't know if "dynamically sized types" needs to be capitalized here, but not a big deal

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree, it shouldn't be capitalized.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It was to make easier the understanding of DST.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok removed.

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. 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##"
Attempted to access a non-existent field in a struct.

Expand Down
13 changes: 13 additions & 0 deletions src/test/compile-fail/E0604.rs
Original file line number Diff line number Diff line change
@@ -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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

fn main() {
1u32 as char; //~ ERROR E0604
}
19 changes: 19 additions & 0 deletions src/test/compile-fail/E0605.rs
Original file line number Diff line number Diff line change
@@ -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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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<u8>; //~ 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
}
13 changes: 13 additions & 0 deletions src/test/compile-fail/E0606.rs
Original file line number Diff line number Diff line change
@@ -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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

fn main() {
&0u8 as u8; //~ ERROR E0606
}
14 changes: 14 additions & 0 deletions src/test/compile-fail/E0607.rs
Original file line number Diff line number Diff line change
@@ -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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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
}
2 changes: 1 addition & 1 deletion src/test/compile-fail/cast-from-nil.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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); }
4 changes: 2 additions & 2 deletions src/test/compile-fail/cast-to-bare-fn.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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());
}
2 changes: 1 addition & 1 deletion src/test/compile-fail/cast-to-nil.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 (); }
2 changes: 1 addition & 1 deletion src/test/compile-fail/closure-no-fn-3.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
2 changes: 1 addition & 1 deletion src/test/compile-fail/coerce-to-bang-cast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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() { }
2 changes: 1 addition & 1 deletion src/test/compile-fail/fat-ptr-cast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion src/test/compile-fail/issue-10991.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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`
}
2 changes: 1 addition & 1 deletion src/test/compile-fail/issue-22289.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
Loading