Skip to content

Commit 8f5d225

Browse files
committed
Extend object safety so that methods with Sized:Self are exempt.
1 parent f0f7ca2 commit 8f5d225

8 files changed

+201
-12
lines changed

src/librustc/middle/traits/object_safety.rs

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -157,19 +157,25 @@ fn supertraits_reference_self<'tcx>(tcx: &ty::ctxt<'tcx>,
157157
fn trait_has_sized_self<'tcx>(tcx: &ty::ctxt<'tcx>,
158158
trait_def_id: ast::DefId)
159159
-> bool
160+
{
161+
let trait_def = ty::lookup_trait_def(tcx, trait_def_id);
162+
let trait_predicates = ty::lookup_predicates(tcx, trait_def_id);
163+
generics_require_sized_self(tcx, &trait_def.generics, &trait_predicates)
164+
}
165+
166+
fn generics_require_sized_self<'tcx>(tcx: &ty::ctxt<'tcx>,
167+
generics: &ty::Generics<'tcx>,
168+
predicates: &ty::GenericPredicates<'tcx>)
169+
-> bool
160170
{
161171
let sized_def_id = match tcx.lang_items.sized_trait() {
162172
Some(def_id) => def_id,
163173
None => { return false; /* No Sized trait, can't require it! */ }
164174
};
165175

166176
// Search for a predicate like `Self : Sized` amongst the trait bounds.
167-
let trait_def = ty::lookup_trait_def(tcx, trait_def_id);
168-
let free_substs = ty::construct_free_substs(tcx, &trait_def.generics, ast::DUMMY_NODE_ID);
169-
170-
let trait_predicates = ty::lookup_predicates(tcx, trait_def_id);
171-
let predicates = trait_predicates.instantiate(tcx, &free_substs).predicates.into_vec();
172-
177+
let free_substs = ty::construct_free_substs(tcx, generics, ast::DUMMY_NODE_ID);
178+
let predicates = predicates.instantiate(tcx, &free_substs).predicates.into_vec();
173179
elaborate_predicates(tcx, predicates)
174180
.any(|predicate| {
175181
match predicate {
@@ -192,6 +198,12 @@ fn object_safety_violations_for_method<'tcx>(tcx: &ty::ctxt<'tcx>,
192198
method: &ty::Method<'tcx>)
193199
-> Option<MethodViolationCode>
194200
{
201+
// Any method that has a `Self : Sized` requisite is otherwise
202+
// exempt from the regulations.
203+
if generics_require_sized_self(tcx, &method.generics, &method.predicates) {
204+
return None;
205+
}
206+
195207
// The method's first parameter must be something that derefs to
196208
// `&self`. For now, we only accept `&self` and `Box<Self>`.
197209
match method.explicit_self {

src/librustc_trans/trans/meth.rs

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -815,9 +815,6 @@ fn emit_vtable_methods<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
815815
param_substs,
816816
substs.clone()).val;
817817

818-
// currently, at least, by-value self is not object safe
819-
assert!(m.explicit_self != ty::ByValueExplicitSelfCategory);
820-
821818
Some(fn_ref).into_iter()
822819
}
823820
}

src/test/compile-fail/object-safety-by-value-self.rs

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@
99
// except according to those terms.
1010

1111
// Check that we correctly prevent users from making trait objects
12-
// from traits with a `fn(self)` method.
12+
// from traits with a `fn(self)` method, unless `where Self : Sized`
13+
// is present on the method.
1314

1415
trait Bar {
1516
fn bar(self);
@@ -19,6 +20,11 @@ trait Baz {
1920
fn baz(self: Self);
2021
}
2122

23+
trait Quux {
24+
// Legal because of the where clause:
25+
fn baz(self: Self) where Self : Sized;
26+
}
27+
2228
fn make_bar<T:Bar>(t: &T) -> &Bar {
2329
t
2430
//~^ ERROR `Bar` is not object-safe
@@ -43,5 +49,13 @@ fn make_baz_explicit<T:Baz>(t: &T) -> &Baz {
4349
//~| NOTE method `baz` has a receiver type of `Self`
4450
}
4551

52+
fn make_quux<T:Quux>(t: &T) -> &Quux {
53+
t
54+
}
55+
56+
fn make_quux_explicit<T:Quux>(t: &T) -> &Quux {
57+
t as &Quux
58+
}
59+
4660
fn main() {
4761
}

src/test/compile-fail/object-safety-generics.rs

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,18 @@
99
// except according to those terms.
1010

1111
// Check that we correctly prevent users from making trait objects
12-
// from traits with generic methods.
12+
// from traits with generic methods, unless `where Self : Sized` is
13+
// present.
1314

1415
trait Bar {
1516
fn bar<T>(&self, t: T);
1617
}
1718

19+
trait Quux {
20+
fn bar<T>(&self, t: T)
21+
where Self : Sized;
22+
}
23+
1824
fn make_bar<T:Bar>(t: &T) -> &Bar {
1925
t
2026
//~^ ERROR `Bar` is not object-safe
@@ -27,5 +33,13 @@ fn make_bar_explicit<T:Bar>(t: &T) -> &Bar {
2733
//~| NOTE method `bar` has generic type parameters
2834
}
2935

36+
fn make_quux<T:Quux>(t: &T) -> &Quux {
37+
t
38+
}
39+
40+
fn make_quux_explicit<T:Quux>(t: &T) -> &Quux {
41+
t as &Quux
42+
}
43+
3044
fn main() {
3145
}

src/test/compile-fail/object-safety-mentions-Self.rs

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@
99
// except according to those terms.
1010

1111
// Check that we correctly prevent users from making trait objects
12-
// form traits that make use of `Self` in an argument or return position.
12+
// form traits that make use of `Self` in an argument or return
13+
// position, unless `where Self : Sized` is present..
1314

1415
trait Bar {
1516
fn bar(&self, x: &Self);
@@ -19,6 +20,10 @@ trait Baz {
1920
fn bar(&self) -> Self;
2021
}
2122

23+
trait Quux {
24+
fn get(&self, s: &Self) -> Self where Self : Sized;
25+
}
26+
2227
fn make_bar<T:Bar>(t: &T) -> &Bar {
2328
t
2429
//~^ ERROR `Bar` is not object-safe
@@ -43,5 +48,13 @@ fn make_baz_explicit<T:Baz>(t: &T) -> &Baz {
4348
//~| NOTE method `bar` references the `Self` type in its arguments or return type
4449
}
4550

51+
fn make_quux<T:Quux>(t: &T) -> &Quux {
52+
t
53+
}
54+
55+
fn make_quux_explicit<T:Quux>(t: &T) -> &Quux {
56+
t as &Quux
57+
}
58+
4659
fn main() {
4760
}
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
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+
// Check that a trait is still object-safe (and usable) if it has
12+
// methods with by-value self so long as they require `Self : Sized`.
13+
14+
trait Counter {
15+
fn tick(&mut self) -> u32;
16+
fn get(self) -> u32 where Self : Sized;
17+
}
18+
19+
struct CCounter {
20+
c: u32
21+
}
22+
23+
impl Counter for CCounter {
24+
fn tick(&mut self) -> u32 { self.c += 1; self.c }
25+
fn get(self) -> u32 where Self : Sized { self.c }
26+
}
27+
28+
fn tick1<C:Counter>(mut c: C) -> u32 {
29+
tick2(&mut c);
30+
c.get()
31+
}
32+
33+
fn tick2(c: &mut Counter) {
34+
tick3(c);
35+
}
36+
37+
fn tick3<C:?Sized+Counter>(c: &mut C) {
38+
c.tick();
39+
c.tick();
40+
}
41+
42+
fn main() {
43+
let mut c = CCounter { c: 0 };
44+
let value = tick1(c);
45+
assert_eq!(value, 2);
46+
}
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
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+
// Check that a trait is still object-safe (and usable) if it has
12+
// generic methods so long as they require `Self : Sized`.
13+
14+
trait Counter {
15+
fn tick(&mut self) -> u32;
16+
fn with<F:FnOnce(u32)>(&self, f: F) where Self : Sized;
17+
}
18+
19+
struct CCounter {
20+
c: u32
21+
}
22+
23+
impl Counter for CCounter {
24+
fn tick(&mut self) -> u32 { self.c += 1; self.c }
25+
fn with<F:FnOnce(u32)>(&self, f: F) { f(self.c); }
26+
}
27+
28+
fn tick1<C:Counter>(c: &mut C) {
29+
tick2(c);
30+
c.with(|i| ());
31+
}
32+
33+
fn tick2(c: &mut Counter) {
34+
tick3(c);
35+
}
36+
37+
fn tick3<C:?Sized+Counter>(c: &mut C) {
38+
c.tick();
39+
c.tick();
40+
}
41+
42+
fn main() {
43+
let mut c = CCounter { c: 0 };
44+
tick1(&mut c);
45+
assert_eq!(c.tick(), 3);
46+
}
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
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+
// Check that a trait is still object-safe (and usable) if it has
12+
// methods that return `Self` so long as they require `Self : Sized`.
13+
14+
trait Counter {
15+
fn new() -> Self where Self : Sized;
16+
fn tick(&mut self) -> u32;
17+
}
18+
19+
struct CCounter {
20+
c: u32
21+
}
22+
23+
impl Counter for CCounter {
24+
fn new() -> CCounter { CCounter { c: 0 } }
25+
fn tick(&mut self) -> u32 { self.c += 1; self.c }
26+
}
27+
28+
fn preticked<C:Counter>() -> C {
29+
let mut c: C = Counter::new();
30+
tick(&mut c);
31+
c
32+
}
33+
34+
fn tick(c: &mut Counter) {
35+
tick_generic(c);
36+
}
37+
38+
fn tick_generic<C:?Sized+Counter>(c: &mut C) {
39+
c.tick();
40+
c.tick();
41+
}
42+
43+
fn main() {
44+
let mut c = preticked::<CCounter>();
45+
tick(&mut c);
46+
assert_eq!(c.tick(), 5);
47+
}

0 commit comments

Comments
 (0)