Skip to content

Commit 591d8c8

Browse files
committed
Add CodeExtent::Remainder variant to track a suffix of a block.
Added DestructionScope variant to CodeExtent, representing the area immediately surrounding a node that is a terminating_scope (e.g. statements, looping forms) during which the destructors run (the destructors for temporaries from the execution of that node, that is). insert DestructionScope and block Remainder into enclosing CodeExtents hierarchy. Switch to constructing DestructionScope rather than Misc in a number of places, mostly related to `ty::ReFree` creation, and use destruction-scopes of node-ids at various calls to liberate_late_bound_regions. middle::resolve_lifetime: Map BlockScope to DestructionScope in `fn resolve_free_lifetime`. add the InnermostDeclaringBlock and InnermostEnclosingExpr enums that are my attempt to clarify the region::Context structure, and that later commmts build upon. Expanded region-inference graph with enclosing relationship as well as the constraint edges. improve the debug output for `CodeExtent` attached to `ty::Region::ReScope`. loosened an assertion in `rustc_trans::trans::cleanup` to account for `DestructionScope`. (Perhaps this should just be switched entirely over to `DestructionScope`, rather than allowing for either `Misc` or `DestructionScope`.) ---- The more fine-grained scopes introduced by this change break some code. A simple example can be seen in libregex/vm.rs, where two references `clist` and `nlist` need to have the same lifetime lead to this code breaking: ```rust let mut clist = &mut Threads::new(self.which, ninsts, ncaps); let mut nlist = &mut Threads::new(self.which, ninsts, ncaps); ... mem::swap(&mut clist, &mut nlist); ``` The reason for the breakage is that the thread-value associated with `nlist` has a strictly shorter lifetime than the `&mut`-reference for `clist`, but the code in question needs both `clist` and `list` to be assigned compatible lifetimes. The usual fix is to revise the code as follows, moving *both* of the thread values up above the creation of the `&mut`-references, like so: ```rust let mut cthread = Threads::new(self.which, ninsts, ncaps); let mut nthread = Threads::new(self.which, ninsts, ncaps); let mut clist = &mut cthread; let mut nlist = &mut nthread; ... mem::swap(&mut clist, &mut nlist); ``` Likewise, there are other cases where the value needs to have a strictly greater lifetime than the reference taken to that value, and the typical solution is to create the value and bind it to a name in statement preceding the creation of the reference. ---- Due to these (relatively rare) instances, this is a (wait for it) [breaking-change]
1 parent 382c070 commit 591d8c8

File tree

13 files changed

+426
-99
lines changed

13 files changed

+426
-99
lines changed

src/librustc/metadata/tydecode.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -390,6 +390,18 @@ fn parse_scope(st: &mut PState) -> region::CodeExtent {
390390
let node_id = parse_uint(st) as ast::NodeId;
391391
region::CodeExtent::Misc(node_id)
392392
}
393+
'D' => {
394+
let node_id = parse_uint(st) as ast::NodeId;
395+
region::CodeExtent::DestructionScope(node_id)
396+
}
397+
'B' => {
398+
let node_id = parse_uint(st) as ast::NodeId;
399+
let first_stmt_index = parse_uint(st);
400+
let block_remainder = region::BlockRemainder {
401+
block: node_id, first_statement_index: first_stmt_index,
402+
};
403+
region::CodeExtent::Remainder(block_remainder)
404+
}
393405
_ => panic!("parse_scope: bad input")
394406
}
395407
}

src/librustc/metadata/tyencode.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -276,7 +276,10 @@ pub fn enc_region(w: &mut SeekableMemWriter, cx: &ctxt, r: ty::Region) {
276276

277277
fn enc_scope(w: &mut SeekableMemWriter, _cx: &ctxt, scope: region::CodeExtent) {
278278
match scope {
279-
region::CodeExtent::Misc(node_id) => mywrite!(w, "M{}", node_id)
279+
region::CodeExtent::Misc(node_id) => mywrite!(w, "M{}", node_id),
280+
region::CodeExtent::Remainder(region::BlockRemainder {
281+
block: b, first_statement_index: i }) => mywrite!(w, "B{}{}", b, i),
282+
region::CodeExtent::DestructionScope(node_id) => mywrite!(w, "D{}", node_id),
280283
}
281284
}
282285

src/librustc/middle/infer/region_inference/graphviz.rs

Lines changed: 50 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,14 @@
1919
use graphviz as dot;
2020

2121
use middle::ty;
22+
use middle::region::CodeExtent;
2223
use super::Constraint;
2324
use middle::infer::SubregionOrigin;
2425
use middle::infer::region_inference::RegionVarBindings;
2526
use util::nodemap::{FnvHashMap, FnvHashSet};
2627
use util::ppaux::Repr;
2728

29+
use std::borrow::Cow;
2830
use std::collections::hash_map::Entry::Vacant;
2931
use std::io::{self, File};
3032
use std::os;
@@ -120,13 +122,18 @@ struct ConstraintGraph<'a, 'tcx: 'a> {
120122
node_ids: FnvHashMap<Node, uint>,
121123
}
122124

123-
#[derive(Clone, Hash, PartialEq, Eq, Show)]
125+
#[derive(Clone, Hash, PartialEq, Eq, Show, Copy)]
124126
enum Node {
125127
RegionVid(ty::RegionVid),
126128
Region(ty::Region),
127129
}
128130

129-
type Edge = Constraint;
131+
// type Edge = Constraint;
132+
#[derive(Clone, PartialEq, Eq, Show, Copy)]
133+
enum Edge {
134+
Constraint(Constraint),
135+
EnclScope(CodeExtent, CodeExtent),
136+
}
130137

