diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs index 21d9eaccf67e7..57ce4933a3b3f 100644 --- a/compiler/rustc_interface/src/tests.rs +++ b/compiler/rustc_interface/src/tests.rs @@ -670,6 +670,7 @@ fn test_unstable_options_tracking_hash() { untracked!(ls, true); untracked!(macro_backtrace, true); untracked!(meta_stats, true); + untracked!(mir_pretty_relative_line_numbers, true); untracked!(nll_facts, true); untracked!(no_analysis, true); untracked!(no_interleave_lints, true); diff --git a/compiler/rustc_middle/src/mir/pretty.rs b/compiler/rustc_middle/src/mir/pretty.rs index 78b5131bac65e..0ce41337b910d 100644 --- a/compiler/rustc_middle/src/mir/pretty.rs +++ b/compiler/rustc_middle/src/mir/pretty.rs @@ -360,7 +360,7 @@ where "{:A$} // {}{}", indented_body, if tcx.sess.verbose() { format!("{:?}: ", current_location) } else { String::new() }, - comment(tcx, statement.source_info), + comment(tcx, statement.source_info, body.span), A = ALIGN, )?; @@ -381,7 +381,7 @@ where "{:A$} // {}{}", indented_terminator, if tcx.sess.verbose() { format!("{:?}: ", current_location) } else { String::new() }, - comment(tcx, data.terminator().source_info), + comment(tcx, data.terminator().source_info, body.span), A = ALIGN, )?; @@ -518,8 +518,14 @@ impl<'tcx> Visitor<'tcx> for ExtraComments<'tcx> { } } -fn comment(tcx: TyCtxt<'_>, SourceInfo { span, scope }: SourceInfo) -> String { - format!("scope {} at {}", scope.index(), tcx.sess.source_map().span_to_embeddable_string(span)) +fn comment(tcx: TyCtxt<'_>, SourceInfo { span, scope }: SourceInfo, function_span: Span) -> String { + let location = if tcx.sess.opts.unstable_opts.mir_pretty_relative_line_numbers { + tcx.sess.source_map().span_to_relative_line_string(span, function_span) + } else { + tcx.sess.source_map().span_to_embeddable_string(span) + }; + + format!("scope {} at {}", scope.index(), location,) } /// Prints local variables in a scope tree. @@ -550,7 +556,7 @@ fn write_scope_tree( "{0:1$} // in {2}", indented_debug_info, ALIGN, - comment(tcx, var_debug_info.source_info), + comment(tcx, var_debug_info.source_info, body.span), )?; } @@ -585,7 +591,7 @@ fn write_scope_tree( indented_decl, ALIGN, local_name, - comment(tcx, local_decl.source_info), + comment(tcx, local_decl.source_info, body.span), )?; } diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index 501997679f4bf..ef314115043b2 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -1379,6 +1379,8 @@ options! { "use like `-Zmir-enable-passes=+DestProp,-InstCombine`. Forces the specified passes to be \ enabled, overriding all other checks. Passes that are not specified are enabled or \ disabled by other flags as usual."), + mir_pretty_relative_line_numbers: bool = (false, parse_bool, [UNTRACKED], + "use line numbers relative to the function in mir pretty printing"), #[cfg_attr(not(bootstrap), rustc_lint_opt_deny_field_access("use `Session::mir_opt_level` instead of this field"))] mir_opt_level: Option = (None, parse_opt_number, [TRACKED], "MIR optimization level (0-4; default: 1 in non optimized builds and 2 in optimized builds)"), diff --git a/compiler/rustc_span/src/source_map.rs b/compiler/rustc_span/src/source_map.rs index 47159584afe3b..28381157d50a9 100644 --- a/compiler/rustc_span/src/source_map.rs +++ b/compiler/rustc_span/src/source_map.rs @@ -463,6 +463,33 @@ impl SourceMap { self.span_to_string(sp, FileNameDisplayPreference::Remapped) } + /// Format the span location suitable for pretty printing anotations with relative line numbers + pub fn span_to_relative_line_string(&self, sp: Span, relative_to: Span) -> String { + if self.files.borrow().source_files.is_empty() || sp.is_dummy() || relative_to.is_dummy() { + return "no-location".to_string(); + } + + let lo = self.lookup_char_pos(sp.lo()); + let hi = self.lookup_char_pos(sp.hi()); + let offset = self.lookup_char_pos(relative_to.lo()); + + if lo.file.name != offset.file.name { + return self.span_to_embeddable_string(sp); + } + + let lo_line = lo.line.saturating_sub(offset.line); + let hi_line = hi.line.saturating_sub(offset.line); + + format!( + "{}:+{}:{}: +{}:{}", + lo.file.name.display(FileNameDisplayPreference::Remapped), + lo_line, + lo.col.to_usize() + 1, + hi_line, + hi.col.to_usize() + 1, + ) + } + /// Format the span location to be printed in diagnostics. Must not be emitted /// to build artifacts as this may leak local file paths. Use span_to_embeddable_string /// for string suitable for embedding. diff --git a/src/test/rustdoc-ui/z-help.stdout b/src/test/rustdoc-ui/z-help.stdout index 86e42440bd0bc..780c0032b6d15 100644 --- a/src/test/rustdoc-ui/z-help.stdout +++ b/src/test/rustdoc-ui/z-help.stdout @@ -76,6 +76,7 @@ -Z meta-stats=val -- gather metadata statistics (default: no) -Z mir-emit-retag=val -- emit Retagging MIR statements, interpreted e.g., by miri; implies -Zmir-opt-level=0 (default: no) -Z mir-enable-passes=val -- use like `-Zmir-enable-passes=+DestProp,-InstCombine`. Forces the specified passes to be enabled, overriding all other checks. Passes that are not specified are enabled or disabled by other flags as usual. + -Z mir-pretty-relative-line-numbers=val -- use line numbers relative to the function in mir pretty printing -Z mir-opt-level=val -- MIR optimization level (0-4; default: 1 in non optimized builds and 2 in optimized builds) -Z move-size-limit=val -- the size at which the `large_assignments` lint starts to be emitted -Z mutable-noalias=val -- emit noalias metadata for mutable references (default: yes) diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index 26730fcec4cec..d3e5a2dd644af 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -1960,6 +1960,7 @@ impl<'test> TestCx<'test> { "-Zdump-mir=all", "-Zvalidate-mir", "-Zdump-mir-exclude-pass-number", + "-Zmir-pretty-relative-line-numbers=yes", ]); if let Some(pass) = &self.props.mir_unit_test { rustc.args(&["-Zmir-opt-level=0", &format!("-Zmir-enable-passes=+{}", pass)]);