Skip to content

Rollup of 8 pull requests #136222

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 21 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
7d9fe91
[cfg_match] Document the use of expressions
c410-f3r Jan 21, 2025
1ee7582
add NLL region graph to the polonius MIR dump
lqd Jan 26, 2025
052e9b4
add NLL SCCs to polonius MIR dump
lqd Jan 26, 2025
6bdc2dc
tidy up html structure
lqd Jan 26, 2025
cedd3e2
Update books
rustbot Jan 27, 2025
93ee180
ABI-required target features: warn when they are missing in base CPU …
RalfJung Jan 27, 2025
3f6ffa1
update comments
RalfJung Jan 27, 2025
7877d86
Add mir-opt pattern type tests
oli-obk Jan 28, 2025
fd6713f
Make mir dumps more readable
oli-obk Jan 27, 2025
6509596
ci: remove unused windows runner
marcoieni Jan 28, 2025
3026545
parse_format optimize import use
hkBst Jan 23, 2025
81a5e14
Move fulfillment error derivation into new module
compiler-errors Jan 22, 2025
5f76f1a
Manually walk into WF obligations in BestObligation proof tree visitor
compiler-errors Jan 22, 2025
5317161
Rollup merge of #135625 - c410-f3r:cfg-match-foo-bar-baz, r=tgross35,…
Zalathar Jan 29, 2025
64fc3bf
Rollup merge of #135900 - compiler-errors:derive-wf, r=lcnr
Zalathar Jan 29, 2025
9567909
Rollup merge of #135943 - hkBst:opt_imports, r=estebank
Zalathar Jan 29, 2025
74f5b28
Rollup merge of #136104 - lqd:polonius-debugger-episode-2, r=matthewj…
Zalathar Jan 29, 2025
1d35c31
Rollup merge of #136143 - rustbot:docs-update, r=ehuss
Zalathar Jan 29, 2025
efe01ea
Rollup merge of #136147 - RalfJung:required-target-features-check-not…
Zalathar Jan 29, 2025
c3c573c
Rollup merge of #136176 - oli-obk:pattern-type-mir-opts, r=compiler-e…
Zalathar Jan 29, 2025
e31f420
Rollup merge of #136192 - marcoieni:remove-windows-unused-runner, r=K…
Zalathar Jan 29, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
141 changes: 136 additions & 5 deletions compiler/rustc_borrowck/src/polonius/dump.rs
Original file line number Diff line number Diff line change
@@ -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.
Expand Down Expand Up @@ -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>,
Expand All @@ -68,7 +74,7 @@ fn emit_polonius_dump<'tcx>(
// Section 1: the NLL + Polonius MIR.
writeln!(out, "<div>")?;
writeln!(out, "Raw MIR dump")?;
writeln!(out, "<code><pre>")?;
writeln!(out, "<pre><code>")?;
emit_html_mir(
tcx,
body,
Expand All @@ -78,15 +84,31 @@ fn emit_polonius_dump<'tcx>(
closure_region_requirements,
out,
)?;
writeln!(out, "</pre></code>")?;
writeln!(out, "</code></pre>")?;
writeln!(out, "</div>")?;

// Section 2: mermaid visualization of the CFG.
writeln!(out, "<div>")?;
writeln!(out, "Control-flow graph")?;
writeln!(out, "<code><pre class='mermaid'>")?;
writeln!(out, "<pre class='mermaid'>")?;
emit_mermaid_cfg(body, out)?;
writeln!(out, "</pre></code>")?;
writeln!(out, "</pre>")?;
writeln!(out, "</div>")?;

// Section 3: mermaid visualization of the NLL region graph.
writeln!(out, "<div>")?;
writeln!(out, "NLL regions")?;
writeln!(out, "<pre class='mermaid'>")?;
emit_mermaid_nll_regions(regioncx, out)?;
writeln!(out, "</pre>")?;
writeln!(out, "</div>")?;

