about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/librustc_typeck/check/mod.rs3
-rw-r--r--src/librustc_typeck/check/vtable.rs27
-rw-r--r--src/test/compile-fail/issue-18959.rs26
3 files changed, 48 insertions, 8 deletions
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index a0f3f2734d9..cdf34c7f4d2 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -1747,8 +1747,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 self.register_unsize_obligations(span, &**u)
             }
             ty::UnsizeVtable(ref ty_trait, self_ty) => {
-                vtable::check_object_safety(self.tcx(), ty_trait, span);
-
+                vtable::check_object_safety(self.tcx(), &ty_trait.principal, span);
                 // If the type is `Foo+'a`, ensures that the type
                 // being cast to `Foo+'a` implements `Foo`:
                 vtable::register_object_cast_obligations(self,
diff --git a/src/librustc_typeck/check/vtable.rs b/src/librustc_typeck/check/vtable.rs
index c2b263885bd..b9f7eb3f271 100644
--- a/src/librustc_typeck/check/vtable.rs
+++ b/src/librustc_typeck/check/vtable.rs
@@ -45,7 +45,7 @@ pub fn check_object_cast<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
 
             // Ensure that if ~T is cast to ~Trait, then T : Trait
             push_cast_obligation(fcx, cast_expr, object_trait, referent_ty);
-            check_object_safety(fcx.tcx(), object_trait, source_expr.span);
+            check_object_safety(fcx.tcx(), &object_trait.principal, source_expr.span);
         }
 
         (&ty::ty_rptr(referent_region, ty::mt { ty: referent_ty,
@@ -69,7 +69,7 @@ pub fn check_object_cast<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
                                target_region,
                                referent_region);
 
-                check_object_safety(fcx.tcx(), object_trait, source_expr.span);
+                check_object_safety(fcx.tcx(), &object_trait.principal, source_expr.span);
             }
         }
 
@@ -133,17 +133,32 @@ pub fn check_object_cast<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
 // self by value, has no type parameters and does not use the `Self` type, except
 // in self position.
 pub fn check_object_safety<'tcx>(tcx: &ty::ctxt<'tcx>,
-                                 object_trait: &ty::TyTrait<'tcx>,
+                                 object_trait: &ty::TraitRef<'tcx>,
+                                 span: Span) {
+
+    let mut object = object_trait.clone();
+    if object.substs.types.len(SelfSpace) == 0 {
+        object.substs.types.push(SelfSpace, ty::mk_err());
+    }
+
+    let object = Rc::new(object);
+    for tr in traits::supertraits(tcx, object) {
+        check_object_safety_inner(tcx, &*tr, span);
+    }
+}
+
+fn check_object_safety_inner<'tcx>(tcx: &ty::ctxt<'tcx>,
+                                 object_trait: &ty::TraitRef<'tcx>,
                                  span: Span) {
     // Skip the fn_once lang item trait since only the compiler should call
     // `call_once` which is the method which takes self by value. What could go
     // wrong?
     match tcx.lang_items.fn_once_trait() {
-        Some(def_id) if def_id == object_trait.principal.def_id => return,
+        Some(def_id) if def_id == object_trait.def_id => return,
         _ => {}
     }
 
-    let trait_items = ty::trait_items(tcx, object_trait.principal.def_id);
+    let trait_items = ty::trait_items(tcx, object_trait.def_id);
 
     let mut errors = Vec::new();
     for item in trait_items.iter() {
@@ -157,7 +172,7 @@ pub fn check_object_safety<'tcx>(tcx: &ty::ctxt<'tcx>,
 
     let mut errors = errors.iter().flat_map(|x| x.iter()).peekable();
     if errors.peek().is_some() {
-        let trait_name = ty::item_path_str(tcx, object_trait.principal.def_id);
+        let trait_name = ty::item_path_str(tcx, object_trait.def_id);
         span_err!(tcx.sess, span, E0038,
             "cannot convert to a trait object because trait `{}` is not object-safe",
             trait_name);
diff --git a/src/test/compile-fail/issue-18959.rs b/src/test/compile-fail/issue-18959.rs
new file mode 100644
index 00000000000..3d126790335
--- /dev/null
+++ b/src/test/compile-fail/issue-18959.rs
@@ -0,0 +1,26 @@
+// 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.
+
+pub trait Foo for Sized? { fn foo<T>(&self, ext_thing: &T); }
+pub trait Bar for Sized?: Foo { }
+impl<T: Foo> Bar for T { }
+
+pub struct Thing;
+impl Foo for Thing {
+    fn foo<T>(&self, _: &T) {}
+}
+
+#[inline(never)] fn foo(b: &Bar) { b.foo(&0u) }
+
+fn main() {
+    let mut thing = Thing;
+    let test: &Bar = &mut thing; //~ ERROR cannot convert to a trait object because trait `Foo`
+    foo(test);
+}