From f33d94d88f800ef00a13747a3ee9dda77f6f42d1 Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Thu, 26 Sep 2019 16:24:02 -0700 Subject: [PATCH 1/6] Fix typo in docs --- src/librustc_mir/dataflow/generic.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc_mir/dataflow/generic.rs b/src/librustc_mir/dataflow/generic.rs index 6f598469e9dae..18dd8a0ecbd05 100644 --- a/src/librustc_mir/dataflow/generic.rs +++ b/src/librustc_mir/dataflow/generic.rs @@ -77,7 +77,7 @@ pub trait Analysis<'tcx>: BottomValue { location: Location, ); - /// Updates the current dataflow state with the effect of evaluating a statement. + /// Updates the current dataflow state with the effect of evaluating a terminator. /// /// Note that the effect of a successful return from a `Call` terminator should **not** be /// acounted for in this function. That should go in `apply_call_return_effect`. For example, From 3e88aa20b49fdc7693e253dafc3d782973f05c84 Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Thu, 26 Sep 2019 16:25:27 -0700 Subject: [PATCH 2/6] Allow `ResultsCursor` to borrow the underlying `Results` --- src/librustc_mir/dataflow/generic.rs | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/src/librustc_mir/dataflow/generic.rs b/src/librustc_mir/dataflow/generic.rs index 18dd8a0ecbd05..400f612a0fc9f 100644 --- a/src/librustc_mir/dataflow/generic.rs +++ b/src/librustc_mir/dataflow/generic.rs @@ -180,17 +180,20 @@ impl CursorPosition { } } +type ResultsRefCursor<'a, 'mir, 'tcx, A> = + ResultsCursor<'mir, 'tcx, A, &'a Results<'tcx, A>>; + /// Inspect the results of dataflow analysis. /// /// This cursor has linear performance when visiting statements in a block in order. Visiting /// statements within a block in reverse order is `O(n^2)`, where `n` is the number of statements /// in that block. -pub struct ResultsCursor<'mir, 'tcx, A> +pub struct ResultsCursor<'mir, 'tcx, A, R = Results<'tcx, A>> where A: Analysis<'tcx>, { body: &'mir mir::Body<'tcx>, - results: Results<'tcx, A>, + results: R, state: BitSet, pos: CursorPosition, @@ -202,24 +205,29 @@ where is_call_return_effect_applied: bool, } -impl<'mir, 'tcx, A> ResultsCursor<'mir, 'tcx, A> +impl<'mir, 'tcx, A, R> ResultsCursor<'mir, 'tcx, A, R> where A: Analysis<'tcx>, + R: Borrow>, { /// Returns a new cursor for `results` that points to the start of the `START_BLOCK`. - pub fn new(body: &'mir mir::Body<'tcx>, results: Results<'tcx, A>) -> Self { + pub fn new(body: &'mir mir::Body<'tcx>, results: R) -> Self { ResultsCursor { body, pos: CursorPosition::AtBlockStart(mir::START_BLOCK), is_call_return_effect_applied: false, - state: results.entry_sets[mir::START_BLOCK].clone(), + state: results.borrow().entry_sets[mir::START_BLOCK].clone(), results, } } + pub fn analysis(&self) -> &A { + &self.results.borrow().analysis + } + /// Resets the cursor to the start of the given `block`. pub fn seek_to_block_start(&mut self, block: BasicBlock) { - self.state.overwrite(&self.results.entry_sets[block]); + self.state.overwrite(&self.results.borrow().entry_sets[block]); self.pos = CursorPosition::AtBlockStart(block); self.is_call_return_effect_applied = false; } @@ -275,7 +283,7 @@ where } = &term.kind { if !self.is_call_return_effect_applied { self.is_call_return_effect_applied = true; - self.results.analysis.apply_call_return_effect( + self.results.borrow().analysis.apply_call_return_effect( &mut self.state, target.block, func, @@ -316,7 +324,7 @@ where }; let block_data = &self.body.basic_blocks()[target_block]; - self.results.analysis.apply_partial_block_effect( + self.results.borrow().analysis.apply_partial_block_effect( &mut self.state, target_block, block_data, From d37c3186779e6fcafe216e291ce30d1775ce4cbb Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Thu, 26 Sep 2019 16:26:11 -0700 Subject: [PATCH 3/6] Add graphviz debug output for generic dataflow --- src/librustc_mir/dataflow/generic.rs | 103 ++++- src/librustc_mir/dataflow/generic/graphviz.rs | 412 ++++++++++++++++++ 2 files changed, 510 insertions(+), 5 deletions(-) create mode 100644 src/librustc_mir/dataflow/generic/graphviz.rs diff --git a/src/librustc_mir/dataflow/generic.rs b/src/librustc_mir/dataflow/generic.rs index 400f612a0fc9f..dd6238b80d174 100644 --- a/src/librustc_mir/dataflow/generic.rs +++ b/src/librustc_mir/dataflow/generic.rs @@ -16,16 +16,24 @@ //! [gk]: https://en.wikipedia.org/wiki/Data-flow_analysis#Bit_vector_problems //! [#64566]: https://github.com/rust-lang/rust/pull/64566 +use std::borrow::Borrow; use std::cmp::Ordering; -use std::ops; +use std::ffi::OsString; +use std::path::{Path, PathBuf}; +use std::{fs, io, ops}; +use rustc::hir::def_id::DefId; use rustc::mir::{self, traversal, BasicBlock, Location}; +use rustc::ty::{self, TyCtxt}; +use rustc_data_structures::work_queue::WorkQueue; use rustc_index::bit_set::BitSet; use rustc_index::vec::{Idx, IndexVec}; -use rustc_data_structures::work_queue::WorkQueue; +use syntax::symbol::sym; use crate::dataflow::BottomValue; +mod graphviz; + /// A specific kind of dataflow analysis. /// /// To run a dataflow analysis, one must set the initial state of the `START_BLOCK` via @@ -62,6 +70,13 @@ pub trait Analysis<'tcx>: BottomValue { /// and try to keep it short. const NAME: &'static str; + /// How each element of your dataflow state will be displayed during debugging. + /// + /// By default, this is the `fmt::Debug` representation of `Self::Idx`. + fn pretty_print_idx(&self, w: &mut impl io::Write, idx: Self::Idx) -> io::Result<()> { + write!(w, "{:?}", idx) + } + /// The size of each bitvector allocated for each block. fn bits_per_block(&self, body: &mir::Body<'tcx>) -> usize; @@ -357,7 +372,9 @@ where { analysis: A, bits_per_block: usize, + tcx: TyCtxt<'tcx>, body: &'a mir::Body<'tcx>, + def_id: DefId, dead_unwinds: &'a BitSet, entry_sets: IndexVec>, } @@ -367,7 +384,9 @@ where A: Analysis<'tcx>, { pub fn new( + tcx: TyCtxt<'tcx>, body: &'a mir::Body<'tcx>, + def_id: DefId, dead_unwinds: &'a BitSet, analysis: A, ) -> Self { @@ -385,7 +404,9 @@ where Engine { analysis, bits_per_block, + tcx, body, + def_id, dead_unwinds, entry_sets, } @@ -421,10 +442,26 @@ where ); } - Results { - analysis: self.analysis, - entry_sets: self.entry_sets, + let Engine { + tcx, + body, + def_id, + analysis, + entry_sets, + .. + } = self; + + let results = Results { analysis, entry_sets }; + + let attrs = tcx.get_attrs(def_id); + if let Some(path) = get_dataflow_graphviz_output_path(tcx, attrs, A::NAME) { + let result = write_dataflow_graphviz_results(body, def_id, &path, &results); + if let Err(e) = result { + warn!("Failed to write dataflow results to {}: {}", path.display(), e); + } } + + results } fn propagate_bits_into_graph_successors_of( @@ -518,3 +555,59 @@ where } } } + +/// Looks for attributes like `#[rustc_mir(borrowck_graphviz_postflow="./path/to/suffix.dot")]` and +/// extracts the path with the given analysis name prepended to the suffix. +/// +/// Returns `None` if no such attribute exists. +fn get_dataflow_graphviz_output_path( + tcx: TyCtxt<'tcx>, + attrs: ty::Attributes<'tcx>, + analysis: &str, +) -> Option { + let mut rustc_mir_attrs = attrs + .into_iter() + .filter(|attr| attr.check_name(sym::rustc_mir)) + .flat_map(|attr| attr.meta_item_list().into_iter().flat_map(|v| v.into_iter())); + + let borrowck_graphviz_postflow = rustc_mir_attrs + .find(|attr| attr.check_name(sym::borrowck_graphviz_postflow))?; + + let path_and_suffix = match borrowck_graphviz_postflow.value_str() { + Some(p) => p, + None => { + tcx.sess.span_err( + borrowck_graphviz_postflow.span(), + "borrowck_graphviz_postflow requires a path", + ); + + return None; + } + }; + + // Change "path/suffix.dot" to "path/analysis_name_suffix.dot" + let mut ret = PathBuf::from(path_and_suffix.to_string()); + let suffix = ret.file_name().unwrap(); + + let mut file_name: OsString = analysis.into(); + file_name.push("_"); + file_name.push(suffix); + ret.set_file_name(file_name); + + Some(ret) +} + +fn write_dataflow_graphviz_results>( + body: &mir::Body<'tcx>, + def_id: DefId, + path: &Path, + results: &Results<'tcx, A> +) -> io::Result<()> { + debug!("printing dataflow results for {:?} to {}", def_id, path.display()); + + let mut buf = Vec::new(); + let graphviz = graphviz::Formatter::new(body, def_id, results); + + dot::render(&graphviz, &mut buf)?; + fs::write(path, buf) +} diff --git a/src/librustc_mir/dataflow/generic/graphviz.rs b/src/librustc_mir/dataflow/generic/graphviz.rs new file mode 100644 index 0000000000000..2a08feff9e77a --- /dev/null +++ b/src/librustc_mir/dataflow/generic/graphviz.rs @@ -0,0 +1,412 @@ +use std::cell::RefCell; +use std::io::{self, Write}; +use std::{ops, str}; + +use rustc::hir::def_id::DefId; +use rustc::mir::{self, BasicBlock, Body, Location}; +use rustc_index::bit_set::{BitSet, HybridBitSet}; +use rustc_index::vec::Idx; + +use crate::util::graphviz_safe_def_name; +use super::{Analysis, Results, ResultsRefCursor}; + +pub struct Formatter<'a, 'tcx, A> +where + A: Analysis<'tcx>, +{ + body: &'a Body<'tcx>, + def_id: DefId, + + // This must be behind a `RefCell` because `dot::Labeller` takes `&self`. + block_formatter: RefCell>, +} + +impl Formatter<'a, 'tcx, A> +where + A: Analysis<'tcx>, +{ + pub fn new( + body: &'a Body<'tcx>, + def_id: DefId, + results: &'a Results<'tcx, A>, + ) -> Self { + let block_formatter = BlockFormatter { + bg: Background::Light, + prev_state: BitSet::new_empty(results.analysis.bits_per_block(body)), + results: ResultsRefCursor::new(body, results), + }; + + Formatter { + body, + def_id, + block_formatter: RefCell::new(block_formatter), + } + } +} + +/// A pair of a basic block and an index into that basic blocks `successors`. +#[derive(Copy, Clone, PartialEq, Eq, Debug)] +pub struct CfgEdge { + source: BasicBlock, + index: usize, +} + +fn outgoing_edges(body: &Body<'_>, bb: BasicBlock) -> Vec { + body[bb] + .terminator() + .successors() + .enumerate() + .map(|(index, _)| CfgEdge { source: bb, index }) + .collect() +} + +impl dot::Labeller<'_> for Formatter<'a, 'tcx, A> +where + A: Analysis<'tcx>, +{ + type Node = BasicBlock; + type Edge = CfgEdge; + + fn graph_id(&self) -> dot::Id<'_> { + let name = graphviz_safe_def_name(self.def_id); + dot::Id::new(format!("graph_for_def_id_{}", name)).unwrap() + } + + fn node_id(&self, n: &Self::Node) -> dot::Id<'_> { + dot::Id::new(format!("bb_{}", n.index())).unwrap() + } + + fn node_label(&self, block: &Self::Node) -> dot::LabelText<'_> { + let mut label = Vec::new(); + self.block_formatter + .borrow_mut() + .write_node_label(&mut label, self.body, *block) + .unwrap(); + dot::LabelText::html(String::from_utf8(label).unwrap()) + } + + fn node_shape(&self, _n: &Self::Node) -> Option> { + Some(dot::LabelText::label("none")) + } + + fn edge_label(&self, e: &Self::Edge) -> dot::LabelText<'_> { + let label = &self.body + [e.source] + .terminator() + .kind + .fmt_successor_labels() + [e.index]; + dot::LabelText::label(label.clone()) + } +} + +impl dot::GraphWalk<'a> for Formatter<'a, 'tcx, A> +where + A: Analysis<'tcx>, +{ + type Node = BasicBlock; + type Edge = CfgEdge; + + fn nodes(&self) -> dot::Nodes<'_, Self::Node> { + self.body + .basic_blocks() + .indices() + .collect::>() + .into() + } + + fn edges(&self) -> dot::Edges<'_, Self::Edge> { + self.body + .basic_blocks() + .indices() + .flat_map(|bb| outgoing_edges(self.body, bb)) + .collect::>() + .into() + } + + fn source(&self, edge: &Self::Edge) -> Self::Node { + edge.source + } + + fn target(&self, edge: &Self::Edge) -> Self::Node { + self.body + [edge.source] + .terminator() + .successors() + .nth(edge.index) + .copied() + .unwrap() + } +} + +struct BlockFormatter<'a, 'tcx, A> +where + A: Analysis<'tcx>, +{ + prev_state: BitSet, + results: ResultsRefCursor<'a, 'a, 'tcx, A>, + bg: Background, +} + +impl BlockFormatter<'a, 'tcx, A> +where + A: Analysis<'tcx>, +{ + fn toggle_background(&mut self) -> Background { + let bg = self.bg; + self.bg = !bg; + bg + } + + fn write_node_label( + &mut self, + w: &mut impl io::Write, + body: &'a Body<'tcx>, + block: BasicBlock, + ) -> io::Result<()> { + // Sample output: + // +-+--------------------------------------------------+ + // A | bb4 | + // +-+----------------------------------+---------------+ + // B | MIR | STATE | + // +-+----------------------------------+---------------+ + // C | | (on entry) | {_0,_2,_3} | + // +-+----------------------------------+---------------+ + // D |0| 0: StorageLive(_7) | | + // +-+----------------------------------+---------------+ + // |1| 1: StorageLive(_8) | | + // +-+----------------------------------+---------------+ + // |2| 2: _8 = &mut _1 | +_8 | + // +-+----------------------------------+---------------+ + // E |T| _7 = const Foo::twiddle(move _8) | -_8 | + // +-+----------------------------------+---------------+ + // F | | (on unwind) | {_0,_2,_3,_7} | + // +-+----------------------------------+---------------+ + // | | (on successful return) | +_7 | + // +-+----------------------------------+---------------+ + + write!( + w, + r#""#, + )?; + + // A: Block info + write!( + w, + r#" + + "#, + num_headers = 3, + block_id = block.index(), + )?; + + // B: Column headings + write!( + w, + r#" + + + "#, + fmt = r##"bgcolor="#a0a0a0" sides="tl""##, + )?; + + // C: Entry state + self.results.seek_to_block_start(block); + self.write_row_with_curr_state(w, "", "(on entry)")?; + self.prev_state.overwrite(self.results.get()); + + // D: Statement transfer functions + for (i, statement) in body[block].statements.iter().enumerate() { + let location = Location { block, statement_index: i }; + + let mir_col = format!("{:?}", statement); + let i_col = i.to_string(); + + self.results.seek_after(location); + self.write_row_with_curr_diff(w, &i_col, &mir_col)?; + self.prev_state.overwrite(self.results.get()); + } + + // E: Terminator transfer function + let terminator = body[block].terminator(); + let location = body.terminator_loc(block); + + let mut mir_col = String::new(); + terminator.kind.fmt_head(&mut mir_col).unwrap(); + + self.results.seek_after(location); + self.write_row_with_curr_diff(w, "T", &mir_col)?; + self.prev_state.overwrite(self.results.get()); + + // F: Exit state + if let mir::TerminatorKind::Call { destination: Some(_), .. } = &terminator.kind { + self.write_row_with_curr_state(w, "", "(on unwind)")?; + + self.results.seek_after_assume_call_returns(location); + self.write_row_with_curr_diff(w, "", "(on successful return)")?; + } else { + self.write_row_with_curr_state(w, "", "(on exit)")?; + } + + write!(w, "
bb{block_id}
MIRSTATE
") + } + + fn write_row_with_curr_state( + &mut self, + w: &mut impl io::Write, + i: &str, + mir: &str, + ) -> io::Result<()> { + let bg = self.toggle_background(); + + let mut out = Vec::new(); + write!(&mut out, "{{")?; + pretty_print_state_elems(&mut out, self.results.analysis(), self.results.get().iter())?; + write!(&mut out, "}}")?; + + write!( + w, + r#" + {i} + {mir} + {state} + "#, + fmt = &["sides=\"tl\"", bg.attr()].join(" "), + i = i, + mir = dot::escape_html(mir), + state = dot::escape_html(str::from_utf8(&out).unwrap()), + ) + } + + fn write_row_with_curr_diff( + &mut self, + w: &mut impl io::Write, + i: &str, + mir: &str, + ) -> io::Result<()> { + let bg = self.toggle_background(); + let analysis = self.results.analysis(); + + let diff = BitSetDiff::compute(&self.prev_state, self.results.get()); + + let mut set = Vec::new(); + pretty_print_state_elems(&mut set, analysis, diff.set.iter())?; + + let mut clear = Vec::new(); + pretty_print_state_elems(&mut clear, analysis, diff.clear.iter())?; + + write!( + w, + r#" + {i} + {mir} + "#, + i = i, + fmt = &["sides=\"tl\"", bg.attr()].join(" "), + mir = dot::escape_html(mir), + )?; + + if !set.is_empty() { + write!( + w, + r#"+{}"#, + dot::escape_html(str::from_utf8(&set).unwrap()), + )?; + } + + if !set.is_empty() && !clear.is_empty() { + write!(w, " ")?; + } + + if !clear.is_empty() { + write!( + w, + r#"-{}"#, + dot::escape_html(str::from_utf8(&clear).unwrap()), + )?; + } + + write!(w, "") + } +} + +/// The operations required to transform one `BitSet` into another. +struct BitSetDiff { + set: HybridBitSet, + clear: HybridBitSet, +} + +impl BitSetDiff { + fn compute(from: &BitSet, to: &BitSet) -> Self { + assert_eq!(from.domain_size(), to.domain_size()); + let len = from.domain_size(); + + let mut set = HybridBitSet::new_empty(len); + let mut clear = HybridBitSet::new_empty(len); + + // FIXME: This could be made faster if `BitSet::xor` were implemented. + for i in (0..len).map(|i| T::new(i)) { + match (from.contains(i), to.contains(i)) { + (false, true) => set.insert(i), + (true, false) => clear.insert(i), + _ => continue, + }; + } + + BitSetDiff { + set, + clear, + } + } +} + +/// Formats each `elem` using the pretty printer provided by `analysis` into a comma-separated +/// list. +fn pretty_print_state_elems
( + w: &mut impl io::Write, + analysis: &A, + elems: impl Iterator, +) -> io::Result<()> +where + A: Analysis<'tcx>, +{ + let mut first = true; + for idx in elems { + if first { + first = false; + } else { + write!(w, ",")?; + } + + analysis.pretty_print_idx(w, idx)?; + } + + Ok(()) +} + +/// The background color used for zebra-striping the table. +#[derive(Clone, Copy)] +enum Background { + Light, + Dark, +} + +impl Background { + fn attr(self) -> &'static str { + match self { + Self::Dark => "bgcolor=\"#f0f0f0\"", + Self::Light => "", + } + } +} + +impl ops::Not for Background { + type Output = Self; + + fn not(self) -> Self { + match self { + Self::Light => Self::Dark, + Self::Dark => Self::Light, + } + } +} From cd24cd4eecf39c545b0373746631a8bddf2b46d3 Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Sun, 29 Sep 2019 21:33:51 -0700 Subject: [PATCH 4/6] Update consumers of `generic::Engine` API --- src/librustc_mir/transform/check_consts/resolver.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/librustc_mir/transform/check_consts/resolver.rs b/src/librustc_mir/transform/check_consts/resolver.rs index f95b240195b1e..54cb4fbad6d5d 100644 --- a/src/librustc_mir/transform/check_consts/resolver.rs +++ b/src/librustc_mir/transform/check_consts/resolver.rs @@ -208,7 +208,8 @@ where _qualif: PhantomData, }; let results = - dataflow::Engine::new(item.body, dead_unwinds, analysis).iterate_to_fixpoint(); + dataflow::Engine::new(item.tcx, item.body, item.def_id, dead_unwinds, analysis) + .iterate_to_fixpoint(); let cursor = dataflow::ResultsCursor::new(item.body, results); let mut qualifs_in_any_value_of_ty = BitSet::new_empty(item.body.local_decls.len()); From cf5f5c55be027a055867bef7773d27be1799ac06 Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Sun, 29 Sep 2019 21:43:09 -0700 Subject: [PATCH 5/6] Use separate files for debugging `Qualif` dataflow results --- src/librustc_mir/transform/check_consts/qualifs.rs | 5 +++++ src/librustc_mir/transform/check_consts/resolver.rs | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/librustc_mir/transform/check_consts/qualifs.rs b/src/librustc_mir/transform/check_consts/qualifs.rs index 0c6468309dc4b..40007eb3c4a3e 100644 --- a/src/librustc_mir/transform/check_consts/qualifs.rs +++ b/src/librustc_mir/transform/check_consts/qualifs.rs @@ -27,6 +27,9 @@ impl QualifSet { pub trait Qualif { const IDX: usize; + /// The name of the file used to debug the dataflow analysis that computes this qualif. + const ANALYSIS_NAME: &'static str; + /// Whether this `Qualif` is cleared when a local is moved from. const IS_CLEARED_ON_MOVE: bool = false; @@ -207,6 +210,7 @@ pub struct HasMutInterior; impl Qualif for HasMutInterior { const IDX: usize = 0; + const ANALYSIS_NAME: &'static str = "flow_has_mut_interior"; fn in_any_value_of_ty(cx: &ConstCx<'_, 'tcx>, ty: Ty<'tcx>) -> bool { !ty.is_freeze(cx.tcx, cx.param_env, DUMMY_SP) @@ -264,6 +268,7 @@ pub struct NeedsDrop; impl Qualif for NeedsDrop { const IDX: usize = 1; + const ANALYSIS_NAME: &'static str = "flow_needs_drop"; const IS_CLEARED_ON_MOVE: bool = true; fn in_any_value_of_ty(cx: &ConstCx<'_, 'tcx>, ty: Ty<'tcx>) -> bool { diff --git a/src/librustc_mir/transform/check_consts/resolver.rs b/src/librustc_mir/transform/check_consts/resolver.rs index 54cb4fbad6d5d..4fa4eba4c23b6 100644 --- a/src/librustc_mir/transform/check_consts/resolver.rs +++ b/src/librustc_mir/transform/check_consts/resolver.rs @@ -309,7 +309,7 @@ where { type Idx = Local; - const NAME: &'static str = "flow_sensitive_qualif"; + const NAME: &'static str = Q::ANALYSIS_NAME; fn bits_per_block(&self, body: &mir::Body<'tcx>) -> usize { body.local_decls.len() From 2b8e023b9d28f2f912ad21427b5266b62c007f11 Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Sun, 29 Sep 2019 21:45:10 -0700 Subject: [PATCH 6/6] Stop printing `Qualif` results in debug logs Now we can use the dataflow graphviz debugging. --- src/librustc_mir/transform/check_consts/validation.rs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/librustc_mir/transform/check_consts/validation.rs b/src/librustc_mir/transform/check_consts/validation.rs index e74b22b43525c..3045239d7a770 100644 --- a/src/librustc_mir/transform/check_consts/validation.rs +++ b/src/librustc_mir/transform/check_consts/validation.rs @@ -467,8 +467,6 @@ impl Visitor<'tcx> for Validator<'_, 'mir, 'tcx> { self.qualifs.needs_drop.visit_statement(statement, location); self.qualifs.has_mut_interior.visit_statement(statement, location); - debug!("needs_drop: {:?}", self.qualifs.needs_drop.get()); - debug!("has_mut_interior: {:?}", self.qualifs.has_mut_interior.get()); match statement.kind { StatementKind::Assign(..) => { @@ -494,8 +492,6 @@ impl Visitor<'tcx> for Validator<'_, 'mir, 'tcx> { self.qualifs.needs_drop.visit_terminator(terminator, location); self.qualifs.has_mut_interior.visit_terminator(terminator, location); - debug!("needs_drop: {:?}", self.qualifs.needs_drop.get()); - debug!("has_mut_interior: {:?}", self.qualifs.has_mut_interior.get()); self.super_terminator(terminator, location); }