Skip to content

Commit a4d0929

Browse files
committed
Enforce object safety
closes rust-lang#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 e05c3b7 commit a4d0929

File tree

3 files changed

+69
-74
lines changed

3 files changed

+69
-74
lines changed

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

-73
Original file line numberDiff line numberDiff line change
@@ -1316,16 +1316,6 @@ impl<'a, 'tcx> LookupContext<'a, 'tcx> {
13161316
self.ty_to_string(rcvr_ty),
13171317
candidate.repr(self.tcx()));
13181318

1319-
let mut rcvr_substs = candidate.rcvr_substs.clone();
1320-
1321-
if !self.enforce_object_limitations(candidate) {
1322-
// Here we change `Self` from `Trait` to `err` in the case that
1323-
// this is an illegal object method. This is necessary to prevent
1324-
// the user from getting strange, derivative errors when the method
1325-
// takes an argument/return-type of type `Self` etc.
1326-
rcvr_substs.types.get_mut_slice(SelfSpace)[0] = ty::mk_err();
1327-
}
1328-
13291319
self.enforce_drop_trait_limitations(candidate);
13301320

13311321
// Determine the values for the generic parameters of the method.
@@ -1534,69 +1524,6 @@ impl<'a, 'tcx> LookupContext<'a, 'tcx> {
15341524
}
15351525
}
15361526

1537-
fn enforce_object_limitations(&self, candidate: &Candidate) -> bool {
1538-
/*!
1539-
* There are some limitations to calling functions through an
1540-
* object, because (a) the self type is not known
1541-
* (that's the whole point of a trait instance, after all, to
1542-
* obscure the self type) and (b) the call must go through a
1543-
* vtable and hence cannot be monomorphized.
1544-
*/
1545-
1546-
match candidate.origin {
1547-
MethodStatic(..) |
1548-
MethodTypeParam(..) |
1549-
MethodStaticUnboxedClosure(..) => {
1550-
return true; // not a call to a trait instance
1551-
}
1552-
MethodTraitObject(..) => {}
1553-
}
1554-
1555-
match candidate.method_ty.explicit_self {
1556-
ty::StaticExplicitSelfCategory => { // reason (a) above
1557-
self.tcx().sess.span_err(
1558-
self.span,
1559-
"cannot call a method without a receiver \
1560-
through an object");
1561-
return false;
1562-
}
1563-
1564-
ty::ByValueExplicitSelfCategory |
1565-
ty::ByReferenceExplicitSelfCategory(..) |
1566-
ty::ByBoxExplicitSelfCategory => {}
1567-
}
1568-
1569-
// reason (a) above
1570-
let check_for_self_ty = |ty| -> bool {
1571-
if ty::type_has_self(ty) {
1572-
span_err!(self.tcx().sess, self.span, E0038,
1573-
"cannot call a method whose type contains a \
1574-
self-type through an object");
1575-
false
1576-
} else {
1577-
true
1578-
}
1579-
};
1580-
let ref sig = candidate.method_ty.fty.sig;
1581-
for &input_ty in sig.inputs[1..].iter() {
1582-
if !check_for_self_ty(input_ty) {
1583-
return false;
1584-
}
1585-
}
1586-
if !check_for_self_ty(sig.output) {
1587-
return false;
1588-
}
1589-
1590-
if candidate.method_ty.generics.has_type_params(subst::FnSpace) {
1591-
// reason (b) above
1592-
span_err!(self.tcx().sess, self.span, E0039,
1593-
"cannot call a generic method through an object");
1594-
return false;
1595-
}
1596-
1597-
true
1598-
}
1599-
16001527
fn enforce_drop_trait_limitations(&self, candidate: &Candidate) {
16011528
// No code can call the finalize method explicitly.
16021529
let bad = match candidate.origin {

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

+1
Original file line numberDiff line numberDiff line change
@@ -1675,6 +1675,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
16751675
self.register_unsize_obligations(span, &**u)
16761676
}
16771677
ty::UnsizeVtable(ref ty_trait, self_ty) => {
1678+
vtable2::check_object_safety(self.tcx(), ty_trait, span);
16781679
// If the type is `Foo+'a`, ensures that the type
16791680
// being cast to `Foo+'a` implements `Foo`:
16801681
vtable2::register_object_cast_obligations(self,

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

+68-1
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)