Rollup merge of #136336 - nnethercote:overhaul-rustc_middle-util, r=jieyouxu

Overhaul `rustc_middle::util`

It's an odd module with some odd stuff in it.

r? `@Noratrieb`
This commit is contained in:
Matthias Krüger 2025-01-31 12:28:20 +01:00 committed by GitHub
commit 95f746d2ef
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
16 changed files with 102 additions and 135 deletions

View File

@ -3777,7 +3777,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
let tcx = self.infcx.tcx;
if let Some(Terminator { kind: TerminatorKind::Call { call_source, fn_span, .. }, .. }) =
&self.body[loan.reserve_location.block].terminator
&& let Some((method_did, method_args)) = rustc_middle::util::find_self_call(
&& let Some((method_did, method_args)) = mir::find_self_call(
tcx,
self.body,
loan.assigned_place.local,

View File

@ -17,7 +17,7 @@ use rustc_middle::mir::tcx::PlaceTy;
use rustc_middle::mir::{
AggregateKind, CallSource, ConstOperand, ConstraintCategory, FakeReadCause, Local, LocalInfo,
LocalKind, Location, Operand, Place, PlaceRef, ProjectionElem, Rvalue, Statement,
StatementKind, Terminator, TerminatorKind,
StatementKind, Terminator, TerminatorKind, find_self_call,
};
use rustc_middle::ty::print::Print;
use rustc_middle::ty::{self, Ty, TyCtxt};
@ -1016,12 +1016,9 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
kind: TerminatorKind::Call { fn_span, call_source, .. }, ..
}) = &self.body[location.block].terminator
{
let Some((method_did, method_args)) = rustc_middle::util::find_self_call(
self.infcx.tcx,
self.body,
target_temp,
location.block,
) else {
let Some((method_did, method_args)) =
find_self_call(self.infcx.tcx, self.body, target_temp, location.block)
else {
return normal_ret;
};

View File

@ -76,6 +76,7 @@ pub mod sync;
pub mod tagged_ptr;
pub mod temp_dir;
pub mod thinvec;
pub mod thousands;
pub mod transitive_relation;
pub mod unhash;
pub mod unord;

View File

@ -0,0 +1,16 @@
//! This is an extremely bare-bones alternative to the `thousands` crate on
//! crates.io, for printing large numbers in a readable fashion.
#[cfg(test)]
mod tests;
// Converts the number to a string, with underscores as the thousands separator.
pub fn format_with_underscores(n: usize) -> String {
let mut s = n.to_string();
let mut i = s.len();
while i > 3 {
i -= 3;
s.insert(i, '_');
}
s
}

View File

@ -0,0 +1,14 @@
use super::*;
#[test]
fn test_format_with_underscores() {
assert_eq!("0", format_with_underscores(0));
assert_eq!("1", format_with_underscores(1));
assert_eq!("99", format_with_underscores(99));
assert_eq!("345", format_with_underscores(345));
assert_eq!("1_000", format_with_underscores(1_000));
assert_eq!("12_001", format_with_underscores(12_001));
assert_eq!("999_999", format_with_underscores(999_999));
assert_eq!("1_000_000", format_with_underscores(1_000_000));
assert_eq!("12_345_678", format_with_underscores(12_345_678));
}

View File

@ -9,6 +9,7 @@ use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
use rustc_data_structures::memmap::{Mmap, MmapMut};
use rustc_data_structures::sync::{Lrc, join, par_for_each_in};
use rustc_data_structures::temp_dir::MaybeTempDir;
use rustc_data_structures::thousands::format_with_underscores;
use rustc_feature::Features;
use rustc_hir as hir;
use rustc_hir::def_id::{CRATE_DEF_ID, CRATE_DEF_INDEX, LOCAL_CRATE, LocalDefId, LocalDefIdSet};
@ -22,7 +23,6 @@ use rustc_middle::traits::specialization_graph;
use rustc_middle::ty::codec::TyEncoder;
use rustc_middle::ty::fast_reject::{self, TreatParams};
use rustc_middle::ty::{AssocItemContainer, SymbolName};
use rustc_middle::util::common::to_readable_str;
use rustc_middle::{bug, span_bug};
use rustc_serialize::{Decodable, Decoder, Encodable, Encoder, opaque};
use rustc_session::config::{CrateType, OptLevel};
@ -782,7 +782,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
"{} {:<23}{:>10} ({:4.1}%)",
prefix,
label,
to_readable_str(size),
format_with_underscores(size),
perc(size)
);
}
@ -791,7 +791,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
"{} {:<23}{:>10} (of which {:.1}% are zero bytes)",
prefix,
"Total",
to_readable_str(total_bytes),
format_with_underscores(total_bytes),
perc(zero_bytes)
);
eprintln!("{prefix}");