131138
impl<'a, 'tcx> ConstraintGraph<'a, 'tcx> {
132139
fn new(tcx: &'a ty::ctxt<'tcx>,
@@ -146,6 +153,11 @@ impl<'a, 'tcx> ConstraintGraph<'a, 'tcx> {
146153
add_node(n1);
147154
add_node(n2);
148155
}
156+
157+
tcx.region_maps.each_encl_scope(|&mut: sub, sup| {
158+
add_node(Node::Region(ty::ReScope(*sub)));
159+
add_node(Node::Region(ty::ReScope(*sup)));
160+
});
149161
}
150162

151163
ConstraintGraph { tcx: tcx,
@@ -160,7 +172,17 @@ impl<'a, 'tcx> dot::Labeller<'a, Node, Edge> for ConstraintGraph<'a, 'tcx> {
160172
dot::Id::new(self.graph_name.as_slice()).unwrap()
161173
}
162174
fn node_id(&self, n: &Node) -> dot::Id {
163-
dot::Id::new(format!("node_{}", self.node_ids.get(n).unwrap())).unwrap()
175+
let node_id = match self.node_ids.get(n) {
176+
Some(node_id) => node_id,
177+
None => panic!("no node_id found for node: {:?}", n),
178+
};
179+
let name = |&:| format!("node_{}", node_id);
180+
match dot::Id::new(name()) {
181+
Ok(id) => id,
182+
Err(()) => {
183+
panic!("failed to create graphviz node identified by {}", name());
184+
}
185+
}
164186
}
165187
fn node_label(&self, n: &Node) -> dot::LabelText {
166188
match *n {
@@ -171,7 +193,12 @@ impl<'a, 'tcx> dot::Labeller<'a, Node, Edge> for ConstraintGraph<'a, 'tcx> {
171193
}
172194
}
173195
fn edge_label(&self, e: &Edge) -> dot::LabelText {
174-
dot::LabelText::label(format!("{}", self.map.get(e).unwrap().repr(self.tcx)))
196+
match *e {
197+
Edge::Constraint(ref c) =>
198+
dot::LabelText::label(format!("{}", self.map.get(c).unwrap().repr(self.tcx))),
199+
Edge::EnclScope(..) =>
200+
dot::LabelText::label(format!("(enclosed)")),
201+
}
175202
}
176203
}
177204

@@ -186,28 +213,40 @@ fn constraint_to_nodes(c: &Constraint) -> (Node, Node) {
186213
}
187214
}
188215

216+
fn edge_to_nodes(e: &Edge) -> (Node, Node) {
217+
match *e {
218+
Edge::Constraint(ref c) => constraint_to_nodes(c),
219+
Edge::EnclScope(sub, sup) => {
220+
(Node::Region(ty::ReScope(sub)), Node::Region(ty::ReScope(sup)))
221+
}
222+
}
223+
}
224+
189225
impl<'a, 'tcx> dot::GraphWalk<'a, Node, Edge> for ConstraintGraph<'a, 'tcx> {
190226
fn nodes(&self) -> dot::Nodes<Node> {
191227
let mut set = FnvHashSet::new();
192-
for constraint in self.map.keys() {
193-
let (n1, n2) = constraint_to_nodes(constraint);
194-
set.insert(n1);
195-
set.insert(n2);
228+
for node in self.node_ids.keys() {
229+
set.insert(*node);
196230
}
197231
debug!("constraint graph has {} nodes", set.len());
198232
set.into_iter().collect()
199233
}
200234
fn edges(&self) -> dot::Edges<Edge> {
201235
debug!("constraint graph has {} edges", self.map.len());
202-
self.map.keys().map(|e|*e).collect()
236+
let mut v : Vec<_> = self.map.keys().map(|e| Edge::Constraint(*e)).collect();
237+
self.tcx.region_maps.each_encl_scope(|&mut: sub, sup| {
238+
v.push(Edge::EnclScope(*sub, *sup))
239+
});
240+
debug!("region graph has {} edges", v.len());
241+
Cow::Owned(v)
203242
}
204243
fn source(&self, edge: &Edge) -> Node {
205-
let (n1, _) = constraint_to_nodes(edge);
244+
let (n1, _) = edge_to_nodes(edge);
206245
debug!("edge {:?} has source {:?}", edge, n1);
207246
n1
208247
}
209248
fn target(&self, edge: &Edge) -> Node {
210-
let (_, n2) = constraint_to_nodes(edge);
249+
let (_, n2) = edge_to_nodes(edge);
211250
debug!("edge {:?} has target {:?}", edge, n2);
212251
n2
213252
}

src/librustc/middle/liveness.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1535,7 +1535,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
15351535
let fn_ret =
15361536
ty::liberate_late_bound_regions(
15371537
self.ir.tcx,
1538-
CodeExtent::from_node_id(body.id),
1538+
CodeExtent::DestructionScope(body.id),
15391539
&self.fn_ret(id));
15401540

15411541
match fn_ret {

src/librustc/middle/mem_categorization.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -690,7 +690,10 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> {
690690

691691
// Region of environment pointer
692692
let env_region = ty::ReFree(ty::FreeRegion {
693-
scope: region::CodeExtent::from_node_id(fn_body_id),
693+
// The environment of a closure is guaranteed to
694+
// outlive any bindings introduced in the body of the
695+
// closure itself.
696+
scope: region::CodeExtent::DestructionScope(fn_body_id),
694697
bound_region: ty::BrEnv
695698
});
696699

0 commit comments

Comments
 (0)