From 9046a9343bbf298cf835a6b4189827fffae38eb3 Mon Sep 17 00:00:00 2001 From: Rich Kadel Date: Thu, 3 Sep 2020 20:31:18 -0700 Subject: [PATCH] Improved the MIR spanview output * Adds missing "tail" spans (spans that continue beyond the end of overlapping spans) * Adds a caret to highlight empty spans associated with MIR elements that have a position, but otherwise would not be visible. * Adds visual pointing brackets at the beginning and end of each span --- .../src/transform/instrument_coverage.rs | 2 +- compiler/rustc_mir/src/util/spanview.rs | 379 +++++++++++---- .../spanview_block.main.mir_map.0.html | 6 +- .../spanview_statement.main.mir_map.0.html | 8 +- .../spanview_terminator.main.mir_map.0.html | 6 +- ...lse.main.-------.InstrumentCoverage.0.html | 449 +++++++++++++----- ...lse.main.-------.InstrumentCoverage.0.html | 449 +++++++++++++----- 7 files changed, 980 insertions(+), 319 deletions(-) diff --git a/compiler/rustc_mir/src/transform/instrument_coverage.rs b/compiler/rustc_mir/src/transform/instrument_coverage.rs index d3a2bd241230e..8f43df8a6cbd1 100644 --- a/compiler/rustc_mir/src/transform/instrument_coverage.rs +++ b/compiler/rustc_mir/src/transform/instrument_coverage.rs @@ -309,7 +309,7 @@ impl<'a, 'tcx> Instrumentor<'a, 'tcx> { for coverage_region in coverage_regions { span_viewables.push(SpanViewable { span: coverage_region.span, - title: format!("{}", coverage_region.blocks[0].index()), + id: format!("{}", coverage_region.blocks[0].index()), tooltip: self.make_tooltip_text(coverage_region), }); } diff --git a/compiler/rustc_mir/src/util/spanview.rs b/compiler/rustc_mir/src/util/spanview.rs index b2f2b5fc1e6f4..fe33fffe0ead1 100644 --- a/compiler/rustc_mir/src/util/spanview.rs +++ b/compiler/rustc_mir/src/util/spanview.rs @@ -3,13 +3,16 @@ use rustc_middle::hir; use rustc_middle::mir::*; use rustc_middle::ty::TyCtxt; use rustc_session::config::MirSpanview; -use rustc_span::{BytePos, Pos, Span}; +use rustc_span::{BytePos, Pos, Span, SyntaxContext}; +use std::cmp; use std::io::{self, Write}; -use std::iter::Peekable; pub const TOOLTIP_INDENT: &str = " "; +const CARET: char = '\u{2038}'; // Unicode `CARET` +const ANNOTATION_LEFT_BRACKET: char = '\u{298a}'; // Unicode `Z NOTATION RIGHT BINDING BRACKET +const ANNOTATION_RIGHT_BRACKET: char = '\u{2989}'; // Unicode `Z NOTATION LEFT BINDING BRACKET` const NEW_LINE_SPAN: &str = "\n"; const HEADER: &str = r#" @@ -80,7 +83,7 @@ const FOOTER: &str = r#" /// Metadata to highlight the span of a MIR BasicBlock, Statement, or Terminator. pub struct SpanViewable { pub span: Span, - pub title: String, + pub id: String, pub tooltip: String, } @@ -139,16 +142,22 @@ where W: Write, { let fn_span = fn_span(tcx, def_id); - writeln!(w, "{}", HEADER)?; - let mut next_pos = fn_span.lo(); + let mut from_pos = fn_span.lo(); let end_pos = fn_span.hi(); let source_map = tcx.sess.source_map(); - let start = source_map.lookup_char_pos(next_pos); + let start = source_map.lookup_char_pos(from_pos); + let indent_to_initial_start_col = " ".repeat(start.col.to_usize()); + debug!( + "fn_span source is:\n{}{}", + indent_to_initial_start_col, + source_map.span_to_snippet(fn_span).expect("function should have printable source") + ); + writeln!(w, "{}", HEADER)?; write!( w, r#"
{}"#, start.line - 1, - " ".repeat(start.col.to_usize()) + indent_to_initial_start_col, )?; span_viewables.sort_unstable_by(|a, b| { let a = a.span; @@ -163,14 +172,43 @@ where } .unwrap() }); - let mut ordered_span_viewables = span_viewables.iter().peekable(); + let mut ordered_viewables = &span_viewables[..]; + const LOWEST_VIEWABLE_LAYER: usize = 1; let mut alt = false; - while ordered_span_viewables.peek().is_some() { - next_pos = write_span_viewables(tcx, next_pos, &mut ordered_span_viewables, false, 1, w)?; - alt = !alt; + while ordered_viewables.len() > 0 { + debug!( + "calling write_next_viewable with from_pos={}, end_pos={}, and viewables len={}", + from_pos.to_usize(), + end_pos.to_usize(), + ordered_viewables.len() + ); + let (next_from_pos, next_ordered_viewables) = write_next_viewable_with_overlaps( + tcx, + from_pos, + end_pos, + ordered_viewables, + alt, + LOWEST_VIEWABLE_LAYER, + w, + )?; + debug!( + "DONE calling write_next_viewable, with new from_pos={}, \ + and remaining viewables len={}", + next_from_pos.to_usize(), + next_ordered_viewables.len() + ); + assert!( + from_pos != next_from_pos || ordered_viewables.len() != next_ordered_viewables.len(), + "write_next_viewable_with_overlaps() must make a state change" + ); + from_pos = next_from_pos; + if next_ordered_viewables.len() != ordered_viewables.len() { + ordered_viewables = next_ordered_viewables; + alt = !alt; + } } - if next_pos < end_pos { - write_coverage_gap(tcx, next_pos, end_pos, w)?; + if from_pos < end_pos { + write_coverage_gap(tcx, from_pos, end_pos, w)?; } write!(w, r#"
"#)?; writeln!(w, "{}", FOOTER)?; @@ -233,9 +271,9 @@ fn statement_span_viewable<'tcx>( if !body_span.contains(span) { return None; } - let title = format!("bb{}[{}]", bb.index(), i); - let tooltip = tooltip(tcx, &title, span, vec![statement.clone()], &None); - Some(SpanViewable { span, title, tooltip }) + let id = format!("{}[{}]", bb.index(), i); + let tooltip = tooltip(tcx, &id, span, vec![statement.clone()], &None); + Some(SpanViewable { span, id, tooltip }) } fn terminator_span_viewable<'tcx>( @@ -249,9 +287,9 @@ fn terminator_span_viewable<'tcx>( if !body_span.contains(span) { return None; } - let title = format!("bb{}`{}`", bb.index(), terminator_kind_name(term)); - let tooltip = tooltip(tcx, &title, span, vec![], &data.terminator); - Some(SpanViewable { span, title, tooltip }) + let id = format!("{}:{}", bb.index(), terminator_kind_name(term)); + let tooltip = tooltip(tcx, &id, span, vec![], &data.terminator); + Some(SpanViewable { span, id, tooltip }) } fn block_span_viewable<'tcx>( @@ -264,16 +302,16 @@ fn block_span_viewable<'tcx>( if !body_span.contains(span) { return None; } - let title = format!("bb{}", bb.index()); - let tooltip = tooltip(tcx, &title, span, data.statements.clone(), &data.terminator); - Some(SpanViewable { span, title, tooltip }) + let id = format!("{}", bb.index()); + let tooltip = tooltip(tcx, &id, span, data.statements.clone(), &data.terminator); + Some(SpanViewable { span, id, tooltip }) } fn compute_block_span<'tcx>(data: &BasicBlockData<'tcx>, body_span: Span) -> Span { let mut span = data.terminator().source_info.span; for statement_span in data.statements.iter().map(|statement| statement.source_info.span) { - // Only combine Spans from the function's body_span. - if body_span.contains(statement_span) { + // Only combine Spans from the root context, and within the function's body_span. + if statement_span.ctxt() == SyntaxContext::root() && body_span.contains(statement_span) { span = span.to(statement_span); } } @@ -286,100 +324,217 @@ fn compute_block_span<'tcx>(data: &BasicBlockData<'tcx>, body_span: Span) -> Spa /// The `layer` is incremented for each overlap, and the `alt` bool alternates between true /// and false, for each adjacent non-overlapping span. Source code between the spans (code /// that is not in any coverage region) has neutral styling. -fn write_span_viewables<'tcx, 'b, W>( +fn write_next_viewable_with_overlaps<'tcx, 'b, W>( tcx: TyCtxt<'tcx>, - next_pos: BytePos, - ordered_span_viewables: &mut Peekable>, + mut from_pos: BytePos, + mut to_pos: BytePos, + ordered_viewables: &'b [SpanViewable], alt: bool, layer: usize, w: &mut W, -) -> io::Result +) -> io::Result<(BytePos, &'b [SpanViewable])> where W: Write, { - let span_viewable = - ordered_span_viewables.next().expect("ordered_span_viewables should have some"); - if next_pos < span_viewable.span.lo() { - write_coverage_gap(tcx, next_pos, span_viewable.span.lo(), w)?; + let debug_indent = " ".repeat(layer); + let (viewable, mut remaining_viewables) = + ordered_viewables.split_first().expect("ordered_viewables should have some"); + + if from_pos < viewable.span.lo() { + debug!( + "{}advance from_pos to next SpanViewable (from from_pos={} to viewable.span.lo()={} \ + of {:?}), with to_pos={}", + debug_indent, + from_pos.to_usize(), + viewable.span.lo().to_usize(), + viewable.span, + to_pos.to_usize() + ); + let hi = cmp::min(viewable.span.lo(), to_pos); + write_coverage_gap(tcx, from_pos, hi, w)?; + from_pos = hi; + if from_pos < viewable.span.lo() { + debug!( + "{}EARLY RETURN: stopped before getting to next SpanViewable, at {}", + debug_indent, + from_pos.to_usize() + ); + return Ok((from_pos, ordered_viewables)); + } } - let mut remaining_span = span_viewable.span; + + if from_pos < viewable.span.hi() { + // Set to_pos to the end of this `viewable` to ensure the recursive calls stop writing + // with room to print the tail. + to_pos = cmp::min(viewable.span.hi(), to_pos); + debug!( + "{}update to_pos (if not closer) to viewable.span.hi()={}; to_pos is now {}", + debug_indent, + viewable.span.hi().to_usize(), + to_pos.to_usize() + ); + } + let mut subalt = false; - loop { - let next_span_viewable = match ordered_span_viewables.peek() { - None => break, - Some(span_viewable) => *span_viewable, + while remaining_viewables.len() > 0 && remaining_viewables[0].span.overlaps(viewable.span) { + let overlapping_viewable = &remaining_viewables[0]; + debug!("{}overlapping_viewable.span={:?}", debug_indent, overlapping_viewable.span); + + let span = + trim_span(viewable.span, from_pos, cmp::min(overlapping_viewable.span.lo(), to_pos)); + let mut some_html_snippet = if from_pos <= viewable.span.hi() || viewable.span.is_empty() { + // `viewable` is not yet fully rendered, so start writing the span, up to either the + // `to_pos` or the next `overlapping_viewable`, whichever comes first. + debug!( + "{}make html_snippet (may not write it if early exit) for partial span {:?} \ + of viewable.span {:?}", + debug_indent, span, viewable.span + ); + from_pos = span.hi(); + make_html_snippet(tcx, span, Some(&viewable)) + } else { + None }; - if !next_span_viewable.span.overlaps(remaining_span) { - break; + + // Defer writing the HTML snippet (until after early return checks) ONLY for empty spans. + // An empty Span with Some(html_snippet) is probably a tail marker. If there is an early + // exit, there should be another opportunity to write the tail marker. + if !span.is_empty() { + if let Some(ref html_snippet) = some_html_snippet { + debug!( + "{}write html_snippet for that partial span of viewable.span {:?}", + debug_indent, viewable.span + ); + write_span(html_snippet, &viewable.tooltip, alt, layer, w)?; + } + some_html_snippet = None; } - write_span( - tcx, - remaining_span.until(next_span_viewable.span), - Some(span_viewable), - alt, - layer, - w, - )?; - let next_pos = write_span_viewables( + + if from_pos < overlapping_viewable.span.lo() { + debug!( + "{}EARLY RETURN: from_pos={} has not yet reached the \ + overlapping_viewable.span {:?}", + debug_indent, + from_pos.to_usize(), + overlapping_viewable.span + ); + // must have reached `to_pos` before reaching the start of the + // `overlapping_viewable.span` + return Ok((from_pos, ordered_viewables)); + } + + if from_pos == to_pos + && !(from_pos == overlapping_viewable.span.lo() && overlapping_viewable.span.is_empty()) + { + debug!( + "{}EARLY RETURN: from_pos=to_pos={} and overlapping_viewable.span {:?} is not \ + empty, or not from_pos", + debug_indent, + to_pos.to_usize(), + overlapping_viewable.span + ); + // `to_pos` must have occurred before the overlapping viewable. Return + // `ordered_viewables` so we can continue rendering the `viewable`, from after the + // `to_pos`. + return Ok((from_pos, ordered_viewables)); + } + + if let Some(ref html_snippet) = some_html_snippet { + debug!( + "{}write html_snippet for that partial span of viewable.span {:?}", + debug_indent, viewable.span + ); + write_span(html_snippet, &viewable.tooltip, alt, layer, w)?; + } + + debug!( + "{}recursively calling write_next_viewable with from_pos={}, to_pos={}, \ + and viewables len={}", + debug_indent, + from_pos.to_usize(), + to_pos.to_usize(), + remaining_viewables.len() + ); + // Write the overlaps (and the overlaps' overlaps, if any) up to `to_pos`. + let (next_from_pos, next_remaining_viewables) = write_next_viewable_with_overlaps( tcx, - next_span_viewable.span.lo(), - ordered_span_viewables, + from_pos, + to_pos, + &remaining_viewables, subalt, layer + 1, w, )?; - subalt = !subalt; - if next_pos < remaining_span.hi() { - remaining_span = remaining_span.with_lo(next_pos); - } else { - return Ok(next_pos); + debug!( + "{}DONE recursively calling write_next_viewable, with new from_pos={}, and remaining \ + viewables len={}", + debug_indent, + next_from_pos.to_usize(), + next_remaining_viewables.len() + ); + assert!( + from_pos != next_from_pos + || remaining_viewables.len() != next_remaining_viewables.len(), + "write_next_viewable_with_overlaps() must make a state change" + ); + from_pos = next_from_pos; + if next_remaining_viewables.len() != remaining_viewables.len() { + remaining_viewables = next_remaining_viewables; + subalt = !subalt; + } + } + if from_pos <= viewable.span.hi() { + let span = trim_span(viewable.span, from_pos, to_pos); + debug!( + "{}After overlaps, writing (end span?) {:?} of viewable.span {:?}", + debug_indent, span, viewable.span + ); + if let Some(ref html_snippet) = make_html_snippet(tcx, span, Some(&viewable)) { + from_pos = span.hi(); + write_span(html_snippet, &viewable.tooltip, alt, layer, w)?; } } - write_span(tcx, remaining_span, Some(span_viewable), alt, layer, w) + debug!("{}RETURN: No more overlap", debug_indent); + Ok(( + from_pos, + if from_pos < viewable.span.hi() { ordered_viewables } else { remaining_viewables }, + )) } +#[inline(always)] fn write_coverage_gap<'tcx, W>( tcx: TyCtxt<'tcx>, lo: BytePos, hi: BytePos, w: &mut W, -) -> io::Result +) -> io::Result<()> where W: Write, { - write_span(tcx, Span::with_root_ctxt(lo, hi), None, false, 0, w) + let span = Span::with_root_ctxt(lo, hi); + if let Some(ref html_snippet) = make_html_snippet(tcx, span, None) { + write_span(html_snippet, "", false, 0, w) + } else { + Ok(()) + } } -fn write_span<'tcx, W>( - tcx: TyCtxt<'tcx>, - span: Span, - span_viewable: Option<&SpanViewable>, +fn write_span( + html_snippet: &str, + tooltip: &str, alt: bool, layer: usize, w: &mut W, -) -> io::Result +) -> io::Result<()> where W: Write, { - let source_map = tcx.sess.source_map(); - let snippet = source_map - .span_to_snippet(span) - .unwrap_or_else(|err| bug!("span_to_snippet error for span {:?}: {:?}", span, err)); - let labeled_snippet = if let Some(SpanViewable { title, .. }) = span_viewable { - if span.is_empty() { - format!(r#"@{}"#, title) - } else { - format!(r#"@{}: {}"#, title, escape_html(&snippet)) - } - } else { - snippet - }; - let maybe_alt = if layer > 0 { + let maybe_alt_class = if layer > 0 { if alt { " odd" } else { " even" } } else { "" }; - let maybe_tooltip = if let Some(SpanViewable { tooltip, .. }) = span_viewable { + let maybe_title_attr = if !tooltip.is_empty() { format!(" title=\"{}\"", escape_attr(tooltip)) } else { "".to_owned() @@ -387,32 +542,73 @@ where if layer == 1 { write!(w, "")?; } - for (i, line) in labeled_snippet.lines().enumerate() { + for (i, line) in html_snippet.lines().enumerate() { if i > 0 { write!(w, "{}", NEW_LINE_SPAN)?; } write!( w, r#"{}"#, - maybe_alt, layer, maybe_tooltip, line + maybe_alt_class, layer, maybe_title_attr, line )?; } + // Check for and translate trailing newlines, because `str::lines()` ignores them + if html_snippet.ends_with('\n') { + write!(w, "{}", NEW_LINE_SPAN)?; + } if layer == 1 { write!(w, "")?; } - Ok(span.hi()) + Ok(()) +} + +fn make_html_snippet<'tcx>( + tcx: TyCtxt<'tcx>, + span: Span, + some_viewable: Option<&SpanViewable>, +) -> Option { + let source_map = tcx.sess.source_map(); + let snippet = source_map + .span_to_snippet(span) + .unwrap_or_else(|err| bug!("span_to_snippet error for span {:?}: {:?}", span, err)); + let html_snippet = if let Some(viewable) = some_viewable { + let is_head = span.lo() == viewable.span.lo(); + let is_tail = span.hi() == viewable.span.hi(); + let mut labeled_snippet = if is_head { + format!(r#"{}{}"#, viewable.id, ANNOTATION_LEFT_BRACKET) + } else { + "".to_owned() + }; + if span.is_empty() { + if is_head && is_tail { + labeled_snippet.push(CARET); + } + } else { + labeled_snippet.push_str(&escape_html(&snippet)); + }; + if is_tail { + labeled_snippet.push_str(&format!( + r#"{}{}"#, + ANNOTATION_RIGHT_BRACKET, viewable.id + )); + } + labeled_snippet + } else { + escape_html(&snippet) + }; + if html_snippet.is_empty() { None } else { Some(html_snippet) } } fn tooltip<'tcx>( tcx: TyCtxt<'tcx>, - title: &str, + spanview_id: &str, span: Span, statements: Vec>, terminator: &Option>, ) -> String { let source_map = tcx.sess.source_map(); let mut text = Vec::new(); - text.push(format!("{}: {}:", title, &source_map.span_to_string(span))); + text.push(format!("{}: {}:", spanview_id, &source_map.span_to_string(span))); for statement in statements { let source_range = source_range_no_file(tcx, &statement.source_info.span); text.push(format!( @@ -436,10 +632,25 @@ fn tooltip<'tcx>( text.join("") } +fn trim_span(span: Span, from_pos: BytePos, to_pos: BytePos) -> Span { + trim_span_hi(trim_span_lo(span, from_pos), to_pos) +} + +fn trim_span_lo(span: Span, from_pos: BytePos) -> Span { + if from_pos <= span.lo() { span } else { span.with_lo(cmp::min(span.hi(), from_pos)) } +} + +fn trim_span_hi(span: Span, to_pos: BytePos) -> Span { + if to_pos >= span.hi() { span } else { span.with_hi(cmp::max(span.lo(), to_pos)) } +} + fn fn_span<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> Span { let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.as_local().expect("expected DefId is local")); - tcx.hir().span(hir_id) + let fn_decl_span = tcx.hir().span(hir_id); + let body_span = hir_body(tcx, def_id).value.span; + debug_assert_eq!(fn_decl_span.ctxt(), body_span.ctxt()); + fn_decl_span.to(body_span) } fn hir_body<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> &'tcx rustc_hir::Body<'tcx> { diff --git a/src/test/mir-opt/spanview_block.main.mir_map.0.html b/src/test/mir-opt/spanview_block.main.mir_map.0.html index 7c1b7bc3b84b0..8f6b1307971b6 100644 --- a/src/test/mir-opt/spanview_block.main.mir_map.0.html +++ b/src/test/mir-opt/spanview_block.main.mir_map.0.html @@ -59,9 +59,9 @@ -
fn main() fn main() @bb0: {}@bb2
+ 5:13-5:13: Goto: goto -> bb2">0⦊{}⦉0
2⦊⦉2 diff --git a/src/test/mir-opt/spanview_statement.main.mir_map.0.html b/src/test/mir-opt/spanview_statement.main.mir_map.0.html index f8662a3277a05..072d22473a991 100644 --- a/src/test/mir-opt/spanview_statement.main.mir_map.0.html +++ b/src/test/mir-opt/spanview_statement.main.mir_map.0.html @@ -59,9 +59,9 @@ -
fn main() @bb0[0]: {}@bb0`Goto`@bb2`Return`
+
fn main() 0[0]⦊{}⦉0[0]0:Goto⦊⦉0:Goto2:Return⦊⦉2:Return
diff --git a/src/test/mir-opt/spanview_terminator.main.mir_map.0.html b/src/test/mir-opt/spanview_terminator.main.mir_map.0.html index d0a11a8d2629d..e023f0f8aeac9 100644 --- a/src/test/mir-opt/spanview_terminator.main.mir_map.0.html +++ b/src/test/mir-opt/spanview_terminator.main.mir_map.0.html @@ -59,8 +59,8 @@ -
fn main() {}@bb0`Goto`@bb2`Return`
+
fn main() {}0:Goto⦊⦉0:Goto2:Return⦊⦉2:Return
diff --git a/src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-base/expected_mir_dump.coverage_of_if_else/coverage_of_if_else.main.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-base/expected_mir_dump.coverage_of_if_else/coverage_of_if_else.main.-------.InstrumentCoverage.0.html index faa5d65e7e787..1ea9aba488e77 100644 --- a/src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-base/expected_mir_dump.coverage_of_if_else/coverage_of_if_else.main.-------.InstrumentCoverage.0.html +++ b/src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-base/expected_mir_dump.coverage_of_if_else/coverage_of_if_else.main.-------.InstrumentCoverage.0.html @@ -62,12 +62,12 @@
fn main() { let mut countdown = 0; @22⦊@44⦊@3: if 3⦊if @0: true0⦊true⦉0@3: { + 5:5-7:6: Goto: goto -> bb5"> { countdown = 10; } + 5:5-7:6: Goto: goto -> bb5"> }⦉3⦉4⦉2 - @6 6⦊@99⦊@25: if 25⦊if @5: countdown > 75⦊countdown > 7⦉5@25: { + 9:5-18:6: Goto: goto -> bb28"> { @8: countdown -= 48⦊countdown -= 4⦉8@25: ; + 9:5-18:6: Goto: goto -> bb28">; } else @10: if 10⦊if @7: countdown > 2@10: { + 11:12-18:6: SwitchInt: switchInt(_8) -> [false: bb11, otherwise: bb10]">7⦊countdown > 2⦉7 { @2222⦊@23@21: if 23⦊21⦊if @1414⦊@1515⦊@1616⦊@1313⦊@2020⦊@1212⦊@1818⦊@1919⦊@17: countdown < 1 || countdown > 517⦊countdown < 1 || countdown > 5⦉17⦉19⦉18@12: || countdown != 9@21: { + 12:12-12:42: SwitchInt: switchInt(move _13) -> [false: bb19, otherwise: bb17]"> || countdown != 9⦉12⦉20⦉13⦉16⦉15⦉14 { countdown = 0; @24: } + 15:9-15:23: Assert: assert(!move (_19.1: bool), "attempt to compute `{} - {}` which would overflow", _1, const 5_i32) -> [success: bb25, unwind: bb1]">24⦊}⦉22⦉23⦉21⦉21 countdown -= 5@10: ; + 15:9-15:23: Assert: assert(!move (_19.1: bool), "attempt to compute `{} - {}` which would overflow", _1, const 5_i32) -> [success: bb25, unwind: bb1]"> countdown -= 5⦉24; } else { @2727⦊@11: return; + 17:9-17:15: Goto: goto -> bb27">11⦊return; } }⦉11⦉6⦉9⦉25⦉25⦉25⦉10⦉10⦉10⦉11@27: + 17:9-17:15: Goto: goto -> bb26"> @@ -230,11 +294,11 @@ 51:1-51:2: StorageDead: StorageDead(_1) 17:9-17:15: Goto: goto -> bb26"> @3030⦊@31@29: if 31⦊29⦊if @28: true@29: { + 21:5-23:6: SwitchInt: switchInt(_23) -> [false: bb30, otherwise: bb29]">28⦊true⦉28 { countdown = 10; } }⦉29⦉31⦉30@27: + 17:9-17:15: Goto: goto -> bb26"> @3333⦊@5252⦊@36: if 36⦊if @32: countdown > 732⦊countdown > 7⦉32@36: { + 25:5-34:6: Goto: goto -> bb53"> { @35: countdown -= 435⦊countdown -= 4⦉35@36: ; + 25:5-34:6: Goto: goto -> bb53">; } else @37: if 37⦊if @34: countdown > 2@37: { + 27:12-34:6: SwitchInt: switchInt(_28) -> [false: bb38, otherwise: bb37]">34⦊countdown > 2⦉34 { @4848⦊@5050⦊@49: if 49⦊if @3939⦊@4747⦊@4040⦊@4343⦊@4242⦊@4141⦊@4646⦊@4545⦊@44: countdown < 1 || countdown > 544⦊countdown < 1 || countdown > 5⦉44⦉45⦉46@41: || countdown != 9 || countdown != 9⦉41⦉42⦉43⦉40⦉47⦉39@49: { + 28:9-30:10: Goto: goto -> bb51"> { countdown = 0; @@ -358,13 +459,25 @@ 30:9-30:10: StorageDead: StorageDead(_31) 30:9-30:10: StorageDead: StorageDead(_30) 31:9-31:23: Assign: _39 = CheckedSub(_21, const 5_i32) - 31:9-31:23: Assert: assert(!move (_39.1: bool), "attempt to compute `{} - {}` which would overflow", _21, const 5_i32) -> [success: bb52, unwind: bb1]">@51: } + 31:9-31:23: Assert: assert(!move (_39.1: bool), "attempt to compute `{} - {}` which would overflow", _21, const 5_i32) -> [success: bb52, unwind: bb1]">51⦊}⦉48⦉50⦉49⦉49 countdown -= 5@37: ; + 31:9-31:23: Assert: assert(!move (_39.1: bool), "attempt to compute `{} - {}` which would overflow", _21, const 5_i32) -> [success: bb52, unwind: bb1]"> countdown -= 5⦉51; } else { @38: return; + 33:9-33:15: Goto: goto -> bb27">38⦊return; } + 33:9-33:15: Goto: goto -> bb27"> }⦉33⦉52⦉36⦉36⦉36⦉37⦉37⦉37 @56@5456⦊54⦊@55: if 55⦊if @53: true53⦊true⦉53@55: { + 37:5-39:6: Goto: goto -> bb57"> { countdown = 10; } }⦉55⦉54⦉56@38: + 33:9-33:15: Goto: goto -> bb27"> @61@5861⦊58⦊@77: if 77⦊if @57: countdown > 757⦊countdown > 7⦉57@77: { + 41:5-50:6: Goto: goto -> bb78"> { @60: countdown -= 460⦊countdown -= 4⦉60@77: ; + 41:5-50:6: Goto: goto -> bb78">; } else @62: if 62⦊if @59: countdown > 2@62: { + 43:12-50:6: SwitchInt: switchInt(_47) -> [false: bb63, otherwise: bb62]">59⦊countdown > 2⦉59 { @7575⦊@74@73: if 74⦊73⦊if @6767⦊@6868⦊@6565⦊@7272⦊@6464⦊@6666⦊@6969⦊@7171⦊@70: countdown < 1 || countdown > 570⦊countdown < 1 || countdown > 5⦉70⦉71⦉69@66: || countdown != 9@73: { + 44:12-44:60: Goto: goto -> bb68"> || countdown != 9⦉66⦉64⦉72⦉65⦉68⦉67 { countdown = 0; @76: } + 47:9-47:23: Assert: assert(!move (_58.1: bool), "attempt to compute `{} - {}` which would overflow", _41, const 5_i32) -> [success: bb77, unwind: bb1]">76⦊}⦉75⦉74⦉73⦉73 countdown -= 5@62: ; + 47:9-47:23: Assert: assert(!move (_58.1: bool), "attempt to compute `{} - {}` which would overflow", _41, const 5_i32) -> [success: bb77, unwind: bb1]"> countdown -= 5⦉76; } else { @63: return; + 49:9-49:15: Goto: goto -> bb26">63⦊return; } }⦉61⦉58⦉77⦉77⦉77⦉62⦉62⦉62 +@78: }@26
+ 51:2-51:2: Goto: goto -> bb26">78⦊}⦉78⦉63⦉38⦉2726⦊⦉26 diff --git a/src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-link-dead-code/expected_mir_dump.coverage_of_if_else/coverage_of_if_else.main.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-link-dead-code/expected_mir_dump.coverage_of_if_else/coverage_of_if_else.main.-------.InstrumentCoverage.0.html index faa5d65e7e787..1ea9aba488e77 100644 --- a/src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-link-dead-code/expected_mir_dump.coverage_of_if_else/coverage_of_if_else.main.-------.InstrumentCoverage.0.html +++ b/src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-link-dead-code/expected_mir_dump.coverage_of_if_else/coverage_of_if_else.main.-------.InstrumentCoverage.0.html @@ -62,12 +62,12 @@
fn main() { let mut countdown = 0; @22⦊@44⦊@3: if 3⦊if @0: true0⦊true⦉0@3: { + 5:5-7:6: Goto: goto -> bb5"> { countdown = 10; } + 5:5-7:6: Goto: goto -> bb5"> }⦉3⦉4⦉2 - @6 6⦊@99⦊@25: if 25⦊if @5: countdown > 75⦊countdown > 7⦉5@25: { + 9:5-18:6: Goto: goto -> bb28"> { @8: countdown -= 48⦊countdown -= 4⦉8@25: ; + 9:5-18:6: Goto: goto -> bb28">; } else @10: if 10⦊if @7: countdown > 2@10: { + 11:12-18:6: SwitchInt: switchInt(_8) -> [false: bb11, otherwise: bb10]">7⦊countdown > 2⦉7 { @2222⦊@23@21: if 23⦊21⦊if @1414⦊@1515⦊@1616⦊@1313⦊@2020⦊@1212⦊@1818⦊@1919⦊@17: countdown < 1 || countdown > 517⦊countdown < 1 || countdown > 5⦉17⦉19⦉18@12: || countdown != 9@21: { + 12:12-12:42: SwitchInt: switchInt(move _13) -> [false: bb19, otherwise: bb17]"> || countdown != 9⦉12⦉20⦉13⦉16⦉15⦉14 { countdown = 0; @24: } + 15:9-15:23: Assert: assert(!move (_19.1: bool), "attempt to compute `{} - {}` which would overflow", _1, const 5_i32) -> [success: bb25, unwind: bb1]">24⦊}⦉22⦉23⦉21⦉21 countdown -= 5@10: ; + 15:9-15:23: Assert: assert(!move (_19.1: bool), "attempt to compute `{} - {}` which would overflow", _1, const 5_i32) -> [success: bb25, unwind: bb1]"> countdown -= 5⦉24; } else { @2727⦊@11: return; + 17:9-17:15: Goto: goto -> bb27">11⦊return; } }⦉11⦉6⦉9⦉25⦉25⦉25⦉10⦉10⦉10⦉11@27: + 17:9-17:15: Goto: goto -> bb26"> @@ -230,11 +294,11 @@ 51:1-51:2: StorageDead: StorageDead(_1) 17:9-17:15: Goto: goto -> bb26"> @3030⦊@31@29: if 31⦊29⦊if @28: true@29: { + 21:5-23:6: SwitchInt: switchInt(_23) -> [false: bb30, otherwise: bb29]">28⦊true⦉28 { countdown = 10; } }⦉29⦉31⦉30@27: + 17:9-17:15: Goto: goto -> bb26"> @3333⦊@5252⦊@36: if 36⦊if @32: countdown > 732⦊countdown > 7⦉32@36: { + 25:5-34:6: Goto: goto -> bb53"> { @35: countdown -= 435⦊countdown -= 4⦉35@36: ; + 25:5-34:6: Goto: goto -> bb53">; } else @37: if 37⦊if @34: countdown > 2@37: { + 27:12-34:6: SwitchInt: switchInt(_28) -> [false: bb38, otherwise: bb37]">34⦊countdown > 2⦉34 { @4848⦊@5050⦊@49: if 49⦊if @3939⦊@4747⦊@4040⦊@4343⦊@4242⦊@4141⦊@4646⦊@4545⦊@44: countdown < 1 || countdown > 544⦊countdown < 1 || countdown > 5⦉44⦉45⦉46@41: || countdown != 9 || countdown != 9⦉41⦉42⦉43⦉40⦉47⦉39@49: { + 28:9-30:10: Goto: goto -> bb51"> { countdown = 0; @@ -358,13 +459,25 @@ 30:9-30:10: StorageDead: StorageDead(_31) 30:9-30:10: StorageDead: StorageDead(_30) 31:9-31:23: Assign: _39 = CheckedSub(_21, const 5_i32) - 31:9-31:23: Assert: assert(!move (_39.1: bool), "attempt to compute `{} - {}` which would overflow", _21, const 5_i32) -> [success: bb52, unwind: bb1]">@51: } + 31:9-31:23: Assert: assert(!move (_39.1: bool), "attempt to compute `{} - {}` which would overflow", _21, const 5_i32) -> [success: bb52, unwind: bb1]">51⦊}⦉48⦉50⦉49⦉49 countdown -= 5@37: ; + 31:9-31:23: Assert: assert(!move (_39.1: bool), "attempt to compute `{} - {}` which would overflow", _21, const 5_i32) -> [success: bb52, unwind: bb1]"> countdown -= 5⦉51; } else { @38: return; + 33:9-33:15: Goto: goto -> bb27">38⦊return; } + 33:9-33:15: Goto: goto -> bb27"> }⦉33⦉52⦉36⦉36⦉36⦉37⦉37⦉37 @56@5456⦊54⦊@55: if 55⦊if @53: true53⦊true⦉53@55: { + 37:5-39:6: Goto: goto -> bb57"> { countdown = 10; } }⦉55⦉54⦉56@38: + 33:9-33:15: Goto: goto -> bb27"> @61@5861⦊58⦊@77: if 77⦊if @57: countdown > 757⦊countdown > 7⦉57@77: { + 41:5-50:6: Goto: goto -> bb78"> { @60: countdown -= 460⦊countdown -= 4⦉60@77: ; + 41:5-50:6: Goto: goto -> bb78">; } else @62: if 62⦊if @59: countdown > 2@62: { + 43:12-50:6: SwitchInt: switchInt(_47) -> [false: bb63, otherwise: bb62]">59⦊countdown > 2⦉59 { @7575⦊@74@73: if 74⦊73⦊if @6767⦊@6868⦊@6565⦊@7272⦊@6464⦊@6666⦊@6969⦊@7171⦊@70: countdown < 1 || countdown > 570⦊countdown < 1 || countdown > 5⦉70⦉71⦉69@66: || countdown != 9@73: { + 44:12-44:60: Goto: goto -> bb68"> || countdown != 9⦉66⦉64⦉72⦉65⦉68⦉67 { countdown = 0; @76: } + 47:9-47:23: Assert: assert(!move (_58.1: bool), "attempt to compute `{} - {}` which would overflow", _41, const 5_i32) -> [success: bb77, unwind: bb1]">76⦊}⦉75⦉74⦉73⦉73 countdown -= 5@62: ; + 47:9-47:23: Assert: assert(!move (_58.1: bool), "attempt to compute `{} - {}` which would overflow", _41, const 5_i32) -> [success: bb77, unwind: bb1]"> countdown -= 5⦉76; } else { @63: return; + 49:9-49:15: Goto: goto -> bb26">63⦊return; } }⦉61⦉58⦉77⦉77⦉77⦉62⦉62⦉62 +@78: }@26
+ 51:2-51:2: Goto: goto -> bb26">78⦊}⦉78⦉63⦉38⦉2726⦊⦉26