Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

avoid IdxSets containing garbage above the universe length #49570

Merged
merged 1 commit into from
Apr 5, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
74 changes: 73 additions & 1 deletion src/librustc_data_structures/indexed_set.rs
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,9 @@ impl<T: Idx> IdxSetBuf<T> {

/// Creates set holding every element whose index falls in range 0..universe_size.
pub fn new_filled(universe_size: usize) -> Self {
Self::new(!0, universe_size)
let mut result = Self::new(!0, universe_size);
result.trim_to(universe_size);
result
}

/// Creates set holding no elements.
Expand Down Expand Up @@ -168,6 +170,36 @@ impl<T: Idx> IdxSet<T> {
}
}

/// Sets all elements up to `universe_size`
pub fn set_up_to(&mut self, universe_size: usize) {
for b in &mut self.bits {
*b = !0;
}
self.trim_to(universe_size);
}

/// Clear all elements above `universe_size`.
fn trim_to(&mut self, universe_size: usize) {
let word_bits = mem::size_of::<Word>() * 8;

// `trim_block` is the first block where some bits have
// to be cleared.
let trim_block = universe_size / word_bits;

// all the blocks above it have to be completely cleared.
if trim_block < self.bits.len() {
for b in &mut self.bits[trim_block+1..] {
*b = 0;
}

// at that block, the `universe_size % word_bits` lsbs
// should remain.
let remaining_bits = universe_size % word_bits;
let mask = (1<<remaining_bits)-1;
self.bits[trim_block] &= mask;
}
}

/// Removes `elem` from the set `self`; returns true iff this changed `self`.
pub fn remove(&mut self, elem: &T) -> bool {
self.bits.clear_bit(elem.index())
Expand Down Expand Up @@ -252,3 +284,43 @@ impl<'a, T: Idx> Iterator for Iter<'a, T> {
}
}
}

#[test]
fn test_trim_to() {
use std::cmp;

for i in 0..256 {
let mut idx_buf: IdxSetBuf<usize> = IdxSetBuf::new_filled(128);
idx_buf.trim_to(i);

let elems: Vec<usize> = idx_buf.iter().collect();
let expected: Vec<usize> = (0..cmp::min(i, 128)).collect();
assert_eq!(elems, expected);
}
}

#[test]
fn test_set_up_to() {
for i in 0..128 {
for mut idx_buf in
vec![IdxSetBuf::new_empty(128), IdxSetBuf::new_filled(128)]
.into_iter()
{
idx_buf.set_up_to(i);

let elems: Vec<usize> = idx_buf.iter().collect();
let expected: Vec<usize> = (0..i).collect();
assert_eq!(elems, expected);
}
}
}

#[test]
fn test_new_filled() {
for i in 0..128 {
let mut idx_buf = IdxSetBuf::new_filled(i);
let elems: Vec<usize> = idx_buf.iter().collect();
let expected: Vec<usize> = (0..i).collect();
assert_eq!(elems, expected);
}
}
4 changes: 2 additions & 2 deletions src/librustc_mir/dataflow/impls/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -389,7 +389,7 @@ impl<'a, 'gcx, 'tcx> BitDenotation for MaybeUninitializedPlaces<'a, 'gcx, 'tcx>
// sets on_entry bits for Arg places
fn start_block_effect(&self, entry_set: &mut IdxSet<MovePathIndex>) {
// set all bits to 1 (uninit) before gathering counterevidence
for e in entry_set.words_mut() { *e = !0; }
entry_set.set_up_to(self.bits_per_block());

drop_flag_effects_for_function_entry(
self.tcx, self.mir, self.mdpe,
Expand Down Expand Up @@ -443,7 +443,7 @@ impl<'a, 'gcx, 'tcx> BitDenotation for DefinitelyInitializedPlaces<'a, 'gcx, 'tc

// sets on_entry bits for Arg places
fn start_block_effect(&self, entry_set: &mut IdxSet<MovePathIndex>) {
for e in entry_set.words_mut() { *e = 0; }
entry_set.clear();

drop_flag_effects_for_function_entry(
self.tcx, self.mir, self.mdpe,
Expand Down