diff --git a/.travis.yml b/.travis.yml index 78de5b657e..ef15fa98d3 100644 --- a/.travis.yml +++ b/.travis.yml @@ -16,7 +16,7 @@ script: - | # Test plain miri cargo build --release --features "cargo_miri" && - cargo test --release && + cargo test --release --all && cargo install --features "cargo_miri" - | # Test cargo miri diff --git a/src/librustc_mir/Cargo.toml b/src/librustc_mir/Cargo.toml index 1a64bb8c7c..4189f240c5 100644 --- a/src/librustc_mir/Cargo.toml +++ b/src/librustc_mir/Cargo.toml @@ -8,7 +8,6 @@ version = "0.1.0" workspace = "../.." [lib] -test = false path = "lib.rs" [dependencies] diff --git a/src/librustc_mir/interpret/range_map.rs b/src/librustc_mir/interpret/range_map.rs index 7c8debc270..e4db9b0e0f 100644 --- a/src/librustc_mir/interpret/range_map.rs +++ b/src/librustc_mir/interpret/range_map.rs @@ -1,4 +1,9 @@ -//! Implements a map from disjoint non-empty integer ranges to data associated with those ranges +//! Implements a map from integer indices to data. +//! Rather than storing data for every index, internally, this maps entire ranges to the data. +//! To this end, the APIs all work on ranges, not on individual integers. Ranges are split as +//! necessary (e.g. when [0,5) is first associated with X, and then [1,2) is mutated). +//! Users must not depend on whether a range is coalesced or not, even though this is observable +//! via the iteration APIs. use std::collections::{BTreeMap}; use std::ops; @@ -21,6 +26,7 @@ struct Range { impl Range { fn range(offset: u64, len: u64) -> ops::Range { + assert!(len > 0); // We select all elements that are within // the range given by the offset into the allocation and the length. // This is sound if all ranges that intersect with the argument range, are in the @@ -36,6 +42,7 @@ impl Range { left..right } + /// Tests if all of [offset, offset+len) are contained in this range. fn overlaps(&self, offset: u64, len: u64) -> bool { assert!(len > 0); offset < self.end && offset+len >= self.start @@ -48,6 +55,7 @@ impl RangeMap { } fn iter_with_range<'a>(&'a self, offset: u64, len: u64) -> impl Iterator + 'a { + assert!(len > 0); self.map.range(Range::range(offset, len)) .filter_map(move |(range, data)| { if range.overlaps(offset, len) { @@ -63,7 +71,7 @@ impl RangeMap { } fn split_entry_at(&mut self, offset: u64) where T: Clone { - let range = match self.iter_with_range(offset, 0).next() { + let range = match self.iter_with_range(offset, 1).next() { Some((&range, _)) => range, None => return, }; @@ -88,6 +96,7 @@ impl RangeMap { pub fn iter_mut_with_gaps<'a>(&'a mut self, offset: u64, len: u64) -> impl Iterator + 'a where T: Clone { + assert!(len > 0); // Preparation: Split first and last entry as needed. self.split_entry_at(offset); self.split_entry_at(offset+len); @@ -112,14 +121,15 @@ impl RangeMap { { // Do a first iteration to collect the gaps let mut gaps = Vec::new(); - let mut last_end = None; + let mut last_end = offset; for (range, _) in self.iter_with_range(offset, len) { - if let Some(last_end) = last_end { - if last_end < range.start { - gaps.push(Range { start: last_end, end: range.start }); - } + if last_end < range.start { + gaps.push(Range { start: last_end, end: range.start }); } - last_end = Some(range.end); + last_end = range.end; + } + if last_end < offset+len { + gaps.push(Range { start: last_end, end: offset+len }); } // Add default for all gaps @@ -147,3 +157,43 @@ impl RangeMap { } } } + +#[cfg(test)] +mod tests { + use super::*; + + /// Query the map at every offset in the range and collect the results. + fn to_vec(map: &RangeMap, offset: u64, len: u64) -> Vec { + (offset..offset+len).into_iter().map(|i| *map.iter(i, 1).next().unwrap()).collect() + } + + #[test] + fn basic_insert() { + let mut map = RangeMap::::new(); + // Insert + for x in map.iter_mut(10, 1) { + *x = 42; + } + // Check + assert_eq!(to_vec(&map, 10, 1), vec![42]); + } + + #[test] + fn gaps() { + let mut map = RangeMap::::new(); + for x in map.iter_mut(11, 1) { + *x = 42; + } + for x in map.iter_mut(15, 1) { + *x = 42; + } + + // Now request a range that needs three gaps filled + for x in map.iter_mut(10, 10) { + if *x != 42 { *x = 23; } + } + + assert_eq!(to_vec(&map, 10, 10), vec![23, 42, 23, 23, 23, 42, 23, 23, 23, 23]); + assert_eq!(to_vec(&map, 13, 5), vec![23, 23, 42, 23, 23]); + } +}