// Section 4: mermaid visualization of the NLL SCC graph.
writeln!(out, "<div>")?;
writeln!(out, "NLL SCCs")?;
writeln!(out, "<pre class='mermaid'>")?;
emit_mermaid_nll_sccs(regioncx, out)?;
writeln!(out, "</pre>")?;
writeln!(out, "</div>")?;

// Finalize the dump with the HTML epilogue.
Expand Down Expand Up @@ -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, "&lt;")?;
}
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, &region) 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(())
}
2 changes: 1 addition & 1 deletion compiler/rustc_builtin_macros/src/asm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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) => {
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_builtin_macros/src/format.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 }) => {
Expand Down
50 changes: 1 addition & 49 deletions compiler/rustc_codegen_gcc/src/gcc_util.rs
Original file line number Diff line number Diff line change
@@ -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;
Expand Down Expand Up @@ -45,12 +43,6 @@ pub(crate) fn global_gcc_features(sess: &Session, diagnostics: bool) -> Vec<Stri
let known_features = sess.target.rust_target_features();
let mut featsmap = FxHashMap::default();

// Ensure that all ABI-required features are enabled, and the ABI-forbidden ones
// are disabled.
let abi_feature_constraints = sess.target.abi_required_features();
let abi_incompatible_set =
FxHashSet::from_iter(abi_feature_constraints.incompatible.iter().copied());

// Compute implied features
let mut all_rust_features = vec![];
for feature in sess.opts.cg.target_feature.split(',') {
Expand Down Expand Up @@ -117,51 +109,11 @@ pub(crate) fn global_gcc_features(sess: &Session, diagnostics: bool) -> Vec<Stri
}
}

// Ensure that the features we enable/disable are compatible with the ABI.
if enable {
if abi_incompatible_set.contains(feature) {
sess.dcx().emit_warn(ForbiddenCTargetFeature {
feature,
enabled: "enabled",
reason: "this feature is incompatible with the target ABI",
});
}
} else {
// FIXME: we have to request implied features here since
// negative features do not handle implied features above.
for &required in abi_feature_constraints.required.iter() {
let implied = sess.target.implied_target_features(std::iter::once(required));
if implied.contains(feature) {
sess.dcx().emit_warn(ForbiddenCTargetFeature {
feature,
enabled: "disabled",
reason: "this feature is required by the target ABI",
});
}
}
}

// FIXME(nagisa): figure out how to not allocate a full hashset here.
featsmap.insert(feature, enable);
}
}

// To be sure the ABI-relevant features are all in the right state, we explicitly
// (un)set them here. This means if the target spec sets those features wrong,
// we will silently correct them rather than silently producing wrong code.
// (The target sanity check tries to catch this, but we can't know which features are
// enabled in GCC by default so we can't be fully sure about that check.)
// We add these at the beginning of the list so that `-Ctarget-features` can
// still override it... that's unsound, but more compatible with past behavior.
all_rust_features.splice(
0..0,
abi_feature_constraints
.required
.iter()
.map(|&f| (true, f))
.chain(abi_feature_constraints.incompatible.iter().map(|&f| (false, f))),
);

