mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-25 16:24:46 +00:00
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.
This commit is contained in:
commit
1c51e5b110
@ -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.
|
||||
|
@ -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::AfterTerminator(_) => {}
|
||||
|
||||
PassWhere::BeforeBlock(_) | PassWhere::AfterLocation(_) | PassWhere::AfterCFG => {}
|
||||
}
|
||||
Ok(())
|
||||
},
|
||||
options,
|
||||
);
|
||||
|
||||
PassWhere::BeforeLocation(_) => {}
|
||||
|
||||
PassWhere::AfterTerminator(_) => {}
|
||||
|
||||
PassWhere::BeforeBlock(_) | PassWhere::AfterLocation(_) | PassWhere::AfterCFG => {}
|
||||
}
|
||||
Ok(())
|
||||
});
|
||||
|
||||
// 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)?;
|
||||
};
|
||||
}
|
||||
|
@ -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();
|
||||
|
@ -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()
|
||||
});
|
||||
|
@ -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);
|
||||
|
@ -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>
|
||||
@ -77,12 +92,40 @@ pub fn dump_mir<'tcx, F>(
|
||||
extra_data: 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));
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -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)"),
|
||||
|
@ -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 {
|
||||
|
@ -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)];
|
||||
|
@ -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)];
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user