Skip to content

Commit 56fafe2

Browse files
committed
auto merge of #15767 : pcwalton/rust/lifetime-elision, r=nick29581
This implements RFC 39. Omitted lifetimes in return values will now be inferred to more useful defaults, and an error is reported if a lifetime in a return type is omitted and one of the two lifetime elision rules does not specify what it should be. This primarily breaks two uncommon code patterns. The first is this: unsafe fn get_foo_out_of_thin_air() -> &Foo { ... } This should be changed to: unsafe fn get_foo_out_of_thin_air() -> &'static Foo { ... } The second pattern that needs to be changed is this: enum MaybeBorrowed<'a> { Borrowed(&'a str), Owned(String), } fn foo() -> MaybeBorrowed { Owned(format!("hello world")) } Change code like this to: enum MaybeBorrowed<'a> { Borrowed(&'a str), Owned(String), } fn foo() -> MaybeBorrowed<'static> { Owned(format!("hello world")) } Closes #15552. [breaking-change] r? @nick29581
2 parents 5e0a597 + 6f99a27 commit 56fafe2

File tree

71 files changed

+303
-168
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

71 files changed

+303
-168
lines changed

src/libcollections/dlist.rs

+5-3
Original file line numberDiff line numberDiff line change
@@ -87,12 +87,14 @@ impl<T> Rawlink<T> {
8787
}
8888

8989
/// Convert the `Rawlink` into an Option value
90-
fn resolve_immut(&self) -> Option<&T> {
91-
unsafe { self.p.to_option() }
90+
fn resolve_immut<'a>(&self) -> Option<&'a T> {
91+
unsafe {
92+
mem::transmute(self.p.to_option())
93+
}
9294
}
9395

9496
/// Convert the `Rawlink` into an Option value
95-
fn resolve(&mut self) -> Option<&mut T> {
97+
fn resolve<'a>(&mut self) -> Option<&'a mut T> {
9698
if self.p.is_null() {
9799
None
98100
} else {

src/libgraphviz/lib.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -455,12 +455,12 @@ impl<'a> LabelText<'a> {
455455
}
456456

457457
/// Puts `prefix` on a line above this label, with a blank line separator.
458-
pub fn prefix_line(self, prefix: LabelText) -> LabelText {
458+
pub fn prefix_line(self, prefix: LabelText) -> LabelText<'static> {
459459
prefix.suffix_line(self)
460460
}
461461

462462
/// Puts `suffix` on a line below this label, with a blank line separator.
463-
pub fn suffix_line(self, suffix: LabelText) -> LabelText {
463+
pub fn suffix_line(self, suffix: LabelText) -> LabelText<'static> {
464464
let prefix = self.pre_escaped_content().into_string();
465465
let suffix = suffix.pre_escaped_content();
466466
EscStr(str::Owned(prefix.append(r"\n\n").append(suffix.as_slice())))

src/libgraphviz/maybe_owned_vec.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ impl<'b,T> slice::Vector<T> for MaybeOwnedVector<'b,T> {
109109
}
110110

111111
impl<'a,T> FromIterator<T> for MaybeOwnedVector<'a,T> {
112-
fn from_iter<I:Iterator<T>>(iterator: I) -> MaybeOwnedVector<T> {
112+
fn from_iter<I:Iterator<T>>(iterator: I) -> MaybeOwnedVector<'a,T> {
113113
// If we are building from scratch, might as well build the
114114
// most flexible variant.
115115
Growable(FromIterator::from_iter(iterator))

src/libgreen/sched.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -959,13 +959,13 @@ impl CleanupJob {
959959
type UnsafeTaskReceiver = raw::Closure;
960960
trait ClosureConverter {
961961
fn from_fn(|&mut Scheduler, Box<GreenTask>|) -> Self;
962-
fn to_fn(self) -> |&mut Scheduler, Box<GreenTask>|;
962+
fn to_fn(self) -> |&mut Scheduler, Box<GreenTask>|:'static ;
963963
}
964964
impl ClosureConverter for UnsafeTaskReceiver {
965965
fn from_fn(f: |&mut Scheduler, Box<GreenTask>|) -> UnsafeTaskReceiver {
966966
unsafe { mem::transmute(f) }
967967
}
968-
fn to_fn(self) -> |&mut Scheduler, Box<GreenTask>| {
968+
fn to_fn(self) -> |&mut Scheduler, Box<GreenTask>|:'static {
969969
unsafe { mem::transmute(self) }
970970
}
971971
}

src/librustc/middle/trans/basic_block.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ impl BasicBlock {
3131
}
3232
}
3333

34-
pub fn pred_iter(self) -> Preds {
34+
pub fn pred_iter(self) -> Preds<'static> {
3535
self.as_value().user_iter()
3636
.filter(|user| user.is_a_terminator_inst())
3737
.map(|user| user.get_parent().unwrap())

src/librustc/middle/ty.rs

+52
Original file line numberDiff line numberDiff line change
@@ -4872,3 +4872,55 @@ pub enum ExplicitSelfCategory {
48724872
ByBoxExplicitSelfCategory,
48734873
}
48744874

4875+
/// Pushes all the lifetimes in the given type onto the given list. A
4876+
/// "lifetime in a type" is a lifetime specified by a reference or a lifetime
4877+
/// in a list of type substitutions. This does *not* traverse into nominal
4878+
/// types, nor does it resolve fictitious types.
4879+
pub fn accumulate_lifetimes_in_type(accumulator: &mut Vec<ty::Region>,
4880+
typ: t) {
4881+
walk_ty(typ, |typ| {
4882+
match get(typ).sty {
4883+
ty_rptr(region, _) => accumulator.push(region),
4884+
ty_enum(_, ref substs) |
4885+
ty_trait(box TyTrait {
4886+
substs: ref substs,
4887+
..
4888+
}) |
4889+
ty_struct(_, ref substs) => {
4890+
match substs.regions {
4891+
subst::ErasedRegions => {}
4892+
subst::NonerasedRegions(ref regions) => {
4893+
for region in regions.iter() {
4894+
accumulator.push(*region)
4895+
}
4896+
}
4897+
}
4898+
}
4899+
ty_closure(ref closure_ty) => {
4900+
match closure_ty.store {
4901+
RegionTraitStore(region, _) => accumulator.push(region),
4902+
UniqTraitStore => {}
4903+
}
4904+
}
4905+
ty_nil |
4906+
ty_bot |
4907+
ty_bool |
4908+
ty_char |
4909+
ty_int(_) |
4910+
ty_uint(_) |
4911+
ty_float(_) |
4912+
ty_box(_) |
4913+
ty_uniq(_) |
4914+
ty_str |
4915+
ty_vec(_, _) |
4916+
ty_ptr(_) |
4917+
ty_bare_fn(_) |
4918+
ty_tup(_) |
4919+
ty_param(_) |
4920+
ty_infer(_) |
4921+
ty_unboxed_closure(_) |
4922+
ty_err => {}
4923+
}
4924+
})
4925+
}
4926+

src/librustc/middle/typeck/astconv.rs

+72-22
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ use middle::lang_items::FnMutTraitLangItem;
5555
use middle::subst::{FnSpace, TypeSpace, SelfSpace, Subst, Substs};
5656
use middle::ty;
5757
use middle::ty_fold::TypeFolder;
58+
use middle::typeck::rscope::{ExplicitRscope, ImpliedSingleRscope};
5859
use middle::typeck::rscope::RegionScope;
5960
use middle::typeck::{TypeAndSubsts, infer, lookup_def_tcx, rscope};
6061
use middle::typeck;
@@ -931,31 +932,45 @@ fn ty_of_method_or_bare_fn<AC:AstConv>(
931932
Option<ty::ExplicitSelfCategory>) {
932933
debug!("ty_of_method_or_bare_fn");
933934

934-
// new region names that appear inside of the fn decl are bound to
935-
// that function type
935+
// New region names that appear inside of the arguments of the function
936+
// declaration are bound to that function type.
936937
let rb = rscope::BindingRscope::new(id);
937938

939+
// `implied_output_region` is the region that will be assumed for any
940+
// region parameters in the return type. In accordance with the rules for
941+
// lifetime elision, we can determine it in two ways. First (determined
942+
// here), if self is by-reference, then the implied output region is the
943+
// region of the self parameter.
938944
let mut explicit_self_category_result = None;
939-
let self_ty = opt_self_info.and_then(|self_info| {
940-
// Figure out and record the explicit self category.
941-
let explicit_self_category =
942-
determine_explicit_self_category(this, &rb, &self_info);
943-
explicit_self_category_result = Some(explicit_self_category);
944-
match explicit_self_category {
945-
ty::StaticExplicitSelfCategory => None,
946-
ty::ByValueExplicitSelfCategory => {
947-
Some(self_info.untransformed_self_ty)
948-
}
949-
ty::ByReferenceExplicitSelfCategory(region, mutability) => {
950-
Some(ty::mk_rptr(this.tcx(), region,
951-
ty::mt {ty: self_info.untransformed_self_ty,
952-
mutbl: mutability}))
953-
}
954-
ty::ByBoxExplicitSelfCategory => {
955-
Some(ty::mk_uniq(this.tcx(), self_info.untransformed_self_ty))
945+
let (self_ty, mut implied_output_region) = match opt_self_info {
946+
None => (None, None),
947+
Some(self_info) => {
948+
// Figure out and record the explicit self category.
949+
let explicit_self_category =
950+
determine_explicit_self_category(this, &rb, &self_info);
951+
explicit_self_category_result = Some(explicit_self_category);
952+
match explicit_self_category {
953+
ty::StaticExplicitSelfCategory => (None, None),
954+
ty::ByValueExplicitSelfCategory => {
955+
(Some(self_info.untransformed_self_ty), None)
956+
}
957+
ty::ByReferenceExplicitSelfCategory(region, mutability) => {
958+
(Some(ty::mk_rptr(this.tcx(),
959+
region,
960+
ty::mt {
961+
ty: self_info.untransformed_self_ty,
962+
mutbl: mutability
963+
})),
964+
Some(region))
965+
}
966+
ty::ByBoxExplicitSelfCategory => {
967+
(Some(ty::mk_uniq(this.tcx(),
968+
self_info.untransformed_self_ty)),
969+
None)
970+
}
956971
}
957972
}
958-
});
973+
};
959974

960975
// HACK(eddyb) replace the fake self type in the AST with the actual type.
961976
let input_tys = if self_ty.is_some() {
@@ -964,12 +979,47 @@ fn ty_of_method_or_bare_fn<AC:AstConv>(
964979
decl.inputs.as_slice()
965980
};
966981
let input_tys = input_tys.iter().map(|a| ty_of_arg(this, &rb, a, None));
982+
let self_and_input_tys: Vec<_> =
983+
self_ty.move_iter().chain(input_tys).collect();
984+
985+
// Second, if there was exactly one lifetime (either a substitution or a
986+
// reference) in the arguments, then any anonymous regions in the output
987+
// have that lifetime.
988+
if implied_output_region.is_none() {
989+
let mut self_and_input_tys_iter = self_and_input_tys.iter();
990+
if self_ty.is_some() {
991+
// Skip the first argument if `self` is present.
992+
drop(self_and_input_tys_iter.next())
993+
}
967994

968-
let self_and_input_tys = self_ty.move_iter().chain(input_tys).collect();
995+
let mut accumulator = Vec::new();
996+
for input_type in self_and_input_tys_iter {
997+
ty::accumulate_lifetimes_in_type(&mut accumulator, *input_type)
998+
}
999+
if accumulator.len() == 1 {
1000+
implied_output_region = Some(*accumulator.get(0));
1001+
}
1002+
}
9691003

9701004
let output_ty = match decl.output.node {
9711005
ast::TyInfer => this.ty_infer(decl.output.span),
972-
_ => ast_ty_to_ty(this, &rb, &*decl.output)
1006+
_ => {
1007+
match implied_output_region {
1008+
Some(implied_output_region) => {
1009+
let rb = ImpliedSingleRscope {
1010+
region: implied_output_region,
1011+
};
1012+
ast_ty_to_ty(this, &rb, &*decl.output)
1013+
}
1014+
None => {
1015+
// All regions must be explicitly specified in the output
1016+
// if the lifetime elision rules do not apply. This saves
1017+
// the user from potentially-confusing errors.
1018+
let rb = ExplicitRscope;
1019+
ast_ty_to_ty(this, &rb, &*decl.output)
1020+
}
1021+
}
1022+
}
9731023
};
9741024

9751025
(ty::BareFnTy {

src/librustc/middle/typeck/rscope.rs

+15-1
Original file line numberDiff line numberDiff line change
@@ -64,10 +64,24 @@ impl RegionScope for BindingRscope {
6464
fn anon_regions(&self,
6565
_: Span,
6666
count: uint)
67-
-> Result<Vec<ty::Region> , ()> {
67+
-> Result<Vec<ty::Region>, ()> {
6868
let idx = self.anon_bindings.get();
6969
self.anon_bindings.set(idx + count);
7070
Ok(Vec::from_fn(count, |i| ty::ReLateBound(self.binder_id,
7171
ty::BrAnon(idx + i))))
7272
}
7373
}
74+
75+
/// A scope in which we generate one specific region. This occurs after the
76+
/// `->` (i.e. in the return type) of function signatures.
77+
pub struct ImpliedSingleRscope {
78+
pub region: ty::Region,
79+
}
80+
81+
impl RegionScope for ImpliedSingleRscope {
82+
fn anon_regions(&self, _: Span, count: uint)
83+
-> Result<Vec<ty::Region>,()> {
84+
Ok(Vec::from_elem(count, self.region.clone()))
85+
}
86+
}
87+

src/librustrt/local_data.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ pub type Map = Vec<Option<(*const u8, TLSValue, uint)>>;
9494
type TLSValue = Box<LocalData + Send>;
9595

9696
// Gets the map from the runtime. Lazily initialises if not done so already.
97-
unsafe fn get_local_map() -> Option<&mut Map> {
97+
unsafe fn get_local_map<'a>() -> Option<&'a mut Map> {
9898
if !Local::exists(None::<Task>) { return None }
9999

100100
let task: *mut Task = Local::unsafe_borrow();

src/librustrt/rtio.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,7 @@ impl<'a> Drop for LocalIo<'a> {
134134
impl<'a> LocalIo<'a> {
135135
/// Returns the local I/O: either the local scheduler's I/O services or
136136
/// the native I/O services.
137-
pub fn borrow() -> Option<LocalIo> {
137+
pub fn borrow() -> Option<LocalIo<'a>> {
138138
// FIXME(#11053): bad
139139
//
140140
// This is currently very unsafely implemented. We don't actually

src/librustuv/file.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -469,7 +469,7 @@ mod test {
469469
use super::super::Loop;
470470
use super::super::local_loop;
471471

472-
fn l() -> &mut Loop { &mut local_loop().loop_ }
472+
fn l() -> &'static mut Loop { &mut local_loop().loop_ }
473473

474474
#[test]
475475
fn file_test_full_simple_sync() {

src/test/auxiliary/overloaded_autoderef_xc.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -15,17 +15,17 @@ struct DerefWithHelper<H, T> {
1515
}
1616

1717
trait Helper<T> {
18-
fn helper_borrow<'a>(&'a self) -> &'a T;
18+
fn helper_borrow(&self) -> &T;
1919
}
2020

2121
impl<T> Helper<T> for Option<T> {
22-
fn helper_borrow<'a>(&'a self) -> &'a T {
22+
fn helper_borrow(&self) -> &T {
2323
self.as_ref().unwrap()
2424
}
2525
}
2626

2727
impl<T, H: Helper<T>> Deref<T> for DerefWithHelper<H, T> {
28-
fn deref<'a>(&'a self) -> &'a T {
28+
fn deref(&self) -> &T {
2929
self.helper.helper_borrow()
3030
}
3131
}

src/test/bench/shootout-k-nucleotide.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -156,7 +156,7 @@ impl Table {
156156
}
157157
}
158158

159-
fn iter<'a>(&'a self) -> Items<'a> {
159+
fn iter(&self) -> Items {
160160
Items { cur: None, items: self.items.iter() }
161161
}
162162
}

src/test/compile-fail/borrowck-borrow-from-temporary.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313

1414
struct Foo(int);
1515

16-
fn foo() -> &int {
16+
fn foo<'a>() -> &'a int {
1717
let &Foo(ref x) = &Foo(3); //~ ERROR borrowed value does not live long enough
1818
x
1919
}

src/test/compile-fail/borrowck-borrow-mut-object-twice.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
// other `&mut` pointers.
1313

1414
trait Foo {
15-
fn f1<'a>(&'a mut self) -> &'a ();
15+
fn f1(&mut self) -> &();
1616
fn f2(&mut self);
1717
}
1818

0 commit comments

Comments
 (0)