about summary refs log tree commit diff
diff options
context:
space:
mode:
authorNiko Matsakis <niko@alum.mit.edu>2014-11-07 16:26:26 -0500
committerNiko Matsakis <niko@alum.mit.edu>2014-11-20 09:16:20 -0500
commit7a372e23cbab0be6abd3fbd321d0548640568920 (patch)
tree8a7ccd1dbf4b3e462e679ebb3eb4a69f5c8261ab
parentdd5ce5ae2f254cc42763518909f6e7c486d9502a (diff)
downloadrust-7a372e23cbab0be6abd3fbd321d0548640568920.tar.gz
rust-7a372e23cbab0be6abd3fbd321d0548640568920.zip
Require that objects can only be made from Sized types. Fixes #18333.
-rw-r--r--src/librustc/middle/traits/mod.rs3
-rw-r--r--src/librustc/middle/typeck/check/mod.rs7
-rw-r--r--src/librustc/middle/typeck/check/vtable.rs19
-rw-r--r--src/librustc/util/common.rs3
-rw-r--r--src/test/compile-fail/dst-object-from-unsized-type.rs30
-rw-r--r--src/test/compile-fail/issue-14366.rs2
6 files changed, 59 insertions, 5 deletions
diff --git a/src/librustc/middle/traits/mod.rs b/src/librustc/middle/traits/mod.rs
index d34d413225e..0a47d647890 100644
--- a/src/librustc/middle/traits/mod.rs
+++ b/src/librustc/middle/traits/mod.rs
@@ -94,6 +94,9 @@ pub enum ObligationCauseCode<'tcx> {
 
     // Types of fields (other than the last) in a struct must be sized.
     FieldSized,
+
+    // Only Sized types can be made into objects
+    ObjectSized,
 }
 
 pub type Obligations<'tcx> = subst::VecPerParamSpace<Obligation<'tcx>>;
diff --git a/src/librustc/middle/typeck/check/mod.rs b/src/librustc/middle/typeck/check/mod.rs
index 553d80852c2..704168da158 100644
--- a/src/librustc/middle/typeck/check/mod.rs
+++ b/src/librustc/middle/typeck/check/mod.rs
@@ -1771,12 +1771,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             }
             ty::UnsizeVtable(ref ty_trait, self_ty) => {
                 vtable::check_object_safety(self.tcx(), ty_trait, span);
+
                 // If the type is `Foo+'a`, ensures that the type
                 // being cast to `Foo+'a` implements `Foo`:
                 vtable::register_object_cast_obligations(self,
-                                                          span,
-                                                          ty_trait,
-                                                          self_ty);
+                                                         span,
+                                                         ty_trait,
+                                                         self_ty);
 
                 // If the type is `Foo+'a`, ensures that the type
                 // being cast to `Foo+'a` outlives `'a`:
diff --git a/src/librustc/middle/typeck/check/vtable.rs b/src/librustc/middle/typeck/check/vtable.rs
index 99ffe898622..1619a4224f9 100644
--- a/src/librustc/middle/typeck/check/vtable.rs
+++ b/src/librustc/middle/typeck/check/vtable.rs
@@ -21,6 +21,7 @@ use middle::typeck::infer;
 use std::rc::Rc;
 use syntax::ast;
 use syntax::codemap::Span;
+use util::common::ErrorReported;
 use util::ppaux::{UserString, Repr, ty_to_string};
 
 pub fn check_object_cast<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
@@ -238,6 +239,20 @@ pub fn register_object_cast_obligations<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
                                                   referent_ty: Ty<'tcx>)
                                                   -> Rc<ty::TraitRef<'tcx>>
 {
+    // We can only make objects from sized types.
+    let sized_obligation =
+        traits::obligation_for_builtin_bound(
+            fcx.tcx(),
+            traits::ObligationCause::new(span, traits::ObjectSized),
+            referent_ty,
+            ty::BoundSized);
+    match sized_obligation {
+        Ok(sized_obligation) => {
+            fcx.register_obligation(sized_obligation);
+        }
+        Err(ErrorReported) => { }
+    }
+
     // This is just for better error reporting. Kinda goofy. The object type stuff
     // needs some refactoring so there is a more convenient type to pass around.
     let object_trait_ty =
@@ -543,5 +558,9 @@ fn note_obligation_cause<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
                        "only the last field of a struct or enum variant \
                        may have a dynamically sized type")
         }
+        traits::ObjectSized => {
+            span_note!(tcx.sess, obligation.cause.span,
+                       "only sized types can be made into objects");
+        }
     }
 }
diff --git a/src/librustc/util/common.rs b/src/librustc/util/common.rs
index cdbe107e11c..e2fa02584f4 100644
--- a/src/librustc/util/common.rs
+++ b/src/librustc/util/common.rs
@@ -20,7 +20,8 @@ use syntax::ast;
 use syntax::visit;
 use syntax::visit::Visitor;
 
-// An error has already been reported to the user, so no need to continue checking.
+// Useful type to use with `Result<>` indicate that an error has already
+// been reported to the user, so no need to continue checking.
 #[deriving(Clone,Show)]
 pub struct ErrorReported;
 
diff --git a/src/test/compile-fail/dst-object-from-unsized-type.rs b/src/test/compile-fail/dst-object-from-unsized-type.rs
new file mode 100644
index 00000000000..e40cc342c0b
--- /dev/null
+++ b/src/test/compile-fail/dst-object-from-unsized-type.rs
@@ -0,0 +1,30 @@
+// Copyright 2014 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.
+
+// Test that we cannot create objects from unsized types.
+
+trait Foo for Sized? {}
+impl Foo for str {}
+
+fn test<Sized? T: Foo>(t: &T) {
+    let u: &Foo = t;
+    //~^ ERROR `core::kinds::Sized` is not implemented for the type `T`
+
+    let v: &Foo = t as &Foo;
+    //~^ ERROR `core::kinds::Sized` is not implemented for the type `T`
+}
+
+fn main() {
+    let _: &[&Foo] = &["hi"];
+    //~^ ERROR `core::kinds::Sized` is not implemented for the type `str`
+
+    let _: &Foo = "hi" as &Foo;
+    //~^ ERROR `core::kinds::Sized` is not implemented for the type `str`
+}
diff --git a/src/test/compile-fail/issue-14366.rs b/src/test/compile-fail/issue-14366.rs
index a0eca1d49dc..01a15023fba 100644
--- a/src/test/compile-fail/issue-14366.rs
+++ b/src/test/compile-fail/issue-14366.rs
@@ -11,5 +11,5 @@
 fn main() {
     let _x = "test" as &::std::any::Any;
 //~^ ERROR the trait `core::kinds::Sized` is not implemented for the type `str`
-//~^^ NOTE the trait `core::kinds::Sized` must be implemented for the cast to the object type
+//~^^ ERROR the trait `core::kinds::Sized` is not implemented for the type `str`
 }