Skip to content

Commit 8d8d8d4

Browse files
committed
Enforce object safety
closes #17670 [breaking-change] Traits must be object-safe if they are to be used in trait objects. This might require splitting a trait into object-safe and non-object-safe parts. Some standard library traits in std::io have been split - Reader has new traits BytesReader (for the bytes method) and AsRefReader (for by_ref), Writer has new trait AsRefWriter (for by_ref). All these new traits have blanket impls, so any type which implements Reader or Writer (respectively) will have an implmentation of the new traits. To fix your code, you just need to `use` the new trait.
1 parent 15dd90b commit 8d8d8d4

File tree

3 files changed

+69
-76
lines changed

3 files changed

+69
-76
lines changed

src/librustc/middle/typeck/check/method.rs

Lines changed: 0 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -1336,16 +1336,6 @@ impl<'a, 'tcx> LookupContext<'a, 'tcx> {
13361336
self.ty_to_string(rcvr_ty),
13371337
candidate.repr(self.tcx()));
13381338

1339-
let mut rcvr_substs = candidate.rcvr_substs.clone();
1340-
1341-
if !self.enforce_object_limitations(candidate) {
1342-
// Here we change `Self` from `Trait` to `err` in the case that
1343-
// this is an illegal object method. This is necessary to prevent
1344-
// the user from getting strange, derivative errors when the method
1345-
// takes an argument/return-type of type `Self` etc.
1346-
rcvr_substs.types.get_mut_slice(SelfSpace)[0] = ty::mk_err();
1347-
}
1348-
13491339
self.enforce_drop_trait_limitations(candidate);
13501340

13511341
// Determine the values for the generic parameters of the method.
@@ -1554,71 +1544,6 @@ impl<'a, 'tcx> LookupContext<'a, 'tcx> {
15541544
}
15551545
}
15561546

