Skip to content

Commit 1672c27

Browse files
committed
Improve predecessor detection.
It is necessary to detect whether we are making the first assignment into a union. This is checked by looking at the moves and checking if there are any from locations earlier in the control flow graph. This commit improves the detection of this by switching from a naive method that compared only the statement and basic block indices with a more robust method that looks at the predecessors of a location.
1 parent 8e7786a commit 1672c27

File tree

2 files changed

+39
-6
lines changed

2 files changed

+39
-6
lines changed

src/librustc/mir/mod.rs

+31
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ use mir::interpret::{ConstValue, EvalErrorKind, Scalar};
2020
use mir::visit::MirVisitable;
2121
use rustc_apfloat::ieee::{Double, Single};
2222
use rustc_apfloat::Float;
23+
use rustc_data_structures::fx::FxHashSet;
2324
use rustc_data_structures::graph::dominators::{dominators, Dominators};
2425
use rustc_data_structures::graph::{self, GraphPredecessors, GraphSuccessors};
2526
use rustc_data_structures::indexed_vec::{Idx, IndexVec};
@@ -2706,6 +2707,36 @@ impl Location {
27062707
}
27072708
}
27082709

2710+
/// Returns `true` if `other` is earlier in the control flow graph than `self`.
2711+
pub fn is_predecessor_of<'tcx>(&self, other: Location, mir: &Mir<'tcx>) -> bool {
2712+
// If we are in the same block as the other location and are an earlier statement
2713+
// then we are a predecessor of `other`.
2714+
if self.block == other.block && self.statement_index < other.statement_index {
2715+
return true;
2716+
}
2717+
2718+
// If we're in another block, then we want to check that block is a predecessor of `other`.
2719+
let mut queue: Vec<BasicBlock> = mir.predecessors_for(other.block).clone();
2720+
let mut visited = FxHashSet::default();
2721+
2722+
while let Some(block) = queue.pop() {
2723+
// If we haven't visited this block before, then make sure we visit it's predecessors.
2724+
if visited.insert(block) {
2725+
queue.append(&mut mir.predecessors_for(block).clone());
2726+
} else {
2727+
continue;
2728+
}
2729+
2730+
// If we found the block that `self` is in, then we are a predecessor of `other` (since
2731+
// we found that block by looking at the predecessors of `other`).
2732+
if self.block == block {
2733+
return true;
2734+
}
2735+
}
2736+
2737+
false
2738+
}
2739+
27092740
pub fn dominates(&self, other: Location, dominators: &Dominators<BasicBlock>) -> bool {
27102741
if self.block == other.block {
27112742
self.statement_index <= other.statement_index

src/librustc_mir/borrow_check/mod.rs

+8-6
Original file line numberDiff line numberDiff line change
@@ -1784,12 +1784,14 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
17841784
// of the union - we should error in that case.
17851785
let tcx = this.infcx.tcx;
17861786
if let ty::TyKind::Adt(def, _) = base.ty(this.mir, tcx).to_ty(tcx).sty {
1787-
let moved_before_this = this.move_data.path_map[mpi].iter().any(|moi| {
1788-
this.move_data.moves[*moi].source < context.loc
1789-
});
1790-
1791-
if def.is_union() && moved_before_this {
1792-
return;
1787+
if def.is_union() {
1788+
if this.move_data.path_map[mpi].iter().any(|moi| {
1789+
this.move_data.moves[*moi].source.is_predecessor_of(
1790+
context.loc, this.mir,
1791+
)
1792+
}) {
1793+
return;
1794+
}
17931795
}
17941796
}
17951797

0 commit comments

Comments
 (0)