Auto merge of #108944 - cjgillot:clear-local-info, r=oli-obk
Wrap the whole LocalInfo in ClearCrossCrate. MIR contains a lot of information about locals. The primary purpose of this information is the quality of borrowck diagnostics. This PR aims to drop this information after MIR analyses are finished, ie. starting from post-cleanup runtime MIR.
This commit is contained in:
commit
511364e787
@ -1985,16 +1985,18 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
let (place_desc, note) = if let Some(place_desc) = opt_place_desc {
|
||||
let local_kind = if let Some(local) = borrow.borrowed_place.as_local() {
|
||||
match self.body.local_kind(local) {
|
||||
LocalKind::ReturnPointer | LocalKind::Temp => {
|
||||
bug!("temporary or return pointer with a name")
|
||||
LocalKind::Temp if self.body.local_decls[local].is_user_variable() => {
|
||||
"local variable "
|
||||
}
|
||||
LocalKind::Var => "local variable ",
|
||||
LocalKind::Arg
|
||||
if !self.upvars.is_empty() && local == ty::CAPTURE_STRUCT_LOCAL =>
|
||||
{
|
||||
"variable captured by `move` "
|
||||
}
|
||||
LocalKind::Arg => "function parameter ",
|
||||
LocalKind::ReturnPointer | LocalKind::Temp => {
|
||||
bug!("temporary or return pointer with a name")
|
||||
}
|
||||
}
|
||||
} else {
|
||||
"local data "
|
||||
@ -2008,16 +2010,16 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
self.prefixes(borrow.borrowed_place.as_ref(), PrefixSet::All).last().unwrap();
|
||||
let local = root_place.local;
|
||||
match self.body.local_kind(local) {
|
||||
LocalKind::ReturnPointer | LocalKind::Temp => {
|
||||
("temporary value".to_string(), "temporary value created here".to_string())
|
||||
}
|
||||
LocalKind::Arg => (
|
||||
"function parameter".to_string(),
|
||||
"function parameter borrowed here".to_string(),
|
||||
),
|
||||
LocalKind::Var => {
|
||||
LocalKind::Temp if self.body.local_decls[local].is_user_variable() => {
|
||||
("local binding".to_string(), "local binding introduced here".to_string())
|
||||
}
|
||||
LocalKind::ReturnPointer | LocalKind::Temp => {
|
||||
("temporary value".to_string(), "temporary value created here".to_string())
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@ -2482,15 +2484,14 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
let (place_description, assigned_span) = match local_decl {
|
||||
Some(LocalDecl {
|
||||
local_info:
|
||||
Some(box LocalInfo::User(
|
||||
ClearCrossCrate::Clear
|
||||
| ClearCrossCrate::Set(BindingForm::Var(VarBindingForm {
|
||||
ClearCrossCrate::Set(
|
||||
box LocalInfo::User(BindingForm::Var(VarBindingForm {
|
||||
opt_match_place: None,
|
||||
..
|
||||
})),
|
||||
))
|
||||
| Some(box LocalInfo::StaticRef { .. })
|
||||
| None,
|
||||
}))
|
||||
| box LocalInfo::StaticRef { .. }
|
||||
| box LocalInfo::Boring,
|
||||
),
|
||||
..
|
||||
})
|
||||
| None => (self.describe_any_place(place.as_ref()), assigned_span),
|
||||
|
@ -6,8 +6,8 @@ use rustc_hir::intravisit::Visitor;
|
||||
use rustc_index::vec::IndexVec;
|
||||
use rustc_infer::infer::NllRegionVariableOrigin;
|
||||
use rustc_middle::mir::{
|
||||
Body, CastKind, ConstraintCategory, FakeReadCause, Local, Location, Operand, Place, Rvalue,
|
||||
Statement, StatementKind, TerminatorKind,
|
||||
Body, CastKind, ConstraintCategory, FakeReadCause, Local, LocalInfo, Location, Operand, Place,
|
||||
Rvalue, Statement, StatementKind, TerminatorKind,
|
||||
};
|
||||
use rustc_middle::ty::adjustment::PointerCast;
|
||||
use rustc_middle::ty::{self, RegionVid, TyCtxt};
|
||||
@ -220,7 +220,7 @@ impl<'tcx> BorrowExplanation<'tcx> {
|
||||
);
|
||||
err.span_label(body.source_info(drop_loc).span, message);
|
||||
|
||||
if let Some(info) = &local_decl.is_block_tail {
|
||||
if let LocalInfo::BlockTailTemp(info) = local_decl.local_info() {
|
||||
if info.tail_result_is_ignored {
|
||||
// #85581: If the first mutable borrow's scope contains
|
||||
// the second borrow, this suggestion isn't helpful.
|
||||
|
@ -196,10 +196,10 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
if self.body.local_decls[local].is_ref_for_guard() {
|
||||
continue;
|
||||
}
|
||||
if let Some(box LocalInfo::StaticRef { def_id, .. }) =
|
||||
&self.body.local_decls[local].local_info
|
||||
if let LocalInfo::StaticRef { def_id, .. } =
|
||||
*self.body.local_decls[local].local_info()
|
||||
{
|
||||
buf.push_str(self.infcx.tcx.item_name(*def_id).as_str());
|
||||
buf.push_str(self.infcx.tcx.item_name(def_id).as_str());
|
||||
ok = Ok(());
|
||||
continue;
|
||||
}
|
||||
|
@ -102,14 +102,12 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
||||
//
|
||||
// opt_match_place is None for let [mut] x = ... statements,
|
||||
// whether or not the right-hand side is a place expression
|
||||
if let Some(box LocalInfo::User(ClearCrossCrate::Set(BindingForm::Var(
|
||||
VarBindingForm {
|
||||
opt_match_place: Some((opt_match_place, match_span)),
|
||||
binding_mode: _,
|
||||
opt_ty_info: _,
|
||||
pat_span: _,
|
||||
},
|
||||
)))) = local_decl.local_info
|
||||
if let LocalInfo::User(BindingForm::Var(VarBindingForm {
|
||||
opt_match_place: Some((opt_match_place, match_span)),
|
||||
binding_mode: _,
|
||||
opt_ty_info: _,
|
||||
pat_span: _,
|
||||
})) = *local_decl.local_info()
|
||||
{
|
||||
let stmt_source_info = self.body.source_info(location);
|
||||
self.append_binding_error(
|
||||
@ -478,9 +476,8 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
||||
let mut suggestions: Vec<(Span, String, String)> = Vec::new();
|
||||
for local in binds_to {
|
||||
let bind_to = &self.body.local_decls[*local];
|
||||
if let Some(box LocalInfo::User(ClearCrossCrate::Set(BindingForm::Var(
|
||||
VarBindingForm { pat_span, .. },
|
||||
)))) = bind_to.local_info
|
||||
if let LocalInfo::User(BindingForm::Var(VarBindingForm { pat_span, .. })) =
|
||||
*bind_to.local_info()
|
||||
{
|
||||
let Ok(pat_snippet) =
|
||||
self.infcx.tcx.sess.source_map().span_to_snippet(pat_span) else { continue; };
|
||||
|
@ -7,7 +7,7 @@ use rustc_middle::mir::{Mutability, Place, PlaceRef, ProjectionElem};
|
||||
use rustc_middle::ty::{self, Ty, TyCtxt};
|
||||
use rustc_middle::{
|
||||
hir::place::PlaceBase,
|
||||
mir::{self, BindingForm, ClearCrossCrate, Local, LocalDecl, LocalInfo, LocalKind, Location},
|
||||
mir::{self, BindingForm, Local, LocalDecl, LocalInfo, LocalKind, Location},
|
||||
};
|
||||
use rustc_span::source_map::DesugaringKind;
|
||||
use rustc_span::symbol::{kw, Symbol};
|
||||
@ -105,8 +105,8 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
||||
reason = String::new();
|
||||
} else {
|
||||
item_msg = access_place_desc;
|
||||
let local_info = &self.body.local_decls[local].local_info;
|
||||
if let Some(box LocalInfo::StaticRef { def_id, .. }) = *local_info {
|
||||
let local_info = self.body.local_decls[local].local_info();
|
||||
if let LocalInfo::StaticRef { def_id, .. } = *local_info {
|
||||
let static_name = &self.infcx.tcx.item_name(def_id);
|
||||
reason = format!(", as `{static_name}` is an immutable static item");
|
||||
} else {
|
||||
@ -305,15 +305,13 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
||||
..
|
||||
}) = &self.body[location.block].statements.get(location.statement_index)
|
||||
{
|
||||
match decl.local_info {
|
||||
Some(box LocalInfo::User(ClearCrossCrate::Set(BindingForm::Var(
|
||||
mir::VarBindingForm {
|
||||
binding_mode: ty::BindingMode::BindByValue(Mutability::Not),
|
||||
opt_ty_info: Some(sp),
|
||||
opt_match_place: _,
|
||||
pat_span: _,
|
||||
},
|
||||
)))) => {
|
||||
match *decl.local_info() {
|
||||
LocalInfo::User(BindingForm::Var(mir::VarBindingForm {
|
||||
binding_mode: ty::BindingMode::BindByValue(Mutability::Not),
|
||||
opt_ty_info: Some(sp),
|
||||
opt_match_place: _,
|
||||
pat_span: _,
|
||||
})) => {
|
||||
if suggest {
|
||||
err.span_note(sp, "the binding is already a mutable borrow");
|
||||
}
|
||||
@ -346,10 +344,8 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
||||
}
|
||||
} else if decl.mutability.is_not() {
|
||||
if matches!(
|
||||
decl.local_info,
|
||||
Some(box LocalInfo::User(ClearCrossCrate::Set(BindingForm::ImplicitSelf(
|
||||
hir::ImplicitSelfKind::MutRef
|
||||
),)))
|
||||
decl.local_info(),
|
||||
LocalInfo::User(BindingForm::ImplicitSelf(hir::ImplicitSelfKind::MutRef))
|
||||
) {
|
||||
err.note(
|
||||
"as `Self` may be unsized, this call attempts to take `&mut &mut self`",
|
||||
@ -482,22 +478,18 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
||||
|
||||
match self.local_names[local] {
|
||||
Some(name) if !local_decl.from_compiler_desugaring() => {
|
||||
let label = match local_decl.local_info.as_deref().unwrap() {
|
||||
LocalInfo::User(ClearCrossCrate::Set(
|
||||
mir::BindingForm::ImplicitSelf(_),
|
||||
)) => {
|
||||
let label = match *local_decl.local_info() {
|
||||
LocalInfo::User(mir::BindingForm::ImplicitSelf(_)) => {
|
||||
let (span, suggestion) =
|
||||
suggest_ampmut_self(self.infcx.tcx, local_decl);
|
||||
Some((true, span, suggestion))
|
||||
}
|
||||
|
||||
LocalInfo::User(ClearCrossCrate::Set(mir::BindingForm::Var(
|
||||
mir::VarBindingForm {
|
||||
binding_mode: ty::BindingMode::BindByValue(_),
|
||||
opt_ty_info,
|
||||
..
|
||||
},
|
||||
))) => {
|
||||
LocalInfo::User(mir::BindingForm::Var(mir::VarBindingForm {
|
||||
binding_mode: ty::BindingMode::BindByValue(_),
|
||||
opt_ty_info,
|
||||
..
|
||||
})) => {
|
||||
// check if the RHS is from desugaring
|
||||
let opt_assignment_rhs_span =
|
||||
self.body.find_assignments(local).first().map(|&location| {
|
||||
@ -534,16 +526,15 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
||||
self.infcx.tcx,
|
||||
local_decl,
|
||||
opt_assignment_rhs_span,
|
||||
*opt_ty_info,
|
||||
opt_ty_info,
|
||||
)
|
||||
} else {
|
||||
match local_decl.local_info.as_deref() {
|
||||
Some(LocalInfo::User(ClearCrossCrate::Set(
|
||||
mir::BindingForm::Var(mir::VarBindingForm {
|
||||
opt_ty_info: None,
|
||||
..
|
||||
}),
|
||||
))) => {
|
||||
match local_decl.local_info() {
|
||||
LocalInfo::User(mir::BindingForm::Var(
|
||||
mir::VarBindingForm {
|
||||
opt_ty_info: None, ..
|
||||
},
|
||||
)) => {
|
||||
let (span, sugg) = suggest_ampmut_self(
|
||||
self.infcx.tcx,
|
||||
local_decl,
|
||||
@ -555,7 +546,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
||||
self.infcx.tcx,
|
||||
local_decl,
|
||||
opt_assignment_rhs_span,
|
||||
*opt_ty_info,
|
||||
opt_ty_info,
|
||||
),
|
||||
}
|
||||
};
|
||||
@ -564,21 +555,15 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
LocalInfo::User(ClearCrossCrate::Set(mir::BindingForm::Var(
|
||||
mir::VarBindingForm {
|
||||
binding_mode: ty::BindingMode::BindByReference(_),
|
||||
..
|
||||
},
|
||||
))) => {
|
||||
LocalInfo::User(mir::BindingForm::Var(mir::VarBindingForm {
|
||||
binding_mode: ty::BindingMode::BindByReference(_),
|
||||
..
|
||||
})) => {
|
||||
let pattern_span = local_decl.source_info.span;
|
||||
suggest_ref_mut(self.infcx.tcx, pattern_span)
|
||||
.map(|replacement| (true, pattern_span, replacement))
|
||||
}
|
||||
|
||||
LocalInfo::User(ClearCrossCrate::Clear) => {
|
||||
bug!("saw cleared local state")
|
||||
}
|
||||
|
||||
_ => unreachable!(),
|
||||
};
|
||||
|
||||
@ -1151,20 +1136,19 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
||||
pub fn mut_borrow_of_mutable_ref(local_decl: &LocalDecl<'_>, local_name: Option<Symbol>) -> bool {
|
||||
debug!("local_info: {:?}, ty.kind(): {:?}", local_decl.local_info, local_decl.ty.kind());
|
||||
|
||||
match local_decl.local_info.as_deref() {
|
||||
match *local_decl.local_info() {
|
||||
// Check if mutably borrowing a mutable reference.
|
||||
Some(LocalInfo::User(ClearCrossCrate::Set(mir::BindingForm::Var(
|
||||
mir::VarBindingForm {
|
||||
binding_mode: ty::BindingMode::BindByValue(Mutability::Not), ..
|
||||
},
|
||||
)))) => matches!(local_decl.ty.kind(), ty::Ref(_, _, hir::Mutability::Mut)),
|
||||
Some(LocalInfo::User(ClearCrossCrate::Set(mir::BindingForm::ImplicitSelf(kind)))) => {
|
||||
LocalInfo::User(mir::BindingForm::Var(mir::VarBindingForm {
|
||||
binding_mode: ty::BindingMode::BindByValue(Mutability::Not),
|
||||
..
|
||||
})) => matches!(local_decl.ty.kind(), ty::Ref(_, _, hir::Mutability::Mut)),
|
||||
LocalInfo::User(mir::BindingForm::ImplicitSelf(kind)) => {
|
||||
// Check if the user variable is a `&mut self` and we can therefore
|
||||
// suggest removing the `&mut`.
|
||||
//
|
||||
// Deliberately fall into this case for all implicit self types,
|
||||
// so that we don't fall in to the next case with them.
|
||||
*kind == hir::ImplicitSelfKind::MutRef
|
||||
kind == hir::ImplicitSelfKind::MutRef
|
||||
}
|
||||
_ if Some(kw::SelfLower) == local_name => {
|
||||
// Otherwise, check if the name is the `self` keyword - in which case
|
||||
|
@ -1180,10 +1180,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||
}
|
||||
}
|
||||
Some(l)
|
||||
if matches!(
|
||||
body.local_decls[l].local_info,
|
||||
Some(box LocalInfo::AggregateTemp)
|
||||
) =>
|
||||
if matches!(body.local_decls[l].local_info(), LocalInfo::AggregateTemp) =>
|
||||
{
|
||||
ConstraintCategory::Usage
|
||||
}
|
||||
@ -1684,7 +1681,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||
// - maybe we should make that a warning.
|
||||
return;
|
||||
}
|
||||
LocalKind::Var | LocalKind::Temp => {}
|
||||
LocalKind::Temp => {}
|
||||
}
|
||||
|
||||
// When `unsized_fn_params` or `unsized_locals` is enabled, only function calls
|
||||
|
@ -241,12 +241,6 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
||||
pub fn debug_introduce_local(&self, bx: &mut Bx, local: mir::Local) {
|
||||
let full_debug_info = bx.sess().opts.debuginfo == DebugInfo::Full;
|
||||
|
||||
// FIXME(eddyb) maybe name the return place as `_0` or `return`?
|
||||
if local == mir::RETURN_PLACE && !self.mir.local_decls[mir::RETURN_PLACE].is_user_variable()
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
let vars = match &self.per_local_var_debug_info {
|
||||
Some(per_local) => &per_local[local],
|
||||
None => return,
|
||||
@ -303,7 +297,8 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
||||
|
||||
let local_ref = &self.locals[local];
|
||||
|
||||
let name = if bx.sess().fewer_names() {
|
||||
// FIXME Should the return place be named?
|
||||
let name = if bx.sess().fewer_names() || local == mir::RETURN_PLACE {
|
||||
None
|
||||
} else {
|
||||
Some(match whole_local_var.or(fallback_var.clone()) {
|
||||
|
@ -643,7 +643,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
|
||||
if base_ty.is_unsafe_ptr() {
|
||||
if proj_base.is_empty() {
|
||||
let decl = &self.body.local_decls[place_local];
|
||||
if let Some(box LocalInfo::StaticRef { def_id, .. }) = decl.local_info {
|
||||
if let LocalInfo::StaticRef { def_id, .. } = *decl.local_info() {
|
||||
let span = decl.source_info.span;
|
||||
self.check_static(def_id, span);
|
||||
return;
|
||||
|
@ -704,7 +704,7 @@ pub mod ty {
|
||||
|
||||
fn importance(&self) -> DiagnosticImportance {
|
||||
match self.0 {
|
||||
mir::LocalKind::Var | mir::LocalKind::Temp => DiagnosticImportance::Secondary,
|
||||
mir::LocalKind::Temp => DiagnosticImportance::Secondary,
|
||||
mir::LocalKind::ReturnPointer | mir::LocalKind::Arg => {
|
||||
DiagnosticImportance::Primary
|
||||
}
|
||||
|
@ -106,8 +106,9 @@ impl<'tcx> Visitor<'tcx> for Collector<'_, 'tcx> {
|
||||
debug!("visit_local: index={:?} context={:?} location={:?}", index, context, location);
|
||||
// We're only interested in temporaries and the return place
|
||||
match self.ccx.body.local_kind(index) {
|
||||
LocalKind::Temp | LocalKind::ReturnPointer => {}
|
||||
LocalKind::Arg | LocalKind::Var => return,
|
||||
LocalKind::Arg => return,
|
||||
LocalKind::Temp if self.ccx.body.local_decls[index].is_user_variable() => return,
|
||||
LocalKind::ReturnPointer | LocalKind::Temp => {}
|
||||
}
|
||||
|
||||
// Ignore drops, if the temp gets promoted,
|
||||
|
@ -401,8 +401,6 @@ impl<'tcx> Body<'tcx> {
|
||||
LocalKind::ReturnPointer
|
||||
} else if index < self.arg_count + 1 {
|
||||
LocalKind::Arg
|
||||
} else if self.local_decls[local].is_user_variable() {
|
||||
LocalKind::Var
|
||||
} else {
|
||||
LocalKind::Temp
|
||||
}
|
||||
@ -572,6 +570,13 @@ impl<T> ClearCrossCrate<T> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_mut(&mut self) -> ClearCrossCrate<&mut T> {
|
||||
match self {
|
||||
ClearCrossCrate::Clear => ClearCrossCrate::Clear,
|
||||
ClearCrossCrate::Set(v) => ClearCrossCrate::Set(v),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn assert_crate_local(self) -> T {
|
||||
match self {
|
||||
ClearCrossCrate::Clear => bug!("unwrapping cross-crate data"),
|
||||
@ -661,9 +666,7 @@ impl Atom for Local {
|
||||
/// Classifies locals into categories. See `Body::local_kind`.
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Debug, HashStable)]
|
||||
pub enum LocalKind {
|
||||
/// User-declared variable binding.
|
||||
Var,
|
||||
/// Compiler-introduced temporary.
|
||||
/// User-declared variable binding or compiler-introduced temporary.
|
||||
Temp,
|
||||
/// Function argument.
|
||||
Arg,
|
||||
@ -760,7 +763,7 @@ pub struct LocalDecl<'tcx> {
|
||||
pub mutability: Mutability,
|
||||
|
||||
// FIXME(matthewjasper) Don't store in this in `Body`
|
||||
pub local_info: Option<Box<LocalInfo<'tcx>>>,
|
||||
pub local_info: ClearCrossCrate<Box<LocalInfo<'tcx>>>,
|
||||
|
||||
/// `true` if this is an internal local.
|
||||
///
|
||||
@ -778,13 +781,6 @@ pub struct LocalDecl<'tcx> {
|
||||
/// generator.
|
||||
pub internal: bool,
|
||||
|
||||
/// If this local is a temporary and `is_block_tail` is `Some`,
|
||||
/// then it is a temporary created for evaluation of some
|
||||
/// subexpression of some block's tail expression (with no
|
||||
/// intervening statement context).
|
||||
// FIXME(matthewjasper) Don't store in this in `Body`
|
||||
pub is_block_tail: Option<BlockTailInfo>,
|
||||
|
||||
/// The type of this local.
|
||||
pub ty: Ty<'tcx>,
|
||||
|
||||
@ -890,7 +886,7 @@ pub enum LocalInfo<'tcx> {
|
||||
/// The `BindingForm` is solely used for local diagnostics when generating
|
||||
/// warnings/errors when compiling the current crate, and therefore it need
|
||||
/// not be visible across crates.
|
||||
User(ClearCrossCrate<BindingForm<'tcx>>),
|
||||
User(BindingForm<'tcx>),
|
||||
/// A temporary created that references the static with the given `DefId`.
|
||||
StaticRef { def_id: DefId, is_thread_local: bool },
|
||||
/// A temporary created that references the const with the given `DefId`
|
||||
@ -898,13 +894,23 @@ pub enum LocalInfo<'tcx> {
|
||||
/// A temporary created during the creation of an aggregate
|
||||
/// (e.g. a temporary for `foo` in `MyStruct { my_field: foo }`)
|
||||
AggregateTemp,
|
||||
/// A temporary created for evaluation of some subexpression of some block's tail expression
|
||||
/// (with no intervening statement context).
|
||||
// FIXME(matthewjasper) Don't store in this in `Body`
|
||||
BlockTailTemp(BlockTailInfo),
|
||||
/// A temporary created during the pass `Derefer` to avoid it's retagging
|
||||
DerefTemp,
|
||||
/// A temporary created for borrow checking.
|
||||
FakeBorrow,
|
||||
/// A local without anything interesting about it.
|
||||
Boring,
|
||||
}
|
||||
|
||||
impl<'tcx> LocalDecl<'tcx> {
|
||||
pub fn local_info(&self) -> &LocalInfo<'tcx> {
|
||||
&**self.local_info.as_ref().assert_crate_local()
|
||||
}
|
||||
|
||||
/// Returns `true` only if local is a binding that can itself be
|
||||
/// made mutable via the addition of the `mut` keyword, namely
|
||||
/// something like the occurrences of `x` in:
|
||||
@ -913,15 +919,15 @@ impl<'tcx> LocalDecl<'tcx> {
|
||||
/// - or `match ... { C(x) => ... }`
|
||||
pub fn can_be_made_mutable(&self) -> bool {
|
||||
matches!(
|
||||
self.local_info,
|
||||
Some(box LocalInfo::User(ClearCrossCrate::Set(
|
||||
self.local_info(),
|
||||
LocalInfo::User(
|
||||
BindingForm::Var(VarBindingForm {
|
||||
binding_mode: ty::BindingMode::BindByValue(_),
|
||||
opt_ty_info: _,
|
||||
opt_match_place: _,
|
||||
pat_span: _,
|
||||
}) | BindingForm::ImplicitSelf(ImplicitSelfKind::Imm),
|
||||
)))
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@ -930,15 +936,15 @@ impl<'tcx> LocalDecl<'tcx> {
|
||||
/// mutable bindings, but the inverse does not necessarily hold).
|
||||
pub fn is_nonref_binding(&self) -> bool {
|
||||
matches!(
|
||||
self.local_info,
|
||||
Some(box LocalInfo::User(ClearCrossCrate::Set(
|
||||
self.local_info(),
|
||||
LocalInfo::User(
|
||||
BindingForm::Var(VarBindingForm {
|
||||
binding_mode: ty::BindingMode::BindByValue(_),
|
||||
opt_ty_info: _,
|
||||
opt_match_place: _,
|
||||
pat_span: _,
|
||||
}) | BindingForm::ImplicitSelf(_),
|
||||
)))
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@ -946,38 +952,35 @@ impl<'tcx> LocalDecl<'tcx> {
|
||||
/// parameter declared by the user.
|
||||
#[inline]
|
||||
pub fn is_user_variable(&self) -> bool {
|
||||
matches!(self.local_info, Some(box LocalInfo::User(_)))
|
||||
matches!(self.local_info(), LocalInfo::User(_))
|
||||
}
|
||||
|
||||
/// Returns `true` if this is a reference to a variable bound in a `match`
|
||||
/// expression that is used to access said variable for the guard of the
|
||||
/// match arm.
|
||||
pub fn is_ref_for_guard(&self) -> bool {
|
||||
matches!(
|
||||
self.local_info,
|
||||
Some(box LocalInfo::User(ClearCrossCrate::Set(BindingForm::RefForGuard)))
|
||||
)
|
||||
matches!(self.local_info(), LocalInfo::User(BindingForm::RefForGuard))
|
||||
}
|
||||
|
||||
/// Returns `Some` if this is a reference to a static item that is used to
|
||||
/// access that static.
|
||||
pub fn is_ref_to_static(&self) -> bool {
|
||||
matches!(self.local_info, Some(box LocalInfo::StaticRef { .. }))
|
||||
matches!(self.local_info(), LocalInfo::StaticRef { .. })
|
||||
}
|
||||
|
||||
/// Returns `Some` if this is a reference to a thread-local static item that is used to
|
||||
/// access that static.
|
||||
pub fn is_ref_to_thread_local(&self) -> bool {
|
||||
match self.local_info {
|
||||
Some(box LocalInfo::StaticRef { is_thread_local, .. }) => is_thread_local,
|
||||
match self.local_info() {
|
||||
LocalInfo::StaticRef { is_thread_local, .. } => *is_thread_local,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns `true` if this is a DerefTemp
|
||||
pub fn is_deref_temp(&self) -> bool {
|
||||
match self.local_info {
|
||||
Some(box LocalInfo::DerefTemp) => return true,
|
||||
match self.local_info() {
|
||||
LocalInfo::DerefTemp => return true,
|
||||
_ => (),
|
||||
}
|
||||
return false;
|
||||
@ -1001,9 +1004,8 @@ impl<'tcx> LocalDecl<'tcx> {
|
||||
pub fn with_source_info(ty: Ty<'tcx>, source_info: SourceInfo) -> Self {
|
||||
LocalDecl {
|
||||
mutability: Mutability::Mut,
|
||||
local_info: None,
|
||||
local_info: ClearCrossCrate::Set(Box::new(LocalInfo::Boring)),
|
||||
internal: false,
|
||||
is_block_tail: None,
|
||||
ty,
|
||||
user_ty: None,
|
||||
source_info,
|
||||
@ -1023,14 +1025,6 @@ impl<'tcx> LocalDecl<'tcx> {
|
||||
self.mutability = Mutability::Not;
|
||||
self
|
||||
}
|
||||
|
||||
/// Converts `self` into same `LocalDecl` except tagged as internal temporary.
|
||||
#[inline]
|
||||
pub fn block_tail(mut self, info: BlockTailInfo) -> Self {
|
||||
assert!(self.is_block_tail.is_none());
|
||||
self.is_block_tail = Some(info);
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable)]
|
||||
@ -3091,7 +3085,7 @@ mod size_asserts {
|
||||
use rustc_data_structures::static_assert_size;
|
||||
// tidy-alphabetical-start
|
||||
static_assert_size!(BasicBlockData<'_>, 144);
|
||||
static_assert_size!(LocalDecl<'_>, 56);
|
||||
static_assert_size!(LocalDecl<'_>, 40);
|
||||
static_assert_size!(Statement<'_>, 32);
|
||||
static_assert_size!(StatementKind<'_>, 16);
|
||||
static_assert_size!(Terminator<'_>, 112);
|
||||
|
@ -72,12 +72,12 @@ impl<'tcx> MirPatch<'tcx> {
|
||||
&mut self,
|
||||
ty: Ty<'tcx>,
|
||||
span: Span,
|
||||
local_info: Option<Box<LocalInfo<'tcx>>>,
|
||||
local_info: LocalInfo<'tcx>,
|
||||
) -> Local {
|
||||
let index = self.next_local;
|
||||
self.next_local += 1;
|
||||
let mut new_decl = LocalDecl::new(ty, span).internal();
|
||||
new_decl.local_info = local_info;
|
||||
**new_decl.local_info.as_mut().assert_crate_local() = local_info;
|
||||
self.new_locals.push(new_decl);
|
||||
Local::new(index as usize)
|
||||
}
|
||||
|
@ -804,7 +804,6 @@ macro_rules! make_mir_visitor {
|
||||
source_info,
|
||||
internal: _,
|
||||
local_info: _,
|
||||
is_block_tail: _,
|
||||
} = local_decl;
|
||||
|
||||
self.visit_ty($(& $mutability)? *ty, TyContext::LocalDecl {
|
||||
|
@ -20,7 +20,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||
expr: &Expr<'tcx>,
|
||||
) -> BlockAnd<Operand<'tcx>> {
|
||||
let local_scope = self.local_scope();
|
||||
self.as_operand(block, Some(local_scope), expr, None, NeedsTemporary::Maybe)
|
||||
self.as_operand(block, Some(local_scope), expr, LocalInfo::Boring, NeedsTemporary::Maybe)
|
||||
}
|
||||
|
||||
/// Returns an operand suitable for use until the end of the current scope expression and
|
||||
@ -102,7 +102,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||
mut block: BasicBlock,
|
||||
scope: Option<region::Scope>,
|
||||
expr: &Expr<'tcx>,
|
||||
local_info: Option<Box<LocalInfo<'tcx>>>,
|
||||
local_info: LocalInfo<'tcx>,
|
||||
needs_temporary: NeedsTemporary,
|
||||
) -> BlockAnd<Operand<'tcx>> {
|
||||
let this = self;
|
||||
@ -124,8 +124,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||
}
|
||||
Category::Constant | Category::Place | Category::Rvalue(..) => {
|
||||
let operand = unpack!(block = this.as_temp(block, scope, expr, Mutability::Mut));
|
||||
if this.local_decls[operand].local_info.is_none() {
|
||||
this.local_decls[operand].local_info = local_info;
|
||||
// Overwrite temp local info if we have something more interesting to record.
|
||||
if !matches!(local_info, LocalInfo::Boring) {
|
||||
let decl_info = this.local_decls[operand].local_info.as_mut().assert_crate_local();
|
||||
if let LocalInfo::Boring | LocalInfo::BlockTailTemp(_) = **decl_info {
|
||||
**decl_info = local_info;
|
||||
}
|
||||
}
|
||||
block.and(Operand::Move(Place::from(operand)))
|
||||
}
|
||||
@ -178,6 +182,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
this.as_operand(block, scope, expr, None, NeedsTemporary::Maybe)
|
||||
this.as_operand(block, scope, expr, LocalInfo::Boring, NeedsTemporary::Maybe)
|
||||
}
|
||||
}
|
||||
|
@ -64,7 +64,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||
block,
|
||||
scope,
|
||||
&this.thir[value],
|
||||
None,
|
||||
LocalInfo::Boring,
|
||||
NeedsTemporary::No
|
||||
)
|
||||
);
|
||||
@ -74,18 +74,18 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||
ExprKind::Binary { op, lhs, rhs } => {
|
||||
let lhs = unpack!(
|
||||
block =
|
||||
this.as_operand(block, scope, &this.thir[lhs], None, NeedsTemporary::Maybe)
|
||||
this.as_operand(block, scope, &this.thir[lhs], LocalInfo::Boring, NeedsTemporary::Maybe)
|
||||
);
|
||||
let rhs = unpack!(
|
||||
block =
|
||||
this.as_operand(block, scope, &this.thir[rhs], None, NeedsTemporary::No)
|
||||
this.as_operand(block, scope, &this.thir[rhs], LocalInfo::Boring, NeedsTemporary::No)
|
||||
);
|
||||
this.build_binary_op(block, op, expr_span, expr.ty, lhs, rhs)
|
||||
}
|
||||
ExprKind::Unary { op, arg } => {
|
||||
let arg = unpack!(
|
||||
block =
|
||||
this.as_operand(block, scope, &this.thir[arg], None, NeedsTemporary::No)
|
||||
this.as_operand(block, scope, &this.thir[arg], LocalInfo::Boring, NeedsTemporary::No)
|
||||
);
|
||||
// Check for -MIN on signed integers
|
||||
if this.check_overflow && op == UnOp::Neg && expr.ty.is_signed() {
|
||||
@ -260,7 +260,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||
} else {
|
||||
let ty = source.ty;
|
||||
let source = unpack!(
|
||||
block = this.as_operand(block, scope, source, None, NeedsTemporary::No)
|
||||
block = this.as_operand(block, scope, source, LocalInfo::Boring, NeedsTemporary::No)
|
||||
);
|
||||
(source, ty)
|
||||
};
|
||||
@ -273,7 +273,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||
ExprKind::Pointer { cast, source } => {
|
||||
let source = unpack!(
|
||||
block =
|
||||
this.as_operand(block, scope, &this.thir[source], None, NeedsTemporary::No)
|
||||
this.as_operand(block, scope, &this.thir[source], LocalInfo::Boring, NeedsTemporary::No)
|
||||
);
|
||||
block.and(Rvalue::Cast(CastKind::Pointer(cast), source, expr.ty))
|
||||
}
|
||||
@ -315,7 +315,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||
block,
|
||||
scope,
|
||||
&this.thir[f],
|
||||
None,
|
||||
LocalInfo::Boring,
|
||||
NeedsTemporary::Maybe
|
||||
)
|
||||
)
|
||||
@ -336,7 +336,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||
block,
|
||||
scope,
|
||||
&this.thir[f],
|
||||
None,
|
||||
LocalInfo::Boring,
|
||||
NeedsTemporary::Maybe
|
||||
)
|
||||
)
|
||||
@ -424,7 +424,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||
block,
|
||||
scope,
|
||||
upvar,
|
||||
None,
|
||||
LocalInfo::Boring,
|
||||
NeedsTemporary::Maybe
|
||||
)
|
||||
)
|
||||
@ -503,7 +503,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||
Some(Category::Rvalue(RvalueFunc::AsRvalue) | Category::Constant)
|
||||
));
|
||||
let operand =
|
||||
unpack!(block = this.as_operand(block, scope, expr, None, NeedsTemporary::No));
|
||||
unpack!(block = this.as_operand(block, scope, expr, LocalInfo::Boring, NeedsTemporary::No));
|
||||
block.and(Rvalue::Use(operand))
|
||||
}
|
||||
}
|
||||
@ -663,7 +663,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||
} else {
|
||||
// For a non-const, we may need to generate an appropriate `Drop`
|
||||
let value_operand =
|
||||
unpack!(block = this.as_operand(block, scope, value, None, NeedsTemporary::No));
|
||||
unpack!(block = this.as_operand(block, scope, value, LocalInfo::Boring, NeedsTemporary::No));
|
||||
if let Operand::Move(to_drop) = value_operand {
|
||||
let success = this.cfg.start_new_block();
|
||||
this.cfg.terminate(
|
||||
|
@ -49,29 +49,28 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||
}
|
||||
|
||||
debug!("creating temp {:?} with block_context: {:?}", local_decl, this.block_context);
|
||||
// Find out whether this temp is being created within the
|
||||
// tail expression of a block whose result is ignored.
|
||||
if let Some(tail_info) = this.block_context.currently_in_block_tail() {
|
||||
local_decl = local_decl.block_tail(tail_info);
|
||||
}
|
||||
match expr.kind {
|
||||
let local_info = match expr.kind {
|
||||
ExprKind::StaticRef { def_id, .. } => {
|
||||
assert!(!this.tcx.is_thread_local_static(def_id));
|
||||
local_decl.internal = true;
|
||||
local_decl.local_info =
|
||||
Some(Box::new(LocalInfo::StaticRef { def_id, is_thread_local: false }));
|
||||
LocalInfo::StaticRef { def_id, is_thread_local: false }
|
||||
}
|
||||
ExprKind::ThreadLocalRef(def_id) => {
|
||||
assert!(this.tcx.is_thread_local_static(def_id));
|
||||
local_decl.internal = true;
|
||||
local_decl.local_info =
|
||||
Some(Box::new(LocalInfo::StaticRef { def_id, is_thread_local: true }));
|
||||
LocalInfo::StaticRef { def_id, is_thread_local: true }
|
||||
}
|
||||
ExprKind::NamedConst { def_id, .. } | ExprKind::ConstParam { def_id, .. } => {
|
||||
local_decl.local_info = Some(Box::new(LocalInfo::ConstRef { def_id }));
|
||||
LocalInfo::ConstRef { def_id }
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
// Find out whether this temp is being created within the
|
||||
// tail expression of a block whose result is ignored.
|
||||
_ if let Some(tail_info) = this.block_context.currently_in_block_tail() => {
|
||||
LocalInfo::BlockTailTemp(tail_info)
|
||||
}
|
||||
_ => LocalInfo::Boring,
|
||||
};
|
||||
**local_decl.local_info.as_mut().assert_crate_local() = local_info;
|
||||
this.local_decls.push(local_decl)
|
||||
};
|
||||
let temp_place = Place::from(temp);
|
||||
|
@ -328,7 +328,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||
let fields_map: FxHashMap<_, _> = fields
|
||||
.into_iter()
|
||||
.map(|f| {
|
||||
let local_info = Box::new(LocalInfo::AggregateTemp);
|
||||
(
|
||||
f.name,
|
||||
unpack!(
|
||||
@ -336,7 +335,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||
block,
|
||||
Some(scope),
|
||||
&this.thir[f.expr],
|
||||
Some(local_info),
|
||||
LocalInfo::AggregateTemp,
|
||||
NeedsTemporary::Maybe,
|
||||
)
|
||||
),
|
||||
@ -526,7 +525,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||
block,
|
||||
Some(scope),
|
||||
&this.thir[value],
|
||||
None,
|
||||
LocalInfo::Boring,
|
||||
NeedsTemporary::No
|
||||
)
|
||||
);
|
||||
|
@ -607,9 +607,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||
// };
|
||||
// ```
|
||||
if let Some(place) = initializer.try_to_place(self) {
|
||||
let Some(box LocalInfo::User(ClearCrossCrate::Set(BindingForm::Var(
|
||||
let LocalInfo::User(BindingForm::Var(
|
||||
VarBindingForm { opt_match_place: Some((ref mut match_place, _)), .. },
|
||||
)))) = self.local_decls[local].local_info else {
|
||||
)) = **self.local_decls[local].local_info.as_mut().assert_crate_local() else {
|
||||
bug!("Let binding to non-user variable.")
|
||||
};
|
||||
*match_place = Some(place);
|
||||
@ -1754,7 +1754,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||
let fake_borrow_ty = tcx.mk_imm_ref(tcx.lifetimes.re_erased, fake_borrow_deref_ty);
|
||||
let mut fake_borrow_temp = LocalDecl::new(fake_borrow_ty, temp_span);
|
||||
fake_borrow_temp.internal = self.local_decls[matched_place.local].internal;
|
||||
fake_borrow_temp.local_info = Some(Box::new(LocalInfo::FakeBorrow));
|
||||
fake_borrow_temp.local_info = ClearCrossCrate::Set(Box::new(LocalInfo::FakeBorrow));
|
||||
let fake_borrow_temp = self.local_decls.push(fake_borrow_temp);
|
||||
|
||||
(matched_place, fake_borrow_temp)
|
||||
@ -2224,8 +2224,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||
user_ty: if user_ty.is_empty() { None } else { Some(Box::new(user_ty)) },
|
||||
source_info,
|
||||
internal: false,
|
||||
is_block_tail: None,
|
||||
local_info: Some(Box::new(LocalInfo::User(ClearCrossCrate::Set(BindingForm::Var(
|
||||
local_info: ClearCrossCrate::Set(Box::new(LocalInfo::User(BindingForm::Var(
|
||||
VarBindingForm {
|
||||
binding_mode,
|
||||
// hypothetically, `visit_primary_bindings` could try to unzip
|
||||
@ -2236,7 +2235,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||
opt_match_place,
|
||||
pat_span,
|
||||
},
|
||||
))))),
|
||||
)))),
|
||||
};
|
||||
let for_arm_body = self.local_decls.push(local);
|
||||
self.var_debug_info.push(VarDebugInfo {
|
||||
@ -2253,10 +2252,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||
user_ty: None,
|
||||
source_info,
|
||||
internal: false,
|
||||
is_block_tail: None,
|
||||
local_info: Some(Box::new(LocalInfo::User(ClearCrossCrate::Set(
|
||||
BindingForm::RefForGuard,
|
||||
)))),
|
||||
local_info: ClearCrossCrate::Set(Box::new(LocalInfo::User(BindingForm::RefForGuard))),
|
||||
});
|
||||
self.var_debug_info.push(VarDebugInfo {
|
||||
name,
|
||||
|
@ -876,20 +876,20 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||
} => {
|
||||
self.local_decls[local].mutability = mutability;
|
||||
self.local_decls[local].source_info.scope = self.source_scope;
|
||||
self.local_decls[local].local_info = if let Some(kind) = param.self_kind {
|
||||
Some(Box::new(LocalInfo::User(ClearCrossCrate::Set(
|
||||
**self.local_decls[local].local_info.as_mut().assert_crate_local() = if let Some(kind) = param.self_kind {
|
||||
LocalInfo::User(
|
||||
BindingForm::ImplicitSelf(kind),
|
||||
))))
|
||||
)
|
||||
} else {
|
||||
let binding_mode = ty::BindingMode::BindByValue(mutability);
|
||||
Some(Box::new(LocalInfo::User(ClearCrossCrate::Set(BindingForm::Var(
|
||||
LocalInfo::User(BindingForm::Var(
|
||||
VarBindingForm {
|
||||
binding_mode,
|
||||
opt_ty_info: param.ty_span,
|
||||
opt_match_place: Some((None, span)),
|
||||
pat_span: span,
|
||||
},
|
||||
)))))
|
||||
))
|
||||
};
|
||||
self.var_indices.insert(var, LocalsForNode::One(local));
|
||||
}
|
||||
|
@ -24,7 +24,7 @@ struct ConstMutationChecker<'a, 'tcx> {
|
||||
|
||||
impl<'tcx> ConstMutationChecker<'_, 'tcx> {
|
||||
fn is_const_item(&self, local: Local) -> Option<DefId> {
|
||||
if let Some(box LocalInfo::ConstRef { def_id }) = self.body.local_decls[local].local_info {
|
||||
if let LocalInfo::ConstRef { def_id } = *self.body.local_decls[local].local_info() {
|
||||
Some(def_id)
|
||||
} else {
|
||||
None
|
||||
|
@ -182,7 +182,7 @@ impl<'tcx> Visitor<'tcx> for UnsafetyChecker<'_, 'tcx> {
|
||||
// If the projection root is an artificial local that we introduced when
|
||||
// desugaring `static`, give a more specific error message
|
||||
// (avoid the general "raw pointer" clause below, that would only be confusing).
|
||||
if let Some(box LocalInfo::StaticRef { def_id, .. }) = decl.local_info {
|
||||
if let LocalInfo::StaticRef { def_id, .. } = *decl.local_info() {
|
||||
if self.tcx.is_mutable_static(def_id) {
|
||||
self.require_unsafe(
|
||||
UnsafetyViolationKind::General,
|
||||
|
@ -40,7 +40,7 @@ impl<'tcx> MutVisitor<'tcx> for DerefChecker<'tcx> {
|
||||
let temp = self.patcher.new_internal_with_info(
|
||||
ty,
|
||||
self.local_decls[p_ref.local].source_info.span,
|
||||
Some(Box::new(LocalInfo::DerefTemp)),
|
||||
LocalInfo::DerefTemp,
|
||||
);
|
||||
|
||||
// We are adding current p_ref's projections to our
|
||||
|
@ -788,7 +788,7 @@ impl<'tcx> Visitor<'tcx> for FindAssignments<'_, '_, 'tcx> {
|
||||
fn is_local_required(local: Local, body: &Body<'_>) -> bool {
|
||||
match body.local_kind(local) {
|
||||
LocalKind::Arg | LocalKind::ReturnPointer => true,
|
||||
LocalKind::Var | LocalKind::Temp => false,
|
||||
LocalKind::Temp => false,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -924,13 +924,19 @@ fn compute_layout<'tcx>(
|
||||
debug!(?decl);
|
||||
|
||||
let ignore_for_traits = if tcx.sess.opts.unstable_opts.drop_tracking_mir {
|
||||
// Do not `assert_crate_local` here, as post-borrowck cleanup may have already cleared
|
||||
// the information. This is alright, since `ignore_for_traits` is only relevant when
|
||||
// this code runs on pre-cleanup MIR, and `ignore_for_traits = false` is the safer
|
||||
// default.
|
||||
match decl.local_info {
|
||||
// Do not include raw pointers created from accessing `static` items, as those could
|
||||
// well be re-created by another access to the same static.
|
||||
Some(box LocalInfo::StaticRef { is_thread_local, .. }) => !is_thread_local,
|
||||
ClearCrossCrate::Set(box LocalInfo::StaticRef { is_thread_local, .. }) => {
|
||||
!is_thread_local
|
||||
}
|
||||
// Fake borrows are only read by fake reads, so do not have any reality in
|
||||
// post-analysis MIR.
|
||||
Some(box LocalInfo::FakeBorrow) => true,
|
||||
ClearCrossCrate::Set(box LocalInfo::FakeBorrow) => true,
|
||||
_ => false,
|
||||
}
|
||||
} else {
|
||||
|
@ -29,9 +29,9 @@ use rustc_hir::intravisit::{self, Visitor};
|
||||
use rustc_index::vec::IndexVec;
|
||||
use rustc_middle::mir::visit::Visitor as _;
|
||||
use rustc_middle::mir::{
|
||||
traversal, AnalysisPhase, Body, ConstQualifs, Constant, LocalDecl, MirPass, MirPhase, Operand,
|
||||
Place, ProjectionElem, Promoted, RuntimePhase, Rvalue, SourceInfo, Statement, StatementKind,
|
||||
TerminatorKind,
|
||||
traversal, AnalysisPhase, Body, ClearCrossCrate, ConstQualifs, Constant, LocalDecl, MirPass,
|
||||
MirPhase, Operand, Place, ProjectionElem, Promoted, RuntimePhase, Rvalue, SourceInfo,
|
||||
Statement, StatementKind, TerminatorKind,
|
||||
};
|
||||
use rustc_middle::ty::query::Providers;
|
||||
use rustc_middle::ty::{self, TyCtxt, TypeVisitableExt};
|
||||
@ -532,6 +532,12 @@ fn run_runtime_cleanup_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
|
||||
&[&lower_intrinsics::LowerIntrinsics, &simplify::SimplifyCfg::new("elaborate-drops")];
|
||||
|
||||
pm::run_passes(tcx, body, passes, Some(MirPhase::Runtime(RuntimePhase::PostCleanup)));
|
||||
|
||||
// Clear this by anticipation. Optimizations and runtime MIR have no reason to look
|
||||
// into this information, which is meant for borrowck diagnostics.
|
||||
for decl in &mut body.local_decls {
|
||||
decl.local_info = ClearCrossCrate::Clear;
|
||||
}
|
||||
}
|
||||
|
||||
fn run_optimization_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
|
||||
|
@ -102,7 +102,7 @@ fn local_eligible_for_nrvo(body: &mut mir::Body<'_>) -> Option<Local> {
|
||||
mir::LocalKind::Arg => return None,
|
||||
|
||||
mir::LocalKind::ReturnPointer => bug!("Return place was assigned to itself?"),
|
||||
mir::LocalKind::Var | mir::LocalKind::Temp => {}
|
||||
mir::LocalKind::Temp => {}
|
||||
}
|
||||
|
||||
// If multiple different locals are copied to the return place. We can't pick a
|
||||
|
@ -13,8 +13,8 @@ pub fn sum(x: u32, y: u32) -> u32 {
|
||||
|
||||
// NO-LABEL: define{{.*}}i32 @sum(i32 noundef %x, i32 noundef %y)
|
||||
// NO-NEXT: start:
|
||||
// NO-NEXT: %z = add i32 %y, %x
|
||||
// NO-NEXT: ret i32 %z
|
||||
// NO-NEXT: %0 = add i32 %y, %x
|
||||
// NO-NEXT: ret i32 %0
|
||||
let z = x + y;
|
||||
z
|
||||
}
|
||||
|
@ -9,7 +9,7 @@ pub fn test(a: u32, b: u32) -> u32 {
|
||||
// CHECK: %c = add i32 %a, %b
|
||||
let d = c;
|
||||
let e = d * a;
|
||||
// CHECK-NEXT: %e = mul i32 %c, %a
|
||||
// CHECK-NEXT: %0 = mul i32 %c, %a
|
||||
e
|
||||
// CHECK-NEXT: ret i32 %e
|
||||
// CHECK-NEXT: ret i32 %0
|
||||
}
|
||||
|
@ -193,9 +193,9 @@ pub fn add_initializer() {
|
||||
}
|
||||
|
||||
#[cfg(not(any(cfail1,cfail4)))]
|
||||
#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,typeck,optimized_mir")]
|
||||
#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,typeck")]
|
||||
#[rustc_clean(cfg="cfail3")]
|
||||
#[rustc_clean(cfg="cfail5", except="hir_owner_nodes,typeck,optimized_mir")]
|
||||
#[rustc_clean(cfg="cfail5", except="hir_owner_nodes,typeck")]
|
||||
#[rustc_clean(cfg="cfail6")]
|
||||
pub fn add_initializer() {
|
||||
let _x: i16 = 3i16;
|
||||
|
@ -12,7 +12,6 @@
|
||||
let mut _7: !; // in scope 0 at $DIR/separate_const_switch.rs:+1:9: +1:10
|
||||
let mut _8: std::result::Result<std::convert::Infallible, i32>; // in scope 0 at $DIR/separate_const_switch.rs:+1:9: +1:10
|
||||
let _9: i32; // in scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10
|
||||
let mut _16: i32; // in scope 0 at $SRC_DIR/core/src/result.rs:LL:COL
|
||||
scope 1 {
|
||||
debug residual => _6; // in scope 1 at $DIR/separate_const_switch.rs:+1:9: +1:10
|
||||
scope 2 {
|
||||
@ -23,7 +22,7 @@
|
||||
scope 9 {
|
||||
debug e => _14; // in scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
|
||||
scope 10 (inlined <i32 as From<i32>>::from) { // at $SRC_DIR/core/src/result.rs:LL:COL
|
||||
debug t => _16; // in scope 10 at $SRC_DIR/core/src/convert/mod.rs:LL:COL
|
||||
debug t => _14; // in scope 10 at $SRC_DIR/core/src/convert/mod.rs:LL:COL
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -90,10 +89,7 @@
|
||||
StorageLive(_14); // scope 2 at $DIR/separate_const_switch.rs:+1:8: +1:10
|
||||
_14 = move ((_8 as Err).0: i32); // scope 8 at $SRC_DIR/core/src/result.rs:LL:COL
|
||||
StorageLive(_15); // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
|
||||
StorageLive(_16); // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
|
||||
_16 = move _14; // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
|
||||
_15 = move _16; // scope 10 at $SRC_DIR/core/src/convert/mod.rs:LL:COL
|
||||
StorageDead(_16); // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
|
||||
_15 = move _14; // scope 10 at $SRC_DIR/core/src/convert/mod.rs:LL:COL
|
||||
_0 = Result::<i32, i32>::Err(move _15); // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
|
||||
StorageDead(_15); // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
|
||||
StorageDead(_14); // scope 2 at $DIR/separate_const_switch.rs:+1:8: +1:10
|
||||
|
Loading…
x
Reference in New Issue
Block a user