View File

@ -4,8 +4,8 @@
///
/// If you have a span available, you should use [`span_bug`] instead.
///
/// If the bug should only be emitted when compilation didn't fail, [`DiagCtxtHandle::span_delayed_bug`]
/// may be useful.
/// If the bug should only be emitted when compilation didn't fail,
/// [`DiagCtxtHandle::span_delayed_bug`] may be useful.
///
/// [`DiagCtxtHandle::span_delayed_bug`]: rustc_errors::DiagCtxtHandle::span_delayed_bug
/// [`span_bug`]: crate::span_bug
@ -14,14 +14,8 @@ macro_rules! bug {
() => (
$crate::bug!("impossible case reached")
);
($msg:expr) => (
$crate::util::bug::bug_fmt(::std::format_args!($msg))
);
($msg:expr,) => (
$crate::bug!($msg)
);
($fmt:expr, $($arg:tt)+) => (
$crate::util::bug::bug_fmt(::std::format_args!($fmt, $($arg)+))
($($arg:tt)+) => (
$crate::util::bug::bug_fmt(::std::format_args!($($arg)+))
);
}
@ -30,20 +24,14 @@ macro_rules! bug {
/// at the code the compiler was compiling when it ICEd. This is the preferred way to trigger
/// ICEs.
///
/// If the bug should only be emitted when compilation didn't fail, [`DiagCtxtHandle::span_delayed_bug`]
/// may be useful.
/// If the bug should only be emitted when compilation didn't fail,
/// [`DiagCtxtHandle::span_delayed_bug`] may be useful.
///
/// [`DiagCtxtHandle::span_delayed_bug`]: rustc_errors::DiagCtxtHandle::span_delayed_bug
#[macro_export]
macro_rules! span_bug {
($span:expr, $msg:expr) => (
$crate::util::bug::span_bug_fmt($span, ::std::format_args!($msg))
);
($span:expr, $msg:expr,) => (
$crate::span_bug!($span, $msg)
);
($span:expr, $fmt:expr, $($arg:tt)+) => (
$crate::util::bug::span_bug_fmt($span, ::std::format_args!($fmt, $($arg)+))
($span:expr, $($arg:tt)+) => (
$crate::util::bug::span_bug_fmt($span, ::std::format_args!($($arg)+))
);
}
@ -53,7 +41,6 @@ macro_rules! span_bug {
// When possible, use one of these (relatively) convenient macros to write
// the impls for you.
#[macro_export]
macro_rules! TrivialLiftImpls {
($($ty:ty),+ $(,)?) => {
$(
@ -69,7 +56,6 @@ macro_rules! TrivialLiftImpls {
/// Used for types that are `Copy` and which **do not care about arena
/// allocated data** (i.e., don't need to be folded).
#[macro_export]
macro_rules! TrivialTypeTraversalImpls {
($($ty:ty),+ $(,)?) => {
$(
@ -104,7 +90,6 @@ macro_rules! TrivialTypeTraversalImpls {
};
}
#[macro_export]
macro_rules! TrivialTypeTraversalAndLiftImpls {
($($t:tt)*) => {
TrivialTypeTraversalImpls! { $($t)* }

View File

@ -27,7 +27,7 @@ use rustc_macros::{HashStable, TyDecodable, TyEncodable, TypeFoldable, TypeVisit
use rustc_serialize::{Decodable, Encodable};
use rustc_span::source_map::Spanned;
use rustc_span::{DUMMY_SP, Span, Symbol};
use tracing::trace;
use tracing::{debug, trace};
pub use self::query::*;
use self::visit::TyContext;
@ -1796,6 +1796,47 @@ impl DefLocation {
}
}
/// Checks if the specified `local` is used as the `self` parameter of a method call
/// in the provided `BasicBlock`. If it is, then the `DefId` of the called method is
/// returned.
pub fn find_self_call<'tcx>(
tcx: TyCtxt<'tcx>,
body: &Body<'tcx>,
local: Local,
block: BasicBlock,
) -> Option<(DefId, GenericArgsRef<'tcx>)> {
debug!("find_self_call(local={:?}): terminator={:?}", local, body[block].terminator);
if let Some(Terminator { kind: TerminatorKind::Call { func, args, .. }, .. }) =
&body[block].terminator
&& let Operand::Constant(box ConstOperand { const_, .. }) = func
&& let ty::FnDef(def_id, fn_args) = *const_.ty().kind()
&& let Some(ty::AssocItem { fn_has_self_parameter: true, .. }) =
tcx.opt_associated_item(def_id)
&& let [Spanned { node: Operand::Move(self_place) | Operand::Copy(self_place), .. }, ..] =
**args
{
if self_place.as_local() == Some(local) {
return Some((def_id, fn_args));
}
// Handle the case where `self_place` gets reborrowed.
// This happens when the receiver is `&T`.
for stmt in &body[block].statements {
if let StatementKind::Assign(box (place, rvalue)) = &stmt.kind
&& let Some(reborrow_local) = place.as_local()
&& self_place.as_local() == Some(reborrow_local)
&& let Rvalue::Ref(_, _, deref_place) = rvalue
&& let PlaceRef { local: deref_local, projection: [ProjectionElem::Deref] } =
deref_place.as_ref()
&& deref_local == local
{
return Some((def_id, fn_args));
}
}
}
None
}
// Some nodes are used a lot. Make sure they don't unintentionally get bigger.
#[cfg(target_pointer_width = "64")]
mod size_asserts {

View File

@ -428,7 +428,7 @@ pub enum IsConstable {
Ctor,
}
crate::TrivialTypeTraversalAndLiftImpls! {
TrivialTypeTraversalAndLiftImpls! {
IsConstable,
}

View File

@ -1,4 +1,4 @@
// These functions are used by macro expansion for bug! and span_bug!
// These functions are used by macro expansion for `bug!` and `span_bug!`.
use std::fmt;
use std::panic::{Location, panic_any};
@ -8,15 +8,15 @@ use rustc_span::Span;
use crate::ty::{TyCtxt, tls};
// This wrapper makes for more compact code at callsites than calling `opt_span_buf_fmt` directly.
#[cold]
#[inline(never)]
#[track_caller]
pub fn bug_fmt(args: fmt::Arguments<'_>) -> ! {
// this wrapper mostly exists so I don't have to write a fully
// qualified path of None::<Span> inside the bug!() macro definition
opt_span_bug_fmt(None::<Span>, args, Location::caller());
}
// This wrapper makes for more compact code at callsites than calling `opt_span_buf_fmt` directly.
#[cold]
#[inline(never)]
#[track_caller]

View File

@ -1,22 +0,0 @@
#[cfg(test)]
mod tests;
pub fn to_readable_str(mut val: usize) -> String {
let mut groups = vec![];
loop {
let group = val % 1000;
val /= 1000;
if val == 0 {
groups.push(group.to_string());
break;
} else {
groups.push(format!("{group:03}"));
}
}
groups.reverse();
groups.join("_")
}

View File

@ -1,14 +0,0 @@
use super::*;
#[test]
fn test_to_readable_str() {
assert_eq!("0", to_readable_str(0));
assert_eq!("1", to_readable_str(1));
assert_eq!("99", to_readable_str(99));
assert_eq!("999", to_readable_str(999));
assert_eq!("1_000", to_readable_str(1_000));
assert_eq!("1_001", to_readable_str(1_001));
assert_eq!("999_999", to_readable_str(999_999));
assert_eq!("1_000_000", to_readable_str(1_000_000));
assert_eq!("1_234_567", to_readable_str(1_234_567));
}

View File

@ -1,47 +0,0 @@
use rustc_span::def_id::DefId;
use rustc_span::source_map::Spanned;
use tracing::debug;
use crate::mir::*;
use crate::ty::{self, GenericArgsRef, TyCtxt};
/// Checks if the specified `local` is used as the `self` parameter of a method call
/// in the provided `BasicBlock`. If it is, then the `DefId` of the called method is
/// returned.
pub fn find_self_call<'tcx>(
tcx: TyCtxt<'tcx>,
body: &Body<'tcx>,
local: Local,
block: BasicBlock,
) -> Option<(DefId, GenericArgsRef<'tcx>)> {
debug!("find_self_call(local={:?}): terminator={:?}", local, body[block].terminator);
if let Some(Terminator { kind: TerminatorKind::Call { func, args, .. }, .. }) =
&body[block].terminator
&& let Operand::Constant(box ConstOperand { const_, .. }) = func
&& let ty::FnDef(def_id, fn_args) = *const_.ty().kind()
&& let Some(ty::AssocItem { fn_has_self_parameter: true, .. }) =
tcx.opt_associated_item(def_id)
&& let [Spanned { node: Operand::Move(self_place) | Operand::Copy(self_place), .. }, ..] =
**args
{
if self_place.as_local() == Some(local) {
return Some((def_id, fn_args));
}
// Handle the case where `self_place` gets reborrowed.
// This happens when the receiver is `&T`.
for stmt in &body[block].statements {
if let StatementKind::Assign(box (place, rvalue)) = &stmt.kind
&& let Some(reborrow_local) = place.as_local()
&& self_place.as_local() == Some(reborrow_local)
&& let Rvalue::Ref(_, _, deref_place) = rvalue
&& let PlaceRef { local: deref_local, projection: [ProjectionElem::Deref] } =
deref_place.as_ref()
&& deref_local == local
{
return Some((def_id, fn_args));
}
}
}
None
}

View File

@ -1,8 +1,4 @@
pub mod bug;
pub mod common;
pub mod find_self_call;
pub use find_self_call::find_self_call;
#[derive(Default, Copy, Clone)]
pub struct Providers {

View File

@ -133,7 +133,7 @@ impl<'tcx> Visitor<'tcx> for ConstMutationChecker<'_, 'tcx> {
// the `self` parameter of a method call (as the terminator of our current
// BasicBlock). If so, we emit a more specific lint.
let method_did = self.target_local.and_then(|target_local| {
rustc_middle::util::find_self_call(self.tcx, self.body, target_local, loc.block)
find_self_call(self.tcx, self.body, target_local, loc.block)
});
let lint_loc =
if method_did.is_some() { self.body.terminator_loc(loc.block) } else { loc };

View File

@ -5,10 +5,10 @@
use rustc_ast::visit::BoundKind;
use rustc_ast::{self as ast, NodeId, visit as ast_visit};
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_data_structures::thousands::format_with_underscores;
use rustc_hir::{self as hir, AmbigArg, HirId, intravisit as hir_visit};
use rustc_middle::hir::map::Map;
use rustc_middle::ty::TyCtxt;
use rustc_middle::util::common::to_readable_str;
use rustc_span::Span;
use rustc_span::def_id::LocalDefId;
@ -144,10 +144,10 @@ impl<'k> StatCollector<'k> {
"{} {:<18}{:>10} ({:4.1}%){:>14}{:>14}",
prefix,
label,
to_readable_str(size),
format_with_underscores(size),
percent(size, total_size),
to_readable_str(node.stats.count),
to_readable_str(node.stats.size)
format_with_underscores(node.stats.count),
format_with_underscores(node.stats.size)
);
if !node.subnodes.is_empty() {
// We will soon sort, so the initial order does not matter.
@ -163,9 +163,9 @@ impl<'k> StatCollector<'k> {
"{} - {:<18}{:>10} ({:4.1}%){:>14}",
prefix,
label,
to_readable_str(size),
format_with_underscores(size),
percent(size, total_size),
to_readable_str(subnode.count),
format_with_underscores(subnode.count),
);
}
}
@ -175,8 +175,8 @@ impl<'k> StatCollector<'k> {
"{} {:<18}{:>10} {:>14}",
prefix,
"Total",
to_readable_str(total_size),
to_readable_str(total_count),
format_with_underscores(total_size),
format_with_underscores(total_count),
);
eprintln!("{prefix}");
}