Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
There are two interesting kinds of breakage illustrated here: 1. `Box<Trait>` in many contexts is treated as `Box<Trait + 'static>`, due to [RFC 599]. However, in a type like `&'a Box<Trait>`, the `Box<Trait>` type will be expanded to `Box<Trait + 'a>`, again due to [RFC 599]. This, combined with the fix to Issue 25199, leads to a borrowck problem due the combination of this function signature (in src/libstd/net/parser.rs): ```rust fn read_or<T>(&mut self, parsers: &mut [Box<FnMut(&mut Parser) -> Option<T>>]) -> Option<T>; ``` with this call site (again in src/libstd/net/parser.rs): ```rust fn read_ip_addr(&mut self) -> Option<IpAddr> { let ipv4_addr = |p: &mut Parser| p.read_ipv4_addr().map(|v4| IpAddr::V4(v4)); let ipv6_addr = |p: &mut Parser| p.read_ipv6_addr().map(|v6| IpAddr::V6(v6)); self.read_or(&mut [Box::new(ipv4_addr), Box::new(ipv6_addr)]) } ``` yielding borrowck errors like: ``` parser.rs:265:27: 265:69 error: borrowed value does not live long enough parser.rs:265 self.read_or(&mut [Box::new(ipv4_addr), Box::new(ipv6_addr)]) ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ``` (full log at: https://gist.github.com/pnkfelix/e2e80f1a71580f5d3103 ) The issue here is perhaps subtle: the `parsers` argument is inferred to be taking a slice of boxed objects with the implicit lifetime bound attached to the `self` parameter to `read_or`. Meanwhile, the fix to Issue 25199 (added in a forth-coming commit) is forcing us to assume that each boxed object may have a destructor that could refer to state of that lifetime, and *therefore* that inferred lifetime is required to outlive the boxed object itself. In this case, the relevant boxed object here is not going to make any such references; I believe it is just an artifact of how the expression was built that it is not assigned type: `Box<FnMut(&mut Parser) -> Option<T> + 'static>`. (i.e., mucking with the expression is probably one way to fix this problem). But the other way to fix it, adopted here, is to change the `read_or` method type to force make the (presumably-intended) `'static` bound explicit on the boxed `FnMut` object. (Note: this is still just the *first* example of breakage.) 2. In `macro_rules.rs`, the `TTMacroExpander` trait defines a method with signature: ```rust fn expand<'cx>(&self, cx: &'cx mut ExtCtxt, ...) -> Box<MacResult+'cx>; ``` taking a `&'cx mut ExtCtxt` as an argument and returning a `Box<MacResult'cx>`. The fix to Issue 25199 (added in aforementioned forth-coming commit) assumes that a value of type `Box<MacResult+'cx>` may, in its destructor, refer to a reference of lifetime `'cx`; thus the `'cx` lifetime is forced to outlive the returned value. Meanwhile, within `expand.rs`, the old code was doing: ```rust match expander.expand(fld.cx, ...).make_pat() { ... => immutable borrow of fld.cx ... } ``` The problem is that the `'cx` lifetime, inferred for the `expander.expand` call, has now been extended so that it has to outlive the temporary R-value returned by `expanded.expand`. But call is also reborrowing `fld.cx` *mutably*, which means that this reborrow must end before any immutable borrow of `fld.cx`; but there is one of those within the match body. (Note that the temporary R-values for the input expression to `match` all live as long as the whole `match` expression itself (see Issue rust-lang#3511 and PR rust-lang#11585). To address this, I moved the construction of the pat value into its own `let`-statement, so that the `Box<MacResult>` will only live for as long as the initializing expression for the `let`-statement, and thus allow the subsequent immutable borrow within the `match`. [RFC 599]: https://github.com/rust-lang/rfcs/blob/master/text/0599-default-object-bound.md
- Loading branch information