From 9916ce362f712b7aa91cd7576a5dcfc575ffd621 Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Fri, 1 Aug 2025 15:31:16 +0200 Subject: [PATCH 01/48] fix `#[loop_match]` on diverging loop this generated invalid MIR before --- .../rustc_mir_build/src/builder/expr/into.rs | 2 +- tests/ui/loop-match/diverges.rs | 44 +++++++++++++++++++ 2 files changed, 45 insertions(+), 1 deletion(-) create mode 100644 tests/ui/loop-match/diverges.rs diff --git a/compiler/rustc_mir_build/src/builder/expr/into.rs b/compiler/rustc_mir_build/src/builder/expr/into.rs index 82b883a99a11..ac87f671699d 100644 --- a/compiler/rustc_mir_build/src/builder/expr/into.rs +++ b/compiler/rustc_mir_build/src/builder/expr/into.rs @@ -345,7 +345,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { expr_span, |this| { this.lower_match_arms( - destination, + state_place, scrutinee_place_builder, scrutinee_span, arms, diff --git a/tests/ui/loop-match/diverges.rs b/tests/ui/loop-match/diverges.rs new file mode 100644 index 000000000000..f1b3ffb2076b --- /dev/null +++ b/tests/ui/loop-match/diverges.rs @@ -0,0 +1,44 @@ +//@ build-pass +//@ compile-flags: -Zvalidate-mir +#![allow(incomplete_features)] +#![feature(loop_match)] +#![crate_type = "lib"] + +// Test that a #[loop_match] without an explicit break from the loop generates valid MIR. + +fn break_to_block_unit() -> u8 { + let mut state = 0; + #[loop_match] + loop { + state = 'blk: { + match state { + _ => 'b: { + break 'b 2; + } + } + } + } +} + +fn break_to_block_value() -> u8 { + let mut state = 0u8; + #[loop_match] + 'a: loop { + state = 'blk: { + match state { + _ => break 'blk state, + } + } + } +} + +fn infinite_a(mut state: u8) { + #[loop_match] + loop { + state = 'blk: { + match state { + a => a, + } + } + } +} From 3e76b58453461a7ac04db4914caff584345d8448 Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Fri, 1 Aug 2025 16:15:21 +0200 Subject: [PATCH 02/48] add place mention for `#[loop_match]` scrutinee --- .../rustc_mir_build/src/builder/expr/into.rs | 6 +- .../src/builder/matches/mod.rs | 2 +- ...verges.break_to_block_unit.built.after.mir | 63 ++++++ ..._match_diverges.infinite_a.built.after.mir | 51 +++++ tests/mir-opt/building/loop_match_diverges.rs | 68 +++++++ ...loop_match_diverges.simple.built.after.mir | 187 ++++++++++++++++++ 6 files changed, 374 insertions(+), 3 deletions(-) create mode 100644 tests/mir-opt/building/loop_match_diverges.break_to_block_unit.built.after.mir create mode 100644 tests/mir-opt/building/loop_match_diverges.infinite_a.built.after.mir create mode 100644 tests/mir-opt/building/loop_match_diverges.rs create mode 100644 tests/mir-opt/building/loop_match_diverges.simple.built.after.mir diff --git a/compiler/rustc_mir_build/src/builder/expr/into.rs b/compiler/rustc_mir_build/src/builder/expr/into.rs index ac87f671699d..78bcc47d9d0d 100644 --- a/compiler/rustc_mir_build/src/builder/expr/into.rs +++ b/compiler/rustc_mir_build/src/builder/expr/into.rs @@ -295,9 +295,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { this.diverge_from(loop_block); // Logic for `match`. - let scrutinee_place_builder = - unpack!(body_block = this.as_place_builder(body_block, scrutinee)); let scrutinee_span = this.thir.exprs[scrutinee].span; + let scrutinee_place_builder = unpack!( + body_block = this.lower_scrutinee(body_block, scrutinee, scrutinee_span) + ); + let match_start_span = match_span.shrink_to_lo().to(scrutinee_span); let mut patterns = Vec::with_capacity(arms.len()); diff --git a/compiler/rustc_mir_build/src/builder/matches/mod.rs b/compiler/rustc_mir_build/src/builder/matches/mod.rs index 2c29b8628417..e863f94af7ea 100644 --- a/compiler/rustc_mir_build/src/builder/matches/mod.rs +++ b/compiler/rustc_mir_build/src/builder/matches/mod.rs @@ -407,7 +407,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } /// Evaluate the scrutinee and add the PlaceMention for it. - fn lower_scrutinee( + pub(crate) fn lower_scrutinee( &mut self, mut block: BasicBlock, scrutinee_id: ExprId, diff --git a/tests/mir-opt/building/loop_match_diverges.break_to_block_unit.built.after.mir b/tests/mir-opt/building/loop_match_diverges.break_to_block_unit.built.after.mir new file mode 100644 index 000000000000..6d779e46146c --- /dev/null +++ b/tests/mir-opt/building/loop_match_diverges.break_to_block_unit.built.after.mir @@ -0,0 +1,63 @@ +// MIR for `break_to_block_unit` after built + +fn break_to_block_unit() -> u8 { + let mut _0: u8; + let mut _1: i32; + let mut _2: !; + scope 1 { + debug state => _1; + } + + bb0: { + StorageLive(_1); + _1 = const 0_i32; + FakeRead(ForLet(None), _1); + StorageLive(_2); + goto -> bb1; + } + + bb1: { + falseUnwind -> [real: bb2, unwind: bb10]; + } + + bb2: { + PlaceMention(_1); + _1 = const 2_i32; + goto -> bb5; + } + + bb3: { + FakeRead(ForMatchedPlace(None), _1); + unreachable; + } + + bb4: { + goto -> bb6; + } + + bb5: { + goto -> bb6; + } + + bb6: { + goto -> bb7; + } + + bb7: { + goto -> bb1; + } + + bb8: { + unreachable; + } + + bb9: { + StorageDead(_2); + StorageDead(_1); + return; + } + + bb10 (cleanup): { + resume; + } +} diff --git a/tests/mir-opt/building/loop_match_diverges.infinite_a.built.after.mir b/tests/mir-opt/building/loop_match_diverges.infinite_a.built.after.mir new file mode 100644 index 000000000000..e3766744790b --- /dev/null +++ b/tests/mir-opt/building/loop_match_diverges.infinite_a.built.after.mir @@ -0,0 +1,51 @@ +// MIR for `infinite_a` after built + +fn infinite_a(_1: u8) -> () { + debug state => _1; + let mut _0: (); + let mut _2: !; + let _3: u8; + scope 1 { + debug a => _3; + } + + bb0: { + StorageLive(_2); + goto -> bb1; + } + + bb1: { + falseUnwind -> [real: bb2, unwind: bb7]; + } + + bb2: { + PlaceMention(_1); + StorageLive(_3); + _3 = copy _1; + _1 = copy _3; + StorageDead(_3); + goto -> bb4; + } + + bb3: { + FakeRead(ForMatchedPlace(None), _1); + unreachable; + } + + bb4: { + goto -> bb1; + } + + bb5: { + unreachable; + } + + bb6: { + StorageDead(_2); + return; + } + + bb7 (cleanup): { + resume; + } +} diff --git a/tests/mir-opt/building/loop_match_diverges.rs b/tests/mir-opt/building/loop_match_diverges.rs new file mode 100644 index 000000000000..774e195c33c9 --- /dev/null +++ b/tests/mir-opt/building/loop_match_diverges.rs @@ -0,0 +1,68 @@ +// skip-filecheck +#![allow(incomplete_features)] +#![feature(loop_match)] +#![crate_type = "lib"] + +// Test that a #[loop_match] without an explicit break from the loop generates valid MIR. + +enum State { + A, + B, + C, +} + +// EMIT_MIR loop_match_diverges.simple.built.after.mir +fn simple(mut state: State) -> State { + #[loop_match] + 'a: loop { + state = 'blk: { + match state { + State::A => { + #[const_continue] + break 'blk State::B; + } + State::B => { + if true { + #[const_continue] + break 'blk State::C; + } else { + #[const_continue] + break 'blk State::A; + } + } + State::C => break 'a, + } + }; + } + + state +} + +// EMIT_MIR loop_match_diverges.break_to_block_unit.built.after.mir +#[unsafe(no_mangle)] +fn break_to_block_unit() -> u8 { + let mut state = 0; + #[loop_match] + loop { + state = 'blk: { + match state { + _ => 'b: { + break 'b 2; + } + } + } + } +} + +// EMIT_MIR loop_match_diverges.infinite_a.built.after.mir +#[unsafe(no_mangle)] +fn infinite_a(mut state: u8) { + #[loop_match] + loop { + state = 'blk: { + match state { + a => a, + } + } + } +} diff --git a/tests/mir-opt/building/loop_match_diverges.simple.built.after.mir b/tests/mir-opt/building/loop_match_diverges.simple.built.after.mir new file mode 100644 index 000000000000..26476ad77627 --- /dev/null +++ b/tests/mir-opt/building/loop_match_diverges.simple.built.after.mir @@ -0,0 +1,187 @@ +// MIR for `simple` after built + +fn simple(_1: State) -> State { + debug state => _1; + let mut _0: State; + let _2: (); + let mut _3: isize; + let mut _4: !; + let mut _5: isize; + let mut _6: bool; + let mut _7: !; + let mut _8: isize; + let mut _9: !; + let mut _10: isize; + let mut _11: !; + + bb0: { + StorageLive(_2); + goto -> bb1; + } + + bb1: { + falseUnwind -> [real: bb2, unwind: bb37]; + } + + bb2: { + PlaceMention(_1); + _3 = discriminant(_1); + switchInt(move _3) -> [0: bb4, 1: bb6, 2: bb8, otherwise: bb3]; + } + + bb3: { + FakeRead(ForMatchedPlace(None), _1); + unreachable; + } + + bb4: { + falseEdge -> [real: bb11, imaginary: bb6]; + } + + bb5: { + goto -> bb3; + } + + bb6: { + falseEdge -> [real: bb10, imaginary: bb8]; + } + + bb7: { + goto -> bb3; + } + + bb8: { + _2 = const (); + goto -> bb36; + } + + bb9: { + goto -> bb3; + } + + bb10: { + StorageLive(_6); + _6 = const true; + switchInt(move _6) -> [0: bb17, otherwise: bb16]; + } + + bb11: { + _1 = State::B; + _5 = discriminant(_1); + falseEdge -> [real: bb12, imaginary: bb13]; + } + + bb12: { + goto -> bb10; + } + + bb13: { + goto -> bb34; + } + + bb14: { + unreachable; + } + + bb15: { + goto -> bb32; + } + + bb16: { + _1 = State::C; + _8 = discriminant(_1); + falseEdge -> [real: bb18, imaginary: bb19]; + } + + bb17: { + goto -> bb23; + } + + bb18: { + goto -> bb20; + } + + bb19: { + goto -> bb33; + } + + bb20: { + StorageDead(_6); + goto -> bb8; + } + + bb21: { + unreachable; + } + + bb22: { + goto -> bb29; + } + + bb23: { + _1 = State::A; + _10 = discriminant(_1); + falseEdge -> [real: bb24, imaginary: bb25]; + } + + bb24: { + goto -> bb26; + } + + bb25: { + goto -> bb33; + } + + bb26: { + StorageDead(_6); + goto -> bb11; + } + + bb27: { + unreachable; + } + + bb28: { + goto -> bb29; + } + + bb29: { + StorageDead(_6); + goto -> bb32; + } + + bb30: { + unreachable; + } + + bb31: { + goto -> bb32; + } + + bb32: { + goto -> bb35; + } + + bb33: { + StorageDead(_6); + goto -> bb34; + } + + bb34: { + goto -> bb35; + } + + bb35: { + goto -> bb1; + } + + bb36: { + StorageDead(_2); + _0 = move _1; + return; + } + + bb37 (cleanup): { + resume; + } +} From bd8e3db94d6547829cdfd60c9dfdb6bdcdd262c3 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Sun, 17 Aug 2025 13:41:33 +1000 Subject: [PATCH 03/48] coverage: Add a specific test for `#[rustfmt::skip]` --- tests/coverage/rustfmt-skip.cov-map | 12 ++++++++++++ tests/coverage/rustfmt-skip.coverage | 18 ++++++++++++++++++ tests/coverage/rustfmt-skip.rs | 17 +++++++++++++++++ 3 files changed, 47 insertions(+) create mode 100644 tests/coverage/rustfmt-skip.cov-map create mode 100644 tests/coverage/rustfmt-skip.coverage create mode 100644 tests/coverage/rustfmt-skip.rs diff --git a/tests/coverage/rustfmt-skip.cov-map b/tests/coverage/rustfmt-skip.cov-map new file mode 100644 index 000000000000..bb673a411bfd --- /dev/null +++ b/tests/coverage/rustfmt-skip.cov-map @@ -0,0 +1,12 @@ +Function name: rustfmt_skip::main +Raw bytes (24): 0x[01, 01, 00, 04, 01, 0a, 01, 00, 0a, 01, 02, 05, 00, 0d, 01, 03, 09, 00, 10, 01, 02, 01, 00, 02] +Number of files: 1 +- file 0 => $DIR/rustfmt-skip.rs +Number of expressions: 0 +Number of file 0 mappings: 4 +- Code(Counter(0)) at (prev + 10, 1) to (start + 0, 10) +- Code(Counter(0)) at (prev + 2, 5) to (start + 0, 13) +- Code(Counter(0)) at (prev + 3, 9) to (start + 0, 16) +- Code(Counter(0)) at (prev + 2, 1) to (start + 0, 2) +Highest counter ID seen: c0 + diff --git a/tests/coverage/rustfmt-skip.coverage b/tests/coverage/rustfmt-skip.coverage new file mode 100644 index 000000000000..b7276cf0ee8b --- /dev/null +++ b/tests/coverage/rustfmt-skip.coverage @@ -0,0 +1,18 @@ + LL| |//@ edition: 2024 + LL| | + LL| |// The presence of `#[rustfmt::skip]` on a function should not cause macros + LL| |// within that function to mysteriously not be instrumented. + LL| |// + LL| |// This test detects problems that can occur when building an expansion tree + LL| |// based on `ExpnData::parent` instead of `ExpnData::call_site`, for example. + LL| | + LL| |#[rustfmt::skip] + LL| 1|fn main() { + LL| | // Ensure a gap between the body start and the first statement. + LL| 1| println!( + LL| | // Keep this on a separate line, to distinguish instrumentation of + LL| | // `println!` from instrumentation of its arguments. + LL| 1| "hello" + LL| | ); + LL| 1|} + diff --git a/tests/coverage/rustfmt-skip.rs b/tests/coverage/rustfmt-skip.rs new file mode 100644 index 000000000000..6f6874c9aa0a --- /dev/null +++ b/tests/coverage/rustfmt-skip.rs @@ -0,0 +1,17 @@ +//@ edition: 2024 + +// The presence of `#[rustfmt::skip]` on a function should not cause macros +// within that function to mysteriously not be instrumented. +// +// This test detects problems that can occur when building an expansion tree +// based on `ExpnData::parent` instead of `ExpnData::call_site`, for example. + +#[rustfmt::skip] +fn main() { + // Ensure a gap between the body start and the first statement. + println!( + // Keep this on a separate line, to distinguish instrumentation of + // `println!` from instrumentation of its arguments. + "hello" + ); +} From c2eb45b4a176dba37a0bce8fa9c4d46cf0d55e24 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Sat, 16 Aug 2025 17:46:05 +1000 Subject: [PATCH 04/48] coverage: Build an "expansion tree" and use it to unexpand raw spans --- .../src/coverage/expansion.rs | 127 ++++++++++++++++ .../rustc_mir_transform/src/coverage/mod.rs | 1 + .../rustc_mir_transform/src/coverage/spans.rs | 140 ++++++++++-------- .../src/coverage/spans/from_mir.rs | 34 +---- .../src/coverage/unexpand.rs | 48 +----- compiler/rustc_mir_transform/src/lib.rs | 1 + tests/coverage/closure.cov-map | 35 +++-- tests/coverage/closure.coverage | 6 +- tests/coverage/macro_in_closure.cov-map | 7 +- 9 files changed, 238 insertions(+), 161 deletions(-) create mode 100644 compiler/rustc_mir_transform/src/coverage/expansion.rs diff --git a/compiler/rustc_mir_transform/src/coverage/expansion.rs b/compiler/rustc_mir_transform/src/coverage/expansion.rs new file mode 100644 index 000000000000..91e0528f52f9 --- /dev/null +++ b/compiler/rustc_mir_transform/src/coverage/expansion.rs @@ -0,0 +1,127 @@ +use rustc_data_structures::fx::{FxIndexMap, FxIndexSet, IndexEntry}; +use rustc_middle::mir::coverage::BasicCoverageBlock; +use rustc_span::{ExpnId, ExpnKind, Span}; + +#[derive(Clone, Copy, Debug)] +pub(crate) struct SpanWithBcb { + pub(crate) span: Span, + pub(crate) bcb: BasicCoverageBlock, +} + +#[derive(Debug)] +pub(crate) struct ExpnTree { + nodes: FxIndexMap, +} + +impl ExpnTree { + pub(crate) fn get(&self, expn_id: ExpnId) -> Option<&ExpnNode> { + self.nodes.get(&expn_id) + } + + /// Yields the tree node for the given expansion ID (if present), followed + /// by the nodes of all of its descendants in depth-first order. + pub(crate) fn iter_node_and_descendants( + &self, + root_expn_id: ExpnId, + ) -> impl Iterator { + gen move { + let Some(root_node) = self.get(root_expn_id) else { return }; + yield root_node; + + // Stack of child-node-ID iterators that drives the depth-first traversal. + let mut iter_stack = vec![root_node.child_expn_ids.iter()]; + + while let Some(curr_iter) = iter_stack.last_mut() { + // Pull the next ID from the top of the stack. + let Some(&curr_id) = curr_iter.next() else { + iter_stack.pop(); + continue; + }; + + // Yield this node. + let Some(node) = self.get(curr_id) else { continue }; + yield node; + + // Push the node's children, to be traversed next. + if !node.child_expn_ids.is_empty() { + iter_stack.push(node.child_expn_ids.iter()); + } + } + } + } +} + +#[derive(Debug)] +pub(crate) struct ExpnNode { + /// Storing the expansion ID in its own node is not strictly necessary, + /// but is helpful for debugging and might be useful later. + #[expect(dead_code)] + pub(crate) expn_id: ExpnId, + + // Useful info extracted from `ExpnData`. + pub(crate) expn_kind: ExpnKind, + /// Non-dummy `ExpnData::call_site` span. + pub(crate) call_site: Option, + /// Expansion ID of `call_site`, if present. + /// This links an expansion node to its parent in the tree. + pub(crate) call_site_expn_id: Option, + + /// Spans (and their associated BCBs) belonging to this expansion. + pub(crate) spans: Vec, + /// Expansions whose call-site is in this expansion. + pub(crate) child_expn_ids: FxIndexSet, +} + +impl ExpnNode { + fn new(expn_id: ExpnId) -> Self { + let expn_data = expn_id.expn_data(); + + let call_site = Some(expn_data.call_site).filter(|sp| !sp.is_dummy()); + let call_site_expn_id = try { call_site?.ctxt().outer_expn() }; + + Self { + expn_id, + + expn_kind: expn_data.kind.clone(), + call_site, + call_site_expn_id, + + spans: vec![], + child_expn_ids: FxIndexSet::default(), + } + } +} + +/// Given a collection of span/BCB pairs from potentially-different syntax contexts, +/// arranges them into an "expansion tree" based on their expansion call-sites. +pub(crate) fn build_expn_tree(spans: impl IntoIterator) -> ExpnTree { + let mut nodes = FxIndexMap::default(); + let new_node = |&expn_id: &ExpnId| ExpnNode::new(expn_id); + + for span_with_bcb in spans { + // Create a node for this span's enclosing expansion, and add the span to it. + let expn_id = span_with_bcb.span.ctxt().outer_expn(); + let node = nodes.entry(expn_id).or_insert_with_key(new_node); + node.spans.push(span_with_bcb); + + // Now walk up the expansion call-site chain, creating nodes and registering children. + let mut prev = expn_id; + let mut curr_expn_id = node.call_site_expn_id; + while let Some(expn_id) = curr_expn_id { + let entry = nodes.entry(expn_id); + let node_existed = matches!(entry, IndexEntry::Occupied(_)); + + let node = entry.or_insert_with_key(new_node); + node.child_expn_ids.insert(prev); + + if node_existed { + break; + } + + prev = expn_id; + curr_expn_id = node.call_site_expn_id; + } + } + + ExpnTree { nodes } +} diff --git a/compiler/rustc_mir_transform/src/coverage/mod.rs b/compiler/rustc_mir_transform/src/coverage/mod.rs index c5fef2992447..08c7d346009c 100644 --- a/compiler/rustc_mir_transform/src/coverage/mod.rs +++ b/compiler/rustc_mir_transform/src/coverage/mod.rs @@ -8,6 +8,7 @@ use crate::coverage::graph::CoverageGraph; use crate::coverage::mappings::ExtractedMappings; mod counters; +mod expansion; mod graph; mod hir_info; mod mappings; diff --git a/compiler/rustc_mir_transform/src/coverage/spans.rs b/compiler/rustc_mir_transform/src/coverage/spans.rs index d1b04c8f5877..325935ee8468 100644 --- a/compiler/rustc_mir_transform/src/coverage/spans.rs +++ b/compiler/rustc_mir_transform/src/coverage/spans.rs @@ -1,15 +1,14 @@ -use rustc_data_structures::fx::FxHashSet; use rustc_middle::mir; use rustc_middle::mir::coverage::{Mapping, MappingKind, START_BCB}; use rustc_middle::ty::TyCtxt; use rustc_span::source_map::SourceMap; -use rustc_span::{BytePos, DesugaringKind, ExpnKind, MacroKind, Span}; +use rustc_span::{BytePos, DesugaringKind, ExpnId, ExpnKind, MacroKind, Span}; use tracing::instrument; +use crate::coverage::expansion::{self, ExpnTree, SpanWithBcb}; use crate::coverage::graph::{BasicCoverageBlock, CoverageGraph}; use crate::coverage::hir_info::ExtractedHirInfo; -use crate::coverage::spans::from_mir::{Hole, RawSpanFromMir, SpanFromMir}; -use crate::coverage::unexpand; +use crate::coverage::spans::from_mir::{Hole, RawSpanFromMir}; mod from_mir; @@ -34,19 +33,51 @@ pub(super) fn extract_refined_covspans<'tcx>( let &ExtractedHirInfo { body_span, .. } = hir_info; let raw_spans = from_mir::extract_raw_spans_from_mir(mir_body, graph); - let mut covspans = raw_spans - .into_iter() - .filter_map(|RawSpanFromMir { raw_span, bcb }| try { - let (span, expn_kind) = - unexpand::unexpand_into_body_span_with_expn_kind(raw_span, body_span)?; - // Discard any spans that fill the entire body, because they tend - // to represent compiler-inserted code, e.g. implicitly returning `()`. - if span.source_equal(body_span) { - return None; - }; - SpanFromMir { span, expn_kind, bcb } - }) - .collect::>(); + // Use the raw spans to build a tree of expansions for this function. + let expn_tree = expansion::build_expn_tree( + raw_spans + .into_iter() + .map(|RawSpanFromMir { raw_span, bcb }| SpanWithBcb { span: raw_span, bcb }), + ); + + let mut covspans = vec![]; + let mut push_covspan = |covspan: Covspan| { + let covspan_span = covspan.span; + // Discard any spans not contained within the function body span. + // Also discard any spans that fill the entire body, because they tend + // to represent compiler-inserted code, e.g. implicitly returning `()`. + if !body_span.contains(covspan_span) || body_span.source_equal(covspan_span) { + return; + } + + // Each pushed covspan should have the same context as the body span. + // If it somehow doesn't, discard the covspan, or panic in debug builds. + if !body_span.eq_ctxt(covspan_span) { + debug_assert!( + false, + "span context mismatch: body_span={body_span:?}, covspan.span={covspan_span:?}" + ); + return; + } + + covspans.push(covspan); + }; + + if let Some(node) = expn_tree.get(body_span.ctxt().outer_expn()) { + for &SpanWithBcb { span, bcb } in &node.spans { + push_covspan(Covspan { span, bcb }); + } + + // For each expansion with its call-site in the body span, try to + // distill a corresponding covspan. + for &child_expn_id in &node.child_expn_ids { + if let Some(covspan) = + single_covspan_for_child_expn(tcx, graph, &expn_tree, child_expn_id) + { + push_covspan(covspan); + } + } + } // Only proceed if we found at least one usable span. if covspans.is_empty() { @@ -57,17 +88,10 @@ pub(super) fn extract_refined_covspans<'tcx>( // Otherwise, add a fake span at the start of the body, to avoid an ugly // gap between the start of the body and the first real span. // FIXME: Find a more principled way to solve this problem. - covspans.push(SpanFromMir::for_fn_sig( - hir_info.fn_sig_span.unwrap_or_else(|| body_span.shrink_to_lo()), - )); - - // First, perform the passes that need macro information. - covspans.sort_by(|a, b| graph.cmp_in_dominator_order(a.bcb, b.bcb)); - remove_unwanted_expansion_spans(&mut covspans); - shrink_visible_macro_spans(tcx, &mut covspans); - - // We no longer need the extra information in `SpanFromMir`, so convert to `Covspan`. - let mut covspans = covspans.into_iter().map(SpanFromMir::into_covspan).collect::>(); + covspans.push(Covspan { + span: hir_info.fn_sig_span.unwrap_or_else(|| body_span.shrink_to_lo()), + bcb: START_BCB, + }); let compare_covspans = |a: &Covspan, b: &Covspan| { compare_spans(a.span, b.span) @@ -117,43 +141,37 @@ pub(super) fn extract_refined_covspans<'tcx>( })); } -/// Macros that expand into branches (e.g. `assert!`, `trace!`) tend to generate -/// multiple condition/consequent blocks that have the span of the whole macro -/// invocation, which is unhelpful. Keeping only the first such span seems to -/// give better mappings, so remove the others. -/// -/// Similarly, `await` expands to a branch on the discriminant of `Poll`, which -/// leads to incorrect coverage if the `Future` is immediately ready (#98712). -/// -/// (The input spans should be sorted in BCB dominator order, so that the -/// retained "first" span is likely to dominate the others.) -fn remove_unwanted_expansion_spans(covspans: &mut Vec) { - let mut deduplicated_spans = FxHashSet::default(); +/// For a single child expansion, try to distill it into a single span+BCB mapping. +fn single_covspan_for_child_expn( + tcx: TyCtxt<'_>, + graph: &CoverageGraph, + expn_tree: &ExpnTree, + expn_id: ExpnId, +) -> Option { + let node = expn_tree.get(expn_id)?; - covspans.retain(|covspan| { - match covspan.expn_kind { - // Retain only the first await-related or macro-expanded covspan with this span. - Some(ExpnKind::Desugaring(DesugaringKind::Await)) => { - deduplicated_spans.insert(covspan.span) - } - Some(ExpnKind::Macro(MacroKind::Bang, _)) => deduplicated_spans.insert(covspan.span), - // Ignore (retain) other spans. - _ => true, + let bcbs = + expn_tree.iter_node_and_descendants(expn_id).flat_map(|n| n.spans.iter().map(|s| s.bcb)); + + let bcb = match node.expn_kind { + // For bang-macros (e.g. `assert!`, `trace!`) and for `await`, taking + // the "first" BCB in dominator order seems to give good results. + ExpnKind::Macro(MacroKind::Bang, _) | ExpnKind::Desugaring(DesugaringKind::Await) => { + bcbs.min_by(|&a, &b| graph.cmp_in_dominator_order(a, b))? } - }); -} + // For other kinds of expansion, taking the "last" (most-dominated) BCB + // seems to give good results. + _ => bcbs.max_by(|&a, &b| graph.cmp_in_dominator_order(a, b))?, + }; -/// When a span corresponds to a macro invocation that is visible from the -/// function body, truncate it to just the macro name plus `!`. -/// This seems to give better results for code that uses macros. -fn shrink_visible_macro_spans(tcx: TyCtxt<'_>, covspans: &mut Vec) { - let source_map = tcx.sess.source_map(); - - for covspan in covspans { - if matches!(covspan.expn_kind, Some(ExpnKind::Macro(MacroKind::Bang, _))) { - covspan.span = source_map.span_through_char(covspan.span, '!'); - } + // For bang-macro expansions, limit the call-site span to just the macro + // name plus `!`, excluding the macro arguments. + let mut span = node.call_site?; + if matches!(node.expn_kind, ExpnKind::Macro(MacroKind::Bang, _)) { + span = tcx.sess.source_map().span_through_char(span, '!'); } + + Some(Covspan { span, bcb }) } /// Discard all covspans that overlap a hole. diff --git a/compiler/rustc_mir_transform/src/coverage/spans/from_mir.rs b/compiler/rustc_mir_transform/src/coverage/spans/from_mir.rs index 7985e1c07988..dfeaa90dc2e2 100644 --- a/compiler/rustc_mir_transform/src/coverage/spans/from_mir.rs +++ b/compiler/rustc_mir_transform/src/coverage/spans/from_mir.rs @@ -5,10 +5,9 @@ use rustc_middle::mir::coverage::CoverageKind; use rustc_middle::mir::{ self, FakeReadCause, Statement, StatementKind, Terminator, TerminatorKind, }; -use rustc_span::{ExpnKind, Span}; +use rustc_span::Span; -use crate::coverage::graph::{BasicCoverageBlock, CoverageGraph, START_BCB}; -use crate::coverage::spans::Covspan; +use crate::coverage::graph::{BasicCoverageBlock, CoverageGraph}; #[derive(Debug)] pub(crate) struct RawSpanFromMir { @@ -160,32 +159,3 @@ impl Hole { true } } - -#[derive(Debug)] -pub(crate) struct SpanFromMir { - /// A span that has been extracted from MIR and then "un-expanded" back to - /// within the current function's `body_span`. After various intermediate - /// processing steps, this span is emitted as part of the final coverage - /// mappings. - /// - /// With the exception of `fn_sig_span`, this should always be contained - /// within `body_span`. - pub(crate) span: Span, - pub(crate) expn_kind: Option, - pub(crate) bcb: BasicCoverageBlock, -} - -impl SpanFromMir { - pub(crate) fn for_fn_sig(fn_sig_span: Span) -> Self { - Self::new(fn_sig_span, None, START_BCB) - } - - pub(crate) fn new(span: Span, expn_kind: Option, bcb: BasicCoverageBlock) -> Self { - Self { span, expn_kind, bcb } - } - - pub(crate) fn into_covspan(self) -> Covspan { - let Self { span, expn_kind: _, bcb } = self; - Covspan { span, bcb } - } -} diff --git a/compiler/rustc_mir_transform/src/coverage/unexpand.rs b/compiler/rustc_mir_transform/src/coverage/unexpand.rs index cb8615447362..922edd3cc4fe 100644 --- a/compiler/rustc_mir_transform/src/coverage/unexpand.rs +++ b/compiler/rustc_mir_transform/src/coverage/unexpand.rs @@ -1,4 +1,4 @@ -use rustc_span::{ExpnKind, Span}; +use rustc_span::Span; /// Walks through the expansion ancestors of `original_span` to find a span that /// is contained in `body_span` and has the same [syntax context] as `body_span`. @@ -7,49 +7,3 @@ pub(crate) fn unexpand_into_body_span(original_span: Span, body_span: Span) -> O // we can just delegate directly to `find_ancestor_inside_same_ctxt`. original_span.find_ancestor_inside_same_ctxt(body_span) } - -/// Walks through the expansion ancestors of `original_span` to find a span that -/// is contained in `body_span` and has the same [syntax context] as `body_span`. -/// -/// If the returned span represents a bang-macro invocation (e.g. `foo!(..)`), -/// the returned symbol will be the name of that macro (e.g. `foo`). -pub(crate) fn unexpand_into_body_span_with_expn_kind( - original_span: Span, - body_span: Span, -) -> Option<(Span, Option)> { - let (span, prev) = unexpand_into_body_span_with_prev(original_span, body_span)?; - - let expn_kind = prev.map(|prev| prev.ctxt().outer_expn_data().kind); - - Some((span, expn_kind)) -} - -/// Walks through the expansion ancestors of `original_span` to find a span that -/// is contained in `body_span` and has the same [syntax context] as `body_span`. -/// The ancestor that was traversed just before the matching span (if any) is -/// also returned. -/// -/// For example, a return value of `Some((ancestor, Some(prev)))` means that: -/// - `ancestor == original_span.find_ancestor_inside_same_ctxt(body_span)` -/// - `prev.parent_callsite() == ancestor` -/// -/// [syntax context]: rustc_span::SyntaxContext -fn unexpand_into_body_span_with_prev( - original_span: Span, - body_span: Span, -) -> Option<(Span, Option)> { - let mut prev = None; - let mut curr = original_span; - - while !body_span.contains(curr) || !curr.eq_ctxt(body_span) { - prev = Some(curr); - curr = curr.parent_callsite()?; - } - - debug_assert_eq!(Some(curr), original_span.find_ancestor_inside_same_ctxt(body_span)); - if let Some(prev) = prev { - debug_assert_eq!(Some(curr), prev.parent_callsite()); - } - - Some((curr, prev)) -} diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs index 08f25276cecc..8f319e649166 100644 --- a/compiler/rustc_mir_transform/src/lib.rs +++ b/compiler/rustc_mir_transform/src/lib.rs @@ -5,6 +5,7 @@ #![feature(const_type_name)] #![feature(cow_is_borrowed)] #![feature(file_buffered)] +#![feature(gen_blocks)] #![feature(if_let_guard)] #![feature(impl_trait_in_assoc_type)] #![feature(try_blocks)] diff --git a/tests/coverage/closure.cov-map b/tests/coverage/closure.cov-map index 5f7e4ce58e97..ee8934f0a846 100644 --- a/tests/coverage/closure.cov-map +++ b/tests/coverage/closure.cov-map @@ -118,21 +118,23 @@ Number of file 0 mappings: 4 Highest counter ID seen: (none) Function name: closure::main::{closure#12} (unused) -Raw bytes (10): 0x[01, 01, 00, 01, 00, a7, 01, 0a, 00, 16] +Raw bytes (15): 0x[01, 01, 00, 02, 00, a7, 01, 01, 00, 09, 00, 00, 0a, 00, 16] Number of files: 1 - file 0 => $DIR/closure.rs Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Zero) at (prev + 167, 10) to (start + 0, 22) +Number of file 0 mappings: 2 +- Code(Zero) at (prev + 167, 1) to (start + 0, 9) +- Code(Zero) at (prev + 0, 10) to (start + 0, 22) Highest counter ID seen: (none) Function name: closure::main::{closure#13} (unused) -Raw bytes (10): 0x[01, 01, 00, 01, 00, ad, 01, 11, 00, 1d] +Raw bytes (15): 0x[01, 01, 00, 02, 00, ac, 01, 0d, 00, 15, 00, 01, 11, 00, 1d] Number of files: 1 - file 0 => $DIR/closure.rs Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Zero) at (prev + 173, 17) to (start + 0, 29) +Number of file 0 mappings: 2 +- Code(Zero) at (prev + 172, 13) to (start + 0, 21) +- Code(Zero) at (prev + 1, 17) to (start + 0, 29) Highest counter ID seen: (none) Function name: closure::main::{closure#14} @@ -289,30 +291,33 @@ Number of file 0 mappings: 7 Highest counter ID seen: (none) Function name: closure::main::{closure#5} -Raw bytes (10): 0x[01, 01, 00, 01, 01, 8c, 01, 46, 00, 4e] +Raw bytes (15): 0x[01, 01, 00, 02, 01, 8c, 01, 3d, 00, 45, 01, 00, 46, 00, 4e] Number of files: 1 - file 0 => $DIR/closure.rs Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 140, 70) to (start + 0, 78) +Number of file 0 mappings: 2 +- Code(Counter(0)) at (prev + 140, 61) to (start + 0, 69) +- Code(Counter(0)) at (prev + 0, 70) to (start + 0, 78) Highest counter ID seen: c0 Function name: closure::main::{closure#6} -Raw bytes (10): 0x[01, 01, 00, 01, 01, 8d, 01, 4a, 00, 56] +Raw bytes (15): 0x[01, 01, 00, 02, 01, 8d, 01, 41, 00, 49, 01, 00, 4a, 00, 56] Number of files: 1 - file 0 => $DIR/closure.rs Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 141, 74) to (start + 0, 86) +Number of file 0 mappings: 2 +- Code(Counter(0)) at (prev + 141, 65) to (start + 0, 73) +- Code(Counter(0)) at (prev + 0, 74) to (start + 0, 86) Highest counter ID seen: c0 Function name: closure::main::{closure#7} (unused) -Raw bytes (10): 0x[01, 01, 00, 01, 00, 8e, 01, 44, 00, 50] +Raw bytes (15): 0x[01, 01, 00, 02, 00, 8e, 01, 3b, 00, 43, 00, 00, 44, 00, 50] Number of files: 1 - file 0 => $DIR/closure.rs Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Zero) at (prev + 142, 68) to (start + 0, 80) +Number of file 0 mappings: 2 +- Code(Zero) at (prev + 142, 59) to (start + 0, 67) +- Code(Zero) at (prev + 0, 68) to (start + 0, 80) Highest counter ID seen: (none) Function name: closure::main::{closure#8} (unused) diff --git a/tests/coverage/closure.coverage b/tests/coverage/closure.coverage index 142852692289..d44ecf5a69e2 100644 --- a/tests/coverage/closure.coverage +++ b/tests/coverage/closure.coverage @@ -139,9 +139,9 @@ LL| | LL| 1| let short_used_covered_closure_macro = | used_arg: u8 | println!("called"); LL| 1| let short_used_not_covered_closure_macro = | used_arg: u8 | println!("not called"); - ^0 + ^0 ^0 LL| 1| let _short_unused_closure_macro = | _unused_arg: u8 | println!("not called"); - ^0 + ^0 ^0 LL| | LL| | LL| | @@ -173,7 +173,7 @@ LL| | LL| 1| let _short_unused_closure_line_break_no_block2 = LL| | | _unused_arg: u8 | - LL| | println!( + LL| 0| println!( LL| 0| "not called" LL| | ) LL| | ; diff --git a/tests/coverage/macro_in_closure.cov-map b/tests/coverage/macro_in_closure.cov-map index 4544aa50143e..3529d0c4c321 100644 --- a/tests/coverage/macro_in_closure.cov-map +++ b/tests/coverage/macro_in_closure.cov-map @@ -1,10 +1,11 @@ Function name: macro_in_closure::NO_BLOCK::{closure#0} -Raw bytes (9): 0x[01, 01, 00, 01, 01, 07, 25, 00, 2c] +Raw bytes (14): 0x[01, 01, 00, 02, 01, 07, 1c, 00, 24, 01, 00, 25, 00, 2c] Number of files: 1 - file 0 => $DIR/macro_in_closure.rs Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 7, 37) to (start + 0, 44) +Number of file 0 mappings: 2 +- Code(Counter(0)) at (prev + 7, 28) to (start + 0, 36) +- Code(Counter(0)) at (prev + 0, 37) to (start + 0, 44) Highest counter ID seen: c0 Function name: macro_in_closure::WITH_BLOCK::{closure#0} From 75d8687f2b6ac1e73071450cb57c4157fcba53b4 Mon Sep 17 00:00:00 2001 From: Valdemar Erk Date: Sat, 23 Aug 2025 11:37:53 +0200 Subject: [PATCH 05/48] add span to struct pattern rest (..) --- compiler/rustc_ast/src/ast.rs | 6 +++--- compiler/rustc_ast_lowering/src/expr.rs | 6 +++--- compiler/rustc_ast_lowering/src/lib.rs | 2 +- compiler/rustc_ast_lowering/src/pat.rs | 9 +++++---- compiler/rustc_ast_pretty/src/pprust/state.rs | 2 +- compiler/rustc_hir/src/hir.rs | 8 ++++---- compiler/rustc_hir_pretty/src/lib.rs | 4 ++-- compiler/rustc_hir_typeck/src/pat.rs | 12 +++++++++-- compiler/rustc_parse/src/parser/pat.rs | 2 +- compiler/rustc_passes/src/liveness.rs | 2 +- compiler/rustc_resolve/src/late.rs | 2 +- .../clippy_lints/src/equatable_if_let.rs | 2 +- .../clippy_lints/src/manual_let_else.rs | 4 ++-- .../matches/rest_pat_in_fully_bound_struct.rs | 2 +- .../clippy/clippy_lints/src/utils/author.rs | 3 ++- src/tools/clippy/clippy_utils/src/lib.rs | 2 +- src/tools/rustfmt/src/patterns.rs | 2 +- tests/ui/stats/input-stats.stderr | 20 +++++++++---------- 18 files changed, 50 insertions(+), 40 deletions(-) diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index de3e0e0c87f5..802a6fa32498 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -937,7 +937,7 @@ pub enum PatKind { #[derive(Clone, Copy, Encodable, Decodable, Debug, PartialEq, Walkable)] pub enum PatFieldsRest { /// `module::StructName { field, ..}` - Rest, + Rest(Span), /// `module::StructName { field, syntax error }` Recovered(ErrorGuaranteed), /// `module::StructName { field }` @@ -4051,8 +4051,8 @@ mod size_asserts { static_assert_size!(Local, 96); static_assert_size!(MetaItemLit, 40); static_assert_size!(Param, 40); - static_assert_size!(Pat, 72); - static_assert_size!(PatKind, 48); + static_assert_size!(Pat, 80); + static_assert_size!(PatKind, 56); static_assert_size!(Path, 24); static_assert_size!(PathSegment, 24); static_assert_size!(Stmt, 32); diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index cbd17d66b754..3674814b796c 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -1434,10 +1434,10 @@ impl<'hir> LoweringContext<'_, 'hir> { self.dcx().emit_err(FunctionalRecordUpdateDestructuringAssignment { span: e.span, }); - true + Some(self.lower_span(e.span)) } - StructRest::Rest(_) => true, - StructRest::None => false, + StructRest::Rest(span) => Some(self.lower_span(*span)), + StructRest::None => None, }; let struct_pat = hir::PatKind::Struct(qpath, field_pats, fields_omitted); return self.pat_without_dbm(lhs.span, struct_pat); diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 70595391b85b..137207bde1f1 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -2508,7 +2508,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { fields: &'hir [hir::PatField<'hir>], ) -> &'hir hir::Pat<'hir> { let qpath = hir::QPath::LangItem(lang_item, self.lower_span(span)); - self.pat(span, hir::PatKind::Struct(qpath, fields, false)) + self.pat(span, hir::PatKind::Struct(qpath, fields, None)) } fn pat_ident(&mut self, span: Span, ident: Ident) -> (&'hir hir::Pat<'hir>, HirId) { diff --git a/compiler/rustc_ast_lowering/src/pat.rs b/compiler/rustc_ast_lowering/src/pat.rs index b8f862478756..ed159f37051c 100644 --- a/compiler/rustc_ast_lowering/src/pat.rs +++ b/compiler/rustc_ast_lowering/src/pat.rs @@ -106,10 +106,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { break hir::PatKind::Struct( qpath, fs, - matches!( - etc, - ast::PatFieldsRest::Rest | ast::PatFieldsRest::Recovered(_) - ), + match etc { + ast::PatFieldsRest::Rest(sp) => Some(self.lower_span(*sp)), + ast::PatFieldsRest::Recovered(_) => Some(Span::default()), + _ => None, + }, ); } PatKind::Tuple(pats) => { diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs index a056ce3e29d2..41b520b04c99 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state.rs @@ -1769,7 +1769,7 @@ impl<'a> State<'a> { }, |f| f.pat.span, ); - if let ast::PatFieldsRest::Rest | ast::PatFieldsRest::Recovered(_) = etc { + if let ast::PatFieldsRest::Rest(_) | ast::PatFieldsRest::Recovered(_) = etc { if !fields.is_empty() { self.word_space(","); } diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index e397c286de28..e3c27c73638c 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -1884,8 +1884,8 @@ pub enum PatKind<'hir> { Binding(BindingMode, HirId, Ident, Option<&'hir Pat<'hir>>), /// A struct or struct variant pattern (e.g., `Variant {x, y, ..}`). - /// The `bool` is `true` in the presence of a `..`. - Struct(QPath<'hir>, &'hir [PatField<'hir>], bool), + /// The `Option` contains the span of a possible `..`. + Struct(QPath<'hir>, &'hir [PatField<'hir>], Option), /// A tuple struct/variant pattern `Variant(x, y, .., z)`. /// If the `..` pattern fragment is present, then `DotDotPos` denotes its position. @@ -4979,8 +4979,8 @@ mod size_asserts { static_assert_size!(ItemKind<'_>, 64); static_assert_size!(LetStmt<'_>, 72); static_assert_size!(Param<'_>, 32); - static_assert_size!(Pat<'_>, 72); - static_assert_size!(PatKind<'_>, 48); + static_assert_size!(Pat<'_>, 80); + static_assert_size!(PatKind<'_>, 56); static_assert_size!(Path<'_>, 40); static_assert_size!(PathSegment<'_>, 48); static_assert_size!(QPath<'_>, 24); diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index be5859b57c5e..52b29e05dcb0 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -1958,12 +1958,12 @@ impl<'a> State<'a> { self.print_qpath(qpath, true); self.nbsp(); self.word("{"); - let empty = fields.is_empty() && !etc; + let empty = fields.is_empty() && etc.is_none(); if !empty { self.space(); } self.commasep_cmnt(Consistent, fields, |s, f| s.print_patfield(f), |f| f.pat.span); - if etc { + if etc.is_some() { if !fields.is_empty() { self.word_space(","); } diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs index 7dc736e5e6b1..f735c0a41609 100644 --- a/compiler/rustc_hir_typeck/src/pat.rs +++ b/compiler/rustc_hir_typeck/src/pat.rs @@ -605,7 +605,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }, PatKind::Struct(_, fields, has_rest_pat) => match opt_path_res.unwrap() { Ok(ResolvedPat { ty, kind: ResolvedPatKind::Struct { variant } }) => self - .check_pat_struct(pat, fields, has_rest_pat, ty, variant, expected, pat_info), + .check_pat_struct( + pat, + fields, + has_rest_pat.is_some(), + ty, + variant, + expected, + pat_info, + ), Err(guar) => { let ty_err = Ty::new_error(self.tcx, guar); for field in fields { @@ -2428,7 +2436,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let len = unmentioned_fields.len(); let (prefix, postfix, sp) = match fields { [] => match &pat.kind { - PatKind::Struct(path, [], false) => { + PatKind::Struct(path, [], None) => { (" { ", " }", path.span().shrink_to_hi().until(pat.span.shrink_to_hi())) } _ => return err, diff --git a/compiler/rustc_parse/src/parser/pat.rs b/compiler/rustc_parse/src/parser/pat.rs index 9754691a0b9c..c4d30b3d3283 100644 --- a/compiler/rustc_parse/src/parser/pat.rs +++ b/compiler/rustc_parse/src/parser/pat.rs @@ -1516,7 +1516,7 @@ impl<'a> Parser<'a> { || self.check_noexpect(&token::DotDotDot) || self.check_keyword(exp!(Underscore)) { - etc = PatFieldsRest::Rest; + etc = PatFieldsRest::Rest(self.token.span); let mut etc_sp = self.token.span; if first_etc_and_maybe_comma_span.is_none() { if let Some(comma_tok) = diff --git a/compiler/rustc_passes/src/liveness.rs b/compiler/rustc_passes/src/liveness.rs index 801a533c9433..ae16a51bc693 100644 --- a/compiler/rustc_passes/src/liveness.rs +++ b/compiler/rustc_passes/src/liveness.rs @@ -1583,7 +1583,7 @@ impl<'tcx> Liveness<'_, 'tcx> { }); let can_remove = match pat.kind { - hir::PatKind::Struct(_, fields, true) => { + hir::PatKind::Struct(_, fields, Some(_)) => { // if all fields are shorthand, remove the struct field, otherwise, mark with _ as prefix fields.iter().all(|f| f.is_shorthand) } diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 679e663f8861..84108f0b8663 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -3922,7 +3922,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { fn record_patterns_with_skipped_bindings(&mut self, pat: &Pat, rest: &ast::PatFieldsRest) { match rest { - ast::PatFieldsRest::Rest | ast::PatFieldsRest::Recovered(_) => { + ast::PatFieldsRest::Rest(_) | ast::PatFieldsRest::Recovered(_) => { // Record that the pattern doesn't introduce all the bindings it could. if let Some(partial_res) = self.r.partial_res_map.get(&pat.id) && let Some(res) = partial_res.full_res() diff --git a/src/tools/clippy/clippy_lints/src/equatable_if_let.rs b/src/tools/clippy/clippy_lints/src/equatable_if_let.rs index 72f5eaf8a4bc..c3fc09343dbf 100644 --- a/src/tools/clippy/clippy_lints/src/equatable_if_let.rs +++ b/src/tools/clippy/clippy_lints/src/equatable_if_let.rs @@ -53,7 +53,7 @@ fn unary_pattern(pat: &Pat<'_>) -> bool { | PatKind::Never | PatKind::Or(_) | PatKind::Err(_) => false, - PatKind::Struct(_, a, etc) => !etc && a.iter().all(|x| unary_pattern(x.pat)), + PatKind::Struct(_, a, etc) => etc.is_none() && a.iter().all(|x| unary_pattern(x.pat)), PatKind::Tuple(a, etc) | PatKind::TupleStruct(_, a, etc) => etc.as_opt_usize().is_none() && array_rec(a), PatKind::Ref(x, _) | PatKind::Box(x) | PatKind::Deref(x) | PatKind::Guard(x, _) => unary_pattern(x), PatKind::Expr(_) => true, diff --git a/src/tools/clippy/clippy_lints/src/manual_let_else.rs b/src/tools/clippy/clippy_lints/src/manual_let_else.rs index 5a7967bbf946..2705ef20b795 100644 --- a/src/tools/clippy/clippy_lints/src/manual_let_else.rs +++ b/src/tools/clippy/clippy_lints/src/manual_let_else.rs @@ -287,7 +287,7 @@ fn replace_in_pattern( } return or_pat; }, - PatKind::Struct(path, fields, has_dot_dot) => { + PatKind::Struct(path, fields, dot_dot) => { let fields = fields .iter() .map(|fld| { @@ -311,7 +311,7 @@ fn replace_in_pattern( .collect::>(); let fields_string = fields.join(", "); - let dot_dot_str = if has_dot_dot { " .." } else { "" }; + let dot_dot_str = if dot_dot.is_some() { " .." } else { "" }; let (sn_pth, _) = snippet_with_context(cx, path.span(), span.ctxt(), "", app); return format!("{sn_pth} {{ {fields_string}{dot_dot_str} }}"); }, diff --git a/src/tools/clippy/clippy_lints/src/matches/rest_pat_in_fully_bound_struct.rs b/src/tools/clippy/clippy_lints/src/matches/rest_pat_in_fully_bound_struct.rs index 2154cd5b24a5..ae09c2e87d6b 100644 --- a/src/tools/clippy/clippy_lints/src/matches/rest_pat_in_fully_bound_struct.rs +++ b/src/tools/clippy/clippy_lints/src/matches/rest_pat_in_fully_bound_struct.rs @@ -7,7 +7,7 @@ use super::REST_PAT_IN_FULLY_BOUND_STRUCTS; pub(crate) fn check(cx: &LateContext<'_>, pat: &Pat<'_>) { if !pat.span.from_expansion() - && let PatKind::Struct(QPath::Resolved(_, path), fields, true) = pat.kind + && let PatKind::Struct(QPath::Resolved(_, path), fields, Some(_)) = pat.kind && let Some(def_id) = path.res.opt_def_id() && let ty = cx.tcx.type_of(def_id).instantiate_identity() && let ty::Adt(def, _) = ty.kind() diff --git a/src/tools/clippy/clippy_lints/src/utils/author.rs b/src/tools/clippy/clippy_lints/src/utils/author.rs index 2113cb92137e..ece29362a39f 100644 --- a/src/tools/clippy/clippy_lints/src/utils/author.rs +++ b/src/tools/clippy/clippy_lints/src/utils/author.rs @@ -754,7 +754,8 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> { self.ident(name); sub.if_some(|p| self.pat(p)); }, - PatKind::Struct(ref qpath, fields, ignore) => { + PatKind::Struct(ref qpath, fields, etc) => { + let ignore = etc.is_some(); bind!(self, qpath, fields); kind!("Struct(ref {qpath}, {fields}, {ignore})"); self.qpath(qpath, pat); diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs index 8533fa855419..011c9b2f931a 100644 --- a/src/tools/clippy/clippy_utils/src/lib.rs +++ b/src/tools/clippy/clippy_utils/src/lib.rs @@ -2011,7 +2011,7 @@ pub fn is_expr_identity_of_pat(cx: &LateContext<'_>, pat: &Pat<'_>, expr: &Expr< false } }, - (PatKind::Struct(pat_ident, field_pats, false), ExprKind::Struct(ident, fields, hir::StructTailExpr::None)) + (PatKind::Struct(pat_ident, field_pats, None), ExprKind::Struct(ident, fields, hir::StructTailExpr::None)) if field_pats.len() == fields.len() => { // check ident diff --git a/src/tools/rustfmt/src/patterns.rs b/src/tools/rustfmt/src/patterns.rs index d212ecf392a7..848bd0766e78 100644 --- a/src/tools/rustfmt/src/patterns.rs +++ b/src/tools/rustfmt/src/patterns.rs @@ -303,7 +303,7 @@ impl Rewrite for Pat { qself, path, fields, - rest == ast::PatFieldsRest::Rest, + matches!(rest, ast::PatFieldsRest::Rest(_)), self.span, context, shape, diff --git a/tests/ui/stats/input-stats.stderr b/tests/ui/stats/input-stats.stderr index 72a9820bb643..4a73a4747ad0 100644 --- a/tests/ui/stats/input-stats.stderr +++ b/tests/ui/stats/input-stats.stderr @@ -23,10 +23,10 @@ ast-stats - Path 72 (NN.N%) 1 ast-stats - Struct 72 (NN.N%) 1 ast-stats - Lit 144 (NN.N%) 2 ast-stats - Block 216 (NN.N%) 3 -ast-stats Pat 504 (NN.N%) 7 72 -ast-stats - Struct 72 (NN.N%) 1 -ast-stats - Wild 72 (NN.N%) 1 -ast-stats - Ident 360 (NN.N%) 5 +ast-stats Pat 560 (NN.N%) 7 80 +ast-stats - Struct 80 (NN.N%) 1 +ast-stats - Wild 80 (NN.N%) 1 +ast-stats - Ident 400 (NN.N%) 5 ast-stats GenericParam 480 (NN.N%) 5 96 ast-stats GenericBound 352 (NN.N%) 4 88 ast-stats - Trait 352 (NN.N%) 4 @@ -57,7 +57,7 @@ ast-stats GenericArgs 40 (NN.N%) 1 40 ast-stats - AngleBracketed 40 (NN.N%) 1 ast-stats Crate 40 (NN.N%) 1 40 ast-stats ---------------------------------------------------------------- -ast-stats Total 7_472 129 +ast-stats Total 7_528 129 ast-stats ================================================================ hir-stats ================================================================ hir-stats HIR STATS: input_stats @@ -85,11 +85,11 @@ hir-stats - Ptr 48 (NN.N%) 1 hir-stats - Ref 48 (NN.N%) 1 hir-stats - Path 624 (NN.N%) 13 hir-stats Generics 560 (NN.N%) 10 56 +hir-stats Pat 400 (NN.N%) 5 80 +hir-stats - Struct 80 (NN.N%) 1 +hir-stats - Wild 80 (NN.N%) 1 +hir-stats - Binding 240 (NN.N%) 3 hir-stats GenericParam 400 (NN.N%) 5 80 -hir-stats Pat 360 (NN.N%) 5 72 -hir-stats - Struct 72 (NN.N%) 1 -hir-stats - Wild 72 (NN.N%) 1 -hir-stats - Binding 216 (NN.N%) 3 hir-stats Block 288 (NN.N%) 6 48 hir-stats GenericBound 256 (NN.N%) 4 64 hir-stats - Trait 256 (NN.N%) 4 @@ -119,5 +119,5 @@ hir-stats TraitItemId 8 (NN.N%) 2 4 hir-stats ImplItemId 8 (NN.N%) 2 4 hir-stats ForeignItemId 4 (NN.N%) 1 4 hir-stats ---------------------------------------------------------------- -hir-stats Total 8_584 173 +hir-stats Total 8_624 173 hir-stats ================================================================ From 142e25e35621b7043cc86bdc3d74f463ca2032d1 Mon Sep 17 00:00:00 2001 From: Ed Page Date: Fri, 22 Aug 2025 10:46:47 -0500 Subject: [PATCH 06/48] fix(lexer): Don't require frontmatters to be escaped with indented fences The RFC only limits hyphens at the beginning of lines and not if they are indented or embedded in other content. Sticking to that approach was confirmed by the T-lang liason at https://github.com/rust-lang/rust/issues/141367#issuecomment-3202217544 There is a regression in error message quality which I'm leaving for someone if they feel this needs improving. --- compiler/rustc_lexer/src/lib.rs | 34 ++++++-------- .../frontmatter/frontmatter-whitespace-1.rs | 2 +- .../frontmatter-whitespace-1.stderr | 22 ++++++---- .../frontmatter/frontmatter-whitespace-2.rs | 5 +-- .../frontmatter-whitespace-2.stderr | 44 ++++++++++--------- tests/ui/frontmatter/multifrontmatter-2.rs | 6 +-- .../ui/frontmatter/multifrontmatter-2.stderr | 22 ---------- 7 files changed, 56 insertions(+), 79 deletions(-) delete mode 100644 tests/ui/frontmatter/multifrontmatter-2.stderr diff --git a/compiler/rustc_lexer/src/lib.rs b/compiler/rustc_lexer/src/lib.rs index 483cc3e93dc2..d10b19203435 100644 --- a/compiler/rustc_lexer/src/lib.rs +++ b/compiler/rustc_lexer/src/lib.rs @@ -550,28 +550,20 @@ impl Cursor<'_> { self.eat_while(|ch| ch != '\n' && is_whitespace(ch)); let invalid_infostring = self.first() != '\n'; - let mut s = self.as_str(); let mut found = false; - let mut size = 0; - while let Some(closing) = s.find(&"-".repeat(length_opening as usize)) { - let preceding_chars_start = s[..closing].rfind("\n").map_or(0, |i| i + 1); - if s[preceding_chars_start..closing].chars().all(is_whitespace) { - // candidate found - self.bump_bytes(size + closing); - // in case like - // ---cargo - // --- blahblah - // or - // ---cargo - // ---- - // combine those stuff into this frontmatter token such that it gets detected later. - self.eat_until(b'\n'); - found = true; - break; - } else { - s = &s[closing + length_opening as usize..]; - size += closing + length_opening as usize; - } + let nl_fence_pattern = format!("\n{:-<1$}", "", length_opening as usize); + if let Some(closing) = self.as_str().find(&nl_fence_pattern) { + // candidate found + self.bump_bytes(closing + nl_fence_pattern.len()); + // in case like + // ---cargo + // --- blahblah + // or + // ---cargo + // ---- + // combine those stuff into this frontmatter token such that it gets detected later. + self.eat_until(b'\n'); + found = true; } if !found { diff --git a/tests/ui/frontmatter/frontmatter-whitespace-1.rs b/tests/ui/frontmatter/frontmatter-whitespace-1.rs index 8b6e2d1af849..3b7f762d26ea 100644 --- a/tests/ui/frontmatter/frontmatter-whitespace-1.rs +++ b/tests/ui/frontmatter/frontmatter-whitespace-1.rs @@ -1,7 +1,7 @@ --- //~^ ERROR: invalid preceding whitespace for frontmatter opening +//~^^ ERROR: unclosed frontmatter --- -//~^ ERROR: invalid preceding whitespace for frontmatter close #![feature(frontmatter)] diff --git a/tests/ui/frontmatter/frontmatter-whitespace-1.stderr b/tests/ui/frontmatter/frontmatter-whitespace-1.stderr index 37ece27acb22..f16788fa3992 100644 --- a/tests/ui/frontmatter/frontmatter-whitespace-1.stderr +++ b/tests/ui/frontmatter/frontmatter-whitespace-1.stderr @@ -10,17 +10,21 @@ note: frontmatter opening should not be preceded by whitespace LL | --- | ^^ -error: invalid preceding whitespace for frontmatter close - --> $DIR/frontmatter-whitespace-1.rs:3:1 +error: unclosed frontmatter + --> $DIR/frontmatter-whitespace-1.rs:1:3 + | +LL | / --- +LL | | +LL | | +LL | | --- +LL | | + | |_^ + | +note: frontmatter opening here was not closed + --> $DIR/frontmatter-whitespace-1.rs:1:3 | LL | --- - | ^^^^^ - | -note: frontmatter close should not be preceded by whitespace - --> $DIR/frontmatter-whitespace-1.rs:3:1 - | -LL | --- - | ^^ + | ^^^ error: aborting due to 2 previous errors diff --git a/tests/ui/frontmatter/frontmatter-whitespace-2.rs b/tests/ui/frontmatter/frontmatter-whitespace-2.rs index e8c100849b40..7a28e5c1b85a 100644 --- a/tests/ui/frontmatter/frontmatter-whitespace-2.rs +++ b/tests/ui/frontmatter/frontmatter-whitespace-2.rs @@ -1,4 +1,5 @@ ---cargo +//~^ ERROR: unclosed frontmatter //@ compile-flags: --crate-type lib @@ -6,10 +7,8 @@ fn foo(x: i32) -> i32 { ---x - //~^ ERROR: invalid preceding whitespace for frontmatter close - //~| ERROR: extra characters after frontmatter close are not allowed + //~^ WARNING: use of a double negation [double_negations] } -//~^ ERROR: unexpected closing delimiter: `}` // this test is for the weird case that valid Rust code can have three dashes // within them and get treated as a frontmatter close. diff --git a/tests/ui/frontmatter/frontmatter-whitespace-2.stderr b/tests/ui/frontmatter/frontmatter-whitespace-2.stderr index ada6af0ec04c..2ae63cdc6fe4 100644 --- a/tests/ui/frontmatter/frontmatter-whitespace-2.stderr +++ b/tests/ui/frontmatter/frontmatter-whitespace-2.stderr @@ -1,26 +1,30 @@ -error: invalid preceding whitespace for frontmatter close - --> $DIR/frontmatter-whitespace-2.rs:8:1 +error: unclosed frontmatter + --> $DIR/frontmatter-whitespace-2.rs:1:1 + | +LL | / ---cargo +... | +LL | | + | |_^ + | +note: frontmatter opening here was not closed + --> $DIR/frontmatter-whitespace-2.rs:1:1 + | +LL | ---cargo + | ^^^ + +warning: use of a double negation + --> $DIR/frontmatter-whitespace-2.rs:9:6 | LL | ---x - | ^^^^^^^^ + | ^^^ | -note: frontmatter close should not be preceded by whitespace - --> $DIR/frontmatter-whitespace-2.rs:8:1 + = note: the prefix `--` could be misinterpreted as a decrement operator which exists in other languages + = note: use `-= 1` if you meant to decrement the value + = note: `#[warn(double_negations)]` on by default +help: add parentheses for clarity | -LL | ---x - | ^^^^ +LL | --(-x) + | + + -error: extra characters after frontmatter close are not allowed - --> $DIR/frontmatter-whitespace-2.rs:8:1 - | -LL | ---x - | ^^^^^^^^ - -error: unexpected closing delimiter: `}` - --> $DIR/frontmatter-whitespace-2.rs:11:1 - | -LL | } - | ^ unexpected closing delimiter - -error: aborting due to 3 previous errors +error: aborting due to 1 previous error; 1 warning emitted diff --git a/tests/ui/frontmatter/multifrontmatter-2.rs b/tests/ui/frontmatter/multifrontmatter-2.rs index 33cc30cb4655..8e5b45a0bf75 100644 --- a/tests/ui/frontmatter/multifrontmatter-2.rs +++ b/tests/ui/frontmatter/multifrontmatter-2.rs @@ -1,12 +1,12 @@ --- --- -//~^ ERROR: invalid preceding whitespace for frontmatter close --- -//~^ ERROR: expected item, found `-` -// FIXME(frontmatter): make this diagnostic better --- +// hyphens only need to be escaped when at the start of a line +//@ check-pass + #![feature(frontmatter)] fn main() {} diff --git a/tests/ui/frontmatter/multifrontmatter-2.stderr b/tests/ui/frontmatter/multifrontmatter-2.stderr deleted file mode 100644 index ed9ac4029e27..000000000000 --- a/tests/ui/frontmatter/multifrontmatter-2.stderr +++ /dev/null @@ -1,22 +0,0 @@ -error: invalid preceding whitespace for frontmatter close - --> $DIR/multifrontmatter-2.rs:2:1 - | -LL | --- - | ^^^^ - | -note: frontmatter close should not be preceded by whitespace - --> $DIR/multifrontmatter-2.rs:2:1 - | -LL | --- - | ^ - -error: expected item, found `-` - --> $DIR/multifrontmatter-2.rs:5:2 - | -LL | --- - | ^ expected item - | - = note: for a full list of items that can appear in modules, see - -error: aborting due to 2 previous errors - From 0edb22cdbf8f25bede8d46e706b181457e27003a Mon Sep 17 00:00:00 2001 From: lcnr Date: Thu, 28 Aug 2025 09:57:36 +0200 Subject: [PATCH 07/48] cleanup proof tree implementation and add cache --- compiler/rustc_interface/src/passes.rs | 3 +- compiler/rustc_middle/src/arena.rs | 1 + compiler/rustc_middle/src/query/erase.rs | 5 + compiler/rustc_middle/src/query/mod.rs | 10 +- compiler/rustc_middle/src/ty/context.rs | 15 +- .../src/solve/eval_ctxt/canonical.rs | 47 +- .../src/solve/eval_ctxt/mod.rs | 151 ++++--- .../src/solve/inspect/build.rs | 409 +++++------------- .../rustc_next_trait_solver/src/solve/mod.rs | 11 +- .../src/solve/search_graph.rs | 14 +- compiler/rustc_trait_selection/src/solve.rs | 16 + .../src/solve/inspect/analyse.rs | 18 +- compiler/rustc_type_ir/src/interner.rs | 11 +- .../rustc_type_ir/src/search_graph/mod.rs | 42 +- compiler/rustc_type_ir/src/solve/inspect.rs | 29 +- 15 files changed, 336 insertions(+), 446 deletions(-) diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index bc5ef04079ed..ca8c10311fb8 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -41,7 +41,7 @@ use rustc_span::{ Symbol, sym, }; use rustc_target::spec::PanicStrategy; -use rustc_trait_selection::traits; +use rustc_trait_selection::{solve, traits}; use tracing::{info, instrument}; use crate::interface::Compiler; @@ -895,6 +895,7 @@ pub static DEFAULT_QUERY_PROVIDERS: LazyLock = LazyLock::new(|| { rustc_hir_typeck::provide(providers); ty::provide(providers); traits::provide(providers); + solve::provide(providers); rustc_passes::provide(providers); rustc_traits::provide(providers); rustc_ty_utils::provide(providers); diff --git a/compiler/rustc_middle/src/arena.rs b/compiler/rustc_middle/src/arena.rs index 4b6e38cd52dd..52fbe19c9f2d 100644 --- a/compiler/rustc_middle/src/arena.rs +++ b/compiler/rustc_middle/src/arena.rs @@ -80,6 +80,7 @@ macro_rules! arena_types { rustc_middle::infer::canonical::Canonical<'tcx, rustc_middle::infer::canonical::QueryResponse<'tcx, rustc_middle::ty::Ty<'tcx>> >, + [] inspect_probe: rustc_middle::traits::solve::inspect::Probe>, [] effective_visibilities: rustc_middle::middle::privacy::EffectiveVisibilities, [] upvars_mentioned: rustc_data_structures::fx::FxIndexMap, [] dyn_compatibility_violations: rustc_middle::traits::DynCompatibilityViolation, diff --git a/compiler/rustc_middle/src/query/erase.rs b/compiler/rustc_middle/src/query/erase.rs index ea62461ebeb6..bea2191c5601 100644 --- a/compiler/rustc_middle/src/query/erase.rs +++ b/compiler/rustc_middle/src/query/erase.rs @@ -6,6 +6,7 @@ use rustc_span::ErrorGuaranteed; use crate::mir::interpret::EvalToValTreeResult; use crate::query::CyclePlaceholder; +use crate::traits::solve; use crate::ty::adjustment::CoerceUnsizedInfo; use crate::ty::{self, Ty, TyCtxt}; use crate::{mir, traits}; @@ -219,6 +220,10 @@ impl EraseType for (&'_ T0, &'_ T1) { type Result = [u8; size_of::<(&'static (), &'static ())>()]; } +impl EraseType for (solve::QueryResult<'_>, &'_ T0) { + type Result = [u8; size_of::<(solve::QueryResult<'static>, &'static ())>()]; +} + impl EraseType for (&'_ T0, &'_ [T1]) { type Result = [u8; size_of::<(&'static (), &'static [()])>()]; } diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 7bd8a0525a2c..1855c0ef6a65 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -131,7 +131,7 @@ use crate::traits::query::{ }; use crate::traits::{ CodegenObligationError, DynCompatibilityViolation, EvaluationResult, ImplSource, - ObligationCause, OverflowError, WellFormedLoc, specialization_graph, + ObligationCause, OverflowError, WellFormedLoc, solve, specialization_graph, }; use crate::ty::fast_reject::SimplifiedType; use crate::ty::layout::ValidityRequirement; @@ -2561,6 +2561,14 @@ rustc_queries! { desc { "computing autoderef types for `{}`", goal.canonical.value.value } } + /// Used by `-Znext-solver` to compute proof trees. + query evaluate_root_goal_for_proof_tree_raw( + goal: solve::CanonicalInput<'tcx>, + ) -> (solve::QueryResult<'tcx>, &'tcx solve::inspect::Probe>) { + no_hash + desc { "computing proof tree for `{}`", goal.canonical.value.goal.predicate } + } + /// Returns the Rust target features for the current target. These are not always the same as LLVM target features! query rust_target_features(_: CrateNum) -> &'tcx UnordMap { arena_cache diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 5dbbc7297ab6..72ab6ac612c6 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -72,9 +72,9 @@ use crate::query::plumbing::QuerySystem; use crate::query::{IntoQueryParam, LocalCrate, Providers, TyCtxtAt}; use crate::thir::Thir; use crate::traits; -use crate::traits::solve; use crate::traits::solve::{ - ExternalConstraints, ExternalConstraintsData, PredefinedOpaques, PredefinedOpaquesData, + self, CanonicalInput, ExternalConstraints, ExternalConstraintsData, PredefinedOpaques, + PredefinedOpaquesData, QueryResult, inspect, }; use crate::ty::predicate::ExistentialPredicateStableCmpExt as _; use crate::ty::{ @@ -737,6 +737,17 @@ impl<'tcx> Interner for TyCtxt<'tcx> { self.opaque_types_defined_by(defining_anchor).iter().chain(coroutines_defined_by), ) } + + type ProbeRef = &'tcx inspect::Probe>; + fn mk_probe_ref(self, probe: inspect::Probe) -> &'tcx inspect::Probe> { + self.arena.alloc(probe) + } + fn evaluate_root_goal_for_proof_tree_raw( + self, + canonical_goal: CanonicalInput<'tcx>, + ) -> (QueryResult<'tcx>, &'tcx inspect::Probe>) { + self.evaluate_root_goal_for_proof_tree_raw(canonical_goal) + } } macro_rules! bidirectional_lang_item_map { diff --git a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/canonical.rs b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/canonical.rs index 4644b145b18a..6f9f40673847 100644 --- a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/canonical.rs +++ b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/canonical.rs @@ -56,22 +56,23 @@ where /// /// This expects `goal` and `opaque_types` to be eager resolved. pub(super) fn canonicalize_goal( - &self, + delegate: &D, goal: Goal, opaque_types: Vec<(ty::OpaqueTypeKey, I::Ty)>, ) -> (Vec, CanonicalInput) { let mut orig_values = Default::default(); let canonical = Canonicalizer::canonicalize_input( - self.delegate, + delegate, &mut orig_values, QueryInput { goal, - predefined_opaques_in_body: self + predefined_opaques_in_body: delegate .cx() .mk_predefined_opaques_in_body(PredefinedOpaquesData { opaque_types }), }, ); - let query_input = ty::CanonicalQueryInput { canonical, typing_mode: self.typing_mode() }; + let query_input = + ty::CanonicalQueryInput { canonical, typing_mode: delegate.typing_mode() }; (orig_values, query_input) } @@ -271,28 +272,23 @@ where /// - we apply the `external_constraints` returned by the query, returning /// the `normalization_nested_goals` pub(super) fn instantiate_and_apply_query_response( - &mut self, + delegate: &D, param_env: I::ParamEnv, original_values: &[I::GenericArg], response: CanonicalResponse, + span: I::Span, ) -> (NestedNormalizationGoals, Certainty) { let instantiation = Self::compute_query_response_instantiation_values( - self.delegate, + delegate, &original_values, &response, - self.origin_span, + span, ); let Response { var_values, external_constraints, certainty } = - self.delegate.instantiate_canonical(response, instantiation); + delegate.instantiate_canonical(response, instantiation); - Self::unify_query_var_values( - self.delegate, - param_env, - &original_values, - var_values, - self.origin_span, - ); + Self::unify_query_var_values(delegate, param_env, &original_values, var_values, span); let ExternalConstraintsData { region_constraints, @@ -300,8 +296,8 @@ where normalization_nested_goals, } = &*external_constraints; - self.register_region_constraints(region_constraints); - self.register_new_opaque_types(opaque_types); + Self::register_region_constraints(delegate, region_constraints, span); + Self::register_new_opaque_types(delegate, opaque_types, span); (normalization_nested_goals.clone(), certainty) } @@ -424,21 +420,26 @@ where } fn register_region_constraints( - &mut self, + delegate: &D, outlives: &[ty::OutlivesPredicate], + span: I::Span, ) { for &ty::OutlivesPredicate(lhs, rhs) in outlives { match lhs.kind() { - ty::GenericArgKind::Lifetime(lhs) => self.register_region_outlives(lhs, rhs), - ty::GenericArgKind::Type(lhs) => self.register_ty_outlives(lhs, rhs), + ty::GenericArgKind::Lifetime(lhs) => delegate.sub_regions(rhs, lhs, span), + ty::GenericArgKind::Type(lhs) => delegate.register_ty_outlives(lhs, rhs, span), ty::GenericArgKind::Const(_) => panic!("const outlives: {lhs:?}: {rhs:?}"), } } } - fn register_new_opaque_types(&mut self, opaque_types: &[(ty::OpaqueTypeKey, I::Ty)]) { + fn register_new_opaque_types( + delegate: &D, + opaque_types: &[(ty::OpaqueTypeKey, I::Ty)], + span: I::Span, + ) { for &(key, ty) in opaque_types { - let prev = self.delegate.register_hidden_type_in_storage(key, ty, self.origin_span); + let prev = delegate.register_hidden_type_in_storage(key, ty, span); // We eagerly resolve inference variables when computing the query response. // This can cause previously distinct opaque type keys to now be structurally equal. // @@ -447,7 +448,7 @@ where // types here. However, doing so is difficult as it may result in nested goals and // any errors may make it harder to track the control flow for diagnostics. if let Some(prev) = prev { - self.delegate.add_duplicate_opaque_type(key, prev, self.origin_span); + delegate.add_duplicate_opaque_type(key, prev, span); } } } diff --git a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs index 4f87902e46e9..31106a745279 100644 --- a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs @@ -20,13 +20,12 @@ use crate::coherence; use crate::delegate::SolverDelegate; use crate::placeholder::BoundVarReplacer; use crate::resolve::eager_resolve_vars; -use crate::solve::inspect::{self, ProofTreeBuilder}; use crate::solve::search_graph::SearchGraph; use crate::solve::ty::may_use_unstable_feature; use crate::solve::{ - CanonicalInput, Certainty, FIXPOINT_STEP_LIMIT, Goal, GoalEvaluation, GoalEvaluationKind, - GoalSource, GoalStalledOn, HasChanged, NestedNormalizationGoals, NoSolution, QueryInput, - QueryResult, + CanonicalInput, Certainty, FIXPOINT_STEP_LIMIT, Goal, GoalEvaluation, GoalSource, + GoalStalledOn, HasChanged, NestedNormalizationGoals, NoSolution, QueryInput, QueryResult, + inspect, }; pub(super) mod canonical; @@ -130,7 +129,7 @@ where // evaluation code. tainted: Result<(), NoSolution>, - pub(super) inspect: ProofTreeBuilder, + pub(super) inspect: inspect::EvaluationStepBuilder, } #[derive(PartialEq, Eq, Debug, Hash, Clone, Copy)] @@ -172,10 +171,7 @@ pub trait SolverDelegateEvalExt: SolverDelegate { goal: Goal::Predicate>, span: ::Span, ) -> ( - Result< - (NestedNormalizationGoals, GoalEvaluation), - NoSolution, - >, + Result, NoSolution>, inspect::GoalEvaluation, ); } @@ -192,14 +188,9 @@ where span: I::Span, stalled_on: Option>, ) -> Result, NoSolution> { - EvalCtxt::enter_root( - self, - self.cx().recursion_limit(), - GenerateProofTree::No, - span, - |ecx| ecx.evaluate_goal(GoalEvaluationKind::Root, GoalSource::Misc, goal, stalled_on), - ) - .0 + EvalCtxt::enter_root(self, self.cx().recursion_limit(), span, |ecx| { + ecx.evaluate_goal(GoalSource::Misc, goal, stalled_on) + }) } fn root_goal_may_hold_with_depth( @@ -208,10 +199,9 @@ where goal: Goal::Predicate>, ) -> bool { self.probe(|| { - EvalCtxt::enter_root(self, root_depth, GenerateProofTree::No, I::Span::dummy(), |ecx| { - ecx.evaluate_goal(GoalEvaluationKind::Root, GoalSource::Misc, goal, None) + EvalCtxt::enter_root(self, root_depth, I::Span::dummy(), |ecx| { + ecx.evaluate_goal(GoalSource::Misc, goal, None) }) - .0 }) .is_ok() } @@ -221,18 +211,8 @@ where &self, goal: Goal, span: I::Span, - ) -> ( - Result<(NestedNormalizationGoals, GoalEvaluation), NoSolution>, - inspect::GoalEvaluation, - ) { - let (result, proof_tree) = EvalCtxt::enter_root( - self, - self.cx().recursion_limit(), - GenerateProofTree::Yes, - span, - |ecx| ecx.evaluate_goal_raw(GoalEvaluationKind::Root, GoalSource::Misc, goal, None), - ); - (result, proof_tree.unwrap()) + ) -> (Result, NoSolution>, inspect::GoalEvaluation) { + evaluate_root_goal_for_proof_tree(self, goal, span) } } @@ -301,17 +281,16 @@ where pub(super) fn enter_root( delegate: &D, root_depth: usize, - generate_proof_tree: GenerateProofTree, origin_span: I::Span, f: impl FnOnce(&mut EvalCtxt<'_, D>) -> R, - ) -> (R, Option>) { + ) -> R { let mut search_graph = SearchGraph::new(root_depth); let mut ecx = EvalCtxt { delegate, search_graph: &mut search_graph, nested_goals: Default::default(), - inspect: ProofTreeBuilder::new_maybe_root(generate_proof_tree), + inspect: inspect::EvaluationStepBuilder::new_noop(), // Only relevant when canonicalizing the response, // which we don't do within this evaluation context. @@ -324,15 +303,12 @@ where tainted: Ok(()), }; let result = f(&mut ecx); - - let proof_tree = ecx.inspect.finalize(); assert!( ecx.nested_goals.is_empty(), "root `EvalCtxt` should not have any goals added to it" ); - assert!(search_graph.is_empty()); - (result, proof_tree) + result } /// Creates a nested evaluation context that shares the same search graph as the @@ -346,11 +322,10 @@ where cx: I, search_graph: &'a mut SearchGraph, canonical_input: CanonicalInput, - canonical_goal_evaluation: &mut ProofTreeBuilder, + proof_tree_builder: &mut inspect::ProofTreeBuilder, f: impl FnOnce(&mut EvalCtxt<'_, D>, Goal) -> R, ) -> R { let (ref delegate, input, var_values) = D::build_with_canonical(cx, &canonical_input); - for &(key, ty) in &input.predefined_opaques_in_body.opaque_types { let prev = delegate.register_hidden_type_in_storage(key, ty, I::Span::dummy()); // It may be possible that two entries in the opaque type storage end up @@ -381,12 +356,12 @@ where nested_goals: Default::default(), origin_span: I::Span::dummy(), tainted: Ok(()), - inspect: canonical_goal_evaluation.new_goal_evaluation_step(var_values), + inspect: proof_tree_builder.new_evaluation_step(var_values), }; let result = f(&mut ecx, input.goal); ecx.inspect.probe_final_state(ecx.delegate, ecx.max_input_universe); - canonical_goal_evaluation.goal_evaluation_step(ecx.inspect); + proof_tree_builder.finish_evaluation_step(ecx.inspect); // When creating a query response we clone the opaque type constraints // instead of taking them. This would cause an ICE here, since we have @@ -406,13 +381,12 @@ where /// been constrained and the certainty of the result. fn evaluate_goal( &mut self, - goal_evaluation_kind: GoalEvaluationKind, source: GoalSource, goal: Goal, stalled_on: Option>, ) -> Result, NoSolution> { let (normalization_nested_goals, goal_evaluation) = - self.evaluate_goal_raw(goal_evaluation_kind, source, goal, stalled_on)?; + self.evaluate_goal_raw(source, goal, stalled_on)?; assert!(normalization_nested_goals.is_empty()); Ok(goal_evaluation) } @@ -426,7 +400,6 @@ where /// storage. pub(super) fn evaluate_goal_raw( &mut self, - goal_evaluation_kind: GoalEvaluationKind, source: GoalSource, goal: Goal, stalled_on: Option>, @@ -458,17 +431,14 @@ where let opaque_types = self.delegate.clone_opaque_types_lookup_table(); let (goal, opaque_types) = eager_resolve_vars(self.delegate, (goal, opaque_types)); - let (orig_values, canonical_goal) = self.canonicalize_goal(goal, opaque_types); - let mut goal_evaluation = - self.inspect.new_goal_evaluation(goal, &orig_values, goal_evaluation_kind); + let (orig_values, canonical_goal) = + Self::canonicalize_goal(self.delegate, goal, opaque_types); let canonical_result = self.search_graph.evaluate_goal( self.cx(), canonical_goal, self.step_kind_for_source(source), - &mut goal_evaluation, + &mut inspect::ProofTreeBuilder::new_noop(), ); - goal_evaluation.query_result(canonical_result); - self.inspect.goal_evaluation(goal_evaluation); let response = match canonical_result { Err(e) => return Err(e), Ok(response) => response, @@ -477,8 +447,13 @@ where let has_changed = if !has_only_region_constraints(response) { HasChanged::Yes } else { HasChanged::No }; - let (normalization_nested_goals, certainty) = - self.instantiate_and_apply_query_response(goal.param_env, &orig_values, response); + let (normalization_nested_goals, certainty) = Self::instantiate_and_apply_query_response( + self.delegate, + goal.param_env, + &orig_values, + response, + self.origin_span, + ); // FIXME: We previously had an assert here that checked that recomputing // a goal after applying its constraints did not change its response. @@ -676,12 +651,7 @@ where let ( NestedNormalizationGoals(nested_goals), GoalEvaluation { goal, certainty, stalled_on, has_changed: _ }, - ) = self.evaluate_goal_raw( - GoalEvaluationKind::Nested, - source, - unconstrained_goal, - stalled_on, - )?; + ) = self.evaluate_goal_raw(source, unconstrained_goal, stalled_on)?; // Add the nested goals from normalization to our own nested goals. trace!(?nested_goals); self.nested_goals.extend(nested_goals.into_iter().map(|(s, g)| (s, g, None))); @@ -734,7 +704,7 @@ where } } else { let GoalEvaluation { goal, certainty, has_changed, stalled_on } = - self.evaluate_goal(GoalEvaluationKind::Nested, source, goal, stalled_on)?; + self.evaluate_goal(source, goal, stalled_on)?; if has_changed == HasChanged::Yes { unchanged_certainty = None; } @@ -1297,3 +1267,62 @@ where if predicate.allow_normalization() { predicate.super_fold_with(self) } else { predicate } } } + +/// Do not call this directly, use the `tcx` query instead. +pub fn evaluate_root_goal_for_proof_tree_raw_provider< + D: SolverDelegate, + I: Interner, +>( + cx: I, + canonical_goal: CanonicalInput, +) -> (QueryResult, I::ProbeRef) { + let mut inspect = inspect::ProofTreeBuilder::new(); + let canonical_result = SearchGraph::::evaluate_root_goal_for_proof_tree( + cx, + cx.recursion_limit(), + canonical_goal, + &mut inspect, + ); + let final_revision = inspect.unwrap(); + (canonical_result, cx.mk_probe_ref(final_revision)) +} + +/// Evaluate a goal to build a proof tree. +/// +/// This is a copy of [EvalCtxt::evaluate_goal_raw] which avoids relying on the +/// [EvalCtxt] and uses a separate cache. +pub(super) fn evaluate_root_goal_for_proof_tree, I: Interner>( + delegate: &D, + goal: Goal, + origin_span: I::Span, +) -> (Result, NoSolution>, inspect::GoalEvaluation) { + let opaque_types = delegate.clone_opaque_types_lookup_table(); + let (goal, opaque_types) = eager_resolve_vars(delegate, (goal, opaque_types)); + + let (orig_values, canonical_goal) = EvalCtxt::canonicalize_goal(delegate, goal, opaque_types); + + let (canonical_result, final_revision) = + delegate.cx().evaluate_root_goal_for_proof_tree_raw(canonical_goal); + + let proof_tree = inspect::GoalEvaluation { + uncanonicalized_goal: goal, + orig_values, + final_revision, + result: canonical_result, + }; + + let response = match canonical_result { + Err(e) => return (Err(e), proof_tree), + Ok(response) => response, + }; + + let (normalization_nested_goals, _certainty) = EvalCtxt::instantiate_and_apply_query_response( + delegate, + goal.param_env, + &proof_tree.orig_values, + response, + origin_span, + ); + + (Ok(normalization_nested_goals), proof_tree) +} diff --git a/compiler/rustc_next_trait_solver/src/solve/inspect/build.rs b/compiler/rustc_next_trait_solver/src/solve/inspect/build.rs index fc56b006d942..2675ed0d0da6 100644 --- a/compiler/rustc_next_trait_solver/src/solve/inspect/build.rs +++ b/compiler/rustc_next_trait_solver/src/solve/inspect/build.rs @@ -12,96 +12,86 @@ use rustc_type_ir::{self as ty, Interner}; use crate::delegate::SolverDelegate; use crate::solve::eval_ctxt::canonical; -use crate::solve::{ - Certainty, GenerateProofTree, Goal, GoalEvaluationKind, GoalSource, QueryResult, inspect, -}; +use crate::solve::{Certainty, Goal, GoalSource, QueryResult, inspect}; -/// The core data structure when building proof trees. +/// We need to know whether to build a prove tree while evaluating. We +/// pass a `ProofTreeBuilder` with `state: Some(None)` into the search +/// graph which then causes the initial `EvalCtxt::compute_goal` to actually +/// build a proof tree which then gets written into the `state`. /// -/// In case the current evaluation does not generate a proof -/// tree, `state` is simply `None` and we avoid any work. -/// -/// The possible states of the solver are represented via -/// variants of [DebugSolver]. For any nested computation we call -/// `ProofTreeBuilder::new_nested_computation_kind` which -/// creates a new `ProofTreeBuilder` to temporarily replace the -/// current one. Once that nested computation is done, -/// `ProofTreeBuilder::nested_computation_kind` is called -/// to add the finished nested evaluation to the parent. -/// -/// We provide additional information to the current state -/// by calling methods such as `ProofTreeBuilder::probe_kind`. -/// -/// The actual structure closely mirrors the finished proof -/// trees. At the end of trait solving `ProofTreeBuilder::finalize` -/// is called to recursively convert the whole structure to a -/// finished proof tree. +/// Building the proof tree for a single evaluation step happens via the +/// [EvaluationStepBuilder] which is updated by the `EvalCtxt` when +/// appropriate. pub(crate) struct ProofTreeBuilder::Interner> where D: SolverDelegate, I: Interner, { + state: Option>>>, _infcx: PhantomData, - state: Option>>, } -/// The current state of the proof tree builder, at most places -/// in the code, only one or two variants are actually possible. -/// -/// We simply ICE in case that assumption is broken. -#[derive_where(Debug; I: Interner)] -enum DebugSolver { - Root, - GoalEvaluation(WipGoalEvaluation), - CanonicalGoalEvaluationStep(WipCanonicalGoalEvaluationStep), -} - -impl From> for DebugSolver { - fn from(g: WipGoalEvaluation) -> DebugSolver { - DebugSolver::GoalEvaluation(g) +impl, I: Interner> ProofTreeBuilder { + pub(crate) fn new() -> ProofTreeBuilder { + ProofTreeBuilder { state: Some(Box::new(None)), _infcx: PhantomData } } -} -impl From> for DebugSolver { - fn from(g: WipCanonicalGoalEvaluationStep) -> DebugSolver { - DebugSolver::CanonicalGoalEvaluationStep(g) + pub(crate) fn new_noop() -> ProofTreeBuilder { + ProofTreeBuilder { state: None, _infcx: PhantomData } } -} -#[derive_where(PartialEq, Debug; I: Interner)] -struct WipGoalEvaluation { - pub uncanonicalized_goal: Goal, - pub orig_values: Vec, - pub encountered_overflow: bool, - /// After we finished evaluating this is moved into `kind`. - pub final_revision: Option>, - pub result: Option>, -} + pub(crate) fn is_noop(&self) -> bool { + self.state.is_none() + } -impl Eq for WipGoalEvaluation {} - -impl WipGoalEvaluation { - fn finalize(self) -> inspect::GoalEvaluation { - inspect::GoalEvaluation { - uncanonicalized_goal: self.uncanonicalized_goal, - orig_values: self.orig_values, - kind: if self.encountered_overflow { - assert!(self.final_revision.is_none()); - inspect::GoalEvaluationKind::Overflow - } else { - let final_revision = self.final_revision.unwrap().finalize(); - inspect::GoalEvaluationKind::Evaluation { final_revision } - }, - result: self.result.unwrap(), + pub(crate) fn new_evaluation_step( + &mut self, + var_values: ty::CanonicalVarValues, + ) -> EvaluationStepBuilder { + if self.is_noop() { + EvaluationStepBuilder { state: None, _infcx: PhantomData } + } else { + EvaluationStepBuilder { + state: Some(Box::new(WipEvaluationStep { + var_values: var_values.var_values.to_vec(), + evaluation: WipProbe { + initial_num_var_values: var_values.len(), + steps: vec![], + kind: None, + final_state: None, + }, + probe_depth: 0, + })), + _infcx: PhantomData, + } } } + + pub(crate) fn finish_evaluation_step( + &mut self, + goal_evaluation_step: EvaluationStepBuilder, + ) { + if let Some(this) = self.state.as_deref_mut() { + *this = Some(goal_evaluation_step.state.unwrap().finalize()); + } + } + + pub(crate) fn unwrap(self) -> inspect::Probe { + self.state.unwrap().unwrap() + } } -/// This only exists during proof tree building and does not have -/// a corresponding struct in `inspect`. We need this to track a -/// bunch of metadata about the current evaluation. -#[derive_where(PartialEq, Debug; I: Interner)] -struct WipCanonicalGoalEvaluationStep { +pub(crate) struct EvaluationStepBuilder::Interner> +where + D: SolverDelegate, + I: Interner, +{ + state: Option>>, + _infcx: PhantomData, +} + +#[derive_where(PartialEq, Eq, Debug; I: Interner)] +struct WipEvaluationStep { /// Unlike `EvalCtxt::var_values`, we append a new /// generic arg here whenever we create a new inference /// variable. @@ -113,9 +103,7 @@ struct WipCanonicalGoalEvaluationStep { evaluation: WipProbe, } -impl Eq for WipCanonicalGoalEvaluationStep {} - -impl WipCanonicalGoalEvaluationStep { +impl WipEvaluationStep { fn current_evaluation_scope(&mut self) -> &mut WipProbe { let mut current = &mut self.evaluation; for _ in 0..self.probe_depth { @@ -181,169 +169,48 @@ impl WipProbeStep { } } -impl, I: Interner> ProofTreeBuilder { - fn new(state: impl Into>) -> ProofTreeBuilder { - ProofTreeBuilder { state: Some(Box::new(state.into())), _infcx: PhantomData } - } - - fn opt_nested>>(&self, state: impl FnOnce() -> Option) -> Self { - ProofTreeBuilder { - state: self.state.as_ref().and_then(|_| Some(state()?.into())).map(Box::new), - _infcx: PhantomData, - } - } - - fn nested>>(&self, state: impl FnOnce() -> T) -> Self { - ProofTreeBuilder { - state: self.state.as_ref().map(|_| Box::new(state().into())), - _infcx: PhantomData, - } - } - - fn as_mut(&mut self) -> Option<&mut DebugSolver> { - self.state.as_deref_mut() - } - - pub(crate) fn take_and_enter_probe(&mut self) -> ProofTreeBuilder { - let mut nested = ProofTreeBuilder { state: self.state.take(), _infcx: PhantomData }; - nested.enter_probe(); - nested - } - - pub(crate) fn finalize(self) -> Option> { - match *self.state? { - DebugSolver::GoalEvaluation(wip_goal_evaluation) => { - Some(wip_goal_evaluation.finalize()) - } - root => unreachable!("unexpected proof tree builder root node: {:?}", root), - } - } - - pub(crate) fn new_maybe_root(generate_proof_tree: GenerateProofTree) -> ProofTreeBuilder { - match generate_proof_tree { - GenerateProofTree::No => ProofTreeBuilder::new_noop(), - GenerateProofTree::Yes => ProofTreeBuilder::new_root(), - } - } - - fn new_root() -> ProofTreeBuilder { - ProofTreeBuilder::new(DebugSolver::Root) - } - - fn new_noop() -> ProofTreeBuilder { - ProofTreeBuilder { state: None, _infcx: PhantomData } +impl, I: Interner> EvaluationStepBuilder { + pub(crate) fn new_noop() -> EvaluationStepBuilder { + EvaluationStepBuilder { state: None, _infcx: PhantomData } } pub(crate) fn is_noop(&self) -> bool { self.state.is_none() } - pub(in crate::solve) fn new_goal_evaluation( - &mut self, - uncanonicalized_goal: Goal, - orig_values: &[I::GenericArg], - kind: GoalEvaluationKind, - ) -> ProofTreeBuilder { - self.opt_nested(|| match kind { - GoalEvaluationKind::Root => Some(WipGoalEvaluation { - uncanonicalized_goal, - orig_values: orig_values.to_vec(), - encountered_overflow: false, - final_revision: None, - result: None, - }), - GoalEvaluationKind::Nested => None, - }) + fn as_mut(&mut self) -> Option<&mut WipEvaluationStep> { + self.state.as_deref_mut() } - pub(crate) fn canonical_goal_evaluation_overflow(&mut self) { - if let Some(this) = self.as_mut() { - match this { - DebugSolver::GoalEvaluation(goal_evaluation) => { - goal_evaluation.encountered_overflow = true; - } - _ => unreachable!(), - }; - } - } - - pub(crate) fn goal_evaluation(&mut self, goal_evaluation: ProofTreeBuilder) { - if let Some(this) = self.as_mut() { - match this { - DebugSolver::Root => *this = *goal_evaluation.state.unwrap(), - DebugSolver::CanonicalGoalEvaluationStep(_) => { - assert!(goal_evaluation.state.is_none()) - } - _ => unreachable!(), - } - } - } - - pub(crate) fn new_goal_evaluation_step( - &mut self, - var_values: ty::CanonicalVarValues, - ) -> ProofTreeBuilder { - self.nested(|| WipCanonicalGoalEvaluationStep { - var_values: var_values.var_values.to_vec(), - evaluation: WipProbe { - initial_num_var_values: var_values.len(), - steps: vec![], - kind: None, - final_state: None, - }, - probe_depth: 0, - }) - } - - pub(crate) fn goal_evaluation_step(&mut self, goal_evaluation_step: ProofTreeBuilder) { - if let Some(this) = self.as_mut() { - match (this, *goal_evaluation_step.state.unwrap()) { - ( - DebugSolver::GoalEvaluation(goal_evaluation), - DebugSolver::CanonicalGoalEvaluationStep(goal_evaluation_step), - ) => { - goal_evaluation.final_revision = Some(goal_evaluation_step); - } - _ => unreachable!(), - } - } + pub(crate) fn take_and_enter_probe(&mut self) -> EvaluationStepBuilder { + let mut nested = EvaluationStepBuilder { state: self.state.take(), _infcx: PhantomData }; + nested.enter_probe(); + nested } pub(crate) fn add_var_value>(&mut self, arg: T) { - match self.as_mut() { - None => {} - Some(DebugSolver::CanonicalGoalEvaluationStep(state)) => { - state.var_values.push(arg.into()); - } - Some(s) => panic!("tried to add var values to {s:?}"), + if let Some(this) = self.as_mut() { + this.var_values.push(arg.into()); } } fn enter_probe(&mut self) { - match self.as_mut() { - None => {} - Some(DebugSolver::CanonicalGoalEvaluationStep(state)) => { - let initial_num_var_values = state.var_values.len(); - state.current_evaluation_scope().steps.push(WipProbeStep::NestedProbe(WipProbe { - initial_num_var_values, - steps: vec![], - kind: None, - final_state: None, - })); - state.probe_depth += 1; - } - Some(s) => panic!("tried to start probe to {s:?}"), + if let Some(this) = self.as_mut() { + let initial_num_var_values = this.var_values.len(); + this.current_evaluation_scope().steps.push(WipProbeStep::NestedProbe(WipProbe { + initial_num_var_values, + steps: vec![], + kind: None, + final_state: None, + })); + this.probe_depth += 1; } } pub(crate) fn probe_kind(&mut self, probe_kind: inspect::ProbeKind) { - match self.as_mut() { - None => {} - Some(DebugSolver::CanonicalGoalEvaluationStep(state)) => { - let prev = state.current_evaluation_scope().kind.replace(probe_kind); - assert_eq!(prev, None); - } - _ => panic!(), + if let Some(this) = self.as_mut() { + let prev = this.current_evaluation_scope().kind.replace(probe_kind); + assert_eq!(prev, None); } } @@ -352,19 +219,11 @@ impl, I: Interner> ProofTreeBuilder { delegate: &D, max_input_universe: ty::UniverseIndex, ) { - match self.as_mut() { - None => {} - Some(DebugSolver::CanonicalGoalEvaluationStep(state)) => { - let final_state = canonical::make_canonical_state( - delegate, - &state.var_values, - max_input_universe, - (), - ); - let prev = state.current_evaluation_scope().final_state.replace(final_state); - assert_eq!(prev, None); - } - _ => panic!(), + if let Some(this) = self.as_mut() { + let final_state = + canonical::make_canonical_state(delegate, &this.var_values, max_input_universe, ()); + let prev = this.current_evaluation_scope().final_state.replace(final_state); + assert_eq!(prev, None); } } @@ -375,18 +234,14 @@ impl, I: Interner> ProofTreeBuilder { source: GoalSource, goal: Goal, ) { - match self.as_mut() { - None => {} - Some(DebugSolver::CanonicalGoalEvaluationStep(state)) => { - let goal = canonical::make_canonical_state( - delegate, - &state.var_values, - max_input_universe, - goal, - ); - state.current_evaluation_scope().steps.push(WipProbeStep::AddGoal(source, goal)) - } - _ => panic!(), + if let Some(this) = self.as_mut() { + let goal = canonical::make_canonical_state( + delegate, + &this.var_values, + max_input_universe, + goal, + ); + this.current_evaluation_scope().steps.push(WipProbeStep::AddGoal(source, goal)) } } @@ -396,47 +251,31 @@ impl, I: Interner> ProofTreeBuilder { max_input_universe: ty::UniverseIndex, impl_args: I::GenericArgs, ) { - match self.as_mut() { - Some(DebugSolver::CanonicalGoalEvaluationStep(state)) => { - let impl_args = canonical::make_canonical_state( - delegate, - &state.var_values, - max_input_universe, - impl_args, - ); - state - .current_evaluation_scope() - .steps - .push(WipProbeStep::RecordImplArgs { impl_args }); - } - None => {} - _ => panic!(), + if let Some(this) = self.as_mut() { + let impl_args = canonical::make_canonical_state( + delegate, + &this.var_values, + max_input_universe, + impl_args, + ); + this.current_evaluation_scope().steps.push(WipProbeStep::RecordImplArgs { impl_args }); } } pub(crate) fn make_canonical_response(&mut self, shallow_certainty: Certainty) { - match self.as_mut() { - Some(DebugSolver::CanonicalGoalEvaluationStep(state)) => { - state - .current_evaluation_scope() - .steps - .push(WipProbeStep::MakeCanonicalResponse { shallow_certainty }); - } - None => {} - _ => panic!(), + if let Some(this) = self.as_mut() { + this.current_evaluation_scope() + .steps + .push(WipProbeStep::MakeCanonicalResponse { shallow_certainty }); } } - pub(crate) fn finish_probe(mut self) -> ProofTreeBuilder { - match self.as_mut() { - None => {} - Some(DebugSolver::CanonicalGoalEvaluationStep(state)) => { - assert_ne!(state.probe_depth, 0); - let num_var_values = state.current_evaluation_scope().initial_num_var_values; - state.var_values.truncate(num_var_values); - state.probe_depth -= 1; - } - _ => panic!(), + pub(crate) fn finish_probe(mut self) -> EvaluationStepBuilder { + if let Some(this) = self.as_mut() { + assert_ne!(this.probe_depth, 0); + let num_var_values = this.current_evaluation_scope().initial_num_var_values; + this.var_values.truncate(num_var_values); + this.probe_depth -= 1; } self @@ -444,21 +283,7 @@ impl, I: Interner> ProofTreeBuilder { pub(crate) fn query_result(&mut self, result: QueryResult) { if let Some(this) = self.as_mut() { - match this { - DebugSolver::GoalEvaluation(goal_evaluation) => { - assert_eq!(goal_evaluation.result.replace(result), None); - } - DebugSolver::CanonicalGoalEvaluationStep(evaluation_step) => { - assert_eq!( - evaluation_step - .evaluation - .kind - .replace(inspect::ProbeKind::Root { result }), - None - ); - } - _ => unreachable!(), - } + assert_eq!(this.evaluation.kind.replace(inspect::ProbeKind::Root { result }), None); } } } diff --git a/compiler/rustc_next_trait_solver/src/solve/mod.rs b/compiler/rustc_next_trait_solver/src/solve/mod.rs index 710b59f662a7..85f9d852d959 100644 --- a/compiler/rustc_next_trait_solver/src/solve/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/mod.rs @@ -27,7 +27,10 @@ pub use rustc_type_ir::solve::*; use rustc_type_ir::{self as ty, Interner, TypingMode}; use tracing::instrument; -pub use self::eval_ctxt::{EvalCtxt, GenerateProofTree, SolverDelegateEvalExt}; +pub use self::eval_ctxt::{ + EvalCtxt, GenerateProofTree, SolverDelegateEvalExt, + evaluate_root_goal_for_proof_tree_raw_provider, +}; use crate::delegate::SolverDelegate; use crate::solve::assembly::Candidate; @@ -42,12 +45,6 @@ use crate::solve::assembly::Candidate; /// recursion limit again. However, this feels very unlikely. const FIXPOINT_STEP_LIMIT: usize = 8; -#[derive(Debug, Copy, Clone, PartialEq, Eq)] -enum GoalEvaluationKind { - Root, - Nested, -} - /// Whether evaluating this goal ended up changing the /// inference state. #[derive(PartialEq, Eq, Debug, Hash, Clone, Copy)] diff --git a/compiler/rustc_next_trait_solver/src/solve/search_graph.rs b/compiler/rustc_next_trait_solver/src/solve/search_graph.rs index 84f8eda4f8da..f0342e0523ff 100644 --- a/compiler/rustc_next_trait_solver/src/solve/search_graph.rs +++ b/compiler/rustc_next_trait_solver/src/solve/search_graph.rs @@ -7,8 +7,9 @@ use rustc_type_ir::solve::{CanonicalInput, Certainty, NoSolution, QueryResult}; use rustc_type_ir::{Interner, TypingMode}; use crate::delegate::SolverDelegate; -use crate::solve::inspect::ProofTreeBuilder; -use crate::solve::{EvalCtxt, FIXPOINT_STEP_LIMIT, has_no_inference_or_external_constraints}; +use crate::solve::{ + EvalCtxt, FIXPOINT_STEP_LIMIT, has_no_inference_or_external_constraints, inspect, +}; /// This type is never constructed. We only use it to implement `search_graph::Delegate` /// for all types which impl `SolverDelegate` and doing it directly fails in coherence. @@ -34,7 +35,7 @@ where const FIXPOINT_STEP_LIMIT: usize = FIXPOINT_STEP_LIMIT; - type ProofTreeBuilder = ProofTreeBuilder; + type ProofTreeBuilder = inspect::ProofTreeBuilder; fn inspect_is_noop(inspect: &mut Self::ProofTreeBuilder) -> bool { inspect.is_noop() } @@ -81,12 +82,7 @@ where Self::initial_provisional_result(cx, kind, input) == result } - fn on_stack_overflow( - cx: I, - input: CanonicalInput, - inspect: &mut ProofTreeBuilder, - ) -> QueryResult { - inspect.canonical_goal_evaluation_overflow(); + fn on_stack_overflow(cx: I, input: CanonicalInput) -> QueryResult { response_no_constraints(cx, input, Certainty::overflow(true)) } diff --git a/compiler/rustc_trait_selection/src/solve.rs b/compiler/rustc_trait_selection/src/solve.rs index f58961683a9c..5d200c4d340b 100644 --- a/compiler/rustc_trait_selection/src/solve.rs +++ b/compiler/rustc_trait_selection/src/solve.rs @@ -13,4 +13,20 @@ pub use normalize::{ deeply_normalize, deeply_normalize_with_skipped_universes, deeply_normalize_with_skipped_universes_and_ambiguous_coroutine_goals, }; +use rustc_middle::query::Providers; +use rustc_middle::ty::TyCtxt; pub use select::InferCtxtSelectExt; + +fn evaluate_root_goal_for_proof_tree_raw<'tcx>( + tcx: TyCtxt<'tcx>, + canonical_input: CanonicalInput>, +) -> (QueryResult>, &'tcx inspect::Probe>) { + evaluate_root_goal_for_proof_tree_raw_provider::, TyCtxt<'tcx>>( + tcx, + canonical_input, + ) +} + +pub fn provide(providers: &mut Providers) { + *providers = Providers { evaluate_root_goal_for_proof_tree_raw, ..*providers }; +} diff --git a/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs b/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs index 308486811e6e..342d7121fc37 100644 --- a/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs +++ b/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs @@ -37,7 +37,7 @@ pub struct InspectGoal<'a, 'tcx> { orig_values: Vec>, goal: Goal<'tcx, ty::Predicate<'tcx>>, result: Result, - evaluation_kind: inspect::GoalEvaluationKind>, + final_revision: &'tcx inspect::Probe>, normalizes_to_term_hack: Option>, source: GoalSource, } @@ -249,7 +249,7 @@ impl<'a, 'tcx> InspectCandidate<'a, 'tcx> { // `InspectGoal::new` so that the goal has the right result (and maintains // the impression that we don't do this normalizes-to infer hack at all). let (nested, proof_tree) = infcx.evaluate_root_goal_for_proof_tree(goal, span); - let nested_goals_result = nested.and_then(|(nested, _)| { + let nested_goals_result = nested.and_then(|nested| { normalizes_to_term_hack.constrain_and( infcx, span, @@ -391,15 +391,8 @@ impl<'a, 'tcx> InspectGoal<'a, 'tcx> { pub fn candidates(&'a self) -> Vec> { let mut candidates = vec![]; - let last_eval_step = match &self.evaluation_kind { - // An annoying edge case in case the recursion limit is 0. - inspect::GoalEvaluationKind::Overflow => return vec![], - inspect::GoalEvaluationKind::Evaluation { final_revision } => final_revision, - }; - let mut nested_goals = vec![]; - self.candidates_recur(&mut candidates, &mut nested_goals, &last_eval_step); - + self.candidates_recur(&mut candidates, &mut nested_goals, &self.final_revision); candidates } @@ -426,7 +419,8 @@ impl<'a, 'tcx> InspectGoal<'a, 'tcx> { ) -> Self { let infcx = <&SolverDelegate<'tcx>>::from(infcx); - let inspect::GoalEvaluation { uncanonicalized_goal, orig_values, kind, result } = root; + let inspect::GoalEvaluation { uncanonicalized_goal, orig_values, final_revision, result } = + root; // If there's a normalizes-to goal, AND the evaluation result with the result of // constraining the normalizes-to RHS and computing the nested goals. let result = result.and_then(|ok| { @@ -441,7 +435,7 @@ impl<'a, 'tcx> InspectGoal<'a, 'tcx> { orig_values, goal: eager_resolve_vars(infcx, uncanonicalized_goal), result, - evaluation_kind: kind, + final_revision, normalizes_to_term_hack: term_hack_and_nested_certainty.map(|(n, _)| n), source, } diff --git a/compiler/rustc_type_ir/src/interner.rs b/compiler/rustc_type_ir/src/interner.rs index 21fe7879b298..f5448baf8c0b 100644 --- a/compiler/rustc_type_ir/src/interner.rs +++ b/compiler/rustc_type_ir/src/interner.rs @@ -10,7 +10,9 @@ use crate::inherent::*; use crate::ir_print::IrPrint; use crate::lang_items::{SolverLangItem, SolverTraitLangItem}; use crate::relate::Relate; -use crate::solve::{CanonicalInput, ExternalConstraintsData, PredefinedOpaquesData, QueryResult}; +use crate::solve::{ + CanonicalInput, ExternalConstraintsData, PredefinedOpaquesData, QueryResult, inspect, +}; use crate::visit::{Flags, TypeVisitable}; use crate::{self as ty, CanonicalParamEnvCacheEntry, search_graph}; @@ -380,6 +382,13 @@ pub trait Interner: self, defining_anchor: Self::LocalDefId, ) -> Self::LocalDefIds; + + type ProbeRef: Copy + Debug + Hash + Eq + Deref>; + fn mk_probe_ref(self, probe: inspect::Probe) -> Self::ProbeRef; + fn evaluate_root_goal_for_proof_tree_raw( + self, + canonical_goal: CanonicalInput, + ) -> (QueryResult, Self::ProbeRef); } /// Imagine you have a function `F: FnOnce(&[T]) -> R`, plus an iterator `iter` diff --git a/compiler/rustc_type_ir/src/search_graph/mod.rs b/compiler/rustc_type_ir/src/search_graph/mod.rs index 348178a527fb..dbbc0c217d7d 100644 --- a/compiler/rustc_type_ir/src/search_graph/mod.rs +++ b/compiler/rustc_type_ir/src/search_graph/mod.rs @@ -92,11 +92,7 @@ pub trait Delegate: Sized { input: ::Input, result: ::Result, ) -> bool; - fn on_stack_overflow( - cx: Self::Cx, - input: ::Input, - inspect: &mut Self::ProofTreeBuilder, - ) -> ::Result; + fn on_stack_overflow(cx: Self::Cx, input: ::Input) -> ::Result; fn on_fixpoint_overflow( cx: Self::Cx, input: ::Input, @@ -703,6 +699,31 @@ impl, X: Cx> SearchGraph { } } + pub fn evaluate_root_goal_for_proof_tree( + cx: X, + root_depth: usize, + input: X::Input, + inspect: &mut D::ProofTreeBuilder, + ) -> X::Result { + let mut this = SearchGraph::::new(root_depth); + let available_depth = AvailableDepth(root_depth); + let step_kind_from_parent = PathKind::Inductive; // is never used + this.stack.push(StackEntry { + input, + step_kind_from_parent, + available_depth, + provisional_result: None, + required_depth: 0, + heads: Default::default(), + encountered_overflow: false, + usages: None, + candidate_usages: None, + nested_goals: Default::default(), + }); + let evaluation_result = this.evaluate_goal_in_task(cx, input, inspect); + evaluation_result.result + } + /// Probably the most involved method of the whole solver. /// /// While goals get computed via `D::compute_goal`, this function handles @@ -718,7 +739,7 @@ impl, X: Cx> SearchGraph { let Some(available_depth) = AvailableDepth::allowed_depth_for_nested::(self.root_depth, &self.stack) else { - return self.handle_overflow(cx, input, inspect); + return self.handle_overflow(cx, input); }; // We check the provisional cache before checking the global cache. This simplifies @@ -833,12 +854,7 @@ impl, X: Cx> SearchGraph { result } - fn handle_overflow( - &mut self, - cx: X, - input: X::Input, - inspect: &mut D::ProofTreeBuilder, - ) -> X::Result { + fn handle_overflow(&mut self, cx: X, input: X::Input) -> X::Result { if let Some(last) = self.stack.last_mut() { last.encountered_overflow = true; // If computing a goal `B` depends on another goal `A` and @@ -853,7 +869,7 @@ impl, X: Cx> SearchGraph { } debug!("encountered stack overflow"); - D::on_stack_overflow(cx, input, inspect) + D::on_stack_overflow(cx, input) } /// When reevaluating a goal with a changed provisional result, all provisional cache entry diff --git a/compiler/rustc_type_ir/src/solve/inspect.rs b/compiler/rustc_type_ir/src/solve/inspect.rs index afb4043648f6..5452ac441589 100644 --- a/compiler/rustc_type_ir/src/solve/inspect.rs +++ b/compiler/rustc_type_ir/src/solve/inspect.rs @@ -45,31 +45,18 @@ pub type CanonicalState = Canonical>; /// for the `CanonicalVarValues` of the canonicalized goal. /// We use this to map any [CanonicalState] from the local `InferCtxt` /// of the solver query to the `InferCtxt` of the caller. -#[derive_where(PartialEq, Hash; I: Interner)] +#[derive_where(PartialEq, Eq, Hash; I: Interner)] pub struct GoalEvaluation { pub uncanonicalized_goal: Goal, pub orig_values: Vec, - pub kind: GoalEvaluationKind, + pub final_revision: I::ProbeRef, pub result: QueryResult, } -impl Eq for GoalEvaluation {} - -#[derive_where(PartialEq, Hash, Debug; I: Interner)] -pub enum GoalEvaluationKind { - Overflow, - Evaluation { - /// This is always `ProbeKind::Root`. - final_revision: Probe, - }, -} - -impl Eq for GoalEvaluationKind {} - /// A self-contained computation during trait solving. This either /// corresponds to a `EvalCtxt::probe(_X)` call or the root evaluation /// of a goal. -#[derive_where(PartialEq, Hash, Debug; I: Interner)] +#[derive_where(PartialEq, Eq, Hash, Debug; I: Interner)] pub struct Probe { /// What happened inside of this probe in chronological order. pub steps: Vec>, @@ -77,9 +64,7 @@ pub struct Probe { pub final_state: CanonicalState, } -impl Eq for Probe {} - -#[derive_where(PartialEq, Hash, Debug; I: Interner)] +#[derive_where(PartialEq, Eq, Hash, Debug; I: Interner)] pub enum ProbeStep { /// We added a goal to the `EvalCtxt` which will get proven /// the next time `EvalCtxt::try_evaluate_added_goals` is called. @@ -98,12 +83,10 @@ pub enum ProbeStep { MakeCanonicalResponse { shallow_certainty: Certainty }, } -impl Eq for ProbeStep {} - /// What kind of probe we're in. In case the probe represents a candidate, or /// the final result of the current goal - via [ProbeKind::Root] - we also /// store the [QueryResult]. -#[derive_where(Clone, Copy, PartialEq, Hash, Debug; I: Interner)] +#[derive_where(Clone, Copy, PartialEq, Eq, Hash, Debug; I: Interner)] #[derive(TypeVisitable_Generic, TypeFoldable_Generic)] pub enum ProbeKind { /// The root inference context while proving a goal. @@ -128,5 +111,3 @@ pub enum ProbeKind { /// Checking that a rigid alias is well-formed. RigidAlias { result: QueryResult }, } - -impl Eq for ProbeKind {} From 7aec84d485ec1159c3ead3800ba601fd6d1d7869 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Fri, 29 Aug 2025 17:03:38 +0300 Subject: [PATCH 08/48] resolve: Merge `ExternPreludeEntry::introduced_by_item` into `item_binding` --- .../rustc_resolve/src/build_reduced_graph.rs | 6 ++--- compiler/rustc_resolve/src/check_unused.rs | 2 +- compiler/rustc_resolve/src/diagnostics.rs | 5 ++-- compiler/rustc_resolve/src/lib.rs | 26 +++++++++++-------- 4 files changed, 21 insertions(+), 18 deletions(-) diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs index f75a625a279b..feaaaa6f539d 100644 --- a/compiler/rustc_resolve/src/build_reduced_graph.rs +++ b/compiler/rustc_resolve/src/build_reduced_graph.rs @@ -1008,16 +1008,14 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { let msg = format!("extern crate `{ident}` already in extern prelude"); self.r.tcx.dcx().span_delayed_bug(item.span, msg); } else { - entry.item_binding = Some(imported_binding); - entry.introduced_by_item = orig_name.is_some(); + entry.item_binding = Some((imported_binding, orig_name.is_some())); } entry } Entry::Vacant(vacant) => vacant.insert(ExternPreludeEntry { - item_binding: Some(imported_binding), + item_binding: Some((imported_binding, true)), flag_binding: Cell::new(None), only_item: true, - introduced_by_item: true, }), }; } diff --git a/compiler/rustc_resolve/src/check_unused.rs b/compiler/rustc_resolve/src/check_unused.rs index 11d93a58ae29..50a1ad23a546 100644 --- a/compiler/rustc_resolve/src/check_unused.rs +++ b/compiler/rustc_resolve/src/check_unused.rs @@ -204,7 +204,7 @@ impl<'a, 'ra, 'tcx> UnusedImportCheckVisitor<'a, 'ra, 'tcx> { .r .extern_prelude .get(&Macros20NormalizedIdent::new(extern_crate.ident)) - .is_none_or(|entry| entry.introduced_by_item) + .is_none_or(|entry| entry.introduced_by_item()) { continue; } diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index 337e7d2dd863..1ec527e3b81c 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -322,7 +322,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let from_item = self .extern_prelude .get(&Macros20NormalizedIdent::new(ident)) - .is_none_or(|entry| entry.introduced_by_item); + .is_none_or(|entry| entry.introduced_by_item()); // Only suggest removing an import if both bindings are to the same def, if both spans // aren't dummy spans. Further, if both bindings are imports, then the ident must have // been introduced by an item. @@ -1845,7 +1845,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let AmbiguityError { kind, ident, b1, b2, misc1, misc2, .. } = *ambiguity_error; let extern_prelude_ambiguity = || { self.extern_prelude.get(&Macros20NormalizedIdent::new(ident)).is_some_and(|entry| { - entry.item_binding == Some(b1) && entry.flag_binding.get() == Some(b2) + entry.item_binding.map(|(b, _)| b) == Some(b1) + && entry.flag_binding.get() == Some(b2) }) }; let (b1, b2, misc1, misc2, swapped) = if b2.span.is_dummy() && !b1.span.is_dummy() { diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 2afb52ef4d4b..e3d896be0d20 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -1028,15 +1028,20 @@ impl<'ra> NameBindingData<'ra> { #[derive(Default, Clone)] struct ExternPreludeEntry<'ra> { /// Binding from an `extern crate` item. - item_binding: Option>, + /// The boolean flag is true is `item_binding` is non-redundant, happens either when + /// `only_item` is true, or when `extern crate` introducing `item_binding` used renaming. + item_binding: Option<(NameBinding<'ra>, /* introduced by item */ bool)>, /// Binding from an `--extern` flag, lazily populated on first use. flag_binding: Cell>>, /// There was no `--extern` flag introducing this name, /// `flag_binding` doesn't need to be populated. only_item: bool, - /// `item_binding` is non-redundant, happens either when `only_item` is true, - /// or when `extern crate` introducing `item_binding` used renaming. - introduced_by_item: bool, +} + +impl ExternPreludeEntry<'_> { + fn introduced_by_item(&self) -> bool { + matches!(self.item_binding, Some((_, true))) + } } struct DeriveData { @@ -2062,12 +2067,11 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } // Avoid marking `extern crate` items that refer to a name from extern prelude, // but not introduce it, as used if they are accessed from lexical scope. - if used == Used::Scope { - if let Some(entry) = self.extern_prelude.get(&Macros20NormalizedIdent::new(ident)) { - if !entry.introduced_by_item && entry.item_binding == Some(used_binding) { - return; - } - } + if used == Used::Scope + && let Some(entry) = self.extern_prelude.get(&Macros20NormalizedIdent::new(ident)) + && entry.item_binding == Some((used_binding, false)) + { + return; } let old_used = self.import_use_map.entry(import).or_insert(used); if *old_used < used { @@ -2226,7 +2230,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { finalize: bool, ) -> Option> { let entry = self.extern_prelude.get(&Macros20NormalizedIdent::new(ident)); - entry.and_then(|entry| entry.item_binding).map(|binding| { + entry.and_then(|entry| entry.item_binding).map(|(binding, _)| { if finalize { self.get_mut().record_use(ident, binding, Used::Scope); } From f0dbfadaa2a5e6f6e839d49ed12951f0535ee03c Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Fri, 29 Aug 2025 17:36:10 +0300 Subject: [PATCH 09/48] resolve: Merge `ExternPreludeEntry::only_item` into `flag_binding` --- .../rustc_resolve/src/build_reduced_graph.rs | 3 +- compiler/rustc_resolve/src/diagnostics.rs | 2 +- compiler/rustc_resolve/src/lib.rs | 71 ++++++++++--------- 3 files changed, 38 insertions(+), 38 deletions(-) diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs index feaaaa6f539d..fa3c06059b3d 100644 --- a/compiler/rustc_resolve/src/build_reduced_graph.rs +++ b/compiler/rustc_resolve/src/build_reduced_graph.rs @@ -1014,8 +1014,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { } Entry::Vacant(vacant) => vacant.insert(ExternPreludeEntry { item_binding: Some((imported_binding, true)), - flag_binding: Cell::new(None), - only_item: true, + flag_binding: None, }), }; } diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index 1ec527e3b81c..5dfc4292a380 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -1846,7 +1846,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let extern_prelude_ambiguity = || { self.extern_prelude.get(&Macros20NormalizedIdent::new(ident)).is_some_and(|entry| { entry.item_binding.map(|(b, _)| b) == Some(b1) - && entry.flag_binding.get() == Some(b2) + && entry.flag_binding.as_ref().and_then(|pb| pb.get().binding()) == Some(b2) }) }; let (b1, b2, misc1, misc2, swapped) = if b2.span.is_dummy() && !b1.span.is_dummy() { diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index e3d896be0d20..9674c0356c21 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -32,7 +32,7 @@ use std::sync::Arc; use diagnostics::{ImportSuggestion, LabelSuggestion, Suggestion}; use effective_visibilities::EffectiveVisibilitiesVisitor; use errors::{ParamKindInEnumDiscriminant, ParamKindInNonTrivialAnonConst}; -use imports::{Import, ImportData, ImportKind, NameResolution}; +use imports::{Import, ImportData, ImportKind, NameResolution, PendingBinding}; use late::{ ForwardGenericParamBanReason, HasGenericParams, PathSource, PatternSource, UnnecessaryQualification, @@ -1025,23 +1025,26 @@ impl<'ra> NameBindingData<'ra> { } } -#[derive(Default, Clone)] struct ExternPreludeEntry<'ra> { /// Binding from an `extern crate` item. /// The boolean flag is true is `item_binding` is non-redundant, happens either when - /// `only_item` is true, or when `extern crate` introducing `item_binding` used renaming. + /// `flag_binding` is `None`, or when `extern crate` introducing `item_binding` used renaming. item_binding: Option<(NameBinding<'ra>, /* introduced by item */ bool)>, /// Binding from an `--extern` flag, lazily populated on first use. - flag_binding: Cell>>, - /// There was no `--extern` flag introducing this name, - /// `flag_binding` doesn't need to be populated. - only_item: bool, + flag_binding: Option>>, } impl ExternPreludeEntry<'_> { fn introduced_by_item(&self) -> bool { matches!(self.item_binding, Some((_, true))) } + + fn flag() -> Self { + ExternPreludeEntry { + item_binding: None, + flag_binding: Some(Cell::new(PendingBinding::Pending)), + } + } } struct DeriveData { @@ -1533,7 +1536,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { && let name = Symbol::intern(name) && name.can_be_raw() { - Some((Macros20NormalizedIdent::with_dummy_span(name), Default::default())) + let ident = Macros20NormalizedIdent::with_dummy_span(name); + Some((ident, ExternPreludeEntry::flag())) } else { None } @@ -1541,11 +1545,11 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { .collect(); if !attr::contains_name(attrs, sym::no_core) { - extern_prelude - .insert(Macros20NormalizedIdent::with_dummy_span(sym::core), Default::default()); + let ident = Macros20NormalizedIdent::with_dummy_span(sym::core); + extern_prelude.insert(ident, ExternPreludeEntry::flag()); if !attr::contains_name(attrs, sym::no_std) { - extern_prelude - .insert(Macros20NormalizedIdent::with_dummy_span(sym::std), Default::default()); + let ident = Macros20NormalizedIdent::with_dummy_span(sym::std); + extern_prelude.insert(ident, ExternPreludeEntry::flag()); } } @@ -2240,31 +2244,28 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { fn extern_prelude_get_flag(&self, ident: Ident, finalize: bool) -> Option> { let entry = self.extern_prelude.get(&Macros20NormalizedIdent::new(ident)); - entry.and_then(|entry| match entry.flag_binding.get() { - Some(binding) => { - if finalize { - self.cstore_mut().process_path_extern(self.tcx, ident.name, ident.span); - } - Some(binding) - } - None if entry.only_item => None, - None => { - let crate_id = if finalize { - self.cstore_mut().process_path_extern(self.tcx, ident.name, ident.span) - } else { - self.cstore_mut().maybe_process_path_extern(self.tcx, ident.name) - }; - match crate_id { - Some(crate_id) => { - let res = Res::Def(DefKind::Mod, crate_id.as_def_id()); - let binding = - self.arenas.new_pub_res_binding(res, DUMMY_SP, LocalExpnId::ROOT); - entry.flag_binding.set(Some(binding)); - Some(binding) + entry.and_then(|entry| entry.flag_binding.as_ref()).and_then(|flag_binding| { + let binding = match flag_binding.get() { + PendingBinding::Ready(binding) => { + if finalize { + self.cstore_mut().process_path_extern(self.tcx, ident.name, ident.span); } - None => finalize.then_some(self.dummy_binding), + binding } - } + PendingBinding::Pending => { + let crate_id = if finalize { + self.cstore_mut().process_path_extern(self.tcx, ident.name, ident.span) + } else { + self.cstore_mut().maybe_process_path_extern(self.tcx, ident.name) + }; + crate_id.map(|crate_id| { + let res = Res::Def(DefKind::Mod, crate_id.as_def_id()); + self.arenas.new_pub_res_binding(res, DUMMY_SP, LocalExpnId::ROOT) + }) + } + }; + flag_binding.set(PendingBinding::Ready(binding)); + binding.or_else(|| finalize.then_some(self.dummy_binding)) }) } From da8f230d5f87a9a6113ed7774eec7f20268cf240 Mon Sep 17 00:00:00 2001 From: Daniel Paoliello Date: Thu, 21 Aug 2025 11:40:45 -0700 Subject: [PATCH 10/48] Update to ar_archive_writer 0.5.1 --- Cargo.lock | 6 +- .../rustc_codegen_llvm/src/back/archive.rs | 5 + compiler/rustc_codegen_llvm/src/llvm/ffi.rs | 2 + compiler/rustc_codegen_ssa/Cargo.toml | 2 +- .../rustc_codegen_ssa/src/back/archive.rs | 6 +- .../rustc_llvm/llvm-wrapper/SymbolWrapper.cpp | 103 ++++++++++-------- 6 files changed, 74 insertions(+), 50 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 8b9c243879ca..0d176278b8b3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -158,11 +158,11 @@ checksum = "b0674a1ddeecb70197781e945de4b3b8ffb61fa939a5597bcf48503737663100" [[package]] name = "ar_archive_writer" -version = "0.4.2" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01667f6f40216b9a0b2945e05fed5f1ad0ab6470e69cb9378001e37b1c0668e4" +checksum = "3219abbb81fdcb1a976d794ea40cd8567b67c4e8f93bdcd077a40a0905f133e8" dependencies = [ - "object 0.36.7", + "object 0.37.2", ] [[package]] diff --git a/compiler/rustc_codegen_llvm/src/back/archive.rs b/compiler/rustc_codegen_llvm/src/back/archive.rs index 7a340ae83f3d..f9dc48e3aba3 100644 --- a/compiler/rustc_codegen_llvm/src/back/archive.rs +++ b/compiler/rustc_codegen_llvm/src/back/archive.rs @@ -26,6 +26,7 @@ static LLVM_OBJECT_READER: ObjectReader = ObjectReader { get_symbols: get_llvm_object_symbols, is_64_bit_object_file: llvm_is_64_bit_object_file, is_ec_object_file: llvm_is_ec_object_file, + is_any_arm64_coff: llvm_is_any_arm64_coff, get_xcoff_member_alignment: DEFAULT_OBJECT_READER.get_xcoff_member_alignment, }; @@ -95,3 +96,7 @@ fn llvm_is_64_bit_object_file(buf: &[u8]) -> bool { fn llvm_is_ec_object_file(buf: &[u8]) -> bool { unsafe { llvm::LLVMRustIsECObject(buf.as_ptr(), buf.len()) } } + +fn llvm_is_any_arm64_coff(buf: &[u8]) -> bool { + unsafe { llvm::LLVMRustIsAnyArm64Coff(buf.as_ptr(), buf.len()) } +} diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index ba590851dbd5..b66fc157b3cb 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -2686,6 +2686,8 @@ unsafe extern "C" { pub(crate) fn LLVMRustIsECObject(buf_ptr: *const u8, buf_len: usize) -> bool; + pub(crate) fn LLVMRustIsAnyArm64Coff(buf_ptr: *const u8, buf_len: usize) -> bool; + pub(crate) fn LLVMRustSetNoSanitizeAddress(Global: &Value); pub(crate) fn LLVMRustSetNoSanitizeHWAddress(Global: &Value); } diff --git a/compiler/rustc_codegen_ssa/Cargo.toml b/compiler/rustc_codegen_ssa/Cargo.toml index 57e1fee2c0a6..6f87b5749c6d 100644 --- a/compiler/rustc_codegen_ssa/Cargo.toml +++ b/compiler/rustc_codegen_ssa/Cargo.toml @@ -5,7 +5,7 @@ edition = "2024" [dependencies] # tidy-alphabetical-start -ar_archive_writer = "0.4.2" +ar_archive_writer = "0.5" bitflags.workspace = true bstr = "1.11.3" # `cc` updates often break things, so we pin it here. Cargo enforces "max 1 semver-compat version diff --git a/compiler/rustc_codegen_ssa/src/back/archive.rs b/compiler/rustc_codegen_ssa/src/back/archive.rs index 84a56f6b0b55..5bf2e6535602 100644 --- a/compiler/rustc_codegen_ssa/src/back/archive.rs +++ b/compiler/rustc_codegen_ssa/src/back/archive.rs @@ -46,7 +46,8 @@ impl From for COFFShortExport { name: item.name, ext_name: None, symbol_name: item.symbol_name, - alias_target: None, + import_name: None, + export_as: None, ordinal: item.ordinal.unwrap_or(0), noname: item.ordinal.is_some(), data: item.is_data, @@ -134,6 +135,7 @@ pub trait ArchiveBuilderBuilder { // when linking a rust staticlib using `/WHOLEARCHIVE`. // See #129020 true, + &[], ) { sess.dcx() .emit_fatal(ErrorCreatingImportLibrary { lib_name, error: error.to_string() }); @@ -527,7 +529,7 @@ impl<'a> ArArchiveBuilder<'a> { &entries, archive_kind, false, - /* is_ec = */ self.sess.target.arch == "arm64ec", + /* is_ec = */ Some(self.sess.target.arch == "arm64ec"), )?; archive_tmpfile.flush()?; drop(archive_tmpfile); diff --git a/compiler/rustc_llvm/llvm-wrapper/SymbolWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/SymbolWrapper.cpp index a910e78d4895..fccfff65cfc3 100644 --- a/compiler/rustc_llvm/llvm-wrapper/SymbolWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/SymbolWrapper.cpp @@ -103,28 +103,9 @@ LLVMRustGetSymbols(char *BufPtr, size_t BufLen, void *State, #define TRUE_PTR (void *)1 #define FALSE_PTR (void *)0 -extern "C" bool LLVMRustIs64BitSymbolicFile(char *BufPtr, size_t BufLen) { - std::unique_ptr Buf = MemoryBuffer::getMemBuffer( - StringRef(BufPtr, BufLen), StringRef("LLVMRustGetSymbolsObject"), false); - SmallString<0> SymNameBuf; - auto SymName = raw_svector_ostream(SymNameBuf); - - // Code starting from this line is copied from s64BitSymbolicFile in - // ArchiveWriter.cpp. - // In the scenario when LLVMContext is populated SymbolicFile will contain a - // reference to it, thus SymbolicFile should be destroyed first. - LLVMContext Context; - Expected> ObjOrErr = - getSymbolicFile(Buf->getMemBufferRef(), Context); - if (!ObjOrErr) { - return false; - } - std::unique_ptr Obj = std::move(*ObjOrErr); - - return Obj != nullptr ? Obj->is64Bit() : false; -} - -extern "C" bool LLVMRustIsECObject(char *BufPtr, size_t BufLen) { +bool withBufferAsSymbolicFile( + char *BufPtr, size_t BufLen, + std::function Callback) { std::unique_ptr Buf = MemoryBuffer::getMemBuffer( StringRef(BufPtr, BufLen), StringRef("LLVMRustGetSymbolsObject"), false); SmallString<0> SymNameBuf; @@ -139,29 +120,63 @@ extern "C" bool LLVMRustIsECObject(char *BufPtr, size_t BufLen) { return false; } std::unique_ptr Obj = std::move(*ObjOrErr); - if (Obj == nullptr) { return false; } - - // Code starting from this line is copied from isECObject in - // ArchiveWriter.cpp with an extra #if to work with LLVM 17. - if (Obj->isCOFF()) - return cast(&*Obj)->getMachine() != - COFF::IMAGE_FILE_MACHINE_ARM64; - - if (Obj->isCOFFImportFile()) - return cast(&*Obj)->getMachine() != - COFF::IMAGE_FILE_MACHINE_ARM64; - - if (Obj->isIR()) { - Expected TripleStr = - getBitcodeTargetTriple(Obj->getMemoryBufferRef()); - if (!TripleStr) - return false; - Triple T(*TripleStr); - return T.isWindowsArm64EC() || T.getArch() == Triple::x86_64; - } - - return false; + return Callback(*Obj); +} + +extern "C" bool LLVMRustIs64BitSymbolicFile(char *BufPtr, size_t BufLen) { + return withBufferAsSymbolicFile( + BufPtr, BufLen, [](object::SymbolicFile &Obj) { return Obj.is64Bit(); }); +} + +extern "C" bool LLVMRustIsECObject(char *BufPtr, size_t BufLen) { + return withBufferAsSymbolicFile( + BufPtr, BufLen, [](object::SymbolicFile &Obj) { + // Code starting from this line is copied from isECObject in + // ArchiveWriter.cpp with an extra #if to work with LLVM 17. + if (Obj.isCOFF()) + return cast(&Obj)->getMachine() != + COFF::IMAGE_FILE_MACHINE_ARM64; + + if (Obj.isCOFFImportFile()) + return cast(&Obj)->getMachine() != + COFF::IMAGE_FILE_MACHINE_ARM64; + + if (Obj.isIR()) { + Expected TripleStr = + getBitcodeTargetTriple(Obj.getMemoryBufferRef()); + if (!TripleStr) + return false; + Triple T(*TripleStr); + return T.isWindowsArm64EC() || T.getArch() == Triple::x86_64; + } + + return false; + }); +} + +extern "C" bool LLVMRustIsAnyArm64Coff(char *BufPtr, size_t BufLen) { + return withBufferAsSymbolicFile( + BufPtr, BufLen, [](object::SymbolicFile &Obj) { + // Code starting from this line is copied from isAnyArm64COFF in + // ArchiveWriter.cpp. + if (Obj.isCOFF()) + return COFF::isAnyArm64(cast(&Obj)->getMachine()); + + if (Obj.isCOFFImportFile()) + return COFF::isAnyArm64(cast(&Obj)->getMachine()); + + if (Obj.isIR()) { + Expected TripleStr = + getBitcodeTargetTriple(Obj.getMemoryBufferRef()); + if (!TripleStr) + return false; + Triple T(*TripleStr); + return T.isOSWindows() && T.getArch() == Triple::aarch64; + } + + return false; + }); } From 4daae65228caf1bedef2e665102c03b17aa0fe86 Mon Sep 17 00:00:00 2001 From: Daniel Paoliello Date: Mon, 25 Aug 2025 12:07:36 -0700 Subject: [PATCH 11/48] Move to 0.50.1 --- Cargo.lock | 6 +++--- .../rustc_codegen_ssa/src/back/archive.rs | 20 ++++++++++--------- 2 files changed, 14 insertions(+), 12 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0d176278b8b3..a8df53f3a411 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -158,11 +158,11 @@ checksum = "b0674a1ddeecb70197781e945de4b3b8ffb61fa939a5597bcf48503737663100" [[package]] name = "ar_archive_writer" -version = "0.5.0" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3219abbb81fdcb1a976d794ea40cd8567b67c4e8f93bdcd077a40a0905f133e8" +checksum = "7eb93bbb63b9c227414f6eb3a0adfddca591a8ce1e9b60661bb08969b87e340b" dependencies = [ - "object 0.37.2", + "object 0.37.3", ] [[package]] diff --git a/compiler/rustc_codegen_ssa/src/back/archive.rs b/compiler/rustc_codegen_ssa/src/back/archive.rs index 5bf2e6535602..cfd8ceac3a60 100644 --- a/compiler/rustc_codegen_ssa/src/back/archive.rs +++ b/compiler/rustc_codegen_ssa/src/back/archive.rs @@ -40,17 +40,18 @@ pub struct ImportLibraryItem { pub is_data: bool, } -impl From for COFFShortExport { - fn from(item: ImportLibraryItem) -> Self { +impl ImportLibraryItem { + fn into_coff_short_export(self, sess: &Session) -> COFFShortExport { + let import_name = (sess.target.arch == "arm64ec").then(|| self.name.clone()); COFFShortExport { - name: item.name, + name: self.name, ext_name: None, - symbol_name: item.symbol_name, - import_name: None, + symbol_name: self.symbol_name, + import_name, export_as: None, - ordinal: item.ordinal.unwrap_or(0), - noname: item.ordinal.is_some(), - data: item.is_data, + ordinal: self.ordinal.unwrap_or(0), + noname: self.ordinal.is_some(), + data: self.is_data, private: false, constant: false, } @@ -114,7 +115,8 @@ pub trait ArchiveBuilderBuilder { .emit_fatal(ErrorCreatingImportLibrary { lib_name, error: error.to_string() }), }; - let exports = items.into_iter().map(Into::into).collect::>(); + let exports = + items.into_iter().map(|item| item.into_coff_short_export(sess)).collect::>(); let machine = match &*sess.target.arch { "x86_64" => MachineTypes::AMD64, "x86" => MachineTypes::I386, From 1112274275be9216b42ef2f27b1e85c5e88d67c5 Mon Sep 17 00:00:00 2001 From: Connor Tsui Date: Thu, 28 Aug 2025 19:53:12 +0100 Subject: [PATCH 12/48] add `Bound::copied` Signed-off-by: Connor Tsui --- library/core/src/ops/range.rs | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/library/core/src/ops/range.rs b/library/core/src/ops/range.rs index 95d1e2069ac9..c5a7744d73b3 100644 --- a/library/core/src/ops/range.rs +++ b/library/core/src/ops/range.rs @@ -736,6 +736,28 @@ impl Bound { } } +impl Bound<&T> { + /// Map a `Bound<&T>` to a `Bound` by copying the contents of the bound. + /// + /// # Examples + /// + /// ``` + /// use std::ops::Bound::*; + /// use std::ops::RangeBounds; + /// + /// assert_eq!((1..12).start_bound(), Included(&1)); + /// assert_eq!((1..12).start_bound().copied(), Included(1)); + /// ``` + #[unstable(feature = "bound_copied", issue = "145966")] + pub fn copied(self) -> Bound { + match self { + Bound::Unbounded => Bound::Unbounded, + Bound::Included(x) => Bound::Included(*x), + Bound::Excluded(x) => Bound::Excluded(*x), + } + } +} + impl Bound<&T> { /// Map a `Bound<&T>` to a `Bound` by cloning the contents of the bound. /// From 9c1255f0a46e7a8d22f17ad5705f0c8e2018bfe6 Mon Sep 17 00:00:00 2001 From: Connor Tsui <87130162+connortsui20@users.noreply.github.com> Date: Thu, 28 Aug 2025 20:38:07 +0100 Subject: [PATCH 13/48] add feature gate in doc test --- library/core/src/ops/range.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/library/core/src/ops/range.rs b/library/core/src/ops/range.rs index c5a7744d73b3..b1df5afa2022 100644 --- a/library/core/src/ops/range.rs +++ b/library/core/src/ops/range.rs @@ -742,6 +742,8 @@ impl Bound<&T> { /// # Examples /// /// ``` + /// #![feature(bound_copied)] + /// /// use std::ops::Bound::*; /// use std::ops::RangeBounds; /// From 114c0c2fefbc90d1cb71f6a0c4d150174e73ca75 Mon Sep 17 00:00:00 2001 From: Connor Tsui Date: Sat, 30 Aug 2025 11:15:41 +0100 Subject: [PATCH 14/48] Add `#[must_use] and update `cloned` documentation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Connor Tsui Co-authored-by: Jonas Böttiger --- library/core/src/ops/range.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/library/core/src/ops/range.rs b/library/core/src/ops/range.rs index b1df5afa2022..c0a27775694c 100644 --- a/library/core/src/ops/range.rs +++ b/library/core/src/ops/range.rs @@ -751,6 +751,7 @@ impl Bound<&T> { /// assert_eq!((1..12).start_bound().copied(), Included(1)); /// ``` #[unstable(feature = "bound_copied", issue = "145966")] + #[must_use] pub fn copied(self) -> Bound { match self { Bound::Unbounded => Bound::Unbounded, @@ -769,8 +770,11 @@ impl Bound<&T> { /// use std::ops::Bound::*; /// use std::ops::RangeBounds; /// - /// assert_eq!((1..12).start_bound(), Included(&1)); - /// assert_eq!((1..12).start_bound().cloned(), Included(1)); + /// let a1 = String::from("a"); + /// let (a2, a3, a4) = (a1.clone(), a1.clone(), a1.clone()); + /// + /// assert_eq!(Included(&a1), (a2..).start_bound()); + /// assert_eq!(Included(a3), (a4..).start_bound().cloned()); /// ``` #[must_use = "`self` will be dropped if the result is not used"] #[stable(feature = "bound_cloned", since = "1.55.0")] From 6ebd009d470b504a411e47b24b5c99ec17d9af08 Mon Sep 17 00:00:00 2001 From: Karol Zwolak Date: Fri, 15 Aug 2025 09:54:22 +0200 Subject: [PATCH 15/48] dedup recip float test I left the additional asserts on {f16, f128}::MAX.recip() in a new test_max_recip tests. --- library/coretests/tests/floats/f128.rs | 12 +----------- library/coretests/tests/floats/f16.rs | 12 +----------- library/coretests/tests/floats/f32.rs | 14 -------------- library/coretests/tests/floats/f64.rs | 14 -------------- library/coretests/tests/floats/mod.rs | 20 ++++++++++++++++++++ 5 files changed, 22 insertions(+), 50 deletions(-) diff --git a/library/coretests/tests/floats/f128.rs b/library/coretests/tests/floats/f128.rs index ac4a20665305..f718cfa6edc6 100644 --- a/library/coretests/tests/floats/f128.rs +++ b/library/coretests/tests/floats/f128.rs @@ -44,22 +44,12 @@ fn test_mul_add() { #[test] #[cfg(any(miri, target_has_reliable_f128_math))] -fn test_recip() { - let nan: f128 = f128::NAN; - let inf: f128 = f128::INFINITY; - let neg_inf: f128 = f128::NEG_INFINITY; - assert_biteq!(1.0f128.recip(), 1.0); - assert_biteq!(2.0f128.recip(), 0.5); - assert_biteq!((-0.4f128).recip(), -2.5); - assert_biteq!(0.0f128.recip(), inf); +fn test_max_recip() { assert_approx_eq!( f128::MAX.recip(), 8.40525785778023376565669454330438228902076605e-4933, 1e-4900 ); - assert!(nan.recip().is_nan()); - assert_biteq!(inf.recip(), 0.0); - assert_biteq!(neg_inf.recip(), -0.0); } #[test] diff --git a/library/coretests/tests/floats/f16.rs b/library/coretests/tests/floats/f16.rs index bb9c8a002fe8..244b9c3fd69c 100644 --- a/library/coretests/tests/floats/f16.rs +++ b/library/coretests/tests/floats/f16.rs @@ -50,18 +50,8 @@ fn test_mul_add() { #[test] #[cfg(any(miri, target_has_reliable_f16_math))] -fn test_recip() { - let nan: f16 = f16::NAN; - let inf: f16 = f16::INFINITY; - let neg_inf: f16 = f16::NEG_INFINITY; - assert_biteq!(1.0f16.recip(), 1.0); - assert_biteq!(2.0f16.recip(), 0.5); - assert_biteq!((-0.4f16).recip(), -2.5); - assert_biteq!(0.0f16.recip(), inf); +fn test_max_recip() { assert_approx_eq!(f16::MAX.recip(), 1.526624e-5f16, 1e-4); - assert!(nan.recip().is_nan()); - assert_biteq!(inf.recip(), 0.0); - assert_biteq!(neg_inf.recip(), -0.0); } #[test] diff --git a/library/coretests/tests/floats/f32.rs b/library/coretests/tests/floats/f32.rs index e77e44655dc8..8c7cc97329ca 100644 --- a/library/coretests/tests/floats/f32.rs +++ b/library/coretests/tests/floats/f32.rs @@ -32,20 +32,6 @@ fn test_mul_add() { assert_biteq!(f32::math::mul_add(-3.2f32, 2.4, neg_inf), neg_inf); } -#[test] -fn test_recip() { - let nan: f32 = f32::NAN; - let inf: f32 = f32::INFINITY; - let neg_inf: f32 = f32::NEG_INFINITY; - assert_biteq!(1.0f32.recip(), 1.0); - assert_biteq!(2.0f32.recip(), 0.5); - assert_biteq!((-0.4f32).recip(), -2.5); - assert_biteq!(0.0f32.recip(), inf); - assert!(nan.recip().is_nan()); - assert_biteq!(inf.recip(), 0.0); - assert_biteq!(neg_inf.recip(), -0.0); -} - #[test] fn test_powi() { let nan: f32 = f32::NAN; diff --git a/library/coretests/tests/floats/f64.rs b/library/coretests/tests/floats/f64.rs index fea9cc19b39f..7738fc1c4704 100644 --- a/library/coretests/tests/floats/f64.rs +++ b/library/coretests/tests/floats/f64.rs @@ -27,20 +27,6 @@ fn test_mul_add() { assert_biteq!((-3.2f64).mul_add(2.4, neg_inf), neg_inf); } -#[test] -fn test_recip() { - let nan: f64 = f64::NAN; - let inf: f64 = f64::INFINITY; - let neg_inf: f64 = f64::NEG_INFINITY; - assert_biteq!(1.0f64.recip(), 1.0); - assert_biteq!(2.0f64.recip(), 0.5); - assert_biteq!((-0.4f64).recip(), -2.5); - assert_biteq!(0.0f64.recip(), inf); - assert!(nan.recip().is_nan()); - assert_biteq!(inf.recip(), 0.0); - assert_biteq!(neg_inf.recip(), -0.0); -} - #[test] fn test_powi() { let nan: f64 = f64::NAN; diff --git a/library/coretests/tests/floats/mod.rs b/library/coretests/tests/floats/mod.rs index 2c2a07920d06..d5b05c45ddfd 100644 --- a/library/coretests/tests/floats/mod.rs +++ b/library/coretests/tests/floats/mod.rs @@ -1340,3 +1340,23 @@ float_test! { assert_eq!(Ordering::Less, Float::total_cmp(&-s_nan(), &s_nan())); } } + +float_test! { + name: recip, + attrs: { + f16: #[cfg(any(miri, target_has_reliable_f16_math))], + f128: #[cfg(any(miri, target_has_reliable_f128_math))], + }, + test { + let nan: Float = Float::NAN; + let inf: Float = Float::INFINITY; + let neg_inf: Float = Float::NEG_INFINITY; + assert_biteq!((1.0 as Float).recip(), 1.0); + assert_biteq!((2.0 as Float).recip(), 0.5); + assert_biteq!((-0.4 as Float).recip(), -2.5); + assert_biteq!((0.0 as Float).recip(), inf); + assert!(nan.recip().is_nan()); + assert_biteq!(inf.recip(), 0.0); + assert_biteq!(neg_inf.recip(), -0.0); + } +} From ddf1b3e7d4f7a538cdc57d92c8d50458be57bde0 Mon Sep 17 00:00:00 2001 From: Taiki Endo Date: Sat, 30 Aug 2025 23:35:39 +0900 Subject: [PATCH 16/48] Update target spec metadata of Arm64EC Windows and Trusty targets --- .../rustc_target/src/spec/targets/aarch64_unknown_trusty.rs | 2 +- .../rustc_target/src/spec/targets/arm64ec_pc_windows_msvc.rs | 4 ++-- .../rustc_target/src/spec/targets/armv7_unknown_trusty.rs | 2 +- .../rustc_target/src/spec/targets/x86_64_unknown_trusty.rs | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/compiler/rustc_target/src/spec/targets/aarch64_unknown_trusty.rs b/compiler/rustc_target/src/spec/targets/aarch64_unknown_trusty.rs index 126f02512391..05783fde1adf 100644 --- a/compiler/rustc_target/src/spec/targets/aarch64_unknown_trusty.rs +++ b/compiler/rustc_target/src/spec/targets/aarch64_unknown_trusty.rs @@ -11,7 +11,7 @@ pub(crate) fn target() -> Target { description: Some("ARM64 Trusty".into()), tier: Some(3), host_tools: Some(false), - std: Some(false), + std: Some(true), }, pointer_width: 64, data_layout: "e-m:e-p270:32:32-p271:32:32-p272:64:64-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128-Fn32".into(), diff --git a/compiler/rustc_target/src/spec/targets/arm64ec_pc_windows_msvc.rs b/compiler/rustc_target/src/spec/targets/arm64ec_pc_windows_msvc.rs index 8f93523909e3..7292412a18d8 100644 --- a/compiler/rustc_target/src/spec/targets/arm64ec_pc_windows_msvc.rs +++ b/compiler/rustc_target/src/spec/targets/arm64ec_pc_windows_msvc.rs @@ -20,9 +20,9 @@ pub(crate) fn target() -> Target { llvm_target: "arm64ec-pc-windows-msvc".into(), metadata: TargetMetadata { description: Some("Arm64EC Windows MSVC".into()), - tier: Some(3), + tier: Some(2), host_tools: Some(false), - std: None, // ? + std: Some(true), }, pointer_width: 64, data_layout: diff --git a/compiler/rustc_target/src/spec/targets/armv7_unknown_trusty.rs b/compiler/rustc_target/src/spec/targets/armv7_unknown_trusty.rs index 31d492e83cda..2b0b0e1d1170 100644 --- a/compiler/rustc_target/src/spec/targets/armv7_unknown_trusty.rs +++ b/compiler/rustc_target/src/spec/targets/armv7_unknown_trusty.rs @@ -13,7 +13,7 @@ pub(crate) fn target() -> Target { description: Some("Armv7-A Trusty".into()), tier: Some(3), host_tools: Some(false), - std: Some(false), + std: Some(true), }, pointer_width: 32, data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(), diff --git a/compiler/rustc_target/src/spec/targets/x86_64_unknown_trusty.rs b/compiler/rustc_target/src/spec/targets/x86_64_unknown_trusty.rs index c7b002bc9bba..dbcb5fd4e11e 100644 --- a/compiler/rustc_target/src/spec/targets/x86_64_unknown_trusty.rs +++ b/compiler/rustc_target/src/spec/targets/x86_64_unknown_trusty.rs @@ -12,7 +12,7 @@ pub(crate) fn target() -> Target { description: Some("x86_64 Trusty".into()), tier: Some(3), host_tools: Some(false), - std: Some(false), + std: Some(true), }, pointer_width: 64, data_layout: From 18a36bccf5198dcc507d42e0daadcf2de4481741 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Sat, 30 Aug 2025 23:28:46 +0000 Subject: [PATCH 17/48] Detect negative literal inferred to unsigned integer ``` error[E0277]: the trait bound `usize: Neg` is not satisfied --> $DIR/negative-literal-infered-to-unsigned.rs:2:14 | LL | for x in -5..5 { | ^^ the trait `Neg` is not implemented for `usize` | help: consider specifying an integer type that can be negative | LL | for x in -5isize..5 { | +++++ ``` --- .../traits/fulfillment_errors.rs | 41 ++++++++++++++++++- .../negative-literal-infered-to-unsigned.rs | 13 ++++++ ...egative-literal-infered-to-unsigned.stderr | 25 +++++++++++ 3 files changed, 78 insertions(+), 1 deletion(-) create mode 100644 tests/ui/suggestions/negative-literal-infered-to-unsigned.rs create mode 100644 tests/ui/suggestions/negative-literal-infered-to-unsigned.stderr diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs index d768e0bf63fb..f1fd7ebfeba2 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs @@ -3,7 +3,8 @@ use std::borrow::Cow; use std::path::PathBuf; use rustc_abi::ExternAbi; -use rustc_ast::TraitObjectSyntax; +use rustc_ast::ast::LitKind; +use rustc_ast::{LitIntType, TraitObjectSyntax}; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::unord::UnordSet; use rustc_errors::codes::*; @@ -280,6 +281,12 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { (suggested, noted_missing_impl) = self.try_conversion_context(&obligation, main_trait_predicate, &mut err); } + suggested |= self.detect_negative_literal( + &obligation, + main_trait_predicate, + &mut err, + ); + if let Some(ret_span) = self.return_type_span(&obligation) { if is_try_conversion { let ty = self.tcx.short_string( @@ -950,6 +957,38 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { Ok(()) } + fn detect_negative_literal( + &self, + obligation: &PredicateObligation<'tcx>, + trait_pred: ty::PolyTraitPredicate<'tcx>, + err: &mut Diag<'_>, + ) -> bool { + if let ObligationCauseCode::BinOp { lhs_hir_id, .. } = obligation.cause.code() + && let hir::Node::Expr(expr) = self.tcx.hir_node(*lhs_hir_id) + && let hir::ExprKind::Unary(hir::UnOp::Neg, inner) = expr.kind + && let hir::ExprKind::Lit(lit) = inner.kind + && let LitKind::Int(_, LitIntType::Unsuffixed) = lit.node + { + err.span_suggestion_verbose( + lit.span.shrink_to_hi(), + "consider specifying an integer type that can be negative", + match trait_pred.skip_binder().self_ty().kind() { + ty::Uint(ty::UintTy::Usize) => "isize", + ty::Uint(ty::UintTy::U8) => "i8", + ty::Uint(ty::UintTy::U16) => "i16", + ty::Uint(ty::UintTy::U32) => "i32", + ty::Uint(ty::UintTy::U64) => "i64", + ty::Uint(ty::UintTy::U128) => "i128", + _ => "i64", + } + .to_string(), + Applicability::MaybeIncorrect, + ); + return true; + } + false + } + /// When the `E` of the resulting `Result` in an expression `foo().bar().baz()?`, /// identify those method chain sub-expressions that could or could not have been annotated /// with `?`. diff --git a/tests/ui/suggestions/negative-literal-infered-to-unsigned.rs b/tests/ui/suggestions/negative-literal-infered-to-unsigned.rs new file mode 100644 index 000000000000..39797574b977 --- /dev/null +++ b/tests/ui/suggestions/negative-literal-infered-to-unsigned.rs @@ -0,0 +1,13 @@ +fn main() { + for x in -5..5 { + //~^ ERROR: the trait bound `usize: Neg` is not satisfied + //~| HELP: consider specifying an integer type that can be negative + do_something(x); + } + let x = -5; + //~^ ERROR: the trait bound `usize: Neg` is not satisfied + //~| HELP: consider specifying an integer type that can be negative + do_something(x); +} + +fn do_something(_val: usize) {} diff --git a/tests/ui/suggestions/negative-literal-infered-to-unsigned.stderr b/tests/ui/suggestions/negative-literal-infered-to-unsigned.stderr new file mode 100644 index 000000000000..b49ea224d2b1 --- /dev/null +++ b/tests/ui/suggestions/negative-literal-infered-to-unsigned.stderr @@ -0,0 +1,25 @@ +error[E0277]: the trait bound `usize: Neg` is not satisfied + --> $DIR/negative-literal-infered-to-unsigned.rs:2:14 + | +LL | for x in -5..5 { + | ^^ the trait `Neg` is not implemented for `usize` + | +help: consider specifying an integer type that can be negative + | +LL | for x in -5isize..5 { + | +++++ + +error[E0277]: the trait bound `usize: Neg` is not satisfied + --> $DIR/negative-literal-infered-to-unsigned.rs:7:13 + | +LL | let x = -5; + | ^^ the trait `Neg` is not implemented for `usize` + | +help: consider specifying an integer type that can be negative + | +LL | let x = -5isize; + | +++++ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0277`. From 263766bcc28a9441d0acfb1a335308e46cfd1917 Mon Sep 17 00:00:00 2001 From: yukang Date: Sun, 31 Aug 2025 10:53:33 +0800 Subject: [PATCH 18/48] suggest method name with maybe ty mismatch --- compiler/rustc_hir_typeck/src/method/mod.rs | 2 +- ...-suggest-await-on-method-return-mismatch.stderr | 5 +++++ tests/ui/privacy/private-field-ty-err.stderr | 5 +++++ ...st-method-name-with-maybe-ty-mismatch-146008.rs | 14 ++++++++++++++ ...ethod-name-with-maybe-ty-mismatch-146008.stderr | 14 ++++++++++++++ 5 files changed, 39 insertions(+), 1 deletion(-) create mode 100644 tests/ui/typeck/suggest-method-name-with-maybe-ty-mismatch-146008.rs create mode 100644 tests/ui/typeck/suggest-method-name-with-maybe-ty-mismatch-146008.stderr diff --git a/compiler/rustc_hir_typeck/src/method/mod.rs b/compiler/rustc_hir_typeck/src/method/mod.rs index e37ea0316726..652644ad78cc 100644 --- a/compiler/rustc_hir_typeck/src/method/mod.rs +++ b/compiler/rustc_hir_typeck/src/method/mod.rs @@ -117,7 +117,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { Err(Ambiguity(..)) => true, Err(PrivateMatch(..)) => false, Err(IllegalSizedBound { .. }) => true, - Err(BadReturnType) => false, + Err(BadReturnType) => true, Err(ErrorReported(_)) => false, } } diff --git a/tests/ui/async-await/dont-suggest-await-on-method-return-mismatch.stderr b/tests/ui/async-await/dont-suggest-await-on-method-return-mismatch.stderr index 1faaf4ddce2f..aa2343e48a6e 100644 --- a/tests/ui/async-await/dont-suggest-await-on-method-return-mismatch.stderr +++ b/tests/ui/async-await/dont-suggest-await-on-method-return-mismatch.stderr @@ -3,6 +3,11 @@ error[E0599]: no method named `test` found for opaque type `impl Future` + | +help: consider `await`ing on the `Future` and calling the method on its `Output` + | +LL | let x: u32 = foo().await.test(); + | ++++++ error: aborting due to 1 previous error diff --git a/tests/ui/privacy/private-field-ty-err.stderr b/tests/ui/privacy/private-field-ty-err.stderr index 17d50f24a945..0eecad14cfc3 100644 --- a/tests/ui/privacy/private-field-ty-err.stderr +++ b/tests/ui/privacy/private-field-ty-err.stderr @@ -3,6 +3,11 @@ error[E0616]: field `len` of struct `Foo` is private | LL | if x.len { | ^^^ private field + | +help: a method `len` also exists, call it with parentheses + | +LL | if x.len() { + | ++ error: aborting due to 1 previous error diff --git a/tests/ui/typeck/suggest-method-name-with-maybe-ty-mismatch-146008.rs b/tests/ui/typeck/suggest-method-name-with-maybe-ty-mismatch-146008.rs new file mode 100644 index 000000000000..671f280e8143 --- /dev/null +++ b/tests/ui/typeck/suggest-method-name-with-maybe-ty-mismatch-146008.rs @@ -0,0 +1,14 @@ +struct LlamaModel; + +impl LlamaModel { + fn chat_template(&self) -> Result<&str, ()> { + todo!() + } +} + +fn template_from_str(_x: &str) {} + +fn main() { + let model = LlamaModel; + template_from_str(&model.chat_template); //~ ERROR attempted to take value of method `chat_template` on type `LlamaModel` +} diff --git a/tests/ui/typeck/suggest-method-name-with-maybe-ty-mismatch-146008.stderr b/tests/ui/typeck/suggest-method-name-with-maybe-ty-mismatch-146008.stderr new file mode 100644 index 000000000000..7f5dd0617b1b --- /dev/null +++ b/tests/ui/typeck/suggest-method-name-with-maybe-ty-mismatch-146008.stderr @@ -0,0 +1,14 @@ +error[E0615]: attempted to take value of method `chat_template` on type `LlamaModel` + --> $DIR/suggest-method-name-with-maybe-ty-mismatch-146008.rs:13:30 + | +LL | template_from_str(&model.chat_template); + | ^^^^^^^^^^^^^ method, not a field + | +help: use parentheses to call the method + | +LL | template_from_str(&model.chat_template()); + | ++ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0615`. From cfba491e674dcff8cc5edbf9ae3e3880518804fd Mon Sep 17 00:00:00 2001 From: LorrensP-2158466 Date: Sun, 31 Aug 2025 10:03:49 +0200 Subject: [PATCH 19/48] fix --- library/std/tests/floats/f32.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/std/tests/floats/f32.rs b/library/std/tests/floats/f32.rs index 38c906c1d877..c61a8ec4d209 100644 --- a/library/std/tests/floats/f32.rs +++ b/library/std/tests/floats/f32.rs @@ -79,8 +79,8 @@ fn test_log() { let nan: f32 = f32::NAN; let inf: f32 = f32::INFINITY; let neg_inf: f32 = f32::NEG_INFINITY; - assert_approx_eq!(10.0f32.log(10.0), 1.0); - assert_approx_eq!(2.3f32.log(3.5), 0.664858); + assert_approx_eq!(10.0f32.log(10.0), 1.0, APPROX_DELTA); + assert_approx_eq!(2.3f32.log(3.5), 0.664858, APPROX_DELTA); assert_approx_eq!(1.0f32.exp().log(1.0f32.exp()), 1.0, APPROX_DELTA); assert!(1.0f32.log(1.0).is_nan()); assert!(1.0f32.log(-13.9).is_nan()); From 002751155d135de7ef6cfd88404f2bd2b7983b51 Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Sun, 27 Jul 2025 23:05:22 +0200 Subject: [PATCH 20/48] round pointer to alignment without going via int --- compiler/rustc_codegen_llvm/src/va_arg.rs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/va_arg.rs b/compiler/rustc_codegen_llvm/src/va_arg.rs index ce079f3cb0af..7eb5d3020588 100644 --- a/compiler/rustc_codegen_llvm/src/va_arg.rs +++ b/compiler/rustc_codegen_llvm/src/va_arg.rs @@ -28,9 +28,12 @@ fn round_pointer_up_to_alignment<'ll>( align: Align, ptr_ty: &'ll Type, ) -> &'ll Value { - let mut ptr_as_int = bx.ptrtoint(addr, bx.cx().type_isize()); - ptr_as_int = round_up_to_alignment(bx, ptr_as_int, align); - bx.inttoptr(ptr_as_int, ptr_ty) + let ptr = bx.inbounds_ptradd(addr, bx.const_i32(align.bytes() as i32 - 1)); + bx.call_intrinsic( + "llvm.ptrmask", + &[ptr_ty, bx.type_i32()], + &[ptr, bx.const_int(bx.isize_ty, -(align.bytes() as isize) as i64)], + ) } fn emit_direct_ptr_va_arg<'ll, 'tcx>( From 213bb873518b5e6f7612cd3ac373603170b76e2b Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Sun, 27 Jul 2025 23:07:03 +0200 Subject: [PATCH 21/48] explicitly end `va_list` lifetime --- compiler/rustc_codegen_ssa/src/mir/block.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs index c3dc3e42b83d..5f6976f5d005 100644 --- a/compiler/rustc_codegen_ssa/src/mir/block.rs +++ b/compiler/rustc_codegen_ssa/src/mir/block.rs @@ -519,6 +519,9 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { match self.locals[mir::Local::from_usize(1 + va_list_arg_idx)] { LocalRef::Place(va_list) => { bx.va_end(va_list.val.llval); + + // Explicitly end the lifetime of the `va_list`, this matters for LLVM. + bx.lifetime_end(va_list.val.llval, va_list.layout.size); } _ => bug!("C-variadic function must have a `VaList` place"), } From e10e6d78ac671ad4df7f658e8a90dadb7a67b246 Mon Sep 17 00:00:00 2001 From: Karol Zwolak Date: Fri, 15 Aug 2025 10:10:54 +0200 Subject: [PATCH 22/48] dedup powi float test --- library/coretests/tests/floats/f128.rs | 16 -------------- library/coretests/tests/floats/f16.rs | 16 -------------- library/coretests/tests/floats/f32.rs | 19 ----------------- library/coretests/tests/floats/f64.rs | 14 ------------- library/coretests/tests/floats/mod.rs | 29 +++++++++++++++++++++++++- 5 files changed, 28 insertions(+), 66 deletions(-) diff --git a/library/coretests/tests/floats/f128.rs b/library/coretests/tests/floats/f128.rs index f718cfa6edc6..be10a1503f3a 100644 --- a/library/coretests/tests/floats/f128.rs +++ b/library/coretests/tests/floats/f128.rs @@ -52,22 +52,6 @@ fn test_max_recip() { ); } -#[test] -#[cfg(not(miri))] -#[cfg(target_has_reliable_f128_math)] -fn test_powi() { - let nan: f128 = f128::NAN; - let inf: f128 = f128::INFINITY; - let neg_inf: f128 = f128::NEG_INFINITY; - assert_biteq!(1.0f128.powi(1), 1.0); - assert_approx_eq!((-3.1f128).powi(2), 9.6100000000000005506706202140776519387, TOL); - assert_approx_eq!(5.9f128.powi(-2), 0.028727377190462507313100483690639638451, TOL); - assert_biteq!(8.3f128.powi(0), 1.0); - assert!(nan.powi(2).is_nan()); - assert_biteq!(inf.powi(3), inf); - assert_biteq!(neg_inf.powi(2), inf); -} - #[test] fn test_to_degrees() { let pi: f128 = consts::PI; diff --git a/library/coretests/tests/floats/f16.rs b/library/coretests/tests/floats/f16.rs index 244b9c3fd69c..f5cb3184fb7f 100644 --- a/library/coretests/tests/floats/f16.rs +++ b/library/coretests/tests/floats/f16.rs @@ -54,22 +54,6 @@ fn test_max_recip() { assert_approx_eq!(f16::MAX.recip(), 1.526624e-5f16, 1e-4); } -#[test] -#[cfg(not(miri))] -#[cfg(target_has_reliable_f16_math)] -fn test_powi() { - let nan: f16 = f16::NAN; - let inf: f16 = f16::INFINITY; - let neg_inf: f16 = f16::NEG_INFINITY; - assert_biteq!(1.0f16.powi(1), 1.0); - assert_approx_eq!((-3.1f16).powi(2), 9.61, TOL_0); - assert_approx_eq!(5.9f16.powi(-2), 0.028727, TOL_N2); - assert_biteq!(8.3f16.powi(0), 1.0); - assert!(nan.powi(2).is_nan()); - assert_biteq!(inf.powi(3), inf); - assert_biteq!(neg_inf.powi(2), inf); -} - #[test] fn test_to_degrees() { let pi: f16 = consts::PI; diff --git a/library/coretests/tests/floats/f32.rs b/library/coretests/tests/floats/f32.rs index 8c7cc97329ca..06bc889fd55a 100644 --- a/library/coretests/tests/floats/f32.rs +++ b/library/coretests/tests/floats/f32.rs @@ -9,11 +9,6 @@ const NAN_MASK1: u32 = 0x002a_aaaa; /// Second pattern over the mantissa const NAN_MASK2: u32 = 0x0055_5555; -/// Miri adds some extra errors to float functions; make sure the tests still pass. -/// These values are purely used as a canary to test against and are thus not a stable guarantee Rust provides. -/// They serve as a way to get an idea of the real precision of floating point operations on different platforms. -const APPROX_DELTA: f32 = if cfg!(miri) { 1e-4 } else { 1e-6 }; - // FIXME(#140515): mingw has an incorrect fma https://sourceforge.net/p/mingw-w64/bugs/848/ #[cfg_attr(all(target_os = "windows", target_env = "gnu", not(target_abi = "llvm")), ignore)] #[test] @@ -32,20 +27,6 @@ fn test_mul_add() { assert_biteq!(f32::math::mul_add(-3.2f32, 2.4, neg_inf), neg_inf); } -#[test] -fn test_powi() { - let nan: f32 = f32::NAN; - let inf: f32 = f32::INFINITY; - let neg_inf: f32 = f32::NEG_INFINITY; - assert_approx_eq!(1.0f32.powi(1), 1.0); - assert_approx_eq!((-3.1f32).powi(2), 9.61, APPROX_DELTA); - assert_approx_eq!(5.9f32.powi(-2), 0.028727); - assert_biteq!(8.3f32.powi(0), 1.0); - assert!(nan.powi(2).is_nan()); - assert_biteq!(inf.powi(3), inf); - assert_biteq!(neg_inf.powi(2), inf); -} - #[test] fn test_to_degrees() { let pi: f32 = consts::PI; diff --git a/library/coretests/tests/floats/f64.rs b/library/coretests/tests/floats/f64.rs index 7738fc1c4704..34f56ba0f53f 100644 --- a/library/coretests/tests/floats/f64.rs +++ b/library/coretests/tests/floats/f64.rs @@ -27,20 +27,6 @@ fn test_mul_add() { assert_biteq!((-3.2f64).mul_add(2.4, neg_inf), neg_inf); } -#[test] -fn test_powi() { - let nan: f64 = f64::NAN; - let inf: f64 = f64::INFINITY; - let neg_inf: f64 = f64::NEG_INFINITY; - assert_approx_eq!(1.0f64.powi(1), 1.0); - assert_approx_eq!((-3.1f64).powi(2), 9.61); - assert_approx_eq!(5.9f64.powi(-2), 0.028727); - assert_biteq!(8.3f64.powi(0), 1.0); - assert!(nan.powi(2).is_nan()); - assert_biteq!(inf.powi(3), inf); - assert_biteq!(neg_inf.powi(2), inf); -} - #[test] fn test_to_degrees() { let pi: f64 = consts::PI; diff --git a/library/coretests/tests/floats/mod.rs b/library/coretests/tests/floats/mod.rs index d5b05c45ddfd..1a7dd4d05540 100644 --- a/library/coretests/tests/floats/mod.rs +++ b/library/coretests/tests/floats/mod.rs @@ -1,11 +1,13 @@ use std::num::FpCategory as Fp; use std::ops::{Add, Div, Mul, Rem, Sub}; -trait TestableFloat { +trait TestableFloat: Sized { /// Unsigned int with the same size, for converting to/from bits. type Int; /// Set the default tolerance for float comparison based on the type. const APPROX: Self; + /// Allow looser tolerance for f32 on miri + const POWI_APPROX: Self = Self::APPROX; const ZERO: Self; const ONE: Self; const MIN_POSITIVE_NORMAL: Self; @@ -39,6 +41,10 @@ impl TestableFloat for f16 { impl TestableFloat for f32 { type Int = u32; const APPROX: Self = 1e-6; + /// Miri adds some extra errors to float functions; make sure the tests still pass. + /// These values are purely used as a canary to test against and are thus not a stable guarantee Rust provides. + /// They serve as a way to get an idea of the real precision of floating point operations on different platforms. + const POWI_APPROX: Self = if cfg!(miri) { 1e-4 } else { Self::APPROX }; const ZERO: Self = 0.0; const ONE: Self = 1.0; const MIN_POSITIVE_NORMAL: Self = Self::MIN_POSITIVE; @@ -1360,3 +1366,24 @@ float_test! { assert_biteq!(neg_inf.recip(), -0.0); } } + +float_test! { + name: powi, + attrs: { + const: #[cfg(false)], + f16: #[cfg(all(not(miri), target_has_reliable_f16_math))], + f128: #[cfg(all(not(miri), target_has_reliable_f128_math))], + }, + test { + let nan: Float = Float::NAN; + let inf: Float = Float::INFINITY; + let neg_inf: Float = Float::NEG_INFINITY; + assert_approx_eq!(Float::ONE.powi(1), Float::ONE); + assert_approx_eq!((-3.1 as Float).powi(2), 9.6100000000000005506706202140776519387, Float::POWI_APPROX); + assert_approx_eq!((5.9 as Float).powi(-2), 0.028727377190462507313100483690639638451); + assert_biteq!((8.3 as Float).powi(0), Float::ONE); + assert!(nan.powi(2).is_nan()); + assert_biteq!(inf.powi(3), inf); + assert_biteq!(neg_inf.powi(2), inf); + } +} From 43e535947b9ad8d951cde1bed626883cdd00bdf1 Mon Sep 17 00:00:00 2001 From: Waffle Lapkin Date: Sat, 30 Aug 2025 22:33:42 +0200 Subject: [PATCH 23/48] fixup nix dev shell again --- src/tools/nix-dev-shell/shell.nix | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/tools/nix-dev-shell/shell.nix b/src/tools/nix-dev-shell/shell.nix index ad33b121f979..6ca8a7c4652d 100644 --- a/src/tools/nix-dev-shell/shell.nix +++ b/src/tools/nix-dev-shell/shell.nix @@ -14,6 +14,7 @@ pkgs.mkShell { packages = [ pkgs.git pkgs.nix + pkgs.glibc.out pkgs.glibc.static x # Get the runtime deps of the x wrapper @@ -23,5 +24,7 @@ pkgs.mkShell { # Avoid creating text files for ICEs. RUSTC_ICE = 0; SSL_CERT_FILE = cacert; + # cargo seems to dlopen libcurl, so we need it in the ld library path + LD_LIBRARY_PATH = "${pkgs.lib.makeLibraryPath [pkgs.stdenv.cc.cc.lib pkgs.curl]}"; }; } From c81a8a89eebf5683a9be09e3160c956f77bb405e Mon Sep 17 00:00:00 2001 From: Karol Zwolak Date: Fri, 15 Aug 2025 10:33:11 +0200 Subject: [PATCH 24/48] dedup to_degrees float test --- library/coretests/tests/floats/f128.rs | 15 ------------- library/coretests/tests/floats/f16.rs | 15 ------------- library/coretests/tests/floats/f32.rs | 15 ------------- library/coretests/tests/floats/f64.rs | 14 ------------- library/coretests/tests/floats/mod.rs | 29 ++++++++++++++++++++++++++ 5 files changed, 29 insertions(+), 59 deletions(-) diff --git a/library/coretests/tests/floats/f128.rs b/library/coretests/tests/floats/f128.rs index be10a1503f3a..5e62eb7b7c59 100644 --- a/library/coretests/tests/floats/f128.rs +++ b/library/coretests/tests/floats/f128.rs @@ -52,21 +52,6 @@ fn test_max_recip() { ); } -#[test] -fn test_to_degrees() { - let pi: f128 = consts::PI; - let nan: f128 = f128::NAN; - let inf: f128 = f128::INFINITY; - let neg_inf: f128 = f128::NEG_INFINITY; - assert_biteq!(0.0f128.to_degrees(), 0.0); - assert_approx_eq!((-5.8f128).to_degrees(), -332.31552117587745090765431723855668471, TOL); - assert_approx_eq!(pi.to_degrees(), 180.0, TOL); - assert!(nan.to_degrees().is_nan()); - assert_biteq!(inf.to_degrees(), inf); - assert_biteq!(neg_inf.to_degrees(), neg_inf); - assert_biteq!(1_f128.to_degrees(), 57.2957795130823208767981548141051703); -} - #[test] fn test_to_radians() { let pi: f128 = consts::PI; diff --git a/library/coretests/tests/floats/f16.rs b/library/coretests/tests/floats/f16.rs index f5cb3184fb7f..f172e9cb508c 100644 --- a/library/coretests/tests/floats/f16.rs +++ b/library/coretests/tests/floats/f16.rs @@ -54,21 +54,6 @@ fn test_max_recip() { assert_approx_eq!(f16::MAX.recip(), 1.526624e-5f16, 1e-4); } -#[test] -fn test_to_degrees() { - let pi: f16 = consts::PI; - let nan: f16 = f16::NAN; - let inf: f16 = f16::INFINITY; - let neg_inf: f16 = f16::NEG_INFINITY; - assert_biteq!(0.0f16.to_degrees(), 0.0); - assert_approx_eq!((-5.8f16).to_degrees(), -332.315521, TOL_P2); - assert_approx_eq!(pi.to_degrees(), 180.0, TOL_P2); - assert!(nan.to_degrees().is_nan()); - assert_biteq!(inf.to_degrees(), inf); - assert_biteq!(neg_inf.to_degrees(), neg_inf); - assert_biteq!(1_f16.to_degrees(), 57.2957795130823208767981548141051703); -} - #[test] fn test_to_radians() { let pi: f16 = consts::PI; diff --git a/library/coretests/tests/floats/f32.rs b/library/coretests/tests/floats/f32.rs index 06bc889fd55a..c439dfed33ca 100644 --- a/library/coretests/tests/floats/f32.rs +++ b/library/coretests/tests/floats/f32.rs @@ -27,21 +27,6 @@ fn test_mul_add() { assert_biteq!(f32::math::mul_add(-3.2f32, 2.4, neg_inf), neg_inf); } -#[test] -fn test_to_degrees() { - let pi: f32 = consts::PI; - let nan: f32 = f32::NAN; - let inf: f32 = f32::INFINITY; - let neg_inf: f32 = f32::NEG_INFINITY; - assert_biteq!(0.0f32.to_degrees(), 0.0); - assert_approx_eq!((-5.8f32).to_degrees(), -332.315521); - assert_biteq!(pi.to_degrees(), 180.0); - assert!(nan.to_degrees().is_nan()); - assert_biteq!(inf.to_degrees(), inf); - assert_biteq!(neg_inf.to_degrees(), neg_inf); - assert_biteq!(1_f32.to_degrees(), 57.2957795130823208767981548141051703); -} - #[test] fn test_to_radians() { let pi: f32 = consts::PI; diff --git a/library/coretests/tests/floats/f64.rs b/library/coretests/tests/floats/f64.rs index 34f56ba0f53f..10ea901e930c 100644 --- a/library/coretests/tests/floats/f64.rs +++ b/library/coretests/tests/floats/f64.rs @@ -27,20 +27,6 @@ fn test_mul_add() { assert_biteq!((-3.2f64).mul_add(2.4, neg_inf), neg_inf); } -#[test] -fn test_to_degrees() { - let pi: f64 = consts::PI; - let nan: f64 = f64::NAN; - let inf: f64 = f64::INFINITY; - let neg_inf: f64 = f64::NEG_INFINITY; - assert_biteq!(0.0f64.to_degrees(), 0.0); - assert_approx_eq!((-5.8f64).to_degrees(), -332.315521); - assert_biteq!(pi.to_degrees(), 180.0); - assert!(nan.to_degrees().is_nan()); - assert_biteq!(inf.to_degrees(), inf); - assert_biteq!(neg_inf.to_degrees(), neg_inf); -} - #[test] fn test_to_radians() { let pi: f64 = consts::PI; diff --git a/library/coretests/tests/floats/mod.rs b/library/coretests/tests/floats/mod.rs index 1a7dd4d05540..8c939f8037dd 100644 --- a/library/coretests/tests/floats/mod.rs +++ b/library/coretests/tests/floats/mod.rs @@ -8,8 +8,11 @@ trait TestableFloat: Sized { const APPROX: Self; /// Allow looser tolerance for f32 on miri const POWI_APPROX: Self = Self::APPROX; + /// Allow for looser tolerance for f16 + const PI_TO_DEGREES_APPROX: Self = Self::APPROX; const ZERO: Self; const ONE: Self; + const PI: Self; const MIN_POSITIVE_NORMAL: Self; const MAX_SUBNORMAL: Self; /// Smallest number @@ -27,8 +30,10 @@ trait TestableFloat: Sized { impl TestableFloat for f16 { type Int = u16; const APPROX: Self = 1e-3; + const PI_TO_DEGREES_APPROX: Self = 0.125; const ZERO: Self = 0.0; const ONE: Self = 1.0; + const PI: Self = std::f16::consts::PI; const MIN_POSITIVE_NORMAL: Self = Self::MIN_POSITIVE; const MAX_SUBNORMAL: Self = Self::MIN_POSITIVE.next_down(); const TINY: Self = Self::from_bits(0x1); @@ -47,6 +52,7 @@ impl TestableFloat for f32 { const POWI_APPROX: Self = if cfg!(miri) { 1e-4 } else { Self::APPROX }; const ZERO: Self = 0.0; const ONE: Self = 1.0; + const PI: Self = std::f32::consts::PI; const MIN_POSITIVE_NORMAL: Self = Self::MIN_POSITIVE; const MAX_SUBNORMAL: Self = Self::MIN_POSITIVE.next_down(); const TINY: Self = Self::from_bits(0x1); @@ -61,6 +67,7 @@ impl TestableFloat for f64 { const APPROX: Self = 1e-6; const ZERO: Self = 0.0; const ONE: Self = 1.0; + const PI: Self = std::f64::consts::PI; const MIN_POSITIVE_NORMAL: Self = Self::MIN_POSITIVE; const MAX_SUBNORMAL: Self = Self::MIN_POSITIVE.next_down(); const TINY: Self = Self::from_bits(0x1); @@ -75,6 +82,7 @@ impl TestableFloat for f128 { const APPROX: Self = 1e-9; const ZERO: Self = 0.0; const ONE: Self = 1.0; + const PI: Self = std::f128::consts::PI; const MIN_POSITIVE_NORMAL: Self = Self::MIN_POSITIVE; const MAX_SUBNORMAL: Self = Self::MIN_POSITIVE.next_down(); const TINY: Self = Self::from_bits(0x1); @@ -1387,3 +1395,24 @@ float_test! { assert_biteq!(neg_inf.powi(2), inf); } } + +float_test! { + name: to_degrees, + attrs: { + f16: #[cfg(target_has_reliable_f16)], + f128: #[cfg(target_has_reliable_f128)], + }, + test { + let pi: Float = Float::PI; + let nan: Float = Float::NAN; + let inf: Float = Float::INFINITY; + let neg_inf: Float = Float::NEG_INFINITY; + assert_biteq!((0.0 as Float).to_degrees(), 0.0); + assert_approx_eq!((-5.8 as Float).to_degrees(), -332.31552117587745090765431723855668471); + assert_approx_eq!(pi.to_degrees(), 180.0, Float::PI_TO_DEGREES_APPROX); + assert!(nan.to_degrees().is_nan()); + assert_biteq!(inf.to_degrees(), inf); + assert_biteq!(neg_inf.to_degrees(), neg_inf); + assert_biteq!((1.0 as Float).to_degrees(), 57.2957795130823208767981548141051703); + } +} From 9028efcf2e67f5fb7a890b64866760c26c6c0270 Mon Sep 17 00:00:00 2001 From: Karol Zwolak Date: Sun, 31 Aug 2025 18:19:06 +0200 Subject: [PATCH 25/48] dedup to_radians float test --- library/coretests/tests/floats/f128.rs | 21 ++------------------- library/coretests/tests/floats/f16.rs | 17 ----------------- library/coretests/tests/floats/f32.rs | 16 ---------------- library/coretests/tests/floats/f64.rs | 16 ---------------- library/coretests/tests/floats/mod.rs | 24 ++++++++++++++++++++++++ 5 files changed, 26 insertions(+), 68 deletions(-) diff --git a/library/coretests/tests/floats/f128.rs b/library/coretests/tests/floats/f128.rs index 5e62eb7b7c59..c173d7f0ae01 100644 --- a/library/coretests/tests/floats/f128.rs +++ b/library/coretests/tests/floats/f128.rs @@ -1,18 +1,18 @@ // FIXME(f16_f128): only tested on platforms that have symbols and aren't buggy #![cfg(target_has_reliable_f128)] -use std::f128::consts; - use super::{assert_approx_eq, assert_biteq}; // Note these tolerances make sense around zero, but not for more extreme exponents. /// Default tolerances. Works for values that should be near precise but not exact. Roughly /// the precision carried by `100 * 100`. +#[allow(unused)] const TOL: f128 = 1e-12; /// For operations that are near exact, usually not involving math of different /// signs. +#[allow(unused)] const TOL_PRECISE: f128 = 1e-28; /// First pattern over the mantissa @@ -52,23 +52,6 @@ fn test_max_recip() { ); } -#[test] -fn test_to_radians() { - let pi: f128 = consts::PI; - let nan: f128 = f128::NAN; - let inf: f128 = f128::INFINITY; - let neg_inf: f128 = f128::NEG_INFINITY; - assert_biteq!(0.0f128.to_radians(), 0.0); - assert_approx_eq!(154.6f128.to_radians(), 2.6982790235832334267135442069489767804, TOL); - assert_approx_eq!((-332.31f128).to_radians(), -5.7999036373023566567593094812182763013, TOL); - // check approx rather than exact because round trip for pi doesn't fall on an exactly - // representable value (unlike `f32` and `f64`). - assert_approx_eq!(180.0f128.to_radians(), pi, TOL_PRECISE); - assert!(nan.to_radians().is_nan()); - assert_biteq!(inf.to_radians(), inf); - assert_biteq!(neg_inf.to_radians(), neg_inf); -} - #[test] fn test_float_bits_conv() { assert_eq!((1f128).to_bits(), 0x3fff0000000000000000000000000000); diff --git a/library/coretests/tests/floats/f16.rs b/library/coretests/tests/floats/f16.rs index f172e9cb508c..c12de7221baa 100644 --- a/library/coretests/tests/floats/f16.rs +++ b/library/coretests/tests/floats/f16.rs @@ -1,8 +1,6 @@ // FIXME(f16_f128): only tested on platforms that have symbols and aren't buggy #![cfg(target_has_reliable_f16)] -use std::f16::consts; - use super::{assert_approx_eq, assert_biteq}; /// Tolerance for results on the order of 10.0e-2 @@ -54,21 +52,6 @@ fn test_max_recip() { assert_approx_eq!(f16::MAX.recip(), 1.526624e-5f16, 1e-4); } -#[test] -fn test_to_radians() { - let pi: f16 = consts::PI; - let nan: f16 = f16::NAN; - let inf: f16 = f16::INFINITY; - let neg_inf: f16 = f16::NEG_INFINITY; - assert_biteq!(0.0f16.to_radians(), 0.0); - assert_approx_eq!(154.6f16.to_radians(), 2.698279, TOL_0); - assert_approx_eq!((-332.31f16).to_radians(), -5.799903, TOL_0); - assert_approx_eq!(180.0f16.to_radians(), pi, TOL_0); - assert!(nan.to_radians().is_nan()); - assert_biteq!(inf.to_radians(), inf); - assert_biteq!(neg_inf.to_radians(), neg_inf); -} - #[test] fn test_float_bits_conv() { assert_eq!((1f16).to_bits(), 0x3c00); diff --git a/library/coretests/tests/floats/f32.rs b/library/coretests/tests/floats/f32.rs index c439dfed33ca..b79295f470de 100644 --- a/library/coretests/tests/floats/f32.rs +++ b/library/coretests/tests/floats/f32.rs @@ -1,5 +1,4 @@ use core::f32; -use core::f32::consts; use super::{assert_approx_eq, assert_biteq}; @@ -27,21 +26,6 @@ fn test_mul_add() { assert_biteq!(f32::math::mul_add(-3.2f32, 2.4, neg_inf), neg_inf); } -#[test] -fn test_to_radians() { - let pi: f32 = consts::PI; - let nan: f32 = f32::NAN; - let inf: f32 = f32::INFINITY; - let neg_inf: f32 = f32::NEG_INFINITY; - assert_biteq!(0.0f32.to_radians(), 0.0); - assert_approx_eq!(154.6f32.to_radians(), 2.698279); - assert_approx_eq!((-332.31f32).to_radians(), -5.799903); - assert_biteq!(180.0f32.to_radians(), pi); - assert!(nan.to_radians().is_nan()); - assert_biteq!(inf.to_radians(), inf); - assert_biteq!(neg_inf.to_radians(), neg_inf); -} - #[test] fn test_float_bits_conv() { assert_eq!((1f32).to_bits(), 0x3f800000); diff --git a/library/coretests/tests/floats/f64.rs b/library/coretests/tests/floats/f64.rs index 10ea901e930c..a25405863286 100644 --- a/library/coretests/tests/floats/f64.rs +++ b/library/coretests/tests/floats/f64.rs @@ -1,5 +1,4 @@ use core::f64; -use core::f64::consts; use super::{assert_approx_eq, assert_biteq}; @@ -27,21 +26,6 @@ fn test_mul_add() { assert_biteq!((-3.2f64).mul_add(2.4, neg_inf), neg_inf); } -#[test] -fn test_to_radians() { - let pi: f64 = consts::PI; - let nan: f64 = f64::NAN; - let inf: f64 = f64::INFINITY; - let neg_inf: f64 = f64::NEG_INFINITY; - assert_biteq!(0.0f64.to_radians(), 0.0); - assert_approx_eq!(154.6f64.to_radians(), 2.698279); - assert_approx_eq!((-332.31f64).to_radians(), -5.799903); - assert_biteq!(180.0f64.to_radians(), pi); - assert!(nan.to_radians().is_nan()); - assert_biteq!(inf.to_radians(), inf); - assert_biteq!(neg_inf.to_radians(), neg_inf); -} - #[test] fn test_float_bits_conv() { assert_eq!((1f64).to_bits(), 0x3ff0000000000000); diff --git a/library/coretests/tests/floats/mod.rs b/library/coretests/tests/floats/mod.rs index 8c939f8037dd..5f59cb9cce37 100644 --- a/library/coretests/tests/floats/mod.rs +++ b/library/coretests/tests/floats/mod.rs @@ -8,6 +8,8 @@ trait TestableFloat: Sized { const APPROX: Self; /// Allow looser tolerance for f32 on miri const POWI_APPROX: Self = Self::APPROX; + /// Allow looser tolerance for f16 + const _180_TO_RADIANS_APPROX: Self = Self::APPROX; /// Allow for looser tolerance for f16 const PI_TO_DEGREES_APPROX: Self = Self::APPROX; const ZERO: Self; @@ -30,6 +32,7 @@ trait TestableFloat: Sized { impl TestableFloat for f16 { type Int = u16; const APPROX: Self = 1e-3; + const _180_TO_RADIANS_APPROX: Self = 1e-2; const PI_TO_DEGREES_APPROX: Self = 0.125; const ZERO: Self = 0.0; const ONE: Self = 1.0; @@ -1416,3 +1419,24 @@ float_test! { assert_biteq!((1.0 as Float).to_degrees(), 57.2957795130823208767981548141051703); } } + +float_test! { + name: to_radians, + attrs: { + f16: #[cfg(target_has_reliable_f16)], + f128: #[cfg(target_has_reliable_f128)], + }, + test { + let pi: Float = Float::PI; + let nan: Float = Float::NAN; + let inf: Float = Float::INFINITY; + let neg_inf: Float = Float::NEG_INFINITY; + assert_biteq!((0.0 as Float).to_radians(), 0.0); + assert_approx_eq!((154.6 as Float).to_radians(), 2.6982790235832334267135442069489767804); + assert_approx_eq!((-332.31 as Float).to_radians(), -5.7999036373023566567593094812182763013); + assert_approx_eq!((180.0 as Float).to_radians(), pi, Float::_180_TO_RADIANS_APPROX); + assert!(nan.to_radians().is_nan()); + assert_biteq!(inf.to_radians(), inf); + assert_biteq!(neg_inf.to_radians(), neg_inf); + } +} From ea2daa33c8a61af4518d86d78c742ec8e922c93e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Sun, 31 Aug 2025 21:13:12 +0000 Subject: [PATCH 26/48] Split `ObligationCauseCode::BinOp` for unops to `UnOp` --- compiler/rustc_hir_typeck/src/op.rs | 16 +++++++------ compiler/rustc_middle/src/traits/mod.rs | 8 +++++-- .../traits/fulfillment_errors.rs | 8 +++---- .../src/error_reporting/traits/suggestions.rs | 23 ++++++++----------- 4 files changed, 27 insertions(+), 28 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/op.rs b/compiler/rustc_hir_typeck/src/op.rs index 87a7cd62ae5e..11defc3aa033 100644 --- a/compiler/rustc_hir_typeck/src/op.rs +++ b/compiler/rustc_hir_typeck/src/op.rs @@ -962,13 +962,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let (opt_rhs_expr, opt_rhs_ty) = opt_rhs.unzip(); let cause = self.cause( span, - ObligationCauseCode::BinOp { - lhs_hir_id: lhs_expr.hir_id, - rhs_hir_id: opt_rhs_expr.map(|expr| expr.hir_id), - rhs_span: opt_rhs_expr.map(|expr| expr.span), - rhs_is_lit: opt_rhs_expr - .is_some_and(|expr| matches!(expr.kind, hir::ExprKind::Lit(_))), - output_ty: expected.only_has_type(self), + match opt_rhs_expr { + Some(rhs) => ObligationCauseCode::BinOp { + lhs_hir_id: lhs_expr.hir_id, + rhs_hir_id: rhs.hir_id, + rhs_span: rhs.span, + rhs_is_lit: matches!(rhs.kind, hir::ExprKind::Lit(_)), + output_ty: expected.only_has_type(self), + }, + None => ObligationCauseCode::UnOp { hir_id: lhs_expr.hir_id }, }, ); diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs index 32f91bfba6be..ab8a31429539 100644 --- a/compiler/rustc_middle/src/traits/mod.rs +++ b/compiler/rustc_middle/src/traits/mod.rs @@ -389,10 +389,14 @@ pub enum ObligationCauseCode<'tcx> { /// against. MatchImpl(ObligationCause<'tcx>, DefId), + UnOp { + hir_id: HirId, + }, + BinOp { lhs_hir_id: HirId, - rhs_hir_id: Option, - rhs_span: Option, + rhs_hir_id: HirId, + rhs_span: Span, rhs_is_lit: bool, output_ty: Option>, }, diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs index f1fd7ebfeba2..bc984f30472d 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs @@ -963,8 +963,8 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { trait_pred: ty::PolyTraitPredicate<'tcx>, err: &mut Diag<'_>, ) -> bool { - if let ObligationCauseCode::BinOp { lhs_hir_id, .. } = obligation.cause.code() - && let hir::Node::Expr(expr) = self.tcx.hir_node(*lhs_hir_id) + if let ObligationCauseCode::UnOp { hir_id, .. } = obligation.cause.code() + && let hir::Node::Expr(expr) = self.tcx.hir_node(*hir_id) && let hir::ExprKind::Unary(hir::UnOp::Neg, inner) = expr.kind && let hir::ExprKind::Lit(lit) = inner.kind && let LitKind::Int(_, LitIntType::Unsuffixed) = lit.node @@ -2769,9 +2769,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { suggested: bool, ) { let body_def_id = obligation.cause.body_id; - let span = if let ObligationCauseCode::BinOp { rhs_span: Some(rhs_span), .. } = - obligation.cause.code() - { + let span = if let ObligationCauseCode::BinOp { rhs_span, .. } = obligation.cause.code() { *rhs_span } else { span diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs index aa153d3607bf..40a27c9aebe2 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs @@ -554,7 +554,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { return true; } } else if let ( - ObligationCauseCode::BinOp { lhs_hir_id, rhs_hir_id: Some(rhs_hir_id), .. }, + ObligationCauseCode::BinOp { lhs_hir_id, rhs_hir_id, .. }, predicate, ) = code.peel_derives_with_predicate() && let Some(typeck_results) = &self.typeck_results @@ -2801,6 +2801,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { | ObligationCauseCode::QuestionMark | ObligationCauseCode::CheckAssociatedTypeBounds { .. } | ObligationCauseCode::LetElse + | ObligationCauseCode::UnOp { .. } | ObligationCauseCode::BinOp { .. } | ObligationCauseCode::AscribeUserTypeProvePredicate(..) | ObligationCauseCode::AlwaysApplicableImpl @@ -3839,9 +3840,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { trait_pred: ty::PolyTraitPredicate<'tcx>, ) { let rhs_span = match obligation.cause.code() { - ObligationCauseCode::BinOp { rhs_span: Some(span), rhs_is_lit, .. } if *rhs_is_lit => { - span - } + ObligationCauseCode::BinOp { rhs_span, rhs_is_lit, .. } if *rhs_is_lit => rhs_span, _ => return, }; if let ty::Float(_) = trait_pred.skip_binder().self_ty().kind() @@ -5108,16 +5107,12 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { let tcx = self.tcx; let predicate = predicate.upcast(tcx); match *cause_code { - ObligationCauseCode::BinOp { - lhs_hir_id, - rhs_hir_id: Some(rhs_hir_id), - rhs_span: Some(rhs_span), - .. - } if let Some(typeck_results) = &self.typeck_results - && let hir::Node::Expr(lhs) = tcx.hir_node(lhs_hir_id) - && let hir::Node::Expr(rhs) = tcx.hir_node(rhs_hir_id) - && let Some(lhs_ty) = typeck_results.expr_ty_opt(lhs) - && let Some(rhs_ty) = typeck_results.expr_ty_opt(rhs) => + ObligationCauseCode::BinOp { lhs_hir_id, rhs_hir_id, rhs_span, .. } + if let Some(typeck_results) = &self.typeck_results + && let hir::Node::Expr(lhs) = tcx.hir_node(lhs_hir_id) + && let hir::Node::Expr(rhs) = tcx.hir_node(rhs_hir_id) + && let Some(lhs_ty) = typeck_results.expr_ty_opt(lhs) + && let Some(rhs_ty) = typeck_results.expr_ty_opt(rhs) => { if let Some(pred) = predicate.as_trait_clause() && tcx.is_lang_item(pred.def_id(), LangItem::PartialEq) From 7ea882d4c475855fe3e453f709429cf2c8be295f Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 14 Aug 2025 10:56:18 +1000 Subject: [PATCH 27/48] Inline and remove `dump_matched_mir_node`. It has a single call site. --- compiler/rustc_middle/src/mir/pretty.rs | 36 ++++++++----------------- 1 file changed, 11 insertions(+), 25 deletions(-) diff --git a/compiler/rustc_middle/src/mir/pretty.rs b/compiler/rustc_middle/src/mir/pretty.rs index 128ae8549f7c..94f9c58b5cf4 100644 --- a/compiler/rustc_middle/src/mir/pretty.rs +++ b/compiler/rustc_middle/src/mir/pretty.rs @@ -125,7 +125,17 @@ pub fn dump_mir_with_options<'tcx, F>( return; } - dump_matched_mir_node(tcx, pass_num, pass_name, disambiguator, body, extra_data, options); + let _: io::Result<()> = try { + let mut file = create_dump_file(tcx, "mir", pass_num, pass_name, disambiguator, body)?; + dump_mir_to_writer(tcx, pass_name, disambiguator, body, &mut file, extra_data, options)?; + }; + + if tcx.sess.opts.unstable_opts.dump_mir_graphviz { + let _: io::Result<()> = try { + let mut file = create_dump_file(tcx, "dot", pass_num, pass_name, disambiguator, body)?; + write_mir_fn_graphviz(tcx, body, false, &mut file)?; + }; + } } pub fn dump_enabled(tcx: TyCtxt<'_>, pass_name: &str, def_id: DefId) -> bool { @@ -187,30 +197,6 @@ where extra_data(PassWhere::AfterCFG, w) } -fn dump_matched_mir_node<'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<()>, -{ - let _: io::Result<()> = try { - let mut file = create_dump_file(tcx, "mir", pass_num, pass_name, disambiguator, body)?; - dump_mir_to_writer(tcx, pass_name, disambiguator, body, &mut file, extra_data, options)?; - }; - - if tcx.sess.opts.unstable_opts.dump_mir_graphviz { - let _: io::Result<()> = try { - let mut file = create_dump_file(tcx, "dot", pass_num, pass_name, disambiguator, body)?; - write_mir_fn_graphviz(tcx, body, false, &mut file)?; - }; - } -} - /// Returns the path to the filename where we should dump a given MIR. /// Also used by other bits of code (e.g., NLL inference) that dump /// graphviz data or other things. From 3a0d0be586c0135bff8e8e2a280ee647337a07e7 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 14 Aug 2025 11:13:24 +1000 Subject: [PATCH 28/48] Inline and remove `dump_mir_for_pass`. The code is more readable without it. --- .../rustc_mir_transform/src/pass_manager.rs | 22 +++++-------------- 1 file changed, 6 insertions(+), 16 deletions(-) diff --git a/compiler/rustc_mir_transform/src/pass_manager.rs b/compiler/rustc_mir_transform/src/pass_manager.rs index 5b3ddcc777be..374421507230 100644 --- a/compiler/rustc_mir_transform/src/pass_manager.rs +++ b/compiler/rustc_mir_transform/src/pass_manager.rs @@ -275,13 +275,14 @@ fn run_passes_inner<'tcx>( } let prof_arg = tcx.sess.prof.enabled().then(|| format!("{:?}", body.source.def_id())); + let pass_num = true; if !body.should_skip() { let validate = validate_each & tcx.sess.opts.unstable_opts.validate_mir; let lint = tcx.sess.opts.unstable_opts.lint_mir; for pass in passes { - let name = pass.name(); + let pass_name = pass.name(); if !should_run_pass(tcx, *pass, optimizations) { continue; @@ -290,7 +291,7 @@ fn run_passes_inner<'tcx>( let dump_enabled = pass.is_mir_dump_enabled(); if dump_enabled { - dump_mir_for_pass(tcx, body, name, false); + mir::dump_mir(tcx, pass_num, pass_name, &"before", body, |_, _| Ok(())); } if let Some(prof_arg) = &prof_arg { @@ -303,13 +304,13 @@ fn run_passes_inner<'tcx>( } if dump_enabled { - dump_mir_for_pass(tcx, body, name, true); + mir::dump_mir(tcx, pass_num, pass_name, &"after", body, |_, _| Ok(())); } if validate { - validate_body(tcx, body, format!("after pass {name}")); + validate_body(tcx, body, format!("after pass {pass_name}")); } if lint { - lint_body(tcx, body, format!("after pass {name}")); + lint_body(tcx, body, format!("after pass {pass_name}")); } body.pass_count += 1; @@ -345,17 +346,6 @@ pub(super) fn validate_body<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>, when validate::Validator { when }.run_pass(tcx, body); } -fn dump_mir_for_pass<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>, pass_name: &str, is_after: bool) { - mir::dump_mir( - tcx, - true, - pass_name, - if is_after { &"after" } else { &"before" }, - body, - |_, _| Ok(()), - ); -} - pub(super) fn dump_mir_for_phase_change<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>) { assert_eq!(body.pass_count, 0); mir::dump_mir(tcx, true, body.phase.name(), &"after", body, |_, _| Ok(())) From d7faa5630daf13c3d298e81ac329bf048a0d5a01 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Fri, 15 Aug 2025 09:13:23 +1000 Subject: [PATCH 29/48] Avoid unnecessary `mut`-ness for various closures. --- compiler/rustc_codegen_cranelift/src/base.rs | 2 +- compiler/rustc_middle/src/mir/pretty.rs | 28 ++++++++++---------- compiler/rustc_mir_build/src/builder/mod.rs | 2 +- 3 files changed, 16 insertions(+), 16 deletions(-) diff --git a/compiler/rustc_codegen_cranelift/src/base.rs b/compiler/rustc_codegen_cranelift/src/base.rs index bc0a0f034b23..aefb9c9a1156 100644 --- a/compiler/rustc_codegen_cranelift/src/base.rs +++ b/compiler/rustc_codegen_cranelift/src/base.rs @@ -46,7 +46,7 @@ pub(crate) fn codegen_fn<'tcx>( with_no_trimmed_paths!({ use rustc_middle::mir::pretty; let options = pretty::PrettyPrintMirOptions::from_cli(tcx); - pretty::write_mir_fn(tcx, mir, &mut |_, _| Ok(()), &mut buf, options).unwrap(); + pretty::write_mir_fn(tcx, mir, &|_, _| Ok(()), &mut buf, options).unwrap(); }); String::from_utf8_lossy(&buf).into_owned() }); diff --git a/compiler/rustc_middle/src/mir/pretty.rs b/compiler/rustc_middle/src/mir/pretty.rs index 94f9c58b5cf4..c2cc20425816 100644 --- a/compiler/rustc_middle/src/mir/pretty.rs +++ b/compiler/rustc_middle/src/mir/pretty.rs @@ -91,7 +91,7 @@ pub fn dump_mir<'tcx, F>( body: &Body<'tcx>, extra_data: F, ) where - F: FnMut(PassWhere, &mut dyn io::Write) -> io::Result<()>, + F: Fn(PassWhere, &mut dyn io::Write) -> io::Result<()>, { dump_mir_with_options( tcx, @@ -119,7 +119,7 @@ pub fn dump_mir_with_options<'tcx, F>( extra_data: F, options: PrettyPrintMirOptions, ) where - F: FnMut(PassWhere, &mut dyn io::Write) -> io::Result<()>, + F: Fn(PassWhere, &mut dyn io::Write) -> io::Result<()>, { if !dump_enabled(tcx, pass_name, body.source.def_id()) { return; @@ -171,11 +171,11 @@ pub fn dump_mir_to_writer<'tcx, F>( disambiguator: &dyn Display, body: &Body<'tcx>, w: &mut dyn io::Write, - mut extra_data: F, + extra_data: F, options: PrettyPrintMirOptions, ) -> io::Result<()> where - F: FnMut(PassWhere, &mut dyn io::Write) -> io::Result<()>, + F: Fn(PassWhere, &mut dyn io::Write) -> io::Result<()>, { // see notes on #41697 above let def_path = @@ -193,7 +193,7 @@ where writeln!(w)?; extra_data(PassWhere::BeforeCFG, w)?; write_user_type_annotations(tcx, body, w)?; - write_mir_fn(tcx, body, &mut extra_data, w, options)?; + write_mir_fn(tcx, body, &extra_data, w, options)?; extra_data(PassWhere::AfterCFG, w) } @@ -343,11 +343,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, options)?; + write_mir_fn(tcx, body, &|_, _| Ok(()), w, options)?; for body in tcx.promoted_mir(def_id) { writeln!(w)?; - write_mir_fn(tcx, body, &mut |_, _| Ok(()), w, options)?; + write_mir_fn(tcx, body, &|_, _| Ok(()), w, options)?; } Ok(()) }; @@ -359,7 +359,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, options)?; + write_mir_fn(tcx, tcx.mir_for_ctfe(def_id), &|_, _| Ok(()), w, options)?; } else { let instance_mir = tcx.instance_mir(ty::InstanceKind::Item(def_id)); render_body(w, instance_mir)?; @@ -372,12 +372,12 @@ pub fn write_mir_pretty<'tcx>( pub fn write_mir_fn<'tcx, F>( tcx: TyCtxt<'tcx>, body: &Body<'tcx>, - extra_data: &mut F, + extra_data: &F, w: &mut dyn io::Write, options: PrettyPrintMirOptions, ) -> io::Result<()> where - F: FnMut(PassWhere, &mut dyn io::Write) -> io::Result<()>, + F: Fn(PassWhere, &mut dyn io::Write) -> io::Result<()>, { write_mir_intro(tcx, body, w, options)?; for block in body.basic_blocks.indices() { @@ -710,12 +710,12 @@ fn write_basic_block<'tcx, F>( tcx: TyCtxt<'tcx>, block: BasicBlock, body: &Body<'tcx>, - extra_data: &mut F, + extra_data: &F, w: &mut dyn io::Write, options: PrettyPrintMirOptions, ) -> io::Result<()> where - F: FnMut(PassWhere, &mut dyn io::Write) -> io::Result<()>, + F: Fn(PassWhere, &mut dyn io::Write) -> io::Result<()>, { let data = &body[block]; @@ -1363,11 +1363,11 @@ fn post_fmt_projection(projection: &[PlaceElem<'_>], fmt: &mut Formatter<'_>) -> fn write_extra<'tcx, F>( tcx: TyCtxt<'tcx>, write: &mut dyn io::Write, - mut visit_op: F, + visit_op: F, options: PrettyPrintMirOptions, ) -> io::Result<()> where - F: FnMut(&mut ExtraComments<'tcx>), + F: Fn(&mut ExtraComments<'tcx>), { if options.include_extra_comments { let mut extra_comments = ExtraComments { tcx, comments: vec![] }; diff --git a/compiler/rustc_mir_build/src/builder/mod.rs b/compiler/rustc_mir_build/src/builder/mod.rs index 6a8f0b21ee0e..4818f9bb0abf 100644 --- a/compiler/rustc_mir_build/src/builder/mod.rs +++ b/compiler/rustc_mir_build/src/builder/mod.rs @@ -834,7 +834,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { pretty::write_mir_fn( self.tcx, &body, - &mut |_, _| Ok(()), + &|_, _| Ok(()), &mut std::io::stdout(), options, ) From d3e2c93498d2ed4b924ac7b1d42bd824d58ffe0e Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Fri, 15 Aug 2025 13:13:14 +1000 Subject: [PATCH 30/48] Use trait object references for closures. The dynamic dispatch cost doesn't matter for MIR dumping, which is perf-insensitive. And it's necessary for the next commit, which will store some `extra_data` closures in a struct. --- compiler/rustc_borrowck/src/nll.rs | 4 +- compiler/rustc_borrowck/src/polonius/dump.rs | 2 +- compiler/rustc_middle/src/mir/pretty.rs | 62 +++++++------------ compiler/rustc_mir_transform/src/coroutine.rs | 10 +-- .../src/coroutine/by_move_body.rs | 2 +- .../rustc_mir_transform/src/coroutine/drop.rs | 6 +- compiler/rustc_mir_transform/src/dest_prop.rs | 2 +- .../src/lint_tail_expr_drop_order.rs | 2 +- .../rustc_mir_transform/src/pass_manager.rs | 6 +- compiler/rustc_mir_transform/src/shim.rs | 2 +- 10 files changed, 39 insertions(+), 59 deletions(-) diff --git a/compiler/rustc_borrowck/src/nll.rs b/compiler/rustc_borrowck/src/nll.rs index 8608a8a3a66f..021dba9c9a92 100644 --- a/compiler/rustc_borrowck/src/nll.rs +++ b/compiler/rustc_borrowck/src/nll.rs @@ -68,7 +68,7 @@ pub(crate) fn replace_regions_in_mir<'tcx>( // Replace all remaining regions with fresh inference variables. renumber::renumber_mir(infcx, body, promoted); - dump_mir(infcx.tcx, false, "renumber", &0, body, |_, _| Ok(())); + dump_mir(infcx.tcx, false, "renumber", &0, body, &|_, _| Ok(())); universal_regions } @@ -194,7 +194,7 @@ pub(super) fn dump_nll_mir<'tcx>( "nll", &0, body, - |pass_where, out| { + &|pass_where, out| { emit_nll_mir(tcx, regioncx, closure_region_requirements, borrow_set, pass_where, out) }, options, diff --git a/compiler/rustc_borrowck/src/polonius/dump.rs b/compiler/rustc_borrowck/src/polonius/dump.rs index 6b13b5ad0814..173fb5969769 100644 --- a/compiler/rustc_borrowck/src/polonius/dump.rs +++ b/compiler/rustc_borrowck/src/polonius/dump.rs @@ -175,7 +175,7 @@ fn emit_html_mir<'tcx>( &0, body, &mut buffer, - |pass_where, out| { + &|pass_where, out| { emit_polonius_mir( tcx, regioncx, diff --git a/compiler/rustc_middle/src/mir/pretty.rs b/compiler/rustc_middle/src/mir/pretty.rs index c2cc20425816..13b619a5a8bf 100644 --- a/compiler/rustc_middle/src/mir/pretty.rs +++ b/compiler/rustc_middle/src/mir/pretty.rs @@ -83,16 +83,14 @@ impl PrettyPrintMirOptions { /// - `foo & nll | bar & typeck` == match if `foo` and `nll` both appear in the name /// or `typeck` and `bar` both appear in the name. #[inline] -pub fn dump_mir<'tcx, F>( +pub fn dump_mir<'tcx>( tcx: TyCtxt<'tcx>, pass_num: bool, pass_name: &str, disambiguator: &dyn Display, body: &Body<'tcx>, - extra_data: F, -) where - F: Fn(PassWhere, &mut dyn io::Write) -> io::Result<()>, -{ + extra_data: &dyn Fn(PassWhere, &mut dyn io::Write) -> io::Result<()>, +) { dump_mir_with_options( tcx, pass_num, @@ -110,17 +108,15 @@ pub fn dump_mir<'tcx, F>( /// See [`dump_mir`] for more details. /// #[inline] -pub fn dump_mir_with_options<'tcx, F>( +pub fn dump_mir_with_options<'tcx>( tcx: TyCtxt<'tcx>, pass_num: bool, pass_name: &str, disambiguator: &dyn Display, body: &Body<'tcx>, - extra_data: F, + extra_data: &dyn Fn(PassWhere, &mut dyn io::Write) -> io::Result<()>, options: PrettyPrintMirOptions, -) where - F: Fn(PassWhere, &mut dyn io::Write) -> io::Result<()>, -{ +) { if !dump_enabled(tcx, pass_name, body.source.def_id()) { return; } @@ -165,18 +161,15 @@ pub fn dump_enabled(tcx: TyCtxt<'_>, pass_name: &str, def_id: DefId) -> bool { /// most of the MIR dumping occurs, if one needs to export it to a file they have created with /// [create_dump_file], rather than to a new file created as part of [dump_mir], or to stdout/stderr /// for debugging purposes. -pub fn dump_mir_to_writer<'tcx, F>( +pub fn dump_mir_to_writer<'tcx>( tcx: TyCtxt<'tcx>, pass_name: &str, disambiguator: &dyn Display, body: &Body<'tcx>, w: &mut dyn io::Write, - extra_data: F, + extra_data: &dyn Fn(PassWhere, &mut dyn io::Write) -> io::Result<()>, options: PrettyPrintMirOptions, -) -> io::Result<()> -where - F: Fn(PassWhere, &mut dyn io::Write) -> io::Result<()>, -{ +) -> io::Result<()> { // see notes on #41697 above let def_path = ty::print::with_forced_impl_filename_line!(tcx.def_path_str(body.source.def_id())); @@ -193,7 +186,7 @@ where writeln!(w)?; extra_data(PassWhere::BeforeCFG, w)?; write_user_type_annotations(tcx, body, w)?; - write_mir_fn(tcx, body, &extra_data, w, options)?; + write_mir_fn(tcx, body, extra_data, w, options)?; extra_data(PassWhere::AfterCFG, w) } @@ -369,16 +362,13 @@ pub fn write_mir_pretty<'tcx>( } /// Write out a human-readable textual representation for the given function. -pub fn write_mir_fn<'tcx, F>( +pub fn write_mir_fn<'tcx>( tcx: TyCtxt<'tcx>, body: &Body<'tcx>, - extra_data: &F, + extra_data: &dyn Fn(PassWhere, &mut dyn io::Write) -> io::Result<()>, w: &mut dyn io::Write, options: PrettyPrintMirOptions, -) -> io::Result<()> -where - F: Fn(PassWhere, &mut dyn io::Write) -> io::Result<()>, -{ +) -> io::Result<()> { write_mir_intro(tcx, body, w, options)?; for block in body.basic_blocks.indices() { extra_data(PassWhere::BeforeBlock(block), w)?; @@ -706,17 +696,14 @@ pub fn dump_mir_def_ids(tcx: TyCtxt<'_>, single: Option) -> Vec { // Basic blocks and their parts (statements, terminators, ...) /// Write out a human-readable textual representation for the given basic block. -fn write_basic_block<'tcx, F>( +fn write_basic_block<'tcx>( tcx: TyCtxt<'tcx>, block: BasicBlock, body: &Body<'tcx>, - extra_data: &F, + extra_data: &dyn Fn(PassWhere, &mut dyn io::Write) -> io::Result<()>, w: &mut dyn io::Write, options: PrettyPrintMirOptions, -) -> io::Result<()> -where - F: Fn(PassWhere, &mut dyn io::Write) -> io::Result<()>, -{ +) -> io::Result<()> { let data = &body[block]; // Basic block label at the top. @@ -748,9 +735,7 @@ where write_extra( tcx, w, - |visitor| { - visitor.visit_statement(statement, current_location); - }, + &|visitor| visitor.visit_statement(statement, current_location), options, )?; @@ -783,9 +768,7 @@ where write_extra( tcx, w, - |visitor| { - visitor.visit_terminator(data.terminator(), current_location); - }, + &|visitor| visitor.visit_terminator(data.terminator(), current_location), options, )?; } @@ -1360,15 +1343,12 @@ fn post_fmt_projection(projection: &[PlaceElem<'_>], fmt: &mut Formatter<'_>) -> /// After we print the main statement, we sometimes dump extra /// information. There's often a lot of little things "nuzzled up" in /// a statement. -fn write_extra<'tcx, F>( +fn write_extra<'tcx>( tcx: TyCtxt<'tcx>, write: &mut dyn io::Write, - visit_op: F, + visit_op: &dyn Fn(&mut ExtraComments<'tcx>), options: PrettyPrintMirOptions, -) -> io::Result<()> -where - F: Fn(&mut ExtraComments<'tcx>), -{ +) -> io::Result<()> { if options.include_extra_comments { let mut extra_comments = ExtraComments { tcx, comments: vec![] }; visit_op(&mut extra_comments); diff --git a/compiler/rustc_mir_transform/src/coroutine.rs b/compiler/rustc_mir_transform/src/coroutine.rs index 761d5461a996..592192944d2b 100644 --- a/compiler/rustc_mir_transform/src/coroutine.rs +++ b/compiler/rustc_mir_transform/src/coroutine.rs @@ -1294,7 +1294,7 @@ fn create_coroutine_resume_function<'tcx>( pm::run_passes_no_validate(tcx, body, &[&abort_unwinding_calls::AbortUnwindingCalls], None); - dump_mir(tcx, false, "coroutine_resume", &0, body, |_, _| Ok(())); + dump_mir(tcx, false, "coroutine_resume", &0, body, &|_, _| Ok(())); } /// An operation that can be performed on a coroutine. @@ -1446,7 +1446,7 @@ impl<'tcx> crate::MirPass<'tcx> for StateTransform { assert!(body.coroutine_drop().is_none() && body.coroutine_drop_async().is_none()); - dump_mir(tcx, false, "coroutine_before", &0, body, |_, _| Ok(())); + dump_mir(tcx, false, "coroutine_before", &0, body, &|_, _| Ok(())); // The first argument is the coroutine type passed by value let coroutine_ty = body.local_decls.raw[1].ty; @@ -1506,7 +1506,7 @@ impl<'tcx> crate::MirPass<'tcx> for StateTransform { ) { let context_mut_ref = transform_async_context(tcx, body); expand_async_drops(tcx, body, context_mut_ref, coroutine_kind, coroutine_ty); - dump_mir(tcx, false, "coroutine_async_drop_expand", &0, body, |_, _| Ok(())); + dump_mir(tcx, false, "coroutine_async_drop_expand", &0, body, &|_, _| Ok(())); } else { cleanup_async_drops(body); } @@ -1605,14 +1605,14 @@ impl<'tcx> crate::MirPass<'tcx> for StateTransform { // This is expanded to a drop ladder in `elaborate_coroutine_drops`. let drop_clean = insert_clean_drop(tcx, body, has_async_drops); - dump_mir(tcx, false, "coroutine_pre-elab", &0, body, |_, _| Ok(())); + dump_mir(tcx, false, "coroutine_pre-elab", &0, body, &|_, _| Ok(())); // Expand `drop(coroutine_struct)` to a drop ladder which destroys upvars. // If any upvars are moved out of, drop elaboration will handle upvar destruction. // However we need to also elaborate the code generated by `insert_clean_drop`. elaborate_coroutine_drops(tcx, body); - dump_mir(tcx, false, "coroutine_post-transform", &0, body, |_, _| Ok(())); + dump_mir(tcx, false, "coroutine_post-transform", &0, body, &|_, _| Ok(())); let can_unwind = can_unwind(tcx, body); diff --git a/compiler/rustc_mir_transform/src/coroutine/by_move_body.rs b/compiler/rustc_mir_transform/src/coroutine/by_move_body.rs index 81d7b7ba02c2..5ba6fea9fafb 100644 --- a/compiler/rustc_mir_transform/src/coroutine/by_move_body.rs +++ b/compiler/rustc_mir_transform/src/coroutine/by_move_body.rs @@ -225,7 +225,7 @@ pub(crate) fn coroutine_by_move_body_def_id<'tcx>( ); by_move_body.source = mir::MirSource::from_instance(InstanceKind::Item(body_def.def_id().to_def_id())); - dump_mir(tcx, false, "built", &"after", &by_move_body, |_, _| Ok(())); + dump_mir(tcx, false, "built", &"after", &by_move_body, &|_, _| Ok(())); // Feed HIR because we try to access this body's attrs in the inliner. body_def.feed_hir(); diff --git a/compiler/rustc_mir_transform/src/coroutine/drop.rs b/compiler/rustc_mir_transform/src/coroutine/drop.rs index 1a314e029f4a..6dffbc866278 100644 --- a/compiler/rustc_mir_transform/src/coroutine/drop.rs +++ b/compiler/rustc_mir_transform/src/coroutine/drop.rs @@ -605,7 +605,7 @@ pub(super) fn create_coroutine_drop_shim<'tcx>( // Temporary change MirSource to coroutine's instance so that dump_mir produces more sensible // filename. body.source.instance = coroutine_instance; - dump_mir(tcx, false, "coroutine_drop", &0, &body, |_, _| Ok(())); + dump_mir(tcx, false, "coroutine_drop", &0, &body, &|_, _| Ok(())); body.source.instance = drop_instance; // Creating a coroutine drop shim happens on `Analysis(PostCleanup) -> Runtime(Initial)` @@ -696,7 +696,7 @@ pub(super) fn create_coroutine_drop_shim_async<'tcx>( None, ); - dump_mir(tcx, false, "coroutine_drop_async", &0, &body, |_, _| Ok(())); + dump_mir(tcx, false, "coroutine_drop_async", &0, &body, &|_, _| Ok(())); body } @@ -741,7 +741,7 @@ pub(super) fn create_coroutine_drop_shim_proxy_async<'tcx>( }; body.basic_blocks_mut()[call_bb].terminator = Some(Terminator { source_info, kind }); - dump_mir(tcx, false, "coroutine_drop_proxy_async", &0, &body, |_, _| Ok(())); + dump_mir(tcx, false, "coroutine_drop_proxy_async", &0, &body, &|_, _| Ok(())); body } diff --git a/compiler/rustc_mir_transform/src/dest_prop.rs b/compiler/rustc_mir_transform/src/dest_prop.rs index 4c94a6c524e0..bb68d1a06595 100644 --- a/compiler/rustc_mir_transform/src/dest_prop.rs +++ b/compiler/rustc_mir_transform/src/dest_prop.rs @@ -810,7 +810,7 @@ fn dest_prop_mir_dump<'tcx>( let location = points.point_from_location(location); live.rows().filter(|&r| live.contains(r, location)).collect::>() }; - dump_mir(tcx, false, "DestinationPropagation-dataflow", &round, body, |pass_where, w| { + dump_mir(tcx, false, "DestinationPropagation-dataflow", &round, body, &|pass_where, w| { if let PassWhere::BeforeLocation(loc) = pass_where { writeln!(w, " // live: {:?}", locals_live_at(loc))?; } diff --git a/compiler/rustc_mir_transform/src/lint_tail_expr_drop_order.rs b/compiler/rustc_mir_transform/src/lint_tail_expr_drop_order.rs index 2f0edf31162d..0d0a71bc6c7e 100644 --- a/compiler/rustc_mir_transform/src/lint_tail_expr_drop_order.rs +++ b/compiler/rustc_mir_transform/src/lint_tail_expr_drop_order.rs @@ -227,7 +227,7 @@ pub(crate) fn run_lint<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId, body: &Body< return; } - dump_mir(tcx, false, "lint_tail_expr_drop_order", &0 as _, body, |_, _| Ok(())); + dump_mir(tcx, false, "lint_tail_expr_drop_order", &0 as _, body, &|_, _| Ok(())); let locals_with_user_names = collect_user_names(body); let is_closure_like = tcx.is_closure_like(def_id.to_def_id()); diff --git a/compiler/rustc_mir_transform/src/pass_manager.rs b/compiler/rustc_mir_transform/src/pass_manager.rs index 374421507230..374623d4ea54 100644 --- a/compiler/rustc_mir_transform/src/pass_manager.rs +++ b/compiler/rustc_mir_transform/src/pass_manager.rs @@ -291,7 +291,7 @@ fn run_passes_inner<'tcx>( let dump_enabled = pass.is_mir_dump_enabled(); if dump_enabled { - mir::dump_mir(tcx, pass_num, pass_name, &"before", body, |_, _| Ok(())); + mir::dump_mir(tcx, pass_num, pass_name, &"before", body, &|_, _| Ok(())); } if let Some(prof_arg) = &prof_arg { @@ -304,7 +304,7 @@ fn run_passes_inner<'tcx>( } if dump_enabled { - mir::dump_mir(tcx, pass_num, pass_name, &"after", body, |_, _| Ok(())); + mir::dump_mir(tcx, pass_num, pass_name, &"after", body, &|_, _| Ok(())); } if validate { validate_body(tcx, body, format!("after pass {pass_name}")); @@ -348,5 +348,5 @@ pub(super) fn validate_body<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>, when pub(super) fn dump_mir_for_phase_change<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>) { assert_eq!(body.pass_count, 0); - mir::dump_mir(tcx, true, body.phase.name(), &"after", body, |_, _| Ok(())) + mir::dump_mir(tcx, true, body.phase.name(), &"after", body, &|_, _| Ok(())) } diff --git a/compiler/rustc_mir_transform/src/shim.rs b/compiler/rustc_mir_transform/src/shim.rs index c6760b3583f2..39d4aaa98579 100644 --- a/compiler/rustc_mir_transform/src/shim.rs +++ b/compiler/rustc_mir_transform/src/shim.rs @@ -1248,7 +1248,7 @@ fn build_construct_coroutine_by_move_shim<'tcx>( if receiver_by_ref { "coroutine_closure_by_ref" } else { "coroutine_closure_by_move" }, &0, &body, - |_, _| Ok(()), + &|_, _| Ok(()), ); body From 2d21c134054b6d337d4a1b81550a1ad10509b913 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Fri, 15 Aug 2025 14:38:03 +1000 Subject: [PATCH 31/48] Indent some functions. This commit exists purely to simplify reviewing: these functions will become methods in the next commit. This commit indents them so that the next commit is more readable. --- compiler/rustc_middle/src/mir/pretty.rs | 672 ++++++++++++------------ 1 file changed, 336 insertions(+), 336 deletions(-) diff --git a/compiler/rustc_middle/src/mir/pretty.rs b/compiler/rustc_middle/src/mir/pretty.rs index 13b619a5a8bf..14f504bb2a95 100644 --- a/compiler/rustc_middle/src/mir/pretty.rs +++ b/compiler/rustc_middle/src/mir/pretty.rs @@ -58,257 +58,257 @@ impl PrettyPrintMirOptions { } } -/// If the session is properly configured, dumps a human-readable representation of the MIR (with -/// default pretty-printing options) into: -/// -/// ```text -/// rustc.node... -/// ``` -/// -/// Output from this function is controlled by passing `-Z dump-mir=`, -/// where `` takes the following forms: -/// -/// - `all` -- dump MIR for all fns, all passes, all everything -/// - a filter defined by a set of substrings combined with `&` and `|` -/// (`&` has higher precedence). At least one of the `|`-separated groups -/// must match; an `|`-separated group matches if all of its `&`-separated -/// substrings are matched. -/// -/// Example: -/// -/// - `nll` == match if `nll` appears in the name -/// - `foo & nll` == match if `foo` and `nll` both appear in the name -/// - `foo & nll | typeck` == match if `foo` and `nll` both appear in the name -/// or `typeck` appears in the name. -/// - `foo & nll | bar & typeck` == match if `foo` and `nll` both appear in the name -/// or `typeck` and `bar` both appear in the name. -#[inline] -pub fn dump_mir<'tcx>( - tcx: TyCtxt<'tcx>, - pass_num: bool, - pass_name: &str, - disambiguator: &dyn Display, - body: &Body<'tcx>, - extra_data: &dyn Fn(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>( - tcx: TyCtxt<'tcx>, - pass_num: bool, - pass_name: &str, - disambiguator: &dyn Display, - body: &Body<'tcx>, - extra_data: &dyn Fn(PassWhere, &mut dyn io::Write) -> io::Result<()>, - options: PrettyPrintMirOptions, -) { - if !dump_enabled(tcx, pass_name, body.source.def_id()) { - return; + /// If the session is properly configured, dumps a human-readable representation of the MIR + /// (with default pretty-printing options) into: + /// + /// ```text + /// rustc.node... + /// ``` + /// + /// Output from this function is controlled by passing `-Z dump-mir=`, + /// where `` takes the following forms: + /// + /// - `all` -- dump MIR for all fns, all passes, all everything + /// - a filter defined by a set of substrings combined with `&` and `|` + /// (`&` has higher precedence). At least one of the `|`-separated groups + /// must match; an `|`-separated group matches if all of its `&`-separated + /// substrings are matched. + /// + /// Example: + /// + /// - `nll` == match if `nll` appears in the name + /// - `foo & nll` == match if `foo` and `nll` both appear in the name + /// - `foo & nll | typeck` == match if `foo` and `nll` both appear in the name + /// or `typeck` appears in the name. + /// - `foo & nll | bar & typeck` == match if `foo` and `nll` both appear in the name + /// or `typeck` and `bar` both appear in the name. + #[inline] + pub fn dump_mir<'tcx>( + tcx: TyCtxt<'tcx>, + pass_num: bool, + pass_name: &str, + disambiguator: &dyn Display, + body: &Body<'tcx>, + extra_data: &dyn Fn(PassWhere, &mut dyn io::Write) -> io::Result<()>, + ) { + dump_mir_with_options( + tcx, + pass_num, + pass_name, + disambiguator, + body, + extra_data, + PrettyPrintMirOptions::from_cli(tcx), + ); } - let _: io::Result<()> = try { - let mut file = create_dump_file(tcx, "mir", pass_num, pass_name, disambiguator, body)?; - dump_mir_to_writer(tcx, pass_name, disambiguator, body, &mut file, extra_data, options)?; - }; + /// 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>( + tcx: TyCtxt<'tcx>, + pass_num: bool, + pass_name: &str, + disambiguator: &dyn Display, + body: &Body<'tcx>, + extra_data: &dyn Fn(PassWhere, &mut dyn io::Write) -> io::Result<()>, + options: PrettyPrintMirOptions, + ) { + if !dump_enabled(tcx, pass_name, body.source.def_id()) { + return; + } - if tcx.sess.opts.unstable_opts.dump_mir_graphviz { let _: io::Result<()> = try { - let mut file = create_dump_file(tcx, "dot", pass_num, pass_name, disambiguator, body)?; - write_mir_fn_graphviz(tcx, body, false, &mut file)?; + let mut file = create_dump_file(tcx, "mir", pass_num, pass_name, disambiguator, body)?; + dump_mir_to_writer(tcx, pass_name, disambiguator, body, &mut file, extra_data, options)?; }; - } -} -pub fn dump_enabled(tcx: TyCtxt<'_>, pass_name: &str, def_id: DefId) -> bool { - let Some(ref filters) = tcx.sess.opts.unstable_opts.dump_mir else { - return false; - }; - // see notes on #41697 below - let node_path = ty::print::with_forced_impl_filename_line!(tcx.def_path_str(def_id)); - filters.split('|').any(|or_filter| { - or_filter.split('&').all(|and_filter| { - let and_filter_trimmed = and_filter.trim(); - and_filter_trimmed == "all" - || pass_name.contains(and_filter_trimmed) - || node_path.contains(and_filter_trimmed) - }) - }) -} - -// #41697 -- we use `with_forced_impl_filename_line()` because -// `def_path_str()` would otherwise trigger `type_of`, and this can -// run while we are already attempting to evaluate `type_of`. - -/// Most use-cases of dumping MIR should use the [dump_mir] entrypoint instead, which will also -/// check if dumping MIR is enabled, and if this body matches the filters passed on the CLI. -/// -/// That being said, if the above requirements have been validated already, this function is where -/// most of the MIR dumping occurs, if one needs to export it to a file they have created with -/// [create_dump_file], rather than to a new file created as part of [dump_mir], or to stdout/stderr -/// for debugging purposes. -pub fn dump_mir_to_writer<'tcx>( - tcx: TyCtxt<'tcx>, - pass_name: &str, - disambiguator: &dyn Display, - body: &Body<'tcx>, - w: &mut dyn io::Write, - extra_data: &dyn Fn(PassWhere, &mut dyn io::Write) -> io::Result<()>, - options: PrettyPrintMirOptions, -) -> io::Result<()> { - // see notes on #41697 above - let def_path = - ty::print::with_forced_impl_filename_line!(tcx.def_path_str(body.source.def_id())); - // ignore-tidy-odd-backticks the literal below is fine - write!(w, "// MIR for `{def_path}")?; - match body.source.promoted { - None => write!(w, "`")?, - Some(promoted) => write!(w, "::{promoted:?}`")?, - } - writeln!(w, " {disambiguator} {pass_name}")?; - if let Some(ref layout) = body.coroutine_layout_raw() { - writeln!(w, "/* coroutine_layout = {layout:#?} */")?; - } - writeln!(w)?; - extra_data(PassWhere::BeforeCFG, w)?; - write_user_type_annotations(tcx, body, w)?; - write_mir_fn(tcx, body, extra_data, w, options)?; - extra_data(PassWhere::AfterCFG, w) -} - -/// Returns the path to the filename where we should dump a given MIR. -/// Also used by other bits of code (e.g., NLL inference) that dump -/// graphviz data or other things. -fn dump_path<'tcx>( - tcx: TyCtxt<'tcx>, - extension: &str, - pass_num: bool, - pass_name: &str, - disambiguator: &dyn Display, - body: &Body<'tcx>, -) -> PathBuf { - let source = body.source; - let promotion_id = match source.promoted { - Some(id) => format!("-{id:?}"), - None => String::new(), - }; - - let pass_num = if tcx.sess.opts.unstable_opts.dump_mir_exclude_pass_number { - String::new() - } else if pass_num { - let (dialect_index, phase_index) = body.phase.index(); - format!(".{}-{}-{:03}", dialect_index, phase_index, body.pass_count) - } else { - ".-------".to_string() - }; - - let crate_name = tcx.crate_name(source.def_id().krate); - let item_name = tcx.def_path(source.def_id()).to_filename_friendly_no_crate(); - // All drop shims have the same DefId, so we have to add the type - // to get unique file names. - let shim_disambiguator = match source.instance { - ty::InstanceKind::DropGlue(_, Some(ty)) => { - // Unfortunately, pretty-printed typed are not very filename-friendly. - // We dome some filtering. - let mut s = ".".to_owned(); - s.extend(ty.to_string().chars().filter_map(|c| match c { - ' ' => None, - ':' | '<' | '>' => Some('_'), - c => Some(c), - })); - s - } - ty::InstanceKind::AsyncDropGlueCtorShim(_, ty) => { - let mut s = ".".to_owned(); - s.extend(ty.to_string().chars().filter_map(|c| match c { - ' ' => None, - ':' | '<' | '>' => Some('_'), - c => Some(c), - })); - s - } - ty::InstanceKind::AsyncDropGlue(_, ty) => { - let ty::Coroutine(_, args) = ty.kind() else { - bug!(); + if tcx.sess.opts.unstable_opts.dump_mir_graphviz { + let _: io::Result<()> = try { + let mut file = create_dump_file(tcx, "dot", pass_num, pass_name, disambiguator, body)?; + write_mir_fn_graphviz(tcx, body, false, &mut file)?; }; - let ty = args.first().unwrap().expect_ty(); - let mut s = ".".to_owned(); - s.extend(ty.to_string().chars().filter_map(|c| match c { - ' ' => None, - ':' | '<' | '>' => Some('_'), - c => Some(c), - })); - s } - ty::InstanceKind::FutureDropPollShim(_, proxy_cor, impl_cor) => { - let mut s = ".".to_owned(); - s.extend(proxy_cor.to_string().chars().filter_map(|c| match c { - ' ' => None, - ':' | '<' | '>' => Some('_'), - c => Some(c), - })); - s.push('.'); - s.extend(impl_cor.to_string().chars().filter_map(|c| match c { - ' ' => None, - ':' | '<' | '>' => Some('_'), - c => Some(c), - })); - s - } - _ => String::new(), - }; - - let mut file_path = PathBuf::new(); - file_path.push(Path::new(&tcx.sess.opts.unstable_opts.dump_mir_dir)); - - let file_name = format!( - "{crate_name}.{item_name}{shim_disambiguator}{promotion_id}{pass_num}.{pass_name}.{disambiguator}.{extension}", - ); - - file_path.push(&file_name); - - file_path -} - -/// Attempts to open a file where we should dump a given MIR or other -/// bit of MIR-related data. Used by `mir-dump`, but also by other -/// bits of code (e.g., NLL inference) that dump graphviz data or -/// other things, and hence takes the extension as an argument. -pub fn create_dump_file<'tcx>( - tcx: TyCtxt<'tcx>, - extension: &str, - pass_num: bool, - pass_name: &str, - disambiguator: &dyn Display, - body: &Body<'tcx>, -) -> io::Result> { - let file_path = dump_path(tcx, extension, pass_num, pass_name, disambiguator, body); - if let Some(parent) = file_path.parent() { - fs::create_dir_all(parent).map_err(|e| { - io::Error::new( - e.kind(), - format!("IO error creating MIR dump directory: {parent:?}; {e}"), - ) - })?; } - fs::File::create_buffered(&file_path).map_err(|e| { - io::Error::new(e.kind(), format!("IO error creating MIR dump file: {file_path:?}; {e}")) - }) -} + + pub fn dump_enabled(tcx: TyCtxt<'_>, pass_name: &str, def_id: DefId) -> bool { + let Some(ref filters) = tcx.sess.opts.unstable_opts.dump_mir else { + return false; + }; + // see notes on #41697 below + let node_path = ty::print::with_forced_impl_filename_line!(tcx.def_path_str(def_id)); + filters.split('|').any(|or_filter| { + or_filter.split('&').all(|and_filter| { + let and_filter_trimmed = and_filter.trim(); + and_filter_trimmed == "all" + || pass_name.contains(and_filter_trimmed) + || node_path.contains(and_filter_trimmed) + }) + }) + } + + // #41697 -- we use `with_forced_impl_filename_line()` because + // `def_path_str()` would otherwise trigger `type_of`, and this can + // run while we are already attempting to evaluate `type_of`. + + /// Most use-cases of dumping MIR should use the [dump_mir] entrypoint instead, which will also + /// check if dumping MIR is enabled, and if this body matches the filters passed on the CLI. + /// + /// That being said, if the above requirements have been validated already, this function is + /// where most of the MIR dumping occurs, if one needs to export it to a file they have created + /// with [create_dump_file], rather than to a new file created as part of [dump_mir], or to + /// stdout/stderr for debugging purposes. + pub fn dump_mir_to_writer<'tcx>( + tcx: TyCtxt<'tcx>, + pass_name: &str, + disambiguator: &dyn Display, + body: &Body<'tcx>, + w: &mut dyn io::Write, + extra_data: &dyn Fn(PassWhere, &mut dyn io::Write) -> io::Result<()>, + options: PrettyPrintMirOptions, + ) -> io::Result<()> { + // see notes on #41697 above + let def_path = + ty::print::with_forced_impl_filename_line!(tcx.def_path_str(body.source.def_id())); + // ignore-tidy-odd-backticks the literal below is fine + write!(w, "// MIR for `{def_path}")?; + match body.source.promoted { + None => write!(w, "`")?, + Some(promoted) => write!(w, "::{promoted:?}`")?, + } + writeln!(w, " {disambiguator} {pass_name}")?; + if let Some(ref layout) = body.coroutine_layout_raw() { + writeln!(w, "/* coroutine_layout = {layout:#?} */")?; + } + writeln!(w)?; + extra_data(PassWhere::BeforeCFG, w)?; + write_user_type_annotations(tcx, body, w)?; + write_mir_fn(tcx, body, extra_data, w, options)?; + extra_data(PassWhere::AfterCFG, w) + } + + /// Returns the path to the filename where we should dump a given MIR. + /// Also used by other bits of code (e.g., NLL inference) that dump + /// graphviz data or other things. + fn dump_path<'tcx>( + tcx: TyCtxt<'tcx>, + extension: &str, + pass_num: bool, + pass_name: &str, + disambiguator: &dyn Display, + body: &Body<'tcx>, + ) -> PathBuf { + let source = body.source; + let promotion_id = match source.promoted { + Some(id) => format!("-{id:?}"), + None => String::new(), + }; + + let pass_num = if tcx.sess.opts.unstable_opts.dump_mir_exclude_pass_number { + String::new() + } else if pass_num { + let (dialect_index, phase_index) = body.phase.index(); + format!(".{}-{}-{:03}", dialect_index, phase_index, body.pass_count) + } else { + ".-------".to_string() + }; + + let crate_name = tcx.crate_name(source.def_id().krate); + let item_name = tcx.def_path(source.def_id()).to_filename_friendly_no_crate(); + // All drop shims have the same DefId, so we have to add the type + // to get unique file names. + let shim_disambiguator = match source.instance { + ty::InstanceKind::DropGlue(_, Some(ty)) => { + // Unfortunately, pretty-printed typed are not very filename-friendly. + // We dome some filtering. + let mut s = ".".to_owned(); + s.extend(ty.to_string().chars().filter_map(|c| match c { + ' ' => None, + ':' | '<' | '>' => Some('_'), + c => Some(c), + })); + s + } + ty::InstanceKind::AsyncDropGlueCtorShim(_, ty) => { + let mut s = ".".to_owned(); + s.extend(ty.to_string().chars().filter_map(|c| match c { + ' ' => None, + ':' | '<' | '>' => Some('_'), + c => Some(c), + })); + s + } + ty::InstanceKind::AsyncDropGlue(_, ty) => { + let ty::Coroutine(_, args) = ty.kind() else { + bug!(); + }; + let ty = args.first().unwrap().expect_ty(); + let mut s = ".".to_owned(); + s.extend(ty.to_string().chars().filter_map(|c| match c { + ' ' => None, + ':' | '<' | '>' => Some('_'), + c => Some(c), + })); + s + } + ty::InstanceKind::FutureDropPollShim(_, proxy_cor, impl_cor) => { + let mut s = ".".to_owned(); + s.extend(proxy_cor.to_string().chars().filter_map(|c| match c { + ' ' => None, + ':' | '<' | '>' => Some('_'), + c => Some(c), + })); + s.push('.'); + s.extend(impl_cor.to_string().chars().filter_map(|c| match c { + ' ' => None, + ':' | '<' | '>' => Some('_'), + c => Some(c), + })); + s + } + _ => String::new(), + }; + + let mut file_path = PathBuf::new(); + file_path.push(Path::new(&tcx.sess.opts.unstable_opts.dump_mir_dir)); + + let file_name = format!( + "{crate_name}.{item_name}{shim_disambiguator}{promotion_id}{pass_num}.{pass_name}.{disambiguator}.{extension}", + ); + + file_path.push(&file_name); + + file_path + } + + /// Attempts to open a file where we should dump a given MIR or other + /// bit of MIR-related data. Used by `mir-dump`, but also by other + /// bits of code (e.g., NLL inference) that dump graphviz data or + /// other things, and hence takes the extension as an argument. + pub fn create_dump_file<'tcx>( + tcx: TyCtxt<'tcx>, + extension: &str, + pass_num: bool, + pass_name: &str, + disambiguator: &dyn Display, + body: &Body<'tcx>, + ) -> io::Result> { + let file_path = dump_path(tcx, extension, pass_num, pass_name, disambiguator, body); + if let Some(parent) = file_path.parent() { + fs::create_dir_all(parent).map_err(|e| { + io::Error::new( + e.kind(), + format!("IO error creating MIR dump directory: {parent:?}; {e}"), + ) + })?; + } + fs::File::create_buffered(&file_path).map_err(|e| { + io::Error::new(e.kind(), format!("IO error creating MIR dump file: {file_path:?}; {e}")) + }) + } /////////////////////////////////////////////////////////////////////////// // Whole MIR bodies @@ -361,30 +361,30 @@ pub fn write_mir_pretty<'tcx>( Ok(()) } -/// Write out a human-readable textual representation for the given function. -pub fn write_mir_fn<'tcx>( - tcx: TyCtxt<'tcx>, - body: &Body<'tcx>, - extra_data: &dyn Fn(PassWhere, &mut dyn io::Write) -> io::Result<()>, - w: &mut dyn io::Write, - options: PrettyPrintMirOptions, -) -> io::Result<()> { - 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, options)?; - if block.index() + 1 != body.basic_blocks.len() { - writeln!(w)?; + /// Write out a human-readable textual representation for the given function. + pub fn write_mir_fn<'tcx>( + tcx: TyCtxt<'tcx>, + body: &Body<'tcx>, + extra_data: &dyn Fn(PassWhere, &mut dyn io::Write) -> io::Result<()>, + w: &mut dyn io::Write, + options: PrettyPrintMirOptions, + ) -> io::Result<()> { + 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, options)?; + if block.index() + 1 != body.basic_blocks.len() { + writeln!(w)?; + } } + + writeln!(w, "}}")?; + + write_allocations(tcx, body, w)?; + + Ok(()) } - writeln!(w, "}}")?; - - write_allocations(tcx, body, w)?; - - Ok(()) -} - /// Prints local variables in a scope tree. fn write_scope_tree( tcx: TyCtxt<'_>, @@ -695,90 +695,90 @@ pub fn dump_mir_def_ids(tcx: TyCtxt<'_>, single: Option) -> Vec { /////////////////////////////////////////////////////////////////////////// // Basic blocks and their parts (statements, terminators, ...) -/// Write out a human-readable textual representation for the given basic block. -fn write_basic_block<'tcx>( - tcx: TyCtxt<'tcx>, - block: BasicBlock, - body: &Body<'tcx>, - extra_data: &dyn Fn(PassWhere, &mut dyn io::Write) -> io::Result<()>, - w: &mut dyn io::Write, - options: PrettyPrintMirOptions, -) -> io::Result<()> { - let data = &body[block]; + /// Write out a human-readable textual representation for the given basic block. + fn write_basic_block<'tcx>( + tcx: TyCtxt<'tcx>, + block: BasicBlock, + body: &Body<'tcx>, + extra_data: &dyn Fn(PassWhere, &mut dyn io::Write) -> io::Result<()>, + w: &mut dyn io::Write, + options: PrettyPrintMirOptions, + ) -> io::Result<()> { + let data = &body[block]; - // Basic block label at the top. - let cleanup_text = if data.is_cleanup { " (cleanup)" } else { "" }; - writeln!(w, "{INDENT}{block:?}{cleanup_text}: {{")?; + // Basic block label at the top. + let cleanup_text = if data.is_cleanup { " (cleanup)" } else { "" }; + writeln!(w, "{INDENT}{block:?}{cleanup_text}: {{")?; - // List of statements in the middle. - let mut current_location = Location { block, statement_index: 0 }; - for statement in &data.statements { - extra_data(PassWhere::BeforeLocation(current_location), w)?; - let indented_body = format!("{INDENT}{INDENT}{statement:?};"); - if options.include_extra_comments { - writeln!( + // List of statements in the middle. + let mut current_location = Location { block, statement_index: 0 }; + for statement in &data.statements { + extra_data(PassWhere::BeforeLocation(current_location), w)?; + let indented_body = format!("{INDENT}{INDENT}{statement:?};"); + if options.include_extra_comments { + writeln!( + w, + "{:A$} // {}{}", + indented_body, + if tcx.sess.verbose_internals() { + format!("{current_location:?}: ") + } else { + String::new() + }, + comment(tcx, statement.source_info), + A = ALIGN, + )?; + } else { + writeln!(w, "{indented_body}")?; + } + + write_extra( + tcx, w, - "{:A$} // {}{}", - indented_body, - if tcx.sess.verbose_internals() { - format!("{current_location:?}: ") - } else { - String::new() - }, - comment(tcx, statement.source_info), - A = ALIGN, + &|visitor| visitor.visit_statement(statement, current_location), + options, )?; - } else { - writeln!(w, "{indented_body}")?; + + extra_data(PassWhere::AfterLocation(current_location), w)?; + + current_location.statement_index += 1; } - write_extra( - tcx, - w, - &|visitor| visitor.visit_statement(statement, current_location), - options, - )?; + // Terminator at the bottom. + extra_data(PassWhere::BeforeLocation(current_location), w)?; + if data.terminator.is_some() { + let indented_terminator = format!("{0}{0}{1:?};", INDENT, data.terminator().kind); + if options.include_extra_comments { + writeln!( + w, + "{:A$} // {}{}", + indented_terminator, + if tcx.sess.verbose_internals() { + format!("{current_location:?}: ") + } else { + String::new() + }, + comment(tcx, data.terminator().source_info), + A = ALIGN, + )?; + } else { + writeln!(w, "{indented_terminator}")?; + } + + 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)?; - current_location.statement_index += 1; + writeln!(w, "{INDENT}}}") } - // Terminator at the bottom. - extra_data(PassWhere::BeforeLocation(current_location), w)?; - if data.terminator.is_some() { - let indented_terminator = format!("{0}{0}{1:?};", INDENT, data.terminator().kind); - if options.include_extra_comments { - writeln!( - w, - "{:A$} // {}{}", - indented_terminator, - if tcx.sess.verbose_internals() { - format!("{current_location:?}: ") - } else { - String::new() - }, - comment(tcx, data.terminator().source_info), - A = ALIGN, - )?; - } else { - writeln!(w, "{indented_terminator}")?; - } - - 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)?; - - writeln!(w, "{INDENT}}}") -} - impl Debug for Statement<'_> { fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result { use self::StatementKind::*; From 5ce3797073ee5e6cc487b80effbc682533d9425c Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Fri, 15 Aug 2025 14:38:17 +1000 Subject: [PATCH 32/48] Introduce `MirDumper` and `MirWriter`. MIR dumping is a mess. There are lots of functions and entry points, e.g. `dump_mir`, `dump_mir_with_options`, `dump_polonius_mir`, `dump_mir_to_writer`. Also, it's crucial that `create_dump_file` is never called without `dump_enabled` first being checked, but there is no mechanism for ensuring this and it's hard to tell if it is satisfied on all paths. (`dump_enabled` is checked twice on some paths, however!) This commit introduces `MirWriter`, which controls the MIR writing, and encapsulates the `extra_data` closure and `options`. Two existing functions are now methods of this type. It sets reasonable defaults, allowing the removal of many `|_, _| Ok(())` closures. The commit also introduces `MirDumper`, which is layered on top of `MirWriter`, and which manages the creation of the dump files, encapsulating pass names, disambiguators, etc. Four existing functions are now methods of this type. - `MirDumper::new` will only succeed if dumps are enabled, and will return `None` otherwise, which makes it impossible to dump when you shouldn't. - It also sets reasonable defaults for various things like disambiguators, which means you no longer need to specify them in many cases. When they do need to be specified, it's now done via setter methods. - It avoids some repetition. E.g. `dump_nll_mir` previously specifed the pass name `"nll"` four times and the disambiguator `&0` three times; now it specifies them just once, to put them in the `MirDumper`. - For Polonius, the `extra_data` closure can now be specified earlier, which avoids having to pass some arguments through some functions. --- compiler/rustc_borrowck/src/nll.rs | 35 +-- compiler/rustc_borrowck/src/polonius/dump.rs | 89 ++---- compiler/rustc_codegen_cranelift/src/base.rs | 5 +- compiler/rustc_middle/src/mir/mod.rs | 4 +- compiler/rustc_middle/src/mir/pretty.rs | 282 +++++++++--------- compiler/rustc_mir_build/src/builder/mod.rs | 18 +- .../src/framework/graphviz.rs | 13 +- compiler/rustc_mir_transform/src/coroutine.rs | 21 +- .../src/coroutine/by_move_body.rs | 7 +- .../rustc_mir_transform/src/coroutine/drop.rs | 12 +- compiler/rustc_mir_transform/src/dest_prop.rs | 20 +- .../src/lint_tail_expr_drop_order.rs | 9 +- .../rustc_mir_transform/src/pass_manager.rs | 24 +- compiler/rustc_mir_transform/src/shim.rs | 14 +- 14 files changed, 276 insertions(+), 277 deletions(-) diff --git a/compiler/rustc_borrowck/src/nll.rs b/compiler/rustc_borrowck/src/nll.rs index 021dba9c9a92..eb0f56bb869a 100644 --- a/compiler/rustc_borrowck/src/nll.rs +++ b/compiler/rustc_borrowck/src/nll.rs @@ -8,8 +8,8 @@ use std::str::FromStr; use polonius_engine::{Algorithm, AllFacts, Output}; use rustc_data_structures::frozen::Frozen; use rustc_index::IndexSlice; -use rustc_middle::mir::pretty::{PrettyPrintMirOptions, dump_mir_with_options}; -use rustc_middle::mir::{Body, PassWhere, Promoted, create_dump_file, dump_enabled, dump_mir}; +use rustc_middle::mir::pretty::PrettyPrintMirOptions; +use rustc_middle::mir::{Body, MirDumper, PassWhere, Promoted}; use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_middle::ty::{self, TyCtxt}; use rustc_mir_dataflow::move_paths::MoveData; @@ -68,7 +68,9 @@ pub(crate) fn replace_regions_in_mir<'tcx>( // Replace all remaining regions with fresh inference variables. renumber::renumber_mir(infcx, body, promoted); - dump_mir(infcx.tcx, false, "renumber", &0, body, &|_, _| Ok(())); + if let Some(dumper) = MirDumper::new(infcx.tcx, "renumber", body) { + dumper.dump_mir(body); + } universal_regions } @@ -175,9 +177,7 @@ pub(super) fn dump_nll_mir<'tcx>( borrow_set: &BorrowSet<'tcx>, ) { let tcx = infcx.tcx; - if !dump_enabled(tcx, "nll", body.source.def_id()) { - return; - } + let Some(dumper) = MirDumper::new(tcx, "nll", body) else { return }; // 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, @@ -188,27 +188,24 @@ pub(super) fn dump_nll_mir<'tcx>( MirIncludeSpans::On | MirIncludeSpans::Nll ), }; - dump_mir_with_options( - tcx, - false, - "nll", - &0, - body, - &|pass_where, out| { - emit_nll_mir(tcx, regioncx, closure_region_requirements, borrow_set, pass_where, out) - }, - options, - ); + + let extra_data = &|pass_where, out: &mut dyn std::io::Write| { + emit_nll_mir(tcx, regioncx, closure_region_requirements, borrow_set, pass_where, out) + }; + + let dumper = dumper.set_extra_data(extra_data).set_options(options); + + dumper.dump_mir(body); // Also dump the region constraint graph as a graphviz file. let _: io::Result<()> = try { - let mut file = create_dump_file(tcx, "regioncx.all.dot", false, "nll", &0, body)?; + let mut file = dumper.create_dump_file("regioncx.all.dot", body)?; regioncx.dump_graphviz_raw_constraints(tcx, &mut file)?; }; // Also dump the region constraint SCC graph as a graphviz file. let _: io::Result<()> = try { - let mut file = create_dump_file(tcx, "regioncx.scc.dot", false, "nll", &0, body)?; + let mut file = dumper.create_dump_file("regioncx.scc.dot", body)?; regioncx.dump_graphviz_scc_constraints(tcx, &mut file)?; }; } diff --git a/compiler/rustc_borrowck/src/polonius/dump.rs b/compiler/rustc_borrowck/src/polonius/dump.rs index 173fb5969769..62f9ae173474 100644 --- a/compiler/rustc_borrowck/src/polonius/dump.rs +++ b/compiler/rustc_borrowck/src/polonius/dump.rs @@ -2,9 +2,7 @@ use std::io; use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet}; use rustc_index::IndexVec; -use rustc_middle::mir::pretty::{ - PassWhere, PrettyPrintMirOptions, create_dump_file, dump_enabled, dump_mir_to_writer, -}; +use rustc_middle::mir::pretty::{MirDumper, PassWhere, PrettyPrintMirOptions}; use rustc_middle::mir::{Body, Location}; use rustc_middle::ty::{RegionVid, TyCtxt}; use rustc_mir_dataflow::points::PointIndex; @@ -33,22 +31,41 @@ pub(crate) fn dump_polonius_mir<'tcx>( return; } - if !dump_enabled(tcx, "polonius", body.source.def_id()) { - return; - } + let Some(dumper) = MirDumper::new(tcx, "polonius", body) else { return }; let polonius_diagnostics = polonius_diagnostics.expect("missing diagnostics context with `-Zpolonius=next`"); - let _: io::Result<()> = try { - let mut file = create_dump_file(tcx, "html", false, "polonius", &0, body)?; - emit_polonius_dump( + let extra_data = &|pass_where, out: &mut dyn io::Write| { + emit_polonius_mir( tcx, + regioncx, + closure_region_requirements, + borrow_set, + &polonius_diagnostics.localized_outlives_constraints, + pass_where, + out, + ) + }; + // We want the NLL extra comments printed by default in NLL MIR dumps. Specifying `-Z + // mir-include-spans` on the CLI still has priority. + let options = PrettyPrintMirOptions { + include_extra_comments: matches!( + tcx.sess.opts.unstable_opts.mir_include_spans, + MirIncludeSpans::On | MirIncludeSpans::Nll + ), + }; + + let dumper = dumper.set_extra_data(extra_data).set_options(options); + + let _: io::Result<()> = try { + let mut file = dumper.create_dump_file("html", body)?; + emit_polonius_dump( + &dumper, body, regioncx, borrow_set, &polonius_diagnostics.localized_outlives_constraints, - closure_region_requirements, &mut file, )?; }; @@ -61,12 +78,11 @@ pub(crate) fn dump_polonius_mir<'tcx>( /// - 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>, + dumper: &MirDumper<'_, '_, 'tcx>, body: &Body<'tcx>, regioncx: &RegionInferenceContext<'tcx>, borrow_set: &BorrowSet<'tcx>, localized_outlives_constraints: &LocalizedOutlivesConstraintSet, - closure_region_requirements: &Option>, out: &mut dyn io::Write, ) -> io::Result<()> { // Prepare the HTML dump file prologue. @@ -79,15 +95,7 @@ fn emit_polonius_dump<'tcx>( writeln!(out, "
")?; writeln!(out, "Raw MIR dump")?; writeln!(out, "
")?;
-    emit_html_mir(
-        tcx,
-        body,
-        regioncx,
-        borrow_set,
-        &localized_outlives_constraints,
-        closure_region_requirements,
-        out,
-    )?;
+    emit_html_mir(dumper, body, out)?;
     writeln!(out, "
")?; writeln!(out, "
")?; @@ -116,7 +124,7 @@ fn emit_polonius_dump<'tcx>( writeln!(out, "
")?; writeln!(out, "NLL regions")?; writeln!(out, "
")?;
-    emit_mermaid_nll_regions(tcx, regioncx, out)?;
+    emit_mermaid_nll_regions(dumper.tcx(), regioncx, out)?;
     writeln!(out, "
")?; writeln!(out, "
")?; @@ -124,7 +132,7 @@ fn emit_polonius_dump<'tcx>( writeln!(out, "
")?; writeln!(out, "NLL SCCs")?; writeln!(out, "
")?;
-    emit_mermaid_nll_sccs(tcx, regioncx, out)?;
+    emit_mermaid_nll_sccs(dumper.tcx(), regioncx, out)?;
     writeln!(out, "
")?; writeln!(out, "
")?; @@ -149,45 +157,14 @@ fn emit_polonius_dump<'tcx>( /// Emits the polonius MIR, as escaped HTML. fn emit_html_mir<'tcx>( - tcx: TyCtxt<'tcx>, + dumper: &MirDumper<'_, '_, 'tcx>, body: &Body<'tcx>, - regioncx: &RegionInferenceContext<'tcx>, - borrow_set: &BorrowSet<'tcx>, - localized_outlives_constraints: &LocalizedOutlivesConstraintSet, - closure_region_requirements: &Option>, out: &mut dyn io::Write, ) -> io::Result<()> { // Buffer the regular MIR dump to be able to escape it. let mut buffer = Vec::new(); - // We want the NLL extra comments printed by default in NLL MIR dumps. Specifying `-Z - // mir-include-spans` on the CLI still has priority. - let options = PrettyPrintMirOptions { - include_extra_comments: matches!( - tcx.sess.opts.unstable_opts.mir_include_spans, - MirIncludeSpans::On | MirIncludeSpans::Nll - ), - }; - - dump_mir_to_writer( - tcx, - "polonius", - &0, - body, - &mut buffer, - &|pass_where, out| { - emit_polonius_mir( - tcx, - regioncx, - closure_region_requirements, - borrow_set, - localized_outlives_constraints, - pass_where, - out, - ) - }, - options, - )?; + dumper.dump_mir_to_writer(body, &mut buffer)?; // Escape the handful of characters that need it. We don't need to be particularly efficient: // we're actually writing into a buffered writer already. Note that MIR dumps are valid UTF-8. diff --git a/compiler/rustc_codegen_cranelift/src/base.rs b/compiler/rustc_codegen_cranelift/src/base.rs index aefb9c9a1156..3a28dd7e73cb 100644 --- a/compiler/rustc_codegen_cranelift/src/base.rs +++ b/compiler/rustc_codegen_cranelift/src/base.rs @@ -44,9 +44,8 @@ pub(crate) fn codegen_fn<'tcx>( let _mir_guard = crate::PrintOnPanic(|| { let mut buf = Vec::new(); with_no_trimmed_paths!({ - use rustc_middle::mir::pretty; - let options = pretty::PrettyPrintMirOptions::from_cli(tcx); - pretty::write_mir_fn(tcx, mir, &|_, _| Ok(()), &mut buf, options).unwrap(); + let writer = pretty::MirWriter::new(tcx); + writer.write_mir_fn(mir, &mut buf).unwrap(); }); String::from_utf8_lossy(&buf).into_owned() }); diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index c977e5329c29..da2245b12d2c 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -62,9 +62,7 @@ pub use terminator::*; pub use self::generic_graph::graphviz_safe_def_name; pub use self::graphviz::write_mir_graphviz; -pub use self::pretty::{ - PassWhere, create_dump_file, display_allocation, dump_enabled, dump_mir, write_mir_pretty, -}; +pub use self::pretty::{MirDumper, PassWhere, display_allocation, write_mir_pretty}; /// Types for locals pub type LocalDecls<'tcx> = IndexSlice>; diff --git a/compiler/rustc_middle/src/mir/pretty.rs b/compiler/rustc_middle/src/mir/pretty.rs index 14f504bb2a95..a7d99f513a12 100644 --- a/compiler/rustc_middle/src/mir/pretty.rs +++ b/compiler/rustc_middle/src/mir/pretty.rs @@ -44,7 +44,7 @@ pub enum PassWhere { } /// 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`]. +/// override these when dumping its own specific MIR information with `dump_mir`. #[derive(Copy, Clone)] pub struct PrettyPrintMirOptions { /// Whether to include extra comments, like span info. From `-Z mir-include-spans`. @@ -58,6 +58,79 @@ impl PrettyPrintMirOptions { } } +/// Manages MIR dumping, which is MIR writing done to a file with a specific name. In particular, +/// it makes it impossible to dump MIR to one of these files when it hasn't been requested from the +/// command line. Layered on top of `MirWriter`, which does the actual writing. +pub struct MirDumper<'dis, 'de, 'tcx> { + show_pass_num: bool, + pass_name: &'static str, + disambiguator: &'dis dyn Display, + writer: MirWriter<'de, 'tcx>, +} + +impl<'dis, 'de, 'tcx> MirDumper<'dis, 'de, 'tcx> { + // If dumping should be performed (e.g. because it was requested on the + // CLI), returns a `MirDumper` with default values for the following fields: + // - `show_pass_num`: `false` + // - `disambiguator`: `&0` + // - `writer.extra_data`: a no-op + // - `writer.options`: default options derived from CLI flags + pub fn new(tcx: TyCtxt<'tcx>, pass_name: &'static str, body: &Body<'tcx>) -> Option { + let dump_enabled = if let Some(ref filters) = tcx.sess.opts.unstable_opts.dump_mir { + // see notes on #41697 below + let node_path = + ty::print::with_forced_impl_filename_line!(tcx.def_path_str(body.source.def_id())); + filters.split('|').any(|or_filter| { + or_filter.split('&').all(|and_filter| { + let and_filter_trimmed = and_filter.trim(); + and_filter_trimmed == "all" + || pass_name.contains(and_filter_trimmed) + || node_path.contains(and_filter_trimmed) + }) + }) + } else { + false + }; + + dump_enabled.then_some(MirDumper { + show_pass_num: false, + pass_name, + disambiguator: &0, + writer: MirWriter::new(tcx), + }) + } + + pub fn tcx(&self) -> TyCtxt<'tcx> { + self.writer.tcx + } + + #[must_use] + pub fn set_show_pass_num(mut self) -> Self { + self.show_pass_num = true; + self + } + + #[must_use] + pub fn set_disambiguator(mut self, disambiguator: &'dis dyn Display) -> Self { + self.disambiguator = disambiguator; + self + } + + #[must_use] + pub fn set_extra_data( + mut self, + extra_data: &'de dyn Fn(PassWhere, &mut dyn io::Write) -> io::Result<()>, + ) -> Self { + self.writer.extra_data = extra_data; + self + } + + #[must_use] + pub fn set_options(mut self, options: PrettyPrintMirOptions) -> Self { + self.writer.options = options; + self + } + /// If the session is properly configured, dumps a human-readable representation of the MIR /// (with default pretty-printing options) into: /// @@ -82,125 +155,49 @@ impl PrettyPrintMirOptions { /// or `typeck` appears in the name. /// - `foo & nll | bar & typeck` == match if `foo` and `nll` both appear in the name /// or `typeck` and `bar` both appear in the name. - #[inline] - pub fn dump_mir<'tcx>( - tcx: TyCtxt<'tcx>, - pass_num: bool, - pass_name: &str, - disambiguator: &dyn Display, - body: &Body<'tcx>, - extra_data: &dyn Fn(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>( - tcx: TyCtxt<'tcx>, - pass_num: bool, - pass_name: &str, - disambiguator: &dyn Display, - body: &Body<'tcx>, - extra_data: &dyn Fn(PassWhere, &mut dyn io::Write) -> io::Result<()>, - options: PrettyPrintMirOptions, - ) { - if !dump_enabled(tcx, pass_name, body.source.def_id()) { - return; - } - + pub fn dump_mir(&self, body: &Body<'tcx>) { let _: io::Result<()> = try { - let mut file = create_dump_file(tcx, "mir", pass_num, pass_name, disambiguator, body)?; - dump_mir_to_writer(tcx, pass_name, disambiguator, body, &mut file, extra_data, options)?; + let mut file = self.create_dump_file("mir", body)?; + self.dump_mir_to_writer(body, &mut file)?; }; - if tcx.sess.opts.unstable_opts.dump_mir_graphviz { + if self.tcx().sess.opts.unstable_opts.dump_mir_graphviz { let _: io::Result<()> = try { - let mut file = create_dump_file(tcx, "dot", pass_num, pass_name, disambiguator, body)?; - write_mir_fn_graphviz(tcx, body, false, &mut file)?; + let mut file = self.create_dump_file("dot", body)?; + write_mir_fn_graphviz(self.tcx(), body, false, &mut file)?; }; } } - pub fn dump_enabled(tcx: TyCtxt<'_>, pass_name: &str, def_id: DefId) -> bool { - let Some(ref filters) = tcx.sess.opts.unstable_opts.dump_mir else { - return false; - }; - // see notes on #41697 below - let node_path = ty::print::with_forced_impl_filename_line!(tcx.def_path_str(def_id)); - filters.split('|').any(|or_filter| { - or_filter.split('&').all(|and_filter| { - let and_filter_trimmed = and_filter.trim(); - and_filter_trimmed == "all" - || pass_name.contains(and_filter_trimmed) - || node_path.contains(and_filter_trimmed) - }) - }) - } - - // #41697 -- we use `with_forced_impl_filename_line()` because - // `def_path_str()` would otherwise trigger `type_of`, and this can - // run while we are already attempting to evaluate `type_of`. - - /// Most use-cases of dumping MIR should use the [dump_mir] entrypoint instead, which will also - /// check if dumping MIR is enabled, and if this body matches the filters passed on the CLI. - /// - /// That being said, if the above requirements have been validated already, this function is - /// where most of the MIR dumping occurs, if one needs to export it to a file they have created - /// with [create_dump_file], rather than to a new file created as part of [dump_mir], or to - /// stdout/stderr for debugging purposes. - pub fn dump_mir_to_writer<'tcx>( - tcx: TyCtxt<'tcx>, - pass_name: &str, - disambiguator: &dyn Display, - body: &Body<'tcx>, - w: &mut dyn io::Write, - extra_data: &dyn Fn(PassWhere, &mut dyn io::Write) -> io::Result<()>, - options: PrettyPrintMirOptions, - ) -> io::Result<()> { + // #41697 -- we use `with_forced_impl_filename_line()` because `def_path_str()` would otherwise + // trigger `type_of`, and this can run while we are already attempting to evaluate `type_of`. + pub fn dump_mir_to_writer(&self, body: &Body<'tcx>, w: &mut dyn io::Write) -> io::Result<()> { // see notes on #41697 above - let def_path = - ty::print::with_forced_impl_filename_line!(tcx.def_path_str(body.source.def_id())); + let def_path = ty::print::with_forced_impl_filename_line!( + self.tcx().def_path_str(body.source.def_id()) + ); // ignore-tidy-odd-backticks the literal below is fine write!(w, "// MIR for `{def_path}")?; match body.source.promoted { None => write!(w, "`")?, Some(promoted) => write!(w, "::{promoted:?}`")?, } - writeln!(w, " {disambiguator} {pass_name}")?; + writeln!(w, " {} {}", self.disambiguator, self.pass_name)?; if let Some(ref layout) = body.coroutine_layout_raw() { writeln!(w, "/* coroutine_layout = {layout:#?} */")?; } writeln!(w)?; - extra_data(PassWhere::BeforeCFG, w)?; - write_user_type_annotations(tcx, body, w)?; - write_mir_fn(tcx, body, extra_data, w, options)?; - extra_data(PassWhere::AfterCFG, w) + (self.writer.extra_data)(PassWhere::BeforeCFG, w)?; + write_user_type_annotations(self.tcx(), body, w)?; + self.writer.write_mir_fn(body, w)?; + (self.writer.extra_data)(PassWhere::AfterCFG, w) } /// Returns the path to the filename where we should dump a given MIR. /// Also used by other bits of code (e.g., NLL inference) that dump /// graphviz data or other things. - fn dump_path<'tcx>( - tcx: TyCtxt<'tcx>, - extension: &str, - pass_num: bool, - pass_name: &str, - disambiguator: &dyn Display, - body: &Body<'tcx>, - ) -> PathBuf { + fn dump_path(&self, extension: &str, body: &Body<'tcx>) -> PathBuf { + let tcx = self.tcx(); let source = body.source; let promotion_id = match source.promoted { Some(id) => format!("-{id:?}"), @@ -209,7 +206,7 @@ impl PrettyPrintMirOptions { let pass_num = if tcx.sess.opts.unstable_opts.dump_mir_exclude_pass_number { String::new() - } else if pass_num { + } else if self.show_pass_num { let (dialect_index, phase_index) = body.phase.index(); format!(".{}-{}-{:03}", dialect_index, phase_index, body.pass_count) } else { @@ -222,8 +219,8 @@ impl PrettyPrintMirOptions { // to get unique file names. let shim_disambiguator = match source.instance { ty::InstanceKind::DropGlue(_, Some(ty)) => { - // Unfortunately, pretty-printed typed are not very filename-friendly. - // We dome some filtering. + // Unfortunately, pretty-printed types are not very filename-friendly. + // We do some filtering. let mut s = ".".to_owned(); s.extend(ty.to_string().chars().filter_map(|c| match c { ' ' => None, @@ -275,6 +272,8 @@ impl PrettyPrintMirOptions { let mut file_path = PathBuf::new(); file_path.push(Path::new(&tcx.sess.opts.unstable_opts.dump_mir_dir)); + let pass_name = self.pass_name; + let disambiguator = self.disambiguator; let file_name = format!( "{crate_name}.{item_name}{shim_disambiguator}{promotion_id}{pass_num}.{pass_name}.{disambiguator}.{extension}", ); @@ -288,15 +287,12 @@ impl PrettyPrintMirOptions { /// bit of MIR-related data. Used by `mir-dump`, but also by other /// bits of code (e.g., NLL inference) that dump graphviz data or /// other things, and hence takes the extension as an argument. - pub fn create_dump_file<'tcx>( - tcx: TyCtxt<'tcx>, + pub fn create_dump_file( + &self, extension: &str, - pass_num: bool, - pass_name: &str, - disambiguator: &dyn Display, body: &Body<'tcx>, ) -> io::Result> { - let file_path = dump_path(tcx, extension, pass_num, pass_name, disambiguator, body); + let file_path = self.dump_path(extension, body); if let Some(parent) = file_path.parent() { fs::create_dir_all(parent).map_err(|e| { io::Error::new( @@ -309,6 +305,7 @@ impl PrettyPrintMirOptions { io::Error::new(e.kind(), format!("IO error creating MIR dump file: {file_path:?}; {e}")) }) } +} /////////////////////////////////////////////////////////////////////////// // Whole MIR bodies @@ -320,7 +317,7 @@ pub fn write_mir_pretty<'tcx>( single: Option, w: &mut dyn io::Write, ) -> io::Result<()> { - let options = PrettyPrintMirOptions::from_cli(tcx); + let writer = MirWriter::new(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.")?; @@ -336,11 +333,11 @@ pub fn write_mir_pretty<'tcx>( } let render_body = |w: &mut dyn io::Write, body| -> io::Result<()> { - write_mir_fn(tcx, body, &|_, _| Ok(()), w, options)?; + writer.write_mir_fn(body, w)?; for body in tcx.promoted_mir(def_id) { writeln!(w)?; - write_mir_fn(tcx, body, &|_, _| Ok(()), w, options)?; + writer.write_mir_fn(body, w)?; } Ok(()) }; @@ -352,7 +349,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), &|_, _| Ok(()), w, options)?; + writer.write_mir_fn(tcx.mir_for_ctfe(def_id), w)?; } else { let instance_mir = tcx.instance_mir(ty::InstanceKind::Item(def_id)); render_body(w, instance_mir)?; @@ -361,18 +358,24 @@ pub fn write_mir_pretty<'tcx>( Ok(()) } +/// Does the writing of MIR to output, e.g. a file. +pub struct MirWriter<'de, 'tcx> { + tcx: TyCtxt<'tcx>, + extra_data: &'de dyn Fn(PassWhere, &mut dyn io::Write) -> io::Result<()>, + options: PrettyPrintMirOptions, +} + +impl<'de, 'tcx> MirWriter<'de, 'tcx> { + pub fn new(tcx: TyCtxt<'tcx>) -> Self { + MirWriter { tcx, extra_data: &|_, _| Ok(()), options: PrettyPrintMirOptions::from_cli(tcx) } + } + /// Write out a human-readable textual representation for the given function. - pub fn write_mir_fn<'tcx>( - tcx: TyCtxt<'tcx>, - body: &Body<'tcx>, - extra_data: &dyn Fn(PassWhere, &mut dyn io::Write) -> io::Result<()>, - w: &mut dyn io::Write, - options: PrettyPrintMirOptions, - ) -> io::Result<()> { - write_mir_intro(tcx, body, w, options)?; + pub fn write_mir_fn(&self, body: &Body<'tcx>, w: &mut dyn io::Write) -> io::Result<()> { + write_mir_intro(self.tcx, body, w, self.options)?; for block in body.basic_blocks.indices() { - extra_data(PassWhere::BeforeBlock(block), w)?; - write_basic_block(tcx, block, body, extra_data, w, options)?; + (self.extra_data)(PassWhere::BeforeBlock(block), w)?; + self.write_basic_block(block, body, w)?; if block.index() + 1 != body.basic_blocks.len() { writeln!(w)?; } @@ -380,10 +383,11 @@ pub fn write_mir_pretty<'tcx>( writeln!(w, "}}")?; - write_allocations(tcx, body, w)?; + write_allocations(self.tcx, body, w)?; Ok(()) } +} /// Prints local variables in a scope tree. fn write_scope_tree( @@ -695,14 +699,13 @@ pub fn dump_mir_def_ids(tcx: TyCtxt<'_>, single: Option) -> Vec { /////////////////////////////////////////////////////////////////////////// // Basic blocks and their parts (statements, terminators, ...) +impl<'de, 'tcx> MirWriter<'de, 'tcx> { /// Write out a human-readable textual representation for the given basic block. - fn write_basic_block<'tcx>( - tcx: TyCtxt<'tcx>, + fn write_basic_block( + &self, block: BasicBlock, body: &Body<'tcx>, - extra_data: &dyn Fn(PassWhere, &mut dyn io::Write) -> io::Result<()>, w: &mut dyn io::Write, - options: PrettyPrintMirOptions, ) -> io::Result<()> { let data = &body[block]; @@ -713,19 +716,19 @@ pub fn dump_mir_def_ids(tcx: TyCtxt<'_>, single: Option) -> Vec { // List of statements in the middle. let mut current_location = Location { block, statement_index: 0 }; for statement in &data.statements { - extra_data(PassWhere::BeforeLocation(current_location), w)?; + (self.extra_data)(PassWhere::BeforeLocation(current_location), w)?; let indented_body = format!("{INDENT}{INDENT}{statement:?};"); - if options.include_extra_comments { + if self.options.include_extra_comments { writeln!( w, "{:A$} // {}{}", indented_body, - if tcx.sess.verbose_internals() { + if self.tcx.sess.verbose_internals() { format!("{current_location:?}: ") } else { String::new() }, - comment(tcx, statement.source_info), + comment(self.tcx, statement.source_info), A = ALIGN, )?; } else { @@ -733,32 +736,32 @@ pub fn dump_mir_def_ids(tcx: TyCtxt<'_>, single: Option) -> Vec { } write_extra( - tcx, + self.tcx, w, &|visitor| visitor.visit_statement(statement, current_location), - options, + self.options, )?; - extra_data(PassWhere::AfterLocation(current_location), w)?; + (self.extra_data)(PassWhere::AfterLocation(current_location), w)?; current_location.statement_index += 1; } // Terminator at the bottom. - extra_data(PassWhere::BeforeLocation(current_location), w)?; + (self.extra_data)(PassWhere::BeforeLocation(current_location), w)?; if data.terminator.is_some() { let indented_terminator = format!("{0}{0}{1:?};", INDENT, data.terminator().kind); - if options.include_extra_comments { + if self.options.include_extra_comments { writeln!( w, "{:A$} // {}{}", indented_terminator, - if tcx.sess.verbose_internals() { + if self.tcx.sess.verbose_internals() { format!("{current_location:?}: ") } else { String::new() }, - comment(tcx, data.terminator().source_info), + comment(self.tcx, data.terminator().source_info), A = ALIGN, )?; } else { @@ -766,18 +769,19 @@ pub fn dump_mir_def_ids(tcx: TyCtxt<'_>, single: Option) -> Vec { } write_extra( - tcx, + self.tcx, w, &|visitor| visitor.visit_terminator(data.terminator(), current_location), - options, + self.options, )?; } - extra_data(PassWhere::AfterLocation(current_location), w)?; - extra_data(PassWhere::AfterTerminator(block), w)?; + (self.extra_data)(PassWhere::AfterLocation(current_location), w)?; + (self.extra_data)(PassWhere::AfterTerminator(block), w)?; writeln!(w, "{INDENT}}}") } +} impl Debug for Statement<'_> { fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result { diff --git a/compiler/rustc_mir_build/src/builder/mod.rs b/compiler/rustc_mir_build/src/builder/mod.rs index 4818f9bb0abf..cdb2c5561ce6 100644 --- a/compiler/rustc_mir_build/src/builder/mod.rs +++ b/compiler/rustc_mir_build/src/builder/mod.rs @@ -806,10 +806,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { ); body.coverage_info_hi = self.coverage_info.as_ref().map(|b| b.as_done()); - use rustc_middle::mir::pretty; - let options = pretty::PrettyPrintMirOptions::from_cli(self.tcx); - pretty::write_mir_fn(self.tcx, &body, &mut |_, _| Ok(()), &mut std::io::stdout(), options) - .unwrap(); + let writer = pretty::MirWriter::new(self.tcx); + writer.write_mir_fn(&body, &mut std::io::stdout()).unwrap(); } fn finish(self) -> Body<'tcx> { @@ -827,18 +825,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { ); body.coverage_info_hi = self.coverage_info.map(|b| b.into_done()); + let writer = pretty::MirWriter::new(self.tcx); for (index, block) in body.basic_blocks.iter().enumerate() { if block.terminator.is_none() { - use rustc_middle::mir::pretty; - let options = pretty::PrettyPrintMirOptions::from_cli(self.tcx); - pretty::write_mir_fn( - self.tcx, - &body, - &|_, _| Ok(()), - &mut std::io::stdout(), - options, - ) - .unwrap(); + writer.write_mir_fn(&body, &mut std::io::stdout()).unwrap(); span_bug!(self.fn_span, "no terminator on block {:?}", index); } } diff --git a/compiler/rustc_mir_dataflow/src/framework/graphviz.rs b/compiler/rustc_mir_dataflow/src/framework/graphviz.rs index 372a3f3a8b81..b85b82b8f6d9 100644 --- a/compiler/rustc_mir_dataflow/src/framework/graphviz.rs +++ b/compiler/rustc_mir_dataflow/src/framework/graphviz.rs @@ -10,8 +10,7 @@ use std::{io, ops, str}; use regex::Regex; use rustc_index::bit_set::DenseBitSet; use rustc_middle::mir::{ - self, BasicBlock, Body, Location, create_dump_file, dump_enabled, graphviz_safe_def_name, - traversal, + self, BasicBlock, Body, Location, MirDumper, graphviz_safe_def_name, traversal, }; use rustc_middle::ty::TyCtxt; use rustc_middle::ty::print::with_no_trimmed_paths; @@ -61,11 +60,13 @@ where fs::File::create_buffered(&path)? } - None if dump_enabled(tcx, A::NAME, def_id) => { - create_dump_file(tcx, "dot", false, A::NAME, &pass_name.unwrap_or("-----"), body)? + None => { + let Some(dumper) = MirDumper::new(tcx, A::NAME, body) else { + return Ok(()); + }; + let disambiguator = &pass_name.unwrap_or("-----"); + dumper.set_disambiguator(disambiguator).create_dump_file("dot", body)? } - - _ => return Ok(()), } }; let mut file = match file { diff --git a/compiler/rustc_mir_transform/src/coroutine.rs b/compiler/rustc_mir_transform/src/coroutine.rs index 592192944d2b..4603c695dedd 100644 --- a/compiler/rustc_mir_transform/src/coroutine.rs +++ b/compiler/rustc_mir_transform/src/coroutine.rs @@ -1294,7 +1294,9 @@ fn create_coroutine_resume_function<'tcx>( pm::run_passes_no_validate(tcx, body, &[&abort_unwinding_calls::AbortUnwindingCalls], None); - dump_mir(tcx, false, "coroutine_resume", &0, body, &|_, _| Ok(())); + if let Some(dumper) = MirDumper::new(tcx, "coroutine_resume", body) { + dumper.dump_mir(body); + } } /// An operation that can be performed on a coroutine. @@ -1446,7 +1448,9 @@ impl<'tcx> crate::MirPass<'tcx> for StateTransform { assert!(body.coroutine_drop().is_none() && body.coroutine_drop_async().is_none()); - dump_mir(tcx, false, "coroutine_before", &0, body, &|_, _| Ok(())); + if let Some(dumper) = MirDumper::new(tcx, "coroutine_before", body) { + dumper.dump_mir(body); + } // The first argument is the coroutine type passed by value let coroutine_ty = body.local_decls.raw[1].ty; @@ -1506,7 +1510,10 @@ impl<'tcx> crate::MirPass<'tcx> for StateTransform { ) { let context_mut_ref = transform_async_context(tcx, body); expand_async_drops(tcx, body, context_mut_ref, coroutine_kind, coroutine_ty); - dump_mir(tcx, false, "coroutine_async_drop_expand", &0, body, &|_, _| Ok(())); + + if let Some(dumper) = MirDumper::new(tcx, "coroutine_async_drop_expand", body) { + dumper.dump_mir(body); + } } else { cleanup_async_drops(body); } @@ -1605,14 +1612,18 @@ impl<'tcx> crate::MirPass<'tcx> for StateTransform { // This is expanded to a drop ladder in `elaborate_coroutine_drops`. let drop_clean = insert_clean_drop(tcx, body, has_async_drops); - dump_mir(tcx, false, "coroutine_pre-elab", &0, body, &|_, _| Ok(())); + if let Some(dumper) = MirDumper::new(tcx, "coroutine_pre-elab", body) { + dumper.dump_mir(body); + } // Expand `drop(coroutine_struct)` to a drop ladder which destroys upvars. // If any upvars are moved out of, drop elaboration will handle upvar destruction. // However we need to also elaborate the code generated by `insert_clean_drop`. elaborate_coroutine_drops(tcx, body); - dump_mir(tcx, false, "coroutine_post-transform", &0, body, &|_, _| Ok(())); + if let Some(dumper) = MirDumper::new(tcx, "coroutine_post-transform", body) { + dumper.dump_mir(body); + } let can_unwind = can_unwind(tcx, body); diff --git a/compiler/rustc_mir_transform/src/coroutine/by_move_body.rs b/compiler/rustc_mir_transform/src/coroutine/by_move_body.rs index 5ba6fea9fafb..951ff69c19e3 100644 --- a/compiler/rustc_mir_transform/src/coroutine/by_move_body.rs +++ b/compiler/rustc_mir_transform/src/coroutine/by_move_body.rs @@ -77,7 +77,7 @@ use rustc_hir::definitions::DisambiguatorState; use rustc_middle::bug; use rustc_middle::hir::place::{Projection, ProjectionKind}; use rustc_middle::mir::visit::MutVisitor; -use rustc_middle::mir::{self, dump_mir}; +use rustc_middle::mir::{self, MirDumper}; use rustc_middle::ty::{self, InstanceKind, Ty, TyCtxt, TypeVisitableExt}; pub(crate) fn coroutine_by_move_body_def_id<'tcx>( @@ -225,7 +225,10 @@ pub(crate) fn coroutine_by_move_body_def_id<'tcx>( ); by_move_body.source = mir::MirSource::from_instance(InstanceKind::Item(body_def.def_id().to_def_id())); - dump_mir(tcx, false, "built", &"after", &by_move_body, &|_, _| Ok(())); + + if let Some(dumper) = MirDumper::new(tcx, "built", &by_move_body) { + dumper.set_disambiguator(&"after").dump_mir(&by_move_body); + } // Feed HIR because we try to access this body's attrs in the inliner. body_def.feed_hir(); diff --git a/compiler/rustc_mir_transform/src/coroutine/drop.rs b/compiler/rustc_mir_transform/src/coroutine/drop.rs index 6dffbc866278..fd2d8b2b0563 100644 --- a/compiler/rustc_mir_transform/src/coroutine/drop.rs +++ b/compiler/rustc_mir_transform/src/coroutine/drop.rs @@ -605,7 +605,9 @@ pub(super) fn create_coroutine_drop_shim<'tcx>( // Temporary change MirSource to coroutine's instance so that dump_mir produces more sensible // filename. body.source.instance = coroutine_instance; - dump_mir(tcx, false, "coroutine_drop", &0, &body, &|_, _| Ok(())); + if let Some(dumper) = MirDumper::new(tcx, "coroutine_drop", &body) { + dumper.dump_mir(&body); + } body.source.instance = drop_instance; // Creating a coroutine drop shim happens on `Analysis(PostCleanup) -> Runtime(Initial)` @@ -696,7 +698,9 @@ pub(super) fn create_coroutine_drop_shim_async<'tcx>( None, ); - dump_mir(tcx, false, "coroutine_drop_async", &0, &body, &|_, _| Ok(())); + if let Some(dumper) = MirDumper::new(tcx, "coroutine_drop_async", &body) { + dumper.dump_mir(&body); + } body } @@ -741,7 +745,9 @@ pub(super) fn create_coroutine_drop_shim_proxy_async<'tcx>( }; body.basic_blocks_mut()[call_bb].terminator = Some(Terminator { source_info, kind }); - dump_mir(tcx, false, "coroutine_drop_proxy_async", &0, &body, &|_, _| Ok(())); + if let Some(dumper) = MirDumper::new(tcx, "coroutine_drop_proxy_async", &body) { + dumper.dump_mir(&body); + } body } diff --git a/compiler/rustc_mir_transform/src/dest_prop.rs b/compiler/rustc_mir_transform/src/dest_prop.rs index bb68d1a06595..cf7425251e8e 100644 --- a/compiler/rustc_mir_transform/src/dest_prop.rs +++ b/compiler/rustc_mir_transform/src/dest_prop.rs @@ -137,8 +137,8 @@ use rustc_index::interval::SparseIntervalMatrix; use rustc_middle::bug; use rustc_middle::mir::visit::{MutVisitor, PlaceContext, Visitor}; use rustc_middle::mir::{ - Body, HasLocalDecls, InlineAsmOperand, Local, LocalKind, Location, Operand, PassWhere, Place, - Rvalue, Statement, StatementKind, TerminatorKind, dump_mir, traversal, + Body, HasLocalDecls, InlineAsmOperand, Local, LocalKind, Location, MirDumper, Operand, + PassWhere, Place, Rvalue, Statement, StatementKind, TerminatorKind, traversal, }; use rustc_middle::ty::TyCtxt; use rustc_mir_dataflow::Analysis; @@ -810,11 +810,15 @@ fn dest_prop_mir_dump<'tcx>( let location = points.point_from_location(location); live.rows().filter(|&r| live.contains(r, location)).collect::>() }; - dump_mir(tcx, false, "DestinationPropagation-dataflow", &round, body, &|pass_where, w| { - if let PassWhere::BeforeLocation(loc) = pass_where { - writeln!(w, " // live: {:?}", locals_live_at(loc))?; - } - Ok(()) - }); + if let Some(dumper) = MirDumper::new(tcx, "DestinationPropagation-dataflow", body) { + let extra_data = &|pass_where, w: &mut dyn std::io::Write| { + if let PassWhere::BeforeLocation(loc) = pass_where { + writeln!(w, " // live: {:?}", locals_live_at(loc))?; + } + Ok(()) + }; + + dumper.set_disambiguator(&round).set_extra_data(extra_data).dump_mir(body) + } } diff --git a/compiler/rustc_mir_transform/src/lint_tail_expr_drop_order.rs b/compiler/rustc_mir_transform/src/lint_tail_expr_drop_order.rs index 0d0a71bc6c7e..794984d2f3ed 100644 --- a/compiler/rustc_mir_transform/src/lint_tail_expr_drop_order.rs +++ b/compiler/rustc_mir_transform/src/lint_tail_expr_drop_order.rs @@ -12,8 +12,8 @@ use rustc_index::{IndexSlice, IndexVec}; use rustc_macros::{LintDiagnostic, Subdiagnostic}; use rustc_middle::bug; use rustc_middle::mir::{ - self, BasicBlock, Body, ClearCrossCrate, Local, Location, Place, StatementKind, TerminatorKind, - dump_mir, + self, BasicBlock, Body, ClearCrossCrate, Local, Location, MirDumper, Place, StatementKind, + TerminatorKind, }; use rustc_middle::ty::significant_drop_order::{ extract_component_with_significant_dtor, ty_dtor_span, @@ -227,7 +227,10 @@ pub(crate) fn run_lint<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId, body: &Body< return; } - dump_mir(tcx, false, "lint_tail_expr_drop_order", &0 as _, body, &|_, _| Ok(())); + if let Some(dumper) = MirDumper::new(tcx, "lint_tail_expr_drop_order", body) { + dumper.dump_mir(body); + } + let locals_with_user_names = collect_user_names(body); let is_closure_like = tcx.is_closure_like(def_id.to_def_id()); diff --git a/compiler/rustc_mir_transform/src/pass_manager.rs b/compiler/rustc_mir_transform/src/pass_manager.rs index 374623d4ea54..ab09cdf787ee 100644 --- a/compiler/rustc_mir_transform/src/pass_manager.rs +++ b/compiler/rustc_mir_transform/src/pass_manager.rs @@ -2,7 +2,7 @@ use std::cell::RefCell; use std::collections::hash_map::Entry; use rustc_data_structures::fx::{FxHashMap, FxIndexSet}; -use rustc_middle::mir::{self, Body, MirPhase, RuntimePhase}; +use rustc_middle::mir::{Body, MirDumper, MirPhase, RuntimePhase}; use rustc_middle::ty::TyCtxt; use rustc_session::Session; use tracing::trace; @@ -275,7 +275,6 @@ fn run_passes_inner<'tcx>( } let prof_arg = tcx.sess.prof.enabled().then(|| format!("{:?}", body.source.def_id())); - let pass_num = true; if !body.should_skip() { let validate = validate_each & tcx.sess.opts.unstable_opts.validate_mir; @@ -288,10 +287,16 @@ fn run_passes_inner<'tcx>( continue; }; - let dump_enabled = pass.is_mir_dump_enabled(); + let dumper = if pass.is_mir_dump_enabled() + && let Some(dumper) = MirDumper::new(tcx, pass_name, body) + { + Some(dumper.set_show_pass_num().set_disambiguator(&"before")) + } else { + None + }; - if dump_enabled { - mir::dump_mir(tcx, pass_num, pass_name, &"before", body, &|_, _| Ok(())); + if let Some(dumper) = dumper.as_ref() { + dumper.dump_mir(body); } if let Some(prof_arg) = &prof_arg { @@ -303,9 +308,10 @@ fn run_passes_inner<'tcx>( pass.run_pass(tcx, body); } - if dump_enabled { - mir::dump_mir(tcx, pass_num, pass_name, &"after", body, &|_, _| Ok(())); + if let Some(dumper) = dumper { + dumper.set_disambiguator(&"after").dump_mir(body); } + if validate { validate_body(tcx, body, format!("after pass {pass_name}")); } @@ -348,5 +354,7 @@ pub(super) fn validate_body<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>, when pub(super) fn dump_mir_for_phase_change<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>) { assert_eq!(body.pass_count, 0); - mir::dump_mir(tcx, true, body.phase.name(), &"after", body, &|_, _| Ok(())) + if let Some(dumper) = MirDumper::new(tcx, body.phase.name(), body) { + dumper.set_show_pass_num().set_disambiguator(&"after").dump_mir(body) + } } diff --git a/compiler/rustc_mir_transform/src/shim.rs b/compiler/rustc_mir_transform/src/shim.rs index 39d4aaa98579..bca8ffb693b9 100644 --- a/compiler/rustc_mir_transform/src/shim.rs +++ b/compiler/rustc_mir_transform/src/shim.rs @@ -1242,14 +1242,12 @@ fn build_construct_coroutine_by_move_shim<'tcx>( let body = new_body(source, IndexVec::from_elem_n(start_block, 1), locals, sig.inputs().len(), span); - dump_mir( - tcx, - false, - if receiver_by_ref { "coroutine_closure_by_ref" } else { "coroutine_closure_by_move" }, - &0, - &body, - &|_, _| Ok(()), - ); + + let pass_name = + if receiver_by_ref { "coroutine_closure_by_ref" } else { "coroutine_closure_by_move" }; + if let Some(dumper) = MirDumper::new(tcx, pass_name, &body) { + dumper.dump_mir(&body); + } body } From ac89fcbc55181754dd58b90ed31175f72ed93589 Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Sun, 31 Aug 2025 18:31:59 -0700 Subject: [PATCH 33/48] rustdoc-search: skip loading unneeded fnData --- src/librustdoc/html/static/js/rustdoc.d.ts | 2 +- src/librustdoc/html/static/js/search.js | 23 +++++++++++----------- 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/src/librustdoc/html/static/js/rustdoc.d.ts b/src/librustdoc/html/static/js/rustdoc.d.ts index 74f646008ebd..938ccc7d2c32 100644 --- a/src/librustdoc/html/static/js/rustdoc.d.ts +++ b/src/librustdoc/html/static/js/rustdoc.d.ts @@ -289,7 +289,7 @@ declare namespace rustdoc { exactModulePath: string, entry: EntryData?, path: PathData?, - type: FunctionData?, + functionData: FunctionData?, deprecated: boolean, parent: { path: PathData, name: string}?, } diff --git a/src/librustdoc/html/static/js/search.js b/src/librustdoc/html/static/js/search.js index fa812a2b67b5..5da37c97c6a7 100644 --- a/src/librustdoc/html/static/js/search.js +++ b/src/librustdoc/html/static/js/search.js @@ -1802,14 +1802,15 @@ class DocSearch { /** * @param {number} id + * @param {boolean} loadFunctionData * @returns {Promise} */ - async getRow(id) { - const [name_, entry, path, type] = await Promise.all([ + async getRow(id, loadFunctionData) { + const [name_, entry, path, functionData] = await Promise.all([ this.getName(id), this.getEntryData(id), this.getPathData(id), - this.getFunctionData(id), + loadFunctionData ? this.getFunctionData(id) : null, ]); if (!entry && !path) { return null; @@ -1853,7 +1854,7 @@ class DocSearch { `${exactModulePathData.exactModulePath}::${exactModuleName}`), entry, path, - type, + functionData, deprecated: entry ? entry.deprecated : false, parent: parentName !== null && parentPath !== null ? { name: parentName, path: parentPath } : @@ -2563,11 +2564,11 @@ class DocSearch { name: item.parent.name, ty: item.parent.path.ty, } : undefined, - type: item.type && item.type.functionSignature ? - item.type.functionSignature : + type: item.functionData && item.functionData.functionSignature ? + item.functionData.functionSignature : undefined, - paramNames: item.type && item.type.paramNames ? - item.type.paramNames : + paramNames: item.functionData && item.functionData.paramNames ? + item.functionData.paramNames : undefined, dist: result.dist, path_dist: result.path_dist, @@ -2642,7 +2643,7 @@ class DocSearch { /** * @type {rustdoc.Row?} */ - const item = await this.getRow(result.id); + const item = await this.getRow(result.id, typeInfo !== null); if (!item) { continue; } @@ -3749,7 +3750,7 @@ class DocSearch { is_alias: true, elems: [], // only used in type-based queries returned: [], // only used in type-based queries - original: await this.getRow(alias), + original: await this.getRow(alias, false), }; }; /** @@ -3804,7 +3805,7 @@ class DocSearch { * @returns {Promise} */ const handleNameSearch = async id => { - const row = await this.getRow(id); + const row = await this.getRow(id, false); if (!row || !row.entry) { return null; } From e7519c63b0ace45a374290c451db87a5e5f6578d Mon Sep 17 00:00:00 2001 From: Zalathar Date: Sun, 31 Aug 2025 14:35:02 +1000 Subject: [PATCH 34/48] Capture panic messages via a custom panic hook --- src/tools/compiletest/src/executor.rs | 13 +++ src/tools/compiletest/src/lib.rs | 3 + src/tools/compiletest/src/panic_hook.rs | 136 ++++++++++++++++++++++++ 3 files changed, 152 insertions(+) create mode 100644 src/tools/compiletest/src/panic_hook.rs diff --git a/src/tools/compiletest/src/executor.rs b/src/tools/compiletest/src/executor.rs index fdd7155c21ff..5519ef1af1fa 100644 --- a/src/tools/compiletest/src/executor.rs +++ b/src/tools/compiletest/src/executor.rs @@ -13,6 +13,7 @@ use std::sync::{Arc, Mutex, mpsc}; use std::{env, hint, io, mem, panic, thread}; use crate::common::{Config, TestPaths}; +use crate::panic_hook; mod deadline; mod json; @@ -120,6 +121,11 @@ fn run_test_inner( completion_sender: mpsc::Sender, ) { let is_capture = !runnable_test.config.nocapture; + + // Install a panic-capture buffer for use by the custom panic hook. + if is_capture { + panic_hook::set_capture_buf(Default::default()); + } let capture_buf = is_capture.then(|| Arc::new(Mutex::new(vec![]))); if let Some(capture_buf) = &capture_buf { @@ -128,6 +134,13 @@ fn run_test_inner( let panic_payload = panic::catch_unwind(move || runnable_test.run()).err(); + if let Some(panic_buf) = panic_hook::take_capture_buf() { + let panic_buf = panic_buf.lock().unwrap_or_else(|e| e.into_inner()); + // For now, forward any captured panic message to (captured) stderr. + // FIXME(Zalathar): Once we have our own output-capture buffer for + // non-panic output, append the panic message to that buffer instead. + eprint!("{panic_buf}"); + } if is_capture { io::set_output_capture(None); } diff --git a/src/tools/compiletest/src/lib.rs b/src/tools/compiletest/src/lib.rs index 8737fec80bb3..fa84691a46f4 100644 --- a/src/tools/compiletest/src/lib.rs +++ b/src/tools/compiletest/src/lib.rs @@ -15,6 +15,7 @@ pub mod directives; pub mod errors; mod executor; mod json; +mod panic_hook; mod raise_fd_limit; mod read2; pub mod runtest; @@ -493,6 +494,8 @@ pub fn opt_str2(maybestr: Option) -> String { pub fn run_tests(config: Arc) { debug!(?config, "run_tests"); + panic_hook::install_panic_hook(); + // If we want to collect rustfix coverage information, // we first make sure that the coverage file does not exist. // It will be created later on. diff --git a/src/tools/compiletest/src/panic_hook.rs b/src/tools/compiletest/src/panic_hook.rs new file mode 100644 index 000000000000..1661ca6dabe8 --- /dev/null +++ b/src/tools/compiletest/src/panic_hook.rs @@ -0,0 +1,136 @@ +use std::backtrace::{Backtrace, BacktraceStatus}; +use std::cell::Cell; +use std::fmt::{Display, Write}; +use std::panic::PanicHookInfo; +use std::sync::{Arc, LazyLock, Mutex}; +use std::{env, mem, panic, thread}; + +type PanicHook = Box) + Sync + Send + 'static>; +type CaptureBuf = Arc>; + +thread_local!( + static CAPTURE_BUF: Cell> = const { Cell::new(None) }; +); + +/// Installs a custom panic hook that will divert panic output to a thread-local +/// capture buffer, but only for threads that have a capture buffer set. +/// +/// Otherwise, the custom hook delegates to a copy of the default panic hook. +pub(crate) fn install_panic_hook() { + let default_hook = panic::take_hook(); + panic::set_hook(Box::new(move |info| custom_panic_hook(&default_hook, info))); +} + +pub(crate) fn set_capture_buf(buf: CaptureBuf) { + CAPTURE_BUF.set(Some(buf)); +} + +pub(crate) fn take_capture_buf() -> Option { + CAPTURE_BUF.take() +} + +fn custom_panic_hook(default_hook: &PanicHook, info: &panic::PanicHookInfo<'_>) { + // Temporarily taking the capture buffer means that if a panic occurs in + // the subsequent code, that panic will fall back to the default hook. + let Some(buf) = take_capture_buf() else { + // There was no capture buffer, so delegate to the default hook. + default_hook(info); + return; + }; + + let mut out = buf.lock().unwrap_or_else(|e| e.into_inner()); + + let thread = thread::current().name().unwrap_or("(test runner)").to_owned(); + let location = get_location(info); + let payload = payload_as_str(info).unwrap_or("Box"); + let backtrace = Backtrace::capture(); + + writeln!(out, "\nthread '{thread}' panicked at {location}:\n{payload}").unwrap(); + match backtrace.status() { + BacktraceStatus::Captured => { + let bt = trim_backtrace(backtrace.to_string()); + write!(out, "stack backtrace:\n{bt}",).unwrap(); + } + BacktraceStatus::Disabled => { + writeln!( + out, + "note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace", + ) + .unwrap(); + } + _ => {} + } + + drop(out); + set_capture_buf(buf); +} + +fn get_location<'a>(info: &'a PanicHookInfo<'_>) -> &'a dyn Display { + match info.location() { + Some(location) => location, + None => &"(unknown)", + } +} + +/// FIXME(Zalathar): Replace with `PanicHookInfo::payload_as_str` when that's +/// stable in beta. +fn payload_as_str<'a>(info: &'a PanicHookInfo<'_>) -> Option<&'a str> { + let payload = info.payload(); + if let Some(s) = payload.downcast_ref::<&str>() { + Some(s) + } else if let Some(s) = payload.downcast_ref::() { + Some(s) + } else { + None + } +} + +fn rust_backtrace_full() -> bool { + static RUST_BACKTRACE_FULL: LazyLock = + LazyLock::new(|| matches!(env::var("RUST_BACKTRACE").as_deref(), Ok("full"))); + *RUST_BACKTRACE_FULL +} + +/// On stable, short backtraces are only available to the default panic hook, +/// so if we want something similar we have to resort to string processing. +fn trim_backtrace(full_backtrace: String) -> String { + if rust_backtrace_full() { + return full_backtrace; + } + + let mut buf = String::with_capacity(full_backtrace.len()); + // Don't print any frames until after the first `__rust_end_short_backtrace`. + let mut on = false; + // After the short-backtrace state is toggled, skip its associated "at" if present. + let mut skip_next_at = false; + + let mut lines = full_backtrace.lines(); + while let Some(line) = lines.next() { + if mem::replace(&mut skip_next_at, false) && line.trim_start().starts_with("at ") { + continue; + } + + if line.contains("__rust_end_short_backtrace") { + on = true; + skip_next_at = true; + continue; + } + if line.contains("__rust_begin_short_backtrace") { + on = false; + skip_next_at = true; + continue; + } + + if on { + writeln!(buf, "{line}").unwrap(); + } + } + + writeln!( + buf, + "note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace." + ) + .unwrap(); + + buf +} From f6e7c81061c24a2210149ff94670d8672bd0224a Mon Sep 17 00:00:00 2001 From: jullang Date: Sun, 31 Aug 2025 19:27:03 +0000 Subject: [PATCH 35/48] Add compiler error when trying to use concat metavar expr in repetitions Replace unimplemented()! with a more helpful compiler error. --- compiler/rustc_expand/src/mbe/transcribe.rs | 7 ++++++- tests/crashes/140479.rs | 5 ----- .../in-repetition.rs | 21 +++++++++++++++++++ .../in-repetition.stderr | 8 +++++++ 4 files changed, 35 insertions(+), 6 deletions(-) delete mode 100644 tests/crashes/140479.rs create mode 100644 tests/ui/macros/macro-metavar-expr-concat/in-repetition.rs create mode 100644 tests/ui/macros/macro-metavar-expr-concat/in-repetition.stderr diff --git a/compiler/rustc_expand/src/mbe/transcribe.rs b/compiler/rustc_expand/src/mbe/transcribe.rs index 174844d6ad63..e4e4866b64cd 100644 --- a/compiler/rustc_expand/src/mbe/transcribe.rs +++ b/compiler/rustc_expand/src/mbe/transcribe.rs @@ -556,7 +556,12 @@ fn metavar_expr_concat<'tx>( }; match &named_matches[*curr_idx] { // FIXME(c410-f3r) Nested repetitions are unimplemented - MatchedSeq(_) => unimplemented!(), + MatchedSeq(_) => { + return Err(dcx.struct_span_err( + ident.span, + "nested repetitions with `${concat(...)}` metavariable expressions are not yet supported", + )); + } MatchedSingle(pnr) => extract_symbol_from_pnr(dcx, pnr, ident.span)?, } } diff --git a/tests/crashes/140479.rs b/tests/crashes/140479.rs deleted file mode 100644 index ed3ca887546f..000000000000 --- a/tests/crashes/140479.rs +++ /dev/null @@ -1,5 +0,0 @@ -//@ known-bug: #140479 -macro_rules! a { ( $( { $ [ $b:c ] } )) => ( $(${ concat(d, $b)} ))} -fn e() { - a!({}) -} diff --git a/tests/ui/macros/macro-metavar-expr-concat/in-repetition.rs b/tests/ui/macros/macro-metavar-expr-concat/in-repetition.rs new file mode 100644 index 000000000000..d2bd31b06d60 --- /dev/null +++ b/tests/ui/macros/macro-metavar-expr-concat/in-repetition.rs @@ -0,0 +1,21 @@ +// issue: +// Ensure a proper compiler error, instead of an ICE occurs. +// FIXME(macro_metavar_expr_concat): this error message could be improved +#![feature(macro_metavar_expr_concat)] + +macro_rules! InRepetition { + ( + $( + $($arg:ident),+ + )+ + ) => { + $( + $( + ${concat(_, $arg)} //~ ERROR nested repetitions with `${concat(...)}` metavariable expressions are not yet supported + )* + )* + }; +} +InRepetition!(other); + +fn main() {} diff --git a/tests/ui/macros/macro-metavar-expr-concat/in-repetition.stderr b/tests/ui/macros/macro-metavar-expr-concat/in-repetition.stderr new file mode 100644 index 000000000000..ec39ca799e19 --- /dev/null +++ b/tests/ui/macros/macro-metavar-expr-concat/in-repetition.stderr @@ -0,0 +1,8 @@ +error: nested repetitions with `${concat(...)}` metavariable expressions are not yet supported + --> $DIR/in-repetition.rs:14:30 + | +LL | ${concat(_, $arg)} + | ^^^ + +error: aborting due to 1 previous error + From 6be234074e454756d13cd3f969f427f94a5f4950 Mon Sep 17 00:00:00 2001 From: Nathaniel McCallum Date: Mon, 1 Sep 2025 02:40:52 -0400 Subject: [PATCH 36/48] constify impl Try for ControlFlow --- library/core/src/ops/control_flow.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/library/core/src/ops/control_flow.rs b/library/core/src/ops/control_flow.rs index 7489a8bb6e74..73b74d53323f 100644 --- a/library/core/src/ops/control_flow.rs +++ b/library/core/src/ops/control_flow.rs @@ -99,7 +99,8 @@ pub enum ControlFlow { } #[unstable(feature = "try_trait_v2", issue = "84277", old_name = "try_trait")] -impl ops::Try for ControlFlow { +#[rustc_const_unstable(feature = "const_try", issue = "74935")] +impl const ops::Try for ControlFlow { type Output = C; type Residual = ControlFlow; @@ -118,9 +119,10 @@ impl ops::Try for ControlFlow { } #[unstable(feature = "try_trait_v2", issue = "84277", old_name = "try_trait")] +#[rustc_const_unstable(feature = "const_try", issue = "74935")] // Note: manually specifying the residual type instead of using the default to work around // https://github.com/rust-lang/rust/issues/99940 -impl ops::FromResidual> for ControlFlow { +impl const ops::FromResidual> for ControlFlow { #[inline] fn from_residual(residual: ControlFlow) -> Self { match residual { From 8dfd6b8ec208f4f31dd0e41c32e9239bf262068c Mon Sep 17 00:00:00 2001 From: Nathaniel McCallum Date: Mon, 1 Sep 2025 08:55:25 -0400 Subject: [PATCH 37/48] fix a constness ordering bug in rustfmt Normally, changes to rustfmt go into the separate repo. But, in this case, the bug is introduced in a local change and therefore isn't present in the rustfmt repo. --- src/tools/rustfmt/src/items.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/rustfmt/src/items.rs b/src/tools/rustfmt/src/items.rs index 6555679c3944..75e468b35256 100644 --- a/src/tools/rustfmt/src/items.rs +++ b/src/tools/rustfmt/src/items.rs @@ -1175,8 +1175,8 @@ pub(crate) fn format_trait( let mut result = String::with_capacity(128); let header = format!( "{}{}{}{}trait ", - format_constness(constness), format_visibility(context, &item.vis), + format_constness(constness), format_safety(safety), format_auto(is_auto), ); From d8df6312d5b3290c6976e5b55f5ae8344cab1bb4 Mon Sep 17 00:00:00 2001 From: Moritz Hedtke Date: Mon, 1 Sep 2025 17:26:20 +0200 Subject: [PATCH 38/48] Make `Parser::parse_for_head` public for rustfmt usage --- compiler/rustc_parse/src/parser/expr.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index 7de4f6efd0b0..9b09cbba7afc 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -2910,7 +2910,8 @@ impl<'a> Parser<'a> { } } - fn parse_for_head(&mut self) -> PResult<'a, (Box, Box)> { + // Public to use it for custom `for` expressions in rustfmt forks like https://github.com/tucant/rustfmt + pub fn parse_for_head(&mut self) -> PResult<'a, (Box, Box)> { let begin_paren = if self.token == token::OpenParen { // Record whether we are about to parse `for (`. // This is used below for recovery in case of `for ( $stuff ) $block` From 6fc0cf428885a4939fc3b6f60f638ce09e48339f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Le=C3=B3n=20Orell=20Valerian=20Liehr?= Date: Mon, 1 Sep 2025 21:39:01 +0200 Subject: [PATCH 39/48] Remove dead code stemming from an old effects desugaring --- compiler/rustc_ast_lowering/src/lib.rs | 2 +- compiler/rustc_hir/src/hir.rs | 1 - compiler/rustc_hir/src/intravisit.rs | 2 +- compiler/rustc_hir_analysis/src/collect/generics_of.rs | 6 +++--- .../rustc_hir_analysis/src/hir_ty_lowering/generics.rs | 9 +-------- compiler/rustc_hir_pretty/src/lib.rs | 2 +- compiler/rustc_middle/src/ty/generics.rs | 2 +- compiler/rustc_public/src/unstable/convert/stable/ty.rs | 8 ++++---- src/librustdoc/clean/mod.rs | 6 ++---- src/librustdoc/clean/types.rs | 2 +- src/librustdoc/json/conversions.rs | 2 +- 11 files changed, 16 insertions(+), 26 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 70595391b85b..a6a4cc842f0e 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -2028,7 +2028,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { ( hir::ParamName::Plain(self.lower_ident(param.ident)), - hir::GenericParamKind::Const { ty, default, synthetic: false }, + hir::GenericParamKind::Const { ty, default }, ) } } diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index e397c286de28..cdade500a268 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -784,7 +784,6 @@ pub enum GenericParamKind<'hir> { ty: &'hir Ty<'hir>, /// Optional default value for the const generic param default: Option<&'hir ConstArg<'hir>>, - synthetic: bool, }, } diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs index 9b2f8ae75fa7..25a7ae239f31 100644 --- a/compiler/rustc_hir/src/intravisit.rs +++ b/compiler/rustc_hir/src/intravisit.rs @@ -1085,7 +1085,7 @@ pub fn walk_generic_param<'v, V: Visitor<'v>>( GenericParamKind::Type { ref default, .. } => { visit_opt!(visitor, visit_ty_unambig, default) } - GenericParamKind::Const { ref ty, ref default, synthetic: _ } => { + GenericParamKind::Const { ref ty, ref default } => { try_visit!(visitor.visit_ty_unambig(ty)); if let Some(default) = default { try_visit!(visitor.visit_const_param_default(*hir_id, default)); diff --git a/compiler/rustc_hir_analysis/src/collect/generics_of.rs b/compiler/rustc_hir_analysis/src/collect/generics_of.rs index ce0e51f106f5..333cea23c414 100644 --- a/compiler/rustc_hir_analysis/src/collect/generics_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/generics_of.rs @@ -305,7 +305,7 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics { ty::GenericParamDefKind::Type { has_default: default.is_some(), synthetic } } - GenericParamKind::Const { ty: _, default, synthetic } => { + GenericParamKind::Const { ty: _, default } => { if default.is_some() { match param_default_policy.expect("no policy for generic param default") { ParamDefaultPolicy::Allowed => {} @@ -316,7 +316,7 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics { } } - ty::GenericParamDefKind::Const { has_default: default.is_some(), synthetic } + ty::GenericParamDefKind::Const { has_default: default.is_some() } } }; Some(ty::GenericParamDef { @@ -523,7 +523,7 @@ impl<'v> Visitor<'v> for AnonConstInParamTyDetector { type Result = ControlFlow<()>; fn visit_generic_param(&mut self, p: &'v hir::GenericParam<'v>) -> Self::Result { - if let GenericParamKind::Const { ty, default: _, synthetic: _ } = p.kind { + if let GenericParamKind::Const { ty, default: _ } = p.kind { let prev = self.in_param_ty; self.in_param_ty = true; let res = self.visit_ty_unambig(ty); diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/generics.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/generics.rs index fc519c194bb9..f5a64ede398e 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/generics.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/generics.rs @@ -419,14 +419,7 @@ pub(crate) fn check_generic_arg_count( .filter(|param| matches!(param.kind, ty::GenericParamDefKind::Type { synthetic: true, .. })) .count(); let named_type_param_count = param_counts.types - has_self as usize - synth_type_param_count; - let synth_const_param_count = gen_params - .own_params - .iter() - .filter(|param| { - matches!(param.kind, ty::GenericParamDefKind::Const { synthetic: true, .. }) - }) - .count(); - let named_const_param_count = param_counts.consts - synth_const_param_count; + let named_const_param_count = param_counts.consts; let infer_lifetimes = (gen_pos != GenericArgPosition::Type || seg.infer_args) && !gen_args.has_lifetime_params(); diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index be5859b57c5e..a89f059bb351 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -2379,7 +2379,7 @@ impl<'a> State<'a> { self.print_type(default); } } - GenericParamKind::Const { ty, ref default, synthetic: _ } => { + GenericParamKind::Const { ty, ref default } => { self.word_space(":"); self.print_type(ty); if let Some(default) = default { diff --git a/compiler/rustc_middle/src/ty/generics.rs b/compiler/rustc_middle/src/ty/generics.rs index c7b3b5415492..b6b10e245857 100644 --- a/compiler/rustc_middle/src/ty/generics.rs +++ b/compiler/rustc_middle/src/ty/generics.rs @@ -13,7 +13,7 @@ use crate::ty::{EarlyBinder, GenericArgsRef}; pub enum GenericParamDefKind { Lifetime, Type { has_default: bool, synthetic: bool }, - Const { has_default: bool, synthetic: bool }, + Const { has_default: bool }, } impl GenericParamDefKind { diff --git a/compiler/rustc_public/src/unstable/convert/stable/ty.rs b/compiler/rustc_public/src/unstable/convert/stable/ty.rs index 5a661072bc7e..207038db40d6 100644 --- a/compiler/rustc_public/src/unstable/convert/stable/ty.rs +++ b/compiler/rustc_public/src/unstable/convert/stable/ty.rs @@ -656,13 +656,13 @@ impl<'tcx> Stable<'tcx> for rustc_middle::ty::GenericParamDefKind { fn stable(&self, _: &mut Tables<'_, BridgeTys>, _: &CompilerCtxt<'_, BridgeTys>) -> Self::T { use crate::ty::GenericParamDefKind; - match self { + match *self { ty::GenericParamDefKind::Lifetime => GenericParamDefKind::Lifetime, ty::GenericParamDefKind::Type { has_default, synthetic } => { - GenericParamDefKind::Type { has_default: *has_default, synthetic: *synthetic } + GenericParamDefKind::Type { has_default, synthetic } } - ty::GenericParamDefKind::Const { has_default, synthetic: _ } => { - GenericParamDefKind::Const { has_default: *has_default } + ty::GenericParamDefKind::Const { has_default } => { + GenericParamDefKind::Const { has_default } } } } diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 4ff94cc6f3b6..93932936a2e0 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -557,7 +557,7 @@ fn clean_generic_param_def( }, ) } - ty::GenericParamDefKind::Const { has_default, synthetic } => ( + ty::GenericParamDefKind::Const { has_default } => ( def.name, GenericParamDefKind::Const { ty: Box::new(clean_middle_ty( @@ -580,7 +580,6 @@ fn clean_generic_param_def( } else { None }, - synthetic, }, ), }; @@ -636,14 +635,13 @@ fn clean_generic_param<'tcx>( }, ) } - hir::GenericParamKind::Const { ty, default, synthetic } => ( + hir::GenericParamKind::Const { ty, default } => ( param.name.ident().name, GenericParamDefKind::Const { ty: Box::new(clean_ty(ty, cx)), default: default.map(|ct| { Box::new(lower_const_arg_for_rustdoc(cx.tcx, ct, FeedConstTy::No).to_string()) }), - synthetic, }, ), }; diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index fcff15650ce2..dcd67cb7ebc7 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -1396,7 +1396,7 @@ pub(crate) enum GenericParamDefKind { Lifetime { outlives: ThinVec }, Type { bounds: ThinVec, default: Option>, synthetic: bool }, // Option> makes this type smaller than `Option` would. - Const { ty: Box, default: Option>, synthetic: bool }, + Const { ty: Box, default: Option> }, } impl GenericParamDefKind { diff --git a/src/librustdoc/json/conversions.rs b/src/librustdoc/json/conversions.rs index f0520716228a..6fe94f9d291b 100644 --- a/src/librustdoc/json/conversions.rs +++ b/src/librustdoc/json/conversions.rs @@ -466,7 +466,7 @@ impl FromClean for GenericParamDefKind { default: default.into_json(renderer), is_synthetic: *synthetic, }, - Const { ty, default, synthetic: _ } => GenericParamDefKind::Const { + Const { ty, default } => GenericParamDefKind::Const { type_: ty.into_json(renderer), default: default.as_ref().map(|x| x.as_ref().clone()), }, From f67e29e5a82d5272a03028c5e4a91fbe2bbab81f Mon Sep 17 00:00:00 2001 From: Janis Date: Mon, 1 Sep 2025 14:09:14 +0200 Subject: [PATCH 40/48] squash fix `render_call_locations` panic when default span points at file outside of local_sources add test against crashing with --html-after-content file correctly add --html-after-content to env not args formatting fix for rustdoc-call-locations-after-content/rmake.rs Use local crate source file as default span in `render_call_locations` - avoids unwrapping the first file added to the source map as a local file in `href_from_span` move test to tests/rustdoc-gui, rename to scrape_examples_ice test link is correct use rustdocflags, rename path in example, track lock file factor out duplicate function calls use compile-flags to make sure the after.html file is actually included in the rustdoc call fix goml go-to path increment assert-count in sidebar-source-code.goml adjust crate-search width in search-result-display.goml renamed Bar in scrape_examples_ice test make crate name shorter .. --- src/librustdoc/html/render/mod.rs | 52 +++++++++++++------ .../scrape-examples-ice-links.goml | 6 +++ tests/rustdoc-gui/sidebar-source-code.goml | 2 +- .../src/scrape_examples_ice/Cargo.lock | 7 +++ .../src/scrape_examples_ice/Cargo.toml | 9 ++++ .../src/scrape_examples_ice/empty.html | 1 + .../src/scrape_examples_ice/examples/bar.rs | 3 ++ .../src/scrape_examples_ice/src/lib.rs | 9 ++++ 8 files changed, 73 insertions(+), 16 deletions(-) create mode 100644 tests/rustdoc-gui/scrape-examples-ice-links.goml create mode 100644 tests/rustdoc-gui/src/scrape_examples_ice/Cargo.lock create mode 100644 tests/rustdoc-gui/src/scrape_examples_ice/Cargo.toml create mode 100644 tests/rustdoc-gui/src/scrape_examples_ice/empty.html create mode 100644 tests/rustdoc-gui/src/scrape_examples_ice/examples/bar.rs create mode 100644 tests/rustdoc-gui/src/scrape_examples_ice/src/lib.rs diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index 6db90c9bf2a4..b4ef47d1e269 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -2812,24 +2812,46 @@ fn render_call_locations( let needs_expansion = line_max - line_min > NUM_VISIBLE_LINES; let locations_encoded = serde_json::to_string(&line_ranges).unwrap(); - // Look for the example file in the source map if it exists, otherwise return a dummy span - let file_span = (|| { - let source_map = tcx.sess.source_map(); - let crate_src = tcx.sess.local_crate_source_file()?.into_local_path()?; + let source_map = tcx.sess.source_map(); + let files = source_map.files(); + let local = tcx.sess.local_crate_source_file().unwrap(); + + let get_file_start_pos = || { + let crate_src = local.clone().into_local_path()?; let abs_crate_src = crate_src.canonicalize().ok()?; let crate_root = abs_crate_src.parent()?.parent()?; let rel_path = path.strip_prefix(crate_root).ok()?; - let files = source_map.files(); - let file = files.iter().find(|file| match &file.name { - FileName::Real(RealFileName::LocalPath(other_path)) => rel_path == other_path, - _ => false, - })?; - Some(rustc_span::Span::with_root_ctxt( - file.start_pos + BytePos(byte_min), - file.start_pos + BytePos(byte_max), - )) - })() - .unwrap_or(DUMMY_SP); + files + .iter() + .find(|file| match &file.name { + FileName::Real(RealFileName::LocalPath(other_path)) => rel_path == other_path, + _ => false, + }) + .map(|file| file.start_pos) + }; + + // Look for the example file in the source map if it exists, otherwise + // return a span to the local crate's source file + let Some(file_span) = get_file_start_pos() + .or_else(|| { + files + .iter() + .find(|file| match &file.name { + FileName::Real(file_name) => file_name == &local, + _ => false, + }) + .map(|file| file.start_pos) + }) + .map(|start_pos| { + rustc_span::Span::with_root_ctxt( + start_pos + BytePos(byte_min), + start_pos + BytePos(byte_max), + ) + }) + else { + // if the fallback span can't be built, don't render the code for this example + return false; + }; let mut decoration_info = FxIndexMap::default(); decoration_info.insert("highlight focus", vec![byte_ranges.remove(0)]); diff --git a/tests/rustdoc-gui/scrape-examples-ice-links.goml b/tests/rustdoc-gui/scrape-examples-ice-links.goml new file mode 100644 index 000000000000..1db220e1a322 --- /dev/null +++ b/tests/rustdoc-gui/scrape-examples-ice-links.goml @@ -0,0 +1,6 @@ +// Check that the line number column has the correct layout. +go-to: "file://" + |DOC_PATH| + "/scrape_ice/struct.ObscurelyNamedType1.html" +wait-for: ".scraped-example-title" +assert-attribute: (".scraped-example-title a", {"href": "../src/bar/bar.rs.html#2"}) +click: ".scraped-example-title a" +wait-for-property: ("h1", {"innerText": "bar/\nbar.rs"}) diff --git a/tests/rustdoc-gui/sidebar-source-code.goml b/tests/rustdoc-gui/sidebar-source-code.goml index 3f6914a89d63..a3c19d8c6d01 100644 --- a/tests/rustdoc-gui/sidebar-source-code.goml +++ b/tests/rustdoc-gui/sidebar-source-code.goml @@ -71,7 +71,7 @@ assert: "//*[@class='dir-entry' and @open]/*[normalize-space()='sub_mod']" // Only "another_folder" should be "open" in "lib2". assert: "//*[@class='dir-entry' and not(@open)]/*[normalize-space()='another_mod']" // All other trees should be collapsed. -assert-count: ("//*[@id='src-sidebar']/details[not(normalize-space()='lib2') and not(@open)]", 12) +assert-count: ("//*[@id='src-sidebar']/details[not(normalize-space()='lib2') and not(@open)]", 13) // We now switch to mobile mode. set-window-size: (600, 600) diff --git a/tests/rustdoc-gui/src/scrape_examples_ice/Cargo.lock b/tests/rustdoc-gui/src/scrape_examples_ice/Cargo.lock new file mode 100644 index 000000000000..03410a0da12c --- /dev/null +++ b/tests/rustdoc-gui/src/scrape_examples_ice/Cargo.lock @@ -0,0 +1,7 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "scrape_ice" +version = "0.1.0" diff --git a/tests/rustdoc-gui/src/scrape_examples_ice/Cargo.toml b/tests/rustdoc-gui/src/scrape_examples_ice/Cargo.toml new file mode 100644 index 000000000000..076ff38ad231 --- /dev/null +++ b/tests/rustdoc-gui/src/scrape_examples_ice/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "scrape_ice" +version = "0.1.0" +edition = "2024" + +[[example]] +name = "bar" +path = "examples/bar.rs" +doc-scrape-examples = true diff --git a/tests/rustdoc-gui/src/scrape_examples_ice/empty.html b/tests/rustdoc-gui/src/scrape_examples_ice/empty.html new file mode 100644 index 000000000000..8b137891791f --- /dev/null +++ b/tests/rustdoc-gui/src/scrape_examples_ice/empty.html @@ -0,0 +1 @@ + diff --git a/tests/rustdoc-gui/src/scrape_examples_ice/examples/bar.rs b/tests/rustdoc-gui/src/scrape_examples_ice/examples/bar.rs new file mode 100644 index 000000000000..9f05f9e46e87 --- /dev/null +++ b/tests/rustdoc-gui/src/scrape_examples_ice/examples/bar.rs @@ -0,0 +1,3 @@ +fn main() { + let mut bar = scrape_ice::ObscurelyNamedType1::new(); +} diff --git a/tests/rustdoc-gui/src/scrape_examples_ice/src/lib.rs b/tests/rustdoc-gui/src/scrape_examples_ice/src/lib.rs new file mode 100644 index 000000000000..b854c7722c9a --- /dev/null +++ b/tests/rustdoc-gui/src/scrape_examples_ice/src/lib.rs @@ -0,0 +1,9 @@ +//@ run-flags:-Zrustdoc-scrape-examples +//@ compile-flags: --html-after-content empty.html +pub struct ObscurelyNamedType1; + +impl ObscurelyNamedType1 { + pub fn new() -> Self { + ObscurelyNamedType1 + } +} From f6d55aea2c2cc014f8bb105325ef4c21d2c3d185 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 28 Aug 2025 12:03:19 +0200 Subject: [PATCH 41/48] stabilize extended_varargs_abi_support --- compiler/rustc_abi/src/extern_abi.rs | 25 +++++++- compiler/rustc_abi/src/lib.rs | 2 + compiler/rustc_ast_passes/messages.ftl | 2 +- compiler/rustc_feature/src/accepted.rs | 3 + compiler/rustc_feature/src/unstable.rs | 3 - .../rustc_hir_analysis/src/check/check.rs | 2 +- compiler/rustc_hir_analysis/src/check/mod.rs | 2 +- .../src/hir_ty_lowering/mod.rs | 4 +- compiler/rustc_hir_analysis/src/lib.rs | 59 ++++++++----------- library/std/src/lib.rs | 1 - .../extended-varargs-abi-support.md | 10 ---- tests/codegen-llvm/cffi/c-variadic-ffi.rs | 2 +- tests/ui/abi/unsupported-varargs-fnptr.rs | 2 - tests/ui/abi/unsupported-varargs-fnptr.stderr | 2 +- ...ature-gate-extended_varargs_abi_support.rs | 16 ----- ...e-gate-extended_varargs_abi_support.stderr | 33 ----------- tests/ui/c-variadic/issue-86053-1.rs | 2 +- tests/ui/c-variadic/issue-86053-1.stderr | 2 +- .../same-program-multiple-abis-arm.rs | 1 - .../same-program-multiple-abis-x86_64.rs | 1 - .../cmse-nonsecure-entry/generics.rs | 2 +- .../cmse-nonsecure-entry/generics.stderr | 2 +- .../feature-gates/feature-gate-c_variadic.rs | 6 ++ .../feature-gate-c_variadic.stderr | 18 +++++- .../issue-83499-input-output-iteration-ice.rs | 2 +- ...ue-83499-input-output-iteration-ice.stderr | 2 +- .../variadic-ffi-semantic-restrictions.rs | 42 ++++++------- .../variadic-ffi-semantic-restrictions.stderr | 42 ++++++------- 28 files changed, 128 insertions(+), 162 deletions(-) delete mode 100644 src/doc/unstable-book/src/language-features/extended-varargs-abi-support.md delete mode 100644 tests/ui/c-variadic/feature-gate-extended_varargs_abi_support.rs delete mode 100644 tests/ui/c-variadic/feature-gate-extended_varargs_abi_support.stderr diff --git a/compiler/rustc_abi/src/extern_abi.rs b/compiler/rustc_abi/src/extern_abi.rs index 41d744e1946a..e3b2b1eff72d 100644 --- a/compiler/rustc_abi/src/extern_abi.rs +++ b/compiler/rustc_abi/src/extern_abi.rs @@ -6,6 +6,8 @@ use std::hash::{Hash, Hasher}; use rustc_data_structures::stable_hasher::{HashStable, StableHasher, StableOrd}; #[cfg(feature = "nightly")] use rustc_macros::{Decodable, Encodable}; +#[cfg(feature = "nightly")] +use rustc_span::Symbol; use crate::AbiFromStrErr; @@ -226,6 +228,13 @@ impl StableOrd for ExternAbi { #[cfg(feature = "nightly")] rustc_error_messages::into_diag_arg_using_display!(ExternAbi); +#[cfg(feature = "nightly")] +pub enum CVariadicStatus { + NotSupported, + Stable, + Unstable { feature: Symbol }, +} + impl ExternAbi { /// An ABI "like Rust" /// @@ -238,23 +247,33 @@ impl ExternAbi { matches!(self, Rust | RustCall | RustCold) } - pub fn supports_varargs(self) -> bool { + /// Returns whether the ABI supports C variadics. This only controls whether we allow *imports* + /// of such functions via `extern` blocks; there's a separate check during AST construction + /// guarding *definitions* of variadic functions. + #[cfg(feature = "nightly")] + pub fn supports_c_variadic(self) -> CVariadicStatus { // * C and Cdecl obviously support varargs. // * C can be based on Aapcs, SysV64 or Win64, so they must support varargs. // * EfiApi is based on Win64 or C, so it also supports it. + // * System automatically falls back to C when used with variadics, therefore supports it. // // * Stdcall does not, because it would be impossible for the callee to clean // up the arguments. (callee doesn't know how many arguments are there) // * Same for Fastcall, Vectorcall and Thiscall. // * Other calling conventions are related to hardware or the compiler itself. + // + // All of the supported ones must have a test in `tests/codegen/cffi/c-variadic-ffi.rs`. match self { Self::C { .. } | Self::Cdecl { .. } | Self::Aapcs { .. } | Self::Win64 { .. } | Self::SysV64 { .. } - | Self::EfiApi => true, - _ => false, + | Self::EfiApi => CVariadicStatus::Stable, + Self::System { .. } => { + CVariadicStatus::Unstable { feature: rustc_span::sym::extern_system_varargs } + } + _ => CVariadicStatus::NotSupported, } } } diff --git a/compiler/rustc_abi/src/lib.rs b/compiler/rustc_abi/src/lib.rs index 14e256b8045d..22aba1fac0f8 100644 --- a/compiler/rustc_abi/src/lib.rs +++ b/compiler/rustc_abi/src/lib.rs @@ -63,6 +63,8 @@ mod tests; pub use callconv::{Heterogeneous, HomogeneousAggregate, Reg, RegKind}; pub use canon_abi::{ArmCall, CanonAbi, InterruptKind, X86Call}; +#[cfg(feature = "nightly")] +pub use extern_abi::CVariadicStatus; pub use extern_abi::{ExternAbi, all_names}; #[cfg(feature = "nightly")] pub use layout::{FIRST_VARIANT, FieldIdx, Layout, TyAbiInterface, TyAndLayout, VariantIdx}; diff --git a/compiler/rustc_ast_passes/messages.ftl b/compiler/rustc_ast_passes/messages.ftl index a95f14439684..e5f1fcdc4b40 100644 --- a/compiler/rustc_ast_passes/messages.ftl +++ b/compiler/rustc_ast_passes/messages.ftl @@ -57,7 +57,7 @@ ast_passes_auto_super_lifetime = auto traits cannot have super traits or lifetim .label = {ast_passes_auto_super_lifetime} .suggestion = remove the super traits or lifetime bounds -ast_passes_bad_c_variadic = only foreign, `unsafe extern "C"`, or `unsafe extern "C-unwind"` functions may have a C-variadic arg +ast_passes_bad_c_variadic = defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention ast_passes_body_in_extern = incorrect `{$kind}` inside `extern` block .cannot_have = cannot have a body diff --git a/compiler/rustc_feature/src/accepted.rs b/compiler/rustc_feature/src/accepted.rs index 9fe55216f939..6af4cfb0e562 100644 --- a/compiler/rustc_feature/src/accepted.rs +++ b/compiler/rustc_feature/src/accepted.rs @@ -203,6 +203,9 @@ declare_features! ( (accepted, expr_fragment_specifier_2024, "1.83.0", Some(123742)), /// Allows arbitrary expressions in key-value attributes at parse time. (accepted, extended_key_value_attributes, "1.54.0", Some(78835)), + /// Allows using `aapcs`, `efiapi`, `sysv64` and `win64` as calling conventions + /// for functions with varargs. + (accepted, extended_varargs_abi_support, "CURRENT_RUSTC_VERSION", Some(100189)), /// Allows resolving absolute paths as paths from other crates. (accepted, extern_absolute_paths, "1.30.0", Some(44660)), /// Allows `extern crate foo as bar;`. This puts `bar` into extern prelude. diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index 92b435b4b017..573e9aab0554 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -492,9 +492,6 @@ declare_features! ( (incomplete, explicit_tail_calls, "1.72.0", Some(112788)), /// Allows using `#[export_stable]` which indicates that an item is exportable. (incomplete, export_stable, "1.88.0", Some(139939)), - /// Allows using `aapcs`, `efiapi`, `sysv64` and `win64` as calling conventions - /// for functions with varargs. - (unstable, extended_varargs_abi_support, "1.65.0", Some(100189)), /// Allows using `system` as a calling convention with varargs. (unstable, extern_system_varargs, "1.86.0", Some(136946)), /// Allows defining `extern type`s. diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index eccb88a938fb..08b344638dd5 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -978,7 +978,7 @@ pub(crate) fn check_item_type(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Result<(), tcx.ensure_ok().fn_sig(def_id); let item = tcx.hir_foreign_item(item); let hir::ForeignItemKind::Fn(sig, ..) = item.kind else { bug!() }; - require_c_abi_if_c_variadic(tcx, sig.decl, abi, item.span); + check_c_variadic_abi(tcx, sig.decl, abi, item.span); } DefKind::Static { .. } => { tcx.ensure_ok().codegen_fn_attrs(def_id); diff --git a/compiler/rustc_hir_analysis/src/check/mod.rs b/compiler/rustc_hir_analysis/src/check/mod.rs index 2e4b151d4dc8..b5c0ca4727cd 100644 --- a/compiler/rustc_hir_analysis/src/check/mod.rs +++ b/compiler/rustc_hir_analysis/src/check/mod.rs @@ -98,7 +98,7 @@ use tracing::debug; use self::compare_impl_item::collect_return_position_impl_trait_in_trait_tys; use self::region::region_scope_tree; -use crate::{errors, require_c_abi_if_c_variadic}; +use crate::{check_c_variadic_abi, errors}; /// Adds query implementations to the [Providers] vtable, see [`rustc_middle::query`] pub(super) fn provide(providers: &mut Providers) { diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs index c7b984d9b259..c5e079fe89ac 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs @@ -52,11 +52,11 @@ use rustc_trait_selection::traits::{self, FulfillmentError}; use tracing::{debug, instrument}; use crate::check::check_abi; +use crate::check_c_variadic_abi; use crate::errors::{AmbiguousLifetimeBound, BadReturnTypeNotation}; use crate::hir_ty_lowering::errors::{GenericsArgsErrExtend, prohibit_assoc_item_constraint}; use crate::hir_ty_lowering::generics::{check_generic_arg_count, lower_generic_args}; use crate::middle::resolve_bound_vars as rbv; -use crate::require_c_abi_if_c_variadic; /// A path segment that is semantically allowed to have generic arguments. #[derive(Debug)] @@ -2412,7 +2412,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { Ty::new_tup_from_iter(tcx, fields.iter().map(|t| self.lower_ty(t))) } hir::TyKind::FnPtr(bf) => { - require_c_abi_if_c_variadic(tcx, bf.decl, bf.abi, hir_ty.span); + check_c_variadic_abi(tcx, bf.decl, bf.abi, hir_ty.span); Ty::new_fn_ptr( tcx, diff --git a/compiler/rustc_hir_analysis/src/lib.rs b/compiler/rustc_hir_analysis/src/lib.rs index 44a5ceed4696..2562ab7542a6 100644 --- a/compiler/rustc_hir_analysis/src/lib.rs +++ b/compiler/rustc_hir_analysis/src/lib.rs @@ -90,7 +90,7 @@ mod outlives; mod variance; pub use errors::NoVariantNamed; -use rustc_abi::ExternAbi; +use rustc_abi::{CVariadicStatus, ExternAbi}; use rustc_hir::def::DefKind; use rustc_hir::lints::DelayedLint; use rustc_hir::{self as hir}; @@ -99,7 +99,6 @@ use rustc_middle::mir::interpret::GlobalId; use rustc_middle::query::Providers; use rustc_middle::ty::{self, Const, Ty, TyCtxt}; use rustc_session::parse::feature_err; -use rustc_span::symbol::sym; use rustc_span::{ErrorGuaranteed, Span}; use rustc_trait_selection::traits; @@ -108,46 +107,34 @@ use crate::hir_ty_lowering::{FeedConstTy, HirTyLowerer}; rustc_fluent_macro::fluent_messages! { "../messages.ftl" } -fn require_c_abi_if_c_variadic( - tcx: TyCtxt<'_>, - decl: &hir::FnDecl<'_>, - abi: ExternAbi, - span: Span, -) { - // ABIs which can stably use varargs - if !decl.c_variadic || matches!(abi, ExternAbi::C { .. } | ExternAbi::Cdecl { .. }) { +fn check_c_variadic_abi(tcx: TyCtxt<'_>, decl: &hir::FnDecl<'_>, abi: ExternAbi, span: Span) { + if !decl.c_variadic { + // Not even a variadic function. return; } - // ABIs with feature-gated stability - let extended_abi_support = tcx.features().extended_varargs_abi_support(); - let extern_system_varargs = tcx.features().extern_system_varargs(); - - // If the feature gate has been enabled, we can stop here - if extern_system_varargs && let ExternAbi::System { .. } = abi { - return; - }; - if extended_abi_support && abi.supports_varargs() { - return; - }; - - // Looks like we need to pick an error to emit. - // Is there any feature which we could have enabled to make this work? - let unstable_explain = - format!("C-variadic functions with the {abi} calling convention are unstable"); - match abi { - ExternAbi::System { .. } => { - feature_err(&tcx.sess, sym::extern_system_varargs, span, unstable_explain) + match abi.supports_c_variadic() { + CVariadicStatus::Stable => {} + CVariadicStatus::NotSupported => { + tcx.dcx() + .create_err(errors::VariadicFunctionCompatibleConvention { + span, + convention: &format!("{abi}"), + }) + .emit(); } - abi if abi.supports_varargs() => { - feature_err(&tcx.sess, sym::extended_varargs_abi_support, span, unstable_explain) + CVariadicStatus::Unstable { feature } => { + if !tcx.features().enabled(feature) { + feature_err( + &tcx.sess, + feature, + span, + format!("C-variadic functions with the {abi} calling convention are unstable"), + ) + .emit(); + } } - _ => tcx.dcx().create_err(errors::VariadicFunctionCompatibleConvention { - span, - convention: &format!("{abi}"), - }), } - .emit(); } /// Adds query implementations to the [Providers] vtable, see [`rustc_middle::query`] diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index f0de03c9a280..da8fda42cd14 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -291,7 +291,6 @@ #![feature(doc_masked)] #![feature(doc_notable_trait)] #![feature(dropck_eyepatch)] -#![feature(extended_varargs_abi_support)] #![feature(f16)] #![feature(f128)] #![feature(ffi_const)] diff --git a/src/doc/unstable-book/src/language-features/extended-varargs-abi-support.md b/src/doc/unstable-book/src/language-features/extended-varargs-abi-support.md deleted file mode 100644 index b20c30ec8f1c..000000000000 --- a/src/doc/unstable-book/src/language-features/extended-varargs-abi-support.md +++ /dev/null @@ -1,10 +0,0 @@ -# `extended_varargs_abi_support` - -The tracking issue for this feature is: [#100189] - -[#100189]: https://github.com/rust-lang/rust/issues/100189 - ------------------------- - -This feature adds the possibility of using `sysv64`, `win64` or `efiapi` calling -conventions on functions with varargs. diff --git a/tests/codegen-llvm/cffi/c-variadic-ffi.rs b/tests/codegen-llvm/cffi/c-variadic-ffi.rs index 3e99c9fb84e4..1dee477e9ed7 100644 --- a/tests/codegen-llvm/cffi/c-variadic-ffi.rs +++ b/tests/codegen-llvm/cffi/c-variadic-ffi.rs @@ -14,7 +14,7 @@ //@[arm32] needs-llvm-components: arm #![crate_type = "lib"] #![feature(no_core)] -#![feature(extended_varargs_abi_support, extern_system_varargs)] +#![feature(extern_system_varargs)] #![no_core] extern crate minicore; diff --git a/tests/ui/abi/unsupported-varargs-fnptr.rs b/tests/ui/abi/unsupported-varargs-fnptr.rs index 1d23916d0390..ac3913b3ef88 100644 --- a/tests/ui/abi/unsupported-varargs-fnptr.rs +++ b/tests/ui/abi/unsupported-varargs-fnptr.rs @@ -6,8 +6,6 @@ // We have to use this flag to force ABI computation of an invalid ABI //@ compile-flags: -Clink-dead-code -#![feature(extended_varargs_abi_support)] - // sometimes fn ptrs with varargs make layout and ABI computation ICE // as found in https://github.com/rust-lang/rust/issues/142107 diff --git a/tests/ui/abi/unsupported-varargs-fnptr.stderr b/tests/ui/abi/unsupported-varargs-fnptr.stderr index 238f2b313304..c05c55df82e7 100644 --- a/tests/ui/abi/unsupported-varargs-fnptr.stderr +++ b/tests/ui/abi/unsupported-varargs-fnptr.stderr @@ -1,5 +1,5 @@ error[E0570]: "aapcs" is not a supported ABI for the current target - --> $DIR/unsupported-varargs-fnptr.rs:14:20 + --> $DIR/unsupported-varargs-fnptr.rs:12:20 | LL | fn aapcs(f: extern "aapcs" fn(usize, ...)) { | ^^^^^^^ diff --git a/tests/ui/c-variadic/feature-gate-extended_varargs_abi_support.rs b/tests/ui/c-variadic/feature-gate-extended_varargs_abi_support.rs deleted file mode 100644 index 1e0576b21866..000000000000 --- a/tests/ui/c-variadic/feature-gate-extended_varargs_abi_support.rs +++ /dev/null @@ -1,16 +0,0 @@ -//@ only-x86_64 - -fn efiapi(f: extern "efiapi" fn(usize, ...)) { - //~^ ERROR: unstable - f(22, 44); -} -fn sysv(f: extern "sysv64" fn(usize, ...)) { - //~^ ERROR: unstable - f(22, 44); -} -fn win(f: extern "win64" fn(usize, ...)) { - //~^ ERROR: unstable - f(22, 44); -} - -fn main() {} diff --git a/tests/ui/c-variadic/feature-gate-extended_varargs_abi_support.stderr b/tests/ui/c-variadic/feature-gate-extended_varargs_abi_support.stderr deleted file mode 100644 index 7ef54b639ad2..000000000000 --- a/tests/ui/c-variadic/feature-gate-extended_varargs_abi_support.stderr +++ /dev/null @@ -1,33 +0,0 @@ -error[E0658]: C-variadic functions with the "efiapi" calling convention are unstable - --> $DIR/feature-gate-extended_varargs_abi_support.rs:3:14 - | -LL | fn efiapi(f: extern "efiapi" fn(usize, ...)) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: see issue #100189 for more information - = help: add `#![feature(extended_varargs_abi_support)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - -error[E0658]: C-variadic functions with the "sysv64" calling convention are unstable - --> $DIR/feature-gate-extended_varargs_abi_support.rs:7:12 - | -LL | fn sysv(f: extern "sysv64" fn(usize, ...)) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: see issue #100189 for more information - = help: add `#![feature(extended_varargs_abi_support)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - -error[E0658]: C-variadic functions with the "win64" calling convention are unstable - --> $DIR/feature-gate-extended_varargs_abi_support.rs:11:11 - | -LL | fn win(f: extern "win64" fn(usize, ...)) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: see issue #100189 for more information - = help: add `#![feature(extended_varargs_abi_support)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - -error: aborting due to 3 previous errors - -For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/c-variadic/issue-86053-1.rs b/tests/ui/c-variadic/issue-86053-1.rs index 8eeb99a4cc19..537d0263adf7 100644 --- a/tests/ui/c-variadic/issue-86053-1.rs +++ b/tests/ui/c-variadic/issue-86053-1.rs @@ -13,6 +13,6 @@ fn ordering4 < 'a , 'b > ( a : , self , self , self , //~| ERROR unexpected `self` parameter in function //~| ERROR unexpected `self` parameter in function //~| ERROR `...` must be the last argument of a C-variadic function - //~| ERROR only foreign, `unsafe extern "C"`, or `unsafe extern "C-unwind"` functions may have a C-variadic arg + //~| ERROR defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention //~| ERROR cannot find type `F` in this scope } diff --git a/tests/ui/c-variadic/issue-86053-1.stderr b/tests/ui/c-variadic/issue-86053-1.stderr index dc323f9a234d..472295c92b97 100644 --- a/tests/ui/c-variadic/issue-86053-1.stderr +++ b/tests/ui/c-variadic/issue-86053-1.stderr @@ -46,7 +46,7 @@ error: `...` must be the last argument of a C-variadic function LL | self , ... , self , self , ... ) where F : FnOnce ( & 'a & 'b usize ) { | ^^^ -error: only foreign, `unsafe extern "C"`, or `unsafe extern "C-unwind"` functions may have a C-variadic arg +error: defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention --> $DIR/issue-86053-1.rs:11:12 | LL | self , ... , self , self , ... ) where F : FnOnce ( & 'a & 'b usize ) { diff --git a/tests/ui/c-variadic/same-program-multiple-abis-arm.rs b/tests/ui/c-variadic/same-program-multiple-abis-arm.rs index 1b0bdecabfbc..1445bbb47bbd 100644 --- a/tests/ui/c-variadic/same-program-multiple-abis-arm.rs +++ b/tests/ui/c-variadic/same-program-multiple-abis-arm.rs @@ -1,4 +1,3 @@ -#![feature(extended_varargs_abi_support)] //@ run-pass //@ only-arm //@ ignore-thumb (this test uses arm assembly) diff --git a/tests/ui/c-variadic/same-program-multiple-abis-x86_64.rs b/tests/ui/c-variadic/same-program-multiple-abis-x86_64.rs index b21accb999e9..aff8ab613c43 100644 --- a/tests/ui/c-variadic/same-program-multiple-abis-x86_64.rs +++ b/tests/ui/c-variadic/same-program-multiple-abis-x86_64.rs @@ -1,4 +1,3 @@ -#![feature(extended_varargs_abi_support)] //@ run-pass //@ only-x86_64 diff --git a/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/generics.rs b/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/generics.rs index 800dd580af29..ad4fca8252d2 100644 --- a/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/generics.rs +++ b/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/generics.rs @@ -71,6 +71,6 @@ extern "cmse-nonsecure-entry" fn wrapped_trait_object( } extern "cmse-nonsecure-entry" fn c_variadic(_: u32, _: ...) { - //~^ ERROR only foreign, `unsafe extern "C"`, or `unsafe extern "C-unwind"` functions may have a C-variadic arg + //~^ ERROR defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention //~| ERROR requires `va_list` lang_item } diff --git a/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/generics.stderr b/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/generics.stderr index f0190671b5a1..7aeb6969feb9 100644 --- a/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/generics.stderr +++ b/tests/ui/cmse-nonsecure/cmse-nonsecure-entry/generics.stderr @@ -1,4 +1,4 @@ -error: only foreign, `unsafe extern "C"`, or `unsafe extern "C-unwind"` functions may have a C-variadic arg +error: defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention --> $DIR/generics.rs:73:53 | LL | extern "cmse-nonsecure-entry" fn c_variadic(_: u32, _: ...) { diff --git a/tests/ui/feature-gates/feature-gate-c_variadic.rs b/tests/ui/feature-gates/feature-gate-c_variadic.rs index f189f02a26dd..45c688420931 100644 --- a/tests/ui/feature-gates/feature-gate-c_variadic.rs +++ b/tests/ui/feature-gates/feature-gate-c_variadic.rs @@ -2,3 +2,9 @@ pub unsafe extern "C" fn test(_: i32, ap: ...) { } //~^ ERROR C-variadic functions are unstable + +trait Trait { + unsafe extern "C" fn trait_test(_: i32, ap: ...) { } + //~^ ERROR C-variadic functions are unstable + //~| ERROR defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention +} diff --git a/tests/ui/feature-gates/feature-gate-c_variadic.stderr b/tests/ui/feature-gates/feature-gate-c_variadic.stderr index 1b6a8c92af5e..e30a2f1ede36 100644 --- a/tests/ui/feature-gates/feature-gate-c_variadic.stderr +++ b/tests/ui/feature-gates/feature-gate-c_variadic.stderr @@ -1,3 +1,9 @@ +error: defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention + --> $DIR/feature-gate-c_variadic.rs:7:45 + | +LL | unsafe extern "C" fn trait_test(_: i32, ap: ...) { } + | ^^^^^^^ + error[E0658]: C-variadic functions are unstable --> $DIR/feature-gate-c_variadic.rs:3:1 | @@ -8,6 +14,16 @@ LL | pub unsafe extern "C" fn test(_: i32, ap: ...) { } = help: add `#![feature(c_variadic)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date -error: aborting due to 1 previous error +error[E0658]: C-variadic functions are unstable + --> $DIR/feature-gate-c_variadic.rs:7:5 + | +LL | unsafe extern "C" fn trait_test(_: i32, ap: ...) { } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #44930 for more information + = help: add `#![feature(c_variadic)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error: aborting due to 3 previous errors For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/mir/issue-83499-input-output-iteration-ice.rs b/tests/ui/mir/issue-83499-input-output-iteration-ice.rs index 78e5c9618028..9277994d9b30 100644 --- a/tests/ui/mir/issue-83499-input-output-iteration-ice.rs +++ b/tests/ui/mir/issue-83499-input-output-iteration-ice.rs @@ -5,6 +5,6 @@ fn main() {} fn foo(_: Bar, ...) -> impl {} -//~^ ERROR only foreign, `unsafe extern "C"`, or `unsafe extern "C-unwind"` functions may have a C-variadic arg +//~^ ERROR defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention //~| ERROR cannot find type `Bar` in this scope //~| ERROR at least one trait must be specified diff --git a/tests/ui/mir/issue-83499-input-output-iteration-ice.stderr b/tests/ui/mir/issue-83499-input-output-iteration-ice.stderr index 80a8a94aea40..4a1aa49eb6e6 100644 --- a/tests/ui/mir/issue-83499-input-output-iteration-ice.stderr +++ b/tests/ui/mir/issue-83499-input-output-iteration-ice.stderr @@ -1,4 +1,4 @@ -error: only foreign, `unsafe extern "C"`, or `unsafe extern "C-unwind"` functions may have a C-variadic arg +error: defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention --> $DIR/issue-83499-input-output-iteration-ice.rs:7:16 | LL | fn foo(_: Bar, ...) -> impl {} diff --git a/tests/ui/parser/variadic-ffi-semantic-restrictions.rs b/tests/ui/parser/variadic-ffi-semantic-restrictions.rs index 1cd6d13d56b6..e7a0248cffab 100644 --- a/tests/ui/parser/variadic-ffi-semantic-restrictions.rs +++ b/tests/ui/parser/variadic-ffi-semantic-restrictions.rs @@ -4,29 +4,29 @@ fn main() {} fn f1_1(x: isize, ...) {} -//~^ ERROR only foreign, `unsafe extern "C"`, or `unsafe extern "C-unwind"` functions may have a C-variadic arg +//~^ ERROR defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention fn f1_2(...) {} -//~^ ERROR only foreign, `unsafe extern "C"`, or `unsafe extern "C-unwind"` functions may have a C-variadic arg +//~^ ERROR defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention extern "C" fn f2_1(x: isize, ...) {} -//~^ ERROR only foreign, `unsafe extern "C"`, or `unsafe extern "C-unwind"` functions may have a C-variadic arg +//~^ ERROR defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention extern "C" fn f2_2(...) {} -//~^ ERROR only foreign, `unsafe extern "C"`, or `unsafe extern "C-unwind"` functions may have a C-variadic arg +//~^ ERROR defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention extern "C" fn f2_3(..., x: isize) {} -//~^ ERROR only foreign, `unsafe extern "C"`, or `unsafe extern "C-unwind"` functions may have a C-variadic arg +//~^ ERROR defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention //~| ERROR `...` must be the last argument of a C-variadic function extern "C" fn f3_1(x: isize, ...) {} -//~^ ERROR only foreign, `unsafe extern "C"`, or `unsafe extern "C-unwind"` functions may have a C-variadic arg +//~^ ERROR defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention extern "C" fn f3_2(...) {} -//~^ ERROR only foreign, `unsafe extern "C"`, or `unsafe extern "C-unwind"` functions may have a C-variadic arg +//~^ ERROR defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention extern "C" fn f3_3(..., x: isize) {} -//~^ ERROR only foreign, `unsafe extern "C"`, or `unsafe extern "C-unwind"` functions may have a C-variadic arg +//~^ ERROR defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention //~| ERROR `...` must be the last argument of a C-variadic function const unsafe extern "C" fn f4_1(x: isize, ...) {} @@ -35,12 +35,12 @@ const unsafe extern "C" fn f4_1(x: isize, ...) {} const extern "C" fn f4_2(x: isize, ...) {} //~^ ERROR functions cannot be both `const` and C-variadic -//~| ERROR only foreign, `unsafe extern "C"`, or `unsafe extern "C-unwind"` functions may have a C-variadic arg +//~| ERROR defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention //~| ERROR destructor of `VaListImpl<'_>` cannot be evaluated at compile-time const extern "C" fn f4_3(..., x: isize, ...) {} //~^ ERROR functions cannot be both `const` and C-variadic -//~| ERROR only foreign, `unsafe extern "C"`, or `unsafe extern "C-unwind"` functions may have a C-variadic arg +//~| ERROR defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention //~| ERROR `...` must be the last argument of a C-variadic function extern "C" { @@ -52,34 +52,34 @@ struct X; impl X { fn i_f1(x: isize, ...) {} - //~^ ERROR only foreign, `unsafe extern "C"`, or `unsafe extern "C-unwind"` functions may have a C-variadic arg + //~^ ERROR defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention fn i_f2(...) {} - //~^ ERROR only foreign, `unsafe extern "C"`, or `unsafe extern "C-unwind"` functions may have a C-variadic arg + //~^ ERROR defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention fn i_f3(..., x: isize, ...) {} - //~^ ERROR only foreign, `unsafe extern "C"`, or `unsafe extern "C-unwind"` functions may have a C-variadic arg + //~^ ERROR defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention //~| ERROR `...` must be the last argument of a C-variadic function fn i_f4(..., x: isize, ...) {} - //~^ ERROR only foreign, `unsafe extern "C"`, or `unsafe extern "C-unwind"` functions may have a C-variadic arg + //~^ ERROR defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention //~| ERROR `...` must be the last argument of a C-variadic function const fn i_f5(x: isize, ...) {} - //~^ ERROR only foreign, `unsafe extern "C"`, or `unsafe extern "C-unwind"` functions may have a C-variadic arg + //~^ ERROR defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention //~| ERROR functions cannot be both `const` and C-variadic //~| ERROR destructor of `VaListImpl<'_>` cannot be evaluated at compile-time } trait T { fn t_f1(x: isize, ...) {} - //~^ ERROR only foreign, `unsafe extern "C"`, or `unsafe extern "C-unwind"` functions may have a C-variadic arg + //~^ ERROR defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention fn t_f2(x: isize, ...); - //~^ ERROR only foreign, `unsafe extern "C"`, or `unsafe extern "C-unwind"` functions may have a C-variadic arg + //~^ ERROR defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention fn t_f3(...) {} - //~^ ERROR only foreign, `unsafe extern "C"`, or `unsafe extern "C-unwind"` functions may have a C-variadic arg + //~^ ERROR defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention fn t_f4(...); - //~^ ERROR only foreign, `unsafe extern "C"`, or `unsafe extern "C-unwind"` functions may have a C-variadic arg + //~^ ERROR defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention fn t_f5(..., x: isize) {} - //~^ ERROR only foreign, `unsafe extern "C"`, or `unsafe extern "C-unwind"` functions may have a C-variadic arg + //~^ ERROR defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention //~| ERROR `...` must be the last argument of a C-variadic function fn t_f6(..., x: isize); - //~^ ERROR only foreign, `unsafe extern "C"`, or `unsafe extern "C-unwind"` functions may have a C-variadic arg + //~^ ERROR defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention //~| ERROR `...` must be the last argument of a C-variadic function } diff --git a/tests/ui/parser/variadic-ffi-semantic-restrictions.stderr b/tests/ui/parser/variadic-ffi-semantic-restrictions.stderr index b740cef02005..5379045967aa 100644 --- a/tests/ui/parser/variadic-ffi-semantic-restrictions.stderr +++ b/tests/ui/parser/variadic-ffi-semantic-restrictions.stderr @@ -1,22 +1,22 @@ -error: only foreign, `unsafe extern "C"`, or `unsafe extern "C-unwind"` functions may have a C-variadic arg +error: defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention --> $DIR/variadic-ffi-semantic-restrictions.rs:6:19 | LL | fn f1_1(x: isize, ...) {} | ^^^ -error: only foreign, `unsafe extern "C"`, or `unsafe extern "C-unwind"` functions may have a C-variadic arg +error: defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention --> $DIR/variadic-ffi-semantic-restrictions.rs:9:9 | LL | fn f1_2(...) {} | ^^^ -error: only foreign, `unsafe extern "C"`, or `unsafe extern "C-unwind"` functions may have a C-variadic arg +error: defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention --> $DIR/variadic-ffi-semantic-restrictions.rs:12:30 | LL | extern "C" fn f2_1(x: isize, ...) {} | ^^^ -error: only foreign, `unsafe extern "C"`, or `unsafe extern "C-unwind"` functions may have a C-variadic arg +error: defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention --> $DIR/variadic-ffi-semantic-restrictions.rs:15:20 | LL | extern "C" fn f2_2(...) {} @@ -28,19 +28,19 @@ error: `...` must be the last argument of a C-variadic function LL | extern "C" fn f2_3(..., x: isize) {} | ^^^ -error: only foreign, `unsafe extern "C"`, or `unsafe extern "C-unwind"` functions may have a C-variadic arg +error: defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention --> $DIR/variadic-ffi-semantic-restrictions.rs:18:20 | LL | extern "C" fn f2_3(..., x: isize) {} | ^^^ -error: only foreign, `unsafe extern "C"`, or `unsafe extern "C-unwind"` functions may have a C-variadic arg +error: defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention --> $DIR/variadic-ffi-semantic-restrictions.rs:22:30 | LL | extern "C" fn f3_1(x: isize, ...) {} | ^^^ -error: only foreign, `unsafe extern "C"`, or `unsafe extern "C-unwind"` functions may have a C-variadic arg +error: defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention --> $DIR/variadic-ffi-semantic-restrictions.rs:25:20 | LL | extern "C" fn f3_2(...) {} @@ -52,7 +52,7 @@ error: `...` must be the last argument of a C-variadic function LL | extern "C" fn f3_3(..., x: isize) {} | ^^^ -error: only foreign, `unsafe extern "C"`, or `unsafe extern "C-unwind"` functions may have a C-variadic arg +error: defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention --> $DIR/variadic-ffi-semantic-restrictions.rs:28:20 | LL | extern "C" fn f3_3(..., x: isize) {} @@ -70,7 +70,7 @@ error: functions cannot be both `const` and C-variadic LL | const extern "C" fn f4_2(x: isize, ...) {} | ^^^^^ `const` because of this ^^^ C-variadic because of this -error: only foreign, `unsafe extern "C"`, or `unsafe extern "C-unwind"` functions may have a C-variadic arg +error: defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention --> $DIR/variadic-ffi-semantic-restrictions.rs:36:36 | LL | const extern "C" fn f4_2(x: isize, ...) {} @@ -91,7 +91,7 @@ LL | const extern "C" fn f4_3(..., x: isize, ...) {} | | C-variadic because of this | `const` because of this -error: only foreign, `unsafe extern "C"`, or `unsafe extern "C-unwind"` functions may have a C-variadic arg +error: defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention --> $DIR/variadic-ffi-semantic-restrictions.rs:41:26 | LL | const extern "C" fn f4_3(..., x: isize, ...) {} @@ -103,13 +103,13 @@ error: `...` must be the last argument of a C-variadic function LL | fn e_f2(..., x: isize); | ^^^ -error: only foreign, `unsafe extern "C"`, or `unsafe extern "C-unwind"` functions may have a C-variadic arg +error: defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention --> $DIR/variadic-ffi-semantic-restrictions.rs:54:23 | LL | fn i_f1(x: isize, ...) {} | ^^^ -error: only foreign, `unsafe extern "C"`, or `unsafe extern "C-unwind"` functions may have a C-variadic arg +error: defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention --> $DIR/variadic-ffi-semantic-restrictions.rs:56:13 | LL | fn i_f2(...) {} @@ -121,7 +121,7 @@ error: `...` must be the last argument of a C-variadic function LL | fn i_f3(..., x: isize, ...) {} | ^^^ -error: only foreign, `unsafe extern "C"`, or `unsafe extern "C-unwind"` functions may have a C-variadic arg +error: defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention --> $DIR/variadic-ffi-semantic-restrictions.rs:58:13 | LL | fn i_f3(..., x: isize, ...) {} @@ -133,7 +133,7 @@ error: `...` must be the last argument of a C-variadic function LL | fn i_f4(..., x: isize, ...) {} | ^^^ -error: only foreign, `unsafe extern "C"`, or `unsafe extern "C-unwind"` functions may have a C-variadic arg +error: defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention --> $DIR/variadic-ffi-semantic-restrictions.rs:61:13 | LL | fn i_f4(..., x: isize, ...) {} @@ -147,31 +147,31 @@ LL | const fn i_f5(x: isize, ...) {} | | | `const` because of this -error: only foreign, `unsafe extern "C"`, or `unsafe extern "C-unwind"` functions may have a C-variadic arg +error: defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention --> $DIR/variadic-ffi-semantic-restrictions.rs:64:29 | LL | const fn i_f5(x: isize, ...) {} | ^^^ -error: only foreign, `unsafe extern "C"`, or `unsafe extern "C-unwind"` functions may have a C-variadic arg +error: defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention --> $DIR/variadic-ffi-semantic-restrictions.rs:71:23 | LL | fn t_f1(x: isize, ...) {} | ^^^ -error: only foreign, `unsafe extern "C"`, or `unsafe extern "C-unwind"` functions may have a C-variadic arg +error: defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention --> $DIR/variadic-ffi-semantic-restrictions.rs:73:23 | LL | fn t_f2(x: isize, ...); | ^^^ -error: only foreign, `unsafe extern "C"`, or `unsafe extern "C-unwind"` functions may have a C-variadic arg +error: defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention --> $DIR/variadic-ffi-semantic-restrictions.rs:75:13 | LL | fn t_f3(...) {} | ^^^ -error: only foreign, `unsafe extern "C"`, or `unsafe extern "C-unwind"` functions may have a C-variadic arg +error: defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention --> $DIR/variadic-ffi-semantic-restrictions.rs:77:13 | LL | fn t_f4(...); @@ -183,7 +183,7 @@ error: `...` must be the last argument of a C-variadic function LL | fn t_f5(..., x: isize) {} | ^^^ -error: only foreign, `unsafe extern "C"`, or `unsafe extern "C-unwind"` functions may have a C-variadic arg +error: defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention --> $DIR/variadic-ffi-semantic-restrictions.rs:79:13 | LL | fn t_f5(..., x: isize) {} @@ -195,7 +195,7 @@ error: `...` must be the last argument of a C-variadic function LL | fn t_f6(..., x: isize); | ^^^ -error: only foreign, `unsafe extern "C"`, or `unsafe extern "C-unwind"` functions may have a C-variadic arg +error: defining functions with C-variadic arguments is only allowed for free functions with the "C" or "C-unwind" calling convention --> $DIR/variadic-ffi-semantic-restrictions.rs:82:13 | LL | fn t_f6(..., x: isize); From 301655eafe56a4b5064adebd412becf94b59221c Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 2 Sep 2025 19:09:13 +1000 Subject: [PATCH 42/48] Revert introduction of `[workspace.dependencies]`. This was done in #145740 and #145947. It is causing problems for people using r-a on anything that uses the rustc-dev rustup package, e.g. Miri, clippy. This repository has lots of submodules and subtrees and various different projects are carved out of pieces of it. It seems like `[workspace.dependencies]` will just be more trouble than it's worth. --- Cargo.toml | 27 ------------------- compiler/rustc_abi/Cargo.toml | 4 +-- compiler/rustc_ast/Cargo.toml | 10 +++---- compiler/rustc_ast_lowering/Cargo.toml | 4 +-- compiler/rustc_ast_passes/Cargo.toml | 4 +-- compiler/rustc_ast_pretty/Cargo.toml | 4 +-- compiler/rustc_attr_parsing/Cargo.toml | 2 +- compiler/rustc_borrowck/Cargo.toml | 8 +++--- compiler/rustc_builtin_macros/Cargo.toml | 4 +-- compiler/rustc_codegen_llvm/Cargo.toml | 14 +++++----- compiler/rustc_codegen_ssa/Cargo.toml | 14 +++++----- compiler/rustc_const_eval/Cargo.toml | 6 ++--- compiler/rustc_data_structures/Cargo.toml | 18 ++++++------- compiler/rustc_driver_impl/Cargo.toml | 6 ++--- compiler/rustc_error_messages/Cargo.toml | 2 +- compiler/rustc_errors/Cargo.toml | 4 +-- compiler/rustc_expand/Cargo.toml | 4 +-- compiler/rustc_feature/Cargo.toml | 2 +- compiler/rustc_fluent_macro/Cargo.toml | 4 +-- compiler/rustc_fs_util/Cargo.toml | 2 +- compiler/rustc_hir/Cargo.toml | 8 +++--- compiler/rustc_hir_analysis/Cargo.toml | 4 +-- compiler/rustc_hir_typeck/Cargo.toml | 4 +-- compiler/rustc_incremental/Cargo.toml | 4 +-- compiler/rustc_index_macros/Cargo.toml | 4 +-- compiler/rustc_infer/Cargo.toml | 4 +-- compiler/rustc_interface/Cargo.toml | 2 +- compiler/rustc_lexer/Cargo.toml | 2 +- compiler/rustc_lint/Cargo.toml | 2 +- compiler/rustc_llvm/Cargo.toml | 2 +- compiler/rustc_log/Cargo.toml | 2 +- compiler/rustc_macros/Cargo.toml | 4 +-- compiler/rustc_metadata/Cargo.toml | 10 +++---- compiler/rustc_middle/Cargo.toml | 12 ++++----- compiler/rustc_mir_build/Cargo.toml | 6 ++--- compiler/rustc_mir_dataflow/Cargo.toml | 4 +-- compiler/rustc_mir_transform/Cargo.toml | 6 ++--- compiler/rustc_monomorphize/Cargo.toml | 4 +-- compiler/rustc_next_trait_solver/Cargo.toml | 4 +-- compiler/rustc_parse/Cargo.toml | 8 +++--- compiler/rustc_parse_format/Cargo.toml | 2 +- compiler/rustc_passes/Cargo.toml | 2 +- compiler/rustc_pattern_analysis/Cargo.toml | 6 ++--- compiler/rustc_privacy/Cargo.toml | 2 +- compiler/rustc_proc_macro/Cargo.toml | 2 +- compiler/rustc_public/Cargo.toml | 4 +-- compiler/rustc_query_impl/Cargo.toml | 4 +-- compiler/rustc_query_system/Cargo.toml | 2 +- compiler/rustc_resolve/Cargo.toml | 10 +++---- compiler/rustc_sanitizers/Cargo.toml | 4 +-- compiler/rustc_serialize/Cargo.toml | 6 ++--- compiler/rustc_session/Cargo.toml | 8 +++--- compiler/rustc_span/Cargo.toml | 8 +++--- compiler/rustc_symbol_mangling/Cargo.toml | 4 +-- compiler/rustc_target/Cargo.toml | 6 ++--- compiler/rustc_thread_pool/Cargo.toml | 4 +-- compiler/rustc_trait_selection/Cargo.toml | 6 ++--- compiler/rustc_traits/Cargo.toml | 2 +- compiler/rustc_transmute/Cargo.toml | 4 +-- compiler/rustc_ty_utils/Cargo.toml | 4 +-- compiler/rustc_type_ir/Cargo.toml | 12 ++++----- compiler/rustc_type_ir_macros/Cargo.toml | 4 +-- src/librustdoc/Cargo.toml | 10 +++---- src/tools/build-manifest/Cargo.toml | 2 +- src/tools/collect-license-metadata/Cargo.toml | 2 +- src/tools/compiletest/Cargo.toml | 8 +++--- src/tools/coverage-dump/Cargo.toml | 4 +-- src/tools/features-status-dump/Cargo.toml | 2 +- src/tools/generate-copyright/Cargo.toml | 2 +- src/tools/jsondocck/Cargo.toml | 2 +- src/tools/jsondoclint/Cargo.toml | 4 +-- src/tools/lint-docs/Cargo.toml | 4 +-- src/tools/llvm-bitcode-linker/Cargo.toml | 4 +-- src/tools/opt-dist/Cargo.toml | 4 +-- src/tools/run-make-support/Cargo.toml | 4 +-- src/tools/tidy/Cargo.toml | 2 +- 76 files changed, 187 insertions(+), 212 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 2c5044f6a355..67c7a9d67edc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -59,33 +59,6 @@ exclude = [ "obj", ] -[workspace.dependencies] -# tidy-alphabetical-start -bitflags = "2.9.3" -derive-where = "1.6.0" -either = "1.15.0" -indexmap = "2.10.0" -itertools = "0.12.1" -# FIXME: Remove this pin once this rustix issue is resolved -# https://github.com/bytecodealliance/rustix/issues/1496 -libc = "=0.2.174" -measureme = "12.0.3" -memchr = "2.7.5" -odht = { version = "0.3.1", features = ["nightly"] } -polonius-engine = "0.13.0" -proc-macro2 = "1.0.101" -quote = "1.0.40" -rustc-demangle = "0.1.26" -rustc-hash = "2.1.1" -rustc-literal-escaper = "0.0.5" -rustc_apfloat = "0.2.3" -scoped-tls = "1.0.1" -serde_json = "1.0.142" -tempfile = "3.20.0" -thin-vec = "0.2.14" -tracing = "0.1.37" -# tidy-alphabetical-end - [profile.release.package.rustc_thread_pool] # The rustc fork of Rayon has deadlock detection code which intermittently # causes overflows in the CI (see https://github.com/rust-lang/rust/issues/90227) diff --git a/compiler/rustc_abi/Cargo.toml b/compiler/rustc_abi/Cargo.toml index 3de6d186b8ab..83d96d8d04da 100644 --- a/compiler/rustc_abi/Cargo.toml +++ b/compiler/rustc_abi/Cargo.toml @@ -5,7 +5,7 @@ edition = "2024" [dependencies] # tidy-alphabetical-start -bitflags.workspace = true +bitflags = "2.4.1" rand = { version = "0.9.0", default-features = false, optional = true } rand_xoshiro = { version = "0.7.0", optional = true } rustc_data_structures = { path = "../rustc_data_structures", optional = true } @@ -15,7 +15,7 @@ rustc_index = { path = "../rustc_index", default-features = false } rustc_macros = { path = "../rustc_macros", optional = true } rustc_serialize = { path = "../rustc_serialize", optional = true } rustc_span = { path = "../rustc_span", optional = true } -tracing.workspace = true +tracing = "0.1" # tidy-alphabetical-end [features] diff --git a/compiler/rustc_ast/Cargo.toml b/compiler/rustc_ast/Cargo.toml index 7f948a652204..155e14a3796e 100644 --- a/compiler/rustc_ast/Cargo.toml +++ b/compiler/rustc_ast/Cargo.toml @@ -5,9 +5,9 @@ edition = "2024" [dependencies] # tidy-alphabetical-start -bitflags.workspace = true -memchr.workspace = true -rustc-literal-escaper.workspace = true +bitflags = "2.4.1" +memchr = "2.7.4" +rustc-literal-escaper = "0.0.5" rustc_ast_ir = { path = "../rustc_ast_ir" } rustc_data_structures = { path = "../rustc_data_structures" } rustc_index = { path = "../rustc_index" } @@ -15,6 +15,6 @@ rustc_macros = { path = "../rustc_macros" } rustc_serialize = { path = "../rustc_serialize" } rustc_span = { path = "../rustc_span" } smallvec = { version = "1.8.1", features = ["union", "may_dangle"] } -thin-vec.workspace = true -tracing.workspace = true +thin-vec = "0.2.12" +tracing = "0.1" # tidy-alphabetical-end diff --git a/compiler/rustc_ast_lowering/Cargo.toml b/compiler/rustc_ast_lowering/Cargo.toml index 317742a3bb82..6ac258155fe9 100644 --- a/compiler/rustc_ast_lowering/Cargo.toml +++ b/compiler/rustc_ast_lowering/Cargo.toml @@ -24,6 +24,6 @@ rustc_session = { path = "../rustc_session" } rustc_span = { path = "../rustc_span" } rustc_target = { path = "../rustc_target" } smallvec = { version = "1.8.1", features = ["union", "may_dangle"] } -thin-vec.workspace = true -tracing.workspace = true +thin-vec = "0.2.12" +tracing = "0.1" # tidy-alphabetical-end diff --git a/compiler/rustc_ast_passes/Cargo.toml b/compiler/rustc_ast_passes/Cargo.toml index 6d2bcbed22bd..3e04f8b11ec9 100644 --- a/compiler/rustc_ast_passes/Cargo.toml +++ b/compiler/rustc_ast_passes/Cargo.toml @@ -5,7 +5,7 @@ edition = "2024" [dependencies] # tidy-alphabetical-start -itertools.workspace = true +itertools = "0.12" rustc_abi = { path = "../rustc_abi" } rustc_ast = { path = "../rustc_ast" } rustc_ast_pretty = { path = "../rustc_ast_pretty" } @@ -18,5 +18,5 @@ rustc_macros = { path = "../rustc_macros" } rustc_session = { path = "../rustc_session" } rustc_span = { path = "../rustc_span" } rustc_target = { path = "../rustc_target" } -thin-vec.workspace = true +thin-vec = "0.2.12" # tidy-alphabetical-end diff --git a/compiler/rustc_ast_pretty/Cargo.toml b/compiler/rustc_ast_pretty/Cargo.toml index 0c7e55305b48..b704040be961 100644 --- a/compiler/rustc_ast_pretty/Cargo.toml +++ b/compiler/rustc_ast_pretty/Cargo.toml @@ -5,7 +5,7 @@ edition = "2024" [dependencies] # tidy-alphabetical-start -itertools.workspace = true +itertools = "0.12" rustc_ast = { path = "../rustc_ast" } rustc_lexer = { path = "../rustc_lexer" } rustc_span = { path = "../rustc_span" } @@ -13,5 +13,5 @@ rustc_span = { path = "../rustc_span" } [dev-dependencies] # tidy-alphabetical-start -thin-vec.workspace = true +thin-vec = "0.2.12" # tidy-alphabetical-end diff --git a/compiler/rustc_attr_parsing/Cargo.toml b/compiler/rustc_attr_parsing/Cargo.toml index 8bfde43fd334..79193f394fe4 100644 --- a/compiler/rustc_attr_parsing/Cargo.toml +++ b/compiler/rustc_attr_parsing/Cargo.toml @@ -18,5 +18,5 @@ rustc_parse = { path = "../rustc_parse" } rustc_session = { path = "../rustc_session" } rustc_span = { path = "../rustc_span" } rustc_target = { path = "../rustc_target" } -thin-vec.workspace = true +thin-vec = "0.2.12" # tidy-alphabetical-end diff --git a/compiler/rustc_borrowck/Cargo.toml b/compiler/rustc_borrowck/Cargo.toml index 5f9dc41766bc..9e7d55180a23 100644 --- a/compiler/rustc_borrowck/Cargo.toml +++ b/compiler/rustc_borrowck/Cargo.toml @@ -5,9 +5,9 @@ edition = "2024" [dependencies] # tidy-alphabetical-start -either.workspace = true -itertools.workspace = true -polonius-engine.workspace = true +either = "1.5.0" +itertools = "0.12" +polonius-engine = "0.13.0" rustc_abi = { path = "../rustc_abi" } rustc_data_structures = { path = "../rustc_data_structures" } rustc_errors = { path = "../rustc_errors" } @@ -25,5 +25,5 @@ rustc_span = { path = "../rustc_span" } rustc_trait_selection = { path = "../rustc_trait_selection" } rustc_traits = { path = "../rustc_traits" } smallvec = { version = "1.8.1", features = ["union", "may_dangle"] } -tracing.workspace = true +tracing = "0.1" # tidy-alphabetical-end diff --git a/compiler/rustc_builtin_macros/Cargo.toml b/compiler/rustc_builtin_macros/Cargo.toml index 9ca44d671503..e56b9e641a10 100644 --- a/compiler/rustc_builtin_macros/Cargo.toml +++ b/compiler/rustc_builtin_macros/Cargo.toml @@ -30,6 +30,6 @@ rustc_session = { path = "../rustc_session" } rustc_span = { path = "../rustc_span" } rustc_target = { path = "../rustc_target" } smallvec = { version = "1.8.1", features = ["union", "may_dangle"] } -thin-vec.workspace = true -tracing.workspace = true +thin-vec = "0.2.12" +tracing = "0.1" # tidy-alphabetical-end diff --git a/compiler/rustc_codegen_llvm/Cargo.toml b/compiler/rustc_codegen_llvm/Cargo.toml index b04310f3d544..2d11628250cd 100644 --- a/compiler/rustc_codegen_llvm/Cargo.toml +++ b/compiler/rustc_codegen_llvm/Cargo.toml @@ -8,15 +8,15 @@ test = false [dependencies] # tidy-alphabetical-start -bitflags.workspace = true +bitflags = "2.4.1" # To avoid duplicate dependencies, this should match the version of gimli used # by `rustc_codegen_ssa` via its `thorin-dwp` dependency. gimli = "0.31" -itertools.workspace = true -libc.workspace = true -measureme.workspace = true +itertools = "0.12" +libc = "0.2" +measureme = "12.0.1" object = { version = "0.37.0", default-features = false, features = ["std", "read"] } -rustc-demangle.workspace = true +rustc-demangle = "0.1.21" rustc_abi = { path = "../rustc_abi" } rustc_ast = { path = "../rustc_ast" } rustc_codegen_ssa = { path = "../rustc_codegen_ssa" } @@ -38,9 +38,9 @@ rustc_span = { path = "../rustc_span" } rustc_symbol_mangling = { path = "../rustc_symbol_mangling" } rustc_target = { path = "../rustc_target" } serde = { version = "1", features = ["derive"] } -serde_json.workspace = true +serde_json = "1" smallvec = { version = "1.8.1", features = ["union", "may_dangle"] } -tracing.workspace = true +tracing = "0.1" # tidy-alphabetical-end [features] diff --git a/compiler/rustc_codegen_ssa/Cargo.toml b/compiler/rustc_codegen_ssa/Cargo.toml index 6f87b5749c6d..2dfbc5816432 100644 --- a/compiler/rustc_codegen_ssa/Cargo.toml +++ b/compiler/rustc_codegen_ssa/Cargo.toml @@ -6,12 +6,12 @@ edition = "2024" [dependencies] # tidy-alphabetical-start ar_archive_writer = "0.5" -bitflags.workspace = true +bitflags = "2.4.1" bstr = "1.11.3" # `cc` updates often break things, so we pin it here. Cargo enforces "max 1 semver-compat version # per crate", so if you change this, you need to also change it in `rustc_llvm`. cc = "=1.2.16" -itertools.workspace = true +itertools = "0.12" pathdiff = "0.2.0" regex = "1.4" rustc_abi = { path = "../rustc_abi" } @@ -37,18 +37,18 @@ rustc_span = { path = "../rustc_span" } rustc_symbol_mangling = { path = "../rustc_symbol_mangling" } rustc_target = { path = "../rustc_target" } rustc_trait_selection = { path = "../rustc_trait_selection" } -serde_json.workspace = true +serde_json = "1.0.59" smallvec = { version = "1.8.1", features = ["union", "may_dangle"] } -tempfile.workspace = true -thin-vec.workspace = true +tempfile = "3.2" +thin-vec = "0.2.12" thorin-dwp = "0.9" -tracing.workspace = true +tracing = "0.1" wasm-encoder = "0.219" # tidy-alphabetical-end [target.'cfg(unix)'.dependencies] # tidy-alphabetical-start -libc.workspace = true +libc = "0.2.50" # tidy-alphabetical-end [dependencies.object] diff --git a/compiler/rustc_const_eval/Cargo.toml b/compiler/rustc_const_eval/Cargo.toml index acf19b0f2fcd..51dcee8d8822 100644 --- a/compiler/rustc_const_eval/Cargo.toml +++ b/compiler/rustc_const_eval/Cargo.toml @@ -5,9 +5,9 @@ edition = "2024" [dependencies] # tidy-alphabetical-start -either.workspace = true +either = "1" rustc_abi = { path = "../rustc_abi" } -rustc_apfloat.workspace = true +rustc_apfloat = "0.2.0" rustc_ast = { path = "../rustc_ast" } rustc_data_structures = { path = "../rustc_data_structures" } rustc_errors = { path = "../rustc_errors" } @@ -22,5 +22,5 @@ rustc_session = { path = "../rustc_session" } rustc_span = { path = "../rustc_span" } rustc_target = { path = "../rustc_target" } rustc_trait_selection = { path = "../rustc_trait_selection" } -tracing.workspace = true +tracing = "0.1" # tidy-alphabetical-end diff --git a/compiler/rustc_data_structures/Cargo.toml b/compiler/rustc_data_structures/Cargo.toml index 852fc11350b1..c8296e05f6bd 100644 --- a/compiler/rustc_data_structures/Cargo.toml +++ b/compiler/rustc_data_structures/Cargo.toml @@ -6,15 +6,15 @@ edition = "2024" [dependencies] # tidy-alphabetical-start arrayvec = { version = "0.7", default-features = false } -bitflags.workspace = true -either.workspace = true +bitflags = "2.4.1" +either = "1.0" elsa = "1.11.0" ena = "0.14.3" -indexmap.workspace = true +indexmap = "2.4.0" jobserver_crate = { version = "0.1.28", package = "jobserver" } -measureme.workspace = true +measureme = "12.0.1" parking_lot = "0.12" -rustc-hash.workspace = true +rustc-hash = "2.0.0" rustc-stable-hash = { version = "0.1.0", features = ["nightly"] } rustc_arena = { path = "../rustc_arena" } rustc_graphviz = { path = "../rustc_graphviz" } @@ -25,9 +25,9 @@ rustc_serialize = { path = "../rustc_serialize" } rustc_thread_pool = { path = "../rustc_thread_pool" } smallvec = { version = "1.8.1", features = ["const_generics", "union", "may_dangle"] } stacker = "0.1.17" -tempfile.workspace = true -thin-vec.workspace = true -tracing.workspace = true +tempfile = "3.2" +thin-vec = "0.2.12" +tracing = "0.1" # tidy-alphabetical-end [dependencies.hashbrown] @@ -47,7 +47,7 @@ features = [ [target.'cfg(unix)'.dependencies] # tidy-alphabetical-start -libc.workspace = true +libc = "0.2" # tidy-alphabetical-end [target.'cfg(not(target_arch = "wasm32"))'.dependencies] diff --git a/compiler/rustc_driver_impl/Cargo.toml b/compiler/rustc_driver_impl/Cargo.toml index 196c8aa35471..ae1dbd2cf514 100644 --- a/compiler/rustc_driver_impl/Cargo.toml +++ b/compiler/rustc_driver_impl/Cargo.toml @@ -49,14 +49,14 @@ rustc_span = { path = "../rustc_span" } rustc_target = { path = "../rustc_target" } rustc_trait_selection = { path = "../rustc_trait_selection" } rustc_ty_utils = { path = "../rustc_ty_utils" } -serde_json.workspace = true +serde_json = "1.0.59" shlex = "1.0" -tracing.workspace = true +tracing = { version = "0.1.35" } # tidy-alphabetical-end [target.'cfg(all(unix, any(target_env = "gnu", target_os = "macos")))'.dependencies] # tidy-alphabetical-start -libc.workspace = true +libc = "0.2" # tidy-alphabetical-end [target.'cfg(windows)'.dependencies.windows] diff --git a/compiler/rustc_error_messages/Cargo.toml b/compiler/rustc_error_messages/Cargo.toml index 7d2dc20e1366..db22e065907e 100644 --- a/compiler/rustc_error_messages/Cargo.toml +++ b/compiler/rustc_error_messages/Cargo.toml @@ -17,6 +17,6 @@ rustc_data_structures = { path = "../rustc_data_structures" } rustc_macros = { path = "../rustc_macros" } rustc_serialize = { path = "../rustc_serialize" } rustc_span = { path = "../rustc_span" } -tracing.workspace = true +tracing = "0.1" unic-langid = { version = "0.9.0", features = ["macros"] } # tidy-alphabetical-end diff --git a/compiler/rustc_errors/Cargo.toml b/compiler/rustc_errors/Cargo.toml index 67a17ce88faa..7912b8e6098b 100644 --- a/compiler/rustc_errors/Cargo.toml +++ b/compiler/rustc_errors/Cargo.toml @@ -21,10 +21,10 @@ rustc_macros = { path = "../rustc_macros" } rustc_serialize = { path = "../rustc_serialize" } rustc_span = { path = "../rustc_span" } serde = { version = "1.0.125", features = ["derive"] } -serde_json.workspace = true +serde_json = "1.0.59" termcolor = "1.2.0" termize = "0.2" -tracing.workspace = true +tracing = "0.1" # tidy-alphabetical-end [target.'cfg(windows)'.dependencies.windows] diff --git a/compiler/rustc_expand/Cargo.toml b/compiler/rustc_expand/Cargo.toml index 9bb7143af51e..f897833d85c0 100644 --- a/compiler/rustc_expand/Cargo.toml +++ b/compiler/rustc_expand/Cargo.toml @@ -29,6 +29,6 @@ rustc_serialize = { path = "../rustc_serialize" } rustc_session = { path = "../rustc_session" } rustc_span = { path = "../rustc_span" } smallvec = { version = "1.8.1", features = ["union", "may_dangle"] } -thin-vec.workspace = true -tracing.workspace = true +thin-vec = "0.2.12" +tracing = "0.1" # tidy-alphabetical-end diff --git a/compiler/rustc_feature/Cargo.toml b/compiler/rustc_feature/Cargo.toml index b58f23758524..a4746ac455c1 100644 --- a/compiler/rustc_feature/Cargo.toml +++ b/compiler/rustc_feature/Cargo.toml @@ -9,5 +9,5 @@ rustc_data_structures = { path = "../rustc_data_structures" } rustc_hir = { path = "../rustc_hir" } rustc_span = { path = "../rustc_span" } serde = { version = "1.0.125", features = ["derive"] } -serde_json.workspace = true +serde_json = "1.0.59" # tidy-alphabetical-end diff --git a/compiler/rustc_fluent_macro/Cargo.toml b/compiler/rustc_fluent_macro/Cargo.toml index 60afd9aca87e..d7ef4280aef0 100644 --- a/compiler/rustc_fluent_macro/Cargo.toml +++ b/compiler/rustc_fluent_macro/Cargo.toml @@ -11,8 +11,8 @@ proc-macro = true annotate-snippets = "0.11" fluent-bundle = "0.16" fluent-syntax = "0.12" -proc-macro2.workspace = true -quote.workspace = true +proc-macro2 = "1" +quote = "1" syn = { version = "2", features = ["full"] } unic-langid = { version = "0.9.0", features = ["macros"] } # tidy-alphabetical-end diff --git a/compiler/rustc_fs_util/Cargo.toml b/compiler/rustc_fs_util/Cargo.toml index 37970e81fead..90a6acade8b0 100644 --- a/compiler/rustc_fs_util/Cargo.toml +++ b/compiler/rustc_fs_util/Cargo.toml @@ -5,5 +5,5 @@ edition = "2024" [dependencies] # tidy-alphabetical-start -tempfile.workspace = true +tempfile = "3.7.1" # tidy-alphabetical-end diff --git a/compiler/rustc_hir/Cargo.toml b/compiler/rustc_hir/Cargo.toml index e74fcfe74559..1008a3e787d0 100644 --- a/compiler/rustc_hir/Cargo.toml +++ b/compiler/rustc_hir/Cargo.toml @@ -5,8 +5,8 @@ edition = "2024" [dependencies] # tidy-alphabetical-start -bitflags.workspace = true -odht.workspace = true +bitflags = "2.9.1" +odht = { version = "0.3.1", features = ["nightly"] } rustc_abi = { path = "../rustc_abi" } rustc_arena = { path = "../rustc_arena" } rustc_ast = { path = "../rustc_ast" } @@ -21,6 +21,6 @@ rustc_serialize = { path = "../rustc_serialize" } rustc_span = { path = "../rustc_span" } rustc_target = { path = "../rustc_target" } smallvec = { version = "1.8.1", features = ["union", "may_dangle"] } -thin-vec.workspace = true -tracing.workspace = true +thin-vec = "0.2.12" +tracing = "0.1" # tidy-alphabetical-end diff --git a/compiler/rustc_hir_analysis/Cargo.toml b/compiler/rustc_hir_analysis/Cargo.toml index bb86beb22514..e5017794d8f2 100644 --- a/compiler/rustc_hir_analysis/Cargo.toml +++ b/compiler/rustc_hir_analysis/Cargo.toml @@ -9,7 +9,7 @@ doctest = false [dependencies] # tidy-alphabetical-start -itertools.workspace = true +itertools = "0.12" rustc_abi = { path = "../rustc_abi" } rustc_arena = { path = "../rustc_arena" } rustc_ast = { path = "../rustc_ast" } @@ -29,5 +29,5 @@ rustc_span = { path = "../rustc_span" } rustc_target = { path = "../rustc_target" } rustc_trait_selection = { path = "../rustc_trait_selection" } smallvec = { version = "1.8.1", features = ["union", "may_dangle"] } -tracing.workspace = true +tracing = "0.1" # tidy-alphabetical-end diff --git a/compiler/rustc_hir_typeck/Cargo.toml b/compiler/rustc_hir_typeck/Cargo.toml index 5af0c6134cab..f00125c3e090 100644 --- a/compiler/rustc_hir_typeck/Cargo.toml +++ b/compiler/rustc_hir_typeck/Cargo.toml @@ -5,7 +5,7 @@ edition = "2024" [dependencies] # tidy-alphabetical-start -itertools.workspace = true +itertools = "0.12" rustc_abi = { path = "../rustc_abi" } rustc_ast = { path = "../rustc_ast" } rustc_attr_parsing = { path = "../rustc_attr_parsing" } @@ -25,5 +25,5 @@ rustc_span = { path = "../rustc_span" } rustc_target = { path = "../rustc_target" } rustc_trait_selection = { path = "../rustc_trait_selection" } smallvec = { version = "1.8.1", features = ["union", "may_dangle"] } -tracing.workspace = true +tracing = "0.1" # tidy-alphabetical-end diff --git a/compiler/rustc_incremental/Cargo.toml b/compiler/rustc_incremental/Cargo.toml index 8d7f2eb84147..db0a58418875 100644 --- a/compiler/rustc_incremental/Cargo.toml +++ b/compiler/rustc_incremental/Cargo.toml @@ -19,6 +19,6 @@ rustc_middle = { path = "../rustc_middle" } rustc_serialize = { path = "../rustc_serialize" } rustc_session = { path = "../rustc_session" } rustc_span = { path = "../rustc_span" } -thin-vec.workspace = true -tracing.workspace = true +thin-vec = "0.2.12" +tracing = "0.1" # tidy-alphabetical-end diff --git a/compiler/rustc_index_macros/Cargo.toml b/compiler/rustc_index_macros/Cargo.toml index 8593bde26151..34f3109a526b 100644 --- a/compiler/rustc_index_macros/Cargo.toml +++ b/compiler/rustc_index_macros/Cargo.toml @@ -8,8 +8,8 @@ proc-macro = true [dependencies] # tidy-alphabetical-start -proc-macro2.workspace = true -quote.workspace = true +proc-macro2 = "1" +quote = "1" syn = { version = "2.0.9", features = ["full", "extra-traits"] } # tidy-alphabetical-end diff --git a/compiler/rustc_infer/Cargo.toml b/compiler/rustc_infer/Cargo.toml index 6d97fa6af1f4..08c036148849 100644 --- a/compiler/rustc_infer/Cargo.toml +++ b/compiler/rustc_infer/Cargo.toml @@ -18,6 +18,6 @@ rustc_middle = { path = "../rustc_middle" } rustc_span = { path = "../rustc_span" } rustc_type_ir = { path = "../rustc_type_ir" } smallvec = { version = "1.8.1", features = ["union", "may_dangle"] } -thin-vec.workspace = true -tracing.workspace = true +thin-vec = "0.2.12" +tracing = "0.1" # tidy-alphabetical-end diff --git a/compiler/rustc_interface/Cargo.toml b/compiler/rustc_interface/Cargo.toml index 40152e78f8aa..473ac5e0cea4 100644 --- a/compiler/rustc_interface/Cargo.toml +++ b/compiler/rustc_interface/Cargo.toml @@ -46,7 +46,7 @@ rustc_thread_pool = { path = "../rustc_thread_pool" } rustc_trait_selection = { path = "../rustc_trait_selection" } rustc_traits = { path = "../rustc_traits" } rustc_ty_utils = { path = "../rustc_ty_utils" } -tracing.workspace = true +tracing = "0.1" # tidy-alphabetical-end [dev-dependencies] diff --git a/compiler/rustc_lexer/Cargo.toml b/compiler/rustc_lexer/Cargo.toml index e0019fb18216..343b81bd1717 100644 --- a/compiler/rustc_lexer/Cargo.toml +++ b/compiler/rustc_lexer/Cargo.toml @@ -14,7 +14,7 @@ Rust lexer used by rustc. No stability guarantees are provided. # Note that this crate purposefully does not depend on other rustc crates [dependencies] -memchr.workspace = true +memchr = "2.7.4" unicode-properties = { version = "0.1.0", default-features = false, features = ["emoji"] } unicode-xid = "0.2.0" diff --git a/compiler/rustc_lint/Cargo.toml b/compiler/rustc_lint/Cargo.toml index 7900e4b9ab22..7718f16984da 100644 --- a/compiler/rustc_lint/Cargo.toml +++ b/compiler/rustc_lint/Cargo.toml @@ -24,6 +24,6 @@ rustc_span = { path = "../rustc_span" } rustc_target = { path = "../rustc_target" } rustc_trait_selection = { path = "../rustc_trait_selection" } smallvec = { version = "1.8.1", features = ["union", "may_dangle"] } -tracing.workspace = true +tracing = "0.1" unicode-security = "0.1.0" # tidy-alphabetical-end diff --git a/compiler/rustc_llvm/Cargo.toml b/compiler/rustc_llvm/Cargo.toml index e74de453be21..cd352ce3d0f4 100644 --- a/compiler/rustc_llvm/Cargo.toml +++ b/compiler/rustc_llvm/Cargo.toml @@ -5,7 +5,7 @@ edition = "2024" [dependencies] # tidy-alphabetical-start -libc.workspace = true +libc = "0.2.73" # tidy-alphabetical-end [build-dependencies] diff --git a/compiler/rustc_log/Cargo.toml b/compiler/rustc_log/Cargo.toml index e9d7b4723f82..c673d51a1d45 100644 --- a/compiler/rustc_log/Cargo.toml +++ b/compiler/rustc_log/Cargo.toml @@ -5,10 +5,10 @@ edition = "2024" [dependencies] # tidy-alphabetical-start +tracing = "0.1.28" tracing-core = "=0.1.30" # FIXME(Nilstrieb) tracing has a deadlock: https://github.com/tokio-rs/tracing/issues/2635 tracing-subscriber = { version = "0.3.3", default-features = false, features = ["fmt", "env-filter", "smallvec", "parking_lot", "ansi"] } tracing-tree = "0.3.1" -tracing.workspace = true # tidy-alphabetical-end [features] diff --git a/compiler/rustc_macros/Cargo.toml b/compiler/rustc_macros/Cargo.toml index 5add2691b886..f9d3b7583590 100644 --- a/compiler/rustc_macros/Cargo.toml +++ b/compiler/rustc_macros/Cargo.toml @@ -8,8 +8,8 @@ proc-macro = true [dependencies] # tidy-alphabetical-start -proc-macro2.workspace = true -quote.workspace = true +proc-macro2 = "1" +quote = "1" syn = { version = "2.0.9", features = ["full"] } synstructure = "0.13.0" # tidy-alphabetical-end diff --git a/compiler/rustc_metadata/Cargo.toml b/compiler/rustc_metadata/Cargo.toml index a8f3dd18353c..1b40d9f684ef 100644 --- a/compiler/rustc_metadata/Cargo.toml +++ b/compiler/rustc_metadata/Cargo.toml @@ -5,9 +5,9 @@ edition = "2024" [dependencies] # tidy-alphabetical-start -bitflags.workspace = true +bitflags = "2.4.1" libloading = "0.8.0" -odht.workspace = true +odht = { version = "0.3.1", features = ["nightly"] } rustc_abi = { path = "../rustc_abi" } rustc_ast = { path = "../rustc_ast" } rustc_attr_parsing = { path = "../rustc_attr_parsing" } @@ -30,11 +30,11 @@ rustc_serialize = { path = "../rustc_serialize" } rustc_session = { path = "../rustc_session" } rustc_span = { path = "../rustc_span" } rustc_target = { path = "../rustc_target" } -tempfile.workspace = true -tracing.workspace = true +tempfile = "3.7.1" +tracing = "0.1" # tidy-alphabetical-end [target.'cfg(target_os = "aix")'.dependencies] # tidy-alphabetical-start -libc.workspace = true +libc = "0.2" # tidy-alphabetical-end diff --git a/compiler/rustc_middle/Cargo.toml b/compiler/rustc_middle/Cargo.toml index f08324055672..fbcce16cedca 100644 --- a/compiler/rustc_middle/Cargo.toml +++ b/compiler/rustc_middle/Cargo.toml @@ -5,12 +5,12 @@ edition = "2024" [dependencies] # tidy-alphabetical-start -bitflags.workspace = true -either.workspace = true +bitflags = "2.4.1" +either = "1.5.0" gsgdt = "0.1.2" -polonius-engine.workspace = true +polonius-engine = "0.13.0" rustc_abi = { path = "../rustc_abi" } -rustc_apfloat.workspace = true +rustc_apfloat = "0.2.0" rustc_arena = { path = "../rustc_arena" } rustc_ast = { path = "../rustc_ast" } rustc_ast_ir = { path = "../rustc_ast_ir" } @@ -34,8 +34,8 @@ rustc_target = { path = "../rustc_target" } rustc_thread_pool = { path = "../rustc_thread_pool" } rustc_type_ir = { path = "../rustc_type_ir" } smallvec = { version = "1.8.1", features = ["union", "may_dangle"] } -thin-vec.workspace = true -tracing.workspace = true +thin-vec = "0.2.12" +tracing = "0.1" # tidy-alphabetical-end [features] diff --git a/compiler/rustc_mir_build/Cargo.toml b/compiler/rustc_mir_build/Cargo.toml index 440cb0bdbf3e..f756f0a19ee9 100644 --- a/compiler/rustc_mir_build/Cargo.toml +++ b/compiler/rustc_mir_build/Cargo.toml @@ -5,9 +5,9 @@ edition = "2024" [dependencies] # tidy-alphabetical-start -itertools.workspace = true +itertools = "0.12" rustc_abi = { path = "../rustc_abi" } -rustc_apfloat.workspace = true +rustc_apfloat = "0.2.0" rustc_arena = { path = "../rustc_arena" } rustc_ast = { path = "../rustc_ast" } rustc_data_structures = { path = "../rustc_data_structures" } @@ -23,5 +23,5 @@ rustc_pattern_analysis = { path = "../rustc_pattern_analysis" } rustc_session = { path = "../rustc_session" } rustc_span = { path = "../rustc_span" } rustc_trait_selection = { path = "../rustc_trait_selection" } -tracing.workspace = true +tracing = "0.1" # tidy-alphabetical-end diff --git a/compiler/rustc_mir_dataflow/Cargo.toml b/compiler/rustc_mir_dataflow/Cargo.toml index 11713bb77f1e..9621f9f20bdc 100644 --- a/compiler/rustc_mir_dataflow/Cargo.toml +++ b/compiler/rustc_mir_dataflow/Cargo.toml @@ -5,7 +5,7 @@ edition = "2024" [dependencies] # tidy-alphabetical-start -polonius-engine.workspace = true +polonius-engine = "0.13.0" regex = "1" rustc_abi = { path = "../rustc_abi" } rustc_ast = { path = "../rustc_ast" } @@ -18,5 +18,5 @@ rustc_macros = { path = "../rustc_macros" } rustc_middle = { path = "../rustc_middle" } rustc_span = { path = "../rustc_span" } smallvec = { version = "1.8.1", features = ["union", "may_dangle"] } -tracing.workspace = true +tracing = "0.1" # tidy-alphabetical-end diff --git a/compiler/rustc_mir_transform/Cargo.toml b/compiler/rustc_mir_transform/Cargo.toml index 99ef67e2625d..08c43a4648c6 100644 --- a/compiler/rustc_mir_transform/Cargo.toml +++ b/compiler/rustc_mir_transform/Cargo.toml @@ -5,8 +5,8 @@ edition = "2024" [dependencies] # tidy-alphabetical-start -either.workspace = true -itertools.workspace = true +either = "1" +itertools = "0.12" rustc_abi = { path = "../rustc_abi" } rustc_arena = { path = "../rustc_arena" } rustc_ast = { path = "../rustc_ast" } @@ -26,5 +26,5 @@ rustc_span = { path = "../rustc_span" } rustc_target = { path = "../rustc_target" } rustc_trait_selection = { path = "../rustc_trait_selection" } smallvec = { version = "1.8.1", features = ["union", "may_dangle"] } -tracing.workspace = true +tracing = "0.1" # tidy-alphabetical-end diff --git a/compiler/rustc_monomorphize/Cargo.toml b/compiler/rustc_monomorphize/Cargo.toml index 78266d3c6d85..09a55f0b5f8d 100644 --- a/compiler/rustc_monomorphize/Cargo.toml +++ b/compiler/rustc_monomorphize/Cargo.toml @@ -16,6 +16,6 @@ rustc_session = { path = "../rustc_session" } rustc_span = { path = "../rustc_span" } rustc_target = { path = "../rustc_target" } serde = "1" -serde_json.workspace = true -tracing.workspace = true +serde_json = "1" +tracing = "0.1" # tidy-alphabetical-end diff --git a/compiler/rustc_next_trait_solver/Cargo.toml b/compiler/rustc_next_trait_solver/Cargo.toml index 43db90c08f3f..05bcabad02f9 100644 --- a/compiler/rustc_next_trait_solver/Cargo.toml +++ b/compiler/rustc_next_trait_solver/Cargo.toml @@ -5,13 +5,13 @@ edition = "2024" [dependencies] # tidy-alphabetical-start -derive-where.workspace = true +derive-where = "1.2.7" rustc_data_structures = { path = "../rustc_data_structures", optional = true } rustc_index = { path = "../rustc_index", default-features = false } rustc_macros = { path = "../rustc_macros", optional = true } rustc_type_ir = { path = "../rustc_type_ir", default-features = false } rustc_type_ir_macros = { path = "../rustc_type_ir_macros" } -tracing.workspace = true +tracing = "0.1" # tidy-alphabetical-end [features] diff --git a/compiler/rustc_parse/Cargo.toml b/compiler/rustc_parse/Cargo.toml index 7cb4ae7ff5f8..6d738a103715 100644 --- a/compiler/rustc_parse/Cargo.toml +++ b/compiler/rustc_parse/Cargo.toml @@ -5,8 +5,8 @@ edition = "2024" [dependencies] # tidy-alphabetical-start -bitflags.workspace = true -rustc-literal-escaper.workspace = true +bitflags = "2.4.1" +rustc-literal-escaper = "0.0.5" rustc_ast = { path = "../rustc_ast" } rustc_ast_pretty = { path = "../rustc_ast_pretty" } rustc_data_structures = { path = "../rustc_data_structures" } @@ -18,8 +18,8 @@ rustc_lexer = { path = "../rustc_lexer" } rustc_macros = { path = "../rustc_macros" } rustc_session = { path = "../rustc_session" } rustc_span = { path = "../rustc_span" } -thin-vec.workspace = true -tracing.workspace = true +thin-vec = "0.2.12" +tracing = "0.1" unicode-normalization = "0.1.11" unicode-width = "0.2.0" # tidy-alphabetical-end diff --git a/compiler/rustc_parse_format/Cargo.toml b/compiler/rustc_parse_format/Cargo.toml index 645e34b6e322..d178fcda1fb9 100644 --- a/compiler/rustc_parse_format/Cargo.toml +++ b/compiler/rustc_parse_format/Cargo.toml @@ -5,7 +5,7 @@ edition = "2024" [dependencies] # tidy-alphabetical-start -rustc-literal-escaper.workspace = true +rustc-literal-escaper = "0.0.5" rustc_lexer = { path = "../rustc_lexer" } # tidy-alphabetical-end diff --git a/compiler/rustc_passes/Cargo.toml b/compiler/rustc_passes/Cargo.toml index c74608a61467..ba81ef3103bd 100644 --- a/compiler/rustc_passes/Cargo.toml +++ b/compiler/rustc_passes/Cargo.toml @@ -24,5 +24,5 @@ rustc_session = { path = "../rustc_session" } rustc_span = { path = "../rustc_span" } rustc_target = { path = "../rustc_target" } rustc_trait_selection = { path = "../rustc_trait_selection" } -tracing.workspace = true +tracing = "0.1" # tidy-alphabetical-end diff --git a/compiler/rustc_pattern_analysis/Cargo.toml b/compiler/rustc_pattern_analysis/Cargo.toml index e4909ab6d162..a59f7bbeb9e5 100644 --- a/compiler/rustc_pattern_analysis/Cargo.toml +++ b/compiler/rustc_pattern_analysis/Cargo.toml @@ -5,9 +5,9 @@ edition = "2024" [dependencies] # tidy-alphabetical-start -rustc-hash.workspace = true +rustc-hash = "2.0.0" rustc_abi = { path = "../rustc_abi", optional = true } -rustc_apfloat.workspace = true +rustc_apfloat = "0.2.0" rustc_arena = { path = "../rustc_arena", optional = true } rustc_data_structures = { path = "../rustc_data_structures", optional = true } rustc_errors = { path = "../rustc_errors", optional = true } @@ -19,7 +19,7 @@ rustc_middle = { path = "../rustc_middle", optional = true } rustc_session = { path = "../rustc_session", optional = true } rustc_span = { path = "../rustc_span", optional = true } smallvec = { version = "1.8.1", features = ["union"] } -tracing.workspace = true +tracing = "0.1" # tidy-alphabetical-end [dev-dependencies] diff --git a/compiler/rustc_privacy/Cargo.toml b/compiler/rustc_privacy/Cargo.toml index 7de58132e134..c8bfdb913041 100644 --- a/compiler/rustc_privacy/Cargo.toml +++ b/compiler/rustc_privacy/Cargo.toml @@ -15,5 +15,5 @@ rustc_middle = { path = "../rustc_middle" } rustc_session = { path = "../rustc_session" } rustc_span = { path = "../rustc_span" } rustc_ty_utils = { path = "../rustc_ty_utils" } -tracing.workspace = true +tracing = "0.1" # tidy-alphabetical-end diff --git a/compiler/rustc_proc_macro/Cargo.toml b/compiler/rustc_proc_macro/Cargo.toml index 99e7fc7abc6d..beb95aa3b52f 100644 --- a/compiler/rustc_proc_macro/Cargo.toml +++ b/compiler/rustc_proc_macro/Cargo.toml @@ -16,7 +16,7 @@ doctest = false [dependencies] # tidy-alphabetical-start -rustc-literal-escaper.workspace = true +rustc-literal-escaper = "0.0.5" # tidy-alphabetical-end [features] diff --git a/compiler/rustc_public/Cargo.toml b/compiler/rustc_public/Cargo.toml index e67e4fe67396..70af30c1a5f4 100644 --- a/compiler/rustc_public/Cargo.toml +++ b/compiler/rustc_public/Cargo.toml @@ -12,9 +12,9 @@ rustc_public_bridge = { path = "../rustc_public_bridge" } rustc_session = { path = "../rustc_session" } rustc_span = { path = "../rustc_span" } rustc_target = { path = "../rustc_target" } -scoped-tls.workspace = true +scoped-tls = "1.0" serde = { version = "1.0.125", features = [ "derive" ] } -tracing.workspace = true +tracing = "0.1" # tidy-alphabetical-end [features] diff --git a/compiler/rustc_query_impl/Cargo.toml b/compiler/rustc_query_impl/Cargo.toml index 3d5cf0eb72df..e5cceacf15da 100644 --- a/compiler/rustc_query_impl/Cargo.toml +++ b/compiler/rustc_query_impl/Cargo.toml @@ -5,7 +5,7 @@ edition = "2024" [dependencies] # tidy-alphabetical-start -measureme.workspace = true +measureme = "12.0.1" rustc_data_structures = { path = "../rustc_data_structures" } rustc_hashes = { path = "../rustc_hashes" } rustc_hir = { path = "../rustc_hir" } @@ -15,5 +15,5 @@ rustc_query_system = { path = "../rustc_query_system" } rustc_serialize = { path = "../rustc_serialize" } rustc_session = { path = "../rustc_session" } rustc_span = { path = "../rustc_span" } -tracing.workspace = true +tracing = "0.1" # tidy-alphabetical-end diff --git a/compiler/rustc_query_system/Cargo.toml b/compiler/rustc_query_system/Cargo.toml index 0df933bc81c0..7480ba03474f 100644 --- a/compiler/rustc_query_system/Cargo.toml +++ b/compiler/rustc_query_system/Cargo.toml @@ -21,7 +21,7 @@ rustc_session = { path = "../rustc_session" } rustc_span = { path = "../rustc_span" } rustc_thread_pool = { path = "../rustc_thread_pool" } smallvec = { version = "1.8.1", features = ["union", "may_dangle"] } -tracing.workspace = true +tracing = "0.1" # tidy-alphabetical-end [dependencies.hashbrown] diff --git a/compiler/rustc_resolve/Cargo.toml b/compiler/rustc_resolve/Cargo.toml index 4da4c0840dfa..eb98a6e85c06 100644 --- a/compiler/rustc_resolve/Cargo.toml +++ b/compiler/rustc_resolve/Cargo.toml @@ -5,9 +5,9 @@ edition = "2024" [dependencies] # tidy-alphabetical-start -bitflags.workspace = true -indexmap.workspace = true -itertools.workspace = true +bitflags = "2.4.1" +indexmap = "2.4.0" +itertools = "0.12" pulldown-cmark = { version = "0.11", features = ["html"], default-features = false } rustc_arena = { path = "../rustc_arena" } rustc_ast = { path = "../rustc_ast" } @@ -27,6 +27,6 @@ rustc_query_system = { path = "../rustc_query_system" } rustc_session = { path = "../rustc_session" } rustc_span = { path = "../rustc_span" } smallvec = { version = "1.8.1", features = ["union", "may_dangle"] } -thin-vec.workspace = true -tracing.workspace = true +thin-vec = "0.2.12" +tracing = "0.1" # tidy-alphabetical-end diff --git a/compiler/rustc_sanitizers/Cargo.toml b/compiler/rustc_sanitizers/Cargo.toml index 3dbeaa435f30..9069d2c233db 100644 --- a/compiler/rustc_sanitizers/Cargo.toml +++ b/compiler/rustc_sanitizers/Cargo.toml @@ -5,7 +5,7 @@ edition = "2024" [dependencies] # tidy-alphabetical-start -bitflags.workspace = true +bitflags = "2.5.0" rustc_abi = { path = "../rustc_abi" } rustc_data_structures = { path = "../rustc_data_structures" } rustc_hir = { path = "../rustc_hir" } @@ -13,6 +13,6 @@ rustc_middle = { path = "../rustc_middle" } rustc_span = { path = "../rustc_span" } rustc_target = { path = "../rustc_target" } rustc_trait_selection = { path = "../rustc_trait_selection" } -tracing.workspace = true +tracing = "0.1" twox-hash = "1.6.3" # tidy-alphabetical-end diff --git a/compiler/rustc_serialize/Cargo.toml b/compiler/rustc_serialize/Cargo.toml index 853f87ebed96..948242352e7a 100644 --- a/compiler/rustc_serialize/Cargo.toml +++ b/compiler/rustc_serialize/Cargo.toml @@ -5,14 +5,14 @@ edition = "2024" [dependencies] # tidy-alphabetical-start -indexmap.workspace = true +indexmap = "2.0.0" rustc_hashes = { path = "../rustc_hashes" } smallvec = { version = "1.8.1", features = ["union", "may_dangle"] } -thin-vec.workspace = true +thin-vec = "0.2.12" # tidy-alphabetical-end [dev-dependencies] # tidy-alphabetical-start rustc_macros = { path = "../rustc_macros" } -tempfile.workspace = true +tempfile = "3.2" # tidy-alphabetical-end diff --git a/compiler/rustc_session/Cargo.toml b/compiler/rustc_session/Cargo.toml index 5870fb29ae83..60d56b1b808d 100644 --- a/compiler/rustc_session/Cargo.toml +++ b/compiler/rustc_session/Cargo.toml @@ -5,7 +5,7 @@ edition = "2024" [dependencies] # tidy-alphabetical-start -bitflags.workspace = true +bitflags = "2.4.1" getopts = "0.2" rand = "0.9.0" rustc_abi = { path = "../rustc_abi" } @@ -23,12 +23,14 @@ rustc_serialize = { path = "../rustc_serialize" } rustc_span = { path = "../rustc_span" } rustc_target = { path = "../rustc_target" } termize = "0.2" -tracing.workspace = true +tracing = "0.1" # tidy-alphabetical-end [target.'cfg(unix)'.dependencies] +# FIXME: Remove this pin once this rustix issue is resolved +# https://github.com/bytecodealliance/rustix/issues/1496 # tidy-alphabetical-start -libc.workspace = true +libc = "=0.2.174" # tidy-alphabetical-end [target.'cfg(windows)'.dependencies.windows] diff --git a/compiler/rustc_span/Cargo.toml b/compiler/rustc_span/Cargo.toml index da6f2101d234..43a2d692577e 100644 --- a/compiler/rustc_span/Cargo.toml +++ b/compiler/rustc_span/Cargo.toml @@ -6,8 +6,8 @@ edition = "2024" [dependencies] # tidy-alphabetical-start blake3 = "1.5.2" -derive-where.workspace = true -indexmap.workspace = true +derive-where = "1.2.7" +indexmap = { version = "2.0.0" } itoa = "1.0" md5 = { package = "md-5", version = "0.10.0" } rustc_arena = { path = "../rustc_arena" } @@ -16,9 +16,9 @@ rustc_hashes = { path = "../rustc_hashes" } rustc_index = { path = "../rustc_index" } rustc_macros = { path = "../rustc_macros" } rustc_serialize = { path = "../rustc_serialize" } -scoped-tls.workspace = true +scoped-tls = "1.0" sha1 = "0.10.0" sha2 = "0.10.1" -tracing.workspace = true +tracing = "0.1" unicode-width = "0.2.0" # tidy-alphabetical-end diff --git a/compiler/rustc_symbol_mangling/Cargo.toml b/compiler/rustc_symbol_mangling/Cargo.toml index 0ceac4b3e1b3..0df9c7682bf8 100644 --- a/compiler/rustc_symbol_mangling/Cargo.toml +++ b/compiler/rustc_symbol_mangling/Cargo.toml @@ -6,7 +6,7 @@ edition = "2024" [dependencies] # tidy-alphabetical-start punycode = "0.4.0" -rustc-demangle.workspace = true +rustc-demangle = "0.1.21" rustc_abi = { path = "../rustc_abi" } rustc_data_structures = { path = "../rustc_data_structures" } rustc_errors = { path = "../rustc_errors" } @@ -15,5 +15,5 @@ rustc_hir = { path = "../rustc_hir" } rustc_middle = { path = "../rustc_middle" } rustc_session = { path = "../rustc_session" } rustc_span = { path = "../rustc_span" } -tracing.workspace = true +tracing = "0.1" # tidy-alphabetical-end diff --git a/compiler/rustc_target/Cargo.toml b/compiler/rustc_target/Cargo.toml index ed59ee2a5756..7fabb227d9a5 100644 --- a/compiler/rustc_target/Cargo.toml +++ b/compiler/rustc_target/Cargo.toml @@ -5,7 +5,7 @@ edition = "2024" [dependencies] # tidy-alphabetical-start -bitflags.workspace = true +bitflags = "2.4.1" object = { version = "0.37.0", default-features = false, features = ["elf", "macho"] } rustc_abi = { path = "../rustc_abi" } rustc_data_structures = { path = "../rustc_data_structures" } @@ -16,8 +16,8 @@ rustc_serialize = { path = "../rustc_serialize" } rustc_span = { path = "../rustc_span" } serde = "1.0.219" serde_derive = "1.0.219" -serde_json.workspace = true +serde_json = "1.0.59" serde_path_to_error = "0.1.17" -tracing.workspace = true +tracing = "0.1" # tidy-alphabetical-end diff --git a/compiler/rustc_thread_pool/Cargo.toml b/compiler/rustc_thread_pool/Cargo.toml index 8e8c6469512b..c92984470b7a 100644 --- a/compiler/rustc_thread_pool/Cargo.toml +++ b/compiler/rustc_thread_pool/Cargo.toml @@ -20,10 +20,10 @@ smallvec = "1.8.1" [dev-dependencies] rand = "0.9" rand_xorshift = "0.4" -scoped-tls.workspace = true +scoped-tls = "1.0" [target.'cfg(unix)'.dev-dependencies] -libc.workspace = true +libc = "0.2" [[test]] name = "stack_overflow_crash" diff --git a/compiler/rustc_trait_selection/Cargo.toml b/compiler/rustc_trait_selection/Cargo.toml index 6b79b98d1bf5..1071105522d1 100644 --- a/compiler/rustc_trait_selection/Cargo.toml +++ b/compiler/rustc_trait_selection/Cargo.toml @@ -5,7 +5,7 @@ edition = "2024" [dependencies] # tidy-alphabetical-start -itertools.workspace = true +itertools = "0.12" rustc_abi = { path = "../rustc_abi" } rustc_ast = { path = "../rustc_ast" } rustc_data_structures = { path = "../rustc_data_structures" } @@ -21,6 +21,6 @@ rustc_session = { path = "../rustc_session" } rustc_span = { path = "../rustc_span" } rustc_transmute = { path = "../rustc_transmute", features = ["rustc"] } smallvec = { version = "1.8.1", features = ["union", "may_dangle"] } -thin-vec.workspace = true -tracing.workspace = true +thin-vec = "0.2" +tracing = "0.1" # tidy-alphabetical-end diff --git a/compiler/rustc_traits/Cargo.toml b/compiler/rustc_traits/Cargo.toml index 24360a94cc7f..9f40f4d5c23e 100644 --- a/compiler/rustc_traits/Cargo.toml +++ b/compiler/rustc_traits/Cargo.toml @@ -10,5 +10,5 @@ rustc_infer = { path = "../rustc_infer" } rustc_middle = { path = "../rustc_middle" } rustc_span = { path = "../rustc_span" } rustc_trait_selection = { path = "../rustc_trait_selection" } -tracing.workspace = true +tracing = "0.1" # tidy-alphabetical-end diff --git a/compiler/rustc_transmute/Cargo.toml b/compiler/rustc_transmute/Cargo.toml index 2ac2b46cc58f..e61717e5e9ce 100644 --- a/compiler/rustc_transmute/Cargo.toml +++ b/compiler/rustc_transmute/Cargo.toml @@ -11,12 +11,12 @@ rustc_hir = { path = "../rustc_hir", optional = true } rustc_middle = { path = "../rustc_middle", optional = true } rustc_span = { path = "../rustc_span", optional = true } smallvec = "1.8.1" -tracing.workspace = true +tracing = "0.1" # tidy-alphabetical-end [dev-dependencies] # tidy-alphabetical-start -itertools.workspace = true +itertools = "0.12" # tidy-alphabetical-end [features] diff --git a/compiler/rustc_ty_utils/Cargo.toml b/compiler/rustc_ty_utils/Cargo.toml index 394cde5a3234..ce08b300cc80 100644 --- a/compiler/rustc_ty_utils/Cargo.toml +++ b/compiler/rustc_ty_utils/Cargo.toml @@ -5,7 +5,7 @@ edition = "2024" [dependencies] # tidy-alphabetical-start -itertools.workspace = true +itertools = "0.12" rustc_abi = { path = "../rustc_abi" } rustc_data_structures = { path = "../rustc_data_structures" } rustc_errors = { path = "../rustc_errors" } @@ -20,5 +20,5 @@ rustc_session = { path = "../rustc_session" } rustc_span = { path = "../rustc_span" } rustc_target = { path = "../rustc_target" } rustc_trait_selection = { path = "../rustc_trait_selection" } -tracing.workspace = true +tracing = "0.1" # tidy-alphabetical-end diff --git a/compiler/rustc_type_ir/Cargo.toml b/compiler/rustc_type_ir/Cargo.toml index 42860fa2d88d..d55e9b3b1be8 100644 --- a/compiler/rustc_type_ir/Cargo.toml +++ b/compiler/rustc_type_ir/Cargo.toml @@ -5,11 +5,11 @@ edition = "2024" [dependencies] # tidy-alphabetical-start -bitflags.workspace = true -derive-where.workspace = true +bitflags = "2.4.1" +derive-where = "1.2.7" ena = "0.14.3" -indexmap.workspace = true -rustc-hash.workspace = true +indexmap = "2.0.0" +rustc-hash = "2.0.0" rustc_ast_ir = { path = "../rustc_ast_ir", default-features = false } rustc_data_structures = { path = "../rustc_data_structures", optional = true } rustc_error_messages = { path = "../rustc_error_messages", optional = true } @@ -19,8 +19,8 @@ rustc_serialize = { path = "../rustc_serialize", optional = true } rustc_span = { path = "../rustc_span", optional = true } rustc_type_ir_macros = { path = "../rustc_type_ir_macros" } smallvec = { version = "1.8.1", default-features = false, features = ["const_generics"] } -thin-vec.workspace = true -tracing.workspace = true +thin-vec = "0.2.12" +tracing = "0.1" # tidy-alphabetical-end [features] diff --git a/compiler/rustc_type_ir_macros/Cargo.toml b/compiler/rustc_type_ir_macros/Cargo.toml index 29a2cc890335..15a555750992 100644 --- a/compiler/rustc_type_ir_macros/Cargo.toml +++ b/compiler/rustc_type_ir_macros/Cargo.toml @@ -8,8 +8,8 @@ proc-macro = true [dependencies] # tidy-alphabetical-start -proc-macro2.workspace = true -quote.workspace = true +proc-macro2 = "1" +quote = "1" syn = { version = "2.0.9", features = ["full"] } synstructure = "0.13.0" # tidy-alphabetical-end diff --git a/src/librustdoc/Cargo.toml b/src/librustdoc/Cargo.toml index 2985971a053f..5d36ffc2d3a5 100644 --- a/src/librustdoc/Cargo.toml +++ b/src/librustdoc/Cargo.toml @@ -12,20 +12,20 @@ path = "lib.rs" arrayvec = { version = "0.7", default-features = false } askama = { version = "0.14", default-features = false, features = ["alloc", "config", "derive"] } base64 = "0.21.7" -indexmap.workspace = true -itertools.workspace = true +indexmap = "2" +itertools = "0.12" minifier = { version = "0.3.5", default-features = false } pulldown-cmark-escape = { version = "0.11.0", features = ["simd"] } regex = "1" rustdoc-json-types = { path = "../rustdoc-json-types" } serde = { version = "1.0", features = ["derive"] } -serde_json.workspace = true +serde_json = "1.0" smallvec = "1.8.1" stringdex = { version = "0.0.1-alpha4" } -tempfile.workspace = true +tempfile = "3" threadpool = "1.8.1" +tracing = "0.1" tracing-tree = "0.3.0" -tracing.workspace = true unicode-segmentation = "1.9" # tidy-alphabetical-end diff --git a/src/tools/build-manifest/Cargo.toml b/src/tools/build-manifest/Cargo.toml index 05d5f21c12cb..efa99f181b3a 100644 --- a/src/tools/build-manifest/Cargo.toml +++ b/src/tools/build-manifest/Cargo.toml @@ -6,7 +6,7 @@ edition = "2021" [dependencies] toml = "0.7" serde = { version = "1.0", features = ["derive"] } -serde_json.workspace = true +serde_json = "1.0" anyhow = "1.0.32" flate2 = "1.0.26" xz2 = "0.1.7" diff --git a/src/tools/collect-license-metadata/Cargo.toml b/src/tools/collect-license-metadata/Cargo.toml index 7f2e57ced05c..edf9e5c5393e 100644 --- a/src/tools/collect-license-metadata/Cargo.toml +++ b/src/tools/collect-license-metadata/Cargo.toml @@ -8,5 +8,5 @@ license = "MIT OR Apache-2.0" [dependencies] anyhow = "1.0.65" serde = { version = "1.0.147", features = ["derive"] } -serde_json.workspace = true +serde_json = "1.0.85" spdx-rs = "0.5.1" diff --git a/src/tools/compiletest/Cargo.toml b/src/tools/compiletest/Cargo.toml index fb71275b03c7..cdada5a22306 100644 --- a/src/tools/compiletest/Cargo.toml +++ b/src/tools/compiletest/Cargo.toml @@ -20,22 +20,22 @@ diff = "0.1.10" getopts = "0.2" glob = "0.3.0" home = "0.5.5" -indexmap.workspace = true +indexmap = "2.0.0" miropt-test-tools = { path = "../miropt-test-tools" } rayon = "1.10.0" regex = "1.0" rustfix = "0.8.1" semver = { version = "1.0.23", features = ["serde"] } serde = { version = "1.0", features = ["derive"] } -serde_json.workspace = true +serde_json = "1.0" +tracing = "0.1" tracing-subscriber = { version = "0.3.3", default-features = false, features = ["ansi", "env-filter", "fmt", "parking_lot", "smallvec"] } -tracing.workspace = true unified-diff = "0.2.1" walkdir = "2" # tidy-alphabetical-end [target.'cfg(unix)'.dependencies] -libc.workspace = true +libc = "0.2" [target.'cfg(windows)'.dependencies] miow = "0.6" diff --git a/src/tools/coverage-dump/Cargo.toml b/src/tools/coverage-dump/Cargo.toml index e491804c2574..36a66f16030e 100644 --- a/src/tools/coverage-dump/Cargo.toml +++ b/src/tools/coverage-dump/Cargo.toml @@ -7,9 +7,9 @@ edition = "2021" [dependencies] anyhow = "1.0.71" -itertools.workspace = true +itertools = "0.12" leb128 = "0.2.5" md5 = { package = "md-5" , version = "0.10.5" } miniz_oxide = "0.8.8" regex = "1.8.4" -rustc-demangle.workspace = true +rustc-demangle = "0.1.23" diff --git a/src/tools/features-status-dump/Cargo.toml b/src/tools/features-status-dump/Cargo.toml index d72555da4865..b2976f14a01a 100644 --- a/src/tools/features-status-dump/Cargo.toml +++ b/src/tools/features-status-dump/Cargo.toml @@ -8,5 +8,5 @@ edition = "2021" anyhow = { version = "1" } clap = { version = "4", features = ["derive"] } serde = { version = "1.0.125", features = [ "derive" ] } -serde_json.workspace = true +serde_json = "1.0.59" tidy = { path = "../tidy", features = ["build-metrics"] } diff --git a/src/tools/generate-copyright/Cargo.toml b/src/tools/generate-copyright/Cargo.toml index 5edf1f3d88b3..bcb3165de458 100644 --- a/src/tools/generate-copyright/Cargo.toml +++ b/src/tools/generate-copyright/Cargo.toml @@ -11,5 +11,5 @@ anyhow = "1.0.65" askama = "0.14.0" cargo_metadata = "0.21" serde = { version = "1.0.147", features = ["derive"] } -serde_json.workspace = true +serde_json = "1.0.85" thiserror = "1" diff --git a/src/tools/jsondocck/Cargo.toml b/src/tools/jsondocck/Cargo.toml index 92fde3638823..80fc26cbe668 100644 --- a/src/tools/jsondocck/Cargo.toml +++ b/src/tools/jsondocck/Cargo.toml @@ -8,5 +8,5 @@ jsonpath-rust = "1.0.0" getopts = "0.2" regex = "1.4" shlex = "1.0" -serde_json.workspace = true +serde_json = "1.0" fs-err = "2.5.0" diff --git a/src/tools/jsondoclint/Cargo.toml b/src/tools/jsondoclint/Cargo.toml index 44beaf2ddfd2..cc8ecefd530b 100644 --- a/src/tools/jsondoclint/Cargo.toml +++ b/src/tools/jsondoclint/Cargo.toml @@ -9,7 +9,7 @@ edition = "2021" anyhow = "1.0.62" clap = { version = "4.0.15", features = ["derive"] } fs-err = "2.8.1" -rustc-hash.workspace = true +rustc-hash = "2.0.0" rustdoc-json-types = { version = "0.1.0", path = "../../rustdoc-json-types" } serde = { version = "1.0", features = ["derive"] } -serde_json.workspace = true +serde_json = "1.0.85" diff --git a/src/tools/lint-docs/Cargo.toml b/src/tools/lint-docs/Cargo.toml index acafe17cb0cd..6e1ab84ed18d 100644 --- a/src/tools/lint-docs/Cargo.toml +++ b/src/tools/lint-docs/Cargo.toml @@ -8,6 +8,6 @@ description = "A script to extract the lint documentation for the rustc book." [dependencies] rustc-literal-escaper = "0.0.5" -serde_json.workspace = true -tempfile.workspace = true +serde_json = "1.0.57" +tempfile = "3.1.0" walkdir = "2.3.1" diff --git a/src/tools/llvm-bitcode-linker/Cargo.toml b/src/tools/llvm-bitcode-linker/Cargo.toml index f78f8b618d31..a9210b562f33 100644 --- a/src/tools/llvm-bitcode-linker/Cargo.toml +++ b/src/tools/llvm-bitcode-linker/Cargo.toml @@ -8,7 +8,7 @@ publish = false [dependencies] anyhow = "1.0" -tracing.workspace = true -tracing-subscriber = { version = "0.3.0", features = ["std"] } +tracing = "0.1" +tracing-subscriber = {version = "0.3.0", features = ["std"] } clap = { version = "4.3", features = ["derive"] } thiserror = "1.0.24" diff --git a/src/tools/opt-dist/Cargo.toml b/src/tools/opt-dist/Cargo.toml index b2833a9d7f1a..f4051ae67d7c 100644 --- a/src/tools/opt-dist/Cargo.toml +++ b/src/tools/opt-dist/Cargo.toml @@ -15,9 +15,9 @@ fs_extra = "1" camino = "1" tar = "0.4" xz = { version = "0.1", package = "xz2" } -serde_json.workspace = true +serde_json = "1" glob = "0.3" -tempfile.workspace = true +tempfile = "3.5" derive_builder = "0.20" clap = { version = "4", features = ["derive"] } tabled = { version = "0.15", default-features = false, features = ["std"] } diff --git a/src/tools/run-make-support/Cargo.toml b/src/tools/run-make-support/Cargo.toml index 86ac4b9d7b45..250e0f65a9f4 100644 --- a/src/tools/run-make-support/Cargo.toml +++ b/src/tools/run-make-support/Cargo.toml @@ -12,10 +12,10 @@ edition = "2024" # tidy-alphabetical-start bstr = "1.12" gimli = "0.32" -libc.workspace = true +libc = "0.2" object = "0.37" regex = "1.11" -serde_json.workspace = true +serde_json = "1.0" similar = "2.7" wasmparser = { version = "0.236", default-features = false, features = ["std", "features", "validate"] } # tidy-alphabetical-end diff --git a/src/tools/tidy/Cargo.toml b/src/tools/tidy/Cargo.toml index f43733665edd..c1f27de7ed4a 100644 --- a/src/tools/tidy/Cargo.toml +++ b/src/tools/tidy/Cargo.toml @@ -14,7 +14,7 @@ ignore = "0.4.18" semver = "1.0" serde = { version = "1.0.125", features = ["derive"], optional = true } termcolor = "1.1.3" -rustc-hash.workspace = true +rustc-hash = "2.0.0" fluent-syntax = "0.12" similar = "2.5.0" toml = "0.7.8" From 51245cd53340a9b9a44aa086f50911d21e4988f3 Mon Sep 17 00:00:00 2001 From: Kartik Agarwala Date: Tue, 2 Sep 2025 15:19:07 +0530 Subject: [PATCH 43/48] Add maintainer for VxWorks --- src/doc/rustc/src/platform-support/vxworks.md | 1 + 1 file changed, 1 insertion(+) diff --git a/src/doc/rustc/src/platform-support/vxworks.md b/src/doc/rustc/src/platform-support/vxworks.md index 3fccee807223..091c757a2ee3 100644 --- a/src/doc/rustc/src/platform-support/vxworks.md +++ b/src/doc/rustc/src/platform-support/vxworks.md @@ -20,6 +20,7 @@ Target triplets available: ## Target maintainers [@biabbas](https://github.com/biabbas) +[@hax0kartik](https://github.com/hax0kartik) ## Requirements From 7b35d8e1ab2d913f4b15d0ee21d5bd8d50798e9c Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 2 Sep 2025 11:57:33 +0200 Subject: [PATCH 44/48] Fix `unknown number` error when generating search index --- src/librustdoc/formats/item_type.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/librustdoc/formats/item_type.rs b/src/librustdoc/formats/item_type.rs index e94ef5173099..b8b00ab582cd 100644 --- a/src/librustdoc/formats/item_type.rs +++ b/src/librustdoc/formats/item_type.rs @@ -78,7 +78,7 @@ impl<'de> Deserialize<'de> for ItemType { impl<'de> de::Visitor<'de> for ItemTypeVisitor { type Value = ItemType; fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(formatter, "an integer between 0 and 25") + write!(formatter, "an integer between 0 and 27") } fn visit_u64(self, v: u64) -> Result { Ok(match v { @@ -107,7 +107,8 @@ impl<'de> Deserialize<'de> for ItemType { 23 => ItemType::ProcAttribute, 24 => ItemType::ProcDerive, 25 => ItemType::TraitAlias, - _ => return Err(E::missing_field("unknown number")), + 27 => ItemType::Attribute, + _ => return Err(E::missing_field("unknown number for `ItemType` enum")), }) } } From 4ecca581fad73c51d7c7a78c4b97a3ada2ca5249 Mon Sep 17 00:00:00 2001 From: Hans Wennborg Date: Tue, 2 Sep 2025 11:57:58 +0200 Subject: [PATCH 45/48] Adjust issue-118306.rs test after LLVM change This updates tests/codegen-llvm/issues/issue-118306.rs to pass also after https://github.com/llvm/llvm-project/pull/155415 --- tests/codegen-llvm/issues/issue-118306.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/codegen-llvm/issues/issue-118306.rs b/tests/codegen-llvm/issues/issue-118306.rs index f12dc7cdfe2c..934a7687b601 100644 --- a/tests/codegen-llvm/issues/issue-118306.rs +++ b/tests/codegen-llvm/issues/issue-118306.rs @@ -11,7 +11,7 @@ pub fn branchy(input: u64) -> u64 { // CHECK-LABEL: @branchy( // CHECK-NEXT: start: // CHECK-NEXT: [[_2:%.*]] = and i64 [[INPUT:%.*]], 3 - // CHECK-NEXT: [[SWITCH_GEP:%.*]] = getelementptr inbounds{{( nuw)?}} [4 x i64], ptr @switch.table.branchy, i64 0, i64 [[_2]] + // CHECK-NEXT: [[SWITCH_GEP:%.*]] = getelementptr inbounds{{( nuw)?}} {{\[4 x i64\]|i64}}, ptr @switch.table.branchy{{(, i64 0)?}}, i64 [[_2]] // CHECK-NEXT: [[SWITCH_LOAD:%.*]] = load i64, ptr [[SWITCH_GEP]] // CHECK-NEXT: ret i64 [[SWITCH_LOAD]] match input % 4 { From ad2e0961366a6bf5e01d6863a459424e78ebcf40 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 2 Sep 2025 12:04:07 +0200 Subject: [PATCH 46/48] Make it impossible to forget a conversion for the rustdoc `ItemType` enum --- src/librustdoc/formats/item_type.rs | 97 ++++++++++++----------------- 1 file changed, 41 insertions(+), 56 deletions(-) diff --git a/src/librustdoc/formats/item_type.rs b/src/librustdoc/formats/item_type.rs index b8b00ab582cd..ab40c01cb369 100644 --- a/src/librustdoc/formats/item_type.rs +++ b/src/librustdoc/formats/item_type.rs @@ -8,6 +8,9 @@ use serde::{Deserialize, Deserializer, Serialize, Serializer, de}; use crate::clean; +macro_rules! item_type { + ($($variant:ident = $number:literal,)+) => { + /// Item type. Corresponds to `clean::ItemEnum` variants. /// /// The search index uses item types encoded as smaller numbers which equal to @@ -29,6 +32,44 @@ use crate::clean; #[derive(Copy, PartialEq, Eq, Hash, Clone, Debug, PartialOrd, Ord)] #[repr(u8)] pub(crate) enum ItemType { + $($variant = $number,)+ +} + +impl Serialize for ItemType { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + (*self as u8).serialize(serializer) + } +} + +impl<'de> Deserialize<'de> for ItemType { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + struct ItemTypeVisitor; + impl<'de> de::Visitor<'de> for ItemTypeVisitor { + type Value = ItemType; + fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(formatter, "an integer between 0 and 27") + } + fn visit_u64(self, v: u64) -> Result { + Ok(match v { + $($number => ItemType::$variant,)+ + _ => return Err(E::missing_field("unknown number for `ItemType` enum")), + }) + } + } + deserializer.deserialize_any(ItemTypeVisitor) + } +} + + } +} + +item_type! { Keyword = 0, Primitive = 1, Module = 2, @@ -60,62 +101,6 @@ pub(crate) enum ItemType { Attribute = 27, } -impl Serialize for ItemType { - fn serialize(&self, serializer: S) -> Result - where - S: Serializer, - { - (*self as u8).serialize(serializer) - } -} - -impl<'de> Deserialize<'de> for ItemType { - fn deserialize(deserializer: D) -> Result - where - D: Deserializer<'de>, - { - struct ItemTypeVisitor; - impl<'de> de::Visitor<'de> for ItemTypeVisitor { - type Value = ItemType; - fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(formatter, "an integer between 0 and 27") - } - fn visit_u64(self, v: u64) -> Result { - Ok(match v { - 0 => ItemType::Keyword, - 1 => ItemType::Primitive, - 2 => ItemType::Module, - 3 => ItemType::ExternCrate, - 4 => ItemType::Import, - 5 => ItemType::Struct, - 6 => ItemType::Enum, - 7 => ItemType::Function, - 8 => ItemType::TypeAlias, - 9 => ItemType::Static, - 10 => ItemType::Trait, - 11 => ItemType::Impl, - 12 => ItemType::TyMethod, - 13 => ItemType::Method, - 14 => ItemType::StructField, - 15 => ItemType::Variant, - 16 => ItemType::Macro, - 17 => ItemType::AssocType, - 18 => ItemType::Constant, - 19 => ItemType::AssocConst, - 20 => ItemType::Union, - 21 => ItemType::ForeignType, - 23 => ItemType::ProcAttribute, - 24 => ItemType::ProcDerive, - 25 => ItemType::TraitAlias, - 27 => ItemType::Attribute, - _ => return Err(E::missing_field("unknown number for `ItemType` enum")), - }) - } - } - deserializer.deserialize_any(ItemTypeVisitor) - } -} - impl<'a> From<&'a clean::Item> for ItemType { fn from(item: &'a clean::Item) -> ItemType { let kind = match &item.kind { From a6c0519faef6512aff1ee1a1fe2bf2556fe2d642 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 2 Sep 2025 12:09:05 +0200 Subject: [PATCH 47/48] improve process::abort rendering in Miri backtraces --- library/std/src/panicking.rs | 4 ++-- library/std/src/process.rs | 1 + library/std/src/sys/pal/unix/mod.rs | 1 + library/std/src/sys/pal/windows/mod.rs | 1 + .../miri/tests/fail/alloc/alloc_error_handler.rs | 2 -- .../miri/tests/fail/alloc/alloc_error_handler.stderr | 10 ++++------ .../exported_symbol_bad_unwind2.both.stderr | 9 ++++----- .../exported_symbol_bad_unwind2.definition.stderr | 9 ++++----- .../exported_symbol_bad_unwind2.extern_block.stderr | 2 +- .../function_calls/exported_symbol_bad_unwind2.rs | 2 -- src/tools/miri/tests/fail/panic/abort_unwind.rs | 2 -- src/tools/miri/tests/fail/panic/abort_unwind.stderr | 9 ++++----- src/tools/miri/tests/fail/panic/double_panic.rs | 2 -- src/tools/miri/tests/fail/panic/double_panic.stderr | 7 +++---- src/tools/miri/tests/fail/panic/panic_abort1.rs | 2 -- src/tools/miri/tests/fail/panic/panic_abort1.stderr | 10 ++++------ src/tools/miri/tests/fail/panic/panic_abort2.rs | 2 -- src/tools/miri/tests/fail/panic/panic_abort2.stderr | 10 ++++------ src/tools/miri/tests/fail/panic/panic_abort3.rs | 2 -- src/tools/miri/tests/fail/panic/panic_abort3.stderr | 10 ++++------ src/tools/miri/tests/fail/panic/panic_abort4.rs | 2 -- src/tools/miri/tests/fail/panic/panic_abort4.stderr | 10 ++++------ src/tools/miri/tests/fail/ptr_swap_nonoverlapping.rs | 2 -- .../miri/tests/fail/ptr_swap_nonoverlapping.stderr | 9 ++++----- src/tools/miri/tests/fail/terminate-terminator.rs | 2 -- src/tools/miri/tests/fail/terminate-terminator.stderr | 11 +++++------ src/tools/miri/tests/fail/unwind-action-terminate.rs | 2 -- .../miri/tests/fail/unwind-action-terminate.stderr | 9 ++++----- 28 files changed, 54 insertions(+), 90 deletions(-) diff --git a/library/std/src/panicking.rs b/library/std/src/panicking.rs index 87a3fc80dfab..8b7282c51d12 100644 --- a/library/std/src/panicking.rs +++ b/library/std/src/panicking.rs @@ -819,7 +819,7 @@ fn panic_with_hook( rtprintpanic!("aborting due to panic at {location}:\n{payload}\n"); } } - crate::sys::abort_internal(); + crate::process::abort(); } match *HOOK.read().unwrap_or_else(PoisonError::into_inner) { @@ -853,7 +853,7 @@ fn panic_with_hook( // through a nounwind function (e.g. extern "C") then we cannot continue // unwinding and have to abort immediately. rtprintpanic!("thread caused non-unwinding panic. aborting.\n"); - crate::sys::abort_internal(); + crate::process::abort(); } rust_panic(payload) diff --git a/library/std/src/process.rs b/library/std/src/process.rs index 373584d0117c..48265de90c4d 100644 --- a/library/std/src/process.rs +++ b/library/std/src/process.rs @@ -2495,6 +2495,7 @@ pub fn exit(code: i32) -> ! { #[stable(feature = "process_abort", since = "1.17.0")] #[cold] #[cfg_attr(not(test), rustc_diagnostic_item = "process_abort")] +#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub fn abort() -> ! { crate::sys::abort_internal(); } diff --git a/library/std/src/sys/pal/unix/mod.rs b/library/std/src/sys/pal/unix/mod.rs index 400128acf126..ac5c823a1bf6 100644 --- a/library/std/src/sys/pal/unix/mod.rs +++ b/library/std/src/sys/pal/unix/mod.rs @@ -364,6 +364,7 @@ pub fn cvt_nz(error: libc::c_int) -> crate::io::Result<()> { // multithreaded C program. It is much less severe for Rust, because Rust // stdlib doesn't use libc stdio buffering. In a typical Rust program, which // does not use C stdio, even a buggy libc::abort() is, in fact, safe. +#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub fn abort_internal() -> ! { unsafe { libc::abort() } } diff --git a/library/std/src/sys/pal/windows/mod.rs b/library/std/src/sys/pal/windows/mod.rs index 10ad4541beda..3b6a86cbc8f4 100644 --- a/library/std/src/sys/pal/windows/mod.rs +++ b/library/std/src/sys/pal/windows/mod.rs @@ -356,6 +356,7 @@ pub fn abort_internal() -> ! { } #[cfg(miri)] +#[track_caller] // even without panics, this helps for Miri backtraces pub fn abort_internal() -> ! { crate::intrinsics::abort(); } diff --git a/src/tools/miri/tests/fail/alloc/alloc_error_handler.rs b/src/tools/miri/tests/fail/alloc/alloc_error_handler.rs index 4a87411d755c..35b8e20e56b3 100644 --- a/src/tools/miri/tests/fail/alloc/alloc_error_handler.rs +++ b/src/tools/miri/tests/fail/alloc/alloc_error_handler.rs @@ -1,6 +1,4 @@ //@error-in-other-file: aborted -//@normalize-stderr-test: "\|.*::abort\(\).*" -> "| ABORT()" -//@normalize-stderr-test: "\| +\^+" -> "| ^" #![feature(allocator_api)] use std::alloc::*; diff --git a/src/tools/miri/tests/fail/alloc/alloc_error_handler.stderr b/src/tools/miri/tests/fail/alloc/alloc_error_handler.stderr index d67dabd69354..bbf5d14a98a1 100644 --- a/src/tools/miri/tests/fail/alloc/alloc_error_handler.stderr +++ b/src/tools/miri/tests/fail/alloc/alloc_error_handler.stderr @@ -1,13 +1,11 @@ memory allocation of 4 bytes failed error: abnormal termination: the program aborted execution - --> RUSTLIB/std/src/sys/pal/PLATFORM/mod.rs:LL:CC + --> RUSTLIB/std/src/alloc.rs:LL:CC | -LL | ABORT() - | ^ abnormal termination occurred here +LL | crate::process::abort() + | ^^^^^^^^^^^^^^^^^^^^^^^ abnormal termination occurred here | = note: BACKTRACE: - = note: inside `std::sys::pal::PLATFORM::abort_internal` at RUSTLIB/std/src/sys/pal/PLATFORM/mod.rs:LL:CC - = note: inside `std::process::abort` at RUSTLIB/std/src/process.rs:LL:CC = note: inside `std::alloc::rust_oom` at RUSTLIB/std/src/alloc.rs:LL:CC = note: inside `std::alloc::_::__rg_oom` at RUSTLIB/std/src/alloc.rs:LL:CC = note: inside `std::alloc::handle_alloc_error::rt_error` at RUSTLIB/alloc/src/alloc.rs:LL:CC @@ -16,7 +14,7 @@ note: inside `main` --> tests/fail/alloc/alloc_error_handler.rs:LL:CC | LL | handle_alloc_error(Layout::for_value(&0)); - | ^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/function_calls/exported_symbol_bad_unwind2.both.stderr b/src/tools/miri/tests/fail/function_calls/exported_symbol_bad_unwind2.both.stderr index a1571173a53b..95f79aae6c17 100644 --- a/src/tools/miri/tests/fail/function_calls/exported_symbol_bad_unwind2.both.stderr +++ b/src/tools/miri/tests/fail/function_calls/exported_symbol_bad_unwind2.both.stderr @@ -9,13 +9,12 @@ panic in a function that cannot unwind stack backtrace: thread caused non-unwinding panic. aborting. error: abnormal termination: the program aborted execution - --> RUSTLIB/std/src/sys/pal/PLATFORM/mod.rs:LL:CC + --> RUSTLIB/std/src/panicking.rs:LL:CC | -LL | ABORT() - | ^ abnormal termination occurred here +LL | crate::process::abort(); + | ^^^^^^^^^^^^^^^^^^^^^^^ abnormal termination occurred here | = note: BACKTRACE: - = note: inside `std::sys::pal::PLATFORM::abort_internal` at RUSTLIB/std/src/sys/pal/PLATFORM/mod.rs:LL:CC = note: inside `std::panicking::panic_with_hook` at RUSTLIB/std/src/panicking.rs:LL:CC = note: inside closure at RUSTLIB/std/src/panicking.rs:LL:CC = note: inside `std::sys::backtrace::__rust_end_short_backtrace::<{closure@std::panicking::panic_handler::{closure#0}}, !>` at RUSTLIB/std/src/sys/backtrace.rs:LL:CC @@ -33,7 +32,7 @@ note: inside `main` --> tests/fail/function_calls/exported_symbol_bad_unwind2.rs:LL:CC | LL | unsafe { nounwind() } - | ^ + | ^^^^^^^^^^ note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/function_calls/exported_symbol_bad_unwind2.definition.stderr b/src/tools/miri/tests/fail/function_calls/exported_symbol_bad_unwind2.definition.stderr index a1571173a53b..95f79aae6c17 100644 --- a/src/tools/miri/tests/fail/function_calls/exported_symbol_bad_unwind2.definition.stderr +++ b/src/tools/miri/tests/fail/function_calls/exported_symbol_bad_unwind2.definition.stderr @@ -9,13 +9,12 @@ panic in a function that cannot unwind stack backtrace: thread caused non-unwinding panic. aborting. error: abnormal termination: the program aborted execution - --> RUSTLIB/std/src/sys/pal/PLATFORM/mod.rs:LL:CC + --> RUSTLIB/std/src/panicking.rs:LL:CC | -LL | ABORT() - | ^ abnormal termination occurred here +LL | crate::process::abort(); + | ^^^^^^^^^^^^^^^^^^^^^^^ abnormal termination occurred here | = note: BACKTRACE: - = note: inside `std::sys::pal::PLATFORM::abort_internal` at RUSTLIB/std/src/sys/pal/PLATFORM/mod.rs:LL:CC = note: inside `std::panicking::panic_with_hook` at RUSTLIB/std/src/panicking.rs:LL:CC = note: inside closure at RUSTLIB/std/src/panicking.rs:LL:CC = note: inside `std::sys::backtrace::__rust_end_short_backtrace::<{closure@std::panicking::panic_handler::{closure#0}}, !>` at RUSTLIB/std/src/sys/backtrace.rs:LL:CC @@ -33,7 +32,7 @@ note: inside `main` --> tests/fail/function_calls/exported_symbol_bad_unwind2.rs:LL:CC | LL | unsafe { nounwind() } - | ^ + | ^^^^^^^^^^ note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/function_calls/exported_symbol_bad_unwind2.extern_block.stderr b/src/tools/miri/tests/fail/function_calls/exported_symbol_bad_unwind2.extern_block.stderr index e755b262474c..eaca0d3f0122 100644 --- a/src/tools/miri/tests/fail/function_calls/exported_symbol_bad_unwind2.extern_block.stderr +++ b/src/tools/miri/tests/fail/function_calls/exported_symbol_bad_unwind2.extern_block.stderr @@ -7,7 +7,7 @@ error: Undefined Behavior: unwinding past a stack frame that does not allow unwi --> tests/fail/function_calls/exported_symbol_bad_unwind2.rs:LL:CC | LL | unsafe { nounwind() } - | ^ Undefined Behavior occurred here + | ^^^^^^^^^^ Undefined Behavior occurred here | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/src/tools/miri/tests/fail/function_calls/exported_symbol_bad_unwind2.rs b/src/tools/miri/tests/fail/function_calls/exported_symbol_bad_unwind2.rs index 9d993786d57f..aa5a185f110d 100644 --- a/src/tools/miri/tests/fail/function_calls/exported_symbol_bad_unwind2.rs +++ b/src/tools/miri/tests/fail/function_calls/exported_symbol_bad_unwind2.rs @@ -1,6 +1,4 @@ //@revisions: extern_block definition both -//@normalize-stderr-test: "\|.*::abort\(\).*" -> "| ABORT()" -//@normalize-stderr-test: "\| +\^+" -> "| ^" //@normalize-stderr-test: "\n +[0-9]+:[^\n]+" -> "" //@normalize-stderr-test: "\n +at [^\n]+" -> "" //@[definition,both]error-in-other-file: aborted execution diff --git a/src/tools/miri/tests/fail/panic/abort_unwind.rs b/src/tools/miri/tests/fail/panic/abort_unwind.rs index bd819362da41..775cbf62229b 100644 --- a/src/tools/miri/tests/fail/panic/abort_unwind.rs +++ b/src/tools/miri/tests/fail/panic/abort_unwind.rs @@ -1,6 +1,4 @@ //@error-in-other-file: the program aborted execution -//@normalize-stderr-test: "\|.*::abort\(\).*" -> "| ABORT()" -//@normalize-stderr-test: "\| +\^+" -> "| ^" //@normalize-stderr-test: "\n +[0-9]+:[^\n]+" -> "" //@normalize-stderr-test: "\n +at [^\n]+" -> "" diff --git a/src/tools/miri/tests/fail/panic/abort_unwind.stderr b/src/tools/miri/tests/fail/panic/abort_unwind.stderr index 287f7d5432a6..23dbc2fb8f39 100644 --- a/src/tools/miri/tests/fail/panic/abort_unwind.stderr +++ b/src/tools/miri/tests/fail/panic/abort_unwind.stderr @@ -9,13 +9,12 @@ panic in a function that cannot unwind stack backtrace: thread caused non-unwinding panic. aborting. error: abnormal termination: the program aborted execution - --> RUSTLIB/std/src/sys/pal/PLATFORM/mod.rs:LL:CC + --> RUSTLIB/std/src/panicking.rs:LL:CC | -LL | ABORT() - | ^ abnormal termination occurred here +LL | crate::process::abort(); + | ^^^^^^^^^^^^^^^^^^^^^^^ abnormal termination occurred here | = note: BACKTRACE: - = note: inside `std::sys::pal::PLATFORM::abort_internal` at RUSTLIB/std/src/sys/pal/PLATFORM/mod.rs:LL:CC = note: inside `std::panicking::panic_with_hook` at RUSTLIB/std/src/panicking.rs:LL:CC = note: inside closure at RUSTLIB/std/src/panicking.rs:LL:CC = note: inside `std::sys::backtrace::__rust_end_short_backtrace::<{closure@std::panicking::panic_handler::{closure#0}}, !>` at RUSTLIB/std/src/sys/backtrace.rs:LL:CC @@ -27,7 +26,7 @@ note: inside `main` --> tests/fail/panic/abort_unwind.rs:LL:CC | LL | std::panic::abort_unwind(|| panic!("PANIC!!!")); - | ^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/panic/double_panic.rs b/src/tools/miri/tests/fail/panic/double_panic.rs index 4d8f4cb6fb7b..88421e84529e 100644 --- a/src/tools/miri/tests/fail/panic/double_panic.rs +++ b/src/tools/miri/tests/fail/panic/double_panic.rs @@ -1,5 +1,3 @@ -//@normalize-stderr-test: "\|.*::abort\(\).*" -> "| ABORT()" -//@normalize-stderr-test: "\| +\^+" -> "| ^" //@normalize-stderr-test: "\n +[0-9]+:[^\n]+" -> "" //@normalize-stderr-test: "\n +at [^\n]+" -> "" //@error-in-other-file: aborted execution diff --git a/src/tools/miri/tests/fail/panic/double_panic.stderr b/src/tools/miri/tests/fail/panic/double_panic.stderr index b76ece7f1e5e..edbc0d8fc571 100644 --- a/src/tools/miri/tests/fail/panic/double_panic.stderr +++ b/src/tools/miri/tests/fail/panic/double_panic.stderr @@ -12,13 +12,12 @@ thread 'main' ($TID) panicked at RUSTLIB/core/src/panicking.rs:LL:CC: panic in a destructor during cleanup thread caused non-unwinding panic. aborting. error: abnormal termination: the program aborted execution - --> RUSTLIB/std/src/sys/pal/PLATFORM/mod.rs:LL:CC + --> RUSTLIB/std/src/panicking.rs:LL:CC | -LL | ABORT() - | ^ abnormal termination occurred here +LL | crate::process::abort(); + | ^^^^^^^^^^^^^^^^^^^^^^^ abnormal termination occurred here | = note: BACKTRACE: - = note: inside `std::sys::pal::PLATFORM::abort_internal` at RUSTLIB/std/src/sys/pal/PLATFORM/mod.rs:LL:CC = note: inside `std::panicking::panic_with_hook` at RUSTLIB/std/src/panicking.rs:LL:CC = note: inside closure at RUSTLIB/std/src/panicking.rs:LL:CC = note: inside `std::sys::backtrace::__rust_end_short_backtrace::<{closure@std::panicking::panic_handler::{closure#0}}, !>` at RUSTLIB/std/src/sys/backtrace.rs:LL:CC diff --git a/src/tools/miri/tests/fail/panic/panic_abort1.rs b/src/tools/miri/tests/fail/panic/panic_abort1.rs index 06cb673778a2..511b8bddf970 100644 --- a/src/tools/miri/tests/fail/panic/panic_abort1.rs +++ b/src/tools/miri/tests/fail/panic/panic_abort1.rs @@ -1,6 +1,4 @@ //@error-in-other-file: the program aborted execution -//@normalize-stderr-test: "\| +\^+" -> "| ^" -//@normalize-stderr-test: "\|.*::abort\(\).*" -> "| ABORT()" //@compile-flags: -C panic=abort fn main() { diff --git a/src/tools/miri/tests/fail/panic/panic_abort1.stderr b/src/tools/miri/tests/fail/panic/panic_abort1.stderr index c469d24287f9..c389a9bc0750 100644 --- a/src/tools/miri/tests/fail/panic/panic_abort1.stderr +++ b/src/tools/miri/tests/fail/panic/panic_abort1.stderr @@ -4,14 +4,12 @@ panicking from libstd note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace note: in Miri, you may have to set `MIRIFLAGS=-Zmiri-env-forward=RUST_BACKTRACE` for the environment variable to have an effect error: abnormal termination: the program aborted execution - --> RUSTLIB/std/src/sys/pal/PLATFORM/mod.rs:LL:CC + --> RUSTLIB/std/src/rt.rs:LL:CC | -LL | ABORT() - | ^ abnormal termination occurred here +LL | crate::process::abort(); + | ^^^^^^^^^^^^^^^^^^^^^^^ abnormal termination occurred here | = note: BACKTRACE: - = note: inside `std::sys::pal::PLATFORM::abort_internal` at RUSTLIB/std/src/sys/pal/PLATFORM/mod.rs:LL:CC - = note: inside `std::process::abort` at RUSTLIB/std/src/process.rs:LL:CC = note: inside `std::rt::__rust_abort` at RUSTLIB/std/src/rt.rs:LL:CC = note: inside `panic_abort::__rust_start_panic` at RUSTLIB/panic_abort/src/lib.rs:LL:CC = note: inside `std::panicking::rust_panic` at RUSTLIB/std/src/panicking.rs:LL:CC @@ -23,7 +21,7 @@ note: inside `main` --> tests/fail/panic/panic_abort1.rs:LL:CC | LL | std::panic!("panicking from libstd"); - | ^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/panic/panic_abort2.rs b/src/tools/miri/tests/fail/panic/panic_abort2.rs index c011b3ee7eb8..e6c1a130ac94 100644 --- a/src/tools/miri/tests/fail/panic/panic_abort2.rs +++ b/src/tools/miri/tests/fail/panic/panic_abort2.rs @@ -1,6 +1,4 @@ //@error-in-other-file: the program aborted execution -//@normalize-stderr-test: "\| +\^+" -> "| ^" -//@normalize-stderr-test: "\|.*::abort\(\).*" -> "| ABORT()" //@compile-flags: -C panic=abort fn main() { diff --git a/src/tools/miri/tests/fail/panic/panic_abort2.stderr b/src/tools/miri/tests/fail/panic/panic_abort2.stderr index bc7918f5f86a..5fe2245cbe00 100644 --- a/src/tools/miri/tests/fail/panic/panic_abort2.stderr +++ b/src/tools/miri/tests/fail/panic/panic_abort2.stderr @@ -4,14 +4,12 @@ thread 'main' ($TID) panicked at tests/fail/panic/panic_abort2.rs:LL:CC: note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace note: in Miri, you may have to set `MIRIFLAGS=-Zmiri-env-forward=RUST_BACKTRACE` for the environment variable to have an effect error: abnormal termination: the program aborted execution - --> RUSTLIB/std/src/sys/pal/PLATFORM/mod.rs:LL:CC + --> RUSTLIB/std/src/rt.rs:LL:CC | -LL | ABORT() - | ^ abnormal termination occurred here +LL | crate::process::abort(); + | ^^^^^^^^^^^^^^^^^^^^^^^ abnormal termination occurred here | = note: BACKTRACE: - = note: inside `std::sys::pal::PLATFORM::abort_internal` at RUSTLIB/std/src/sys/pal/PLATFORM/mod.rs:LL:CC - = note: inside `std::process::abort` at RUSTLIB/std/src/process.rs:LL:CC = note: inside `std::rt::__rust_abort` at RUSTLIB/std/src/rt.rs:LL:CC = note: inside `panic_abort::__rust_start_panic` at RUSTLIB/panic_abort/src/lib.rs:LL:CC = note: inside `std::panicking::rust_panic` at RUSTLIB/std/src/panicking.rs:LL:CC @@ -23,7 +21,7 @@ note: inside `main` --> tests/fail/panic/panic_abort2.rs:LL:CC | LL | std::panic!("{}-panicking from libstd", 42); - | ^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/panic/panic_abort3.rs b/src/tools/miri/tests/fail/panic/panic_abort3.rs index 911dc4a44abd..28a28c923fdf 100644 --- a/src/tools/miri/tests/fail/panic/panic_abort3.rs +++ b/src/tools/miri/tests/fail/panic/panic_abort3.rs @@ -1,6 +1,4 @@ //@error-in-other-file: the program aborted execution -//@normalize-stderr-test: "\| +\^+" -> "| ^" -//@normalize-stderr-test: "\|.*::abort\(\).*" -> "| ABORT()" //@compile-flags: -C panic=abort fn main() { diff --git a/src/tools/miri/tests/fail/panic/panic_abort3.stderr b/src/tools/miri/tests/fail/panic/panic_abort3.stderr index 553bfa616351..cac24ca41c71 100644 --- a/src/tools/miri/tests/fail/panic/panic_abort3.stderr +++ b/src/tools/miri/tests/fail/panic/panic_abort3.stderr @@ -4,14 +4,12 @@ panicking from libcore note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace note: in Miri, you may have to set `MIRIFLAGS=-Zmiri-env-forward=RUST_BACKTRACE` for the environment variable to have an effect error: abnormal termination: the program aborted execution - --> RUSTLIB/std/src/sys/pal/PLATFORM/mod.rs:LL:CC + --> RUSTLIB/std/src/rt.rs:LL:CC | -LL | ABORT() - | ^ abnormal termination occurred here +LL | crate::process::abort(); + | ^^^^^^^^^^^^^^^^^^^^^^^ abnormal termination occurred here | = note: BACKTRACE: - = note: inside `std::sys::pal::PLATFORM::abort_internal` at RUSTLIB/std/src/sys/pal/PLATFORM/mod.rs:LL:CC - = note: inside `std::process::abort` at RUSTLIB/std/src/process.rs:LL:CC = note: inside `std::rt::__rust_abort` at RUSTLIB/std/src/rt.rs:LL:CC = note: inside `panic_abort::__rust_start_panic` at RUSTLIB/panic_abort/src/lib.rs:LL:CC = note: inside `std::panicking::rust_panic` at RUSTLIB/std/src/panicking.rs:LL:CC @@ -23,7 +21,7 @@ note: inside `main` --> tests/fail/panic/panic_abort3.rs:LL:CC | LL | core::panic!("panicking from libcore"); - | ^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/panic/panic_abort4.rs b/src/tools/miri/tests/fail/panic/panic_abort4.rs index 696fdff74223..248064d14d5d 100644 --- a/src/tools/miri/tests/fail/panic/panic_abort4.rs +++ b/src/tools/miri/tests/fail/panic/panic_abort4.rs @@ -1,6 +1,4 @@ //@error-in-other-file: the program aborted execution -//@normalize-stderr-test: "\| +\^+" -> "| ^" -//@normalize-stderr-test: "\|.*::abort\(\).*" -> "| ABORT()" //@compile-flags: -C panic=abort fn main() { diff --git a/src/tools/miri/tests/fail/panic/panic_abort4.stderr b/src/tools/miri/tests/fail/panic/panic_abort4.stderr index 07ecab6661e5..21195729ae82 100644 --- a/src/tools/miri/tests/fail/panic/panic_abort4.stderr +++ b/src/tools/miri/tests/fail/panic/panic_abort4.stderr @@ -4,14 +4,12 @@ thread 'main' ($TID) panicked at tests/fail/panic/panic_abort4.rs:LL:CC: note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace note: in Miri, you may have to set `MIRIFLAGS=-Zmiri-env-forward=RUST_BACKTRACE` for the environment variable to have an effect error: abnormal termination: the program aborted execution - --> RUSTLIB/std/src/sys/pal/PLATFORM/mod.rs:LL:CC + --> RUSTLIB/std/src/rt.rs:LL:CC | -LL | ABORT() - | ^ abnormal termination occurred here +LL | crate::process::abort(); + | ^^^^^^^^^^^^^^^^^^^^^^^ abnormal termination occurred here | = note: BACKTRACE: - = note: inside `std::sys::pal::PLATFORM::abort_internal` at RUSTLIB/std/src/sys/pal/PLATFORM/mod.rs:LL:CC - = note: inside `std::process::abort` at RUSTLIB/std/src/process.rs:LL:CC = note: inside `std::rt::__rust_abort` at RUSTLIB/std/src/rt.rs:LL:CC = note: inside `panic_abort::__rust_start_panic` at RUSTLIB/panic_abort/src/lib.rs:LL:CC = note: inside `std::panicking::rust_panic` at RUSTLIB/std/src/panicking.rs:LL:CC @@ -23,7 +21,7 @@ note: inside `main` --> tests/fail/panic/panic_abort4.rs:LL:CC | LL | core::panic!("{}-panicking from libcore", 42); - | ^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/ptr_swap_nonoverlapping.rs b/src/tools/miri/tests/fail/ptr_swap_nonoverlapping.rs index 6119e8604b46..0f7cf189f33f 100644 --- a/src/tools/miri/tests/fail/ptr_swap_nonoverlapping.rs +++ b/src/tools/miri/tests/fail/ptr_swap_nonoverlapping.rs @@ -1,7 +1,5 @@ //! This is a regression test for : The precondition //! check in `ptr::swap_nonoverlapping` was incorrectly disabled in Miri. -//@normalize-stderr-test: "\|.*::abort\(\).*" -> "| ABORT()" -//@normalize-stderr-test: "\| +\^+" -> "| ^" //@normalize-stderr-test: "\n +[0-9]+:[^\n]+" -> "" //@normalize-stderr-test: "\n +at [^\n]+" -> "" //@error-in-other-file: aborted execution diff --git a/src/tools/miri/tests/fail/ptr_swap_nonoverlapping.stderr b/src/tools/miri/tests/fail/ptr_swap_nonoverlapping.stderr index 70f5d498da39..c5f6e62b8690 100644 --- a/src/tools/miri/tests/fail/ptr_swap_nonoverlapping.stderr +++ b/src/tools/miri/tests/fail/ptr_swap_nonoverlapping.stderr @@ -7,13 +7,12 @@ note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace note: in Miri, you may have to set `MIRIFLAGS=-Zmiri-env-forward=RUST_BACKTRACE` for the environment variable to have an effect thread caused non-unwinding panic. aborting. error: abnormal termination: the program aborted execution - --> RUSTLIB/std/src/sys/pal/PLATFORM/mod.rs:LL:CC + --> RUSTLIB/std/src/panicking.rs:LL:CC | -LL | ABORT() - | ^ abnormal termination occurred here +LL | crate::process::abort(); + | ^^^^^^^^^^^^^^^^^^^^^^^ abnormal termination occurred here | = note: BACKTRACE: - = note: inside `std::sys::pal::PLATFORM::abort_internal` at RUSTLIB/std/src/sys/pal/PLATFORM/mod.rs:LL:CC = note: inside `std::panicking::panic_with_hook` at RUSTLIB/std/src/panicking.rs:LL:CC = note: inside closure at RUSTLIB/std/src/panicking.rs:LL:CC = note: inside `std::sys::backtrace::__rust_end_short_backtrace::<{closure@std::panicking::panic_handler::{closure#0}}, !>` at RUSTLIB/std/src/sys/backtrace.rs:LL:CC @@ -22,7 +21,7 @@ note: inside `main` --> tests/fail/ptr_swap_nonoverlapping.rs:LL:CC | LL | std::ptr::swap_nonoverlapping(ptr, ptr, 1); - | ^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/terminate-terminator.rs b/src/tools/miri/tests/fail/terminate-terminator.rs index 31ae829a2de7..421cddca1606 100644 --- a/src/tools/miri/tests/fail/terminate-terminator.rs +++ b/src/tools/miri/tests/fail/terminate-terminator.rs @@ -1,6 +1,4 @@ //@compile-flags: -Zmir-opt-level=3 -Zinline-mir-hint-threshold=1000 -//@normalize-stderr-test: "\|.*::abort\(\).*" -> "| ABORT()" -//@normalize-stderr-test: "\| +\^+" -> "| ^" //@normalize-stderr-test: "\n +[0-9]+:[^\n]+" -> "" //@normalize-stderr-test: "\n +at [^\n]+" -> "" //@error-in-other-file: aborted execution diff --git a/src/tools/miri/tests/fail/terminate-terminator.stderr b/src/tools/miri/tests/fail/terminate-terminator.stderr index 228e2d3de1f3..8ae649a392bd 100644 --- a/src/tools/miri/tests/fail/terminate-terminator.stderr +++ b/src/tools/miri/tests/fail/terminate-terminator.stderr @@ -11,13 +11,12 @@ panic in a function that cannot unwind stack backtrace: thread caused non-unwinding panic. aborting. error: abnormal termination: the program aborted execution - --> RUSTLIB/std/src/sys/pal/PLATFORM/mod.rs:LL:CC + --> RUSTLIB/std/src/panicking.rs:LL:CC | -LL | ABORT() - | ^ abnormal termination occurred here +LL | crate::process::abort(); + | ^^^^^^^^^^^^^^^^^^^^^^^ abnormal termination occurred here | = note: BACKTRACE: - = note: inside `std::sys::pal::PLATFORM::abort_internal` at RUSTLIB/std/src/sys/pal/PLATFORM/mod.rs:LL:CC = note: inside `std::panicking::panic_with_hook` at RUSTLIB/std/src/panicking.rs:LL:CC = note: inside closure at RUSTLIB/std/src/panicking.rs:LL:CC = note: inside `std::sys::backtrace::__rust_end_short_backtrace::<{closure@std::panicking::panic_handler::{closure#0}}, !>` at RUSTLIB/std/src/sys/backtrace.rs:LL:CC @@ -36,12 +35,12 @@ note: inside `panic_abort` --> tests/fail/terminate-terminator.rs:LL:CC | LL | has_cleanup(); - | ^ + | ^^^^^^^^^^^^^ note: inside `main` --> tests/fail/terminate-terminator.rs:LL:CC | LL | panic_abort(); - | ^ + | ^^^^^^^^^^^^^ note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/unwind-action-terminate.rs b/src/tools/miri/tests/fail/unwind-action-terminate.rs index f0fbcfd88675..e1c8909fffab 100644 --- a/src/tools/miri/tests/fail/unwind-action-terminate.rs +++ b/src/tools/miri/tests/fail/unwind-action-terminate.rs @@ -1,6 +1,4 @@ //@error-in-other-file: aborted execution -//@normalize-stderr-test: "\|.*::abort\(\).*" -> "| ABORT()" -//@normalize-stderr-test: "\| +\^+" -> "| ^" //@normalize-stderr-test: "\n +[0-9]+:[^\n]+" -> "" //@normalize-stderr-test: "\n +at [^\n]+" -> "" extern "C" fn panic_abort() { diff --git a/src/tools/miri/tests/fail/unwind-action-terminate.stderr b/src/tools/miri/tests/fail/unwind-action-terminate.stderr index 1c0f8cb7ec62..cf41c88ce377 100644 --- a/src/tools/miri/tests/fail/unwind-action-terminate.stderr +++ b/src/tools/miri/tests/fail/unwind-action-terminate.stderr @@ -9,13 +9,12 @@ panic in a function that cannot unwind stack backtrace: thread caused non-unwinding panic. aborting. error: abnormal termination: the program aborted execution - --> RUSTLIB/std/src/sys/pal/PLATFORM/mod.rs:LL:CC + --> RUSTLIB/std/src/panicking.rs:LL:CC | -LL | ABORT() - | ^ abnormal termination occurred here +LL | crate::process::abort(); + | ^^^^^^^^^^^^^^^^^^^^^^^ abnormal termination occurred here | = note: BACKTRACE: - = note: inside `std::sys::pal::PLATFORM::abort_internal` at RUSTLIB/std/src/sys/pal/PLATFORM/mod.rs:LL:CC = note: inside `std::panicking::panic_with_hook` at RUSTLIB/std/src/panicking.rs:LL:CC = note: inside closure at RUSTLIB/std/src/panicking.rs:LL:CC = note: inside `std::sys::backtrace::__rust_end_short_backtrace::<{closure@std::panicking::panic_handler::{closure#0}}, !>` at RUSTLIB/std/src/sys/backtrace.rs:LL:CC @@ -33,7 +32,7 @@ note: inside `main` --> tests/fail/unwind-action-terminate.rs:LL:CC | LL | panic_abort(); - | ^ + | ^^^^^^^^^^^^^ note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace From ef1dab1cb6234bb32a5b82e31b8684be0cabfcd9 Mon Sep 17 00:00:00 2001 From: The Miri Cronjob Bot Date: Wed, 3 Sep 2025 04:53:32 +0000 Subject: [PATCH 48/48] Prepare for merging from rust-lang/rust This updates the rust-version file to 51ff895062ba60a7cba53f57af928c3fb7b0f2f4. --- src/tools/miri/rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/miri/rust-version b/src/tools/miri/rust-version index 594b47b888f9..d44488399f8b 100644 --- a/src/tools/miri/rust-version +++ b/src/tools/miri/rust-version @@ -1 +1 @@ -828e45ad11ce4ab56dd64e93f1fb5dd8f0c0ae93 +51ff895062ba60a7cba53f57af928c3fb7b0f2f4