diff --git a/src/libcore/slice.rs b/src/libcore/slice.rs index 38e66c5a3d6a2..d99ea607e5db3 100644 --- a/src/libcore/slice.rs +++ b/src/libcore/slice.rs @@ -631,8 +631,14 @@ fn size_from_ptr(_: *const T) -> usize { } -// Use macro to be generic over const/mut -macro_rules! slice_offset { +// Use macros to be generic over const/mut +// +// They require non-negative `$by` because otherwise the expression +// `(ptr as usize + $by)` would interpret `-1` as `usize::MAX` (and +// thus trigger a panic when overflow checks are on). + +// Use this to do `$ptr + $by`, where `$by` is non-negative. +macro_rules! slice_add_offset { ($ptr:expr, $by:expr) => {{ let ptr = $ptr; if size_from_ptr(ptr) == 0 { @@ -643,6 +649,18 @@ macro_rules! slice_offset { }}; } +// Use this to do `$ptr - $by`, where `$by` is non-negative. +macro_rules! slice_sub_offset { + ($ptr:expr, $by:expr) => {{ + let ptr = $ptr; + if size_from_ptr(ptr) == 0 { + transmute(ptr as usize - $by) + } else { + ptr.offset(-$by) + } + }}; +} + macro_rules! slice_ref { ($ptr:expr) => {{ let ptr = $ptr; @@ -672,7 +690,7 @@ macro_rules! iterator { None } else { let old = self.ptr; - self.ptr = slice_offset!(self.ptr, 1); + self.ptr = slice_add_offset!(self.ptr, 1); Some(slice_ref!(old)) } } @@ -714,7 +732,7 @@ macro_rules! iterator { if self.end == self.ptr { None } else { - self.end = slice_offset!(self.end, -1); + self.end = slice_sub_offset!(self.end, 1); Some(slice_ref!(self.end)) } } @@ -816,7 +834,7 @@ impl<'a, T> Iter<'a, T> { fn iter_nth(&mut self, n: usize) -> Option<&'a T> { match self.as_slice().get(n) { Some(elem_ref) => unsafe { - self.ptr = slice_offset!(elem_ref as *const _, 1); + self.ptr = slice_add_offset!(elem_ref as *const _, 1); Some(slice_ref!(elem_ref)) }, None => { @@ -959,7 +977,7 @@ impl<'a, T> IterMut<'a, T> { fn iter_nth(&mut self, n: usize) -> Option<&'a mut T> { match make_mut_slice!(T => &'a mut [T]: self.ptr, self.end).get_mut(n) { Some(elem_ref) => unsafe { - self.ptr = slice_offset!(elem_ref as *mut _, 1); + self.ptr = slice_add_offset!(elem_ref as *mut _, 1); Some(slice_ref!(elem_ref)) }, None => { diff --git a/src/libsyntax/codemap.rs b/src/libsyntax/codemap.rs index 5e0cb647c8b41..1aaec73be4f34 100644 --- a/src/libsyntax/codemap.rs +++ b/src/libsyntax/codemap.rs @@ -667,9 +667,22 @@ impl CodeMap { self.lookup_char_pos(sp.lo).file.name.to_string() } - pub fn span_to_lines(&self, sp: Span) -> FileLines { + pub fn span_to_lines(&self, sp: Span) -> FileLinesResult { + if sp.lo > sp.hi { + return Err(SpanLinesError::IllFormedSpan(sp)); + } + let lo = self.lookup_char_pos(sp.lo); let hi = self.lookup_char_pos(sp.hi); + + if lo.file.start_pos != hi.file.start_pos { + return Err(SpanLinesError::DistinctSources(DistinctSources { + begin: (lo.file.name.clone(), lo.file.start_pos), + end: (hi.file.name.clone(), hi.file.start_pos), + })); + } + assert!(hi.line >= lo.line); + let mut lines = Vec::with_capacity(hi.line - lo.line + 1); // The span starts partway through the first line, @@ -693,7 +706,7 @@ impl CodeMap { start_col: start_col, end_col: hi.col }); - FileLines {file: lo.file, lines: lines} + Ok(FileLines {file: lo.file, lines: lines}) } pub fn span_to_snippet(&self, sp: Span) -> Result { @@ -918,9 +931,17 @@ impl CodeMap { } // _____________________________________________________________________________ -// SpanSnippetError, DistinctSources, MalformedCodemapPositions +// SpanLinesError, SpanSnippetError, DistinctSources, MalformedCodemapPositions // +pub type FileLinesResult = Result; + +#[derive(Clone, PartialEq, Eq, Debug)] +pub enum SpanLinesError { + IllFormedSpan(Span), + DistinctSources(DistinctSources), +} + #[derive(Clone, PartialEq, Eq, Debug)] pub enum SpanSnippetError { IllFormedSpan(Span), @@ -1086,7 +1107,7 @@ mod tests { // Test span_to_lines for a span ending at the end of filemap let cm = init_code_map(); let span = Span {lo: BytePos(12), hi: BytePos(23), expn_id: NO_EXPANSION}; - let file_lines = cm.span_to_lines(span); + let file_lines = cm.span_to_lines(span).unwrap(); assert_eq!(file_lines.file.name, "blork.rs"); assert_eq!(file_lines.lines.len(), 1); @@ -1131,7 +1152,7 @@ mod tests { assert_eq!(&cm.span_to_snippet(span).unwrap(), "BB\nCCC\nDDDDD"); // check that span_to_lines gives us the complete result with the lines/cols we expected - let lines = cm.span_to_lines(span); + let lines = cm.span_to_lines(span).unwrap(); let expected = vec![ LineInfo { line_index: 1, start_col: CharPos(4), end_col: CharPos(6) }, LineInfo { line_index: 2, start_col: CharPos(0), end_col: CharPos(3) }, diff --git a/src/libsyntax/diagnostic.rs b/src/libsyntax/diagnostic.rs index a7453636c445c..aa649b4d99ac5 100644 --- a/src/libsyntax/diagnostic.rs +++ b/src/libsyntax/diagnostic.rs @@ -522,7 +522,7 @@ fn highlight_suggestion(err: &mut EmitterWriter, suggestion: &str) -> io::Result<()> { - let lines = cm.span_to_lines(sp); + let lines = cm.span_to_lines(sp).unwrap(); assert!(!lines.lines.is_empty()); // To build up the result, we want to take the snippet from the first @@ -567,9 +567,17 @@ fn highlight_lines(err: &mut EmitterWriter, cm: &codemap::CodeMap, sp: Span, lvl: Level, - lines: codemap::FileLines) + lines: codemap::FileLinesResult) -> io::Result<()> { + let lines = match lines { + Ok(lines) => lines, + Err(_) => { + try!(write!(&mut err.dst, "(internal compiler error: unprintable span)\n")); + return Ok(()); + } + }; + let fm = &*lines.file; let line_strings: Option> = @@ -690,8 +698,16 @@ fn end_highlight_lines(w: &mut EmitterWriter, cm: &codemap::CodeMap, sp: Span, lvl: Level, - lines: codemap::FileLines) + lines: codemap::FileLinesResult) -> io::Result<()> { + let lines = match lines { + Ok(lines) => lines, + Err(_) => { + try!(write!(&mut w.dst, "(internal compiler error: unprintable span)\n")); + return Ok(()); + } + }; + let fm = &*lines.file; let lines = &lines.lines[..];