diff --git a/compiler/rustc_borrowck/src/polonius/dump.rs b/compiler/rustc_borrowck/src/polonius/dump.rs
index 40e801d03885c..f71e6f3e6f3a6 100644
--- a/compiler/rustc_borrowck/src/polonius/dump.rs
+++ b/compiler/rustc_borrowck/src/polonius/dump.rs
@@ -1,14 +1,18 @@
use std::io;
+use rustc_data_structures::fx::FxHashSet;
+use rustc_index::IndexVec;
use rustc_middle::mir::pretty::{
PassWhere, PrettyPrintMirOptions, create_dump_file, dump_enabled, dump_mir_to_writer,
};
use rustc_middle::mir::{Body, ClosureRegionRequirements};
-use rustc_middle::ty::TyCtxt;
+use rustc_middle::ty::{RegionVid, TyCtxt};
use rustc_session::config::MirIncludeSpans;
use crate::borrow_set::BorrowSet;
+use crate::constraints::OutlivesConstraint;
use crate::polonius::{LocalizedOutlivesConstraint, LocalizedOutlivesConstraintSet};
+use crate::type_check::Locations;
use crate::{BorrowckInferCtxt, RegionInferenceContext};
/// `-Zdump-mir=polonius` dumps MIR annotated with NLL and polonius specific information.
@@ -50,6 +54,8 @@ pub(crate) fn dump_polonius_mir<'tcx>(
/// - the NLL MIR
/// - the list of polonius localized constraints
/// - a mermaid graph of the CFG
+/// - a mermaid graph of the NLL regions and the constraints between them
+/// - a mermaid graph of the NLL SCCs and the constraints between them
fn emit_polonius_dump<'tcx>(
tcx: TyCtxt<'tcx>,
body: &Body<'tcx>,
@@ -68,7 +74,7 @@ fn emit_polonius_dump<'tcx>(
// Section 1: the NLL + Polonius MIR.
writeln!(out, "
")?;
writeln!(out, "Raw MIR dump")?;
- writeln!(out, "
")?;
+ writeln!(out, "")?;
emit_html_mir(
tcx,
body,
@@ -78,15 +84,31 @@ fn emit_polonius_dump<'tcx>(
closure_region_requirements,
out,
)?;
- writeln!(out, "
")?;
+ writeln!(out, "")?;
writeln!(out, "
")?;
// Section 2: mermaid visualization of the CFG.
writeln!(out, "")?;
writeln!(out, "Control-flow graph")?;
- writeln!(out, "
")?;
+ writeln!(out, "")?;
emit_mermaid_cfg(body, out)?;
- writeln!(out, "
")?;
+ writeln!(out, "")?;
+ writeln!(out, "
")?;
+
+ // Section 3: mermaid visualization of the NLL region graph.
+ writeln!(out, "")?;
+ writeln!(out, "NLL regions")?;
+ writeln!(out, "
")?;
+ emit_mermaid_nll_regions(regioncx, out)?;
+ writeln!(out, "
")?;
+ writeln!(out, "
")?;
+
+ // Section 4: mermaid visualization of the NLL SCC graph.
+ writeln!(out, "")?;
+ writeln!(out, "NLL SCCs")?;
+ writeln!(out, "
")?;
+ emit_mermaid_nll_sccs(regioncx, out)?;
+ writeln!(out, "
")?;
writeln!(out, "
")?;
// Finalize the dump with the HTML epilogue.
@@ -261,3 +283,112 @@ fn emit_mermaid_cfg(body: &Body<'_>, out: &mut dyn io::Write) -> io::Result<()>
Ok(())
}
+
+/// Emits a region's label: index, universe, external name.
+fn render_region(
+ region: RegionVid,
+ regioncx: &RegionInferenceContext<'_>,
+ out: &mut dyn io::Write,
+) -> io::Result<()> {
+ let def = regioncx.region_definition(region);
+ let universe = def.universe;
+
+ write!(out, "'{}", region.as_usize())?;
+ if !universe.is_root() {
+ write!(out, "/{universe:?}")?;
+ }
+ if let Some(name) = def.external_name.and_then(|e| e.get_name()) {
+ write!(out, " ({name})")?;
+ }
+ Ok(())
+}
+
+/// Emits a mermaid flowchart of the NLL regions and the outlives constraints between them, similar
+/// to the graphviz version.
+fn emit_mermaid_nll_regions<'tcx>(
+ regioncx: &RegionInferenceContext<'tcx>,
+ out: &mut dyn io::Write,
+) -> io::Result<()> {
+ // The mermaid chart type: a top-down flowchart.
+ writeln!(out, "flowchart TD")?;
+
+ // Emit the region nodes.
+ for region in regioncx.var_infos.indices() {
+ write!(out, "{}[\"", region.as_usize())?;
+ render_region(region, regioncx, out)?;
+ writeln!(out, "\"]")?;
+ }
+
+ // Get a set of edges to check for the reverse edge being present.
+ let edges: FxHashSet<_> = regioncx.outlives_constraints().map(|c| (c.sup, c.sub)).collect();
+
+ // Order (and deduplicate) edges for traversal, to display them in a generally increasing order.
+ let constraint_key = |c: &OutlivesConstraint<'_>| {
+ let min = c.sup.min(c.sub);
+ let max = c.sup.max(c.sub);
+ (min, max)
+ };
+ let mut ordered_edges: Vec<_> = regioncx.outlives_constraints().collect();
+ ordered_edges.sort_by_key(|c| constraint_key(c));
+ ordered_edges.dedup_by_key(|c| constraint_key(c));
+
+ for outlives in ordered_edges {
+ // Source node.
+ write!(out, "{} ", outlives.sup.as_usize())?;
+
+ // The kind of arrow: bidirectional if the opposite edge exists in the set.
+ if edges.contains(&(outlives.sub, outlives.sup)) {
+ write!(out, "<")?;
+ }
+ write!(out, "-- ")?;
+
+ // Edge label from its `Locations`.
+ match outlives.locations {
+ Locations::All(_) => write!(out, "All")?,
+ Locations::Single(location) => write!(out, "{:?}", location)?,
+ }
+
+ // Target node.
+ writeln!(out, " --> {}", outlives.sub.as_usize())?;
+ }
+ Ok(())
+}
+
+/// Emits a mermaid flowchart of the NLL SCCs and the outlives constraints between them, similar
+/// to the graphviz version.
+fn emit_mermaid_nll_sccs<'tcx>(
+ regioncx: &RegionInferenceContext<'tcx>,
+ out: &mut dyn io::Write,
+) -> io::Result<()> {
+ // The mermaid chart type: a top-down flowchart.
+ writeln!(out, "flowchart TD")?;
+
+ // Gather and emit the SCC nodes.
+ let mut nodes_per_scc: IndexVec<_, _> =
+ regioncx.constraint_sccs().all_sccs().map(|_| Vec::new()).collect();
+ for region in regioncx.var_infos.indices() {
+ let scc = regioncx.constraint_sccs().scc(region);
+ nodes_per_scc[scc].push(region);
+ }
+ for (scc, regions) in nodes_per_scc.iter_enumerated() {
+ // The node label: the regions contained in the SCC.
+ write!(out, "{scc}[\"SCC({scc}) = {{", scc = scc.as_usize())?;
+ for (idx, ®ion) in regions.iter().enumerate() {
+ render_region(region, regioncx, out)?;
+ if idx < regions.len() - 1 {
+ write!(out, ",")?;
+ }
+ }
+ writeln!(out, "}}\"]")?;
+ }
+
+ // Emit the edges between SCCs.
+ let edges = regioncx.constraint_sccs().all_sccs().flat_map(|source| {
+ regioncx.constraint_sccs().successors(source).iter().map(move |&target| (source, target))
+ });
+ for (source, target) in edges {
+ writeln!(out, "{} --> {}", source.as_usize(), target.as_usize())?;
+ }
+
+ Ok(())
+}
diff --git a/compiler/rustc_builtin_macros/src/asm.rs b/compiler/rustc_builtin_macros/src/asm.rs
index 5062cf55bb9ad..eb5b345e49ecd 100644
--- a/compiler/rustc_builtin_macros/src/asm.rs
+++ b/compiler/rustc_builtin_macros/src/asm.rs
@@ -651,7 +651,7 @@ fn expand_preparsed_asm(
.map(|span| template_span.from_inner(InnerSpan::new(span.start, span.end)));
for piece in unverified_pieces {
match piece {
- parse::Piece::String(s) => {
+ parse::Piece::Lit(s) => {
template.push(ast::InlineAsmTemplatePiece::String(s.to_string().into()))
}
parse::Piece::NextArgument(arg) => {
diff --git a/compiler/rustc_builtin_macros/src/format.rs b/compiler/rustc_builtin_macros/src/format.rs
index 5202fe26c401e..a0ab6375a666b 100644
--- a/compiler/rustc_builtin_macros/src/format.rs
+++ b/compiler/rustc_builtin_macros/src/format.rs
@@ -406,7 +406,7 @@ fn make_format_args(
for piece in &pieces {
match *piece {
- parse::Piece::String(s) => {
+ parse::Piece::Lit(s) => {
unfinished_literal.push_str(s);
}
parse::Piece::NextArgument(box parse::Argument { position, position_span, format }) => {
diff --git a/compiler/rustc_codegen_gcc/src/gcc_util.rs b/compiler/rustc_codegen_gcc/src/gcc_util.rs
index 560aff43d6538..4e8c8aaaf5c8a 100644
--- a/compiler/rustc_codegen_gcc/src/gcc_util.rs
+++ b/compiler/rustc_codegen_gcc/src/gcc_util.rs
@@ -1,10 +1,8 @@
-use std::iter::FromIterator;
-
#[cfg(feature = "master")]
use gccjit::Context;
use rustc_codegen_ssa::codegen_attrs::check_tied_features;
use rustc_codegen_ssa::errors::TargetFeatureDisableOrEnable;
-use rustc_data_structures::fx::{FxHashMap, FxHashSet};
+use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::unord::UnordSet;
use rustc_session::Session;
use rustc_target::target_features::RUSTC_SPECIFIC_FEATURES;
@@ -45,12 +43,6 @@ pub(crate) fn global_gcc_features(sess: &Session, diagnostics: bool) -> Vec