Skip to content

Commit 558f8d8

Browse files
committed
auto merge of #19539 : cmr/rust/18959, r=nikomatsakis
Closes #18959 Technically, this causes code that once compiled to no longer compile, but that code probably never ran. [breaking-change] ------------ Not quite sure the error message is good enough, I feel like it ought to tell you "because it inherits from non-object-safe trait Foo", so I've opened up a follow-up issue #19538
2 parents a243e88 + 6e18b5a commit 558f8d8

File tree

3 files changed

+48
-8
lines changed

3 files changed

+48
-8
lines changed

src/librustc_typeck/check/mod.rs

+1-2
Original file line numberDiff line numberDiff line change
@@ -1747,8 +1747,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
17471747
self.register_unsize_obligations(span, &**u)
17481748
}
17491749
ty::UnsizeVtable(ref ty_trait, self_ty) => {
1750-
vtable::check_object_safety(self.tcx(), ty_trait, span);
1751-
1750+
vtable::check_object_safety(self.tcx(), &ty_trait.principal, span);
17521751
// If the type is `Foo+'a`, ensures that the type
17531752
// being cast to `Foo+'a` implements `Foo`:
17541753
vtable::register_object_cast_obligations(self,

src/librustc_typeck/check/vtable.rs

+21-6
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ pub fn check_object_cast<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
4545

4646
// Ensure that if ~T is cast to ~Trait, then T : Trait
4747
push_cast_obligation(fcx, cast_expr, object_trait, referent_ty);
48-
check_object_safety(fcx.tcx(), object_trait, source_expr.span);
48+
check_object_safety(fcx.tcx(), &object_trait.principal, source_expr.span);
4949
}
5050

5151
(&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>,
6969
target_region,
7070
referent_region);
7171

72-
check_object_safety(fcx.tcx(), object_trait, source_expr.span);
72+
check_object_safety(fcx.tcx(), &object_trait.principal, source_expr.span);
7373
}
7474
}
7575

@@ -133,17 +133,32 @@ pub fn check_object_cast<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
133133
// self by value, has no type parameters and does not use the `Self` type, except
134134
// in self position.
135135
pub fn check_object_safety<'tcx>(tcx: &ty::ctxt<'tcx>,
136-
object_trait: &ty::TyTrait<'tcx>,
136+
object_trait: &ty::TraitRef<'tcx>,
137+
span: Span) {
138+
139+
let mut object = object_trait.clone();
140+
if object.substs.types.len(SelfSpace) == 0 {
141+
object.substs.types.push(SelfSpace, ty::mk_err());
142+
}
143+
144+
let object = Rc::new(object);
145+
for tr in traits::supertraits(tcx, object) {
146+
check_object_safety_inner(tcx, &*tr, span);
147+
}
148+
}
149+
150+
fn check_object_safety_inner<'tcx>(tcx: &ty::ctxt<'tcx>,
151+
object_trait: &ty::TraitRef<'tcx>,
137152
span: Span) {
138153
// Skip the fn_once lang item trait since only the compiler should call
139154
// `call_once` which is the method which takes self by value. What could go
140155
// wrong?
141156
match tcx.lang_items.fn_once_trait() {
142-
Some(def_id) if def_id == object_trait.principal.def_id => return,
157+
Some(def_id) if def_id == object_trait.def_id => return,
143158
_ => {}
144159
}
145160

146-
let trait_items = ty::trait_items(tcx, object_trait.principal.def_id);
161+
let trait_items = ty::trait_items(tcx, object_trait.def_id);
147162

148163
let mut errors = Vec::new();
149164
for item in trait_items.iter() {
@@ -157,7 +172,7 @@ pub fn check_object_safety<'tcx>(tcx: &ty::ctxt<'tcx>,
157172

158173
let mut errors = errors.iter().flat_map(|x| x.iter()).peekable();
159174
if errors.peek().is_some() {
160-
let trait_name = ty::item_path_str(tcx, object_trait.principal.def_id);
175+
let trait_name = ty::item_path_str(tcx, object_trait.def_id);
161176
span_err!(tcx.sess, span, E0038,
162177
"cannot convert to a trait object because trait `{}` is not object-safe",
163178
trait_name);

src/test/compile-fail/issue-18959.rs

+26
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
pub trait Foo for Sized? { fn foo<T>(&self, ext_thing: &T); }
12+
pub trait Bar for Sized?: Foo { }
13+
impl<T: Foo> Bar for T { }
14+
15+
pub struct Thing;
16+
impl Foo for Thing {
17+
fn foo<T>(&self, _: &T) {}
18+
}
19+
20+
#[inline(never)] fn foo(b: &Bar) { b.foo(&0u) }
21+
22+
fn main() {
23+
let mut thing = Thing;
24+
let test: &Bar = &mut thing; //~ ERROR cannot convert to a trait object because trait `Foo`
25+
foo(test);
26+
}

0 commit comments

Comments
 (0)