// Translate this into GCC features.
let feats =
all_rust_features.iter().flat_map(|&(enable, feature)| {
Expand Down
5 changes: 3 additions & 2 deletions compiler/rustc_codegen_gcc/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -493,9 +493,10 @@ fn target_features_cfg(
sess.target
.rust_target_features()
.iter()
.filter(|&&(_, gate, _)| gate.in_cfg())
.filter_map(|&(feature, gate, _)| {
if sess.is_nightly_build() || allow_unstable || gate.requires_nightly().is_none() {
if allow_unstable
|| (gate.in_cfg() && (sess.is_nightly_build() || gate.requires_nightly().is_none()))
{
Some(feature)
} else {
None
Expand Down
56 changes: 6 additions & 50 deletions compiler/rustc_codegen_llvm/src/llvm_util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -319,7 +319,6 @@ pub fn target_features_cfg(sess: &Session, allow_unstable: bool) -> Vec<Symbol>
sess.target
.rust_target_features()
.iter()
.filter(|(_, gate, _)| gate.in_cfg())
.filter(|(feature, _, _)| {
// skip checking special features, as LLVM may not understand them
if RUSTC_SPECIAL_FEATURES.contains(feature) {
Expand Down Expand Up @@ -388,9 +387,13 @@ pub fn target_features_cfg(sess: &Session, allow_unstable: bool) -> Vec<Symbol>
sess.target
.rust_target_features()
.iter()
.filter(|(_, gate, _)| gate.in_cfg())
.filter_map(|(feature, gate, _)| {
if sess.is_nightly_build() || allow_unstable || gate.requires_nightly().is_none() {
// The `allow_unstable` set is used by rustc internally to determined which target
// features are truly available, so we want to return even perma-unstable "forbidden"
// features.
if allow_unstable
|| (gate.in_cfg() && (sess.is_nightly_build() || gate.requires_nightly().is_none()))
{
Some(*feature)
} else {
None
Expand Down Expand Up @@ -670,12 +673,6 @@ pub(crate) fn global_llvm_features(
// Will only be filled when `diagnostics` is set!
let mut featsmap = FxHashMap::default();

// Ensure that all ABI-required features are enabled, and the ABI-forbidden ones
// are disabled.
let abi_feature_constraints = sess.target.abi_required_features();
let abi_incompatible_set =
FxHashSet::from_iter(abi_feature_constraints.incompatible.iter().copied());

// Compute implied features
let mut all_rust_features = vec![];
for feature in sess.opts.cg.target_feature.split(',') {
Expand Down Expand Up @@ -746,52 +743,11 @@ pub(crate) fn global_llvm_features(
}
}

// Ensure that the features we enable/disable are compatible with the ABI.
if enable {
if abi_incompatible_set.contains(feature) {
sess.dcx().emit_warn(ForbiddenCTargetFeature {
feature,
enabled: "enabled",
reason: "this feature is incompatible with the target ABI",
});
}
} else {
// FIXME: we have to request implied features here since
// negative features do not handle implied features above.
for &required in abi_feature_constraints.required.iter() {
let implied =
sess.target.implied_target_features(std::iter::once(required));
if implied.contains(feature) {
sess.dcx().emit_warn(ForbiddenCTargetFeature {
feature,
enabled: "disabled",
reason: "this feature is required by the target ABI",
});
}
}
}

// FIXME(nagisa): figure out how to not allocate a full hashset here.
featsmap.insert(feature, enable);
}
}

// To be sure the ABI-relevant features are all in the right state, we explicitly
// (un)set them here. This means if the target spec sets those features wrong,
// we will silently correct them rather than silently producing wrong code.
// (The target sanity check tries to catch this, but we can't know which features are
// enabled in LLVM by default so we can't be fully sure about that check.)
// We add these at the beginning of the list so that `-Ctarget-features` can
// still override it... that's unsound, but more compatible with past behavior.
all_rust_features.splice(
0..0,
abi_feature_constraints
.required
.iter()
.map(|&f| (true, f))
.chain(abi_feature_constraints.incompatible.iter().map(|&f| (false, f))),
);

// Translate this into LLVM features.
let feats = all_rust_features
.iter()
Expand Down
5 changes: 5 additions & 0 deletions compiler/rustc_interface/messages.ftl
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
interface_abi_required_feature =
target feature `{$feature}` must be {$enabled} to ensure that the ABI of the current target can be implemented correctly
.note = this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
interface_abi_required_feature_issue = for more information, see issue #116344 <https://github.com/rust-lang/rust/issues/116344>

interface_cant_emit_mir =
could not emit MIR: {$error}

Expand Down
Loading
Loading