diff options
| author | Matthias Krüger <matthias.krueger@famsik.de> | 2024-08-31 14:46:07 +0200 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2024-08-31 14:46:07 +0200 |
| commit | 1c51e5b110a328ffb7d726ae7ce0aa07befd010b (patch) | |
| tree | 8749f17a2b9c5dfefbaa99a4938f5d887d50aaee | |
| parent | ea5bb99c0f4ef142cd548e74b4e6857468385b7a (diff) | |
| parent | dff3d3588d8ba35e4b730384d885c95e31e07953 (diff) | |
| download | rust-1c51e5b110a328ffb7d726ae7ce0aa07befd010b.tar.gz rust-1c51e5b110a328ffb7d726ae7ce0aa07befd010b.zip | |
Rollup merge of #129711 - lqd:nll-mir-dumps, r=compiler-errors
Expand NLL MIR dumps This PR is a first step to clean up and expand NLL MIR dumps: - by restoring the "mir-include-spans" comments which are useful for `-Zdump-mir=nll` - by adding the list of borrows to NLL MIR dumps, where they are introduced in the CFG and in which region Comments in MIR dumps were turned off in #112346, but as shown in #114652 they were still useful for us working with NLL MIR dumps. So this PR pulls `-Z mir-include-spans` into its own options struct, so that passes dumping MIR can override them if need be. The rest of the compiler is not affected, only the "nll" pass dumps have these comments enabled again. The CLI still has priority when specifying the flag, so that we can explicitly turn them off in the `mir-opt` tests to keep blessed dumps easier to work with (which was one of the points of #112346). Then, as part of a couple steps to improve NLL/polonius MIR dumps and `.dot` visualizations, I've also added the list of borrows and where they're introduced. I'm doing all this to help debug some polonius scope issues in my prototype location-sensitive analysis :3. I'll probably add member constraints soon.
| -rw-r--r-- | compiler/rustc_borrowck/src/lib.rs | 2 | ||||
| -rw-r--r-- | compiler/rustc_borrowck/src/nll.rs | 94 | ||||
| -rw-r--r-- | compiler/rustc_borrowck/src/region_infer/graphviz.rs | 2 | ||||
| -rw-r--r-- | compiler/rustc_codegen_cranelift/src/base.rs | 5 | ||||
| -rw-r--r-- | compiler/rustc_interface/src/tests.rs | 9 | ||||
| -rw-r--r-- | compiler/rustc_middle/src/mir/pretty.rs | 116 | ||||
| -rw-r--r-- | compiler/rustc_session/src/config.rs | 22 | ||||
| -rw-r--r-- | compiler/rustc_session/src/options.rs | 18 | ||||
| -rw-r--r-- | src/tools/compiletest/src/runtest.rs | 1 | ||||
| -rw-r--r-- | tests/mir-opt/nll/region_subtyping_basic.main.nll.0.32bit.mir | 3 | ||||
| -rw-r--r-- | tests/mir-opt/nll/region_subtyping_basic.main.nll.0.64bit.mir | 3 | ||||
| -rw-r--r-- | tests/mir-opt/storage_ranges.main.nll.0.mir | 3 |
12 files changed, 214 insertions, 64 deletions
diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index bb1aea14693..6c39d730746 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -229,7 +229,7 @@ fn do_mir_borrowck<'tcx>( // Dump MIR results into a file, if that is enabled. This let us // write unit-tests, as well as helping with debugging. - nll::dump_mir_results(&infcx, body, ®ioncx, &opt_closure_req); + nll::dump_nll_mir(&infcx, body, ®ioncx, &opt_closure_req, &borrow_set); // We also have a `#[rustc_regions]` annotation that causes us to dump // information. diff --git a/compiler/rustc_borrowck/src/nll.rs b/compiler/rustc_borrowck/src/nll.rs index af37c028879..5646f56ea37 100644 --- a/compiler/rustc_borrowck/src/nll.rs +++ b/compiler/rustc_borrowck/src/nll.rs @@ -9,6 +9,7 @@ use polonius_engine::{Algorithm, Output}; use rustc_data_structures::fx::FxIndexMap; use rustc_hir::def_id::LocalDefId; use rustc_index::IndexSlice; +use rustc_middle::mir::pretty::{dump_mir_with_options, PrettyPrintMirOptions}; use rustc_middle::mir::{ create_dump_file, dump_enabled, dump_mir, Body, ClosureOutlivesSubject, ClosureRegionRequirements, PassWhere, Promoted, @@ -19,6 +20,7 @@ use rustc_mir_dataflow::impls::MaybeInitializedPlaces; use rustc_mir_dataflow::move_paths::MoveData; use rustc_mir_dataflow::points::DenseLocationMap; use rustc_mir_dataflow::ResultsCursor; +use rustc_session::config::MirIncludeSpans; use rustc_span::symbol::sym; use crate::borrow_set::BorrowSet; @@ -208,52 +210,90 @@ pub(crate) fn compute_regions<'cx, 'tcx>( } } -pub(super) fn dump_mir_results<'tcx>( +/// `-Zdump-mir=nll` dumps MIR annotated with NLL specific information: +/// - free regions +/// - inferred region values +/// - region liveness +/// - inference constraints and their causes +/// +/// As well as graphviz `.dot` visualizations of: +/// - the region constraints graph +/// - the region SCC graph +pub(super) fn dump_nll_mir<'tcx>( infcx: &BorrowckInferCtxt<'tcx>, body: &Body<'tcx>, regioncx: &RegionInferenceContext<'tcx>, closure_region_requirements: &Option<ClosureRegionRequirements<'tcx>>, + borrow_set: &BorrowSet<'tcx>, ) { - if !dump_enabled(infcx.tcx, "nll", body.source.def_id()) { + let tcx = infcx.tcx; + if !dump_enabled(tcx, "nll", body.source.def_id()) { return; } - dump_mir(infcx.tcx, false, "nll", &0, body, |pass_where, out| { - match pass_where { - // Before the CFG, dump out the values for each region variable. - PassWhere::BeforeCFG => { - regioncx.dump_mir(infcx.tcx, out)?; - writeln!(out, "|")?; - - if let Some(closure_region_requirements) = closure_region_requirements { - writeln!(out, "| Free Region Constraints")?; - for_each_region_constraint( - infcx.tcx, - closure_region_requirements, - &mut |msg| writeln!(out, "| {msg}"), - )?; + // We want the NLL extra comments printed by default in NLL MIR dumps (they were removed in + // #112346). Specifying `-Z mir-include-spans` on the CLI still has priority: for example, + // they're always disabled in mir-opt tests to make working with blessed dumps easier. + let options = PrettyPrintMirOptions { + include_extra_comments: matches!( + infcx.tcx.sess.opts.unstable_opts.mir_include_spans, + MirIncludeSpans::On | MirIncludeSpans::Nll + ), + }; + dump_mir_with_options( + tcx, + false, + "nll", + &0, + body, + |pass_where, out| { + match pass_where { + // Before the CFG, dump out the values for each region variable. + PassWhere::BeforeCFG => { + regioncx.dump_mir(tcx, out)?; writeln!(out, "|")?; + + if let Some(closure_region_requirements) = closure_region_requirements { + writeln!(out, "| Free Region Constraints")?; + for_each_region_constraint(tcx, closure_region_requirements, &mut |msg| { + writeln!(out, "| {msg}") + })?; + writeln!(out, "|")?; + } + + if borrow_set.len() > 0 { + writeln!(out, "| Borrows")?; + for (borrow_idx, borrow_data) in borrow_set.iter_enumerated() { + writeln!( + out, + "| {:?}: issued at {:?} in {:?}", + borrow_idx, borrow_data.reserve_location, borrow_data.region + )?; + } + writeln!(out, "|")?; + } } - } - PassWhere::BeforeLocation(_) => {} + PassWhere::BeforeLocation(_) => {} - PassWhere::AfterTerminator(_) => {} + PassWhere::AfterTerminator(_) => {} - PassWhere::BeforeBlock(_) | PassWhere::AfterLocation(_) | PassWhere::AfterCFG => {} - } - Ok(()) - }); + PassWhere::BeforeBlock(_) | PassWhere::AfterLocation(_) | PassWhere::AfterCFG => {} + } + Ok(()) + }, + options, + ); - // Also dump the inference graph constraints as a graphviz file. + // Also dump the region constraint graph as a graphviz file. let _: io::Result<()> = try { - let mut file = create_dump_file(infcx.tcx, "regioncx.all.dot", false, "nll", &0, body)?; + let mut file = create_dump_file(tcx, "regioncx.all.dot", false, "nll", &0, body)?; regioncx.dump_graphviz_raw_constraints(&mut file)?; }; - // Also dump the inference graph constraints as a graphviz file. + // Also dump the region constraint SCC graph as a graphviz file. let _: io::Result<()> = try { - let mut file = create_dump_file(infcx.tcx, "regioncx.scc.dot", false, "nll", &0, body)?; + let mut file = create_dump_file(tcx, "regioncx.scc.dot", false, "nll", &0, body)?; regioncx.dump_graphviz_scc_constraints(&mut file)?; }; } diff --git a/compiler/rustc_borrowck/src/region_infer/graphviz.rs b/compiler/rustc_borrowck/src/region_infer/graphviz.rs index 743864dd535..1936752b63c 100644 --- a/compiler/rustc_borrowck/src/region_infer/graphviz.rs +++ b/compiler/rustc_borrowck/src/region_infer/graphviz.rs @@ -46,7 +46,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { dot::render(&RawConstraints { regioncx: self }, &mut w) } - /// Write out the region constraint graph. + /// Write out the region constraint SCC graph. pub(crate) fn dump_graphviz_scc_constraints(&self, mut w: &mut dyn Write) -> io::Result<()> { let mut nodes_per_scc: IndexVec<ConstraintSccIndex, _> = self.constraint_sccs.all_sccs().map(|_| Vec::new()).collect(); diff --git a/compiler/rustc_codegen_cranelift/src/base.rs b/compiler/rustc_codegen_cranelift/src/base.rs index f1d885bf1bc..4af4b39cc5b 100644 --- a/compiler/rustc_codegen_cranelift/src/base.rs +++ b/compiler/rustc_codegen_cranelift/src/base.rs @@ -44,8 +44,9 @@ pub(crate) fn codegen_fn<'tcx>( let _mir_guard = crate::PrintOnPanic(|| { let mut buf = Vec::new(); with_no_trimmed_paths!({ - rustc_middle::mir::pretty::write_mir_fn(tcx, mir, &mut |_, _| Ok(()), &mut buf) - .unwrap(); + use rustc_middle::mir::pretty; + let options = pretty::PrettyPrintMirOptions::from_cli(tcx); + pretty::write_mir_fn(tcx, mir, &mut |_, _| Ok(()), &mut buf, options).unwrap(); }); String::from_utf8_lossy(&buf).into_owned() }); diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs index 844d8ef02e0..42fed98df01 100644 --- a/compiler/rustc_interface/src/tests.rs +++ b/compiler/rustc_interface/src/tests.rs @@ -12,9 +12,10 @@ use rustc_session::config::{ CollapseMacroDebuginfo, CoverageLevel, CoverageOptions, DebugInfo, DumpMonoStatsFormat, ErrorOutputType, ExternEntry, ExternLocation, Externs, FmtDebug, FunctionReturn, InliningThreshold, Input, InstrumentCoverage, InstrumentXRay, LinkSelfContained, - LinkerPluginLto, LocationDetail, LtoCli, NextSolverConfig, OomStrategy, Options, OutFileName, - OutputType, OutputTypes, PAuthKey, PacRet, Passes, PatchableFunctionEntry, Polonius, - ProcMacroExecutionStrategy, Strip, SwitchWithOptPath, SymbolManglingVersion, WasiExecModel, + LinkerPluginLto, LocationDetail, LtoCli, MirIncludeSpans, NextSolverConfig, OomStrategy, + Options, OutFileName, OutputType, OutputTypes, PAuthKey, PacRet, Passes, + PatchableFunctionEntry, Polonius, ProcMacroExecutionStrategy, Strip, SwitchWithOptPath, + SymbolManglingVersion, WasiExecModel, }; use rustc_session::lint::Level; use rustc_session::search_paths::SearchPath; @@ -705,7 +706,7 @@ fn test_unstable_options_tracking_hash() { untracked!(ls, vec!["all".to_owned()]); untracked!(macro_backtrace, true); untracked!(meta_stats, true); - untracked!(mir_include_spans, true); + untracked!(mir_include_spans, MirIncludeSpans::On); untracked!(nll_facts, true); untracked!(no_analysis, true); untracked!(no_leak_check, true); diff --git a/compiler/rustc_middle/src/mir/pretty.rs b/compiler/rustc_middle/src/mir/pretty.rs index 6785805c27d..9906be60e3e 100644 --- a/compiler/rustc_middle/src/mir/pretty.rs +++ b/compiler/rustc_middle/src/mir/pretty.rs @@ -43,8 +43,23 @@ pub enum PassWhere { AfterTerminator(BasicBlock), } -/// If the session is properly configured, dumps a human-readable -/// representation of the mir into: +/// Cosmetic options for pretty-printing the MIR contents, gathered from the CLI. Each pass can +/// override these when dumping its own specific MIR information with [`dump_mir_with_options`]. +#[derive(Copy, Clone)] +pub struct PrettyPrintMirOptions { + /// Whether to include extra comments, like span info. From `-Z mir-include-spans`. + pub include_extra_comments: bool, +} + +impl PrettyPrintMirOptions { + /// Create the default set of MIR pretty-printing options from the CLI flags. + pub fn from_cli(tcx: TyCtxt<'_>) -> Self { + Self { include_extra_comments: tcx.sess.opts.unstable_opts.mir_include_spans.is_enabled() } + } +} + +/// If the session is properly configured, dumps a human-readable representation of the MIR (with +/// default pretty-printing options) into: /// /// ```text /// rustc.node<node_id>.<pass_num>.<pass_name>.<disambiguator> @@ -78,11 +93,39 @@ pub fn dump_mir<'tcx, F>( ) where F: FnMut(PassWhere, &mut dyn io::Write) -> io::Result<()>, { + dump_mir_with_options( + tcx, + pass_num, + pass_name, + disambiguator, + body, + extra_data, + PrettyPrintMirOptions::from_cli(tcx), + ); +} + +/// If the session is properly configured, dumps a human-readable representation of the MIR, with +/// the given [pretty-printing options][PrettyPrintMirOptions]. +/// +/// See [`dump_mir`] for more details. +/// +#[inline] +pub fn dump_mir_with_options<'tcx, F>( + tcx: TyCtxt<'tcx>, + pass_num: bool, + pass_name: &str, + disambiguator: &dyn Display, + body: &Body<'tcx>, + extra_data: F, + options: PrettyPrintMirOptions, +) where + F: FnMut(PassWhere, &mut dyn io::Write) -> io::Result<()>, +{ if !dump_enabled(tcx, pass_name, body.source.def_id()) { return; } - dump_matched_mir_node(tcx, pass_num, pass_name, disambiguator, body, extra_data); + dump_matched_mir_node(tcx, pass_num, pass_name, disambiguator, body, extra_data, options); } pub fn dump_enabled(tcx: TyCtxt<'_>, pass_name: &str, def_id: DefId) -> bool { @@ -112,6 +155,7 @@ fn dump_matched_mir_node<'tcx, F>( disambiguator: &dyn Display, body: &Body<'tcx>, mut extra_data: F, + options: PrettyPrintMirOptions, ) where F: FnMut(PassWhere, &mut dyn io::Write) -> io::Result<()>, { @@ -133,7 +177,7 @@ fn dump_matched_mir_node<'tcx, F>( writeln!(file)?; extra_data(PassWhere::BeforeCFG, &mut file)?; write_user_type_annotations(tcx, body, &mut file)?; - write_mir_fn(tcx, body, &mut extra_data, &mut file)?; + write_mir_fn(tcx, body, &mut extra_data, &mut file, options)?; extra_data(PassWhere::AfterCFG, &mut file)?; }; @@ -243,12 +287,15 @@ pub fn create_dump_file<'tcx>( /////////////////////////////////////////////////////////////////////////// // Whole MIR bodies -/// Write out a human-readable textual representation for the given MIR. +/// Write out a human-readable textual representation for the given MIR, with the default +/// [PrettyPrintMirOptions]. pub fn write_mir_pretty<'tcx>( tcx: TyCtxt<'tcx>, single: Option<DefId>, w: &mut dyn io::Write, ) -> io::Result<()> { + let options = PrettyPrintMirOptions::from_cli(tcx); + writeln!(w, "// WARNING: This output format is intended for human consumers only")?; writeln!(w, "// and is subject to change without notice. Knock yourself out.")?; @@ -262,11 +309,11 @@ pub fn write_mir_pretty<'tcx>( } let render_body = |w: &mut dyn io::Write, body| -> io::Result<()> { - write_mir_fn(tcx, body, &mut |_, _| Ok(()), w)?; + write_mir_fn(tcx, body, &mut |_, _| Ok(()), w, options)?; for body in tcx.promoted_mir(def_id) { writeln!(w)?; - write_mir_fn(tcx, body, &mut |_, _| Ok(()), w)?; + write_mir_fn(tcx, body, &mut |_, _| Ok(()), w, options)?; } Ok(()) }; @@ -278,7 +325,7 @@ pub fn write_mir_pretty<'tcx>( writeln!(w, "// MIR FOR CTFE")?; // Do not use `render_body`, as that would render the promoteds again, but these // are shared between mir_for_ctfe and optimized_mir - write_mir_fn(tcx, tcx.mir_for_ctfe(def_id), &mut |_, _| Ok(()), w)?; + write_mir_fn(tcx, tcx.mir_for_ctfe(def_id), &mut |_, _| Ok(()), w, options)?; } else { let instance_mir = tcx.instance_mir(ty::InstanceKind::Item(def_id)); render_body(w, instance_mir)?; @@ -293,14 +340,15 @@ pub fn write_mir_fn<'tcx, F>( body: &Body<'tcx>, extra_data: &mut F, w: &mut dyn io::Write, + options: PrettyPrintMirOptions, ) -> io::Result<()> where F: FnMut(PassWhere, &mut dyn io::Write) -> io::Result<()>, { - write_mir_intro(tcx, body, w)?; + write_mir_intro(tcx, body, w, options)?; for block in body.basic_blocks.indices() { extra_data(PassWhere::BeforeBlock(block), w)?; - write_basic_block(tcx, block, body, extra_data, w)?; + write_basic_block(tcx, block, body, extra_data, w, options)?; if block.index() + 1 != body.basic_blocks.len() { writeln!(w)?; } @@ -321,6 +369,7 @@ fn write_scope_tree( w: &mut dyn io::Write, parent: SourceScope, depth: usize, + options: PrettyPrintMirOptions, ) -> io::Result<()> { let indent = depth * INDENT.len(); @@ -333,7 +382,7 @@ fn write_scope_tree( let indented_debug_info = format!("{0:1$}debug {2:?};", INDENT, indent, var_debug_info); - if tcx.sess.opts.unstable_opts.mir_include_spans { + if options.include_extra_comments { writeln!( w, "{0:1$} // in {2}", @@ -373,7 +422,7 @@ fn write_scope_tree( let local_name = if local == RETURN_PLACE { " return place" } else { "" }; - if tcx.sess.opts.unstable_opts.mir_include_spans { + if options.include_extra_comments { writeln!( w, "{0:1$} //{2} in {3}", @@ -410,7 +459,7 @@ fn write_scope_tree( let indented_header = format!("{0:1$}scope {2}{3} {{", "", indent, child.index(), special); - if tcx.sess.opts.unstable_opts.mir_include_spans { + if options.include_extra_comments { if let Some(span) = span { writeln!( w, @@ -426,7 +475,7 @@ fn write_scope_tree( writeln!(w, "{indented_header}")?; } - write_scope_tree(tcx, body, scope_tree, w, child, depth + 1)?; + write_scope_tree(tcx, body, scope_tree, w, child, depth + 1, options)?; writeln!(w, "{0:1$}}}", "", depth * INDENT.len())?; } @@ -449,10 +498,11 @@ impl Debug for VarDebugInfo<'_> { /// Write out a human-readable textual representation of the MIR's `fn` type and the types of its /// local variables (both user-defined bindings and compiler temporaries). -pub fn write_mir_intro<'tcx>( +fn write_mir_intro<'tcx>( tcx: TyCtxt<'tcx>, body: &Body<'_>, w: &mut dyn io::Write, + options: PrettyPrintMirOptions, ) -> io::Result<()> { write_mir_sig(tcx, body, w)?; writeln!(w, "{{")?; @@ -468,7 +518,7 @@ pub fn write_mir_intro<'tcx>( } } - write_scope_tree(tcx, body, &scope_tree, w, OUTERMOST_SOURCE_SCOPE, 1)?; + write_scope_tree(tcx, body, &scope_tree, w, OUTERMOST_SOURCE_SCOPE, 1, options)?; // Add an empty line before the first block is printed. writeln!(w)?; @@ -651,12 +701,13 @@ pub fn dump_mir_def_ids(tcx: TyCtxt<'_>, single: Option<DefId>) -> Vec<DefId> { // Basic blocks and their parts (statements, terminators, ...) /// Write out a human-readable textual representation for the given basic block. -pub fn write_basic_block<'tcx, F>( +fn write_basic_block<'tcx, F>( tcx: TyCtxt<'tcx>, block: BasicBlock, body: &Body<'tcx>, extra_data: &mut F, w: &mut dyn io::Write, + options: PrettyPrintMirOptions, ) -> io::Result<()> where F: FnMut(PassWhere, &mut dyn io::Write) -> io::Result<()>, @@ -672,7 +723,7 @@ where for statement in &data.statements { extra_data(PassWhere::BeforeLocation(current_location), w)?; let indented_body = format!("{INDENT}{INDENT}{statement:?};"); - if tcx.sess.opts.unstable_opts.mir_include_spans { + if options.include_extra_comments { writeln!( w, "{:A$} // {}{}", @@ -689,9 +740,14 @@ where writeln!(w, "{indented_body}")?; } - write_extra(tcx, w, |visitor| { - visitor.visit_statement(statement, current_location); - })?; + write_extra( + tcx, + w, + |visitor| { + visitor.visit_statement(statement, current_location); + }, + options, + )?; extra_data(PassWhere::AfterLocation(current_location), w)?; @@ -701,7 +757,7 @@ where // Terminator at the bottom. extra_data(PassWhere::BeforeLocation(current_location), w)?; let indented_terminator = format!("{0}{0}{1:?};", INDENT, data.terminator().kind); - if tcx.sess.opts.unstable_opts.mir_include_spans { + if options.include_extra_comments { writeln!( w, "{:A$} // {}{}", @@ -718,9 +774,14 @@ where writeln!(w, "{indented_terminator}")?; } - write_extra(tcx, w, |visitor| { - visitor.visit_terminator(data.terminator(), current_location); - })?; + write_extra( + tcx, + w, + |visitor| { + visitor.visit_terminator(data.terminator(), current_location); + }, + options, + )?; extra_data(PassWhere::AfterLocation(current_location), w)?; extra_data(PassWhere::AfterTerminator(block), w)?; @@ -1271,11 +1332,12 @@ fn write_extra<'tcx, F>( tcx: TyCtxt<'tcx>, write: &mut dyn io::Write, mut visit_op: F, + options: PrettyPrintMirOptions, ) -> io::Result<()> where F: FnMut(&mut ExtraComments<'tcx>), { - if tcx.sess.opts.unstable_opts.mir_include_spans { + if options.include_extra_comments { let mut extra_comments = ExtraComments { tcx, comments: vec![] }; visit_op(&mut extra_comments); for comment in extra_comments.comments { @@ -1890,7 +1952,7 @@ pub(crate) fn pretty_print_const_value<'tcx>( /////////////////////////////////////////////////////////////////////////// // Miscellaneous -/// Calc converted u64 decimal into hex and return it's length in chars +/// Calc converted u64 decimal into hex and return its length in chars. /// /// ```ignore (cannot-test-private-function) /// assert_eq!(1, hex_number_length(0)); diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index fbdb3cb1534..945bab6887e 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -3369,3 +3369,25 @@ pub enum FunctionReturn { /// Replace returns with jumps to thunk, without emitting the thunk. ThunkExtern, } + +/// Whether extra span comments are included when dumping MIR, via the `-Z mir-include-spans` flag. +/// By default, only enabled in the NLL MIR dumps, and disabled in all other passes. +#[derive(Clone, Copy, Default, PartialEq, Debug)] +pub enum MirIncludeSpans { + Off, + On, + /// Default: include extra comments in NLL MIR dumps only. Can be ignored and considered as + /// `Off` in all other cases. + #[default] + Nll, +} + +impl MirIncludeSpans { + /// Unless opting into extra comments for all passes, they can be considered disabled. + /// The cases where a distinction between on/off and a per-pass value can exist will be handled + /// in the passes themselves: i.e. the `Nll` value is considered off for all intents and + /// purposes, except for the NLL MIR dump pass. + pub fn is_enabled(self) -> bool { + self == MirIncludeSpans::On + } +} diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index 4492ad09357..37077901e0c 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -445,6 +445,8 @@ mod desc { pub const parse_llvm_module_flag: &str = "<key>:<type>:<value>:<behavior>. Type must currently be `u32`. Behavior should be one of (`error`, `warning`, `require`, `override`, `append`, `appendunique`, `max`, `min`)"; pub const parse_function_return: &str = "`keep` or `thunk-extern`"; pub const parse_wasm_c_abi: &str = "`legacy` or `spec`"; + pub const parse_mir_include_spans: &str = + "either a boolean (`yes`, `no`, `on`, `off`, etc), or `nll` (default: `nll`)"; } mod parse { @@ -1488,6 +1490,17 @@ mod parse { } true } + + pub(crate) fn parse_mir_include_spans(slot: &mut MirIncludeSpans, v: Option<&str>) -> bool { + *slot = match v { + Some("on" | "yes" | "y" | "true") | None => MirIncludeSpans::On, + Some("off" | "no" | "n" | "false") => MirIncludeSpans::Off, + Some("nll") => MirIncludeSpans::Nll, + _ => return false, + }; + + true + } } options! { @@ -1848,8 +1861,9 @@ options! { specified passes to be enabled, overriding all other checks. In particular, this will \ enable unsound (known-buggy and hence usually disabled) passes without further warning! \ Passes that are not specified are enabled or disabled by other flags as usual."), - mir_include_spans: bool = (false, parse_bool, [UNTRACKED], - "use line numbers relative to the function in mir pretty printing"), + mir_include_spans: MirIncludeSpans = (MirIncludeSpans::default(), parse_mir_include_spans, [UNTRACKED], + "include extra comments in mir pretty printing, like line numbers and statement indices, \ + details about types, etc. (boolean for all passes, 'nll' to enable in NLL MIR only, default: 'nll')"), mir_keep_place_mention: bool = (false, parse_bool, [TRACKED], "keep place mention MIR statements, interpreted e.g., by miri; implies -Zmir-opt-level=0 \ (default: no)"), diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index eca21e55989..c18f569e528 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -2175,6 +2175,7 @@ impl<'test> TestCx<'test> { "-Zvalidate-mir", "-Zlint-mir", "-Zdump-mir-exclude-pass-number", + "-Zmir-include-spans=false", // remove span comments from NLL MIR dumps "--crate-type=rlib", ]); if let Some(pass) = &self.props.mir_unit_test { diff --git a/tests/mir-opt/nll/region_subtyping_basic.main.nll.0.32bit.mir b/tests/mir-opt/nll/region_subtyping_basic.main.nll.0.32bit.mir index d09a422d408..7294302609a 100644 --- a/tests/mir-opt/nll/region_subtyping_basic.main.nll.0.32bit.mir +++ b/tests/mir-opt/nll/region_subtyping_basic.main.nll.0.32bit.mir @@ -20,6 +20,9 @@ | '?2: '?3 due to Assignment at Single(bb1[0]) ($DIR/region_subtyping_basic.rs:19:13: 19:18 (#0) | '?3: '?4 due to Assignment at Single(bb1[3]) ($DIR/region_subtyping_basic.rs:20:13: 20:14 (#0) | +| Borrows +| bw0: issued at bb1[0] in '?2 +| fn main() -> () { let mut _0: (); let mut _1: [usize; ValTree(Leaf(0x00000003): usize)]; diff --git a/tests/mir-opt/nll/region_subtyping_basic.main.nll.0.64bit.mir b/tests/mir-opt/nll/region_subtyping_basic.main.nll.0.64bit.mir index 4abb5b0b93b..85b89a013c4 100644 --- a/tests/mir-opt/nll/region_subtyping_basic.main.nll.0.64bit.mir +++ b/tests/mir-opt/nll/region_subtyping_basic.main.nll.0.64bit.mir @@ -20,6 +20,9 @@ | '?2: '?3 due to Assignment at Single(bb1[0]) ($DIR/region_subtyping_basic.rs:19:13: 19:18 (#0) | '?3: '?4 due to Assignment at Single(bb1[3]) ($DIR/region_subtyping_basic.rs:20:13: 20:14 (#0) | +| Borrows +| bw0: issued at bb1[0] in '?2 +| fn main() -> () { let mut _0: (); let mut _1: [usize; ValTree(Leaf(0x0000000000000003): usize)]; diff --git a/tests/mir-opt/storage_ranges.main.nll.0.mir b/tests/mir-opt/storage_ranges.main.nll.0.mir index bc2dcfe0a64..ae8cd0c894d 100644 --- a/tests/mir-opt/storage_ranges.main.nll.0.mir +++ b/tests/mir-opt/storage_ranges.main.nll.0.mir @@ -17,6 +17,9 @@ | '?3 live at {bb0[11]} | '?2: '?3 due to Assignment at Single(bb0[10]) ($DIR/storage_ranges.rs:7:17: 7:25 (#0) | +| Borrows +| bw0: issued at bb0[10] in '?2 +| fn main() -> () { let mut _0: (); let _1: i32; |
