]> git.lizzy.rs Git - rust.git/commitdiff
Require that objects can only be made from Sized types. Fixes #18333.
authorNiko Matsakis <niko@alum.mit.edu>
Fri, 7 Nov 2014 21:26:26 +0000 (16:26 -0500)
committerNiko Matsakis <niko@alum.mit.edu>
Thu, 20 Nov 2014 14:16:20 +0000 (09:16 -0500)
src/librustc/middle/traits/mod.rs
src/librustc/middle/typeck/check/mod.rs
src/librustc/middle/typeck/check/vtable.rs
src/librustc/util/common.rs
src/test/compile-fail/dst-object-from-unsized-type.rs [new file with mode: 0644]
src/test/compile-fail/issue-14366.rs

index d34d413225e808f89a91dee0f4e83a29b12271d4..0a47d647890381d27ca17d249f10e1f3649ca03d 100644 (file)
@@ -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>>;
index 553d80852c28fb959117ebcb0465096c8f20f56d..704168da1582a8dadaf3322152650ac4e0ee9887 100644 (file)
@@ -1771,12 +1771,13 @@ fn register_unsize_obligations(&self,
             }
             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`:
index 99ffe898622297fc6cd86e77b93ae597b3c6eafd..1619a4224f9f02218fd92562dc2e02c723e0ac7a 100644 (file)
@@ -21,6 +21,7 @@
 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");
+        }
     }
 }
index cdbe107e11c9576fdd1f02ae540ccceabb9d6e97..e2fa02584f4fd70be3c9db8a37837be299b13ee6 100644 (file)
@@ -20,7 +20,8 @@
 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 (file)
index 0000000..e40cc34
--- /dev/null
@@ -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`
+}
index a0eca1d49dcc9604808aae12ea7f9ffa78a77bb7..01a15023fbaada5f68e74d61ceb027b95b5d2c00 100644 (file)
@@ -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`
 }