about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/librustc/ty/cast.rs3
-rw-r--r--src/librustc_typeck/check/cast.rs65
-rw-r--r--src/test/run-pass/cast-rfc0401-vtable-kinds.rs17
-rw-r--r--src/test/ui/cast-errors-issue-43825.rs17
-rw-r--r--src/test/ui/cast-errors-issue-43825.stderr8
-rw-r--r--src/test/ui/casts-differing-anon.rs34
-rw-r--r--src/test/ui/casts-differing-anon.stderr10
-rw-r--r--src/test/ui/casts-issue-46365.rs17
-rw-r--r--src/test/ui/casts-issue-46365.stderr8
9 files changed, 167 insertions, 12 deletions
diff --git a/src/librustc/ty/cast.rs b/src/librustc/ty/cast.rs
index 0badb85e9e0..c118b7a4692 100644
--- a/src/librustc/ty/cast.rs
+++ b/src/librustc/ty/cast.rs
@@ -20,6 +20,7 @@ use syntax::ast;
 pub enum IntTy {
     U(ast::UintTy),
     I,
+    Ivar,
     CEnum,
     Bool,
     Char
@@ -63,6 +64,8 @@ impl<'tcx> CastTy<'tcx> {
             ty::TyBool => Some(CastTy::Int(IntTy::Bool)),
             ty::TyChar => Some(CastTy::Int(IntTy::Char)),
             ty::TyInt(_) => Some(CastTy::Int(IntTy::I)),
+            ty::TyInfer(ty::InferTy::IntVar(_)) => Some(CastTy::Int(IntTy::Ivar)),
+            ty::TyInfer(ty::InferTy::FloatVar(_)) => Some(CastTy::Float),
             ty::TyUint(u) => Some(CastTy::Int(IntTy::U(u))),
             ty::TyFloat(_) => Some(CastTy::Float),
             ty::TyAdt(d,_) if d.is_enum() && d.is_payloadfree() =>
diff --git a/src/librustc_typeck/check/cast.rs b/src/librustc_typeck/check/cast.rs
index d68c139894b..7c199587c98 100644
--- a/src/librustc_typeck/check/cast.rs
+++ b/src/librustc_typeck/check/cast.rs
@@ -48,6 +48,7 @@ use rustc::session::Session;
 use rustc::traits;
 use rustc::ty::{self, Ty, TypeFoldable};
 use rustc::ty::cast::{CastKind, CastTy};
+use rustc::ty::subst::Substs;
 use rustc::middle::lang_items;
 use syntax::ast;
 use syntax_pos::Span;
@@ -77,6 +78,8 @@ enum PointerKind<'tcx> {
     Length,
     /// The unsize info of this projection
     OfProjection(&'tcx ty::ProjectionTy<'tcx>),
+    /// The unsize info of this anon ty
+    OfAnon(DefId, &'tcx Substs<'tcx>),
     /// The unsize info of this parameter
     OfParam(&'tcx ty::ParamTy),
 }
@@ -84,36 +87,65 @@ enum PointerKind<'tcx> {
 impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
     /// Returns the kind of unsize information of t, or None
     /// if t is unknown.
-    fn pointer_kind(&self, t: Ty<'tcx>, span: Span) -> Option<PointerKind<'tcx>> {
+    fn pointer_kind(&self, t: Ty<'tcx>, span: Span) ->
+        Result<Option<PointerKind<'tcx>>, ErrorReported>
+    {
+        debug!("pointer_kind({:?}, {:?})", t, span);
+
+        let t = self.resolve_type_vars_if_possible(&t);
+
+        if t.references_error() {
+            return Err(ErrorReported);
+        }
+
         if self.type_is_known_to_be_sized(t, span) {
-            return Some(PointerKind::Thin);
+            return Ok(Some(PointerKind::Thin));
         }
 
-        match t.sty {
+        Ok(match t.sty {
             ty::TySlice(_) | ty::TyStr => Some(PointerKind::Length),
             ty::TyDynamic(ref tty, ..) =>
                 Some(PointerKind::Vtable(tty.principal().map(|p| p.def_id()))),
             ty::TyAdt(def, substs) if def.is_struct() => {
-                // FIXME(arielb1): do some kind of normalization
                 match def.struct_variant().fields.last() {
                     None => Some(PointerKind::Thin),
-                    Some(f) => self.pointer_kind(f.ty(self.tcx, substs), span),
+                    Some(f) => {
+                        let field_ty = self.field_ty(span, f, substs);
+                        self.pointer_kind(field_ty, span)?
+                    }
                 }
             }
+            ty::TyTuple(fields, _) => match fields.last() {
+                None => Some(PointerKind::Thin),
+                Some(f) => self.pointer_kind(f, span)?
+            },
+
             // Pointers to foreign types are thin, despite being unsized
             ty::TyForeign(..) => Some(PointerKind::Thin),
             // We should really try to normalize here.
             ty::TyProjection(ref pi) => Some(PointerKind::OfProjection(pi)),
+            ty::TyAnon(def_id, substs) => Some(PointerKind::OfAnon(def_id, substs)),
             ty::TyParam(ref p) => Some(PointerKind::OfParam(p)),
             // Insufficient type information.
             ty::TyInfer(_) => None,
-            _ => panic!(),
-        }
+
+            ty::TyBool | ty::TyChar | ty::TyInt(..) | ty::TyUint(..) |
+            ty::TyFloat(_) | ty::TyArray(..) |
+            ty::TyRawPtr(_) | ty::TyRef(..) | ty::TyFnDef(..) |
+            ty::TyFnPtr(..) | ty::TyClosure(..) | ty::TyGenerator(..) |
+            ty::TyAdt(..) | ty::TyNever | ty::TyError => {
+                self.tcx.sess.delay_span_bug(
+                    span, &format!("`{:?}` should be sized but is not?", t));
+                return Err(ErrorReported);
+            }
+        })
     }
 }
 
 #[derive(Copy, Clone)]
 enum CastError {
+    ErrorReported,
+
     CastToBool,
     CastToChar,
     DifferingKinds,
@@ -129,6 +161,12 @@ enum CastError {
     UnknownCastPtrKind,
 }
 
+impl From<ErrorReported> for CastError {
+    fn from(ErrorReported: ErrorReported) -> Self {
+        CastError::ErrorReported
+    }
+}
+
 fn make_invalid_casting_error<'a, 'gcx, 'tcx>(sess: &'a Session,
                                               span: Span,
                                               expr_ty: Ty<'tcx>,
@@ -173,6 +211,9 @@ impl<'a, 'gcx, 'tcx> CastCheck<'tcx> {
 
     fn report_cast_error(&self, fcx: &FnCtxt<'a, 'gcx, 'tcx>, e: CastError) {
         match e {
+            CastError::ErrorReported => {
+                // an error has already been reported
+            }
             CastError::NeedDeref => {
                 let error_span = self.span;
                 let mut err = make_invalid_casting_error(fcx.tcx.sess, self.span, self.expr_ty,
@@ -480,8 +521,8 @@ impl<'a, 'gcx, 'tcx> CastCheck<'tcx> {
         debug!("check_ptr_ptr_cast m_expr={:?} m_cast={:?}", m_expr, m_cast);
         // ptr-ptr cast. vtables must match.
 
-        let expr_kind = fcx.pointer_kind(m_expr.ty, self.span);
-        let cast_kind = fcx.pointer_kind(m_cast.ty, self.span);
+        let expr_kind = fcx.pointer_kind(m_expr.ty, self.span)?;
+        let cast_kind = fcx.pointer_kind(m_cast.ty, self.span)?;
 
         let cast_kind = match cast_kind {
             // We can't cast if target pointer kind is unknown
@@ -519,7 +560,7 @@ impl<'a, 'gcx, 'tcx> CastCheck<'tcx> {
                            -> Result<CastKind, CastError> {
         // fptr-ptr cast. must be to thin ptr
 
-        match fcx.pointer_kind(m_cast.ty, self.span) {
+        match fcx.pointer_kind(m_cast.ty, self.span)? {
             None => Err(CastError::UnknownCastPtrKind),
             Some(PointerKind::Thin) => Ok(CastKind::FnPtrPtrCast),
             _ => Err(CastError::IllegalCast),
@@ -532,7 +573,7 @@ impl<'a, 'gcx, 'tcx> CastCheck<'tcx> {
                            -> Result<CastKind, CastError> {
         // ptr-addr cast. must be from thin ptr
 
-        match fcx.pointer_kind(m_expr.ty, self.span) {
+        match fcx.pointer_kind(m_expr.ty, self.span)? {
             None => Err(CastError::UnknownExprPtrKind),
             Some(PointerKind::Thin) => Ok(CastKind::PtrAddrCast),
             _ => Err(CastError::NeedViaThinPtr),
@@ -569,7 +610,7 @@ impl<'a, 'gcx, 'tcx> CastCheck<'tcx> {
                            m_cast: &'tcx ty::TypeAndMut<'tcx>)
                            -> Result<CastKind, CastError> {
         // ptr-addr cast. pointer must be thin.
-        match fcx.pointer_kind(m_cast.ty, self.span) {
+        match fcx.pointer_kind(m_cast.ty, self.span)? {
             None => Err(CastError::UnknownCastPtrKind),
             Some(PointerKind::Thin) => Ok(CastKind::AddrPtrCast),
             _ => Err(CastError::IllegalCast),
diff --git a/src/test/run-pass/cast-rfc0401-vtable-kinds.rs b/src/test/run-pass/cast-rfc0401-vtable-kinds.rs
index 3a9f24ad4cc..32a155c13e6 100644
--- a/src/test/run-pass/cast-rfc0401-vtable-kinds.rs
+++ b/src/test/run-pass/cast-rfc0401-vtable-kinds.rs
@@ -11,6 +11,8 @@
 // Check that you can cast between different pointers to trait objects
 // whose vtable have the same kind (both lengths, or both trait pointers).
 
+#![feature(unsized_tuple_coercion)]
+
 trait Foo<T> {
     fn foo(&self, _: T) -> u32 { 42 }
 }
@@ -39,6 +41,11 @@ fn foo_to_bar<T:?Sized>(u: *const FooS<T>) -> *const BarS<T> {
     u as *const BarS<T>
 }
 
+fn tuple_i32_to_u32<T:?Sized>(u: *const (i32, T)) -> *const (u32, T) {
+    u as *const (u32, T)
+}
+
+
 fn main() {
     let x = 4u32;
     let y : &Foo<u32> = &x;
@@ -51,4 +58,14 @@ fn main() {
     let bar_ref : *const BarS<[u32]> = foo_to_bar(u);
     let z : &BarS<[u32]> = unsafe{&*bar_ref};
     assert_eq!(&z.0, &[0,1,2]);
+
+    // this assumes that tuple reprs for (i32, _) and (u32, _) are
+    // the same.
+    let s = (0i32, [0, 1, 2]);
+    let u: &(i32, [u8]) = &s;
+    let u: *const (i32, [u8]) = u;
+    let u_u32 : *const (u32, [u8]) = tuple_i32_to_u32(u);
+    unsafe {
+        assert_eq!(&(*u_u32).1, &[0, 1, 2]);
+    }
 }
diff --git a/src/test/ui/cast-errors-issue-43825.rs b/src/test/ui/cast-errors-issue-43825.rs
new file mode 100644
index 00000000000..65b391205e3
--- /dev/null
+++ b/src/test/ui/cast-errors-issue-43825.rs
@@ -0,0 +1,17 @@
+// 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 error = error; //~ ERROR cannot find value `error`
+
+    // These used to cause errors.
+    0 as f32;
+    0.0 as u32;
+}
diff --git a/src/test/ui/cast-errors-issue-43825.stderr b/src/test/ui/cast-errors-issue-43825.stderr
new file mode 100644
index 00000000000..db0a33e927f
--- /dev/null
+++ b/src/test/ui/cast-errors-issue-43825.stderr
@@ -0,0 +1,8 @@
+error[E0425]: cannot find value `error` in this scope
+  --> $DIR/cast-errors-issue-43825.rs:12:17
+   |
+12 |     let error = error; //~ ERROR cannot find value `error`
+   |                 ^^^^^ not found in this scope
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/casts-differing-anon.rs b/src/test/ui/casts-differing-anon.rs
new file mode 100644
index 00000000000..74c8ff370f9
--- /dev/null
+++ b/src/test/ui/casts-differing-anon.rs
@@ -0,0 +1,34 @@
+// 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.
+
+#![feature(conservative_impl_trait)]
+
+use std::fmt;
+
+fn foo() -> Box<impl fmt::Debug+?Sized> {
+    let x : Box<[u8]> = Box::new([0]);
+    x
+}
+fn bar() -> Box<impl fmt::Debug+?Sized> {
+    let y: Box<fmt::Debug> = Box::new([0]);
+    y
+}
+
+fn main() {
+    let f = foo();
+    let b = bar();
+
+    // this is an `*mut [u8]` in practice
+    let f_raw : *mut _ = Box::into_raw(f);
+    // this is an `*mut fmt::Debug` in practice
+    let mut b_raw = Box::into_raw(b);
+    // ... and they should not be mixable
+    b_raw = f_raw as *mut _; //~ ERROR is invalid
+}
diff --git a/src/test/ui/casts-differing-anon.stderr b/src/test/ui/casts-differing-anon.stderr
new file mode 100644
index 00000000000..8db6854dba9
--- /dev/null
+++ b/src/test/ui/casts-differing-anon.stderr
@@ -0,0 +1,10 @@
+error[E0606]: casting `*mut impl std::fmt::Debug+?Sized` as `*mut impl std::fmt::Debug+?Sized` is invalid
+  --> $DIR/casts-differing-anon.rs:33:13
+   |
+33 |     b_raw = f_raw as *mut _; //~ ERROR is invalid
+   |             ^^^^^^^^^^^^^^^
+   |
+   = note: vtable kinds may not match
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/casts-issue-46365.rs b/src/test/ui/casts-issue-46365.rs
new file mode 100644
index 00000000000..79f636e413f
--- /dev/null
+++ b/src/test/ui/casts-issue-46365.rs
@@ -0,0 +1,17 @@
+// 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.
+
+struct Lorem {
+    ipsum: Ipsum //~ ERROR cannot find type `Ipsum`
+}
+
+fn main() {
+    let _foo: *mut Lorem = 0 as *mut _; // no error here
+}
diff --git a/src/test/ui/casts-issue-46365.stderr b/src/test/ui/casts-issue-46365.stderr
new file mode 100644
index 00000000000..ce3c8593a97
--- /dev/null
+++ b/src/test/ui/casts-issue-46365.stderr
@@ -0,0 +1,8 @@
+error[E0412]: cannot find type `Ipsum` in this scope
+  --> $DIR/casts-issue-46365.rs:12:12
+   |
+12 |     ipsum: Ipsum //~ ERROR cannot find type `Ipsum`
+   |            ^^^^^ not found in this scope
+
+error: aborting due to previous error
+