Split dummy in region inference graph into distinct source and sink nodes.

Why do this: The RegionGraph representation previously conflated all
of the non-variable regions (i.e. the concrete regions such as
lifetime parameters to the current function) into a single dummy node.

A single dummy node leads DFS on a graph `'a -> '_#1 -> '_#0 -> 'b` to
claim that `'_#1` is reachable from `'_#0` (due to `'a` and `'b` being
conflated in the graph representation), which is incorrect (and can
lead to soundness bugs later on in compilation, see #30438).

Splitting the dummy node ensures that DFS will never introduce new
ancestor relationships between nodes for variable regions in the
graph.
This commit is contained in:
Felix S. Klock II 2016-02-06 04:28:20 +01:00
parent e06f6928cb
commit 8801bdb6b0
1 changed files with 10 additions and 3 deletions

View File

@ -1105,7 +1105,14 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> {
for _ in 0..num_vars {
graph.add_node(());
}
let dummy_idx = graph.add_node(());
// Issue #30438: two distinct dummy nodes, one for incoming
// edges (dummy_source) and another for outgoing edges
// (dummy_sink). In `dummy -> a -> b -> dummy`, using one
// dummy node leads one to think (erroneously) there exists a
// path from `b` to `a`. Two dummy nodes sidesteps the issue.
let dummy_source = graph.add_node(());
let dummy_sink = graph.add_node(());
for (constraint, _) in constraints.iter() {
match *constraint {
@ -1115,10 +1122,10 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> {
*constraint);
}
ConstrainRegSubVar(_, b_id) => {
graph.add_edge(dummy_idx, NodeIndex(b_id.index as usize), *constraint);
graph.add_edge(dummy_source, NodeIndex(b_id.index as usize), *constraint);
}
ConstrainVarSubReg(a_id, _) => {
graph.add_edge(NodeIndex(a_id.index as usize), dummy_idx, *constraint);
graph.add_edge(NodeIndex(a_id.index as usize), dummy_sink, *constraint);
}
}
}