2020-03-05 18:07:42 -03:00
|
|
|
//! MIR datatypes and passes. See the [rustc dev guide] for more info.
|
2017-12-31 17:08:04 +01:00
|
|
|
//!
|
2020-03-09 18:33:04 -03:00
|
|
|
//! [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/mir/index.html
|
2017-04-29 05:28:35 -04:00
|
|
|
|
2023-09-29 22:38:52 +02:00
|
|
|
use crate::mir::interpret::{AllocRange, ConstAllocation, Scalar};
|
2019-02-05 11:20:45 -06:00
|
|
|
use crate::mir::visit::MirVisitable;
|
2020-06-11 15:49:57 +01:00
|
|
|
use crate::ty::codec::{TyDecoder, TyEncoder};
|
2023-02-22 02:18:40 +00:00
|
|
|
use crate::ty::fold::{FallibleTypeFolder, TypeFoldable};
|
2023-09-14 23:33:42 +02:00
|
|
|
use crate::ty::print::{pretty_print_const, with_no_trimmed_paths};
|
2019-07-12 22:49:15 +02:00
|
|
|
use crate::ty::print::{FmtPrinter, Printer};
|
2023-04-26 14:53:14 +10:00
|
|
|
use crate::ty::visit::TypeVisitableExt;
|
2023-02-22 19:51:17 +04:00
|
|
|
use crate::ty::{self, List, Ty, TyCtxt};
|
2023-09-14 23:25:34 +02:00
|
|
|
use crate::ty::{AdtDef, InstanceDef, UserTypeAnnotationIndex};
|
|
|
|
use crate::ty::{GenericArg, GenericArgsRef};
|
2021-03-15 15:09:06 -07:00
|
|
|
|
2022-05-22 12:48:19 -07:00
|
|
|
use rustc_data_structures::captures::Captures;
|
2023-05-17 10:30:14 +00:00
|
|
|
use rustc_errors::{DiagnosticArgValue, DiagnosticMessage, ErrorGuaranteed, IntoDiagnosticArg};
|
2020-01-05 02:37:57 +01:00
|
|
|
use rustc_hir::def::{CtorKind, Namespace};
|
2023-09-14 23:25:34 +02:00
|
|
|
use rustc_hir::def_id::{DefId, CRATE_DEF_ID};
|
2022-08-27 14:07:59 +02:00
|
|
|
use rustc_hir::{self, GeneratorKind, ImplicitSelfKind};
|
2021-03-26 13:39:04 +00:00
|
|
|
use rustc_hir::{self as hir, HirId};
|
2021-11-29 22:46:32 -08:00
|
|
|
use rustc_session::Session;
|
2023-09-14 23:33:42 +02:00
|
|
|
use rustc_target::abi::{FieldIdx, VariantIdx};
|
2019-09-06 03:57:44 +01:00
|
|
|
|
2019-07-12 22:48:02 +02:00
|
|
|
use polonius_engine::Atom;
|
2020-04-27 23:26:11 +05:30
|
|
|
pub use rustc_ast::Mutability;
|
2023-09-13 13:05:15 +02:00
|
|
|
use rustc_data_structures::fx::FxHashMap;
|
2018-11-05 15:14:28 +01:00
|
|
|
use rustc_data_structures::fx::FxHashSet;
|
2022-07-05 00:00:00 +00:00
|
|
|
use rustc_data_structures::graph::dominators::Dominators;
|
2023-04-19 10:57:17 +00:00
|
|
|
use rustc_index::{Idx, IndexSlice, IndexVec};
|
2019-07-23 18:50:47 +03:00
|
|
|
use rustc_serialize::{Decodable, Encodable};
|
2020-01-01 19:30:57 +01:00
|
|
|
use rustc_span::symbol::Symbol;
|
2019-12-31 20:15:40 +03:00
|
|
|
use rustc_span::{Span, DUMMY_SP};
|
2021-03-15 15:09:06 -07:00
|
|
|
|
|
|
|
use either::Either;
|
|
|
|
|
2018-06-19 21:22:52 -03:00
|
|
|
use std::borrow::Cow;
|
2023-09-13 13:05:15 +02:00
|
|
|
use std::cell::RefCell;
|
|
|
|
use std::collections::hash_map::Entry;
|
2023-09-15 08:49:37 +02:00
|
|
|
use std::fmt::{self, Debug, Formatter};
|
2023-04-26 14:53:14 +10:00
|
|
|
use std::ops::{Index, IndexMut};
|
2022-06-28 20:05:23 -04:00
|
|
|
use std::{iter, mem};
|
2015-08-18 17:59:21 -04:00
|
|
|
|
2020-01-05 15:46:44 +00:00
|
|
|
pub use self::query::*;
|
2022-07-04 00:00:00 +00:00
|
|
|
pub use basic_blocks::BasicBlocks;
|
2018-04-27 15:21:31 +02:00
|
|
|
|
2022-07-04 00:00:00 +00:00
|
|
|
mod basic_blocks;
|
2023-09-14 23:25:34 +02:00
|
|
|
mod consts;
|
2020-06-21 23:29:08 -07:00
|
|
|
pub mod coverage;
|
2021-01-05 19:53:07 +01:00
|
|
|
mod generic_graph;
|
|
|
|
pub mod generic_graphviz;
|
|
|
|
pub mod graphviz;
|
2017-09-18 16:18:23 +02:00
|
|
|
pub mod interpret;
|
2017-10-27 10:50:39 +02:00
|
|
|
pub mod mono;
|
2021-01-05 19:53:07 +01:00
|
|
|
pub mod patch;
|
|
|
|
pub mod pretty;
|
2020-01-05 15:46:44 +00:00
|
|
|
mod query;
|
2021-01-05 19:53:07 +01:00
|
|
|
pub mod spanview;
|
2023-09-15 08:49:37 +02:00
|
|
|
mod statement;
|
2022-06-28 20:05:23 -04:00
|
|
|
mod syntax;
|
2018-06-19 21:22:52 -03:00
|
|
|
pub mod tcx;
|
2023-09-14 23:25:34 +02:00
|
|
|
mod terminator;
|
2022-04-28 11:31:08 +08:00
|
|
|
|
2018-06-19 21:22:52 -03:00
|
|
|
pub mod traversal;
|
2020-03-23 22:39:59 +01:00
|
|
|
mod type_foldable;
|
2018-06-19 21:22:52 -03:00
|
|
|
pub mod visit;
|
2016-06-07 22:02:08 +03:00
|
|
|
|
2021-01-05 19:53:07 +01:00
|
|
|
pub use self::generic_graph::graphviz_safe_def_name;
|
|
|
|
pub use self::graphviz::write_mir_graphviz;
|
|
|
|
pub use self::pretty::{
|
|
|
|
create_dump_file, display_allocation, dump_enabled, dump_mir, write_mir_pretty, PassWhere,
|
|
|
|
};
|
2023-09-14 23:33:42 +02:00
|
|
|
pub use consts::*;
|
2023-09-15 08:21:40 +02:00
|
|
|
use pretty::pretty_print_const_value;
|
2023-09-15 08:49:37 +02:00
|
|
|
pub use statement::*;
|
2023-09-14 23:33:42 +02:00
|
|
|
pub use syntax::*;
|
|
|
|
pub use terminator::*;
|
2021-01-05 19:53:07 +01:00
|
|
|
|
2017-07-11 16:02:06 -07:00
|
|
|
/// Types for locals
|
2023-03-31 00:32:44 -07:00
|
|
|
pub type LocalDecls<'tcx> = IndexSlice<Local, LocalDecl<'tcx>>;
|
2017-07-11 16:02:06 -07:00
|
|
|
|
2017-07-12 13:15:29 -07:00
|
|
|
pub trait HasLocalDecls<'tcx> {
|
|
|
|
fn local_decls(&self) -> &LocalDecls<'tcx>;
|
2017-07-12 12:59:05 -07:00
|
|
|
}
|
|
|
|
|
2023-03-31 00:32:44 -07:00
|
|
|
impl<'tcx> HasLocalDecls<'tcx> for IndexVec<Local, LocalDecl<'tcx>> {
|
|
|
|
#[inline]
|
|
|
|
fn local_decls(&self) -> &LocalDecls<'tcx> {
|
|
|
|
self
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-07-12 13:15:29 -07:00
|
|
|
impl<'tcx> HasLocalDecls<'tcx> for LocalDecls<'tcx> {
|
2021-02-26 00:00:00 +00:00
|
|
|
#[inline]
|
2017-07-12 13:15:29 -07:00
|
|
|
fn local_decls(&self) -> &LocalDecls<'tcx> {
|
2017-07-12 12:59:05 -07:00
|
|
|
self
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-05-17 23:55:04 +02:00
|
|
|
impl<'tcx> HasLocalDecls<'tcx> for Body<'tcx> {
|
2021-02-26 00:00:00 +00:00
|
|
|
#[inline]
|
2017-07-12 13:15:29 -07:00
|
|
|
fn local_decls(&self) -> &LocalDecls<'tcx> {
|
2017-07-12 12:59:05 -07:00
|
|
|
&self.local_decls
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-09-13 13:05:15 +02:00
|
|
|
thread_local! {
|
|
|
|
static PASS_NAMES: RefCell<FxHashMap<&'static str, &'static str>> = {
|
|
|
|
RefCell::new(FxHashMap::default())
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Converts a MIR pass name into a snake case form to match the profiling naming style.
|
|
|
|
fn to_profiler_name(type_name: &'static str) -> &'static str {
|
|
|
|
PASS_NAMES.with(|names| match names.borrow_mut().entry(type_name) {
|
|
|
|
Entry::Occupied(e) => *e.get(),
|
|
|
|
Entry::Vacant(e) => {
|
|
|
|
let snake_case: String = type_name
|
|
|
|
.chars()
|
|
|
|
.flat_map(|c| {
|
|
|
|
if c.is_ascii_uppercase() {
|
|
|
|
vec!['_', c.to_ascii_lowercase()]
|
|
|
|
} else if c == '-' {
|
|
|
|
vec!['_']
|
|
|
|
} else {
|
|
|
|
vec![c]
|
|
|
|
}
|
|
|
|
})
|
|
|
|
.collect();
|
|
|
|
let result = &*String::leak(format!("mir_pass{}", snake_case));
|
|
|
|
e.insert(result);
|
|
|
|
result
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2021-01-05 19:53:07 +01:00
|
|
|
/// A streamlined trait that you can implement to create a pass; the
|
|
|
|
/// pass will be named after the type, and it will consist of a main
|
|
|
|
/// loop that goes over each available MIR and applies `run_pass`.
|
|
|
|
pub trait MirPass<'tcx> {
|
2023-05-15 20:23:34 +00:00
|
|
|
fn name(&self) -> &'static str {
|
2021-01-05 19:53:07 +01:00
|
|
|
let name = std::any::type_name::<Self>();
|
2022-12-01 08:38:47 +00:00
|
|
|
if let Some((_, tail)) = name.rsplit_once(':') { tail } else { name }
|
2021-01-05 19:53:07 +01:00
|
|
|
}
|
|
|
|
|
2023-09-13 13:05:15 +02:00
|
|
|
fn profiler_name(&self) -> &'static str {
|
|
|
|
to_profiler_name(self.name())
|
|
|
|
}
|
|
|
|
|
2021-11-29 22:46:32 -08:00
|
|
|
/// Returns `true` if this pass is enabled with the current combination of compiler flags.
|
|
|
|
fn is_enabled(&self, _sess: &Session) -> bool {
|
|
|
|
true
|
|
|
|
}
|
|
|
|
|
2021-01-05 19:53:07 +01:00
|
|
|
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>);
|
2021-11-29 22:46:32 -08:00
|
|
|
|
|
|
|
fn is_mir_dump_enabled(&self) -> bool {
|
|
|
|
true
|
|
|
|
}
|
2021-01-05 19:53:07 +01:00
|
|
|
}
|
|
|
|
|
2018-10-21 10:47:01 -04:00
|
|
|
impl MirPhase {
|
2019-09-06 03:57:44 +01:00
|
|
|
/// Gets the index of the current MirPhase within the set of all `MirPhase`s.
|
2022-07-09 18:04:38 -07:00
|
|
|
///
|
|
|
|
/// FIXME(JakobDegen): Return a `(usize, usize)` instead.
|
2018-10-21 10:47:01 -04:00
|
|
|
pub fn phase_index(&self) -> usize {
|
2022-07-09 18:04:38 -07:00
|
|
|
const BUILT_PHASE_COUNT: usize = 1;
|
|
|
|
const ANALYSIS_PHASE_COUNT: usize = 2;
|
|
|
|
match self {
|
|
|
|
MirPhase::Built => 1,
|
|
|
|
MirPhase::Analysis(analysis_phase) => {
|
|
|
|
1 + BUILT_PHASE_COUNT + (*analysis_phase as usize)
|
|
|
|
}
|
|
|
|
MirPhase::Runtime(runtime_phase) => {
|
|
|
|
1 + BUILT_PHASE_COUNT + ANALYSIS_PHASE_COUNT + (*runtime_phase as usize)
|
|
|
|
}
|
|
|
|
}
|
2018-10-21 10:47:01 -04:00
|
|
|
}
|
2022-08-03 04:30:13 -07:00
|
|
|
|
|
|
|
/// Parses an `MirPhase` from a pair of strings. Panics if this isn't possible for any reason.
|
|
|
|
pub fn parse(dialect: String, phase: Option<String>) -> Self {
|
|
|
|
match &*dialect.to_ascii_lowercase() {
|
|
|
|
"built" => {
|
|
|
|
assert!(phase.is_none(), "Cannot specify a phase for `Built` MIR");
|
|
|
|
MirPhase::Built
|
|
|
|
}
|
|
|
|
"analysis" => Self::Analysis(AnalysisPhase::parse(phase)),
|
|
|
|
"runtime" => Self::Runtime(RuntimePhase::parse(phase)),
|
2023-06-17 12:36:14 +02:00
|
|
|
_ => bug!("Unknown MIR dialect: '{}'", dialect),
|
2022-08-03 04:30:13 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl AnalysisPhase {
|
|
|
|
pub fn parse(phase: Option<String>) -> Self {
|
|
|
|
let Some(phase) = phase else {
|
|
|
|
return Self::Initial;
|
|
|
|
};
|
|
|
|
|
|
|
|
match &*phase.to_ascii_lowercase() {
|
|
|
|
"initial" => Self::Initial,
|
|
|
|
"post_cleanup" | "post-cleanup" | "postcleanup" => Self::PostCleanup,
|
2023-06-17 12:36:14 +02:00
|
|
|
_ => bug!("Unknown analysis phase: '{}'", phase),
|
2022-08-03 04:30:13 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl RuntimePhase {
|
|
|
|
pub fn parse(phase: Option<String>) -> Self {
|
|
|
|
let Some(phase) = phase else {
|
|
|
|
return Self::Initial;
|
|
|
|
};
|
|
|
|
|
|
|
|
match &*phase.to_ascii_lowercase() {
|
|
|
|
"initial" => Self::Initial,
|
|
|
|
"post_cleanup" | "post-cleanup" | "postcleanup" => Self::PostCleanup,
|
|
|
|
"optimized" => Self::Optimized,
|
2023-06-17 12:36:14 +02:00
|
|
|
_ => bug!("Unknown runtime phase: '{}'", phase),
|
2022-08-03 04:30:13 -07:00
|
|
|
}
|
|
|
|
}
|
2018-10-21 10:47:01 -04:00
|
|
|
}
|
|
|
|
|
2020-10-04 11:01:13 -07:00
|
|
|
/// Where a specific `mir::Body` comes from.
|
2022-01-18 10:05:41 -06:00
|
|
|
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
2022-06-17 10:53:29 +01:00
|
|
|
#[derive(HashStable, TyEncodable, TyDecodable, TypeFoldable, TypeVisitable)]
|
2020-10-04 11:01:13 -07:00
|
|
|
pub struct MirSource<'tcx> {
|
|
|
|
pub instance: InstanceDef<'tcx>,
|
|
|
|
|
|
|
|
/// If `Some`, this is a promoted rvalue within the parent function.
|
|
|
|
pub promoted: Option<Promoted>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'tcx> MirSource<'tcx> {
|
|
|
|
pub fn item(def_id: DefId) -> Self {
|
2022-05-08 15:53:19 +02:00
|
|
|
MirSource { instance: InstanceDef::Item(def_id), promoted: None }
|
2020-10-04 11:01:13 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
pub fn from_instance(instance: InstanceDef<'tcx>) -> Self {
|
|
|
|
MirSource { instance, promoted: None }
|
|
|
|
}
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
pub fn def_id(&self) -> DefId {
|
|
|
|
self.instance.def_id()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-06-17 10:53:29 +01:00
|
|
|
#[derive(Clone, TyEncodable, TyDecodable, Debug, HashStable, TypeFoldable, TypeVisitable)]
|
2021-01-17 13:27:05 +01:00
|
|
|
pub struct GeneratorInfo<'tcx> {
|
|
|
|
/// The yield type of the function, if it is a generator.
|
|
|
|
pub yield_ty: Option<Ty<'tcx>>,
|
|
|
|
|
|
|
|
/// Generator drop glue.
|
|
|
|
pub generator_drop: Option<Body<'tcx>>,
|
|
|
|
|
|
|
|
/// The layout of a generator. Produced by the state transformation.
|
|
|
|
pub generator_layout: Option<GeneratorLayout<'tcx>>,
|
|
|
|
|
|
|
|
/// If this is a generator then record the type of source expression that caused this generator
|
|
|
|
/// to be created.
|
|
|
|
pub generator_kind: GeneratorKind,
|
|
|
|
}
|
|
|
|
|
2019-09-06 03:57:44 +01:00
|
|
|
/// The lowered representation of a single function.
|
2022-06-17 10:53:29 +01:00
|
|
|
#[derive(Clone, TyEncodable, TyDecodable, Debug, HashStable, TypeFoldable, TypeVisitable)]
|
2019-05-17 23:55:04 +02:00
|
|
|
pub struct Body<'tcx> {
|
2020-10-16 20:35:56 -07:00
|
|
|
/// A list of basic blocks. References to basic block use a newtyped index type [`BasicBlock`]
|
2015-11-12 14:29:23 -05:00
|
|
|
/// that indexes into this vector.
|
2022-07-04 00:00:00 +00:00
|
|
|
pub basic_blocks: BasicBlocks<'tcx>,
|
2015-08-18 17:59:21 -04:00
|
|
|
|
2018-10-20 16:18:17 -04:00
|
|
|
/// Records how far through the "desugaring and optimization" process this particular
|
|
|
|
/// MIR has traversed. This is particularly useful when inlining, since in that context
|
|
|
|
/// we instantiate the promoted constants and add them to our promoted vector -- but those
|
|
|
|
/// promoted items have already been optimized, whereas ours have not. This field allows
|
|
|
|
/// us to see the difference and forego optimization on the inlined promoted items.
|
|
|
|
pub phase: MirPhase,
|
|
|
|
|
2022-09-26 18:43:35 -07:00
|
|
|
/// How many passses we have executed since starting the current phase. Used for debug output.
|
|
|
|
pub pass_count: usize,
|
|
|
|
|
2020-10-04 11:01:38 -07:00
|
|
|
pub source: MirSource<'tcx>,
|
|
|
|
|
2019-09-06 03:57:44 +01:00
|
|
|
/// A list of source scopes; these are referenced by statements
|
2018-05-28 14:16:09 +03:00
|
|
|
/// and used for debuginfo. Indexed by a `SourceScope`.
|
2020-02-08 21:31:09 +02:00
|
|
|
pub source_scopes: IndexVec<SourceScope, SourceScopeData<'tcx>>,
|
2016-03-09 11:04:26 -05:00
|
|
|
|
2021-01-17 13:27:05 +01:00
|
|
|
pub generator: Option<Box<GeneratorInfo<'tcx>>>,
|
2019-11-25 12:58:40 +00:00
|
|
|
|
2016-09-25 01:38:27 +02:00
|
|
|
/// Declarations of locals.
|
|
|
|
///
|
|
|
|
/// The first local is the return value pointer, followed by `arg_count`
|
|
|
|
/// locals for the function arguments, followed by any user-declared
|
|
|
|
/// variables and temporaries.
|
2023-03-31 00:32:44 -07:00
|
|
|
pub local_decls: IndexVec<Local, LocalDecl<'tcx>>,
|
2015-11-12 14:29:23 -05:00
|
|
|
|
2019-09-06 03:57:44 +01:00
|
|
|
/// User type annotations.
|
2020-10-04 10:59:11 -07:00
|
|
|
pub user_type_annotations: ty::CanonicalUserTypeAnnotations<'tcx>,
|
2018-11-16 22:56:18 +01:00
|
|
|
|
2019-09-06 03:57:44 +01:00
|
|
|
/// The number of arguments this function takes.
|
2016-09-25 01:38:27 +02:00
|
|
|
///
|
2016-09-29 01:11:54 +02:00
|
|
|
/// Starting at local 1, `arg_count` locals will be provided by the caller
|
2016-09-25 01:38:27 +02:00
|
|
|
/// and can be assumed to be initialized.
|
|
|
|
///
|
|
|
|
/// If this MIR was built for a constant, this will be 0.
|
|
|
|
pub arg_count: usize,
|
2016-02-07 21:13:00 +02:00
|
|
|
|
2016-09-26 22:44:01 +02:00
|
|
|
/// Mark an argument local (which must be a tuple) as getting passed as
|
|
|
|
/// its individual components at the LLVM level.
|
2016-09-21 00:45:30 +02:00
|
|
|
///
|
|
|
|
/// This is used for the "rust-call" ABI.
|
2016-09-26 22:44:01 +02:00
|
|
|
pub spread_arg: Option<Local>,
|
2016-09-21 00:45:30 +02:00
|
|
|
|
2018-05-16 18:58:54 +03:00
|
|
|
/// Debug information pertaining to user variables, including captures.
|
|
|
|
pub var_debug_info: Vec<VarDebugInfo<'tcx>>,
|
2018-05-16 15:40:32 +03:00
|
|
|
|
2019-09-06 03:57:44 +01:00
|
|
|
/// A span representing this MIR, for error reporting.
|
2016-02-07 21:13:00 +02:00
|
|
|
pub span: Span,
|
2019-11-22 17:26:09 -03:00
|
|
|
|
2020-04-22 11:16:06 -03:00
|
|
|
/// Constants that are required to evaluate successfully for this MIR to be well-formed.
|
|
|
|
/// We hold in this field all the constants we are not able to evaluate yet.
|
2023-09-20 20:51:14 +02:00
|
|
|
pub required_consts: Vec<ConstOperand<'tcx>>,
|
2020-04-03 18:26:24 -03:00
|
|
|
|
2020-08-06 10:00:08 +02:00
|
|
|
/// Does this body use generic parameters. This is used for the `ConstEvaluatable` check.
|
|
|
|
///
|
|
|
|
/// Note that this does not actually mean that this body is not computable right now.
|
|
|
|
/// The repeat count in the following example is polymorphic, but can still be evaluated
|
|
|
|
/// without knowing anything about the type parameter `T`.
|
|
|
|
///
|
|
|
|
/// ```rust
|
|
|
|
/// fn test<T>() {
|
|
|
|
/// let _ = [0; std::mem::size_of::<*mut T>()];
|
|
|
|
/// }
|
|
|
|
/// ```
|
2020-08-06 22:12:21 +02:00
|
|
|
///
|
|
|
|
/// **WARNING**: Do not change this flags after the MIR was originally created, even if an optimization
|
|
|
|
/// removed the last mention of all generic params. We do not want to rely on optimizations and
|
|
|
|
/// potentially allow things like `[u8; std::mem::size_of::<T>() * 0]` due to this.
|
2020-08-06 10:00:08 +02:00
|
|
|
pub is_polymorphic: bool,
|
|
|
|
|
2022-08-03 04:30:13 -07:00
|
|
|
/// The phase at which this MIR should be "injected" into the compilation process.
|
|
|
|
///
|
|
|
|
/// Everything that comes before this `MirPhase` should be skipped.
|
|
|
|
///
|
|
|
|
/// This is only `Some` if the function that this body comes from was annotated with `rustc_custom_mir`.
|
|
|
|
pub injection_phase: Option<MirPhase>,
|
|
|
|
|
2022-01-23 12:34:26 -06:00
|
|
|
pub tainted_by_errors: Option<ErrorGuaranteed>,
|
2023-09-10 16:35:37 +10:00
|
|
|
|
|
|
|
/// Per-function coverage information added by the `InstrumentCoverage`
|
|
|
|
/// pass, to be used in conjunction with the coverage statements injected
|
|
|
|
/// into this body's blocks.
|
|
|
|
///
|
|
|
|
/// If `-Cinstrument-coverage` is not active, or if an individual function
|
|
|
|
/// is not eligible for coverage, then this should always be `None`.
|
|
|
|
pub function_coverage_info: Option<Box<coverage::FunctionCoverageInfo>>,
|
2015-08-18 17:59:21 -04:00
|
|
|
}
|
|
|
|
|
2019-05-17 23:55:04 +02:00
|
|
|
impl<'tcx> Body<'tcx> {
|
2018-06-19 21:22:52 -03:00
|
|
|
pub fn new(
|
2020-10-04 11:01:38 -07:00
|
|
|
source: MirSource<'tcx>,
|
2018-06-19 21:22:52 -03:00
|
|
|
basic_blocks: IndexVec<BasicBlock, BasicBlockData<'tcx>>,
|
2020-02-08 21:31:09 +02:00
|
|
|
source_scopes: IndexVec<SourceScope, SourceScopeData<'tcx>>,
|
2023-03-31 00:32:44 -07:00
|
|
|
local_decls: IndexVec<Local, LocalDecl<'tcx>>,
|
2020-10-04 10:59:11 -07:00
|
|
|
user_type_annotations: ty::CanonicalUserTypeAnnotations<'tcx>,
|
2018-06-19 21:22:52 -03:00
|
|
|
arg_count: usize,
|
2018-05-16 18:58:54 +03:00
|
|
|
var_debug_info: Vec<VarDebugInfo<'tcx>>,
|
2018-06-19 21:22:52 -03:00
|
|
|
span: Span,
|
2019-11-25 12:58:40 +00:00
|
|
|
generator_kind: Option<GeneratorKind>,
|
2022-01-23 12:34:26 -06:00
|
|
|
tainted_by_errors: Option<ErrorGuaranteed>,
|
2018-06-19 21:22:52 -03:00
|
|
|
) -> Self {
|
2019-09-06 03:57:44 +01:00
|
|
|
// We need `arg_count` locals, and one for the return place.
|
2018-06-19 21:22:52 -03:00
|
|
|
assert!(
|
2020-03-02 18:53:56 +01:00
|
|
|
local_decls.len() > arg_count,
|
2018-06-19 21:22:52 -03:00
|
|
|
"expected at least {} locals, got {}",
|
|
|
|
arg_count + 1,
|
|
|
|
local_decls.len()
|
|
|
|
);
|
2016-09-25 01:38:27 +02:00
|
|
|
|
2020-08-06 10:00:08 +02:00
|
|
|
let mut body = Body {
|
2022-03-05 20:37:04 -05:00
|
|
|
phase: MirPhase::Built,
|
2022-12-02 15:55:02 +00:00
|
|
|
pass_count: 0,
|
2020-10-04 11:01:38 -07:00
|
|
|
source,
|
2022-07-04 00:00:00 +00:00
|
|
|
basic_blocks: BasicBlocks::new(basic_blocks),
|
2018-05-28 14:16:09 +03:00
|
|
|
source_scopes,
|
2021-01-17 13:27:05 +01:00
|
|
|
generator: generator_kind.map(|generator_kind| {
|
|
|
|
Box::new(GeneratorInfo {
|
|
|
|
yield_ty: None,
|
|
|
|
generator_drop: None,
|
|
|
|
generator_layout: None,
|
|
|
|
generator_kind,
|
|
|
|
})
|
|
|
|
}),
|
2017-07-03 11:19:51 -07:00
|
|
|
local_decls,
|
2018-11-16 22:56:18 +01:00
|
|
|
user_type_annotations,
|
2017-07-03 11:19:51 -07:00
|
|
|
arg_count,
|
2016-09-26 22:44:01 +02:00
|
|
|
spread_arg: None,
|
2018-05-16 18:58:54 +03:00
|
|
|
var_debug_info,
|
2017-07-03 11:19:51 -07:00
|
|
|
span,
|
2020-04-22 11:16:06 -03:00
|
|
|
required_consts: Vec::new(),
|
2020-08-06 10:00:08 +02:00
|
|
|
is_polymorphic: false,
|
2022-08-03 04:30:13 -07:00
|
|
|
injection_phase: None,
|
2022-02-07 22:00:15 -08:00
|
|
|
tainted_by_errors,
|
2023-09-10 16:35:37 +10:00
|
|
|
function_coverage_info: None,
|
2020-08-06 10:00:08 +02:00
|
|
|
};
|
2022-10-04 09:43:34 +00:00
|
|
|
body.is_polymorphic = body.has_non_region_param();
|
2020-08-06 10:00:08 +02:00
|
|
|
body
|
2015-08-18 17:59:21 -04:00
|
|
|
}
|
|
|
|
|
2019-11-12 16:12:15 -08:00
|
|
|
/// Returns a partially initialized MIR body containing only a list of basic blocks.
|
|
|
|
///
|
|
|
|
/// The returned MIR contains no `LocalDecl`s (even for the return place) or source scopes. It
|
|
|
|
/// is only useful for testing but cannot be `#[cfg(test)]` because it is used in a different
|
|
|
|
/// crate.
|
2021-07-19 17:20:24 +02:00
|
|
|
pub fn new_cfg_only(basic_blocks: IndexVec<BasicBlock, BasicBlockData<'tcx>>) -> Self {
|
2022-01-12 03:19:52 +00:00
|
|
|
let mut body = Body {
|
2022-03-05 20:37:04 -05:00
|
|
|
phase: MirPhase::Built,
|
2022-12-02 15:55:02 +00:00
|
|
|
pass_count: 0,
|
2022-04-15 19:27:53 +02:00
|
|
|
source: MirSource::item(CRATE_DEF_ID.to_def_id()),
|
2022-07-04 00:00:00 +00:00
|
|
|
basic_blocks: BasicBlocks::new(basic_blocks),
|
2019-11-12 16:12:15 -08:00
|
|
|
source_scopes: IndexVec::new(),
|
2021-01-17 13:27:05 +01:00
|
|
|
generator: None,
|
2019-11-12 16:12:15 -08:00
|
|
|
local_decls: IndexVec::new(),
|
|
|
|
user_type_annotations: IndexVec::new(),
|
|
|
|
arg_count: 0,
|
|
|
|
spread_arg: None,
|
|
|
|
span: DUMMY_SP,
|
2020-04-22 11:16:06 -03:00
|
|
|
required_consts: Vec::new(),
|
2019-11-12 16:12:15 -08:00
|
|
|
var_debug_info: Vec::new(),
|
2020-08-06 10:00:08 +02:00
|
|
|
is_polymorphic: false,
|
2022-08-03 04:30:13 -07:00
|
|
|
injection_phase: None,
|
2022-02-07 22:00:15 -08:00
|
|
|
tainted_by_errors: None,
|
2023-09-10 16:35:37 +10:00
|
|
|
function_coverage_info: None,
|
2022-01-12 03:19:52 +00:00
|
|
|
};
|
2022-10-04 09:43:34 +00:00
|
|
|
body.is_polymorphic = body.has_non_region_param();
|
2022-01-12 03:19:52 +00:00
|
|
|
body
|
2019-11-12 16:12:15 -08:00
|
|
|
}
|
|
|
|
|
2020-04-12 10:30:07 -07:00
|
|
|
#[inline]
|
|
|
|
pub fn basic_blocks_mut(&mut self) -> &mut IndexVec<BasicBlock, BasicBlockData<'tcx>> {
|
2022-07-04 00:00:00 +00:00
|
|
|
self.basic_blocks.as_mut()
|
2020-06-21 19:34:54 -04:00
|
|
|
}
|
|
|
|
|
2016-09-25 01:38:27 +02:00
|
|
|
#[inline]
|
|
|
|
pub fn local_kind(&self, local: Local) -> LocalKind {
|
2018-08-28 12:20:56 -04:00
|
|
|
let index = local.as_usize();
|
2016-09-25 01:38:27 +02:00
|
|
|
if index == 0 {
|
2018-06-19 21:22:52 -03:00
|
|
|
debug_assert!(
|
|
|
|
self.local_decls[local].mutability == Mutability::Mut,
|
|
|
|
"return place should be mutable"
|
|
|
|
);
|
2016-09-25 01:38:27 +02:00
|
|
|
|
|
|
|
LocalKind::ReturnPointer
|
|
|
|
} else if index < self.arg_count + 1 {
|
|
|
|
LocalKind::Arg
|
|
|
|
} else {
|
|
|
|
LocalKind::Temp
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-11-07 13:40:55 +01:00
|
|
|
/// Returns an iterator over all user-declared mutable locals.
|
|
|
|
#[inline]
|
2022-05-22 12:48:19 -07:00
|
|
|
pub fn mut_vars_iter<'a>(&'a self) -> impl Iterator<Item = Local> + Captures<'tcx> + 'a {
|
2018-11-07 13:40:55 +01:00
|
|
|
(self.arg_count + 1..self.local_decls.len()).filter_map(move |index| {
|
|
|
|
let local = Local::new(index);
|
|
|
|
let decl = &self.local_decls[local];
|
2023-02-15 17:39:43 +00:00
|
|
|
(decl.is_user_variable() && decl.mutability.is_mut()).then_some(local)
|
2018-11-07 13:40:55 +01:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2018-03-12 08:47:44 -07:00
|
|
|
/// Returns an iterator over all user-declared mutable arguments and locals.
|
2018-02-28 01:09:08 -08:00
|
|
|
#[inline]
|
2022-05-22 12:48:19 -07:00
|
|
|
pub fn mut_vars_and_args_iter<'a>(
|
|
|
|
&'a self,
|
|
|
|
) -> impl Iterator<Item = Local> + Captures<'tcx> + 'a {
|
2018-03-12 08:47:44 -07:00
|
|
|
(1..self.local_decls.len()).filter_map(move |index| {
|
2018-02-28 01:09:08 -08:00
|
|
|
let local = Local::new(index);
|
|
|
|
let decl = &self.local_decls[local];
|
2019-11-18 23:04:06 +00:00
|
|
|
if (decl.is_user_variable() || index < self.arg_count + 1)
|
2018-06-19 21:22:52 -03:00
|
|
|
&& decl.mutability == Mutability::Mut
|
2018-03-12 08:47:44 -07:00
|
|
|
{
|
2018-02-28 01:09:08 -08:00
|
|
|
Some(local)
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2016-09-25 01:38:27 +02:00
|
|
|
/// Returns an iterator over all function arguments.
|
|
|
|
#[inline]
|
2019-12-07 19:37:09 +01:00
|
|
|
pub fn args_iter(&self) -> impl Iterator<Item = Local> + ExactSizeIterator {
|
2021-08-31 15:53:50 +02:00
|
|
|
(1..self.arg_count + 1).map(Local::new)
|
2016-09-25 01:38:27 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Returns an iterator over all user-defined variables and compiler-generated temporaries (all
|
2017-12-06 09:25:29 +01:00
|
|
|
/// locals that are neither arguments nor the return place).
|
2016-09-25 01:38:27 +02:00
|
|
|
#[inline]
|
2020-11-15 00:00:00 +00:00
|
|
|
pub fn vars_and_temps_iter(
|
|
|
|
&self,
|
|
|
|
) -> impl DoubleEndedIterator<Item = Local> + ExactSizeIterator {
|
2021-08-31 15:53:50 +02:00
|
|
|
(self.arg_count + 1..self.local_decls.len()).map(Local::new)
|
2016-09-15 18:18:40 -07:00
|
|
|
}
|
|
|
|
|
2021-06-03 19:24:48 +02:00
|
|
|
#[inline]
|
|
|
|
pub fn drain_vars_and_temps<'a>(&'a mut self) -> impl Iterator<Item = LocalDecl<'tcx>> + 'a {
|
|
|
|
self.local_decls.drain(self.arg_count + 1..)
|
|
|
|
}
|
|
|
|
|
2017-12-06 09:25:29 +01:00
|
|
|
/// Returns the source info associated with `location`.
|
|
|
|
pub fn source_info(&self, location: Location) -> &SourceInfo {
|
|
|
|
let block = &self[location.block];
|
|
|
|
let stmts = &block.statements;
|
|
|
|
let idx = location.statement_index;
|
|
|
|
if idx < stmts.len() {
|
|
|
|
&stmts[idx].source_info
|
|
|
|
} else {
|
2018-10-03 15:07:18 +02:00
|
|
|
assert_eq!(idx, stmts.len());
|
2017-12-06 09:25:29 +01:00
|
|
|
&block.terminator().source_info
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-09-06 03:57:44 +01:00
|
|
|
/// Returns the return type; it always return first element from `local_decls` array.
|
2020-04-12 10:48:56 -07:00
|
|
|
#[inline]
|
2017-12-06 09:25:29 +01:00
|
|
|
pub fn return_ty(&self) -> Ty<'tcx> {
|
|
|
|
self.local_decls[RETURN_PLACE].ty
|
|
|
|
}
|
2018-08-12 13:07:14 -04:00
|
|
|
|
2022-08-03 01:02:46 -04:00
|
|
|
/// Returns the return type; it always return first element from `local_decls` array.
|
|
|
|
#[inline]
|
|
|
|
pub fn bound_return_ty(&self) -> ty::EarlyBinder<Ty<'tcx>> {
|
2023-05-29 13:46:10 +02:00
|
|
|
ty::EarlyBinder::bind(self.local_decls[RETURN_PLACE].ty)
|
2022-08-03 01:02:46 -04:00
|
|
|
}
|
|
|
|
|
2019-09-06 03:57:44 +01:00
|
|
|
/// Gets the location of the terminator for the given block.
|
2020-04-12 10:48:56 -07:00
|
|
|
#[inline]
|
2018-08-12 13:07:14 -04:00
|
|
|
pub fn terminator_loc(&self, bb: BasicBlock) -> Location {
|
2019-07-12 22:49:15 +02:00
|
|
|
Location { block: bb, statement_index: self[bb].statements.len() }
|
2018-08-12 13:07:14 -04:00
|
|
|
}
|
2020-04-12 10:30:07 -07:00
|
|
|
|
2021-03-15 15:09:06 -07:00
|
|
|
pub fn stmt_at(&self, location: Location) -> Either<&Statement<'tcx>, &Terminator<'tcx>> {
|
|
|
|
let Location { block, statement_index } = location;
|
|
|
|
let block_data = &self.basic_blocks[block];
|
|
|
|
block_data
|
|
|
|
.statements
|
|
|
|
.get(statement_index)
|
|
|
|
.map(Either::Left)
|
|
|
|
.unwrap_or_else(|| Either::Right(block_data.terminator()))
|
|
|
|
}
|
|
|
|
|
2021-01-17 13:27:05 +01:00
|
|
|
#[inline]
|
|
|
|
pub fn yield_ty(&self) -> Option<Ty<'tcx>> {
|
|
|
|
self.generator.as_ref().and_then(|generator| generator.yield_ty)
|
|
|
|
}
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
pub fn generator_layout(&self) -> Option<&GeneratorLayout<'tcx>> {
|
|
|
|
self.generator.as_ref().and_then(|generator| generator.generator_layout.as_ref())
|
|
|
|
}
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
pub fn generator_drop(&self) -> Option<&Body<'tcx>> {
|
|
|
|
self.generator.as_ref().and_then(|generator| generator.generator_drop.as_ref())
|
|
|
|
}
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
pub fn generator_kind(&self) -> Option<GeneratorKind> {
|
|
|
|
self.generator.as_ref().map(|generator| generator.generator_kind)
|
|
|
|
}
|
2022-08-03 04:30:13 -07:00
|
|
|
|
|
|
|
#[inline]
|
|
|
|
pub fn should_skip(&self) -> bool {
|
|
|
|
let Some(injection_phase) = self.injection_phase else {
|
|
|
|
return false;
|
|
|
|
};
|
|
|
|
injection_phase > self.phase
|
|
|
|
}
|
2022-12-03 23:54:55 -08:00
|
|
|
|
|
|
|
#[inline]
|
|
|
|
pub fn is_custom_mir(&self) -> bool {
|
|
|
|
self.injection_phase.is_some()
|
|
|
|
}
|
2015-08-18 17:59:21 -04:00
|
|
|
}
|
|
|
|
|
2020-06-11 15:49:57 +01:00
|
|
|
#[derive(Copy, Clone, PartialEq, Eq, Debug, TyEncodable, TyDecodable, HashStable)]
|
2017-09-19 16:20:02 +03:00
|
|
|
pub enum Safety {
|
|
|
|
Safe,
|
2021-04-29 20:54:22 -05:00
|
|
|
/// Unsafe because of compiler-generated unsafe code, like `await` desugaring
|
|
|
|
BuiltinUnsafe,
|
2017-09-19 16:20:02 +03:00
|
|
|
/// Unsafe because of an unsafe fn
|
|
|
|
FnUnsafe,
|
|
|
|
/// Unsafe because of an `unsafe` block
|
2019-02-22 15:48:14 +01:00
|
|
|
ExplicitUnsafe(hir::HirId),
|
2017-09-13 22:33:07 +03:00
|
|
|
}
|
|
|
|
|
2019-05-17 23:55:04 +02:00
|
|
|
impl<'tcx> Index<BasicBlock> for Body<'tcx> {
|
2016-01-07 05:49:46 -05:00
|
|
|
type Output = BasicBlockData<'tcx>;
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
fn index(&self, index: BasicBlock) -> &BasicBlockData<'tcx> {
|
2022-07-05 00:00:00 +00:00
|
|
|
&self.basic_blocks[index]
|
2016-01-07 05:49:46 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-04-12 10:30:07 -07:00
|
|
|
impl<'tcx> IndexMut<BasicBlock> for Body<'tcx> {
|
|
|
|
#[inline]
|
|
|
|
fn index_mut(&mut self, index: BasicBlock) -> &mut BasicBlockData<'tcx> {
|
2022-07-04 00:00:00 +00:00
|
|
|
&mut self.basic_blocks.as_mut()[index]
|
2020-04-12 10:30:07 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-06-17 10:53:29 +01:00
|
|
|
#[derive(Copy, Clone, Debug, HashStable, TypeFoldable, TypeVisitable)]
|
2017-12-06 09:25:29 +01:00
|
|
|
pub enum ClearCrossCrate<T> {
|
2017-09-13 22:33:07 +03:00
|
|
|
Clear,
|
2018-06-19 21:22:52 -03:00
|
|
|
Set(T),
|
2017-09-13 22:33:07 +03:00
|
|
|
}
|
|
|
|
|
2018-07-03 06:50:54 -04:00
|
|
|
impl<T> ClearCrossCrate<T> {
|
2020-03-07 00:56:32 +01:00
|
|
|
pub fn as_ref(&self) -> ClearCrossCrate<&T> {
|
2019-11-26 19:55:03 +02:00
|
|
|
match self {
|
|
|
|
ClearCrossCrate::Clear => ClearCrossCrate::Clear,
|
|
|
|
ClearCrossCrate::Set(v) => ClearCrossCrate::Set(v),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-03-09 16:55:20 +00:00
|
|
|
pub fn as_mut(&mut self) -> ClearCrossCrate<&mut T> {
|
|
|
|
match self {
|
|
|
|
ClearCrossCrate::Clear => ClearCrossCrate::Clear,
|
|
|
|
ClearCrossCrate::Set(v) => ClearCrossCrate::Set(v),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-07-03 06:50:54 -04:00
|
|
|
pub fn assert_crate_local(self) -> T {
|
|
|
|
match self {
|
|
|
|
ClearCrossCrate::Clear => bug!("unwrapping cross-crate data"),
|
|
|
|
ClearCrossCrate::Set(v) => v,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-06-01 18:58:18 +01:00
|
|
|
const TAG_CLEAR_CROSS_CRATE_CLEAR: u8 = 0;
|
|
|
|
const TAG_CLEAR_CROSS_CRATE_SET: u8 = 1;
|
|
|
|
|
2021-01-31 10:32:34 +01:00
|
|
|
impl<E: TyEncoder, T: Encodable<E>> Encodable<E> for ClearCrossCrate<T> {
|
2020-06-01 18:58:18 +01:00
|
|
|
#[inline]
|
Use delayed error handling for `Encodable` and `Encoder` infallible.
There are two impls of the `Encoder` trait: `opaque::Encoder` and
`opaque::FileEncoder`. The former encodes into memory and is infallible, the
latter writes to file and is fallible.
Currently, standard `Result`/`?`/`unwrap` error handling is used, but this is a
bit verbose and has non-trivial cost, which is annoying given how rare failures
are (especially in the infallible `opaque::Encoder` case).
This commit changes how `Encoder` fallibility is handled. All the `emit_*`
methods are now infallible. `opaque::Encoder` requires no great changes for
this. `opaque::FileEncoder` now implements a delayed error handling strategy.
If a failure occurs, it records this via the `res` field, and all subsequent
encoding operations are skipped if `res` indicates an error has occurred. Once
encoding is complete, the new `finish` method is called, which returns a
`Result`. In other words, there is now a single `Result`-producing method
instead of many of them.
This has very little effect on how any file errors are reported if
`opaque::FileEncoder` has any failures.
Much of this commit is boring mechanical changes, removing `Result` return
values and `?` or `unwrap` from expressions. The more interesting parts are as
follows.
- serialize.rs: The `Encoder` trait gains an `Ok` associated type. The
`into_inner` method is changed into `finish`, which returns
`Result<Vec<u8>, !>`.
- opaque.rs: The `FileEncoder` adopts the delayed error handling
strategy. Its `Ok` type is a `usize`, returning the number of bytes
written, replacing previous uses of `FileEncoder::position`.
- Various methods that take an encoder now consume it, rather than being
passed a mutable reference, e.g. `serialize_query_result_cache`.
2022-06-07 13:30:45 +10:00
|
|
|
fn encode(&self, e: &mut E) {
|
2020-06-11 15:49:57 +01:00
|
|
|
if E::CLEAR_CROSS_CRATE {
|
Use delayed error handling for `Encodable` and `Encoder` infallible.
There are two impls of the `Encoder` trait: `opaque::Encoder` and
`opaque::FileEncoder`. The former encodes into memory and is infallible, the
latter writes to file and is fallible.
Currently, standard `Result`/`?`/`unwrap` error handling is used, but this is a
bit verbose and has non-trivial cost, which is annoying given how rare failures
are (especially in the infallible `opaque::Encoder` case).
This commit changes how `Encoder` fallibility is handled. All the `emit_*`
methods are now infallible. `opaque::Encoder` requires no great changes for
this. `opaque::FileEncoder` now implements a delayed error handling strategy.
If a failure occurs, it records this via the `res` field, and all subsequent
encoding operations are skipped if `res` indicates an error has occurred. Once
encoding is complete, the new `finish` method is called, which returns a
`Result`. In other words, there is now a single `Result`-producing method
instead of many of them.
This has very little effect on how any file errors are reported if
`opaque::FileEncoder` has any failures.
Much of this commit is boring mechanical changes, removing `Result` return
values and `?` or `unwrap` from expressions. The more interesting parts are as
follows.
- serialize.rs: The `Encoder` trait gains an `Ok` associated type. The
`into_inner` method is changed into `finish`, which returns
`Result<Vec<u8>, !>`.
- opaque.rs: The `FileEncoder` adopts the delayed error handling
strategy. Its `Ok` type is a `usize`, returning the number of bytes
written, replacing previous uses of `FileEncoder::position`.
- Various methods that take an encoder now consume it, rather than being
passed a mutable reference, e.g. `serialize_query_result_cache`.
2022-06-07 13:30:45 +10:00
|
|
|
return;
|
2020-06-11 15:49:57 +01:00
|
|
|
}
|
|
|
|
|
2020-06-01 18:58:18 +01:00
|
|
|
match *self {
|
|
|
|
ClearCrossCrate::Clear => TAG_CLEAR_CROSS_CRATE_CLEAR.encode(e),
|
|
|
|
ClearCrossCrate::Set(ref val) => {
|
Use delayed error handling for `Encodable` and `Encoder` infallible.
There are two impls of the `Encoder` trait: `opaque::Encoder` and
`opaque::FileEncoder`. The former encodes into memory and is infallible, the
latter writes to file and is fallible.
Currently, standard `Result`/`?`/`unwrap` error handling is used, but this is a
bit verbose and has non-trivial cost, which is annoying given how rare failures
are (especially in the infallible `opaque::Encoder` case).
This commit changes how `Encoder` fallibility is handled. All the `emit_*`
methods are now infallible. `opaque::Encoder` requires no great changes for
this. `opaque::FileEncoder` now implements a delayed error handling strategy.
If a failure occurs, it records this via the `res` field, and all subsequent
encoding operations are skipped if `res` indicates an error has occurred. Once
encoding is complete, the new `finish` method is called, which returns a
`Result`. In other words, there is now a single `Result`-producing method
instead of many of them.
This has very little effect on how any file errors are reported if
`opaque::FileEncoder` has any failures.
Much of this commit is boring mechanical changes, removing `Result` return
values and `?` or `unwrap` from expressions. The more interesting parts are as
follows.
- serialize.rs: The `Encoder` trait gains an `Ok` associated type. The
`into_inner` method is changed into `finish`, which returns
`Result<Vec<u8>, !>`.
- opaque.rs: The `FileEncoder` adopts the delayed error handling
strategy. Its `Ok` type is a `usize`, returning the number of bytes
written, replacing previous uses of `FileEncoder::position`.
- Various methods that take an encoder now consume it, rather than being
passed a mutable reference, e.g. `serialize_query_result_cache`.
2022-06-07 13:30:45 +10:00
|
|
|
TAG_CLEAR_CROSS_CRATE_SET.encode(e);
|
|
|
|
val.encode(e);
|
2020-06-01 18:58:18 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2021-01-31 10:32:34 +01:00
|
|
|
impl<D: TyDecoder, T: Decodable<D>> Decodable<D> for ClearCrossCrate<T> {
|
2020-06-01 18:58:18 +01:00
|
|
|
#[inline]
|
Make `Decodable` and `Decoder` infallible.
`Decoder` has two impls:
- opaque: this impl is already partly infallible, i.e. in some places it
currently panics on failure (e.g. if the input is too short, or on a
bad `Result` discriminant), and in some places it returns an error
(e.g. on a bad `Option` discriminant). The number of places where
either happens is surprisingly small, just because the binary
representation has very little redundancy and a lot of input reading
can occur even on malformed data.
- json: this impl is fully fallible, but it's only used (a) for the
`.rlink` file production, and there's a `FIXME` comment suggesting it
should change to a binary format, and (b) in a few tests in
non-fundamental ways. Indeed #85993 is open to remove it entirely.
And the top-level places in the compiler that call into decoding just
abort on error anyway. So the fallibility is providing little value, and
getting rid of it leads to some non-trivial performance improvements.
Much of this commit is pretty boring and mechanical. Some notes about
a few interesting parts:
- The commit removes `Decoder::{Error,error}`.
- `InternIteratorElement::intern_with`: the impl for `T` now has the same
optimization for small counts that the impl for `Result<T, E>` has,
because it's now much hotter.
- Decodable impls for SmallVec, LinkedList, VecDeque now all use
`collect`, which is nice; the one for `Vec` uses unsafe code, because
that gave better perf on some benchmarks.
2022-01-18 13:22:50 +11:00
|
|
|
fn decode(d: &mut D) -> ClearCrossCrate<T> {
|
2020-06-11 15:49:57 +01:00
|
|
|
if D::CLEAR_CROSS_CRATE {
|
Make `Decodable` and `Decoder` infallible.
`Decoder` has two impls:
- opaque: this impl is already partly infallible, i.e. in some places it
currently panics on failure (e.g. if the input is too short, or on a
bad `Result` discriminant), and in some places it returns an error
(e.g. on a bad `Option` discriminant). The number of places where
either happens is surprisingly small, just because the binary
representation has very little redundancy and a lot of input reading
can occur even on malformed data.
- json: this impl is fully fallible, but it's only used (a) for the
`.rlink` file production, and there's a `FIXME` comment suggesting it
should change to a binary format, and (b) in a few tests in
non-fundamental ways. Indeed #85993 is open to remove it entirely.
And the top-level places in the compiler that call into decoding just
abort on error anyway. So the fallibility is providing little value, and
getting rid of it leads to some non-trivial performance improvements.
Much of this commit is pretty boring and mechanical. Some notes about
a few interesting parts:
- The commit removes `Decoder::{Error,error}`.
- `InternIteratorElement::intern_with`: the impl for `T` now has the same
optimization for small counts that the impl for `Result<T, E>` has,
because it's now much hotter.
- Decodable impls for SmallVec, LinkedList, VecDeque now all use
`collect`, which is nice; the one for `Vec` uses unsafe code, because
that gave better perf on some benchmarks.
2022-01-18 13:22:50 +11:00
|
|
|
return ClearCrossCrate::Clear;
|
2020-06-11 15:49:57 +01:00
|
|
|
}
|
|
|
|
|
Make `Decodable` and `Decoder` infallible.
`Decoder` has two impls:
- opaque: this impl is already partly infallible, i.e. in some places it
currently panics on failure (e.g. if the input is too short, or on a
bad `Result` discriminant), and in some places it returns an error
(e.g. on a bad `Option` discriminant). The number of places where
either happens is surprisingly small, just because the binary
representation has very little redundancy and a lot of input reading
can occur even on malformed data.
- json: this impl is fully fallible, but it's only used (a) for the
`.rlink` file production, and there's a `FIXME` comment suggesting it
should change to a binary format, and (b) in a few tests in
non-fundamental ways. Indeed #85993 is open to remove it entirely.
And the top-level places in the compiler that call into decoding just
abort on error anyway. So the fallibility is providing little value, and
getting rid of it leads to some non-trivial performance improvements.
Much of this commit is pretty boring and mechanical. Some notes about
a few interesting parts:
- The commit removes `Decoder::{Error,error}`.
- `InternIteratorElement::intern_with`: the impl for `T` now has the same
optimization for small counts that the impl for `Result<T, E>` has,
because it's now much hotter.
- Decodable impls for SmallVec, LinkedList, VecDeque now all use
`collect`, which is nice; the one for `Vec` uses unsafe code, because
that gave better perf on some benchmarks.
2022-01-18 13:22:50 +11:00
|
|
|
let discr = u8::decode(d);
|
2020-06-01 18:58:18 +01:00
|
|
|
|
|
|
|
match discr {
|
Make `Decodable` and `Decoder` infallible.
`Decoder` has two impls:
- opaque: this impl is already partly infallible, i.e. in some places it
currently panics on failure (e.g. if the input is too short, or on a
bad `Result` discriminant), and in some places it returns an error
(e.g. on a bad `Option` discriminant). The number of places where
either happens is surprisingly small, just because the binary
representation has very little redundancy and a lot of input reading
can occur even on malformed data.
- json: this impl is fully fallible, but it's only used (a) for the
`.rlink` file production, and there's a `FIXME` comment suggesting it
should change to a binary format, and (b) in a few tests in
non-fundamental ways. Indeed #85993 is open to remove it entirely.
And the top-level places in the compiler that call into decoding just
abort on error anyway. So the fallibility is providing little value, and
getting rid of it leads to some non-trivial performance improvements.
Much of this commit is pretty boring and mechanical. Some notes about
a few interesting parts:
- The commit removes `Decoder::{Error,error}`.
- `InternIteratorElement::intern_with`: the impl for `T` now has the same
optimization for small counts that the impl for `Result<T, E>` has,
because it's now much hotter.
- Decodable impls for SmallVec, LinkedList, VecDeque now all use
`collect`, which is nice; the one for `Vec` uses unsafe code, because
that gave better perf on some benchmarks.
2022-01-18 13:22:50 +11:00
|
|
|
TAG_CLEAR_CROSS_CRATE_CLEAR => ClearCrossCrate::Clear,
|
2020-06-01 18:58:18 +01:00
|
|
|
TAG_CLEAR_CROSS_CRATE_SET => {
|
Make `Decodable` and `Decoder` infallible.
`Decoder` has two impls:
- opaque: this impl is already partly infallible, i.e. in some places it
currently panics on failure (e.g. if the input is too short, or on a
bad `Result` discriminant), and in some places it returns an error
(e.g. on a bad `Option` discriminant). The number of places where
either happens is surprisingly small, just because the binary
representation has very little redundancy and a lot of input reading
can occur even on malformed data.
- json: this impl is fully fallible, but it's only used (a) for the
`.rlink` file production, and there's a `FIXME` comment suggesting it
should change to a binary format, and (b) in a few tests in
non-fundamental ways. Indeed #85993 is open to remove it entirely.
And the top-level places in the compiler that call into decoding just
abort on error anyway. So the fallibility is providing little value, and
getting rid of it leads to some non-trivial performance improvements.
Much of this commit is pretty boring and mechanical. Some notes about
a few interesting parts:
- The commit removes `Decoder::{Error,error}`.
- `InternIteratorElement::intern_with`: the impl for `T` now has the same
optimization for small counts that the impl for `Result<T, E>` has,
because it's now much hotter.
- Decodable impls for SmallVec, LinkedList, VecDeque now all use
`collect`, which is nice; the one for `Vec` uses unsafe code, because
that gave better perf on some benchmarks.
2022-01-18 13:22:50 +11:00
|
|
|
let val = T::decode(d);
|
|
|
|
ClearCrossCrate::Set(val)
|
2020-06-01 18:58:18 +01:00
|
|
|
}
|
2023-07-25 22:00:13 +02:00
|
|
|
tag => panic!("Invalid tag for ClearCrossCrate: {tag:?}"),
|
2020-06-01 18:58:18 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2017-09-13 22:33:07 +03:00
|
|
|
|
2016-06-07 19:21:56 +03:00
|
|
|
/// Grouped information about the source code origin of a MIR entity.
|
|
|
|
/// Intended to be inspected by diagnostics and debuginfo.
|
|
|
|
/// Most passes can work with it as a whole, within a single function.
|
2019-11-26 22:19:54 -05:00
|
|
|
// The unofficial Cranelift backend, at least as of #65828, needs `SourceInfo` to implement `Eq` and
|
2019-10-25 21:11:29 +02:00
|
|
|
// `Hash`. Please ping @bjorn3 if removing them.
|
2020-06-11 15:49:57 +01:00
|
|
|
#[derive(Copy, Clone, Debug, Eq, PartialEq, TyEncodable, TyDecodable, Hash, HashStable)]
|
2016-06-07 19:21:56 +03:00
|
|
|
pub struct SourceInfo {
|
2019-09-06 03:57:44 +01:00
|
|
|
/// The source span for the AST pertaining to this MIR entity.
|
2016-06-07 19:21:56 +03:00
|
|
|
pub span: Span,
|
|
|
|
|
2018-05-28 14:16:09 +03:00
|
|
|
/// The source scope, keeping track of which bindings can be
|
|
|
|
/// seen by debuginfo, active lint levels, `unsafe {...}`, etc.
|
2018-06-19 21:22:52 -03:00
|
|
|
pub scope: SourceScope,
|
2016-06-07 19:21:56 +03:00
|
|
|
}
|
|
|
|
|
2020-05-06 10:30:11 +10:00
|
|
|
impl SourceInfo {
|
|
|
|
#[inline]
|
|
|
|
pub fn outermost(span: Span) -> Self {
|
|
|
|
SourceInfo { span, scope: OUTERMOST_SOURCE_SCOPE }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-08-18 17:59:21 -04:00
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
|
|
// Variables and temps
|
|
|
|
|
2019-09-26 05:38:33 +00:00
|
|
|
rustc_index::newtype_index! {
|
2022-12-18 20:53:08 +01:00
|
|
|
#[derive(HashStable)]
|
2022-12-18 21:37:38 +01:00
|
|
|
#[debug_format = "_{}"]
|
2018-07-25 13:41:32 +03:00
|
|
|
pub struct Local {
|
2022-12-18 21:47:28 +01:00
|
|
|
const RETURN_PLACE = 0;
|
2018-07-25 13:41:32 +03:00
|
|
|
}
|
|
|
|
}
|
2016-09-25 01:38:27 +02:00
|
|
|
|
2019-07-12 22:48:02 +02:00
|
|
|
impl Atom for Local {
|
|
|
|
fn index(self) -> usize {
|
|
|
|
Idx::index(self)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-05-17 23:55:04 +02:00
|
|
|
/// Classifies locals into categories. See `Body::local_kind`.
|
2020-09-29 17:27:59 -07:00
|
|
|
#[derive(Clone, Copy, PartialEq, Eq, Debug, HashStable)]
|
2016-09-25 01:38:27 +02:00
|
|
|
pub enum LocalKind {
|
2023-03-10 10:29:19 +00:00
|
|
|
/// User-declared variable binding or compiler-introduced temporary.
|
2016-09-25 01:38:27 +02:00
|
|
|
Temp,
|
2019-09-06 03:57:44 +01:00
|
|
|
/// Function argument.
|
2016-09-25 01:38:27 +02:00
|
|
|
Arg,
|
2019-09-06 03:57:44 +01:00
|
|
|
/// Location of function's return value.
|
2016-09-25 01:38:27 +02:00
|
|
|
ReturnPointer,
|
|
|
|
}
|
|
|
|
|
2020-06-11 15:49:57 +01:00
|
|
|
#[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable)]
|
2018-06-27 22:06:54 +01:00
|
|
|
pub struct VarBindingForm<'tcx> {
|
2018-06-07 15:25:08 +02:00
|
|
|
/// Is variable bound via `x`, `mut x`, `ref x`, or `ref mut x`?
|
|
|
|
pub binding_mode: ty::BindingMode,
|
|
|
|
/// If an explicit type was provided for this variable binding,
|
|
|
|
/// this holds the source Span of that type.
|
|
|
|
///
|
2019-02-08 14:53:55 +01:00
|
|
|
/// NOTE: if you want to change this to a `HirId`, be wary that
|
2018-06-07 15:25:08 +02:00
|
|
|
/// doing so breaks incremental compilation (as of this writing),
|
|
|
|
/// while a `Span` does not cause our tests to fail.
|
|
|
|
pub opt_ty_info: Option<Span>,
|
2018-06-27 22:06:54 +01:00
|
|
|
/// Place of the RHS of the =, or the subject of the `match` where this
|
|
|
|
/// variable is initialized. None in the case of `let PATTERN;`.
|
|
|
|
/// Some((None, ..)) in the case of and `let [mut] x = ...` because
|
|
|
|
/// (a) the right-hand side isn't evaluated as a place expression.
|
|
|
|
/// (b) it gives a way to separate this case from the remaining cases
|
|
|
|
/// for diagnostics.
|
|
|
|
pub opt_match_place: Option<(Option<Place<'tcx>>, Span)>,
|
2019-09-06 03:57:44 +01:00
|
|
|
/// The span of the pattern in which this variable was bound.
|
2018-08-07 01:02:39 -07:00
|
|
|
pub pat_span: Span,
|
2018-06-07 15:25:08 +02:00
|
|
|
}
|
|
|
|
|
2020-06-11 15:49:57 +01:00
|
|
|
#[derive(Clone, Debug, TyEncodable, TyDecodable)]
|
2018-06-27 22:06:54 +01:00
|
|
|
pub enum BindingForm<'tcx> {
|
2018-06-07 15:25:08 +02:00
|
|
|
/// This is a binding for a non-`self` binding, or a `self` that has an explicit type.
|
2018-06-27 22:06:54 +01:00
|
|
|
Var(VarBindingForm<'tcx>),
|
2018-06-07 15:25:08 +02:00
|
|
|
/// Binding for a `self`/`&self`/`&mut self` binding where the type is implicit.
|
2018-10-01 17:46:04 +02:00
|
|
|
ImplicitSelf(ImplicitSelfKind),
|
2018-07-15 15:00:58 +01:00
|
|
|
/// Reference used in a guard expression to ensure immutability.
|
|
|
|
RefForGuard,
|
2018-06-07 15:25:08 +02:00
|
|
|
}
|
|
|
|
|
2023-09-14 12:05:05 +10:00
|
|
|
TrivialTypeTraversalImpls! { BindingForm<'tcx> }
|
2018-06-07 15:25:08 +02:00
|
|
|
|
2018-06-27 22:06:54 +01:00
|
|
|
mod binding_form_impl {
|
2019-09-26 18:54:39 -04:00
|
|
|
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
|
2020-11-14 16:48:54 +01:00
|
|
|
use rustc_query_system::ich::StableHashingContext;
|
2018-06-07 15:25:08 +02:00
|
|
|
|
2018-06-27 22:06:54 +01:00
|
|
|
impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for super::BindingForm<'tcx> {
|
2019-09-26 18:54:39 -04:00
|
|
|
fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) {
|
2018-06-27 22:06:54 +01:00
|
|
|
use super::BindingForm::*;
|
2020-10-13 10:17:05 +02:00
|
|
|
std::mem::discriminant(self).hash_stable(hcx, hasher);
|
2018-06-27 22:06:54 +01:00
|
|
|
|
|
|
|
match self {
|
|
|
|
Var(binding) => binding.hash_stable(hcx, hasher),
|
2018-10-01 17:46:04 +02:00
|
|
|
ImplicitSelf(kind) => kind.hash_stable(hcx, hasher),
|
2018-07-15 15:00:58 +01:00
|
|
|
RefForGuard => (),
|
2018-06-27 22:06:54 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2018-06-07 15:25:08 +02:00
|
|
|
|
2018-10-05 12:26:29 +02:00
|
|
|
/// `BlockTailInfo` is attached to the `LocalDecl` for temporaries
|
|
|
|
/// created during evaluation of expressions in a block tail
|
|
|
|
/// expression; that is, a block like `{ STMT_1; STMT_2; EXPR }`.
|
|
|
|
///
|
|
|
|
/// It is used to improve diagnostics when such temporaries are
|
2018-11-27 02:59:49 +00:00
|
|
|
/// involved in borrow_check errors, e.g., explanations of where the
|
2018-10-05 12:26:29 +02:00
|
|
|
/// temporaries come from, when their destructors are run, and/or how
|
|
|
|
/// one might revise the code to satisfy the borrow checker's rules.
|
2020-06-11 15:49:57 +01:00
|
|
|
#[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable)]
|
2018-09-22 00:51:48 +02:00
|
|
|
pub struct BlockTailInfo {
|
|
|
|
/// If `true`, then the value resulting from evaluating this tail
|
|
|
|
/// expression is ignored by the block's expression context.
|
|
|
|
///
|
|
|
|
/// Examples include `{ ...; tail };` and `let _ = { ...; tail };`
|
2018-11-27 02:59:49 +00:00
|
|
|
/// but not e.g., `let _x = { ...; tail };`
|
2018-09-22 00:51:48 +02:00
|
|
|
pub tail_result_is_ignored: bool,
|
2020-04-16 12:43:40 -07:00
|
|
|
|
|
|
|
/// `Span` of the tail expression.
|
|
|
|
pub span: Span,
|
2018-09-22 00:51:48 +02:00
|
|
|
}
|
|
|
|
|
2016-09-25 01:38:27 +02:00
|
|
|
/// A MIR local.
|
|
|
|
///
|
|
|
|
/// This can be a binding declared by the user, a temporary inserted by the compiler, a function
|
2017-12-06 09:25:29 +01:00
|
|
|
/// argument, or the return place.
|
2022-06-17 10:53:29 +01:00
|
|
|
#[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable)]
|
2016-09-25 01:38:27 +02:00
|
|
|
pub struct LocalDecl<'tcx> {
|
2020-10-08 14:21:12 +00:00
|
|
|
/// Whether this is a mutable binding (i.e., `let x` or `let mut x`).
|
2016-09-25 01:38:27 +02:00
|
|
|
///
|
2017-12-06 09:25:29 +01:00
|
|
|
/// Temporaries and the return place are always mutable.
|
2015-08-18 17:59:21 -04:00
|
|
|
pub mutability: Mutability,
|
2016-03-23 04:21:02 -04:00
|
|
|
|
2019-11-18 23:04:06 +00:00
|
|
|
// FIXME(matthewjasper) Don't store in this in `Body`
|
2023-03-09 16:55:20 +00:00
|
|
|
pub local_info: ClearCrossCrate<Box<LocalInfo<'tcx>>>,
|
2017-04-11 23:52:51 +03:00
|
|
|
|
2019-09-06 03:57:44 +01:00
|
|
|
/// The type of this local.
|
2015-10-05 12:31:48 -04:00
|
|
|
pub ty: Ty<'tcx>,
|
2016-03-23 04:21:02 -04:00
|
|
|
|
2018-09-10 10:54:31 -04:00
|
|
|
/// If the user manually ascribed a type to this variable,
|
2018-11-27 02:59:49 +00:00
|
|
|
/// e.g., via `let x: T`, then we carry that type here. The MIR
|
2018-09-10 10:54:31 -04:00
|
|
|
/// borrow checker needs this information since it can affect
|
|
|
|
/// region inference.
|
2019-11-18 23:04:06 +00:00
|
|
|
// FIXME(matthewjasper) Don't store in this in `Body`
|
2020-05-06 12:41:15 +10:00
|
|
|
pub user_ty: Option<Box<UserTypeProjections>>,
|
2018-09-10 10:54:31 -04:00
|
|
|
|
2018-11-27 02:59:49 +00:00
|
|
|
/// The *syntactic* (i.e., not visibility) source scope the local is defined
|
2017-09-13 22:33:07 +03:00
|
|
|
/// in. If the local was defined in a let-statement, this
|
|
|
|
/// is *within* the let-statement, rather than outside
|
2017-09-20 16:34:31 +03:00
|
|
|
/// of it.
|
2017-12-21 00:35:19 +02:00
|
|
|
///
|
2018-05-28 14:16:09 +03:00
|
|
|
/// This is needed because the visibility source scope of locals within
|
|
|
|
/// a let-statement is weird.
|
2017-12-21 00:35:19 +02:00
|
|
|
///
|
|
|
|
/// The reason is that we want the local to be *within* the let-statement
|
|
|
|
/// for lint purposes, but we want the local to be *after* the let-statement
|
|
|
|
/// for names-in-scope purposes.
|
|
|
|
///
|
|
|
|
/// That's it, if we have a let-statement like the one in this
|
|
|
|
/// function:
|
2017-12-31 17:17:01 +01:00
|
|
|
///
|
2017-12-21 00:35:19 +02:00
|
|
|
/// ```
|
|
|
|
/// fn foo(x: &str) {
|
|
|
|
/// #[allow(unused_mut)]
|
|
|
|
/// let mut x: u32 = { // <- one unused mut
|
|
|
|
/// let mut y: u32 = x.parse().unwrap();
|
|
|
|
/// y + 2
|
|
|
|
/// };
|
|
|
|
/// drop(x);
|
|
|
|
/// }
|
|
|
|
/// ```
|
|
|
|
///
|
|
|
|
/// Then, from a lint point of view, the declaration of `x: u32`
|
|
|
|
/// (and `y: u32`) are within the `#[allow(unused_mut)]` scope - the
|
|
|
|
/// lint scopes are the same as the AST/HIR nesting.
|
|
|
|
///
|
|
|
|
/// However, from a name lookup point of view, the scopes look more like
|
|
|
|
/// as if the let-statements were `match` expressions:
|
|
|
|
///
|
|
|
|
/// ```
|
|
|
|
/// fn foo(x: &str) {
|
|
|
|
/// match {
|
2022-04-15 15:04:34 -07:00
|
|
|
/// match x.parse::<u32>().unwrap() {
|
2017-12-21 00:35:19 +02:00
|
|
|
/// y => y + 2
|
|
|
|
/// }
|
|
|
|
/// } {
|
|
|
|
/// x => drop(x)
|
|
|
|
/// };
|
|
|
|
/// }
|
|
|
|
/// ```
|
|
|
|
///
|
|
|
|
/// We care about the name-lookup scopes for debuginfo - if the
|
|
|
|
/// debuginfo instruction pointer is at the call to `x.parse()`, we
|
|
|
|
/// want `x` to refer to `x: &str`, but if it is at the call to
|
|
|
|
/// `drop(x)`, we want it to refer to `x: u32`.
|
|
|
|
///
|
|
|
|
/// To allow both uses to work, we need to have more than a single scope
|
2018-05-16 18:58:54 +03:00
|
|
|
/// for a local. We have the `source_info.scope` represent the "syntactic"
|
|
|
|
/// lint scope (with a variable being under its let block) while the
|
|
|
|
/// `var_debug_info.source_info.scope` represents the "local variable"
|
2017-12-21 00:35:19 +02:00
|
|
|
/// scope (where the "rest" of a block is under all prior let-statements).
|
|
|
|
///
|
|
|
|
/// The end result looks like this:
|
|
|
|
///
|
2017-12-31 17:17:01 +01:00
|
|
|
/// ```text
|
2017-12-21 00:35:19 +02:00
|
|
|
/// ROOT SCOPE
|
|
|
|
/// │{ argument x: &str }
|
|
|
|
/// │
|
2019-09-06 03:57:44 +01:00
|
|
|
/// │ │{ #[allow(unused_mut)] } // This is actually split into 2 scopes
|
|
|
|
/// │ │ // in practice because I'm lazy.
|
2017-12-21 00:35:19 +02:00
|
|
|
/// │ │
|
2018-05-29 21:31:33 +03:00
|
|
|
/// │ │← x.source_info.scope
|
2017-12-21 00:35:19 +02:00
|
|
|
/// │ │← `x.parse().unwrap()`
|
|
|
|
/// │ │
|
2018-05-29 21:31:33 +03:00
|
|
|
/// │ │ │← y.source_info.scope
|
2017-12-21 00:35:19 +02:00
|
|
|
/// │ │
|
|
|
|
/// │ │ │{ let y: u32 }
|
|
|
|
/// │ │ │
|
2018-05-16 18:58:54 +03:00
|
|
|
/// │ │ │← y.var_debug_info.source_info.scope
|
2017-12-21 00:35:19 +02:00
|
|
|
/// │ │ │← `y + 2`
|
|
|
|
/// │
|
|
|
|
/// │ │{ let x: u32 }
|
2018-05-16 18:58:54 +03:00
|
|
|
/// │ │← x.var_debug_info.source_info.scope
|
2019-09-06 03:57:44 +01:00
|
|
|
/// │ │← `drop(x)` // This accesses `x: u32`.
|
2017-12-31 17:17:01 +01:00
|
|
|
/// ```
|
2018-05-29 21:31:33 +03:00
|
|
|
pub source_info: SourceInfo,
|
2015-08-18 17:59:21 -04:00
|
|
|
}
|
|
|
|
|
2020-08-12 19:37:08 +02:00
|
|
|
/// Extra information about a some locals that's used for diagnostics and for
|
|
|
|
/// classifying variables into local variables, statics, etc, which is needed e.g.
|
|
|
|
/// for unsafety checking.
|
|
|
|
///
|
|
|
|
/// Not used for non-StaticRef temporaries, the return place, or anonymous
|
|
|
|
/// function parameters.
|
2022-06-17 10:53:29 +01:00
|
|
|
#[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable)]
|
2019-11-18 23:04:06 +00:00
|
|
|
pub enum LocalInfo<'tcx> {
|
|
|
|
/// A user-defined local variable or function parameter
|
2019-11-21 21:20:47 +00:00
|
|
|
///
|
|
|
|
/// The `BindingForm` is solely used for local diagnostics when generating
|
|
|
|
/// warnings/errors when compiling the current crate, and therefore it need
|
|
|
|
/// not be visible across crates.
|
2023-03-09 16:55:20 +00:00
|
|
|
User(BindingForm<'tcx>),
|
2019-11-18 23:04:06 +00:00
|
|
|
/// A temporary created that references the static with the given `DefId`.
|
|
|
|
StaticRef { def_id: DefId, is_thread_local: bool },
|
2020-08-10 07:16:30 -04:00
|
|
|
/// A temporary created that references the const with the given `DefId`
|
|
|
|
ConstRef { def_id: DefId },
|
2021-09-06 16:59:24 -05:00
|
|
|
/// A temporary created during the creation of an aggregate
|
|
|
|
/// (e.g. a temporary for `foo` in `MyStruct { my_field: foo }`)
|
|
|
|
AggregateTemp,
|
2023-03-10 09:08:10 +00:00
|
|
|
/// A temporary created for evaluation of some subexpression of some block's tail expression
|
|
|
|
/// (with no intervening statement context).
|
|
|
|
// FIXME(matthewjasper) Don't store in this in `Body`
|
|
|
|
BlockTailTemp(BlockTailInfo),
|
2022-04-28 01:03:07 +03:00
|
|
|
/// A temporary created during the pass `Derefer` to avoid it's retagging
|
2022-05-01 15:38:22 +03:00
|
|
|
DerefTemp,
|
2023-01-21 10:03:12 +00:00
|
|
|
/// A temporary created for borrow checking.
|
|
|
|
FakeBorrow,
|
2023-03-09 16:55:20 +00:00
|
|
|
/// A local without anything interesting about it.
|
|
|
|
Boring,
|
2019-11-18 23:04:06 +00:00
|
|
|
}
|
|
|
|
|
2016-09-25 01:38:27 +02:00
|
|
|
impl<'tcx> LocalDecl<'tcx> {
|
2023-03-09 16:55:20 +00:00
|
|
|
pub fn local_info(&self) -> &LocalInfo<'tcx> {
|
2023-04-09 23:07:18 +02:00
|
|
|
&self.local_info.as_ref().assert_crate_local()
|
2023-03-09 16:55:20 +00:00
|
|
|
}
|
|
|
|
|
2019-02-08 14:53:55 +01:00
|
|
|
/// Returns `true` only if local is a binding that can itself be
|
2018-06-15 05:47:36 +02:00
|
|
|
/// made mutable via the addition of the `mut` keyword, namely
|
|
|
|
/// something like the occurrences of `x` in:
|
|
|
|
/// - `fn foo(x: Type) { ... }`,
|
|
|
|
/// - `let x = ...`,
|
|
|
|
/// - or `match ... { C(x) => ... }`
|
2018-06-19 21:22:52 -03:00
|
|
|
pub fn can_be_made_mutable(&self) -> bool {
|
2020-09-21 04:53:44 +02:00
|
|
|
matches!(
|
2023-03-10 10:29:41 +00:00
|
|
|
self.local_info(),
|
|
|
|
LocalInfo::User(
|
2020-09-21 04:53:44 +02:00
|
|
|
BindingForm::Var(VarBindingForm {
|
|
|
|
binding_mode: ty::BindingMode::BindByValue(_),
|
|
|
|
opt_ty_info: _,
|
|
|
|
opt_match_place: _,
|
|
|
|
pat_span: _,
|
2021-01-09 12:00:45 -05:00
|
|
|
}) | BindingForm::ImplicitSelf(ImplicitSelfKind::Imm),
|
2023-03-10 10:29:41 +00:00
|
|
|
)
|
2020-09-21 04:53:44 +02:00
|
|
|
)
|
2018-06-15 05:47:36 +02:00
|
|
|
}
|
|
|
|
|
2019-02-08 14:53:55 +01:00
|
|
|
/// Returns `true` if local is definitely not a `ref ident` or
|
2018-06-15 05:47:36 +02:00
|
|
|
/// `ref mut ident` binding. (Such bindings cannot be made into
|
|
|
|
/// mutable bindings, but the inverse does not necessarily hold).
|
2018-06-19 21:22:52 -03:00
|
|
|
pub fn is_nonref_binding(&self) -> bool {
|
2020-09-21 04:53:44 +02:00
|
|
|
matches!(
|
2023-03-10 10:29:41 +00:00
|
|
|
self.local_info(),
|
|
|
|
LocalInfo::User(
|
2020-09-21 04:53:44 +02:00
|
|
|
BindingForm::Var(VarBindingForm {
|
|
|
|
binding_mode: ty::BindingMode::BindByValue(_),
|
|
|
|
opt_ty_info: _,
|
|
|
|
opt_match_place: _,
|
|
|
|
pat_span: _,
|
2021-01-09 12:00:45 -05:00
|
|
|
}) | BindingForm::ImplicitSelf(_),
|
2023-03-10 10:29:41 +00:00
|
|
|
)
|
2020-09-21 04:53:44 +02:00
|
|
|
)
|
2018-06-15 05:47:36 +02:00
|
|
|
}
|
|
|
|
|
2019-11-18 23:04:06 +00:00
|
|
|
/// Returns `true` if this variable is a named variable or function
|
|
|
|
/// parameter declared by the user.
|
|
|
|
#[inline]
|
|
|
|
pub fn is_user_variable(&self) -> bool {
|
2023-03-10 10:29:41 +00:00
|
|
|
matches!(self.local_info(), LocalInfo::User(_))
|
2018-06-15 05:47:36 +02:00
|
|
|
}
|
|
|
|
|
2019-05-04 22:26:59 +01:00
|
|
|
/// Returns `true` if this is a reference to a variable bound in a `match`
|
|
|
|
/// expression that is used to access said variable for the guard of the
|
|
|
|
/// match arm.
|
|
|
|
pub fn is_ref_for_guard(&self) -> bool {
|
2023-03-10 10:29:41 +00:00
|
|
|
matches!(self.local_info(), LocalInfo::User(BindingForm::RefForGuard))
|
2019-11-18 23:04:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Returns `Some` if this is a reference to a static item that is used to
|
2020-10-19 10:53:20 +02:00
|
|
|
/// access that static.
|
2019-11-18 23:04:06 +00:00
|
|
|
pub fn is_ref_to_static(&self) -> bool {
|
2023-03-10 10:29:41 +00:00
|
|
|
matches!(self.local_info(), LocalInfo::StaticRef { .. })
|
2019-11-18 23:04:06 +00:00
|
|
|
}
|
|
|
|
|
2020-10-19 10:53:20 +02:00
|
|
|
/// Returns `Some` if this is a reference to a thread-local static item that is used to
|
|
|
|
/// access that static.
|
2019-11-18 23:04:06 +00:00
|
|
|
pub fn is_ref_to_thread_local(&self) -> bool {
|
2023-03-10 10:29:41 +00:00
|
|
|
match self.local_info() {
|
|
|
|
LocalInfo::StaticRef { is_thread_local, .. } => *is_thread_local,
|
2019-05-04 22:26:59 +01:00
|
|
|
_ => false,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-06-13 16:37:41 +03:00
|
|
|
/// Returns `true` if this is a DerefTemp
|
|
|
|
pub fn is_deref_temp(&self) -> bool {
|
2023-03-10 10:29:41 +00:00
|
|
|
match self.local_info() {
|
|
|
|
LocalInfo::DerefTemp => return true,
|
2022-06-13 16:37:41 +03:00
|
|
|
_ => (),
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2019-05-03 22:24:52 +01:00
|
|
|
/// Returns `true` is the local is from a compiler desugaring, e.g.,
|
|
|
|
/// `__next` from a `for` loop.
|
|
|
|
#[inline]
|
|
|
|
pub fn from_compiler_desugaring(&self) -> bool {
|
2019-06-19 01:08:45 +03:00
|
|
|
self.source_info.span.desugaring_kind().is_some()
|
2019-05-03 22:24:52 +01:00
|
|
|
}
|
|
|
|
|
2023-10-04 17:50:03 +00:00
|
|
|
/// Creates a new `LocalDecl` for a temporary, mutable.
|
2016-09-25 01:38:27 +02:00
|
|
|
#[inline]
|
2020-05-06 10:17:38 +10:00
|
|
|
pub fn new(ty: Ty<'tcx>, span: Span) -> Self {
|
|
|
|
Self::with_source_info(ty, SourceInfo::outermost(span))
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Like `LocalDecl::new`, but takes a `SourceInfo` instead of a `Span`.
|
|
|
|
#[inline]
|
|
|
|
pub fn with_source_info(ty: Ty<'tcx>, source_info: SourceInfo) -> Self {
|
|
|
|
LocalDecl {
|
|
|
|
mutability: Mutability::Mut,
|
2023-03-09 16:55:20 +00:00
|
|
|
local_info: ClearCrossCrate::Set(Box::new(LocalInfo::Boring)),
|
2020-05-06 10:17:38 +10:00
|
|
|
ty,
|
2020-05-06 12:41:15 +10:00
|
|
|
user_ty: None,
|
2020-05-06 10:17:38 +10:00
|
|
|
source_info,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-09-22 00:51:48 +02:00
|
|
|
/// Converts `self` into same `LocalDecl` except tagged as immutable.
|
2018-09-05 23:49:58 +01:00
|
|
|
#[inline]
|
2018-09-22 00:51:48 +02:00
|
|
|
pub fn immutable(mut self) -> Self {
|
|
|
|
self.mutability = Mutability::Not;
|
|
|
|
self
|
|
|
|
}
|
2016-04-16 21:51:26 +03:00
|
|
|
}
|
|
|
|
|
2022-06-17 10:53:29 +01:00
|
|
|
#[derive(Clone, TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable)]
|
2020-05-30 15:02:32 -04:00
|
|
|
pub enum VarDebugInfoContents<'tcx> {
|
2023-01-14 22:23:49 +00:00
|
|
|
/// This `Place` only contains projection which satisfy `can_use_in_debuginfo`.
|
2020-05-30 15:02:32 -04:00
|
|
|
Place(Place<'tcx>),
|
2023-09-20 20:51:14 +02:00
|
|
|
Const(ConstOperand<'tcx>),
|
2020-05-30 15:02:32 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
impl<'tcx> Debug for VarDebugInfoContents<'tcx> {
|
|
|
|
fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
|
|
|
|
match self {
|
2023-07-25 22:00:13 +02:00
|
|
|
VarDebugInfoContents::Const(c) => write!(fmt, "{c}"),
|
|
|
|
VarDebugInfoContents::Place(p) => write!(fmt, "{p:?}"),
|
2020-05-30 15:02:32 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-08-26 16:58:42 +00:00
|
|
|
#[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable)]
|
2022-10-01 23:10:36 +02:00
|
|
|
pub struct VarDebugInfoFragment<'tcx> {
|
2023-08-26 16:58:42 +00:00
|
|
|
/// Type of the original user variable.
|
|
|
|
/// This cannot contain a union or an enum.
|
|
|
|
pub ty: Ty<'tcx>,
|
|
|
|
|
2022-10-01 23:10:36 +02:00
|
|
|
/// Where in the composite user variable this fragment is,
|
|
|
|
/// represented as a "projection" into the composite variable.
|
|
|
|
/// At lower levels, this corresponds to a byte/bit range.
|
2023-01-14 22:23:49 +00:00
|
|
|
///
|
|
|
|
/// This can only contain `PlaceElem::Field`.
|
|
|
|
// FIXME support this for `enum`s by either using DWARF's
|
2022-10-01 23:10:36 +02:00
|
|
|
// more advanced control-flow features (unsupported by LLVM?)
|
|
|
|
// to match on the discriminant, or by using custom type debuginfo
|
|
|
|
// with non-overlapping variants for the composite variable.
|
|
|
|
pub projection: Vec<PlaceElem<'tcx>>,
|
|
|
|
}
|
|
|
|
|
2018-05-16 18:58:54 +03:00
|
|
|
/// Debug information pertaining to a user variable.
|
2023-08-26 16:58:42 +00:00
|
|
|
#[derive(Clone, TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable)]
|
2018-05-16 18:58:54 +03:00
|
|
|
pub struct VarDebugInfo<'tcx> {
|
2020-04-19 13:00:18 +02:00
|
|
|
pub name: Symbol,
|
2016-04-16 21:51:26 +03:00
|
|
|
|
2018-05-16 18:58:54 +03:00
|
|
|
/// Source info of the user variable, including the scope
|
|
|
|
/// within which the variable is visible (to debuginfo)
|
|
|
|
/// (see `LocalDecl`'s `source_info` field for more details).
|
|
|
|
pub source_info: SourceInfo,
|
|
|
|
|
2023-08-26 16:58:42 +00:00
|
|
|
/// The user variable's data is split across several fragments,
|
|
|
|
/// each described by a `VarDebugInfoFragment`.
|
|
|
|
/// See DWARF 5's "2.6.1.2 Composite Location Descriptions"
|
|
|
|
/// and LLVM's `DW_OP_LLVM_fragment` for more details on
|
|
|
|
/// the underlying debuginfo feature this relies on.
|
|
|
|
pub composite: Option<Box<VarDebugInfoFragment<'tcx>>>,
|
|
|
|
|
2018-05-16 18:58:54 +03:00
|
|
|
/// Where the data for this user variable is to be found.
|
2020-05-30 15:02:32 -04:00
|
|
|
pub value: VarDebugInfoContents<'tcx>,
|
2023-03-21 21:48:03 +11:00
|
|
|
|
|
|
|
/// When present, indicates what argument number this variable is in the function that it
|
|
|
|
/// originated from (starting from 1). Note, if MIR inlining is enabled, then this is the
|
|
|
|
/// argument number in the original function before it was inlined.
|
|
|
|
pub argument_index: Option<u16>,
|
2015-08-18 17:59:21 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
|
|
// BasicBlock
|
|
|
|
|
2019-09-26 05:38:33 +00:00
|
|
|
rustc_index::newtype_index! {
|
2020-09-16 15:31:56 -07:00
|
|
|
/// A node in the MIR [control-flow graph][CFG].
|
2020-09-14 20:05:00 -07:00
|
|
|
///
|
2020-09-15 09:50:55 -07:00
|
|
|
/// There are no branches (e.g., `if`s, function calls, etc.) within a basic block, which makes
|
2020-09-14 20:10:29 -07:00
|
|
|
/// it easier to do [data-flow analyses] and optimizations. Instead, branches are represented
|
|
|
|
/// as an edge in a graph between basic blocks.
|
|
|
|
///
|
2020-09-15 09:50:55 -07:00
|
|
|
/// Basic blocks consist of a series of [statements][Statement], ending with a
|
2020-09-16 15:31:56 -07:00
|
|
|
/// [terminator][Terminator]. Basic blocks can have multiple predecessors and successors,
|
|
|
|
/// however there is a MIR pass ([`CriticalCallEdges`]) that removes *critical edges*, which
|
|
|
|
/// are edges that go from a multi-successor node to a multi-predecessor node. This pass is
|
|
|
|
/// needed because some analyses require that there are no critical edges in the CFG.
|
2020-09-14 20:05:00 -07:00
|
|
|
///
|
2020-10-16 20:35:56 -07:00
|
|
|
/// Note that this type is just an index into [`Body.basic_blocks`](Body::basic_blocks);
|
|
|
|
/// the actual data that a basic block holds is in [`BasicBlockData`].
|
|
|
|
///
|
2020-09-14 20:05:00 -07:00
|
|
|
/// Read more about basic blocks in the [rustc-dev-guide][guide-mir].
|
|
|
|
///
|
|
|
|
/// [CFG]: https://rustc-dev-guide.rust-lang.org/appendix/background.html#cfg
|
|
|
|
/// [data-flow analyses]:
|
|
|
|
/// https://rustc-dev-guide.rust-lang.org/appendix/background.html#what-is-a-dataflow-analysis
|
2021-01-05 20:08:11 +01:00
|
|
|
/// [`CriticalCallEdges`]: ../../rustc_const_eval/transform/add_call_guards/enum.AddCallGuards.html#variant.CriticalCallEdges
|
2020-09-14 20:05:00 -07:00
|
|
|
/// [guide-mir]: https://rustc-dev-guide.rust-lang.org/mir/
|
2022-12-18 20:53:08 +01:00
|
|
|
#[derive(HashStable)]
|
2022-12-18 21:37:38 +01:00
|
|
|
#[debug_format = "bb{}"]
|
2018-07-25 13:41:32 +03:00
|
|
|
pub struct BasicBlock {
|
2022-12-18 21:47:28 +01:00
|
|
|
const START_BLOCK = 0;
|
2018-07-25 13:41:32 +03:00
|
|
|
}
|
|
|
|
}
|
2017-12-06 09:25:29 +01:00
|
|
|
|
|
|
|
impl BasicBlock {
|
|
|
|
pub fn start_location(self) -> Location {
|
2019-07-12 22:49:15 +02:00
|
|
|
Location { block: self, statement_index: 0 }
|
2017-12-06 09:25:29 +01:00
|
|
|
}
|
|
|
|
}
|
2015-08-18 17:59:21 -04:00
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
2022-06-28 20:05:23 -04:00
|
|
|
// BasicBlockData
|
2015-08-18 17:59:21 -04:00
|
|
|
|
2022-07-07 11:32:52 -05:00
|
|
|
/// Data for a basic block, including a list of its statements.
|
|
|
|
///
|
2020-09-14 20:05:00 -07:00
|
|
|
/// See [`BasicBlock`] for documentation on what basic blocks are at a high level.
|
2022-06-17 10:53:29 +01:00
|
|
|
#[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable)]
|
2015-10-05 12:31:48 -04:00
|
|
|
pub struct BasicBlockData<'tcx> {
|
2016-03-24 06:12:19 -04:00
|
|
|
/// List of statements in this block.
|
2015-10-05 12:31:48 -04:00
|
|
|
pub statements: Vec<Statement<'tcx>>,
|
2016-03-24 06:12:19 -04:00
|
|
|
|
|
|
|
/// Terminator for this block.
|
|
|
|
///
|
2019-02-08 14:53:55 +01:00
|
|
|
/// N.B., this should generally ONLY be `None` during construction.
|
2016-03-24 06:12:19 -04:00
|
|
|
/// Therefore, you should generally access it via the
|
|
|
|
/// `terminator()` or `terminator_mut()` methods. The only
|
|
|
|
/// exception is that certain passes, such as `simplify_cfg`, swap
|
|
|
|
/// out the terminator temporarily with `None` while they continue
|
|
|
|
/// to recurse over the set of basic blocks.
|
2015-12-19 00:44:32 +02:00
|
|
|
pub terminator: Option<Terminator<'tcx>>,
|
2016-03-24 06:12:19 -04:00
|
|
|
|
|
|
|
/// If true, this block lies on an unwind path. This is used
|
2018-05-08 16:10:16 +03:00
|
|
|
/// during codegen where distinct kinds of basic blocks may be
|
2016-03-24 06:12:19 -04:00
|
|
|
/// generated (particularly for MSVC cleanup). Unwind blocks must
|
|
|
|
/// only branch to other unwind blocks.
|
2015-12-20 15:30:09 +02:00
|
|
|
pub is_cleanup: bool,
|
2015-08-18 17:59:21 -04:00
|
|
|
}
|
|
|
|
|
2015-10-05 12:31:48 -04:00
|
|
|
impl<'tcx> BasicBlockData<'tcx> {
|
2015-12-19 00:44:32 +02:00
|
|
|
pub fn new(terminator: Option<Terminator<'tcx>>) -> BasicBlockData<'tcx> {
|
2019-07-12 22:49:15 +02:00
|
|
|
BasicBlockData { statements: vec![], terminator, is_cleanup: false }
|
2015-08-18 17:59:21 -04:00
|
|
|
}
|
2015-12-19 00:44:32 +02:00
|
|
|
|
|
|
|
/// Accessor for terminator.
|
|
|
|
///
|
|
|
|
/// Terminator may not be None after construction of the basic block is complete. This accessor
|
2022-07-07 11:32:52 -05:00
|
|
|
/// provides a convenient way to reach the terminator.
|
2021-06-01 00:00:00 +00:00
|
|
|
#[inline]
|
2015-12-19 00:44:32 +02:00
|
|
|
pub fn terminator(&self) -> &Terminator<'tcx> {
|
|
|
|
self.terminator.as_ref().expect("invalid terminator state")
|
|
|
|
}
|
|
|
|
|
2021-06-01 00:00:00 +00:00
|
|
|
#[inline]
|
2019-10-04 00:55:28 -04:00
|
|
|
pub fn terminator_mut(&mut self) -> &mut Terminator<'tcx> {
|
2015-12-19 00:44:32 +02:00
|
|
|
self.terminator.as_mut().expect("invalid terminator state")
|
|
|
|
}
|
2016-12-26 14:34:03 +01:00
|
|
|
|
2018-06-19 21:22:52 -03:00
|
|
|
pub fn retain_statements<F>(&mut self, mut f: F)
|
|
|
|
where
|
2018-08-29 22:02:42 -07:00
|
|
|
F: FnMut(&mut Statement<'_>) -> bool,
|
2018-06-19 21:22:52 -03:00
|
|
|
{
|
2016-12-26 14:34:03 +01:00
|
|
|
for s in &mut self.statements {
|
|
|
|
if !f(s) {
|
2018-02-16 19:20:18 +02:00
|
|
|
s.make_nop();
|
2016-12-26 14:34:03 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2017-12-12 17:29:37 -03:00
|
|
|
|
2018-02-16 19:20:18 +02:00
|
|
|
pub fn expand_statements<F, I>(&mut self, mut f: F)
|
2018-06-19 21:22:52 -03:00
|
|
|
where
|
|
|
|
F: FnMut(&mut Statement<'tcx>) -> Option<I>,
|
|
|
|
I: iter::TrustedLen<Item = Statement<'tcx>>,
|
2018-02-16 19:20:18 +02:00
|
|
|
{
|
|
|
|
// Gather all the iterators we'll need to splice in, and their positions.
|
|
|
|
let mut splices: Vec<(usize, I)> = vec![];
|
|
|
|
let mut extra_stmts = 0;
|
|
|
|
for (i, s) in self.statements.iter_mut().enumerate() {
|
|
|
|
if let Some(mut new_stmts) = f(s) {
|
|
|
|
if let Some(first) = new_stmts.next() {
|
|
|
|
// We can already store the first new statement.
|
|
|
|
*s = first;
|
|
|
|
|
|
|
|
// Save the other statements for optimized splicing.
|
|
|
|
let remaining = new_stmts.size_hint().0;
|
|
|
|
if remaining > 0 {
|
|
|
|
splices.push((i + 1 + extra_stmts, new_stmts));
|
|
|
|
extra_stmts += remaining;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
s.make_nop();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Splice in the new statements, from the end of the block.
|
|
|
|
// FIXME(eddyb) This could be more efficient with a "gap buffer"
|
|
|
|
// where a range of elements ("gap") is left uninitialized, with
|
|
|
|
// splicing adding new elements to the end of that gap and moving
|
|
|
|
// existing elements from before the gap to the end of the gap.
|
|
|
|
// For now, this is safe code, emulating a gap but initializing it.
|
2018-06-19 21:22:52 -03:00
|
|
|
let mut gap = self.statements.len()..self.statements.len() + extra_stmts;
|
|
|
|
self.statements.resize(
|
|
|
|
gap.end,
|
2020-05-06 10:30:11 +10:00
|
|
|
Statement { source_info: SourceInfo::outermost(DUMMY_SP), kind: StatementKind::Nop },
|
2018-06-19 21:22:52 -03:00
|
|
|
);
|
2018-02-16 19:20:18 +02:00
|
|
|
for (splice_start, new_stmts) in splices.into_iter().rev() {
|
|
|
|
let splice_end = splice_start + new_stmts.size_hint().0;
|
|
|
|
while gap.end > splice_end {
|
|
|
|
gap.start -= 1;
|
|
|
|
gap.end -= 1;
|
|
|
|
self.statements.swap(gap.start, gap.end);
|
|
|
|
}
|
|
|
|
self.statements.splice(splice_start..splice_end, new_stmts);
|
|
|
|
gap.end = splice_start;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-12-12 17:29:37 -03:00
|
|
|
pub fn visitable(&self, index: usize) -> &dyn MirVisitable<'tcx> {
|
2022-06-14 17:34:37 +02:00
|
|
|
if index < self.statements.len() { &self.statements[index] } else { &self.terminator }
|
2017-12-12 17:29:37 -03:00
|
|
|
}
|
Use `br` instead of `switch` in more cases.
`codegen_switchint_terminator` already uses `br` instead of `switch`
when there is one normal target plus the `otherwise` target. But there's
another common case with two normal targets and an `otherwise` target
that points to an empty unreachable BB. This comes up a lot when
switching on the tags of enums that use niches.
The pattern looks like this:
```
bb1: ; preds = %bb6
%3 = load i8, ptr %_2, align 1, !range !9, !noundef !4
%4 = sub i8 %3, 2
%5 = icmp eq i8 %4, 0
%_6 = select i1 %5, i64 0, i64 1
switch i64 %_6, label %bb3 [
i64 0, label %bb4
i64 1, label %bb2
]
bb3: ; preds = %bb1
unreachable
```
This commit adds code to convert the `switch` to a `br`:
```
bb1: ; preds = %bb6
%3 = load i8, ptr %_2, align 1, !range !9, !noundef !4
%4 = sub i8 %3, 2
%5 = icmp eq i8 %4, 0
%_6 = select i1 %5, i64 0, i64 1
%6 = icmp eq i64 %_6, 0
br i1 %6, label %bb4, label %bb2
bb3: ; No predecessors!
unreachable
```
This has a surprisingly large effect on compile times, with reductions
of 5% on debug builds of some crates. The reduction is all due to LLVM
taking less time. Maybe LLVM is just much better at handling `br` than
`switch`.
The resulting code is still suboptimal.
- The `icmp`, `select`, `icmp` sequence is silly, converting an `i1` to an `i64`
and back to an `i1`. But with the current code structure it's hard to avoid,
and LLVM will easily clean it up, in opt builds at least.
- `bb3` is usually now truly dead code (though not always, so it can't
be removed universally).
2022-10-20 18:59:07 +11:00
|
|
|
|
|
|
|
/// Does the block have no statements and an unreachable terminator?
|
|
|
|
pub fn is_empty_unreachable(&self) -> bool {
|
|
|
|
self.statements.is_empty() && matches!(self.terminator().kind, TerminatorKind::Unreachable)
|
|
|
|
}
|
2015-08-18 17:59:21 -04:00
|
|
|
}
|
|
|
|
|
2016-03-09 11:04:26 -05:00
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
|
|
// Scopes
|
|
|
|
|
2019-09-26 05:38:33 +00:00
|
|
|
rustc_index::newtype_index! {
|
2022-12-18 20:53:08 +01:00
|
|
|
#[derive(HashStable)]
|
2022-12-18 21:37:38 +01:00
|
|
|
#[debug_format = "scope[{}]"]
|
2018-07-25 13:41:32 +03:00
|
|
|
pub struct SourceScope {
|
2022-12-18 21:47:28 +01:00
|
|
|
const OUTERMOST_SOURCE_SCOPE = 0;
|
2018-07-25 13:41:32 +03:00
|
|
|
}
|
|
|
|
}
|
2016-03-09 11:04:26 -05:00
|
|
|
|
2021-03-26 13:39:04 +00:00
|
|
|
impl SourceScope {
|
|
|
|
/// Finds the original HirId this MIR item came from.
|
|
|
|
/// This is necessary after MIR optimizations, as otherwise we get a HirId
|
|
|
|
/// from the function that was inlined instead of the function call site.
|
2022-12-20 22:10:40 +01:00
|
|
|
pub fn lint_root(
|
2021-03-26 16:33:14 +00:00
|
|
|
self,
|
2023-03-31 00:32:44 -07:00
|
|
|
source_scopes: &IndexSlice<SourceScope, SourceScopeData<'_>>,
|
2021-03-26 16:33:14 +00:00
|
|
|
) -> Option<HirId> {
|
2021-03-26 13:39:04 +00:00
|
|
|
let mut data = &source_scopes[self];
|
|
|
|
// FIXME(oli-obk): we should be able to just walk the `inlined_parent_scope`, but it
|
|
|
|
// does not work as I thought it would. Needs more investigation and documentation.
|
|
|
|
while data.inlined.is_some() {
|
|
|
|
trace!(?data);
|
|
|
|
data = &source_scopes[data.parent_scope.unwrap()];
|
|
|
|
}
|
|
|
|
trace!(?data);
|
|
|
|
match &data.local_data {
|
|
|
|
ClearCrossCrate::Set(data) => Some(data.lint_root),
|
|
|
|
ClearCrossCrate::Clear => None,
|
|
|
|
}
|
|
|
|
}
|
2022-07-03 00:00:00 +00:00
|
|
|
|
|
|
|
/// The instance this source scope was inlined from, if any.
|
|
|
|
#[inline]
|
|
|
|
pub fn inlined_instance<'tcx>(
|
|
|
|
self,
|
2023-03-31 00:32:44 -07:00
|
|
|
source_scopes: &IndexSlice<SourceScope, SourceScopeData<'tcx>>,
|
2022-07-03 00:00:00 +00:00
|
|
|
) -> Option<ty::Instance<'tcx>> {
|
|
|
|
let scope_data = &source_scopes[self];
|
|
|
|
if let Some((inlined_instance, _)) = scope_data.inlined {
|
|
|
|
Some(inlined_instance)
|
|
|
|
} else if let Some(inlined_scope) = scope_data.inlined_parent_scope {
|
|
|
|
Some(source_scopes[inlined_scope].inlined.unwrap().0)
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
}
|
|
|
|
}
|
2021-03-26 13:39:04 +00:00
|
|
|
}
|
|
|
|
|
2022-06-17 10:53:29 +01:00
|
|
|
#[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable)]
|
2020-02-08 21:31:09 +02:00
|
|
|
pub struct SourceScopeData<'tcx> {
|
2016-04-06 17:17:12 +03:00
|
|
|
pub span: Span,
|
2018-05-28 14:16:09 +03:00
|
|
|
pub parent_scope: Option<SourceScope>,
|
2019-11-26 22:17:35 +02:00
|
|
|
|
2020-02-08 21:31:09 +02:00
|
|
|
/// Whether this scope is the root of a scope tree of another body,
|
|
|
|
/// inlined into this body by the MIR inliner.
|
|
|
|
/// `ty::Instance` is the callee, and the `Span` is the call site.
|
|
|
|
pub inlined: Option<(ty::Instance<'tcx>, Span)>,
|
|
|
|
|
2020-09-21 06:52:37 +03:00
|
|
|
/// Nearest (transitive) parent scope (if any) which is inlined.
|
|
|
|
/// This is an optimization over walking up `parent_scope`
|
|
|
|
/// until a scope with `inlined: Some(...)` is found.
|
|
|
|
pub inlined_parent_scope: Option<SourceScope>,
|
|
|
|
|
2019-11-26 22:17:35 +02:00
|
|
|
/// Crate-local information for this source scope, that can't (and
|
|
|
|
/// needn't) be tracked across crates.
|
|
|
|
pub local_data: ClearCrossCrate<SourceScopeLocalData>,
|
2016-03-09 11:04:26 -05:00
|
|
|
}
|
|
|
|
|
2020-06-11 15:49:57 +01:00
|
|
|
#[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable)]
|
2018-05-28 17:37:48 +03:00
|
|
|
pub struct SourceScopeLocalData {
|
2019-09-06 03:57:44 +01:00
|
|
|
/// An `HirId` with lint levels equivalent to this scope's lint levels.
|
2019-02-22 15:48:14 +01:00
|
|
|
pub lint_root: hir::HirId,
|
2018-05-28 17:37:48 +03:00
|
|
|
/// The unsafe block that contains this node.
|
|
|
|
pub safety: Safety,
|
|
|
|
}
|
|
|
|
|
2018-10-22 14:23:44 +02:00
|
|
|
/// A collection of projections into user types.
|
|
|
|
///
|
|
|
|
/// They are projections because a binding can occur a part of a
|
|
|
|
/// parent pattern that has been ascribed a type.
|
|
|
|
///
|
2023-09-15 08:49:37 +02:00
|
|
|
/// It's a collection because there can be multiple type ascriptions on
|
2018-10-22 14:23:44 +02:00
|
|
|
/// the path from the root of the pattern down to the binding itself.
|
2018-10-22 22:50:10 +02:00
|
|
|
///
|
|
|
|
/// An example:
|
|
|
|
///
|
2022-04-15 15:04:34 -07:00
|
|
|
/// ```ignore (illustrative)
|
2018-10-22 22:50:10 +02:00
|
|
|
/// struct S<'a>((i32, &'a str), String);
|
|
|
|
/// let S((_, w): (i32, &'static str), _): S = ...;
|
|
|
|
/// // ------ ^^^^^^^^^^^^^^^^^^^ (1)
|
|
|
|
/// // --------------------------------- ^ (2)
|
|
|
|
/// ```
|
|
|
|
///
|
|
|
|
/// The highlights labelled `(1)` show the subpattern `(_, w)` being
|
|
|
|
/// ascribed the type `(i32, &'static str)`.
|
|
|
|
///
|
|
|
|
/// The highlights labelled `(2)` show the whole pattern being
|
|
|
|
/// ascribed the type `S`.
|
|
|
|
///
|
|
|
|
/// In this example, when we descend to `w`, we will have built up the
|
|
|
|
/// following two projected types:
|
|
|
|
///
|
|
|
|
/// * base: `S`, projection: `(base.0).1`
|
|
|
|
/// * base: `(i32, &'static str)`, projection: `base.1`
|
|
|
|
///
|
|
|
|
/// The first will lead to the constraint `w: &'1 str` (for some
|
|
|
|
/// inferred region `'1`). The second will lead to the constraint `w:
|
|
|
|
/// &'static str`.
|
2022-06-17 10:53:29 +01:00
|
|
|
#[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable)]
|
2019-03-28 18:00:17 -07:00
|
|
|
pub struct UserTypeProjections {
|
2020-05-06 12:41:15 +10:00
|
|
|
pub contents: Vec<(UserTypeProjection, Span)>,
|
2018-10-22 14:23:44 +02:00
|
|
|
}
|
|
|
|
|
2019-03-28 18:00:17 -07:00
|
|
|
impl<'tcx> UserTypeProjections {
|
2018-10-22 14:23:44 +02:00
|
|
|
pub fn none() -> Self {
|
|
|
|
UserTypeProjections { contents: vec![] }
|
|
|
|
}
|
|
|
|
|
2020-05-06 12:41:15 +10:00
|
|
|
pub fn is_empty(&self) -> bool {
|
|
|
|
self.contents.is_empty()
|
|
|
|
}
|
|
|
|
|
2019-12-07 19:37:09 +01:00
|
|
|
pub fn projections_and_spans(
|
|
|
|
&self,
|
|
|
|
) -> impl Iterator<Item = &(UserTypeProjection, Span)> + ExactSizeIterator {
|
2018-10-22 14:23:44 +02:00
|
|
|
self.contents.iter()
|
|
|
|
}
|
|
|
|
|
2019-12-07 19:37:09 +01:00
|
|
|
pub fn projections(&self) -> impl Iterator<Item = &UserTypeProjection> + ExactSizeIterator {
|
2018-10-22 14:23:44 +02:00
|
|
|
self.contents.iter().map(|&(ref user_type, _span)| user_type)
|
|
|
|
}
|
2018-12-19 16:47:06 +01:00
|
|
|
|
2019-07-12 22:49:15 +02:00
|
|
|
pub fn push_projection(mut self, user_ty: &UserTypeProjection, span: Span) -> Self {
|
2018-12-19 16:47:06 +01:00
|
|
|
self.contents.push((user_ty.clone(), span));
|
|
|
|
self
|
|
|
|
}
|
|
|
|
|
|
|
|
fn map_projections(
|
|
|
|
mut self,
|
2019-07-12 22:49:15 +02:00
|
|
|
mut f: impl FnMut(UserTypeProjection) -> UserTypeProjection,
|
2018-12-19 16:47:06 +01:00
|
|
|
) -> Self {
|
2021-11-06 18:42:07 +01:00
|
|
|
self.contents = self.contents.into_iter().map(|(proj, span)| (f(proj), span)).collect();
|
2018-12-19 16:47:06 +01:00
|
|
|
self
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn index(self) -> Self {
|
|
|
|
self.map_projections(|pat_ty_proj| pat_ty_proj.index())
|
|
|
|
}
|
|
|
|
|
2020-08-23 14:54:58 +02:00
|
|
|
pub fn subslice(self, from: u64, to: u64) -> Self {
|
2018-12-19 16:47:06 +01:00
|
|
|
self.map_projections(|pat_ty_proj| pat_ty_proj.subslice(from, to))
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn deref(self) -> Self {
|
|
|
|
self.map_projections(|pat_ty_proj| pat_ty_proj.deref())
|
|
|
|
}
|
|
|
|
|
2023-03-28 12:32:57 -07:00
|
|
|
pub fn leaf(self, field: FieldIdx) -> Self {
|
2018-12-19 16:47:06 +01:00
|
|
|
self.map_projections(|pat_ty_proj| pat_ty_proj.leaf(field))
|
|
|
|
}
|
|
|
|
|
2023-03-28 12:32:57 -07:00
|
|
|
pub fn variant(
|
|
|
|
self,
|
|
|
|
adt_def: AdtDef<'tcx>,
|
|
|
|
variant_index: VariantIdx,
|
|
|
|
field_index: FieldIdx,
|
|
|
|
) -> Self {
|
|
|
|
self.map_projections(|pat_ty_proj| pat_ty_proj.variant(adt_def, variant_index, field_index))
|
2018-12-19 16:47:06 +01:00
|
|
|
}
|
2018-10-22 14:23:44 +02:00
|
|
|
}
|
|
|
|
|
2018-10-22 22:50:10 +02:00
|
|
|
/// Encodes the effect of a user-supplied type annotation on the
|
|
|
|
/// subcomponents of a pattern. The effect is determined by applying the
|
2022-03-30 15:14:15 -04:00
|
|
|
/// given list of projections to some underlying base type. Often,
|
2018-10-22 22:50:10 +02:00
|
|
|
/// the projection element list `projs` is empty, in which case this
|
|
|
|
/// directly encodes a type in `base`. But in the case of complex patterns with
|
|
|
|
/// subpatterns and bindings, we want to apply only a *part* of the type to a variable,
|
|
|
|
/// in which case the `projs` vector is used.
|
|
|
|
///
|
|
|
|
/// Examples:
|
|
|
|
///
|
|
|
|
/// * `let x: T = ...` -- here, the `projs` vector is empty.
|
|
|
|
///
|
|
|
|
/// * `let (x, _): T = ...` -- here, the `projs` vector would contain
|
|
|
|
/// `field[0]` (aka `.0`), indicating that the type of `s` is
|
|
|
|
/// determined by finding the type of the `.0` field from `T`.
|
2020-10-04 15:52:14 +02:00
|
|
|
#[derive(Clone, Debug, TyEncodable, TyDecodable, Hash, HashStable, PartialEq)]
|
2023-04-26 14:53:14 +10:00
|
|
|
#[derive(TypeFoldable, TypeVisitable)]
|
2019-03-28 18:00:17 -07:00
|
|
|
pub struct UserTypeProjection {
|
2018-11-16 22:56:18 +01:00
|
|
|
pub base: UserTypeAnnotationIndex,
|
2019-05-01 15:34:51 +01:00
|
|
|
pub projs: Vec<ProjectionKind>,
|
2018-10-22 11:58:06 +02:00
|
|
|
}
|
|
|
|
|
2019-03-28 18:00:17 -07:00
|
|
|
impl UserTypeProjection {
|
2018-12-19 16:47:06 +01:00
|
|
|
pub(crate) fn index(mut self) -> Self {
|
|
|
|
self.projs.push(ProjectionElem::Index(()));
|
|
|
|
self
|
|
|
|
}
|
|
|
|
|
2020-08-23 14:54:58 +02:00
|
|
|
pub(crate) fn subslice(mut self, from: u64, to: u64) -> Self {
|
2019-11-22 20:28:02 +00:00
|
|
|
self.projs.push(ProjectionElem::Subslice { from, to, from_end: true });
|
2018-12-19 16:47:06 +01:00
|
|
|
self
|
|
|
|
}
|
|
|
|
|
|
|
|
pub(crate) fn deref(mut self) -> Self {
|
|
|
|
self.projs.push(ProjectionElem::Deref);
|
|
|
|
self
|
|
|
|
}
|
|
|
|
|
2023-03-28 12:32:57 -07:00
|
|
|
pub(crate) fn leaf(mut self, field: FieldIdx) -> Self {
|
2018-12-19 16:47:06 +01:00
|
|
|
self.projs.push(ProjectionElem::Field(field, ()));
|
|
|
|
self
|
|
|
|
}
|
|
|
|
|
|
|
|
pub(crate) fn variant(
|
|
|
|
mut self,
|
2022-03-05 07:28:41 +11:00
|
|
|
adt_def: AdtDef<'_>,
|
2018-12-19 16:47:06 +01:00
|
|
|
variant_index: VariantIdx,
|
2023-03-28 12:32:57 -07:00
|
|
|
field_index: FieldIdx,
|
2018-12-19 16:47:06 +01:00
|
|
|
) -> Self {
|
2019-03-28 18:00:17 -07:00
|
|
|
self.projs.push(ProjectionElem::Downcast(
|
2022-03-05 07:28:41 +11:00
|
|
|
Some(adt_def.variant(variant_index).name),
|
2019-07-12 22:49:15 +02:00
|
|
|
variant_index,
|
|
|
|
));
|
2023-03-28 12:32:57 -07:00
|
|
|
self.projs.push(ProjectionElem::Field(field_index, ()));
|
2018-12-19 16:47:06 +01:00
|
|
|
self
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-09-26 05:38:33 +00:00
|
|
|
rustc_index::newtype_index! {
|
2022-12-18 20:53:08 +01:00
|
|
|
#[derive(HashStable)]
|
2022-12-18 21:37:38 +01:00
|
|
|
#[debug_format = "promoted[{}]"]
|
2022-12-18 21:47:28 +01:00
|
|
|
pub struct Promoted {}
|
2018-07-25 13:41:32 +03:00
|
|
|
}
|
2017-12-06 09:25:29 +01:00
|
|
|
|
2020-04-17 13:24:33 -04:00
|
|
|
/// `Location` represents the position of the start of the statement; or, if
|
|
|
|
/// `statement_index` equals the number of statements, then the start of the
|
|
|
|
/// terminator.
|
2022-10-27 16:15:11 +00:00
|
|
|
#[derive(Copy, Clone, PartialEq, Eq, Hash, Ord, PartialOrd, HashStable)]
|
2016-08-08 18:46:06 -07:00
|
|
|
pub struct Location {
|
2019-09-06 03:57:44 +01:00
|
|
|
/// The block that the location is within.
|
2016-08-08 18:46:06 -07:00
|
|
|
pub block: BasicBlock,
|
|
|
|
|
|
|
|
pub statement_index: usize,
|
|
|
|
}
|
|
|
|
|
2016-06-11 23:47:28 +03:00
|
|
|
impl fmt::Debug for Location {
|
2018-08-29 22:02:42 -07:00
|
|
|
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
|
2016-06-11 23:47:28 +03:00
|
|
|
write!(fmt, "{:?}[{}]", self.block, self.statement_index)
|
|
|
|
}
|
|
|
|
}
|
2016-09-15 18:18:40 -07:00
|
|
|
|
|
|
|
impl Location {
|
2019-07-12 22:49:15 +02:00
|
|
|
pub const START: Location = Location { block: START_BLOCK, statement_index: 0 };
|
2018-05-01 09:46:11 -04:00
|
|
|
|
2017-12-06 09:25:29 +01:00
|
|
|
/// Returns the location immediately after this one within the enclosing block.
|
|
|
|
///
|
|
|
|
/// Note that if this location represents a terminator, then the
|
|
|
|
/// resulting location would be out of bounds and invalid.
|
|
|
|
pub fn successor_within_block(&self) -> Location {
|
2019-07-12 22:49:15 +02:00
|
|
|
Location { block: self.block, statement_index: self.statement_index + 1 }
|
2017-12-06 09:25:29 +01:00
|
|
|
}
|
|
|
|
|
2018-11-05 15:14:28 +01:00
|
|
|
/// Returns `true` if `other` is earlier in the control flow graph than `self`.
|
2020-04-12 10:30:07 -07:00
|
|
|
pub fn is_predecessor_of<'tcx>(&self, other: Location, body: &Body<'tcx>) -> bool {
|
2018-11-05 15:14:28 +01:00
|
|
|
// If we are in the same block as the other location and are an earlier statement
|
|
|
|
// then we are a predecessor of `other`.
|
|
|
|
if self.block == other.block && self.statement_index < other.statement_index {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2022-07-05 00:00:00 +00:00
|
|
|
let predecessors = body.basic_blocks.predecessors();
|
2020-04-19 13:56:49 -07:00
|
|
|
|
2018-11-05 15:14:28 +01:00
|
|
|
// If we're in another block, then we want to check that block is a predecessor of `other`.
|
2020-04-19 13:56:49 -07:00
|
|
|
let mut queue: Vec<BasicBlock> = predecessors[other.block].to_vec();
|
2018-11-05 15:14:28 +01:00
|
|
|
let mut visited = FxHashSet::default();
|
|
|
|
|
|
|
|
while let Some(block) = queue.pop() {
|
2022-02-01 22:32:02 +01:00
|
|
|
// If we haven't visited this block before, then make sure we visit its predecessors.
|
2018-11-05 15:14:28 +01:00
|
|
|
if visited.insert(block) {
|
2020-04-19 13:56:49 -07:00
|
|
|
queue.extend(predecessors[block].iter().cloned());
|
2018-11-05 15:14:28 +01:00
|
|
|
} else {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
// If we found the block that `self` is in, then we are a predecessor of `other` (since
|
|
|
|
// we found that block by looking at the predecessors of `other`).
|
|
|
|
if self.block == block {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
false
|
|
|
|
}
|
|
|
|
|
2018-04-06 20:48:13 -04:00
|
|
|
pub fn dominates(&self, other: Location, dominators: &Dominators<BasicBlock>) -> bool {
|
2016-09-15 18:18:40 -07:00
|
|
|
if self.block == other.block {
|
|
|
|
self.statement_index <= other.statement_index
|
|
|
|
} else {
|
2023-01-20 00:00:00 +00:00
|
|
|
dominators.dominates(self.block, other.block)
|
2016-09-15 18:18:40 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2022-09-01 08:57:51 +10:00
|
|
|
|
2023-10-05 00:00:00 +00:00
|
|
|
/// `DefLocation` represents the location of a definition - either an argument or an assignment
|
|
|
|
/// within MIR body.
|
|
|
|
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
|
|
|
pub enum DefLocation {
|
|
|
|
Argument,
|
|
|
|
Body(Location),
|
|
|
|
}
|
|
|
|
|
|
|
|
impl DefLocation {
|
|
|
|
pub fn dominates(self, location: Location, dominators: &Dominators<BasicBlock>) -> bool {
|
|
|
|
match self {
|
|
|
|
DefLocation::Argument => true,
|
|
|
|
DefLocation::Body(def) => def.successor_within_block().dominates(location, dominators),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-09-01 08:57:51 +10:00
|
|
|
// Some nodes are used a lot. Make sure they don't unintentionally get bigger.
|
|
|
|
#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
|
|
|
|
mod size_asserts {
|
|
|
|
use super::*;
|
|
|
|
use rustc_data_structures::static_assert_size;
|
2022-10-05 21:46:21 +02:00
|
|
|
// tidy-alphabetical-start
|
2023-05-01 18:30:54 -04:00
|
|
|
static_assert_size!(BasicBlockData<'_>, 136);
|
2023-03-10 09:08:10 +00:00
|
|
|
static_assert_size!(LocalDecl<'_>, 40);
|
2023-04-23 21:23:54 -07:00
|
|
|
static_assert_size!(SourceScopeData<'_>, 72);
|
2022-09-01 08:57:51 +10:00
|
|
|
static_assert_size!(Statement<'_>, 32);
|
|
|
|
static_assert_size!(StatementKind<'_>, 16);
|
2023-05-01 18:30:54 -04:00
|
|
|
static_assert_size!(Terminator<'_>, 104);
|
|
|
|
static_assert_size!(TerminatorKind<'_>, 88);
|
2023-08-26 16:58:42 +00:00
|
|
|
static_assert_size!(VarDebugInfo<'_>, 88);
|
2022-10-05 21:46:21 +02:00
|
|
|
// tidy-alphabetical-end
|
2022-09-01 08:57:51 +10:00
|
|
|
}
|