1#![cfg_attr(bootstrap, feature(array_windows))]
3#![feature(assert_matches)]
4#![feature(box_patterns)]
5#![feature(const_type_name)]
6#![feature(cow_is_borrowed)]
7#![feature(file_buffered)]
8#![feature(gen_blocks)]
9#![feature(if_let_guard)]
10#![feature(impl_trait_in_assoc_type)]
11#![feature(try_blocks)]
12#![feature(yeet_expr)]
13use hir::ConstContext;
16use required_consts::RequiredConstsVisitor;
17use rustc_const_eval::check_consts::{self, ConstCx};
18use rustc_const_eval::util;
19use rustc_data_structures::fx::FxIndexSet;
20use rustc_data_structures::steal::Steal;
21use rustc_hir as hir;
22use rustc_hir::def::{CtorKind, DefKind};
23use rustc_hir::def_id::LocalDefId;
24use rustc_index::IndexVec;
25use rustc_middle::mir::{
26 AnalysisPhase, Body, CallSource, ClearCrossCrate, ConstOperand, ConstQualifs, LocalDecl,
27 MirPhase, Operand, Place, ProjectionElem, Promoted, RuntimePhase, Rvalue, START_BLOCK,
28 SourceInfo, Statement, StatementKind, TerminatorKind,
29};
30use rustc_middle::ty::{self, TyCtxt, TypeVisitableExt};
31use rustc_middle::util::Providers;
32use rustc_middle::{bug, query, span_bug};
33use rustc_span::source_map::Spanned;
34use rustc_span::{DUMMY_SP, sym};
35use tracing::debug;
36
37#[macro_use]
38mod pass_manager;
39
40use std::sync::LazyLock;
41
42use pass_manager::{self as pm, Lint, MirLint, MirPass, WithMinOptLevel};
43
44mod check_pointers;
45mod cost_checker;
46mod cross_crate_inline;
47mod deduce_param_attrs;
48mod elaborate_drop;
49mod errors;
50mod ffi_unwind_calls;
51mod lint;
52mod lint_tail_expr_drop_order;
53mod liveness;
54mod patch;
55mod shim;
56mod ssa;
57mod trivial_const;
58
59macro_rules! declare_passes {
82 (
83 $(
84 $vis:vis mod $mod_name:ident : $($pass_name:ident $( { $($ident:ident),* } )?),+ $(,)?;
85 )*
86 ) => {
87 $(
88 $vis mod $mod_name;
89 $(
90 #[allow(unused_imports)]
92 use $mod_name::$pass_name as _;
93 )+
94 )*
95
96 static PASS_NAMES: LazyLock<FxIndexSet<&str>> = LazyLock::new(|| [
97 "PreCodegen",
99 $(
100 $(
101 stringify!($pass_name),
102 $(
103 $(
104 $mod_name::$pass_name::$ident.name(),
105 )*
106 )?
107 )+
108 )*
109 ].into_iter().collect());
110 };
111}
112
113mod validate {
use rustc_abi::{ExternAbi, FIRST_VARIANT, Size};
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_hir::LangItem;
use rustc_hir::attrs::InlineAttr;
use rustc_index::IndexVec;
use rustc_index::bit_set::DenseBitSet;
use rustc_infer::infer::TyCtxtInferExt;
use rustc_infer::traits::{Obligation, ObligationCause};
use rustc_middle::mir::coverage::CoverageKind;
use rustc_middle::mir::visit::{
MutatingUseContext, NonUseContext, PlaceContext, Visitor,
};
use rustc_middle::mir::*;
use rustc_middle::ty::adjustment::PointerCoercion;
use rustc_middle::ty::print::with_no_trimmed_paths;
use rustc_middle::ty::{
self, CoroutineArgsExt, InstanceKind, ScalarInt, Ty, TyCtxt,
TypeVisitableExt, Upcast, Variance,
};
use rustc_middle::{bug, span_bug};
use rustc_mir_dataflow::debuginfo::debuginfo_locals;
use rustc_trait_selection::traits::ObligationCtxt;
use crate::util::{self, most_packed_projection};
enum EdgeKind { Unwind, Normal, }
#[automatically_derived]
impl ::core::marker::Copy for EdgeKind { }
#[automatically_derived]
#[doc(hidden)]
unsafe impl ::core::clone::TrivialClone for EdgeKind { }
#[automatically_derived]
impl ::core::clone::Clone for EdgeKind {
#[inline]
fn clone(&self) -> EdgeKind { *self }
}
#[automatically_derived]
impl ::core::fmt::Debug for EdgeKind {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::write_str(f,
match self {
EdgeKind::Unwind => "Unwind",
EdgeKind::Normal => "Normal",
})
}
}
#[automatically_derived]
impl ::core::marker::StructuralPartialEq for EdgeKind { }
#[automatically_derived]
impl ::core::cmp::PartialEq for EdgeKind {
#[inline]
fn eq(&self, other: &EdgeKind) -> bool {
let __self_discr = ::core::intrinsics::discriminant_value(self);
let __arg1_discr = ::core::intrinsics::discriminant_value(other);
__self_discr == __arg1_discr
}
}
#[automatically_derived]
impl ::core::cmp::Eq for EdgeKind {
#[inline]
#[doc(hidden)]
#[coverage(off)]
fn assert_receiver_is_total_eq(&self) -> () {}
}
pub(super) struct Validator {
pub when: String,
}
impl<'tcx> crate::MirPass<'tcx> for Validator {
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
if #[allow(non_exhaustive_omitted_patterns)] match body.source.instance
{
InstanceKind::Intrinsic(..) | InstanceKind::Virtual(..) =>
true,
_ => false,
} {
return;
}
let def_id = body.source.def_id();
let typing_env = body.typing_env(tcx);
let can_unwind =
if body.phase <= MirPhase::Runtime(RuntimePhase::Initial) {
true
} else if !tcx.def_kind(def_id).is_fn_like() {
true
} else {
let body_ty = tcx.type_of(def_id).skip_binder();
let body_abi =
match body_ty.kind() {
ty::FnDef(..) => body_ty.fn_sig(tcx).abi(),
ty::Closure(..) => ExternAbi::RustCall,
ty::CoroutineClosure(..) => ExternAbi::RustCall,
ty::Coroutine(..) => ExternAbi::Rust,
ty::Error(_) => return,
_ =>
::rustc_middle::util::bug::span_bug_fmt(body.span,
format_args!("unexpected body ty: {0}", body_ty)),
};
ty::layout::fn_can_unwind(tcx, Some(def_id), body_abi)
};
let mut cfg_checker =
CfgChecker {
when: &self.when,
body,
tcx,
unwind_edge_count: 0,
reachable_blocks: traversal::reachable_as_bitset(body),
value_cache: FxHashSet::default(),
can_unwind,
};
cfg_checker.visit_body(body);
cfg_checker.check_cleanup_control_flow();
for (location, msg) in validate_types(tcx, typing_env, body, body)
{
cfg_checker.fail(location, msg);
}
for (location, msg) in validate_debuginfos(body) {
cfg_checker.fail(location, msg);
}
if let MirPhase::Runtime(_) = body.phase &&
let ty::InstanceKind::Item(_) = body.source.instance &&
body.has_free_regions() {
cfg_checker.fail(Location::START,
::alloc::__export::must_use({
::alloc::fmt::format(format_args!("Free regions in optimized {0} MIR",
body.phase.name()))
}));
}
}
fn is_required(&self) -> bool { true }
}
struct CfgChecker<'a, 'tcx> {
when: &'a str,
body: &'a Body<'tcx>,
tcx: TyCtxt<'tcx>,
unwind_edge_count: usize,
reachable_blocks: DenseBitSet<BasicBlock>,
value_cache: FxHashSet<u128>,
can_unwind: bool,
}
impl<'a, 'tcx> CfgChecker<'a, 'tcx> {
#[track_caller]
fn fail(&self, location: Location, msg: impl AsRef<str>) {
if self.tcx.dcx().has_errors().is_none() {
::rustc_middle::util::bug::span_bug_fmt(self.body.source_info(location).span,
format_args!("broken MIR in {0:?} ({1}) at {2:?}:\n{3}",
self.body.source.instance, self.when, location,
msg.as_ref()));
}
}
fn check_edge(&mut self, location: Location, bb: BasicBlock,
edge_kind: EdgeKind) {
if bb == START_BLOCK {
self.fail(location, "start block must not have predecessors")
}
if let Some(bb) = self.body.basic_blocks.get(bb) {
let src = self.body.basic_blocks.get(location.block).unwrap();
match (src.is_cleanup, bb.is_cleanup, edge_kind) {
(false, false, EdgeKind::Normal) |
(true, true, EdgeKind::Normal) => {}
(false, true, EdgeKind::Unwind) => {
self.unwind_edge_count += 1;
}
_ => {
self.fail(location,
::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{0:?} edge to {1:?} violates unwind invariants (cleanup {2:?} -> {3:?})",
edge_kind, bb, src.is_cleanup, bb.is_cleanup))
}))
}
}
} else {
self.fail(location,
::alloc::__export::must_use({
::alloc::fmt::format(format_args!("encountered jump to invalid basic block {0:?}",
bb))
}))
}
}
fn check_cleanup_control_flow(&self) {
if self.unwind_edge_count <= 1 { return; }
let doms = self.body.basic_blocks.dominators();
let mut post_contract_node = FxHashMap::default();
let mut dom_path = ::alloc::vec::Vec::new();
let mut get_post_contract_node =
|mut bb|
{
let root =
loop {
if let Some(root) = post_contract_node.get(&bb) {
break *root;
}
let parent = doms.immediate_dominator(bb).unwrap();
dom_path.push(bb);
if !self.body.basic_blocks[parent].is_cleanup { break bb; }
bb = parent;
};
for bb in dom_path.drain(..) {
post_contract_node.insert(bb, root);
}
root
};
let mut parent =
IndexVec::from_elem(None, &self.body.basic_blocks);
for (bb, bb_data) in self.body.basic_blocks.iter_enumerated() {
if !bb_data.is_cleanup || !self.reachable_blocks.contains(bb)
{
continue;
}
let bb = get_post_contract_node(bb);
for s in bb_data.terminator().successors() {
let s = get_post_contract_node(s);
if s == bb { continue; }
let parent = &mut parent[bb];
match parent {
None => { *parent = Some(s); }
Some(e) if *e == s => (),
Some(e) =>
self.fail(Location { block: bb, statement_index: 0 },
::alloc::__export::must_use({
::alloc::fmt::format(format_args!("Cleanup control flow violation: The blocks dominated by {0:?} have edges to both {1:?} and {2:?}",
bb, s, *e))
})),
}
}
}
let mut stack = FxHashSet::default();
for (mut bb, parent) in parent.iter_enumerated_mut() {
stack.clear();
stack.insert(bb);
loop {
let Some(parent) = parent.take() else { break };
let no_cycle = stack.insert(parent);
if !no_cycle {
self.fail(Location { block: bb, statement_index: 0 },
::alloc::__export::must_use({
::alloc::fmt::format(format_args!("Cleanup control flow violation: Cycle involving edge {0:?} -> {1:?}",
bb, parent))
}));
break;
}
bb = parent;
}
}
}
fn check_unwind_edge(&mut self, location: Location,
unwind: UnwindAction) {
let is_cleanup =
self.body.basic_blocks[location.block].is_cleanup;
match unwind {
UnwindAction::Cleanup(unwind) => {
if is_cleanup {
self.fail(location,
"`UnwindAction::Cleanup` in cleanup block");
}
self.check_edge(location, unwind, EdgeKind::Unwind);
}
UnwindAction::Continue => {
if is_cleanup {
self.fail(location,
"`UnwindAction::Continue` in cleanup block");
}
if !self.can_unwind {
self.fail(location,
"`UnwindAction::Continue` in no-unwind function");
}
}
UnwindAction::Terminate(UnwindTerminateReason::InCleanup) => {
if !is_cleanup {
self.fail(location,
"`UnwindAction::Terminate(InCleanup)` in a non-cleanup block");
}
}
UnwindAction::Unreachable |
UnwindAction::Terminate(UnwindTerminateReason::Abi) => (),
}
}
fn is_critical_call_edge(&self, target: Option<BasicBlock>,
unwind: UnwindAction) -> bool {
let Some(target) = target else { return false };
#[allow(non_exhaustive_omitted_patterns)] (match unwind {
UnwindAction::Cleanup(_) | UnwindAction::Terminate(_) =>
true,
_ => false,
}) && self.body.basic_blocks.predecessors()[target].len() > 1
}
}
impl<'a, 'tcx> Visitor<'tcx> for CfgChecker<'a, 'tcx> {
fn visit_local(&mut self, local: Local, _context: PlaceContext,
location: Location) {
if self.body.local_decls.get(local).is_none() {
self.fail(location,
::alloc::__export::must_use({
::alloc::fmt::format(format_args!("local {0:?} has no corresponding declaration in `body.local_decls`",
local))
}));
}
}
fn visit_statement(&mut self, statement: &Statement<'tcx>,
location: Location) {
match &statement.kind {
StatementKind::AscribeUserType(..) => {
if self.body.phase >=
MirPhase::Runtime(RuntimePhase::Initial) {
self.fail(location,
"`AscribeUserType` should have been removed after drop lowering phase");
}
}
StatementKind::FakeRead(..) => {
if self.body.phase >=
MirPhase::Runtime(RuntimePhase::Initial) {
self.fail(location,
"`FakeRead` should have been removed after drop lowering phase");
}
}
StatementKind::SetDiscriminant { .. } => {
if self.body.phase <
MirPhase::Runtime(RuntimePhase::Initial) {
self.fail(location,
"`SetDiscriminant`is not allowed until deaggregation");
}
}
StatementKind::Retag(kind, _) => {
if #[allow(non_exhaustive_omitted_patterns)] match kind {
RetagKind::TwoPhase => true,
_ => false,
} {
self.fail(location,
::alloc::__export::must_use({
::alloc::fmt::format(format_args!("explicit `{0:?}` is forbidden",
kind))
}));
}
}
StatementKind::Coverage(kind) => {
if self.body.phase >=
MirPhase::Analysis(AnalysisPhase::PostCleanup) &&
let CoverageKind::BlockMarker { .. } |
CoverageKind::SpanMarker { .. } = kind {
self.fail(location,
::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{0:?} should have been removed after analysis",
kind))
}));
}
}
StatementKind::Assign(..) | StatementKind::StorageLive(_) |
StatementKind::StorageDead(_) | StatementKind::Intrinsic(_)
| StatementKind::ConstEvalCounter |
StatementKind::PlaceMention(..) |
StatementKind::BackwardIncompatibleDropHint { .. } |
StatementKind::Nop => {}
}
self.super_statement(statement, location);
}
fn visit_terminator(&mut self, terminator: &Terminator<'tcx>,
location: Location) {
match &terminator.kind {
TerminatorKind::Goto { target } => {
self.check_edge(location, *target, EdgeKind::Normal);
}
TerminatorKind::SwitchInt { targets, discr: _ } => {
for (_, target) in targets.iter() {
self.check_edge(location, target, EdgeKind::Normal);
}
self.check_edge(location, targets.otherwise(),
EdgeKind::Normal);
self.value_cache.clear();
self.value_cache.extend(targets.iter().map(|(value, _)|
value));
let has_duplicates =
targets.iter().len() != self.value_cache.len();
if has_duplicates {
self.fail(location,
::alloc::__export::must_use({
::alloc::fmt::format(format_args!("duplicated values in `SwitchInt` terminator: {0:?}",
terminator.kind))
}));
}
}
TerminatorKind::Drop { target, unwind, drop, .. } => {
self.check_edge(location, *target, EdgeKind::Normal);
self.check_unwind_edge(location, *unwind);
if let Some(drop) = drop {
self.check_edge(location, *drop, EdgeKind::Normal);
}
}
TerminatorKind::Call { func, args, .. } |
TerminatorKind::TailCall { func, args, .. } => {
if let TerminatorKind::Call { target, unwind, destination,
.. } = terminator.kind {
if let Some(target) = target {
self.check_edge(location, target, EdgeKind::Normal);
}
self.check_unwind_edge(location, unwind);
if self.body.phase >=
MirPhase::Runtime(RuntimePhase::Optimized) &&
self.is_critical_call_edge(target, unwind) {
self.fail(location,
::alloc::__export::must_use({
::alloc::fmt::format(format_args!("encountered critical edge in `Call` terminator {0:?}",
terminator.kind))
}));
}
if most_packed_projection(self.tcx, &self.body.local_decls,
destination).is_some() {
self.fail(location,
::alloc::__export::must_use({
::alloc::fmt::format(format_args!("encountered packed place in `Call` terminator destination: {0:?}",
terminator.kind))
}));
}
}
for arg in args {
if let Operand::Move(place) = &arg.node {
if most_packed_projection(self.tcx, &self.body.local_decls,
*place).is_some() {
self.fail(location,
::alloc::__export::must_use({
::alloc::fmt::format(format_args!("encountered `Move` of a packed place in `Call` terminator: {0:?}",
terminator.kind))
}));
}
}
}
if let ty::FnDef(did, ..) =
func.ty(&self.body.local_decls, self.tcx).kind() &&
self.body.phase >=
MirPhase::Runtime(RuntimePhase::Optimized) &&
#[allow(non_exhaustive_omitted_patterns)] match self.tcx.codegen_fn_attrs(did).inline
{
InlineAttr::Force { .. } => true,
_ => false,
} {
self.fail(location,
"`#[rustc_force_inline]`-annotated function not inlined");
}
}
TerminatorKind::Assert { target, unwind, .. } => {
self.check_edge(location, *target, EdgeKind::Normal);
self.check_unwind_edge(location, *unwind);
}
TerminatorKind::Yield { resume, drop, .. } => {
if self.body.coroutine.is_none() {
self.fail(location,
"`Yield` cannot appear outside coroutine bodies");
}
if self.body.phase >=
MirPhase::Runtime(RuntimePhase::Initial) {
self.fail(location,
"`Yield` should have been replaced by coroutine lowering");
}
self.check_edge(location, *resume, EdgeKind::Normal);
if let Some(drop) = drop {
self.check_edge(location, *drop, EdgeKind::Normal);
}
}
TerminatorKind::FalseEdge { real_target, imaginary_target } =>
{
if self.body.phase >=
MirPhase::Runtime(RuntimePhase::Initial) {
self.fail(location,
"`FalseEdge` should have been removed after drop elaboration");
}
self.check_edge(location, *real_target, EdgeKind::Normal);
self.check_edge(location, *imaginary_target,
EdgeKind::Normal);
}
TerminatorKind::FalseUnwind { real_target, unwind } => {
if self.body.phase >=
MirPhase::Runtime(RuntimePhase::Initial) {
self.fail(location,
"`FalseUnwind` should have been removed after drop elaboration");
}
self.check_edge(location, *real_target, EdgeKind::Normal);
self.check_unwind_edge(location, *unwind);
}
TerminatorKind::InlineAsm { targets, unwind, .. } => {
for &target in targets {
self.check_edge(location, target, EdgeKind::Normal);
}
self.check_unwind_edge(location, *unwind);
}
TerminatorKind::CoroutineDrop => {
if self.body.coroutine.is_none() {
self.fail(location,
"`CoroutineDrop` cannot appear outside coroutine bodies");
}
if self.body.phase >=
MirPhase::Runtime(RuntimePhase::Initial) {
self.fail(location,
"`CoroutineDrop` should have been replaced by coroutine lowering");
}
}
TerminatorKind::UnwindResume => {
let bb = location.block;
if !self.body.basic_blocks[bb].is_cleanup {
self.fail(location,
"Cannot `UnwindResume` from non-cleanup basic block")
}
if !self.can_unwind {
self.fail(location,
"Cannot `UnwindResume` in a function that cannot unwind")
}
}
TerminatorKind::UnwindTerminate(_) => {
let bb = location.block;
if !self.body.basic_blocks[bb].is_cleanup {
self.fail(location,
"Cannot `UnwindTerminate` from non-cleanup basic block")
}
}
TerminatorKind::Return => {
let bb = location.block;
if self.body.basic_blocks[bb].is_cleanup {
self.fail(location,
"Cannot `Return` from cleanup basic block")
}
}
TerminatorKind::Unreachable => {}
}
self.super_terminator(terminator, location);
}
fn visit_source_scope(&mut self, scope: SourceScope) {
if self.body.source_scopes.get(scope).is_none() {
self.tcx.dcx().span_bug(self.body.span,
::alloc::__export::must_use({
::alloc::fmt::format(format_args!("broken MIR in {0:?} ({1}):\ninvalid source scope {2:?}",
self.body.source.instance, self.when, scope))
}));
}
}
}
pub(super) fn validate_types<'tcx>(tcx: TyCtxt<'tcx>,
typing_env: ty::TypingEnv<'tcx>, body: &Body<'tcx>,
caller_body: &Body<'tcx>) -> Vec<(Location, String)> {
let mut type_checker =
TypeChecker {
body,
caller_body,
tcx,
typing_env,
failures: Vec::new(),
};
{
let _guard = NoTrimmedGuard::new();
{ type_checker.visit_body(body); }
};
type_checker.failures
}
struct TypeChecker<'a, 'tcx> {
body: &'a Body<'tcx>,
caller_body: &'a Body<'tcx>,
tcx: TyCtxt<'tcx>,
typing_env: ty::TypingEnv<'tcx>,
failures: Vec<(Location, String)>,
}
impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
fn fail(&mut self, location: Location, msg: impl Into<String>) {
self.failures.push((location, msg.into()));
}
fn mir_assign_valid_types(&self, src: Ty<'tcx>, dest: Ty<'tcx>)
-> bool {
if src == dest { return true; }
if (src, dest).has_opaque_types() { return true; }
let variance =
if self.body.phase >= MirPhase::Runtime(RuntimePhase::Initial)
{
Variance::Invariant
} else { Variance::Covariant };
crate::util::relate_types(self.tcx, self.typing_env, variance,
src, dest)
}
fn predicate_must_hold_modulo_regions(&self,
pred: impl Upcast<TyCtxt<'tcx>, ty::Predicate<'tcx>>) -> bool {
let pred: ty::Predicate<'tcx> = pred.upcast(self.tcx);
if pred.has_opaque_types() { return true; }
let (infcx, param_env) =
self.tcx.infer_ctxt().build_with_typing_env(self.typing_env);
let ocx = ObligationCtxt::new(&infcx);
ocx.register_obligation(Obligation::new(self.tcx,
ObligationCause::dummy(), param_env, pred));
ocx.evaluate_obligations_error_on_ambiguity().is_empty()
}
}
impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
fn visit_operand(&mut self, operand: &Operand<'tcx>,
location: Location) {
if self.tcx.sess.opts.unstable_opts.validate_mir &&
self.body.phase < MirPhase::Runtime(RuntimePhase::Initial) {
if let Operand::Copy(place) = operand {
let ty = place.ty(&self.body.local_decls, self.tcx).ty;
if !self.tcx.type_is_copy_modulo_regions(self.typing_env,
ty) {
self.fail(location,
::alloc::__export::must_use({
::alloc::fmt::format(format_args!("`Operand::Copy` with non-`Copy` type {0}",
ty))
}));
}
}
}
self.super_operand(operand, location);
}
fn visit_projection_elem(&mut self, place_ref: PlaceRef<'tcx>,
elem: PlaceElem<'tcx>, context: PlaceContext,
location: Location) {
match elem {
ProjectionElem::Deref if
self.body.phase >= MirPhase::Runtime(RuntimePhase::Initial)
=> {
let base_ty =
place_ref.ty(&self.body.local_decls, self.tcx).ty;
if base_ty.is_box() {
self.fail(location,
::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{0} dereferenced after ElaborateBoxDerefs",
base_ty))
}))
}
}
ProjectionElem::Field(f, ty) => {
let parent_ty =
place_ref.ty(&self.body.local_decls, self.tcx);
let fail_out_of_bounds =
|this: &mut Self, location|
{
this.fail(location,
::alloc::__export::must_use({
::alloc::fmt::format(format_args!("Out of bounds field {0:?} for {1:?}",
f, parent_ty))
}));
};
let check_equal =
|this: &mut Self, location, f_ty|
{
if !this.mir_assign_valid_types(ty, f_ty) {
this.fail(location,
::alloc::__export::must_use({
::alloc::fmt::format(format_args!("Field projection `{0:?}.{1:?}` specified type `{2}`, but actual type is `{3}`",
place_ref, f, ty, f_ty))
}))
}
};
let kind =
match parent_ty.ty.kind() {
&ty::Alias(ty::Opaque, ty::AliasTy { def_id, args, .. }) =>
{
self.tcx.type_of(def_id).instantiate(self.tcx, args).kind()
}
kind => kind,
};
match kind {
ty::Tuple(fields) => {
let Some(f_ty) =
fields.get(f.as_usize()) else {
fail_out_of_bounds(self, location);
return;
};
check_equal(self, location, *f_ty);
}
ty::Pat(base, _) => check_equal(self, location, *base),
ty::Adt(adt_def, args) => {
if self.tcx.is_lang_item(adt_def.did(),
LangItem::DynMetadata) {
self.fail(location,
::alloc::__export::must_use({
::alloc::fmt::format(format_args!("You can\'t project to field {0:?} of `DynMetadata` because layout is weird and thinks it doesn\'t have fields.",
f))
}));
}
if adt_def.repr().simd() {
self.fail(location,
::alloc::__export::must_use({
::alloc::fmt::format(format_args!("Projecting into SIMD type {0:?} is banned by MCP#838",
adt_def))
}));
}
let var = parent_ty.variant_index.unwrap_or(FIRST_VARIANT);
let Some(field) =
adt_def.variant(var).fields.get(f) else {
fail_out_of_bounds(self, location);
return;
};
check_equal(self, location, field.ty(self.tcx, args));
}
ty::Closure(_, args) => {
let args = args.as_closure();
let Some(&f_ty) =
args.upvar_tys().get(f.as_usize()) else {
fail_out_of_bounds(self, location);
return;
};
check_equal(self, location, f_ty);
}
ty::CoroutineClosure(_, args) => {
let args = args.as_coroutine_closure();
let Some(&f_ty) =
args.upvar_tys().get(f.as_usize()) else {
fail_out_of_bounds(self, location);
return;
};
check_equal(self, location, f_ty);
}
&ty::Coroutine(def_id, args) => {
let f_ty =
if let Some(var) = parent_ty.variant_index {
let layout =
if def_id == self.caller_body.source.def_id() {
self.caller_body.coroutine_layout_raw().or_else(||
self.tcx.coroutine_layout(def_id, args).ok())
} else if self.tcx.needs_coroutine_by_move_body_def_id(def_id)
&&
let ty::ClosureKind::FnOnce =
args.as_coroutine().kind_ty().to_opt_closure_kind().unwrap()
&&
self.caller_body.source.def_id() ==
self.tcx.coroutine_by_move_body_def_id(def_id) {
self.caller_body.coroutine_layout_raw()
} else { self.tcx.coroutine_layout(def_id, args).ok() };
let Some(layout) =
layout else {
self.fail(location,
::alloc::__export::must_use({
::alloc::fmt::format(format_args!("No coroutine layout for {0:?}",
parent_ty))
}));
return;
};
let Some(&local) =
layout.variant_fields[var].get(f) else {
fail_out_of_bounds(self, location);
return;
};
let Some(f_ty) =
layout.field_tys.get(local) else {
self.fail(location,
::alloc::__export::must_use({
::alloc::fmt::format(format_args!("Out of bounds local {0:?} for {1:?}",
local, parent_ty))
}));
return;
};
ty::EarlyBinder::bind(f_ty.ty).instantiate(self.tcx, args)
} else {
let Some(&f_ty) =
args.as_coroutine().prefix_tys().get(f.index()) else {
fail_out_of_bounds(self, location);
return;
};
f_ty
};
check_equal(self, location, f_ty);
}
_ => {
self.fail(location,
::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{0:?} does not have fields",
parent_ty.ty))
}));
}
}
}
ProjectionElem::Index(index) => {
let indexed_ty =
place_ref.ty(&self.body.local_decls, self.tcx).ty;
match indexed_ty.kind() {
ty::Array(_, _) | ty::Slice(_) => {}
_ =>
self.fail(location,
::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{0:?} cannot be indexed",
indexed_ty))
})),
}
let index_ty = self.body.local_decls[index].ty;
if index_ty != self.tcx.types.usize {
self.fail(location,
::alloc::__export::must_use({
::alloc::fmt::format(format_args!("bad index ({0} != usize)",
index_ty))
}))
}
}
ProjectionElem::ConstantIndex { offset, min_length, from_end }
=> {
let indexed_ty =
place_ref.ty(&self.body.local_decls, self.tcx).ty;
match indexed_ty.kind() {
ty::Array(_, _) => {
if from_end {
self.fail(location,
"arrays should not be indexed from end");
}
}
ty::Slice(_) => {}
_ =>
self.fail(location,
::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{0:?} cannot be indexed",
indexed_ty))
})),
}
if from_end {
if offset > min_length {
self.fail(location,
::alloc::__export::must_use({
::alloc::fmt::format(format_args!("constant index with offset -{0} out of bounds of min length {1}",
offset, min_length))
}));
}
} else {
if offset >= min_length {
self.fail(location,
::alloc::__export::must_use({
::alloc::fmt::format(format_args!("constant index with offset {0} out of bounds of min length {1}",
offset, min_length))
}));
}
}
}
ProjectionElem::Subslice { from, to, from_end } => {
let indexed_ty =
place_ref.ty(&self.body.local_decls, self.tcx).ty;
match indexed_ty.kind() {
ty::Array(_, _) => {
if from_end {
self.fail(location,
"arrays should not be subsliced from end");
}
}
ty::Slice(_) => {
if !from_end {
self.fail(location, "slices should be subsliced from end");
}
}
_ =>
self.fail(location,
::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{0:?} cannot be indexed",
indexed_ty))
})),
}
if !from_end && from > to {
self.fail(location, "backwards subslice {from}..{to}");
}
}
ProjectionElem::OpaqueCast(ty) if
self.body.phase >= MirPhase::Runtime(RuntimePhase::Initial)
=> {
self.fail(location,
::alloc::__export::must_use({
::alloc::fmt::format(format_args!("explicit opaque type cast to `{0}` after `PostAnalysisNormalize`",
ty))
}))
}
ProjectionElem::UnwrapUnsafeBinder(unwrapped_ty) => {
let binder_ty =
place_ref.ty(&self.body.local_decls, self.tcx);
let ty::UnsafeBinder(binder_ty) =
*binder_ty.ty.kind() else {
self.fail(location,
::alloc::__export::must_use({
::alloc::fmt::format(format_args!("WrapUnsafeBinder does not produce a ty::UnsafeBinder"))
}));
return;
};
let binder_inner_ty =
self.tcx.instantiate_bound_regions_with_erased(*binder_ty);
if !self.mir_assign_valid_types(unwrapped_ty,
binder_inner_ty) {
self.fail(location,
::alloc::__export::must_use({
::alloc::fmt::format(format_args!("Cannot unwrap unsafe binder {0:?} into type {1}",
binder_ty, unwrapped_ty))
}));
}
}
_ => {}
}
self.super_projection_elem(place_ref, elem, context, location);
}
fn visit_var_debug_info(&mut self, debuginfo: &VarDebugInfo<'tcx>) {
if let Some(box VarDebugInfoFragment { ty, ref projection }) =
debuginfo.composite {
if ty.is_union() || ty.is_enum() {
self.fail(START_BLOCK.start_location(),
::alloc::__export::must_use({
::alloc::fmt::format(format_args!("invalid type {1} in debuginfo for {0:?}",
debuginfo.name, ty))
}));
}
if projection.is_empty() {
self.fail(START_BLOCK.start_location(),
::alloc::__export::must_use({
::alloc::fmt::format(format_args!("invalid empty projection in debuginfo for {0:?}",
debuginfo.name))
}));
}
if projection.iter().any(|p|
!#[allow(non_exhaustive_omitted_patterns)] match p {
PlaceElem::Field(..) => true,
_ => false,
}) {
self.fail(START_BLOCK.start_location(),
::alloc::__export::must_use({
::alloc::fmt::format(format_args!("illegal projection {0:?} in debuginfo for {1:?}",
projection, debuginfo.name))
}));
}
}
match debuginfo.value {
VarDebugInfoContents::Const(_) => {}
VarDebugInfoContents::Place(place) => {
if place.projection.iter().any(|p|
!p.can_use_in_debuginfo()) {
self.fail(START_BLOCK.start_location(),
::alloc::__export::must_use({
::alloc::fmt::format(format_args!("illegal place {0:?} in debuginfo for {1:?}",
place, debuginfo.name))
}));
}
}
}
self.super_var_debug_info(debuginfo);
}
fn visit_place(&mut self, place: &Place<'tcx>, cntxt: PlaceContext,
location: Location) {
let _ = place.ty(&self.body.local_decls, self.tcx);
if self.body.phase >= MirPhase::Runtime(RuntimePhase::Initial) &&
place.projection.len() > 1 &&
cntxt != PlaceContext::NonUse(NonUseContext::VarDebugInfo)
&& place.projection[1..].contains(&ProjectionElem::Deref) {
self.fail(location,
::alloc::__export::must_use({
::alloc::fmt::format(format_args!("place {0:?} has deref as a later projection (it is only permitted as the first projection)",
place))
}));
}
let mut projections_iter = place.projection.iter();
while let Some(proj) = projections_iter.next() {
if #[allow(non_exhaustive_omitted_patterns)] match proj {
ProjectionElem::Downcast(..) => true,
_ => false,
} {
if !#[allow(non_exhaustive_omitted_patterns)] match projections_iter.next()
{
Some(ProjectionElem::Field(..)) => true,
_ => false,
} {
self.fail(location,
::alloc::__export::must_use({
::alloc::fmt::format(format_args!("place {0:?} has `Downcast` projection not followed by `Field`",
place))
}));
}
}
}
if let ClearCrossCrate::Set(box LocalInfo::DerefTemp) =
self.body.local_decls[place.local].local_info &&
!place.is_indirect_first_projection() {
if cntxt !=
PlaceContext::MutatingUse(MutatingUseContext::Store) ||
place.as_local().is_none() {
self.fail(location,
::alloc::__export::must_use({
::alloc::fmt::format(format_args!("`DerefTemp` locals must only be dereferenced or directly assigned to"))
}));
}
}
if self.body.phase < MirPhase::Runtime(RuntimePhase::Initial) &&
let Some(i) =
place.projection.iter().position(|elem|
#[allow(non_exhaustive_omitted_patterns)] match elem {
ProjectionElem::Subslice { .. } => true,
_ => false,
}) && let Some(tail) = place.projection.get(i + 1..) &&
tail.iter().any(|elem|
{
#[allow(non_exhaustive_omitted_patterns)]
match elem {
ProjectionElem::ConstantIndex { .. } |
ProjectionElem::Subslice { .. } => true,
_ => false,
}
}) {
self.fail(location,
::alloc::__export::must_use({
::alloc::fmt::format(format_args!("place {0:?} has `ConstantIndex` or `Subslice` after `Subslice`",
place))
}));
}
self.super_place(place, cntxt, location);
}
fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>,
location: Location) {
macro_rules! check_kinds {
($t:expr, $text:literal, $typat:pat) =>
{
if !matches!(($t).kind(), $typat)
{ self.fail(location, format!($text, $t)); }
};
}
match rvalue {
Rvalue::Use(_) => {}
Rvalue::CopyForDeref(_) => {
if self.body.phase >=
MirPhase::Runtime(RuntimePhase::Initial) {
self.fail(location,
"`CopyForDeref` should have been removed in runtime MIR");
}
}
Rvalue::Aggregate(kind, fields) =>
match **kind {
AggregateKind::Tuple => {}
AggregateKind::Array(dest) => {
for src in fields {
if !self.mir_assign_valid_types(src.ty(self.body, self.tcx),
dest) {
self.fail(location, "array field has the wrong type");
}
}
}
AggregateKind::Adt(def_id, idx, args, _, Some(field)) => {
let adt_def = self.tcx.adt_def(def_id);
if !adt_def.is_union() {
::core::panicking::panic("assertion failed: adt_def.is_union()")
};
match (&idx, &FIRST_VARIANT) {
(left_val, right_val) => {
if !(*left_val == *right_val) {
let kind = ::core::panicking::AssertKind::Eq;
::core::panicking::assert_failed(kind, &*left_val,
&*right_val, ::core::option::Option::None);
}
}
};
let dest_ty =
self.tcx.normalize_erasing_regions(self.typing_env,
adt_def.non_enum_variant().fields[field].ty(self.tcx,
args));
if let [field] = fields.raw.as_slice() {
let src_ty = field.ty(self.body, self.tcx);
if !self.mir_assign_valid_types(src_ty, dest_ty) {
self.fail(location, "union field has the wrong type");
}
} else {
self.fail(location,
"unions should have one initialized field");
}
}
AggregateKind::Adt(def_id, idx, args, _, None) => {
let adt_def = self.tcx.adt_def(def_id);
if !!adt_def.is_union() {
::core::panicking::panic("assertion failed: !adt_def.is_union()")
};
let variant = &adt_def.variants()[idx];
if variant.fields.len() != fields.len() {
self.fail(location,
::alloc::__export::must_use({
::alloc::fmt::format(format_args!("adt {2:?} has the wrong number of initialized fields, expected {0}, found {1}",
fields.len(), variant.fields.len(), def_id))
}));
}
for (src, dest) in std::iter::zip(fields, &variant.fields) {
let dest_ty =
self.tcx.normalize_erasing_regions(self.typing_env,
dest.ty(self.tcx, args));
if !self.mir_assign_valid_types(src.ty(self.body, self.tcx),
dest_ty) {
self.fail(location, "adt field has the wrong type");
}
}
}
AggregateKind::Closure(_, args) => {
let upvars = args.as_closure().upvar_tys();
if upvars.len() != fields.len() {
self.fail(location,
"closure has the wrong number of initialized fields");
}
for (src, dest) in std::iter::zip(fields, upvars) {
if !self.mir_assign_valid_types(src.ty(self.body, self.tcx),
dest) {
self.fail(location, "closure field has the wrong type");
}
}
}
AggregateKind::Coroutine(_, args) => {
let upvars = args.as_coroutine().upvar_tys();
if upvars.len() != fields.len() {
self.fail(location,
"coroutine has the wrong number of initialized fields");
}
for (src, dest) in std::iter::zip(fields, upvars) {
if !self.mir_assign_valid_types(src.ty(self.body, self.tcx),
dest) {
self.fail(location, "coroutine field has the wrong type");
}
}
}
AggregateKind::CoroutineClosure(_, args) => {
let upvars = args.as_coroutine_closure().upvar_tys();
if upvars.len() != fields.len() {
self.fail(location,
"coroutine-closure has the wrong number of initialized fields");
}
for (src, dest) in std::iter::zip(fields, upvars) {
if !self.mir_assign_valid_types(src.ty(self.body, self.tcx),
dest) {
self.fail(location,
"coroutine-closure field has the wrong type");
}
}
}
AggregateKind::RawPtr(pointee_ty, mutability) => {
if !#[allow(non_exhaustive_omitted_patterns)] match self.body.phase
{
MirPhase::Runtime(_) => true,
_ => false,
} {
self.fail(location, "RawPtr should be in runtime MIR only");
}
if let [data_ptr, metadata] = fields.raw.as_slice() {
let data_ptr_ty = data_ptr.ty(self.body, self.tcx);
let metadata_ty = metadata.ty(self.body, self.tcx);
if let ty::RawPtr(in_pointee, in_mut) = data_ptr_ty.kind() {
if *in_mut != mutability {
self.fail(location,
"input and output mutability must match");
}
if !in_pointee.is_sized(self.tcx, self.typing_env) {
self.fail(location, "input pointer must be thin");
}
} else {
self.fail(location,
"first operand to raw pointer aggregate must be a raw pointer");
}
if pointee_ty.is_slice() {
if !self.mir_assign_valid_types(metadata_ty,
self.tcx.types.usize) {
self.fail(location, "slice metadata must be usize");
}
} else if pointee_ty.is_sized(self.tcx, self.typing_env) {
if metadata_ty != self.tcx.types.unit {
self.fail(location,
"metadata for pointer-to-thin must be unit");
}
}
} else {
self.fail(location,
"raw pointer aggregate must have 2 fields");
}
}
},
Rvalue::Ref(_, BorrowKind::Fake(_), _) => {
if self.body.phase >=
MirPhase::Runtime(RuntimePhase::Initial) {
self.fail(location,
"`Assign` statement with a `Fake` borrow should have been removed in runtime MIR");
}
}
Rvalue::Ref(..) => {}
Rvalue::BinaryOp(op, vals) => {
use BinOp::*;
let a = vals.0.ty(&self.body.local_decls, self.tcx);
let b = vals.1.ty(&self.body.local_decls, self.tcx);
if crate::util::binop_right_homogeneous(*op) {
if let Eq | Lt | Le | Ne | Ge | Gt = op {
if !self.mir_assign_valid_types(a, b) {
self.fail(location,
::alloc::__export::must_use({
::alloc::fmt::format(format_args!("Cannot {0:?} compare incompatible types {1} and {2}",
op, a, b))
}));
}
} else if a != b {
self.fail(location,
::alloc::__export::must_use({
::alloc::fmt::format(format_args!("Cannot perform binary op {0:?} on unequal types {1} and {2}",
op, a, b))
}));
}
}
match op {
Offset => {
if !#[allow(non_exhaustive_omitted_patterns)] match (a).kind()
{
ty::RawPtr(..) => true,
_ => false,
} {
self.fail(location,
::alloc::__export::must_use({
::alloc::fmt::format(format_args!("Cannot offset non-pointer type {0:?}",
a))
}));
};
if b != self.tcx.types.isize && b != self.tcx.types.usize {
self.fail(location,
::alloc::__export::must_use({
::alloc::fmt::format(format_args!("Cannot offset by non-isize type {0}",
b))
}));
}
}
Eq | Lt | Le | Ne | Ge | Gt => {
for x in [a, b] {
if !#[allow(non_exhaustive_omitted_patterns)] match (x).kind()
{
ty::Bool | ty::Char | ty::Int(..) | ty::Uint(..) |
ty::Float(..) | ty::RawPtr(..) | ty::FnPtr(..) => true,
_ => false,
} {
self.fail(location,
::alloc::__export::must_use({
::alloc::fmt::format(format_args!("Cannot {1:?} compare type {0:?}",
x, op))
}));
}
}
}
Cmp => {
for x in [a, b] {
if !#[allow(non_exhaustive_omitted_patterns)] match (x).kind()
{
ty::Char | ty::Uint(..) | ty::Int(..) => true,
_ => false,
} {
self.fail(location,
::alloc::__export::must_use({
::alloc::fmt::format(format_args!("Cannot three-way compare non-integer type {0:?}",
x))
}));
}
}
}
AddUnchecked | AddWithOverflow | SubUnchecked |
SubWithOverflow | MulUnchecked | MulWithOverflow | Shl |
ShlUnchecked | Shr | ShrUnchecked => {
for x in [a, b] {
if !#[allow(non_exhaustive_omitted_patterns)] match (x).kind()
{
ty::Uint(..) | ty::Int(..) => true,
_ => false,
} {
self.fail(location,
::alloc::__export::must_use({
::alloc::fmt::format(format_args!("Cannot {1:?} non-integer type {0:?}",
x, op))
}));
}
}
}
BitAnd | BitOr | BitXor => {
for x in [a, b] {
if !#[allow(non_exhaustive_omitted_patterns)] match (x).kind()
{
ty::Uint(..) | ty::Int(..) | ty::Bool => true,
_ => false,
} {
self.fail(location,
::alloc::__export::must_use({
::alloc::fmt::format(format_args!("Cannot perform bitwise op {1:?} on type {0:?}",
x, op))
}));
}
}
}
Add | Sub | Mul | Div | Rem => {
for x in [a, b] {
if !#[allow(non_exhaustive_omitted_patterns)] match (x).kind()
{
ty::Uint(..) | ty::Int(..) | ty::Float(..) => true,
_ => false,
} {
self.fail(location,
::alloc::__export::must_use({
::alloc::fmt::format(format_args!("Cannot perform arithmetic {1:?} on type {0:?}",
x, op))
}));
}
}
}
}
}
Rvalue::UnaryOp(op, operand) => {
let a = operand.ty(&self.body.local_decls, self.tcx);
match op {
UnOp::Neg => {
if !#[allow(non_exhaustive_omitted_patterns)] match (a).kind()
{
ty::Int(..) | ty::Float(..) => true,
_ => false,
} {
self.fail(location,
::alloc::__export::must_use({
::alloc::fmt::format(format_args!("Cannot negate type {0:?}",
a))
}));
}
}
UnOp::Not => {
if !#[allow(non_exhaustive_omitted_patterns)] match (a).kind()
{
ty::Int(..) | ty::Uint(..) | ty::Bool => true,
_ => false,
} {
self.fail(location,
::alloc::__export::must_use({
::alloc::fmt::format(format_args!("Cannot binary not type {0:?}",
a))
}));
};
}
UnOp::PtrMetadata => {
if !#[allow(non_exhaustive_omitted_patterns)] match (a).kind()
{
ty::RawPtr(..) | ty::Ref(..) => true,
_ => false,
} {
self.fail(location,
::alloc::__export::must_use({
::alloc::fmt::format(format_args!("Cannot PtrMetadata non-pointer non-reference type {0:?}",
a))
}));
};
}
}
}
Rvalue::ShallowInitBox(operand, _) => {
if self.body.phase >=
MirPhase::Runtime(RuntimePhase::Initial) {
self.fail(location,
::alloc::__export::must_use({
::alloc::fmt::format(format_args!("ShallowInitBox after ElaborateBoxDerefs"))
}))
}
let a = operand.ty(&self.body.local_decls, self.tcx);
if !#[allow(non_exhaustive_omitted_patterns)] match (a).kind()
{
ty::RawPtr(..) => true,
_ => false,
} {
self.fail(location,
::alloc::__export::must_use({
::alloc::fmt::format(format_args!("Cannot shallow init type {0:?}",
a))
}));
};
}
Rvalue::Cast(kind, operand, target_type) => {
let op_ty = operand.ty(self.body, self.tcx);
match kind {
CastKind::PointerWithExposedProvenance |
CastKind::PointerExposeProvenance => {}
CastKind::PointerCoercion(PointerCoercion::ReifyFnPointer(_),
_) => {
if !#[allow(non_exhaustive_omitted_patterns)] match (op_ty).kind()
{
ty::FnDef(..) => true,
_ => false,
} {
self.fail(location,
::alloc::__export::must_use({
::alloc::fmt::format(format_args!("CastKind::{1:?} input must be a fn item, not {0:?}",
op_ty, kind))
}));
};
if !#[allow(non_exhaustive_omitted_patterns)] match (target_type).kind()
{
ty::FnPtr(..) => true,
_ => false,
} {
self.fail(location,
::alloc::__export::must_use({
::alloc::fmt::format(format_args!("CastKind::{1:?} output must be a fn pointer, not {0:?}",
target_type, kind))
}));
};
}
CastKind::PointerCoercion(PointerCoercion::UnsafeFnPointer,
_) => {
if !#[allow(non_exhaustive_omitted_patterns)] match (op_ty).kind()
{
ty::FnPtr(..) => true,
_ => false,
} {
self.fail(location,
::alloc::__export::must_use({
::alloc::fmt::format(format_args!("CastKind::{1:?} input must be a fn pointer, not {0:?}",
op_ty, kind))
}));
};
if !#[allow(non_exhaustive_omitted_patterns)] match (target_type).kind()
{
ty::FnPtr(..) => true,
_ => false,
} {
self.fail(location,
::alloc::__export::must_use({
::alloc::fmt::format(format_args!("CastKind::{1:?} output must be a fn pointer, not {0:?}",
target_type, kind))
}));
};
}
CastKind::PointerCoercion(PointerCoercion::ClosureFnPointer(..),
_) => {
if !#[allow(non_exhaustive_omitted_patterns)] match (op_ty).kind()
{
ty::Closure(..) => true,
_ => false,
} {
self.fail(location,
::alloc::__export::must_use({
::alloc::fmt::format(format_args!("CastKind::{1:?} input must be a closure, not {0:?}",
op_ty, kind))
}));
};
if !#[allow(non_exhaustive_omitted_patterns)] match (target_type).kind()
{
ty::FnPtr(..) => true,
_ => false,
} {
self.fail(location,
::alloc::__export::must_use({
::alloc::fmt::format(format_args!("CastKind::{1:?} output must be a fn pointer, not {0:?}",
target_type, kind))
}));
};
}
CastKind::PointerCoercion(PointerCoercion::MutToConstPointer,
_) => {
if !#[allow(non_exhaustive_omitted_patterns)] match (op_ty).kind()
{
ty::RawPtr(_, Mutability::Mut) => true,
_ => false,
} {
self.fail(location,
::alloc::__export::must_use({
::alloc::fmt::format(format_args!("CastKind::{1:?} input must be a raw mut pointer, not {0:?}",
op_ty, kind))
}));
};
if !#[allow(non_exhaustive_omitted_patterns)] match (target_type).kind()
{
ty::RawPtr(_, Mutability::Not) => true,
_ => false,
} {
self.fail(location,
::alloc::__export::must_use({
::alloc::fmt::format(format_args!("CastKind::{1:?} output must be a raw const pointer, not {0:?}",
target_type, kind))
}));
};
if self.body.phase >=
MirPhase::Analysis(AnalysisPhase::PostCleanup) {
self.fail(location,
::alloc::__export::must_use({
::alloc::fmt::format(format_args!("After borrowck, MIR disallows {0:?}",
kind))
}));
}
}
CastKind::PointerCoercion(PointerCoercion::ArrayToPointer,
_) => {
if !#[allow(non_exhaustive_omitted_patterns)] match (op_ty).kind()
{
ty::RawPtr(..) => true,
_ => false,
} {
self.fail(location,
::alloc::__export::must_use({
::alloc::fmt::format(format_args!("CastKind::{1:?} input must be a raw pointer, not {0:?}",
op_ty, kind))
}));
};
if !#[allow(non_exhaustive_omitted_patterns)] match (target_type).kind()
{
ty::RawPtr(..) => true,
_ => false,
} {
self.fail(location,
::alloc::__export::must_use({
::alloc::fmt::format(format_args!("CastKind::{1:?} output must be a raw pointer, not {0:?}",
target_type, kind))
}));
};
if self.body.phase >=
MirPhase::Analysis(AnalysisPhase::PostCleanup) {
self.fail(location,
::alloc::__export::must_use({
::alloc::fmt::format(format_args!("After borrowck, MIR disallows {0:?}",
kind))
}));
}
}
CastKind::PointerCoercion(PointerCoercion::Unsize, _) => {
if !self.predicate_must_hold_modulo_regions(ty::TraitRef::new(self.tcx,
self.tcx.require_lang_item(LangItem::CoerceUnsized,
self.body.source_info(location).span),
[op_ty, *target_type])) {
self.fail(location,
::alloc::__export::must_use({
::alloc::fmt::format(format_args!("Unsize coercion, but `{0}` isn\'t coercible to `{1}`",
op_ty, target_type))
}));
}
}
CastKind::IntToInt | CastKind::IntToFloat => {
let input_valid =
op_ty.is_integral() || op_ty.is_char() || op_ty.is_bool();
let target_valid =
target_type.is_numeric() || target_type.is_char();
if !input_valid || !target_valid {
self.fail(location,
::alloc::__export::must_use({
::alloc::fmt::format(format_args!("Wrong cast kind {0:?} for the type {1}",
kind, op_ty))
}));
}
}
CastKind::FnPtrToPtr => {
if !#[allow(non_exhaustive_omitted_patterns)] match (op_ty).kind()
{
ty::FnPtr(..) => true,
_ => false,
} {
self.fail(location,
::alloc::__export::must_use({
::alloc::fmt::format(format_args!("CastKind::{1:?} input must be a fn pointer, not {0:?}",
op_ty, kind))
}));
};
if !#[allow(non_exhaustive_omitted_patterns)] match (target_type).kind()
{
ty::RawPtr(..) => true,
_ => false,
} {
self.fail(location,
::alloc::__export::must_use({
::alloc::fmt::format(format_args!("CastKind::{1:?} output must be a raw pointer, not {0:?}",
target_type, kind))
}));
};
}
CastKind::PtrToPtr => {
if !#[allow(non_exhaustive_omitted_patterns)] match (op_ty).kind()
{
ty::RawPtr(..) => true,
_ => false,
} {
self.fail(location,
::alloc::__export::must_use({
::alloc::fmt::format(format_args!("CastKind::{1:?} input must be a raw pointer, not {0:?}",
op_ty, kind))
}));
};
if !#[allow(non_exhaustive_omitted_patterns)] match (target_type).kind()
{
ty::RawPtr(..) => true,
_ => false,
} {
self.fail(location,
::alloc::__export::must_use({
::alloc::fmt::format(format_args!("CastKind::{1:?} output must be a raw pointer, not {0:?}",
target_type, kind))
}));
};
}
CastKind::FloatToFloat | CastKind::FloatToInt => {
if !op_ty.is_floating_point() || !target_type.is_numeric() {
self.fail(location,
::alloc::__export::must_use({
::alloc::fmt::format(format_args!("Trying to cast non \'Float\' as {0:?} into {1:?}",
kind, target_type))
}));
}
}
CastKind::Transmute => {
if !self.tcx.normalize_erasing_regions(self.typing_env,
op_ty).is_sized(self.tcx, self.typing_env) {
self.fail(location,
::alloc::__export::must_use({
::alloc::fmt::format(format_args!("Cannot transmute from non-`Sized` type {0}",
op_ty))
}));
}
if !self.tcx.normalize_erasing_regions(self.typing_env,
*target_type).is_sized(self.tcx, self.typing_env) {
self.fail(location,
::alloc::__export::must_use({
::alloc::fmt::format(format_args!("Cannot transmute to non-`Sized` type {0:?}",
target_type))
}));
}
}
CastKind::Subtype => {
if !util::sub_types(self.tcx, self.typing_env, op_ty,
*target_type) {
self.fail(location,
::alloc::__export::must_use({
::alloc::fmt::format(format_args!("Failed subtyping {0} and {1}",
op_ty, target_type))
}))
}
}
}
}
Rvalue::Repeat(_, _) | Rvalue::ThreadLocalRef(_) |
Rvalue::RawPtr(_, _) | Rvalue::Discriminant(_) => {}
Rvalue::WrapUnsafeBinder(op, ty) => {
let unwrapped_ty = op.ty(self.body, self.tcx);
let ty::UnsafeBinder(binder_ty) =
*ty.kind() else {
self.fail(location,
::alloc::__export::must_use({
::alloc::fmt::format(format_args!("WrapUnsafeBinder does not produce a ty::UnsafeBinder"))
}));
return;
};
let binder_inner_ty =
self.tcx.instantiate_bound_regions_with_erased(*binder_ty);
if !self.mir_assign_valid_types(unwrapped_ty,
binder_inner_ty) {
self.fail(location,
::alloc::__export::must_use({
::alloc::fmt::format(format_args!("Cannot wrap {0} into unsafe binder {1:?}",
unwrapped_ty, binder_ty))
}));
}
}
}
self.super_rvalue(rvalue, location);
}
fn visit_statement(&mut self, statement: &Statement<'tcx>,
location: Location) {
match &statement.kind {
StatementKind::Assign(box (dest, rvalue)) => {
let left_ty = dest.ty(&self.body.local_decls, self.tcx).ty;
let right_ty = rvalue.ty(&self.body.local_decls, self.tcx);
if !self.mir_assign_valid_types(right_ty, left_ty) {
self.fail(location,
::alloc::__export::must_use({
::alloc::fmt::format(format_args!("encountered `{0:?}` with incompatible types:\nleft-hand side has type: {1}\nright-hand side has type: {2}",
statement.kind, left_ty, right_ty))
}));
}
if let Some(local) = dest.as_local() &&
let ClearCrossCrate::Set(box LocalInfo::DerefTemp) =
self.body.local_decls[local].local_info &&
!#[allow(non_exhaustive_omitted_patterns)] match rvalue {
Rvalue::CopyForDeref(_) => true,
_ => false,
} {
self.fail(location,
"assignment to a `DerefTemp` must use `CopyForDeref`")
}
}
StatementKind::AscribeUserType(..) => {
if self.body.phase >=
MirPhase::Runtime(RuntimePhase::Initial) {
self.fail(location,
"`AscribeUserType` should have been removed after drop lowering phase");
}
}
StatementKind::FakeRead(..) => {
if self.body.phase >=
MirPhase::Runtime(RuntimePhase::Initial) {
self.fail(location,
"`FakeRead` should have been removed after drop lowering phase");
}
}
StatementKind::Intrinsic(box NonDivergingIntrinsic::Assume(op))
=> {
let ty = op.ty(&self.body.local_decls, self.tcx);
if !ty.is_bool() {
self.fail(location,
::alloc::__export::must_use({
::alloc::fmt::format(format_args!("`assume` argument must be `bool`, but got: `{0}`",
ty))
}));
}
}
StatementKind::Intrinsic(box NonDivergingIntrinsic::CopyNonOverlapping(CopyNonOverlapping {
src, dst, count })) => {
let src_ty = src.ty(&self.body.local_decls, self.tcx);
let op_src_ty =
if let Some(src_deref) = src_ty.builtin_deref(true) {
src_deref
} else {
self.fail(location,
::alloc::__export::must_use({
::alloc::fmt::format(format_args!("Expected src to be ptr in copy_nonoverlapping, got: {0}",
src_ty))
}));
return;
};
let dst_ty = dst.ty(&self.body.local_decls, self.tcx);
let op_dst_ty =
if let Some(dst_deref) = dst_ty.builtin_deref(true) {
dst_deref
} else {
self.fail(location,
::alloc::__export::must_use({
::alloc::fmt::format(format_args!("Expected dst to be ptr in copy_nonoverlapping, got: {0}",
dst_ty))
}));
return;
};
if !self.mir_assign_valid_types(op_src_ty, op_dst_ty) {
self.fail(location,
::alloc::__export::must_use({
::alloc::fmt::format(format_args!("bad arg ({0} != {1})",
op_src_ty, op_dst_ty))
}));
}
let op_cnt_ty = count.ty(&self.body.local_decls, self.tcx);
if op_cnt_ty != self.tcx.types.usize {
self.fail(location,
::alloc::__export::must_use({
::alloc::fmt::format(format_args!("bad arg ({0} != usize)",
op_cnt_ty))
}))
}
}
StatementKind::SetDiscriminant { place, .. } => {
if self.body.phase <
MirPhase::Runtime(RuntimePhase::Initial) {
self.fail(location,
"`SetDiscriminant`is not allowed until deaggregation");
}
let pty = place.ty(&self.body.local_decls, self.tcx).ty;
if !#[allow(non_exhaustive_omitted_patterns)] match pty.kind()
{
ty::Adt(..) | ty::Coroutine(..) | ty::Alias(ty::Opaque, ..)
=> true,
_ => false,
} {
self.fail(location,
::alloc::__export::must_use({
::alloc::fmt::format(format_args!("`SetDiscriminant` is only allowed on ADTs and coroutines, not {0}",
pty))
}));
}
}
StatementKind::Retag(kind, _) => {
if #[allow(non_exhaustive_omitted_patterns)] match kind {
RetagKind::TwoPhase => true,
_ => false,
} {
self.fail(location,
::alloc::__export::must_use({
::alloc::fmt::format(format_args!("explicit `{0:?}` is forbidden",
kind))
}));
}
}
StatementKind::StorageLive(_) | StatementKind::StorageDead(_)
| StatementKind::Coverage(_) |
StatementKind::ConstEvalCounter |
StatementKind::PlaceMention(..) |
StatementKind::BackwardIncompatibleDropHint { .. } |
StatementKind::Nop => {}
}
self.super_statement(statement, location);
}
fn visit_terminator(&mut self, terminator: &Terminator<'tcx>,
location: Location) {
match &terminator.kind {
TerminatorKind::SwitchInt { targets, discr } => {
let switch_ty = discr.ty(&self.body.local_decls, self.tcx);
let target_width = self.tcx.sess.target.pointer_width;
let size =
Size::from_bits(match switch_ty.kind() {
ty::Uint(uint) =>
uint.normalize(target_width).bit_width().unwrap(),
ty::Int(int) =>
int.normalize(target_width).bit_width().unwrap(),
ty::Char => 32,
ty::Bool => 1,
other =>
::rustc_middle::util::bug::bug_fmt(format_args!("unhandled type: {0:?}",
other)),
});
for (value, _) in targets.iter() {
if ScalarInt::try_from_uint(value, size).is_none() {
self.fail(location,
::alloc::__export::must_use({
::alloc::fmt::format(format_args!("the value {0:#x} is not a proper {1}",
value, switch_ty))
}))
}
}
}
TerminatorKind::Call { func, .. } | TerminatorKind::TailCall {
func, .. } => {
let func_ty = func.ty(&self.body.local_decls, self.tcx);
match func_ty.kind() {
ty::FnPtr(..) | ty::FnDef(..) => {}
_ =>
self.fail(location,
::alloc::__export::must_use({
::alloc::fmt::format(format_args!("encountered non-callable type {1} in `{0}` terminator",
terminator.kind.name(), func_ty))
})),
}
if let TerminatorKind::TailCall { .. } = terminator.kind {}
}
TerminatorKind::Assert { cond, .. } => {
let cond_ty = cond.ty(&self.body.local_decls, self.tcx);
if cond_ty != self.tcx.types.bool {
self.fail(location,
::alloc::__export::must_use({
::alloc::fmt::format(format_args!("encountered non-boolean condition of type {0} in `Assert` terminator",
cond_ty))
}));
}
}
TerminatorKind::Goto { .. } | TerminatorKind::Drop { .. } |
TerminatorKind::Yield { .. } | TerminatorKind::FalseEdge {
.. } | TerminatorKind::FalseUnwind { .. } |
TerminatorKind::InlineAsm { .. } |
TerminatorKind::CoroutineDrop | TerminatorKind::UnwindResume
| TerminatorKind::UnwindTerminate(_) |
TerminatorKind::Return | TerminatorKind::Unreachable => {}
}
self.super_terminator(terminator, location);
}
fn visit_local_decl(&mut self, local: Local,
local_decl: &LocalDecl<'tcx>) {
if let ClearCrossCrate::Set(box LocalInfo::DerefTemp) =
local_decl.local_info {
if self.body.phase >= MirPhase::Runtime(RuntimePhase::Initial)
{
self.fail(START_BLOCK.start_location(),
"`DerefTemp` should have been removed in runtime MIR");
} else if local_decl.ty.builtin_deref(true).is_none() {
self.fail(START_BLOCK.start_location(),
"`DerefTemp` should only be used for dereferenceable types")
}
}
self.super_local_decl(local, local_decl);
}
}
pub(super) fn validate_debuginfos<'tcx>(body: &Body<'tcx>)
-> Vec<(Location, String)> {
let mut debuginfo_checker =
DebuginfoChecker {
debuginfo_locals: debuginfo_locals(body),
failures: Vec::new(),
};
debuginfo_checker.visit_body(body);
debuginfo_checker.failures
}
struct DebuginfoChecker {
debuginfo_locals: DenseBitSet<Local>,
failures: Vec<(Location, String)>,
}
impl<'tcx> Visitor<'tcx> for DebuginfoChecker {
fn visit_statement_debuginfo(&mut self,
stmt_debuginfo: &StmtDebugInfo<'tcx>, location: Location) {
let local =
match stmt_debuginfo {
StmtDebugInfo::AssignRef(local, _) |
StmtDebugInfo::InvalidAssign(local) => *local,
};
if !self.debuginfo_locals.contains(local) {
self.failures.push((location,
::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{0:?} is not in debuginfo",
local))
})));
}
}
}
}
#[allow(unused_imports)]
use validate::Validator as _;
static PASS_NAMES: LazyLock<FxIndexSet<&str>> =
LazyLock::new(||
["PreCodegen", "AbortUnwindingCalls", "AddCallGuards",
add_call_guards::AddCallGuards::AllCallEdges.name(),
add_call_guards::AddCallGuards::CriticalCallEdges.name(),
"AddMovesForPackedDrops", "AddRetag", "Subtyper",
"CheckForceInline", "CheckCallRecursion",
"CheckDropRecursion", "CheckInlineAlwaysTargetFeature",
"CheckAlignment", "CheckEnums", "CheckConstItemMutation",
"CheckNull", "CheckPackedRef", "CleanupPostBorrowck",
"CopyProp", "StateTransform", "InstrumentCoverage",
"CtfeLimit", "DataflowConstProp", "DeadStoreElimination",
dead_store_elimination::DeadStoreElimination::Initial.name(),
dead_store_elimination::DeadStoreElimination::Final.name(),
"Derefer", "DestinationPropagation", "Marker",
"EarlyOtherwiseBranch", "EraseDerefTemps",
"ElaborateBoxDerefs", "ElaborateDrops",
"FunctionItemReferences", "GVN", "Inline", "ForceInline",
"ImpossiblePredicates", "InstSimplify",
instsimplify::InstSimplify::BeforeInline.name(),
instsimplify::InstSimplify::AfterSimplifyCfg.name(),
"JumpThreading", "KnownPanicsLint", "EnumSizeOpt",
"LowerIntrinsics", "LowerSliceLenCalls",
"MatchBranchSimplification", "MentionedItems",
"MultipleReturnTerminators", "CheckLiveDrops",
"ReorderBasicBlocks", "ReorderLocals", "PromoteTemps",
"ReferencePropagation", "RemoveNoopLandingPads",
"RemovePlaceMention", "RemoveStorageMarkers",
"RemoveUninitDrops", "RemoveUnneededDrops", "RemoveZsts",
"RequiredConstsVisitor", "PostAnalysisNormalize",
"SanityCheck", "SimplifyCfg",
simplify::SimplifyCfg::Initial.name(),
simplify::SimplifyCfg::PromoteConsts.name(),
simplify::SimplifyCfg::RemoveFalseEdges.name(),
simplify::SimplifyCfg::PostAnalysis.name(),
simplify::SimplifyCfg::PreOptimizations.name(),
simplify::SimplifyCfg::Final.name(),
simplify::SimplifyCfg::MakeShim.name(),
simplify::SimplifyCfg::AfterUnreachableEnumBranching.name(),
"SimplifyLocals",
simplify::SimplifyLocals::BeforeConstProp.name(),
simplify::SimplifyLocals::AfterGVN.name(),
simplify::SimplifyLocals::Final.name(),
"SimplifyConstCondition",
simplify_branches::SimplifyConstCondition::AfterInstSimplify.name(),
simplify_branches::SimplifyConstCondition::AfterConstProp.name(),
simplify_branches::SimplifyConstCondition::Final.name(),
"SimplifyComparisonIntegral", "SingleUseConsts",
"ScalarReplacementOfAggregates", "StripDebugInfo",
"UnreachableEnumBranching", "UnreachablePropagation",
"Validator"].into_iter().collect());declare_passes! {
114 mod abort_unwinding_calls : AbortUnwindingCalls;
115 mod add_call_guards : AddCallGuards { AllCallEdges, CriticalCallEdges };
116 mod add_moves_for_packed_drops : AddMovesForPackedDrops;
117 mod add_retag : AddRetag;
118 mod add_subtyping_projections : Subtyper;
119 mod check_inline : CheckForceInline;
120 mod check_call_recursion : CheckCallRecursion, CheckDropRecursion;
121 mod check_inline_always_target_features: CheckInlineAlwaysTargetFeature;
122 mod check_alignment : CheckAlignment;
123 mod check_enums : CheckEnums;
124 mod check_const_item_mutation : CheckConstItemMutation;
125 mod check_null : CheckNull;
126 mod check_packed_ref : CheckPackedRef;
127 pub mod cleanup_post_borrowck : CleanupPostBorrowck;
129
130 mod copy_prop : CopyProp;
131 mod coroutine : StateTransform;
132 mod coverage : InstrumentCoverage;
133 mod ctfe_limit : CtfeLimit;
134 mod dataflow_const_prop : DataflowConstProp;
135 mod dead_store_elimination : DeadStoreElimination {
136 Initial,
137 Final
138 };
139 mod deref_separator : Derefer;
140 mod dest_prop : DestinationPropagation;
141 pub mod dump_mir : Marker;
142 mod early_otherwise_branch : EarlyOtherwiseBranch;
143 mod erase_deref_temps : EraseDerefTemps;
144 mod elaborate_box_derefs : ElaborateBoxDerefs;
145 mod elaborate_drops : ElaborateDrops;
146 mod function_item_references : FunctionItemReferences;
147 mod gvn : GVN;
148 pub mod inline : Inline, ForceInline;
151 mod impossible_predicates : ImpossiblePredicates;
152 mod instsimplify : InstSimplify { BeforeInline, AfterSimplifyCfg };
153 mod jump_threading : JumpThreading;
154 mod known_panics_lint : KnownPanicsLint;
155 mod large_enums : EnumSizeOpt;
156 mod lower_intrinsics : LowerIntrinsics;
157 mod lower_slice_len : LowerSliceLenCalls;
158 mod match_branches : MatchBranchSimplification;
159 mod mentioned_items : MentionedItems;
160 mod multiple_return_terminators : MultipleReturnTerminators;
161 mod post_drop_elaboration : CheckLiveDrops;
162 mod prettify : ReorderBasicBlocks, ReorderLocals;
163 mod promote_consts : PromoteTemps;
164 mod ref_prop : ReferencePropagation;
165 mod remove_noop_landing_pads : RemoveNoopLandingPads;
166 mod remove_place_mention : RemovePlaceMention;
167 mod remove_storage_markers : RemoveStorageMarkers;
168 mod remove_uninit_drops : RemoveUninitDrops;
169 mod remove_unneeded_drops : RemoveUnneededDrops;
170 mod remove_zsts : RemoveZsts;
171 mod required_consts : RequiredConstsVisitor;
172 mod post_analysis_normalize : PostAnalysisNormalize;
173 mod sanity_check : SanityCheck;
174 pub mod simplify :
176 SimplifyCfg {
177 Initial,
178 PromoteConsts,
179 RemoveFalseEdges,
180 PostAnalysis,
181 PreOptimizations,
182 Final,
183 MakeShim,
184 AfterUnreachableEnumBranching
185 },
186 SimplifyLocals {
187 BeforeConstProp,
188 AfterGVN,
189 Final
190 };
191 mod simplify_branches : SimplifyConstCondition {
192 AfterInstSimplify,
193 AfterConstProp,
194 Final
195 };
196 mod simplify_comparison_integral : SimplifyComparisonIntegral;
197 mod single_use_consts : SingleUseConsts;
198 mod sroa : ScalarReplacementOfAggregates;
199 mod strip_debuginfo : StripDebugInfo;
200 mod unreachable_enum_branching : UnreachableEnumBranching;
201 mod unreachable_prop : UnreachablePropagation;
202 mod validate : Validator;
203}
204
205#[allow(non_upper_case_globals)]
#[doc(hidden)]
#[doc =
r" Auto-generated constants for type-checked references to Fluent messages."]
pub(crate) mod fluent_generated {
#[doc =
"Constant referring to Fluent message `mir_transform_arithmetic_overflow` from `mir_transform`"]
pub const mir_transform_arithmetic_overflow: rustc_errors::DiagMessage =
rustc_errors::DiagMessage::FluentIdentifier(std::borrow::Cow::Borrowed("mir_transform_arithmetic_overflow"),
None);
#[doc =
"Constant referring to Fluent message `mir_transform_asm_unwind_call` from `mir_transform`"]
pub const mir_transform_asm_unwind_call: rustc_errors::DiagMessage =
rustc_errors::DiagMessage::FluentIdentifier(std::borrow::Cow::Borrowed("mir_transform_asm_unwind_call"),
None);
#[doc =
"Constant referring to Fluent message `mir_transform_const_defined_here` from `mir_transform`"]
pub const mir_transform_const_defined_here: rustc_errors::DiagMessage =
rustc_errors::DiagMessage::FluentIdentifier(std::borrow::Cow::Borrowed("mir_transform_const_defined_here"),
None);
#[doc =
"Constant referring to Fluent message `mir_transform_const_modify` from `mir_transform`"]
pub const mir_transform_const_modify: rustc_errors::DiagMessage =
rustc_errors::DiagMessage::FluentIdentifier(std::borrow::Cow::Borrowed("mir_transform_const_modify"),
None);
#[doc =
"Constant referring to Fluent message `mir_transform_const_modify.note` from `mir_transform`"]
pub const mir_transform_note: rustc_errors::SubdiagMessage =
rustc_errors::SubdiagMessage::FluentAttr(std::borrow::Cow::Borrowed("note"));
#[doc =
"Constant referring to Fluent message `mir_transform_const_mut_borrow` from `mir_transform`"]
pub const mir_transform_const_mut_borrow: rustc_errors::DiagMessage =
rustc_errors::DiagMessage::FluentIdentifier(std::borrow::Cow::Borrowed("mir_transform_const_mut_borrow"),
None);
#[doc =
"Constant referring to Fluent message `mir_transform_const_mut_borrow.note2` from `mir_transform`"]
pub const mir_transform_note2: rustc_errors::SubdiagMessage =
rustc_errors::SubdiagMessage::FluentAttr(std::borrow::Cow::Borrowed("note2"));
#[doc =
"Constant referring to Fluent message `mir_transform_const_mut_borrow.note3` from `mir_transform`"]
pub const mir_transform_note3: rustc_errors::SubdiagMessage =
rustc_errors::SubdiagMessage::FluentAttr(std::borrow::Cow::Borrowed("note3"));
#[doc =
"Constant referring to Fluent message `mir_transform_ffi_unwind_call` from `mir_transform`"]
pub const mir_transform_ffi_unwind_call: rustc_errors::DiagMessage =
rustc_errors::DiagMessage::FluentIdentifier(std::borrow::Cow::Borrowed("mir_transform_ffi_unwind_call"),
None);
#[doc =
"Constant referring to Fluent message `mir_transform_fn_item_ref` from `mir_transform`"]
pub const mir_transform_fn_item_ref: rustc_errors::DiagMessage =
rustc_errors::DiagMessage::FluentIdentifier(std::borrow::Cow::Borrowed("mir_transform_fn_item_ref"),
None);
#[doc =
"Constant referring to Fluent message `mir_transform_fn_item_ref.suggestion` from `mir_transform`"]
pub const mir_transform_suggestion: rustc_errors::SubdiagMessage =
rustc_errors::SubdiagMessage::FluentAttr(std::borrow::Cow::Borrowed("suggestion"));
#[doc =
"Constant referring to Fluent message `mir_transform_force_inline` from `mir_transform`"]
pub const mir_transform_force_inline: rustc_errors::DiagMessage =
rustc_errors::DiagMessage::FluentIdentifier(std::borrow::Cow::Borrowed("mir_transform_force_inline"),
None);
#[doc =
"Constant referring to Fluent message `mir_transform_force_inline.call` from `mir_transform`"]
pub const mir_transform_call: rustc_errors::SubdiagMessage =
rustc_errors::SubdiagMessage::FluentAttr(std::borrow::Cow::Borrowed("call"));
#[doc =
"Constant referring to Fluent message `mir_transform_force_inline.attr` from `mir_transform`"]
pub const mir_transform_attr: rustc_errors::SubdiagMessage =
rustc_errors::SubdiagMessage::FluentAttr(std::borrow::Cow::Borrowed("attr"));
#[doc =
"Constant referring to Fluent message `mir_transform_force_inline.caller` from `mir_transform`"]
pub const mir_transform_caller: rustc_errors::SubdiagMessage =
rustc_errors::SubdiagMessage::FluentAttr(std::borrow::Cow::Borrowed("caller"));
#[doc =
"Constant referring to Fluent message `mir_transform_force_inline.callee` from `mir_transform`"]
pub const mir_transform_callee: rustc_errors::SubdiagMessage =
rustc_errors::SubdiagMessage::FluentAttr(std::borrow::Cow::Borrowed("callee"));
#[doc =
"Constant referring to Fluent message `mir_transform_force_inline_attr` from `mir_transform`"]
pub const mir_transform_force_inline_attr: rustc_errors::DiagMessage =
rustc_errors::DiagMessage::FluentIdentifier(std::borrow::Cow::Borrowed("mir_transform_force_inline_attr"),
None);
#[doc =
"Constant referring to Fluent message `mir_transform_force_inline_justification` from `mir_transform`"]
pub const mir_transform_force_inline_justification:
rustc_errors::DiagMessage =
rustc_errors::DiagMessage::FluentIdentifier(std::borrow::Cow::Borrowed("mir_transform_force_inline_justification"),
None);
#[doc =
"Constant referring to Fluent message `mir_transform_maybe_string_interpolation` from `mir_transform`"]
pub const mir_transform_maybe_string_interpolation:
rustc_errors::DiagMessage =
rustc_errors::DiagMessage::FluentIdentifier(std::borrow::Cow::Borrowed("mir_transform_maybe_string_interpolation"),
None);
#[doc =
"Constant referring to Fluent message `mir_transform_must_not_suspend` from `mir_transform`"]
pub const mir_transform_must_not_suspend: rustc_errors::DiagMessage =
rustc_errors::DiagMessage::FluentIdentifier(std::borrow::Cow::Borrowed("mir_transform_must_not_suspend"),
None);
#[doc =
"Constant referring to Fluent message `mir_transform_must_not_suspend.label` from `mir_transform`"]
pub const mir_transform_label: rustc_errors::SubdiagMessage =
rustc_errors::SubdiagMessage::FluentAttr(std::borrow::Cow::Borrowed("label"));
#[doc =
"Constant referring to Fluent message `mir_transform_must_not_suspend.help` from `mir_transform`"]
pub const mir_transform_help: rustc_errors::SubdiagMessage =
rustc_errors::SubdiagMessage::FluentAttr(std::borrow::Cow::Borrowed("help"));
#[doc =
"Constant referring to Fluent message `mir_transform_operation_will_panic` from `mir_transform`"]
pub const mir_transform_operation_will_panic: rustc_errors::DiagMessage =
rustc_errors::DiagMessage::FluentIdentifier(std::borrow::Cow::Borrowed("mir_transform_operation_will_panic"),
None);
#[doc =
"Constant referring to Fluent message `mir_transform_string_interpolation_only_works` from `mir_transform`"]
pub const mir_transform_string_interpolation_only_works:
rustc_errors::DiagMessage =
rustc_errors::DiagMessage::FluentIdentifier(std::borrow::Cow::Borrowed("mir_transform_string_interpolation_only_works"),
None);
#[doc =
"Constant referring to Fluent message `mir_transform_tail_expr_drop_order` from `mir_transform`"]
pub const mir_transform_tail_expr_drop_order: rustc_errors::DiagMessage =
rustc_errors::DiagMessage::FluentIdentifier(std::borrow::Cow::Borrowed("mir_transform_tail_expr_drop_order"),
None);
#[doc =
"Constant referring to Fluent message `mir_transform_tail_expr_drop_order.temporaries` from `mir_transform`"]
pub const mir_transform_temporaries: rustc_errors::SubdiagMessage =
rustc_errors::SubdiagMessage::FluentAttr(std::borrow::Cow::Borrowed("temporaries"));
#[doc =
"Constant referring to Fluent message `mir_transform_tail_expr_drop_order.observers` from `mir_transform`"]
pub const mir_transform_observers: rustc_errors::SubdiagMessage =
rustc_errors::SubdiagMessage::FluentAttr(std::borrow::Cow::Borrowed("observers"));
#[doc =
"Constant referring to Fluent message `mir_transform_tail_expr_drop_order.note_dtors` from `mir_transform`"]
pub const mir_transform_note_dtors: rustc_errors::SubdiagMessage =
rustc_errors::SubdiagMessage::FluentAttr(std::borrow::Cow::Borrowed("note_dtors"));
#[doc =
"Constant referring to Fluent message `mir_transform_tail_expr_drop_order.note_observer_dtors` from `mir_transform`"]
pub const mir_transform_note_observer_dtors: rustc_errors::SubdiagMessage
=
rustc_errors::SubdiagMessage::FluentAttr(std::borrow::Cow::Borrowed("note_observer_dtors"));
#[doc =
"Constant referring to Fluent message `mir_transform_tail_expr_drop_order.drop_location` from `mir_transform`"]
pub const mir_transform_drop_location: rustc_errors::SubdiagMessage =
rustc_errors::SubdiagMessage::FluentAttr(std::borrow::Cow::Borrowed("drop_location"));
#[doc =
"Constant referring to Fluent message `mir_transform_tail_expr_drop_order.note_epilogue` from `mir_transform`"]
pub const mir_transform_note_epilogue: rustc_errors::SubdiagMessage =
rustc_errors::SubdiagMessage::FluentAttr(std::borrow::Cow::Borrowed("note_epilogue"));
#[doc =
"Constant referring to Fluent message `mir_transform_tail_expr_drop_order.label_local_epilogue` from `mir_transform`"]
pub const mir_transform_label_local_epilogue: rustc_errors::SubdiagMessage
=
rustc_errors::SubdiagMessage::FluentAttr(std::borrow::Cow::Borrowed("label_local_epilogue"));
#[doc =
"Constant referring to Fluent message `mir_transform_tail_expr_dtor` from `mir_transform`"]
pub const mir_transform_tail_expr_dtor: rustc_errors::DiagMessage =
rustc_errors::DiagMessage::FluentIdentifier(std::borrow::Cow::Borrowed("mir_transform_tail_expr_dtor"),
None);
#[doc =
"Constant referring to Fluent message `mir_transform_tail_expr_local` from `mir_transform`"]
pub const mir_transform_tail_expr_local: rustc_errors::DiagMessage =
rustc_errors::DiagMessage::FluentIdentifier(std::borrow::Cow::Borrowed("mir_transform_tail_expr_local"),
None);
#[doc =
"Constant referring to Fluent message `mir_transform_unaligned_packed_ref` from `mir_transform`"]
pub const mir_transform_unaligned_packed_ref: rustc_errors::DiagMessage =
rustc_errors::DiagMessage::FluentIdentifier(std::borrow::Cow::Borrowed("mir_transform_unaligned_packed_ref"),
None);
#[doc =
"Constant referring to Fluent message `mir_transform_unaligned_packed_ref.note_ub` from `mir_transform`"]
pub const mir_transform_note_ub: rustc_errors::SubdiagMessage =
rustc_errors::SubdiagMessage::FluentAttr(std::borrow::Cow::Borrowed("note_ub"));
#[doc =
"Constant referring to Fluent message `mir_transform_unconditional_recursion` from `mir_transform`"]
pub const mir_transform_unconditional_recursion: rustc_errors::DiagMessage
=
rustc_errors::DiagMessage::FluentIdentifier(std::borrow::Cow::Borrowed("mir_transform_unconditional_recursion"),
None);
#[doc =
"Constant referring to Fluent message `mir_transform_unconditional_recursion_call_site_label` from `mir_transform`"]
pub const mir_transform_unconditional_recursion_call_site_label:
rustc_errors::DiagMessage =
rustc_errors::DiagMessage::FluentIdentifier(std::borrow::Cow::Borrowed("mir_transform_unconditional_recursion_call_site_label"),
None);
#[doc =
"Constant referring to Fluent message `mir_transform_unknown_pass_name` from `mir_transform`"]
pub const mir_transform_unknown_pass_name: rustc_errors::DiagMessage =
rustc_errors::DiagMessage::FluentIdentifier(std::borrow::Cow::Borrowed("mir_transform_unknown_pass_name"),
None);
#[doc =
"Constant referring to Fluent message `mir_transform_unused_assign` from `mir_transform`"]
pub const mir_transform_unused_assign: rustc_errors::DiagMessage =
rustc_errors::DiagMessage::FluentIdentifier(std::borrow::Cow::Borrowed("mir_transform_unused_assign"),
None);
#[doc =
"Constant referring to Fluent message `mir_transform_unused_assign_passed` from `mir_transform`"]
pub const mir_transform_unused_assign_passed: rustc_errors::DiagMessage =
rustc_errors::DiagMessage::FluentIdentifier(std::borrow::Cow::Borrowed("mir_transform_unused_assign_passed"),
None);
#[doc =
"Constant referring to Fluent message `mir_transform_unused_assign_suggestion` from `mir_transform`"]
pub const mir_transform_unused_assign_suggestion:
rustc_errors::DiagMessage =
rustc_errors::DiagMessage::FluentIdentifier(std::borrow::Cow::Borrowed("mir_transform_unused_assign_suggestion"),
None);
#[doc =
"Constant referring to Fluent message `mir_transform_unused_capture_maybe_capture_ref` from `mir_transform`"]
pub const mir_transform_unused_capture_maybe_capture_ref:
rustc_errors::DiagMessage =
rustc_errors::DiagMessage::FluentIdentifier(std::borrow::Cow::Borrowed("mir_transform_unused_capture_maybe_capture_ref"),
None);
#[doc =
"Constant referring to Fluent message `mir_transform_unused_var_assigned_only` from `mir_transform`"]
pub const mir_transform_unused_var_assigned_only:
rustc_errors::DiagMessage =
rustc_errors::DiagMessage::FluentIdentifier(std::borrow::Cow::Borrowed("mir_transform_unused_var_assigned_only"),
None);
#[doc =
"Constant referring to Fluent message `mir_transform_unused_var_underscore` from `mir_transform`"]
pub const mir_transform_unused_var_underscore: rustc_errors::DiagMessage =
rustc_errors::DiagMessage::FluentIdentifier(std::borrow::Cow::Borrowed("mir_transform_unused_var_underscore"),
None);
#[doc =
"Constant referring to Fluent message `mir_transform_unused_variable` from `mir_transform`"]
pub const mir_transform_unused_variable: rustc_errors::DiagMessage =
rustc_errors::DiagMessage::FluentIdentifier(std::borrow::Cow::Borrowed("mir_transform_unused_variable"),
None);
#[doc =
"Constant referring to Fluent message `mir_transform_unused_variable_args_in_macro` from `mir_transform`"]
pub const mir_transform_unused_variable_args_in_macro:
rustc_errors::DiagMessage =
rustc_errors::DiagMessage::FluentIdentifier(std::borrow::Cow::Borrowed("mir_transform_unused_variable_args_in_macro"),
None);
#[doc =
"Constant referring to Fluent message `mir_transform_unused_variable_try_ignore` from `mir_transform`"]
pub const mir_transform_unused_variable_try_ignore:
rustc_errors::DiagMessage =
rustc_errors::DiagMessage::FluentIdentifier(std::borrow::Cow::Borrowed("mir_transform_unused_variable_try_ignore"),
None);
#[doc =
"Constant referring to Fluent message `mir_transform_unused_variable_typo` from `mir_transform`"]
pub const mir_transform_unused_variable_typo: rustc_errors::DiagMessage =
rustc_errors::DiagMessage::FluentIdentifier(std::borrow::Cow::Borrowed("mir_transform_unused_variable_typo"),
None);
#[doc =
r" Constants expected to exist by the diagnostic derive macros to use as default Fluent"]
#[doc = r" identifiers for different subdiagnostic kinds."]
pub mod _subdiag {
#[doc = r" Default for `#[help]`"]
pub const help: rustc_errors::SubdiagMessage =
rustc_errors::SubdiagMessage::FluentAttr(std::borrow::Cow::Borrowed("help"));
#[doc = r" Default for `#[note]`"]
pub const note: rustc_errors::SubdiagMessage =
rustc_errors::SubdiagMessage::FluentAttr(std::borrow::Cow::Borrowed("note"));
#[doc = r" Default for `#[warn]`"]
pub const warn: rustc_errors::SubdiagMessage =
rustc_errors::SubdiagMessage::FluentAttr(std::borrow::Cow::Borrowed("warn"));
#[doc = r" Default for `#[label]`"]
pub const label: rustc_errors::SubdiagMessage =
rustc_errors::SubdiagMessage::FluentAttr(std::borrow::Cow::Borrowed("label"));
#[doc = r" Default for `#[suggestion]`"]
pub const suggestion: rustc_errors::SubdiagMessage =
rustc_errors::SubdiagMessage::FluentAttr(std::borrow::Cow::Borrowed("suggestion"));
}
}rustc_fluent_macro::fluent_messages! { "../messages.ftl" }
206
207pub fn provide(providers: &mut Providers) {
208 coverage::query::provide(providers);
209 ffi_unwind_calls::provide(&mut providers.queries);
210 shim::provide(&mut providers.queries);
211 cross_crate_inline::provide(&mut providers.queries);
212 providers.queries = query::Providers {
213 mir_keys,
214 mir_built,
215 mir_const_qualif,
216 mir_promoted,
217 mir_drops_elaborated_and_const_checked,
218 mir_for_ctfe,
219 mir_coroutine_witnesses: coroutine::mir_coroutine_witnesses,
220 optimized_mir,
221 check_liveness: liveness::check_liveness,
222 is_mir_available,
223 is_ctfe_mir_available: is_mir_available,
224 mir_callgraph_cyclic: inline::cycle::mir_callgraph_cyclic,
225 mir_inliner_callees: inline::cycle::mir_inliner_callees,
226 promoted_mir,
227 deduced_param_attrs: deduce_param_attrs::deduced_param_attrs,
228 coroutine_by_move_body_def_id: coroutine::coroutine_by_move_body_def_id,
229 trivial_const: trivial_const::trivial_const_provider,
230 ..providers.queries
231 };
232}
233
234fn remap_mir_for_const_eval_select<'tcx>(
235 tcx: TyCtxt<'tcx>,
236 mut body: Body<'tcx>,
237 context: hir::Constness,
238) -> Body<'tcx> {
239 for bb in body.basic_blocks.as_mut().iter_mut() {
240 let terminator = bb.terminator.as_mut().expect("invalid terminator");
241 match terminator.kind {
242 TerminatorKind::Call {
243 func: Operand::Constant(box ConstOperand { ref const_, .. }),
244 ref mut args,
245 destination,
246 target,
247 unwind,
248 fn_span,
249 ..
250 } if let ty::FnDef(def_id, _) = *const_.ty().kind()
251 && tcx.is_intrinsic(def_id, sym::const_eval_select) =>
252 {
253 let Ok([tupled_args, called_in_const, called_at_rt]) = take_array(args) else {
254 ::core::panicking::panic("internal error: entered unreachable code")unreachable!()
255 };
256 let ty = tupled_args.node.ty(&body.local_decls, tcx);
257 let fields = ty.tuple_fields();
258 let num_args = fields.len();
259 let func =
260 if context == hir::Constness::Const { called_in_const } else { called_at_rt };
261 let (method, place): (fn(Place<'tcx>) -> Operand<'tcx>, Place<'tcx>) =
262 match tupled_args.node {
263 Operand::Constant(_) | Operand::RuntimeChecks(_) => {
264 let local = body.local_decls.push(LocalDecl::new(ty, fn_span));
268 bb.statements.push(Statement::new(
269 SourceInfo::outermost(fn_span),
270 StatementKind::Assign(Box::new((
271 local.into(),
272 Rvalue::Use(tupled_args.node.clone()),
273 ))),
274 ));
275 (Operand::Move, local.into())
276 }
277 Operand::Move(place) => (Operand::Move, place),
278 Operand::Copy(place) => (Operand::Copy, place),
279 };
280 let place_elems = place.projection;
281 let arguments = (0..num_args)
282 .map(|x| {
283 let mut place_elems = place_elems.to_vec();
284 place_elems.push(ProjectionElem::Field(x.into(), fields[x]));
285 let projection = tcx.mk_place_elems(&place_elems);
286 let place = Place { local: place.local, projection };
287 Spanned { node: method(place), span: DUMMY_SP }
288 })
289 .collect();
290 terminator.kind = TerminatorKind::Call {
291 func: func.node,
292 args: arguments,
293 destination,
294 target,
295 unwind,
296 call_source: CallSource::Misc,
297 fn_span,
298 };
299 }
300 _ => {}
301 }
302 }
303 body
304}
305
306fn take_array<T, const N: usize>(b: &mut Box<[T]>) -> Result<[T; N], Box<[T]>> {
307 let b: Box<[T; N]> = std::mem::take(b).try_into()?;
308 Ok(*b)
309}
310
311fn is_mir_available(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool {
312 tcx.mir_keys(()).contains(&def_id)
313}
314
315fn mir_keys(tcx: TyCtxt<'_>, (): ()) -> FxIndexSet<LocalDefId> {
318 let mut set: FxIndexSet<_> = tcx.hir_body_owners().collect();
320
321 set.retain(|&def_id| !#[allow(non_exhaustive_omitted_patterns)] match tcx.def_kind(def_id) {
DefKind::GlobalAsm => true,
_ => false,
}matches!(tcx.def_kind(def_id), DefKind::GlobalAsm));
324
325 for body_owner in tcx.hir_body_owners() {
328 if let DefKind::Closure = tcx.def_kind(body_owner)
329 && tcx.needs_coroutine_by_move_body_def_id(body_owner.to_def_id())
330 {
331 set.insert(tcx.coroutine_by_move_body_def_id(body_owner).expect_local());
332 }
333 }
334
335 for item in tcx.hir_crate_items(()).free_items() {
338 if let DefKind::Struct | DefKind::Enum = tcx.def_kind(item.owner_id) {
339 for variant in tcx.adt_def(item.owner_id).variants() {
340 if let Some((CtorKind::Fn, ctor_def_id)) = variant.ctor {
341 set.insert(ctor_def_id.expect_local());
342 }
343 }
344 }
345 }
346
347 set
348}
349
350fn mir_const_qualif(tcx: TyCtxt<'_>, def: LocalDefId) -> ConstQualifs {
351 let body = &tcx.mir_built(def).borrow();
356 let ccx = check_consts::ConstCx::new(tcx, body);
357 match ccx.const_kind {
359 Some(ConstContext::Const { .. } | ConstContext::Static(_) | ConstContext::ConstFn) => {}
360 None => ::rustc_middle::util::bug::span_bug_fmt(tcx.def_span(def),
format_args!("`mir_const_qualif` should only be called on const fns and const items"))span_bug!(
361 tcx.def_span(def),
362 "`mir_const_qualif` should only be called on const fns and const items"
363 ),
364 }
365
366 if body.return_ty().references_error() {
367 tcx.dcx().span_delayed_bug(body.span, "mir_const_qualif: MIR had errors");
369 return Default::default();
370 }
371
372 let mut validator = check_consts::check::Checker::new(&ccx);
373 validator.check_body();
374
375 validator.qualifs_in_return_place()
378}
379
380fn mir_built(tcx: TyCtxt<'_>, def: LocalDefId) -> &Steal<Body<'_>> {
382 let mut body = tcx.build_mir_inner_impl(def);
385
386 if trivial_const::trivial_const(tcx, def, || &body).is_some() {
390 let body = tcx.alloc_steal_mir(body);
392 pass_manager::dump_mir_for_phase_change(tcx, &body.borrow());
393 return body;
394 }
395
396 pass_manager::dump_mir_for_phase_change(tcx, &body);
397
398 pm::run_passes(
399 tcx,
400 &mut body,
401 &[
402 &Lint(check_inline::CheckForceInline),
404 &Lint(check_call_recursion::CheckCallRecursion),
405 &Lint(check_inline_always_target_features::CheckInlineAlwaysTargetFeature),
408 &Lint(check_packed_ref::CheckPackedRef),
409 &Lint(check_const_item_mutation::CheckConstItemMutation),
410 &Lint(function_item_references::FunctionItemReferences),
411 &simplify::SimplifyCfg::Initial,
413 &Lint(sanity_check::SanityCheck),
414 ],
415 None,
416 pm::Optimizations::Allowed,
417 );
418 tcx.alloc_steal_mir(body)
419}
420
421fn mir_promoted(
423 tcx: TyCtxt<'_>,
424 def: LocalDefId,
425) -> (&Steal<Body<'_>>, &Steal<IndexVec<Promoted, Body<'_>>>) {
426 if true {
if !!tcx.is_trivial_const(def) {
{
::core::panicking::panic_fmt(format_args!("Tried to get mir_promoted of a trivial const"));
}
};
};debug_assert!(!tcx.is_trivial_const(def), "Tried to get mir_promoted of a trivial const");
427
428 let const_qualifs = match tcx.def_kind(def) {
433 DefKind::Fn | DefKind::AssocFn | DefKind::Closure
434 if tcx.constness(def) == hir::Constness::Const =>
435 {
436 tcx.mir_const_qualif(def)
437 }
438 DefKind::AssocConst
439 | DefKind::Const
440 | DefKind::Static { .. }
441 | DefKind::InlineConst
442 | DefKind::AnonConst => tcx.mir_const_qualif(def),
443 _ => ConstQualifs::default(),
444 };
445
446 tcx.ensure_done().has_ffi_unwind_calls(def);
448
449 if tcx.needs_coroutine_by_move_body_def_id(def.to_def_id()) {
451 tcx.ensure_done().coroutine_by_move_body_def_id(def);
452 }
453
454 tcx.ensure_done().trivial_const(def);
456
457 let mut body = tcx.mir_built(def).steal();
458 if let Some(error_reported) = const_qualifs.tainted_by_errors {
459 body.tainted_by_errors = Some(error_reported);
460 }
461
462 RequiredConstsVisitor::compute_required_consts(&mut body);
465
466 let promote_pass = promote_consts::PromoteTemps::default();
468 pm::run_passes(
469 tcx,
470 &mut body,
471 &[&promote_pass, &simplify::SimplifyCfg::PromoteConsts, &coverage::InstrumentCoverage],
472 Some(MirPhase::Analysis(AnalysisPhase::Initial)),
473 pm::Optimizations::Allowed,
474 );
475
476 lint_tail_expr_drop_order::run_lint(tcx, def, &body);
477
478 let promoted = promote_pass.promoted_fragments.into_inner();
479 (tcx.alloc_steal_mir(body), tcx.alloc_steal_promoted(promoted))
480}
481
482fn mir_for_ctfe(tcx: TyCtxt<'_>, def_id: LocalDefId) -> &Body<'_> {
484 if true {
if !!tcx.is_trivial_const(def_id) {
{
::core::panicking::panic_fmt(format_args!("Tried to get mir_for_ctfe of a trivial const"));
}
};
};debug_assert!(!tcx.is_trivial_const(def_id), "Tried to get mir_for_ctfe of a trivial const");
485 tcx.arena.alloc(inner_mir_for_ctfe(tcx, def_id))
486}
487
488fn inner_mir_for_ctfe(tcx: TyCtxt<'_>, def: LocalDefId) -> Body<'_> {
489 if tcx.is_constructor(def.to_def_id()) {
491 return shim::build_adt_ctor(tcx, def.to_def_id());
496 }
497
498 let body = tcx.mir_drops_elaborated_and_const_checked(def);
499 let body = match tcx.hir_body_const_context(def) {
500 Some(hir::ConstContext::Const { .. } | hir::ConstContext::Static(_)) => body.steal(),
503 Some(hir::ConstContext::ConstFn) => body.borrow().clone(),
504 None => ::rustc_middle::util::bug::bug_fmt(format_args!("`mir_for_ctfe` called on non-const {0:?}",
def))bug!("`mir_for_ctfe` called on non-const {def:?}"),
505 };
506
507 let mut body = remap_mir_for_const_eval_select(tcx, body, hir::Constness::Const);
508 pm::run_passes(tcx, &mut body, &[&ctfe_limit::CtfeLimit], None, pm::Optimizations::Allowed);
509
510 body
511}
512
513fn mir_drops_elaborated_and_const_checked(tcx: TyCtxt<'_>, def: LocalDefId) -> &Steal<Body<'_>> {
517 if tcx.is_coroutine(def.to_def_id()) {
518 tcx.ensure_done().mir_coroutine_witnesses(def);
519 }
520
521 let tainted_by_errors = if !tcx.is_synthetic_mir(def) {
523 tcx.mir_borrowck(tcx.typeck_root_def_id(def.to_def_id()).expect_local()).err()
524 } else {
525 None
526 };
527
528 let is_fn_like = tcx.def_kind(def).is_fn_like();
529 if is_fn_like {
530 if pm::should_run_pass(tcx, &inline::Inline, pm::Optimizations::Allowed)
532 || inline::ForceInline::should_run_pass_for_callee(tcx, def.to_def_id())
533 {
534 tcx.ensure_done().mir_inliner_callees(ty::InstanceKind::Item(def.to_def_id()));
535 }
536 }
537
538 tcx.ensure_done().check_liveness(def);
539
540 let (body, _) = tcx.mir_promoted(def);
541 let mut body = body.steal();
542
543 if let Some(error_reported) = tainted_by_errors {
544 body.tainted_by_errors = Some(error_reported);
545 }
546
547 let root = tcx.typeck_root_def_id(def.to_def_id());
552 match tcx.def_kind(root) {
553 DefKind::Fn
554 | DefKind::AssocFn
555 | DefKind::Static { .. }
556 | DefKind::Const
557 | DefKind::AssocConst => {
558 if let Err(guar) = tcx.ensure_ok().check_well_formed(root.expect_local()) {
559 body.tainted_by_errors = Some(guar);
560 }
561 }
562 _ => {}
563 }
564
565 run_analysis_to_runtime_passes(tcx, &mut body);
566
567 tcx.alloc_steal_mir(body)
568}
569
570pub fn run_analysis_to_runtime_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
573 if !(body.phase == MirPhase::Analysis(AnalysisPhase::Initial)) {
::core::panicking::panic("assertion failed: body.phase == MirPhase::Analysis(AnalysisPhase::Initial)")
};assert!(body.phase == MirPhase::Analysis(AnalysisPhase::Initial));
574 let did = body.source.def_id();
575
576 {
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event compiler/rustc_mir_transform/src/lib.rs:576",
"rustc_mir_transform", ::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("compiler/rustc_mir_transform/src/lib.rs"),
::tracing_core::__macro_support::Option::Some(576u32),
::tracing_core::__macro_support::Option::Some("rustc_mir_transform"),
::tracing_core::field::FieldSet::new(&["message"],
::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::EVENT)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let enabled =
::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
&&
::tracing::Level::DEBUG <=
::tracing::level_filters::LevelFilter::current() &&
{
let interest = __CALLSITE.interest();
!interest.is_never() &&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest)
};
if enabled {
(|value_set: ::tracing::field::ValueSet|
{
let meta = __CALLSITE.metadata();
::tracing::Event::dispatch(meta, &value_set);
;
})({
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
let mut iter = __CALLSITE.metadata().fields().iter();
__CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
::tracing::__macro_support::Option::Some(&format_args!("analysis_mir_cleanup({0:?})",
did) as &dyn Value))])
});
} else { ; }
};debug!("analysis_mir_cleanup({:?})", did);
577 run_analysis_cleanup_passes(tcx, body);
578 if !(body.phase == MirPhase::Analysis(AnalysisPhase::PostCleanup)) {
::core::panicking::panic("assertion failed: body.phase == MirPhase::Analysis(AnalysisPhase::PostCleanup)")
};assert!(body.phase == MirPhase::Analysis(AnalysisPhase::PostCleanup));
579
580 if check_consts::post_drop_elaboration::checking_enabled(&ConstCx::new(tcx, body)) {
582 pm::run_passes(
583 tcx,
584 body,
585 &[
586 &remove_uninit_drops::RemoveUninitDrops,
587 &simplify::SimplifyCfg::RemoveFalseEdges,
588 &Lint(post_drop_elaboration::CheckLiveDrops),
589 ],
590 None,
591 pm::Optimizations::Allowed,
592 );
593 }
594
595 {
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event compiler/rustc_mir_transform/src/lib.rs:595",
"rustc_mir_transform", ::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("compiler/rustc_mir_transform/src/lib.rs"),
::tracing_core::__macro_support::Option::Some(595u32),
::tracing_core::__macro_support::Option::Some("rustc_mir_transform"),
::tracing_core::field::FieldSet::new(&["message"],
::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::EVENT)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let enabled =
::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
&&
::tracing::Level::DEBUG <=
::tracing::level_filters::LevelFilter::current() &&
{
let interest = __CALLSITE.interest();
!interest.is_never() &&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest)
};
if enabled {
(|value_set: ::tracing::field::ValueSet|
{
let meta = __CALLSITE.metadata();
::tracing::Event::dispatch(meta, &value_set);
;
})({
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
let mut iter = __CALLSITE.metadata().fields().iter();
__CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
::tracing::__macro_support::Option::Some(&format_args!("runtime_mir_lowering({0:?})",
did) as &dyn Value))])
});
} else { ; }
};debug!("runtime_mir_lowering({:?})", did);
596 run_runtime_lowering_passes(tcx, body);
597 if !(body.phase == MirPhase::Runtime(RuntimePhase::Initial)) {
::core::panicking::panic("assertion failed: body.phase == MirPhase::Runtime(RuntimePhase::Initial)")
};assert!(body.phase == MirPhase::Runtime(RuntimePhase::Initial));
598
599 {
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event compiler/rustc_mir_transform/src/lib.rs:599",
"rustc_mir_transform", ::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("compiler/rustc_mir_transform/src/lib.rs"),
::tracing_core::__macro_support::Option::Some(599u32),
::tracing_core::__macro_support::Option::Some("rustc_mir_transform"),
::tracing_core::field::FieldSet::new(&["message"],
::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::EVENT)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let enabled =
::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
&&
::tracing::Level::DEBUG <=
::tracing::level_filters::LevelFilter::current() &&
{
let interest = __CALLSITE.interest();
!interest.is_never() &&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest)
};
if enabled {
(|value_set: ::tracing::field::ValueSet|
{
let meta = __CALLSITE.metadata();
::tracing::Event::dispatch(meta, &value_set);
;
})({
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
let mut iter = __CALLSITE.metadata().fields().iter();
__CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
::tracing::__macro_support::Option::Some(&format_args!("runtime_mir_cleanup({0:?})",
did) as &dyn Value))])
});
} else { ; }
};debug!("runtime_mir_cleanup({:?})", did);
600 run_runtime_cleanup_passes(tcx, body);
601 if !(body.phase == MirPhase::Runtime(RuntimePhase::PostCleanup)) {
::core::panicking::panic("assertion failed: body.phase == MirPhase::Runtime(RuntimePhase::PostCleanup)")
};assert!(body.phase == MirPhase::Runtime(RuntimePhase::PostCleanup));
602}
603
604fn run_analysis_cleanup_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
608 let passes: &[&dyn MirPass<'tcx>] = &[
609 &impossible_predicates::ImpossiblePredicates,
610 &cleanup_post_borrowck::CleanupPostBorrowck,
611 &remove_noop_landing_pads::RemoveNoopLandingPads,
612 &simplify::SimplifyCfg::PostAnalysis,
613 &deref_separator::Derefer,
614 ];
615
616 pm::run_passes(
617 tcx,
618 body,
619 passes,
620 Some(MirPhase::Analysis(AnalysisPhase::PostCleanup)),
621 pm::Optimizations::Allowed,
622 );
623}
624
625fn run_runtime_lowering_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
627 let passes: &[&dyn MirPass<'tcx>] = &[
628 &add_call_guards::CriticalCallEdges,
630 &post_analysis_normalize::PostAnalysisNormalize,
632 &add_subtyping_projections::Subtyper,
634 &elaborate_drops::ElaborateDrops,
635 &Lint(check_call_recursion::CheckDropRecursion),
637 &abort_unwinding_calls::AbortUnwindingCalls,
641 &add_moves_for_packed_drops::AddMovesForPackedDrops,
644 &add_retag::AddRetag,
647 &erase_deref_temps::EraseDerefTemps,
648 &elaborate_box_derefs::ElaborateBoxDerefs,
649 &coroutine::StateTransform,
650 &Lint(known_panics_lint::KnownPanicsLint),
651 ];
652 pm::run_passes_no_validate(tcx, body, passes, Some(MirPhase::Runtime(RuntimePhase::Initial)));
653}
654
655fn run_runtime_cleanup_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
657 let passes: &[&dyn MirPass<'tcx>] = &[
658 &lower_intrinsics::LowerIntrinsics,
659 &remove_place_mention::RemovePlaceMention,
660 &simplify::SimplifyCfg::PreOptimizations,
661 ];
662
663 pm::run_passes(
664 tcx,
665 body,
666 passes,
667 Some(MirPhase::Runtime(RuntimePhase::PostCleanup)),
668 pm::Optimizations::Allowed,
669 );
670
671 for decl in &mut body.local_decls {
674 decl.local_info = ClearCrossCrate::Clear;
675 }
676}
677
678pub(crate) fn run_optimization_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
679 fn o1<T>(x: T) -> WithMinOptLevel<T> {
680 WithMinOptLevel(1, x)
681 }
682
683 let def_id = body.source.def_id();
684 let optimizations = if tcx.def_kind(def_id).has_codegen_attrs()
685 && tcx.codegen_fn_attrs(def_id).optimize.do_not_optimize()
686 {
687 pm::Optimizations::Suppressed
688 } else {
689 pm::Optimizations::Allowed
690 };
691
692 pm::run_passes(
694 tcx,
695 body,
696 &[
697 &check_alignment::CheckAlignment,
699 &check_null::CheckNull,
700 &check_enums::CheckEnums,
701 &lower_slice_len::LowerSliceLenCalls,
706 &instsimplify::InstSimplify::BeforeInline,
709 &inline::ForceInline,
711 &inline::Inline,
713 &remove_storage_markers::RemoveStorageMarkers,
718 &remove_zsts::RemoveZsts,
720 &remove_unneeded_drops::RemoveUnneededDrops,
721 &unreachable_enum_branching::UnreachableEnumBranching,
724 &unreachable_prop::UnreachablePropagation,
725 &o1(simplify::SimplifyCfg::AfterUnreachableEnumBranching),
726 &multiple_return_terminators::MultipleReturnTerminators,
727 &instsimplify::InstSimplify::AfterSimplifyCfg,
731 &o1(simplify_branches::SimplifyConstCondition::AfterInstSimplify),
740 &ref_prop::ReferencePropagation,
741 &sroa::ScalarReplacementOfAggregates,
742 &simplify::SimplifyLocals::BeforeConstProp,
743 &dead_store_elimination::DeadStoreElimination::Initial,
744 &gvn::GVN,
745 &simplify::SimplifyLocals::AfterGVN,
746 &match_branches::MatchBranchSimplification,
747 &dataflow_const_prop::DataflowConstProp,
748 &single_use_consts::SingleUseConsts,
749 &o1(simplify_branches::SimplifyConstCondition::AfterConstProp),
750 &jump_threading::JumpThreading,
751 &early_otherwise_branch::EarlyOtherwiseBranch,
752 &simplify_comparison_integral::SimplifyComparisonIntegral,
753 &o1(simplify_branches::SimplifyConstCondition::Final),
754 &o1(remove_noop_landing_pads::RemoveNoopLandingPads),
755 &o1(simplify::SimplifyCfg::Final),
756 &strip_debuginfo::StripDebugInfo,
758 ©_prop::CopyProp,
759 &dead_store_elimination::DeadStoreElimination::Final,
760 &dest_prop::DestinationPropagation,
761 &simplify::SimplifyLocals::Final,
762 &multiple_return_terminators::MultipleReturnTerminators,
763 &large_enums::EnumSizeOpt { discrepancy: 128 },
764 &add_call_guards::CriticalCallEdges,
766 &prettify::ReorderBasicBlocks,
768 &prettify::ReorderLocals,
769 &dump_mir::Marker("PreCodegen"),
771 ],
772 Some(MirPhase::Runtime(RuntimePhase::Optimized)),
773 optimizations,
774 );
775}
776
777fn optimized_mir(tcx: TyCtxt<'_>, did: LocalDefId) -> &Body<'_> {
779 tcx.arena.alloc(inner_optimized_mir(tcx, did))
780}
781
782fn inner_optimized_mir(tcx: TyCtxt<'_>, did: LocalDefId) -> Body<'_> {
783 if tcx.is_constructor(did.to_def_id()) {
784 return shim::build_adt_ctor(tcx, did.to_def_id());
789 }
790
791 match tcx.hir_body_const_context(did) {
792 Some(hir::ConstContext::ConstFn) => tcx.ensure_done().mir_for_ctfe(did),
796 None => {}
797 Some(other) => {
::core::panicking::panic_fmt(format_args!("do not use `optimized_mir` for constants: {0:?}",
other));
}panic!("do not use `optimized_mir` for constants: {other:?}"),
798 }
799 {
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event compiler/rustc_mir_transform/src/lib.rs:799",
"rustc_mir_transform", ::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("compiler/rustc_mir_transform/src/lib.rs"),
::tracing_core::__macro_support::Option::Some(799u32),
::tracing_core::__macro_support::Option::Some("rustc_mir_transform"),
::tracing_core::field::FieldSet::new(&["message"],
::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::EVENT)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let enabled =
::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
&&
::tracing::Level::DEBUG <=
::tracing::level_filters::LevelFilter::current() &&
{
let interest = __CALLSITE.interest();
!interest.is_never() &&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest)
};
if enabled {
(|value_set: ::tracing::field::ValueSet|
{
let meta = __CALLSITE.metadata();
::tracing::Event::dispatch(meta, &value_set);
;
})({
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
let mut iter = __CALLSITE.metadata().fields().iter();
__CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
::tracing::__macro_support::Option::Some(&format_args!("about to call mir_drops_elaborated...")
as &dyn Value))])
});
} else { ; }
};debug!("about to call mir_drops_elaborated...");
800 let body = tcx.mir_drops_elaborated_and_const_checked(did).steal();
801 let mut body = remap_mir_for_const_eval_select(tcx, body, hir::Constness::NotConst);
802
803 if body.tainted_by_errors.is_some() {
804 return body;
805 }
806
807 mentioned_items::MentionedItems.run_pass(tcx, &mut body);
811
812 if let TerminatorKind::Unreachable = body.basic_blocks[START_BLOCK].terminator().kind
816 && body.basic_blocks[START_BLOCK].statements.is_empty()
817 {
818 return body;
819 }
820
821 run_optimization_passes(tcx, &mut body);
822
823 body
824}
825
826fn promoted_mir(tcx: TyCtxt<'_>, def: LocalDefId) -> &IndexVec<Promoted, Body<'_>> {
829 if tcx.is_constructor(def.to_def_id()) {
830 return tcx.arena.alloc(IndexVec::new());
831 }
832
833 if !tcx.is_synthetic_mir(def) {
834 tcx.ensure_done().mir_borrowck(tcx.typeck_root_def_id(def.to_def_id()).expect_local());
835 }
836 let mut promoted = tcx.mir_promoted(def).1.steal();
837
838 for body in &mut promoted {
839 run_analysis_to_runtime_passes(tcx, body);
840 }
841
842 tcx.arena.alloc(promoted)
843}