From 0cea2b7c3c32ea5028227f85431f8af7636ef558 Mon Sep 17 00:00:00 2001 From: Tshepang Lekhonkhobe Date: Sun, 22 Feb 2015 20:43:45 +0200 Subject: [PATCH 01/10] doc: nits and fixes for thread API --- src/libstd/thread.rs | 34 ++++++++++++++++------------------ 1 file changed, 16 insertions(+), 18 deletions(-) diff --git a/src/libstd/thread.rs b/src/libstd/thread.rs index 1f70e1526a0..fb7386f18e7 100644 --- a/src/libstd/thread.rs +++ b/src/libstd/thread.rs @@ -28,25 +28,25 @@ //! a thread will unwind the stack, running destructors and freeing //! owned resources. Thread panic is unrecoverable from within //! the panicking thread (i.e. there is no 'try/catch' in Rust), but -//! panic may optionally be detected from a different thread. If -//! the main thread panics the application will exit with a non-zero +//! the panic may optionally be detected from a different thread. If +//! the main thread panics, the application will exit with a non-zero //! exit code. //! //! When the main thread of a Rust program terminates, the entire program shuts //! down, even if other threads are still running. However, this module provides //! convenient facilities for automatically waiting for the termination of a -//! child thread (i.e., join), described below. +//! child thread (i.e., join). //! //! ## The `Thread` type //! -//! Already-running threads are represented via the `Thread` type, which you can +//! Threads are represented via the `Thread` type, which you can //! get in one of two ways: //! -//! * By spawning a new thread, e.g. using the `thread::spawn` constructor; +//! * By spawning a new thread, e.g. using the `thread::spawn` function. //! * By requesting the current thread, using the `thread::current` function. //! //! Threads can be named, and provide some built-in support for low-level -//! synchronization described below. +//! synchronization (described below). //! //! The `thread::current()` function is available even for threads not spawned //! by the APIs of this module. @@ -59,29 +59,27 @@ //! use std::thread; //! //! thread::spawn(move || { -//! println!("Hello, World!"); -//! // some computation here +//! // some work here //! }); //! ``` //! //! In this example, the spawned thread is "detached" from the current -//! thread, meaning that it can outlive the thread that spawned -//! it. (Note, however, that when the main thread terminates all -//! detached threads are terminated as well.) +//! thread. This means that it can outlive its parent (the thread that spawned +//! it), unless this parent is the main thread. //! //! ## Scoped threads //! //! Often a parent thread uses a child thread to perform some particular task, //! and at some point must wait for the child to complete before continuing. -//! For this scenario, use the `scoped` constructor: +//! For this scenario, use the `thread::scoped` function: //! //! ```rust //! use std::thread; //! //! let guard = thread::scoped(move || { -//! println!("Hello, World!"); -//! // some computation here +//! // some work here //! }); +//! //! // do some other work in the meantime //! let output = guard.join(); //! ``` @@ -92,7 +90,7 @@ //! terminates) when it is dropped. You can join the child thread in //! advance by calling the `join` method on the guard, which will also //! return the result produced by the thread. A handle to the thread -//! itself is available via the `thread` method on the join guard. +//! itself is available via the `thread` method of the join guard. //! //! (Note: eventually, the `scoped` constructor will allow the parent and child //! threads to data that lives on the parent thread's stack, but some language @@ -108,7 +106,7 @@ //! use std::thread; //! //! thread::Builder::new().name("child1".to_string()).spawn(move || { -//! println!("Hello, world!") +//! println!("Hello, world!"); //! }); //! ``` //! @@ -121,7 +119,7 @@ //! initially not present: //! //! * The `thread::park()` function blocks the current thread unless or until -//! the token is available for its thread handle, at which point It atomically +//! the token is available for its thread handle, at which point it atomically //! consumes the token. It may also return *spuriously*, without consuming the //! token. `thread::park_timeout()` does the same, but allows specifying a //! maximum time to block the thread for. @@ -143,7 +141,7 @@ //! * It avoids the need to allocate mutexes and condvars when building new //! synchronization primitives; the threads already provide basic blocking/signaling. //! -//! * It can be implemented highly efficiently on many platforms. +//! * It can be implemented very efficiently on many platforms. #![stable(feature = "rust1", since = "1.0.0")] From fa4cb49b0475232d7e7eed2b77cdd017b762db8c Mon Sep 17 00:00:00 2001 From: Tshepang Lekhonkhobe Date: Mon, 23 Feb 2015 01:56:52 +0200 Subject: [PATCH 02/10] doc: I learnt from review that this is now implemented --- src/libstd/thread.rs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/libstd/thread.rs b/src/libstd/thread.rs index fb7386f18e7..ce1ba3a4364 100644 --- a/src/libstd/thread.rs +++ b/src/libstd/thread.rs @@ -92,10 +92,6 @@ //! return the result produced by the thread. A handle to the thread //! itself is available via the `thread` method of the join guard. //! -//! (Note: eventually, the `scoped` constructor will allow the parent and child -//! threads to data that lives on the parent thread's stack, but some language -//! changes are needed before this is possible.) -//! //! ## Configuring threads //! //! A new thread can be configured before it is spawned via the `Builder` type, From d084f7031c5a6b862fecd4d43466eef66c1e5748 Mon Sep 17 00:00:00 2001 From: Alexander Campbell Date: Sat, 28 Feb 2015 11:32:13 -0600 Subject: [PATCH 03/10] Change slithtly -> slightly in README.md --- src/doc/intro.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/doc/intro.md b/src/doc/intro.md index 07a90959deb..1e1aa1e22b4 100644 --- a/src/doc/intro.md +++ b/src/doc/intro.md @@ -510,10 +510,10 @@ numbers[1] is 3 numbers[0] is 2 ``` -Each time, we can get a slithtly different output because the threads -are not quaranteed to run in any set order. If you get the same order -every time it is because each of these threads are very small and -complete too fast for their indeterminate behavior to surface. +Each time, we can get a slightly different output because the threads are not +quaranteed to run in any set order. If you get the same order every time it is +because each of these threads are very small and complete too fast for their +indeterminate behavior to surface. The important part here is that the Rust compiler was able to use ownership to give us assurance _at compile time_ that we weren't doing something incorrect From fdc45e361c0846770e7057c5c54b0ee1c82f8f5e Mon Sep 17 00:00:00 2001 From: Alexander Campbell Date: Sat, 28 Feb 2015 11:33:48 -0600 Subject: [PATCH 04/10] Change quaranteed -> guaranteed in README.md --- src/doc/intro.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/intro.md b/src/doc/intro.md index 1e1aa1e22b4..d145eaada2b 100644 --- a/src/doc/intro.md +++ b/src/doc/intro.md @@ -511,7 +511,7 @@ numbers[0] is 2 ``` Each time, we can get a slightly different output because the threads are not -quaranteed to run in any set order. If you get the same order every time it is +guaranteed to run in any set order. If you get the same order every time it is because each of these threads are very small and complete too fast for their indeterminate behavior to surface. From a457dd5c7811391223f58ca1a31e48c450200723 Mon Sep 17 00:00:00 2001 From: David Mally Date: Sat, 28 Feb 2015 17:40:04 -0500 Subject: [PATCH 05/10] Changed wording to use Result instead of Option in several places, fixed example that actually does use an Option --- src/doc/trpl/guessing-game.md | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/doc/trpl/guessing-game.md b/src/doc/trpl/guessing-game.md index a40374fe30f..4e7222269a8 100644 --- a/src/doc/trpl/guessing-game.md +++ b/src/doc/trpl/guessing-game.md @@ -422,11 +422,11 @@ In this case, we say `x` is a `u32` explicitly, so Rust is able to properly tell `random()` what to generate. In a similar fashion, both of these work: ```{rust,ignore} -let input_num = "5".parse::(); // input_num: Option -let input_num: Result = "5".parse(); // input_num: Result::Err> +let input_num_option = "5".parse::().ok(); // input_num: Option +let input_num_result: Result = "5".parse(); // input_num: Result::Err> ``` -Here we're converting the `Result` returned by `parse` to an `Option` by using +Above, we're converting the `Result` returned by `parse` to an `Option` by using the `ok` method as well. Anyway, with us now converting our input to a number, our code looks like this: @@ -470,14 +470,14 @@ Let's try it out! ```bash $ cargo build Compiling guessing_game v0.0.1 (file:///home/you/projects/guessing_game) -src/main.rs:22:15: 22:24 error: mismatched types: expected `u32` but found `core::option::Option` (expected u32 but found enum core::option::Option) -src/main.rs:22 match cmp(input_num, secret_number) { +src/main.rs:21:15: 21:24 error: mismatched types: expected `u32`, found `core::result::Result` (expected u32, found enum `core::result::Result`) [E0308] +src/main.rs:21 match cmp(input_num, secret_number) { ^~~~~~~~~ error: aborting due to previous error ``` -Oh yeah! Our `input_num` has the type `Option`, rather than `u32`. We -need to unwrap the Option. If you remember from before, `match` is a great way +Oh yeah! Our `input_num` has the type `Result>`, rather than `u32`. We +need to unwrap the Result. If you remember from before, `match` is a great way to do that. Try this code: ```{rust,no_run} @@ -500,7 +500,7 @@ fn main() { let input_num: Result = input.parse(); let num = match input_num { - Ok(num) => num, + Ok(n) => n, Err(_) => { println!("Please input a number!"); return; @@ -524,7 +524,7 @@ fn cmp(a: u32, b: u32) -> Ordering { } ``` -We use a `match` to either give us the `u32` inside of the `Option`, or else +We use a `match` to either give us the `u32` inside of the `Result`, or else print an error message and return. Let's give this a shot: ```bash From c04c9632f6239c223485e3c2c5a580f0d2f909e7 Mon Sep 17 00:00:00 2001 From: Leonids Maslovs Date: Sun, 1 Mar 2015 14:11:12 +0200 Subject: [PATCH 06/10] Addresses rust-lang/rust#22646 Removes deprecated `{:08d}` format from the module documentation. `{:08}` should be used instead now. --- src/libcollections/fmt.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libcollections/fmt.rs b/src/libcollections/fmt.rs index 98673af3c68..5a20ba4b49f 100644 --- a/src/libcollections/fmt.rs +++ b/src/libcollections/fmt.rs @@ -364,7 +364,7 @@ //! * `o` - precedes the argument with a "0o" //! * '0' - This is used to indicate for integer formats that the padding should //! both be done with a `0` character as well as be sign-aware. A format -//! like `{:08d}` would yield `00000001` for the integer `1`, while the +//! like `{:08}` would yield `00000001` for the integer `1`, while the //! same format would yield `-0000001` for the integer `-1`. Notice that //! the negative version has one fewer zero than the positive version. //! From 00fcf794488e5e1a4761342dac7d2bcdfb66152f Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Sat, 28 Feb 2015 19:34:16 -0500 Subject: [PATCH 07/10] Remove the synthetic "region bound" from closures and instead update how type-outlives works for closure types so that it ensures that all upvars outlive the region in question. This gives the same guarantees but without introducing artificial regions (and gives better error messages to boot). --- src/librustc/metadata/tydecode.rs | 4 +- src/librustc/metadata/tyencode.rs | 3 +- src/librustc/middle/fast_reject.rs | 2 +- src/librustc/middle/infer/combine.rs | 7 +- src/librustc/middle/liveness.rs | 2 +- src/librustc/middle/mem_categorization.rs | 2 +- src/librustc/middle/region.rs | 2 + src/librustc/middle/traits/project.rs | 2 +- src/librustc/middle/traits/select.rs | 8 +- src/librustc/middle/ty.rs | 24 +-- src/librustc/middle/ty_fold.rs | 5 +- src/librustc/middle/ty_walk.rs | 2 +- src/librustc/util/ppaux.rs | 2 +- src/librustc_trans/trans/adt.rs | 2 +- src/librustc_trans/trans/base.rs | 8 +- src/librustc_trans/trans/closure.rs | 2 +- src/librustc_trans/trans/debuginfo.rs | 4 +- src/librustc_typeck/check/callee.rs | 2 +- src/librustc_typeck/check/closure.rs | 10 - src/librustc_typeck/check/implicator.rs | 34 ++-- src/librustc_typeck/check/method/probe.rs | 6 +- src/librustc_typeck/check/regionck.rs | 171 ++++-------------- src/librustc_typeck/coherence/mod.rs | 2 +- src/test/compile-fail/issue-4335.rs | 4 +- .../regions-proc-bound-capture.rs | 2 +- .../compile-fail/regions-steal-closure.rs | 4 +- .../send-is-not-static-ensures-scoping.rs | 5 +- .../compile-fail/unboxed-closure-region.rs | 2 +- 28 files changed, 93 insertions(+), 230 deletions(-) diff --git a/src/librustc/metadata/tydecode.rs b/src/librustc/metadata/tydecode.rs index baecfb7eb22..b33839f33e8 100644 --- a/src/librustc/metadata/tydecode.rs +++ b/src/librustc/metadata/tydecode.rs @@ -555,11 +555,9 @@ fn parse_ty_<'a, 'tcx, F>(st: &mut PState<'a, 'tcx>, conv: &mut F) -> Ty<'tcx> w 'k' => { assert_eq!(next(st), '['); let did = parse_def_(st, ClosureSource, conv); - let region = parse_region_(st, conv); let substs = parse_substs_(st, conv); assert_eq!(next(st), ']'); - return ty::mk_closure(st.tcx, did, - st.tcx.mk_region(region), st.tcx.mk_substs(substs)); + return ty::mk_closure(st.tcx, did, st.tcx.mk_substs(substs)); } 'P' => { assert_eq!(next(st), '['); diff --git a/src/librustc/metadata/tyencode.rs b/src/librustc/metadata/tyencode.rs index 76a365259aa..ebb4153e32b 100644 --- a/src/librustc/metadata/tyencode.rs +++ b/src/librustc/metadata/tyencode.rs @@ -139,9 +139,8 @@ pub fn enc_ty<'a, 'tcx>(w: &mut SeekableMemWriter, cx: &ctxt<'a, 'tcx>, t: Ty<'t enc_substs(w, cx, substs); mywrite!(w, "]"); } - ty::ty_closure(def, region, substs) => { + ty::ty_closure(def, substs) => { mywrite!(w, "k[{}|", (cx.ds)(def)); - enc_region(w, cx, *region); enc_substs(w, cx, substs); mywrite!(w, "]"); } diff --git a/src/librustc/middle/fast_reject.rs b/src/librustc/middle/fast_reject.rs index 7584a2e44cc..063845c6c34 100644 --- a/src/librustc/middle/fast_reject.rs +++ b/src/librustc/middle/fast_reject.rs @@ -74,7 +74,7 @@ pub fn simplify_type(tcx: &ty::ctxt, let def_id = tcx.lang_items.owned_box().unwrap(); Some(StructSimplifiedType(def_id)) } - ty::ty_closure(def_id, _, _) => { + ty::ty_closure(def_id, _) => { Some(ClosureSimplifiedType(def_id)) } ty::ty_tup(ref tys) => { diff --git a/src/librustc/middle/infer/combine.rs b/src/librustc/middle/infer/combine.rs index b782a655d89..be94a73df37 100644 --- a/src/librustc/middle/infer/combine.rs +++ b/src/librustc/middle/infer/combine.rs @@ -503,15 +503,14 @@ pub fn super_tys<'tcx, C>(this: &C, Ok(ty::mk_struct(tcx, a_id, tcx.mk_substs(substs))) } - (&ty::ty_closure(a_id, a_region, a_substs), - &ty::ty_closure(b_id, b_region, b_substs)) + (&ty::ty_closure(a_id, a_substs), + &ty::ty_closure(b_id, b_substs)) if a_id == b_id => { // All ty_closure types with the same id represent // the (anonymous) type of the same closure expression. So // all of their regions should be equated. - let region = try!(this.equate().regions(*a_region, *b_region)); let substs = try!(this.substs_variances(None, a_substs, b_substs)); - Ok(ty::mk_closure(tcx, a_id, tcx.mk_region(region), tcx.mk_substs(substs))) + Ok(ty::mk_closure(tcx, a_id, tcx.mk_substs(substs))) } (&ty::ty_uniq(a_inner), &ty::ty_uniq(b_inner)) => { diff --git a/src/librustc/middle/liveness.rs b/src/librustc/middle/liveness.rs index 5cb034667cc..224a568c77f 100644 --- a/src/librustc/middle/liveness.rs +++ b/src/librustc/middle/liveness.rs @@ -1496,7 +1496,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { fn fn_ret(&self, id: NodeId) -> ty::PolyFnOutput<'tcx> { let fn_ty = ty::node_id_to_type(self.ir.tcx, id); match fn_ty.sty { - ty::ty_closure(closure_def_id, _, substs) => + ty::ty_closure(closure_def_id, substs) => self.ir.tcx.closure_type(closure_def_id, substs).sig.output(), _ => ty::ty_fn_ret(fn_ty), diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index c4446b87855..1f02f13a4a1 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -607,7 +607,7 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> { def::DefUpvar(var_id, fn_node_id) => { let ty = try!(self.node_ty(fn_node_id)); match ty.sty { - ty::ty_closure(closure_id, _, _) => { + ty::ty_closure(closure_id, _) => { match self.typer.closure_kind(closure_id) { Some(kind) => { self.cat_upvar(id, span, var_id, fn_node_id, kind) diff --git a/src/librustc/middle/region.rs b/src/librustc/middle/region.rs index 7db1138ac72..b4db3aba786 100644 --- a/src/librustc/middle/region.rs +++ b/src/librustc/middle/region.rs @@ -320,8 +320,10 @@ impl InnermostEnclosingExpr { #[derive(Debug, Copy)] pub struct Context { + /// the scope that contains any new variables declared var_parent: InnermostDeclaringBlock, + /// region parent of expressions etc parent: InnermostEnclosingExpr, } diff --git a/src/librustc/middle/traits/project.rs b/src/librustc/middle/traits/project.rs index 7d4febb38e6..b9a863f4fe4 100644 --- a/src/librustc/middle/traits/project.rs +++ b/src/librustc/middle/traits/project.rs @@ -154,7 +154,7 @@ fn consider_unification_despite_ambiguity<'cx,'tcx>(selcx: &mut SelectionContext debug!("consider_unification_despite_ambiguity: self_ty.sty={:?}", self_ty.sty); match self_ty.sty { - ty::ty_closure(closure_def_id, _, substs) => { + ty::ty_closure(closure_def_id, substs) => { let closure_typer = selcx.closure_typer(); let closure_type = closure_typer.closure_type(closure_def_id, substs); let ty::Binder((_, ret_type)) = diff --git a/src/librustc/middle/traits/select.rs b/src/librustc/middle/traits/select.rs index d8c62780a78..470315c78f8 100644 --- a/src/librustc/middle/traits/select.rs +++ b/src/librustc/middle/traits/select.rs @@ -293,7 +293,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // lifetimes can appear inside the self-type. let self_ty = self.infcx.shallow_resolve(obligation.self_ty()); let (closure_def_id, substs) = match self_ty.sty { - ty::ty_closure(id, _, ref substs) => (id, substs.clone()), + ty::ty_closure(id, ref substs) => (id, substs.clone()), _ => { return; } }; assert!(!substs.has_escaping_regions()); @@ -1054,7 +1054,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let self_ty = self.infcx.shallow_resolve(obligation.self_ty()); let (closure_def_id, substs) = match self_ty.sty { - ty::ty_closure(id, _, ref substs) => (id, substs.clone()), + ty::ty_closure(id, ref substs) => (id, substs.clone()), ty::ty_infer(ty::TyVar(_)) => { debug!("assemble_unboxed_closure_candidates: ambiguous self-type"); candidates.ambiguous = true; @@ -1533,7 +1533,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // (T1, ..., Tn) -- meets any bound that all of T1...Tn meet ty::ty_tup(ref tys) => Ok(If(tys.clone())), - ty::ty_closure(def_id, _, substs) => { + ty::ty_closure(def_id, substs) => { // FIXME -- This case is tricky. In the case of by-ref // closures particularly, we need the results of // inference to decide how to reflect the type of each @@ -1687,7 +1687,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { Some(tys.clone()) } - ty::ty_closure(def_id, _, substs) => { + ty::ty_closure(def_id, substs) => { assert_eq!(def_id.krate, ast::LOCAL_CRATE); match self.closure_typer.closure_upvars(def_id, substs) { diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index 635ec09d339..aaba840825e 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -1367,7 +1367,7 @@ pub enum sty<'tcx> { ty_trait(Box>), ty_struct(DefId, &'tcx Substs<'tcx>), - ty_closure(DefId, &'tcx Region, &'tcx Substs<'tcx>), + ty_closure(DefId, &'tcx Substs<'tcx>), ty_tup(Vec>), @@ -2658,8 +2658,7 @@ impl FlagComputation { } } - &ty_closure(_, region, substs) => { - self.add_region(*region); + &ty_closure(_, substs) => { self.add_substs(substs); } @@ -2927,10 +2926,9 @@ pub fn mk_struct<'tcx>(cx: &ctxt<'tcx>, struct_id: ast::DefId, mk_t(cx, ty_struct(struct_id, substs)) } -pub fn mk_closure<'tcx>(cx: &ctxt<'tcx>, closure_id: ast::DefId, - region: &'tcx Region, substs: &'tcx Substs<'tcx>) +pub fn mk_closure<'tcx>(cx: &ctxt<'tcx>, closure_id: ast::DefId, substs: &'tcx Substs<'tcx>) -> Ty<'tcx> { - mk_t(cx, ty_closure(closure_id, region, substs)) + mk_t(cx, ty_closure(closure_id, substs)) } pub fn mk_var<'tcx>(cx: &ctxt<'tcx>, v: TyVid) -> Ty<'tcx> { @@ -3513,13 +3511,11 @@ pub fn type_contents<'tcx>(cx: &ctxt<'tcx>, ty: Ty<'tcx>) -> TypeContents { apply_lang_items(cx, did, res) } - ty_closure(did, r, substs) => { + ty_closure(did, substs) => { // FIXME(#14449): `borrowed_contents` below assumes `&mut` closure. let param_env = ty::empty_parameter_environment(cx); let upvars = closure_upvars(¶m_env, did, substs).unwrap(); - TypeContents::union(&upvars, - |f| tc_ty(cx, &f.ty, cache)) - | borrowed_contents(*r, MutMutable) + TypeContents::union(&upvars, |f| tc_ty(cx, &f.ty, cache)) } ty_tup(ref tys) => { @@ -5175,7 +5171,7 @@ pub fn ty_to_def_id(ty: Ty) -> Option { Some(tt.principal_def_id()), ty_struct(id, _) | ty_enum(id, _) | - ty_closure(id, _, _) => + ty_closure(id, _) => Some(id), _ => None @@ -6301,10 +6297,9 @@ pub fn hash_crate_independent<'tcx>(tcx: &ctxt<'tcx>, ty: Ty<'tcx>, svh: &Svh) - } ty_infer(_) => unreachable!(), ty_err => byte!(21), - ty_closure(d, r, _) => { + ty_closure(d, _) => { byte!(22); did(state, d); - region(state, *r); } ty_projection(ref data) => { byte!(23); @@ -6618,8 +6613,7 @@ pub fn accumulate_lifetimes_in_type(accumulator: &mut Vec, ty_struct(_, substs) => { accum_substs(accumulator, substs); } - ty_closure(_, region, substs) => { - accumulator.push(*region); + ty_closure(_, substs) => { accum_substs(accumulator, substs); } ty_bool | diff --git a/src/librustc/middle/ty_fold.rs b/src/librustc/middle/ty_fold.rs index 4bf47c3a75f..1b904aacc30 100644 --- a/src/librustc/middle/ty_fold.rs +++ b/src/librustc/middle/ty_fold.rs @@ -650,10 +650,9 @@ pub fn super_fold_ty<'tcx, T: TypeFolder<'tcx>>(this: &mut T, let substs = substs.fold_with(this); ty::ty_struct(did, this.tcx().mk_substs(substs)) } - ty::ty_closure(did, ref region, ref substs) => { - let r = region.fold_with(this); + ty::ty_closure(did, ref substs) => { let s = substs.fold_with(this); - ty::ty_closure(did, this.tcx().mk_region(r), this.tcx().mk_substs(s)) + ty::ty_closure(did, this.tcx().mk_substs(s)) } ty::ty_projection(ref data) => { ty::ty_projection(data.fold_with(this)) diff --git a/src/librustc/middle/ty_walk.rs b/src/librustc/middle/ty_walk.rs index 3336e7ee8bf..5b5eac45178 100644 --- a/src/librustc/middle/ty_walk.rs +++ b/src/librustc/middle/ty_walk.rs @@ -45,7 +45,7 @@ impl<'tcx> TypeWalker<'tcx> { } ty::ty_enum(_, ref substs) | ty::ty_struct(_, ref substs) | - ty::ty_closure(_, _, ref substs) => { + ty::ty_closure(_, ref substs) => { self.push_reversed(substs.types.as_slice()); } ty::ty_tup(ref ts) => { diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index 15b3c6d9d06..0eeb746022c 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -406,7 +406,7 @@ pub fn ty_to_string<'tcx>(cx: &ctxt<'tcx>, typ: &ty::TyS<'tcx>) -> String { data.item_name.user_string(cx)) } ty_str => "str".to_string(), - ty_closure(ref did, _, substs) => { + ty_closure(ref did, substs) => { let closure_tys = cx.closure_tys.borrow(); closure_tys.get(did).map(|closure_type| { closure_to_string(cx, &closure_type.subst(cx, substs)) diff --git a/src/librustc_trans/trans/adt.rs b/src/librustc_trans/trans/adt.rs index 3ea14d3c589..2fb0488cd70 100644 --- a/src/librustc_trans/trans/adt.rs +++ b/src/librustc_trans/trans/adt.rs @@ -169,7 +169,7 @@ fn represent_type_uncached<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, Univariant(mk_struct(cx, &ftys[..], packed, t), dtor) } - ty::ty_closure(def_id, _, substs) => { + ty::ty_closure(def_id, substs) => { let typer = NormalizingClosureTyper::new(cx.tcx()); let upvars = typer.closure_upvars(def_id, substs).unwrap(); let upvar_types = upvars.iter().map(|u| u.ty).collect::>(); diff --git a/src/librustc_trans/trans/base.rs b/src/librustc_trans/trans/base.rs index 1f578ac0bdb..7a6960d3790 100644 --- a/src/librustc_trans/trans/base.rs +++ b/src/librustc_trans/trans/base.rs @@ -291,7 +291,7 @@ pub fn decl_rust_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ty::ty_bare_fn(_, ref f) => { (&f.sig, f.abi, None) } - ty::ty_closure(closure_did, _, substs) => { + ty::ty_closure(closure_did, substs) => { let typer = common::NormalizingClosureTyper::new(ccx.tcx()); function_type = typer.closure_type(closure_did, substs); let self_type = self_type_for_closure(ccx, closure_did, fn_ty); @@ -685,7 +685,7 @@ pub fn iter_structural_ty<'blk, 'tcx, F>(cx: Block<'blk, 'tcx>, } }) } - ty::ty_closure(def_id, _, substs) => { + ty::ty_closure(def_id, substs) => { let repr = adt::represent_type(cx.ccx(), t); let typer = common::NormalizingClosureTyper::new(cx.tcx()); let upvars = typer.closure_upvars(def_id, substs).unwrap(); @@ -2437,7 +2437,7 @@ pub fn get_fn_llvm_attributes<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fn_ty: Ty< let function_type; let (fn_sig, abi, env_ty) = match fn_ty.sty { ty::ty_bare_fn(_, ref f) => (&f.sig, f.abi, None), - ty::ty_closure(closure_did, _, substs) => { + ty::ty_closure(closure_did, substs) => { let typer = common::NormalizingClosureTyper::new(ccx.tcx()); function_type = typer.closure_type(closure_did, substs); let self_type = self_type_for_closure(ccx, closure_did, fn_ty); @@ -2454,7 +2454,7 @@ pub fn get_fn_llvm_attributes<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fn_ty: Ty< // These have an odd calling convention, so we need to manually // unpack the input ty's let input_tys = match fn_ty.sty { - ty::ty_closure(_, _, _) => { + ty::ty_closure(..) => { assert!(abi == RustCall); match fn_sig.inputs[0].sty { diff --git a/src/librustc_trans/trans/closure.rs b/src/librustc_trans/trans/closure.rs index 1d4bbd79d71..7fa26a7c128 100644 --- a/src/librustc_trans/trans/closure.rs +++ b/src/librustc_trans/trans/closure.rs @@ -138,7 +138,7 @@ pub fn get_or_create_declaration_if_closure<'a, 'tcx>(ccx: &CrateContext<'a, 'tc // duplicate declarations let function_type = erase_regions(ccx.tcx(), &function_type); let params = match function_type.sty { - ty::ty_closure(_, _, substs) => &substs.types, + ty::ty_closure(_, substs) => &substs.types, _ => unreachable!() }; let mono_id = MonoId { diff --git a/src/librustc_trans/trans/debuginfo.rs b/src/librustc_trans/trans/debuginfo.rs index d70a904b811..f3b7058336b 100644 --- a/src/librustc_trans/trans/debuginfo.rs +++ b/src/librustc_trans/trans/debuginfo.rs @@ -472,7 +472,7 @@ impl<'tcx> TypeMap<'tcx> { } } }, - ty::ty_closure(def_id, _, substs) => { + ty::ty_closure(def_id, substs) => { let typer = NormalizingClosureTyper::new(cx.tcx()); let closure_ty = typer.closure_type(def_id, substs); self.get_unique_type_id_of_closure_type(cx, @@ -2983,7 +2983,7 @@ fn type_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, ty::ty_bare_fn(_, ref barefnty) => { subroutine_type_metadata(cx, unique_type_id, &barefnty.sig, usage_site_span) } - ty::ty_closure(def_id, _, substs) => { + ty::ty_closure(def_id, substs) => { let typer = NormalizingClosureTyper::new(cx.tcx()); let sig = typer.closure_type(def_id, substs).sig; subroutine_type_metadata(cx, unique_type_id, &sig, usage_site_span) diff --git a/src/librustc_typeck/check/callee.rs b/src/librustc_typeck/check/callee.rs index 0ad15456df9..f9495af79c5 100644 --- a/src/librustc_typeck/check/callee.rs +++ b/src/librustc_typeck/check/callee.rs @@ -137,7 +137,7 @@ fn try_overloaded_call_step<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, return Some(CallStep::Builtin); } - ty::ty_closure(def_id, _, substs) => { + ty::ty_closure(def_id, substs) => { assert_eq!(def_id.krate, ast::LOCAL_CRATE); // Check whether this is a call to a closure where we diff --git a/src/librustc_typeck/check/closure.rs b/src/librustc_typeck/check/closure.rs index 0b7c5b04aaa..0d4edc01a4c 100644 --- a/src/librustc_typeck/check/closure.rs +++ b/src/librustc_typeck/check/closure.rs @@ -16,7 +16,6 @@ use astconv; use middle::region; use middle::subst; use middle::ty::{self, ToPolyTraitRef, Ty}; -use rscope::RegionScope; use syntax::abi; use syntax::ast; use syntax::ast_util; @@ -61,17 +60,8 @@ fn check_closure<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>, abi::RustCall, expected_sig); - let region = match fcx.anon_regions(expr.span, 1) { - Err(_) => { - fcx.ccx.tcx.sess.span_bug(expr.span, - "can't make anon regions here?!") - } - Ok(regions) => regions[0], - }; - let closure_type = ty::mk_closure(fcx.ccx.tcx, expr_def_id, - fcx.ccx.tcx.mk_region(region), fcx.ccx.tcx.mk_substs( fcx.inh.param_env.free_substs.clone())); diff --git a/src/librustc_typeck/check/implicator.rs b/src/librustc_typeck/check/implicator.rs index f65e585d23e..f99ba894029 100644 --- a/src/librustc_typeck/check/implicator.rs +++ b/src/librustc_typeck/check/implicator.rs @@ -29,6 +29,7 @@ use util::ppaux::Repr; pub enum Implication<'tcx> { RegionSubRegion(Option>, ty::Region, ty::Region), RegionSubGeneric(Option>, ty::Region, GenericKind<'tcx>), + RegionSubClosure(Option>, ty::Region, ast::DefId, &'tcx Substs<'tcx>), Predicate(ast::DefId, ty::Predicate<'tcx>), } @@ -91,29 +92,9 @@ impl<'a, 'tcx> Implicator<'a, 'tcx> { // No borrowed content reachable here. } - ty::ty_closure(_, region, _) => { - // An "closure type" is basically - // modeled here as equivalent to a struct like - // - // struct TheClosure<'b> { - // ... - // } - // - // where the `'b` is the lifetime bound of the - // contents (i.e., all contents must outlive 'b). - // - // Even though closures are glorified structs - // of upvars, we do not need to consider them as they - // can't generate any new constraints. The - // substitutions on the closure are equal to the free - // substitutions of the enclosing parameter - // environment. An upvar captured by value has the - // same type as the original local variable which is - // already checked for consistency. If the upvar is - // captured by reference it must also outlive the - // region bound on the closure, but this is explicitly - // handled by logic in regionck. - self.push_region_constraint_from_top(*region); + ty::ty_closure(def_id, substs) => { + let &(r_a, opt_ty) = self.stack.last().unwrap(); + self.out.push(Implication::RegionSubClosure(opt_ty, r_a, def_id, substs)); } ty::ty_trait(ref t) => { @@ -448,6 +429,13 @@ impl<'tcx> Repr<'tcx> for Implication<'tcx> { p.repr(tcx)) } + Implication::RegionSubClosure(_, ref a, ref b, ref c) => { + format!("RegionSubClosure({}, {}, {})", + a.repr(tcx), + b.repr(tcx), + c.repr(tcx)) + } + Implication::Predicate(ref def_id, ref p) => { format!("Predicate({}, {})", def_id.repr(tcx), diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs index f24da78bc7d..fbf002b709e 100644 --- a/src/librustc_typeck/check/method/probe.rs +++ b/src/librustc_typeck/check/method/probe.rs @@ -278,7 +278,7 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> { } ty::ty_enum(did, _) | ty::ty_struct(did, _) | - ty::ty_closure(did, _, _) => { + ty::ty_closure(did, _) => { self.assemble_inherent_impl_candidates_for_type(did); } ty::ty_uniq(_) => { @@ -641,8 +641,8 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> { // If so, add "synthetic impls". let steps = self.steps.clone(); for step in &*steps { - let (closure_def_id, _, _) = match step.self_ty.sty { - ty::ty_closure(a, b, ref c) => (a, b, c), + let closure_def_id = match step.self_ty.sty { + ty::ty_closure(a, _) => a, _ => continue, }; diff --git a/src/librustc_typeck/check/regionck.rs b/src/librustc_typeck/check/regionck.rs index 1518a09e7dc..a3e98b0c4c6 100644 --- a/src/librustc_typeck/check/regionck.rs +++ b/src/librustc_typeck/check/regionck.rs @@ -87,12 +87,11 @@ use check::dropck; use check::FnCtxt; use check::implicator; use check::vtable; -use middle::def; use middle::mem_categorization as mc; use middle::region::CodeExtent; +use middle::subst::Substs; use middle::traits; -use middle::ty::{ReScope}; -use middle::ty::{self, Ty, MethodCall}; +use middle::ty::{self, ClosureTyper, ReScope, Ty, MethodCall}; use middle::infer::{self, GenericKind}; use middle::pat_util; use util::ppaux::{ty_to_string, Repr}; @@ -179,20 +178,6 @@ pub struct Rcx<'a, 'tcx: 'a> { } -/// Returns the validity region of `def` -- that is, how long is `def` valid? -fn region_of_def(fcx: &FnCtxt, def: def::Def) -> ty::Region { - let tcx = fcx.tcx(); - match def { - def::DefLocal(node_id) | def::DefUpvar(node_id, _) => { - tcx.region_maps.var_region(node_id) - } - _ => { - tcx.sess.bug(&format!("unexpected def in region_of_def: {:?}", - def)) - } - } -} - struct RepeatingScope(ast::NodeId); pub enum SubjectNode { Subject(ast::NodeId), None } @@ -368,7 +353,15 @@ impl<'a, 'tcx> Rcx<'a, 'tcx> { ty::ReInfer(ty::ReVar(vid_b))) => { self.fcx.inh.infcx.add_given(free_a, vid_b); } - implicator::Implication::RegionSubRegion(..) => { + implicator::Implication::RegionSubGeneric(_, r_a, ref generic_b) => { + debug!("RegionSubGeneric: {} <= {}", + r_a.repr(tcx), generic_b.repr(tcx)); + + self.region_bound_pairs.push((r_a, generic_b.clone())); + } + implicator::Implication::RegionSubRegion(..) | + implicator::Implication::RegionSubClosure(..) | + implicator::Implication::Predicate(..) => { // In principle, we could record (and take // advantage of) every relationship here, but // we are also free not to -- it simply means @@ -379,13 +372,6 @@ impl<'a, 'tcx> Rcx<'a, 'tcx> { // relationship that arises here, but // presently we do not.) } - implicator::Implication::RegionSubGeneric(_, r_a, ref generic_b) => { - debug!("RegionSubGeneric: {} <= {}", - r_a.repr(tcx), generic_b.repr(tcx)); - - self.region_bound_pairs.push((r_a, generic_b.clone())); - } - implicator::Implication::Predicate(..) => { } } } } @@ -792,124 +778,9 @@ fn constrain_cast(rcx: &mut Rcx, fn check_expr_fn_block(rcx: &mut Rcx, expr: &ast::Expr, body: &ast::Block) { - let tcx = rcx.fcx.tcx(); - let function_type = rcx.resolve_node_type(expr.id); - - match function_type.sty { - ty::ty_closure(_, region, _) => { - ty::with_freevars(tcx, expr.id, |freevars| { - constrain_captured_variables(rcx, *region, expr, freevars); - }) - } - _ => { } - } - let repeating_scope = rcx.set_repeating_scope(body.id); visit::walk_expr(rcx, expr); rcx.set_repeating_scope(repeating_scope); - - match function_type.sty { - ty::ty_closure(_, region, _) => { - ty::with_freevars(tcx, expr.id, |freevars| { - let bounds = ty::region_existential_bound(*region); - ensure_free_variable_types_outlive_closure_bound(rcx, &bounds, expr, freevars); - }) - } - _ => {} - } - - /// Make sure that the type of all free variables referenced inside a closure/proc outlive the - /// closure/proc's lifetime bound. This is just a special case of the usual rules about closed - /// over values outliving the object's lifetime bound. - fn ensure_free_variable_types_outlive_closure_bound( - rcx: &mut Rcx, - bounds: &ty::ExistentialBounds, - expr: &ast::Expr, - freevars: &[ty::Freevar]) - { - let tcx = rcx.fcx.ccx.tcx; - - debug!("ensure_free_variable_types_outlive_closure_bound({}, {})", - bounds.region_bound.repr(tcx), expr.repr(tcx)); - - for freevar in freevars { - let var_node_id = { - let def_id = freevar.def.def_id(); - assert!(def_id.krate == ast::LOCAL_CRATE); - def_id.node - }; - - // Compute the type of the field in the environment that - // represents `var_node_id`. For a by-value closure, this - // will be the same as the type of the variable. For a - // by-reference closure, this will be `&T` where `T` is - // the type of the variable. - let raw_var_ty = rcx.resolve_node_type(var_node_id); - let upvar_id = ty::UpvarId { var_id: var_node_id, - closure_expr_id: expr.id }; - let var_ty = match rcx.fcx.inh.upvar_capture_map.borrow()[upvar_id] { - ty::UpvarCapture::ByRef(ref upvar_borrow) => { - ty::mk_rptr(rcx.tcx(), - rcx.tcx().mk_region(upvar_borrow.region), - ty::mt { mutbl: upvar_borrow.kind.to_mutbl_lossy(), - ty: raw_var_ty }) - } - ty::UpvarCapture::ByValue => raw_var_ty, - }; - - // Check that the type meets the criteria of the existential bounds: - for builtin_bound in &bounds.builtin_bounds { - let code = traits::ClosureCapture(var_node_id, expr.span, builtin_bound); - let cause = traits::ObligationCause::new(freevar.span, rcx.fcx.body_id, code); - rcx.fcx.register_builtin_bound(var_ty, builtin_bound, cause); - } - - type_must_outlive( - rcx, infer::FreeVariable(expr.span, var_node_id), - var_ty, bounds.region_bound); - } - } - - /// Make sure that all free variables referenced inside the closure outlive the closure's - /// lifetime bound. Also, create an entry in the upvar_borrows map with a region. - fn constrain_captured_variables( - rcx: &mut Rcx, - region_bound: ty::Region, - expr: &ast::Expr, - freevars: &[ty::Freevar]) - { - let tcx = rcx.fcx.ccx.tcx; - debug!("constrain_captured_variables({}, {})", - region_bound.repr(tcx), expr.repr(tcx)); - for freevar in freevars { - debug!("constrain_captured_variables: freevar.def={:?}", freevar.def); - - // Identify the variable being closed over and its node-id. - let def = freevar.def; - let var_node_id = { - let def_id = def.def_id(); - assert!(def_id.krate == ast::LOCAL_CRATE); - def_id.node - }; - let upvar_id = ty::UpvarId { var_id: var_node_id, - closure_expr_id: expr.id }; - - match rcx.fcx.inh.upvar_capture_map.borrow()[upvar_id] { - ty::UpvarCapture::ByValue => { } - ty::UpvarCapture::ByRef(upvar_borrow) => { - rcx.fcx.mk_subr(infer::FreeVariable(freevar.span, var_node_id), - region_bound, upvar_borrow.region); - - // Guarantee that the closure does not outlive the variable itself. - let enclosing_region = region_of_def(rcx.fcx, def); - debug!("constrain_captured_variables: enclosing_region = {}", - enclosing_region.repr(tcx)); - rcx.fcx.mk_subr(infer::FreeVariable(freevar.span, var_node_id), - region_bound, enclosing_region); - } - } - } - } } fn constrain_callee(rcx: &mut Rcx, @@ -1538,6 +1409,9 @@ pub fn type_must_outlive<'a, 'tcx>(rcx: &mut Rcx<'a, 'tcx>, let o1 = infer::ReferenceOutlivesReferent(ty, origin.span()); generic_must_outlive(rcx, o1, r_a, generic_b); } + implicator::Implication::RegionSubClosure(_, r_a, def_id, substs) => { + closure_must_outlive(rcx, origin.clone(), r_a, def_id, substs); + } implicator::Implication::Predicate(def_id, predicate) => { let cause = traits::ObligationCause::new(origin.span(), rcx.body_id, @@ -1549,6 +1423,23 @@ pub fn type_must_outlive<'a, 'tcx>(rcx: &mut Rcx<'a, 'tcx>, } } +fn closure_must_outlive<'a, 'tcx>(rcx: &mut Rcx<'a, 'tcx>, + origin: infer::SubregionOrigin<'tcx>, + region: ty::Region, + def_id: ast::DefId, + substs: &'tcx Substs<'tcx>) { + debug!("closure_must_outlive(region={}, def_id={}, substs={})", + region.repr(rcx.tcx()), def_id.repr(rcx.tcx()), substs.repr(rcx.tcx())); + + let upvars = rcx.fcx.closure_upvars(def_id, substs).unwrap(); + for upvar in upvars { + let var_id = upvar.def.def_id().local_id(); + type_must_outlive( + rcx, infer::FreeVariable(origin.span(), var_id), + upvar.ty, region); + } +} + fn generic_must_outlive<'a, 'tcx>(rcx: &Rcx<'a, 'tcx>, origin: infer::SubregionOrigin<'tcx>, region: ty::Region, diff --git a/src/librustc_typeck/coherence/mod.rs b/src/librustc_typeck/coherence/mod.rs index 1913b55f1d8..58b67d31ab5 100644 --- a/src/librustc_typeck/coherence/mod.rs +++ b/src/librustc_typeck/coherence/mod.rs @@ -397,7 +397,7 @@ impl<'a, 'tcx> CoherenceChecker<'a, 'tcx> { match self_type.ty.sty { ty::ty_enum(type_def_id, _) | ty::ty_struct(type_def_id, _) | - ty::ty_closure(type_def_id, _, _) => { + ty::ty_closure(type_def_id, _) => { tcx.destructor_for_type .borrow_mut() .insert(type_def_id, method_def_id.def_id()); diff --git a/src/test/compile-fail/issue-4335.rs b/src/test/compile-fail/issue-4335.rs index d0da51373d9..85298e4c6e0 100644 --- a/src/test/compile-fail/issue-4335.rs +++ b/src/test/compile-fail/issue-4335.rs @@ -14,7 +14,9 @@ fn id(t: T) -> T { t } fn f<'r, T>(v: &'r T) -> Box T + 'r> { - id(box || *v) //~ ERROR cannot infer + id(box || *v) + //~^ ERROR `v` does not live long enough + //~| ERROR cannot move out of borrowed content } fn main() { diff --git a/src/test/compile-fail/regions-proc-bound-capture.rs b/src/test/compile-fail/regions-proc-bound-capture.rs index 7ea4d1c7507..cc33d112417 100644 --- a/src/test/compile-fail/regions-proc-bound-capture.rs +++ b/src/test/compile-fail/regions-proc-bound-capture.rs @@ -18,7 +18,7 @@ fn borrowed_proc<'a>(x: &'a isize) -> Box(isize) + 'a> { fn static_proc(x: &isize) -> Box(isize) + 'static> { // This is illegal, because the region bound on `proc` is 'static. - box move|| { *x } //~ ERROR cannot infer + box move|| { *x } //~ ERROR captured variable `x` does not outlive the enclosing closure } fn main() { } diff --git a/src/test/compile-fail/regions-steal-closure.rs b/src/test/compile-fail/regions-steal-closure.rs index 97b51fdb325..c9b378d1df2 100644 --- a/src/test/compile-fail/regions-steal-closure.rs +++ b/src/test/compile-fail/regions-steal-closure.rs @@ -20,9 +20,9 @@ fn box_it<'r>(x: Box) -> closure_box<'r> { } fn main() { - let cl_box = { + let mut cl_box = { let mut i = 3; - box_it(box || i += 1) //~ ERROR cannot infer + box_it(box || i += 1) //~ ERROR `i` does not live long enough }; cl_box.cl.call_mut(()); } diff --git a/src/test/compile-fail/send-is-not-static-ensures-scoping.rs b/src/test/compile-fail/send-is-not-static-ensures-scoping.rs index abbcd7e4590..fe03ca8353d 100755 --- a/src/test/compile-fail/send-is-not-static-ensures-scoping.rs +++ b/src/test/compile-fail/send-is-not-static-ensures-scoping.rs @@ -13,9 +13,10 @@ use std::thread; fn main() { let bad = { let x = 1; - let y = &x; + let y = &x; //~ ERROR `x` does not live long enough - thread::scoped(|| { //~ ERROR cannot infer an appropriate lifetime + thread::scoped(|| { + //~^ ERROR `y` does not live long enough let _z = y; }) }; diff --git a/src/test/compile-fail/unboxed-closure-region.rs b/src/test/compile-fail/unboxed-closure-region.rs index 59c84953718..5f4bf0d33be 100644 --- a/src/test/compile-fail/unboxed-closure-region.rs +++ b/src/test/compile-fail/unboxed-closure-region.rs @@ -15,6 +15,6 @@ fn main() { let _f = { let x = 0_usize; - || x //~ ERROR cannot infer an appropriate lifetime due to conflicting requirements + || x //~ ERROR `x` does not live long enough }; } From 31ad998bfd974a5488665099fe6b5962583fa958 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Steinbrink?= Date: Mon, 2 Mar 2015 12:11:46 +0100 Subject: [PATCH 08/10] Properly propagate block changes while translating drop glue --- src/librustc_trans/trans/glue.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/librustc_trans/trans/glue.rs b/src/librustc_trans/trans/glue.rs index 9491c8377a6..1151b11d21f 100644 --- a/src/librustc_trans/trans/glue.rs +++ b/src/librustc_trans/trans/glue.rs @@ -313,8 +313,7 @@ fn trans_struct_drop<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, ty::mk_nil(bcx.tcx())); let (_, variant_cx) = invoke(variant_cx, dtor_addr, &args[..], dtor_ty, DebugLoc::None); - variant_cx.fcx.pop_and_trans_custom_cleanup_scope(variant_cx, field_scope); - variant_cx + variant_cx.fcx.pop_and_trans_custom_cleanup_scope(variant_cx, field_scope) }) } From fe91974dd6eb3c16cc80081d6eb9f7017eb6bada Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Steinbrink?= Date: Mon, 2 Mar 2015 12:11:46 +0100 Subject: [PATCH 09/10] Properly propagate block changes while translating drop glue --- src/librustc_trans/trans/glue.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/librustc_trans/trans/glue.rs b/src/librustc_trans/trans/glue.rs index 9491c8377a6..1151b11d21f 100644 --- a/src/librustc_trans/trans/glue.rs +++ b/src/librustc_trans/trans/glue.rs @@ -313,8 +313,7 @@ fn trans_struct_drop<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, ty::mk_nil(bcx.tcx())); let (_, variant_cx) = invoke(variant_cx, dtor_addr, &args[..], dtor_ty, DebugLoc::None); - variant_cx.fcx.pop_and_trans_custom_cleanup_scope(variant_cx, field_scope); - variant_cx + variant_cx.fcx.pop_and_trans_custom_cleanup_scope(variant_cx, field_scope) }) } From 8567f290b840bbdf1149a23faa4ac4c47ab62fb4 Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Mon, 2 Mar 2015 17:44:01 +0530 Subject: [PATCH 10/10] Add cfg_attr to known attributes --- src/libsyntax/feature_gate.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index ffc136d5a1d..8043bd9bd70 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -173,6 +173,7 @@ pub static KNOWN_ATTRIBUTES: &'static [(&'static str, AttributeType)] = &[ ("plugin_registrar", Normal), ("cfg", Normal), + ("cfg_attr", Normal), ("main", Normal), ("start", Normal), ("test", Normal),