1557-
fn enforce_object_limitations(&self, candidate: &Candidate) -> bool {
1558-
/*!
1559-
* There are some limitations to calling functions through an
1560-
* object, because (a) the self type is not known
1561-
* (that's the whole point of a trait instance, after all, to
1562-
* obscure the self type) and (b) the call must go through a
1563-
* vtable and hence cannot be monomorphized.
1564-
*/
1565-
1566-
match candidate.origin {
1567-
MethodStatic(..) |
1568-
MethodTypeParam(..) |
1569-
MethodStaticUnboxedClosure(..) => {
1570-
return true; // not a call to a trait instance
1571-
}
1572-
MethodTraitObject(..) => {}
1573-
}
1574-
1575-
match candidate.method_ty.explicit_self {
1576-
ty::StaticExplicitSelfCategory => { // reason (a) above
1577-
self.tcx().sess.span_err(
1578-
self.span,
1579-
"cannot call a method without a receiver \
1580-
through an object");
1581-
return false;
1582-
}
1583-
1584-
ty::ByValueExplicitSelfCategory |
1585-
ty::ByReferenceExplicitSelfCategory(..) |
1586-
ty::ByBoxExplicitSelfCategory => {}
1587-
}
1588-
1589-
// reason (a) above
1590-
let check_for_self_ty = |ty| -> bool {
1591-
if ty::type_has_self(ty) {
1592-
span_err!(self.tcx().sess, self.span, E0038,
1593-
"cannot call a method whose type contains a \
1594-
self-type through an object");
1595-
false
1596-
} else {
1597-
true
1598-
}
1599-
};
1600-
let ref sig = candidate.method_ty.fty.sig;
1601-
for &input_ty in sig.inputs[1..].iter() {
1602-
if !check_for_self_ty(input_ty) {
1603-
return false;
1604-
}
1605-
}
1606-
if let ty::FnConverging(result_type) = sig.output {
1607-
if !check_for_self_ty(result_type) {
1608-
return false;
1609-
}
1610-
}
1611-
1612-
if candidate.method_ty.generics.has_type_params(subst::FnSpace) {
1613-
// reason (b) above
1614-
span_err!(self.tcx().sess, self.span, E0039,
1615-
"cannot call a generic method through an object");
1616-
return false;
1617-
}
1618-
1619-
true
1620-
}
1621-
16221547
fn enforce_drop_trait_limitations(&self, candidate: &Candidate) {
16231548
// No code can call the finalize method explicitly.
16241549
let bad = match candidate.origin {

src/librustc/middle/typeck/check/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1687,6 +1687,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
16871687
self.register_unsize_obligations(span, &**u)
16881688
}
16891689
ty::UnsizeVtable(ref ty_trait, self_ty) => {
1690+
vtable2::check_object_safety(self.tcx(), ty_trait, span);
16901691
// If the type is `Foo+'a`, ensures that the type
16911692
// being cast to `Foo+'a` implements `Foo`:
16921693
vtable::register_object_cast_obligations(self,

src/librustc/middle/typeck/check/vtable.rs

Lines changed: 68 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11-
use middle::subst::{SelfSpace};
11+
use middle::subst::{SelfSpace, FnSpace};
1212
use middle::traits;
1313
use middle::traits::{SelectionError, OutputTypeParameterMismatch, Overflow, Unimplemented};
1414
use middle::traits::{Obligation, obligation_for_builtin_bound};
@@ -46,6 +46,7 @@ pub fn check_object_cast(fcx: &FnCtxt,
4646

4747
// Ensure that if ~T is cast to ~Trait, then T : Trait
4848
push_cast_obligation(fcx, cast_expr, object_trait, referent_ty);
49+
check_object_safety(fcx.tcx(), object_trait, source_expr.span);
4950
}
5051

5152
(&ty::ty_rptr(referent_region, ty::mt { ty: referent_ty,
@@ -68,6 +69,8 @@ pub fn check_object_cast(fcx: &FnCtxt,
6869
infer::RelateObjectBound(source_expr.span),
6970
target_region,
7071
referent_region);
72+
73+
check_object_safety(fcx.tcx(), object_trait, source_expr.span);
7174
}
7275
}
7376

@@ -128,6 +131,70 @@ pub fn check_object_cast(fcx: &FnCtxt,
128131
}
129132
}
130133

134+
// TODO comment
135+
pub fn check_object_safety(tcx: &ty::ctxt, object_trait: &ty::TyTrait, span: Span) {
136+
let trait_items = ty::trait_items(tcx, object_trait.def_id);
137+
for item in trait_items.iter() {
138+
match *item {
139+
ty::MethodTraitItem(ref m) => check_object_safety_of_method(tcx, &**m, span),
140+
ty::TypeTraitItem(_) => {}
141+
}
142+
}
143+
144+
// TODO error messages
145+
fn check_object_safety_of_method(tcx: &ty::ctxt, method: &ty::Method, span: Span) {
146+
/*!
147+
* There are some limitations to calling functions through an
148+
* object, because (a) the self type is not known
149+
* (that's the whole point of a trait instance, after all, to
150+
* obscure the self type) and (b) the call must go through a
151+
* vtable and hence cannot be monomorphized.
152+
*/
153+
154+
match method.explicit_self {
155+
ty::ByValueExplicitSelfCategory => { // reason (a) above
156+
tcx.sess.span_err(
157+
span,
158+
"cannot call a method with a by-value receiver \
159+
through a trait object");
160+
}
161+
162+
ty::StaticExplicitSelfCategory |
163+
ty::ByReferenceExplicitSelfCategory(..) |
164+
ty::ByBoxExplicitSelfCategory => {}
165+
}
166+
167+
// reason (a) above
168+
let check_for_self_ty = |ty| {
169+
if ty::type_has_self(ty) {
170+
span_err!(tcx.sess, span, E0038,
171+
"cannot call a method whose type contains a \
172+
self-type through an object: {}", ::util::ppaux::ty_to_string(tcx, ty));
173+
true
174+
} else {
175+
false
176+
}
177+
};
178+
let ref sig = method.fty.sig;
179+
let mut found_self_ty = false;
180+
for &input_ty in sig.inputs.tail().iter() {
181+
if check_for_self_ty(input_ty) {
182+
found_self_ty = true;
183+
break;
184+
}
185+
}
186+
if !found_self_ty {
187+
check_for_self_ty(sig.output);
188+
}
189+
190+
if method.generics.has_type_params(FnSpace) {
191+
// reason (b) above
192+
span_err!(tcx.sess, span, E0039,
193+
"cannot call a generic method through an object");
194+
}
195+
}
196+
}
197+
131198
pub fn register_object_cast_obligations(fcx: &FnCtxt,
132199
span: Span,
133200
object_trait: &ty::TyTrait,

0 commit comments

Comments
 (0)