remove DerefTemp and CopyFromDeref from runtime mir
This commit is contained in:
parent
8111a2d6da
commit
fc959e5464
19 changed files with 122 additions and 82 deletions
|
|
@ -1539,24 +1539,6 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
|
|||
self.consume_operand(location, (operand, span), state)
|
||||
}
|
||||
|
||||
&Rvalue::CopyForDeref(place) => {
|
||||
self.access_place(
|
||||
location,
|
||||
(place, span),
|
||||
(Deep, Read(ReadKind::Copy)),
|
||||
LocalMutationIsAllowed::No,
|
||||
state,
|
||||
);
|
||||
|
||||
// Finally, check if path was already moved.
|
||||
self.check_if_path_or_subpath_is_moved(
|
||||
location,
|
||||
InitializationRequiringAction::Use,
|
||||
(place.as_ref(), span),
|
||||
state,
|
||||
);
|
||||
}
|
||||
|
||||
&Rvalue::Discriminant(place) => {
|
||||
let af = match *rvalue {
|
||||
Rvalue::Discriminant(..) => None,
|
||||
|
|
@ -1618,6 +1600,8 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
|
|||
Rvalue::WrapUnsafeBinder(op, _) => {
|
||||
self.consume_operand(location, (op, span), state);
|
||||
}
|
||||
|
||||
Rvalue::CopyForDeref(_) => bug!("`CopyForDeref` in borrowck"),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -301,11 +301,6 @@ impl<'a, 'tcx> LoanInvalidationsGenerator<'a, 'tcx> {
|
|||
| Rvalue::Cast(_ /*cast_kind*/, operand, _ /*ty*/)
|
||||
| Rvalue::ShallowInitBox(operand, _ /*ty*/) => self.consume_operand(location, operand),
|
||||
|
||||
&Rvalue::CopyForDeref(place) => {
|
||||
let op = &Operand::Copy(place);
|
||||
self.consume_operand(location, op);
|
||||
}
|
||||
|
||||
&Rvalue::Discriminant(place) => {
|
||||
self.access_place(
|
||||
location,
|
||||
|
|
@ -331,6 +326,8 @@ impl<'a, 'tcx> LoanInvalidationsGenerator<'a, 'tcx> {
|
|||
Rvalue::WrapUnsafeBinder(op, _) => {
|
||||
self.consume_operand(location, op);
|
||||
}
|
||||
|
||||
Rvalue::CopyForDeref(_) => bug!("`CopyForDeref` in borrowck"),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -600,11 +600,6 @@ fn codegen_stmt<'tcx>(fx: &mut FunctionCx<'_, '_, 'tcx>, cur_block: Block, stmt:
|
|||
let val = codegen_operand(fx, operand);
|
||||
lval.write_cvalue(fx, val);
|
||||
}
|
||||
Rvalue::CopyForDeref(place) => {
|
||||
let cplace = codegen_place(fx, place);
|
||||
let val = cplace.to_cvalue(fx);
|
||||
lval.write_cvalue(fx, val)
|
||||
}
|
||||
Rvalue::Ref(_, _, place) | Rvalue::RawPtr(_, place) => {
|
||||
let place = codegen_place(fx, place);
|
||||
let ref_ = place.place_ref(fx, lval.layout());
|
||||
|
|
@ -928,6 +923,7 @@ fn codegen_stmt<'tcx>(fx: &mut FunctionCx<'_, '_, 'tcx>, cur_block: Block, stmt:
|
|||
let operand = codegen_operand(fx, operand);
|
||||
lval.write_cvalue_transmute(fx, operand);
|
||||
}
|
||||
Rvalue::CopyForDeref(_) => bug!("`CopyForDeref` in codegen"),
|
||||
}
|
||||
}
|
||||
StatementKind::StorageLive(_)
|
||||
|
|
|
|||
|
|
@ -504,9 +504,6 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||
self.codegen_place_to_pointer(bx, place, mk_ref)
|
||||
}
|
||||
|
||||
mir::Rvalue::CopyForDeref(place) => {
|
||||
self.codegen_operand(bx, &mir::Operand::Copy(place))
|
||||
}
|
||||
mir::Rvalue::RawPtr(kind, place) => {
|
||||
let mk_ptr = move |tcx: TyCtxt<'tcx>, ty: Ty<'tcx>| {
|
||||
Ty::new_ptr(tcx, ty, kind.to_mutbl_lossy())
|
||||
|
|
@ -742,6 +739,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||
let layout = bx.cx().layout_of(binder_ty);
|
||||
OperandRef { val: operand.val, layout }
|
||||
}
|
||||
mir::Rvalue::CopyForDeref(_) => bug!("`CopyForDeref` in codegen"),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -234,7 +234,7 @@ where
|
|||
|
||||
Rvalue::Discriminant(place) => in_place::<Q, _>(cx, in_local, place.as_ref()),
|
||||
|
||||
Rvalue::CopyForDeref(place) => in_place::<Q, _>(cx, in_local, place.as_ref()),
|
||||
Rvalue::CopyForDeref(_) => bug!("`CopyForDeref` in runtime MIR"),
|
||||
|
||||
Rvalue::Use(operand)
|
||||
| Rvalue::Repeat(operand, _)
|
||||
|
|
|
|||
|
|
@ -188,10 +188,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
|
|||
self.copy_op(&op, &dest)?;
|
||||
}
|
||||
|
||||
CopyForDeref(place) => {
|
||||
let op = self.eval_place_to_op(place, Some(dest.layout))?;
|
||||
self.copy_op(&op, &dest)?;
|
||||
}
|
||||
CopyForDeref(_) => bug!("`CopyForDeref` in runtime MIR"),
|
||||
|
||||
BinaryOp(bin_op, box (ref left, ref right)) => {
|
||||
let layout = util::binop_left_homogeneous(bin_op).then_some(dest.layout);
|
||||
|
|
|
|||
|
|
@ -1065,7 +1065,11 @@ pub enum LocalInfo<'tcx> {
|
|||
/// A temporary created during evaluating `if` predicate, possibly for pattern matching for `let`s,
|
||||
/// and subject to Edition 2024 temporary lifetime rules
|
||||
IfThenRescopeTemp { if_then: HirId },
|
||||
/// A temporary created during the pass `Derefer` to avoid it's retagging
|
||||
/// A temporary created during the pass `Derefer` treated as a transparent alias
|
||||
/// for the place its copied from by analysis passes such as `AddRetag` and `ElaborateDrops`.
|
||||
///
|
||||
/// It may only be written to by a `CopyForDeref` and otherwise only accessed through a deref.
|
||||
/// In runtime MIR, it is replaced with a normal `Boring` local.
|
||||
DerefTemp,
|
||||
/// A temporary created for borrow checking.
|
||||
FakeBorrow,
|
||||
|
|
|
|||
|
|
@ -130,7 +130,9 @@ pub enum RuntimePhase {
|
|||
/// * [`TerminatorKind::Yield`]
|
||||
/// * [`TerminatorKind::CoroutineDrop`]
|
||||
/// * [`Rvalue::Aggregate`] for any `AggregateKind` except `Array`
|
||||
/// * [`Rvalue::CopyForDeref`]
|
||||
/// * [`PlaceElem::OpaqueCast`]
|
||||
/// * [`LocalInfo::DerefTemp`](super::LocalInfo::DerefTemp)
|
||||
///
|
||||
/// And the following variants are allowed:
|
||||
/// * [`StatementKind::Retag`]
|
||||
|
|
@ -1460,11 +1462,13 @@ pub enum Rvalue<'tcx> {
|
|||
/// A CopyForDeref is equivalent to a read from a place at the
|
||||
/// codegen level, but is treated specially by drop elaboration. When such a read happens, it
|
||||
/// is guaranteed (via nature of the mir_opt `Derefer` in rustc_mir_transform/src/deref_separator)
|
||||
/// that the only use of the returned value is a deref operation, immediately
|
||||
/// followed by one or more projections. Drop elaboration treats this rvalue as if the
|
||||
/// that the returned value is written into a `DerefTemp` local and that its only use is a deref operation,
|
||||
/// immediately followed by one or more projections. Drop elaboration treats this rvalue as if the
|
||||
/// read never happened and just projects further. This allows simplifying various MIR
|
||||
/// optimizations and codegen backends that previously had to handle deref operations anywhere
|
||||
/// in a place.
|
||||
///
|
||||
/// Disallowed in runtime MIR and is replaced by normal copies.
|
||||
CopyForDeref(Place<'tcx>),
|
||||
|
||||
/// Wraps a value in an unsafe binder.
|
||||
|
|
|
|||
|
|
@ -74,9 +74,7 @@ fn fully_moved_locals(ssa: &SsaLocals, body: &Body<'_>) -> DenseBitSet<Local> {
|
|||
let mut fully_moved = DenseBitSet::new_filled(body.local_decls.len());
|
||||
|
||||
for (_, rvalue, _) in ssa.assignments(body) {
|
||||
let (Rvalue::Use(Operand::Copy(place) | Operand::Move(place))
|
||||
| Rvalue::CopyForDeref(place)) = rvalue
|
||||
else {
|
||||
let Rvalue::Use(Operand::Copy(place) | Operand::Move(place)) = rvalue else {
|
||||
continue;
|
||||
};
|
||||
|
||||
|
|
@ -85,7 +83,7 @@ fn fully_moved_locals(ssa: &SsaLocals, body: &Body<'_>) -> DenseBitSet<Local> {
|
|||
continue;
|
||||
}
|
||||
|
||||
if let Rvalue::Use(Operand::Copy(_)) | Rvalue::CopyForDeref(_) = rvalue {
|
||||
if let Rvalue::Use(Operand::Copy(_)) = rvalue {
|
||||
fully_moved.remove(rhs);
|
||||
}
|
||||
}
|
||||
|
|
@ -146,8 +144,7 @@ impl<'tcx> MutVisitor<'tcx> for Replacer<'_, 'tcx> {
|
|||
|
||||
// Do not leave tautological assignments around.
|
||||
if let StatementKind::Assign(box (lhs, ref rhs)) = stmt.kind
|
||||
&& let Rvalue::Use(Operand::Copy(rhs) | Operand::Move(rhs)) | Rvalue::CopyForDeref(rhs) =
|
||||
*rhs
|
||||
&& let Rvalue::Use(Operand::Copy(rhs) | Operand::Move(rhs)) = *rhs
|
||||
&& lhs == rhs
|
||||
{
|
||||
stmt.make_nop(true);
|
||||
|
|
|
|||
|
|
@ -309,12 +309,7 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> {
|
|||
self.assign_operand(state, target, operand);
|
||||
}
|
||||
}
|
||||
Rvalue::CopyForDeref(rhs) => {
|
||||
state.flood(target.as_ref(), &self.map);
|
||||
if let Some(target) = self.map.find(target.as_ref()) {
|
||||
self.assign_operand(state, target, &Operand::Copy(*rhs));
|
||||
}
|
||||
}
|
||||
Rvalue::CopyForDeref(_) => bug!("`CopyForDeref` in runtime MIR"),
|
||||
Rvalue::Aggregate(kind, operands) => {
|
||||
// If we assign `target = Enum::Variant#0(operand)`,
|
||||
// we must make sure that all `target as Variant#i` are `Top`.
|
||||
|
|
@ -488,9 +483,7 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> {
|
|||
}
|
||||
Rvalue::Discriminant(place) => state.get_discr(place.as_ref(), &self.map),
|
||||
Rvalue::Use(operand) => return self.handle_operand(operand, state),
|
||||
Rvalue::CopyForDeref(place) => {
|
||||
return self.handle_operand(&Operand::Copy(*place), state);
|
||||
}
|
||||
Rvalue::CopyForDeref(_) => bug!("`CopyForDeref` in runtime MIR"),
|
||||
Rvalue::Ref(..) | Rvalue::RawPtr(..) => {
|
||||
// We don't track such places.
|
||||
return ValueOrPlace::TOP;
|
||||
|
|
|
|||
|
|
@ -285,8 +285,7 @@ impl<'tcx> MutVisitor<'tcx> for Merger<'tcx> {
|
|||
match &statement.kind {
|
||||
StatementKind::Assign(box (dest, rvalue)) => {
|
||||
match rvalue {
|
||||
Rvalue::CopyForDeref(place)
|
||||
| Rvalue::Use(Operand::Copy(place) | Operand::Move(place)) => {
|
||||
Rvalue::Use(Operand::Copy(place) | Operand::Move(place)) => {
|
||||
// These might've been turned into self-assignments by the replacement
|
||||
// (this includes the original statement we wanted to eliminate).
|
||||
if dest == place {
|
||||
|
|
@ -400,7 +399,7 @@ impl<'tcx> Visitor<'tcx> for FindAssignments<'_, 'tcx> {
|
|||
fn visit_statement(&mut self, statement: &Statement<'tcx>, _: Location) {
|
||||
if let StatementKind::Assign(box (
|
||||
lhs,
|
||||
Rvalue::CopyForDeref(rhs) | Rvalue::Use(Operand::Copy(rhs) | Operand::Move(rhs)),
|
||||
Rvalue::Use(Operand::Copy(rhs) | Operand::Move(rhs)),
|
||||
)) = &statement.kind
|
||||
&& let Some(src) = lhs.as_local()
|
||||
&& let Some(dest) = rhs.as_local()
|
||||
|
|
|
|||
41
compiler/rustc_mir_transform/src/erase_deref_temps.rs
Normal file
41
compiler/rustc_mir_transform/src/erase_deref_temps.rs
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
//! This pass converts all `DerefTemp` locals into normal temporaries
|
||||
//! and turns their `CopyForDeref` rvalues into normal copies.
|
||||
|
||||
use rustc_middle::mir::visit::MutVisitor;
|
||||
use rustc_middle::mir::*;
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
|
||||
struct EraseDerefTempsVisitor<'tcx> {
|
||||
tcx: TyCtxt<'tcx>,
|
||||
}
|
||||
|
||||
impl<'tcx> MutVisitor<'tcx> for EraseDerefTempsVisitor<'tcx> {
|
||||
fn tcx(&self) -> TyCtxt<'tcx> {
|
||||
self.tcx
|
||||
}
|
||||
|
||||
fn visit_rvalue(&mut self, rvalue: &mut Rvalue<'tcx>, _: Location) {
|
||||
if let &mut Rvalue::CopyForDeref(place) = rvalue {
|
||||
*rvalue = Rvalue::Use(Operand::Copy(place))
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_local_decl(&mut self, _: Local, local_decl: &mut LocalDecl<'tcx>) {
|
||||
if local_decl.is_deref_temp() {
|
||||
let info = local_decl.local_info.as_mut().unwrap_crate_local();
|
||||
**info = LocalInfo::Boring;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) struct EraseDerefTemps;
|
||||
|
||||
impl<'tcx> crate::MirPass<'tcx> for EraseDerefTemps {
|
||||
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
|
||||
EraseDerefTempsVisitor { tcx }.visit_body_preserves_cfg(body);
|
||||
}
|
||||
|
||||
fn is_required(&self) -> bool {
|
||||
true
|
||||
}
|
||||
}
|
||||
|
|
@ -939,12 +939,6 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
|
|||
let value = match *rvalue {
|
||||
// Forward values.
|
||||
Rvalue::Use(ref mut operand) => return self.simplify_operand(operand, location),
|
||||
Rvalue::CopyForDeref(place) => {
|
||||
let mut operand = Operand::Copy(place);
|
||||
let val = self.simplify_operand(&mut operand, location);
|
||||
*rvalue = Rvalue::Use(operand);
|
||||
return val;
|
||||
}
|
||||
|
||||
// Roots.
|
||||
Rvalue::Repeat(ref mut op, amount) => {
|
||||
|
|
@ -986,6 +980,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
|
|||
|
||||
// Unsupported values.
|
||||
Rvalue::ThreadLocalRef(..) | Rvalue::ShallowInitBox(..) => return None,
|
||||
Rvalue::CopyForDeref(_) => bug!("`CopyForDeref` in runtime MIR"),
|
||||
};
|
||||
let ty = rvalue.ty(self.local_decls, self.tcx);
|
||||
Some(self.insert(ty, value))
|
||||
|
|
|
|||
|
|
@ -455,7 +455,6 @@ impl<'a, 'tcx> TOFinder<'a, 'tcx> {
|
|||
match rhs {
|
||||
Rvalue::Use(operand) => self.process_operand(bb, lhs, operand, state),
|
||||
// Transfer the conditions on the copy rhs.
|
||||
Rvalue::CopyForDeref(rhs) => self.process_operand(bb, lhs, &Operand::Copy(*rhs), state),
|
||||
Rvalue::Discriminant(rhs) => {
|
||||
let Some(rhs) = self.map.find_discr(rhs.as_ref()) else { return };
|
||||
state.insert_place_idx(rhs, lhs, &self.map);
|
||||
|
|
|
|||
|
|
@ -139,6 +139,7 @@ declare_passes! {
|
|||
mod dest_prop : DestinationPropagation;
|
||||
pub mod dump_mir : Marker;
|
||||
mod early_otherwise_branch : EarlyOtherwiseBranch;
|
||||
mod erase_deref_temps : EraseDerefTemps;
|
||||
mod elaborate_box_derefs : ElaborateBoxDerefs;
|
||||
mod elaborate_drops : ElaborateDrops;
|
||||
mod function_item_references : FunctionItemReferences;
|
||||
|
|
@ -619,6 +620,7 @@ fn run_runtime_lowering_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
|
|||
// `AddRetag` needs to run after `ElaborateDrops` but before `ElaborateBoxDerefs`.
|
||||
// Otherwise it should run fairly late, but before optimizations begin.
|
||||
&add_retag::AddRetag,
|
||||
&erase_deref_temps::EraseDerefTemps,
|
||||
&elaborate_box_derefs::ElaborateBoxDerefs,
|
||||
&coroutine::StateTransform,
|
||||
&Lint(known_panics_lint::KnownPanicsLint),
|
||||
|
|
|
|||
|
|
@ -247,8 +247,7 @@ fn compute_replacement<'tcx>(
|
|||
// This is a copy, just use the value we have in store for the previous one.
|
||||
// As we are visiting in `assignment_order`, ie. reverse postorder, `rhs` should
|
||||
// have been visited before.
|
||||
Rvalue::Use(Operand::Copy(place) | Operand::Move(place))
|
||||
| Rvalue::CopyForDeref(place) => {
|
||||
Rvalue::Use(Operand::Copy(place) | Operand::Move(place)) => {
|
||||
if let Some(rhs) = place.as_local()
|
||||
&& ssa.is_ssa(rhs)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -240,7 +240,7 @@ fn build_adrop_for_coroutine_shim<'tcx>(
|
|||
source_info,
|
||||
StatementKind::Assign(Box::new((
|
||||
Place::from(proxy_ref_local),
|
||||
Rvalue::CopyForDeref(proxy_ref_place),
|
||||
Rvalue::Use(Operand::Copy(proxy_ref_place)),
|
||||
))),
|
||||
),
|
||||
);
|
||||
|
|
@ -261,7 +261,7 @@ fn build_adrop_for_coroutine_shim<'tcx>(
|
|||
source_info,
|
||||
StatementKind::Assign(Box::new((
|
||||
Place::from(cor_ptr_local),
|
||||
Rvalue::CopyForDeref(impl_ptr_place),
|
||||
Rvalue::Use(Operand::Copy(impl_ptr_place)),
|
||||
))),
|
||||
),
|
||||
);
|
||||
|
|
@ -334,7 +334,7 @@ fn build_adrop_for_adrop_shim<'tcx>(
|
|||
source_info,
|
||||
StatementKind::Assign(Box::new((
|
||||
Place::from(proxy_ref_local),
|
||||
Rvalue::CopyForDeref(proxy_ref_place),
|
||||
Rvalue::Use(Operand::Copy(proxy_ref_place)),
|
||||
))),
|
||||
));
|
||||
|
||||
|
|
@ -350,7 +350,7 @@ fn build_adrop_for_adrop_shim<'tcx>(
|
|||
source_info,
|
||||
StatementKind::Assign(Box::new((
|
||||
Place::from(cor_ptr_local),
|
||||
Rvalue::CopyForDeref(impl_ptr_place),
|
||||
Rvalue::Use(Operand::Copy(impl_ptr_place)),
|
||||
))),
|
||||
));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -297,9 +297,7 @@ fn compute_copy_classes(ssa: &mut SsaLocals, body: &Body<'_>) {
|
|||
let mut copies = IndexVec::from_fn_n(|l| l, body.local_decls.len());
|
||||
|
||||
for (local, rvalue, _) in ssa.assignments(body) {
|
||||
let (Rvalue::Use(Operand::Copy(place) | Operand::Move(place))
|
||||
| Rvalue::CopyForDeref(place)) = rvalue
|
||||
else {
|
||||
let Rvalue::Use(Operand::Copy(place) | Operand::Move(place)) = rvalue else {
|
||||
continue;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ 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::{NonUseContext, PlaceContext, Visitor};
|
||||
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;
|
||||
|
|
@ -906,6 +906,20 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
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,
|
||||
format!("`DerefTemp` locals must only be dereferenced or directly assigned to"),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
self.super_place(place, cntxt, location);
|
||||
}
|
||||
|
||||
|
|
@ -918,7 +932,12 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
|
|||
};
|
||||
}
|
||||
match rvalue {
|
||||
Rvalue::Use(_) | Rvalue::CopyForDeref(_) => {}
|
||||
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) => {
|
||||
|
|
@ -1416,13 +1435,13 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
|
|||
),
|
||||
);
|
||||
}
|
||||
if let Rvalue::CopyForDeref(place) = rvalue {
|
||||
if place.ty(&self.body.local_decls, self.tcx).ty.builtin_deref(true).is_none() {
|
||||
self.fail(
|
||||
location,
|
||||
"`CopyForDeref` should only be used for dereferenceable types",
|
||||
)
|
||||
}
|
||||
|
||||
if let Some(local) = dest.as_local()
|
||||
&& let ClearCrossCrate::Set(box LocalInfo::DerefTemp) =
|
||||
self.body.local_decls[local].local_info
|
||||
&& !matches!(rvalue, Rvalue::CopyForDeref(_))
|
||||
{
|
||||
self.fail(location, "assignment to a `DerefTemp` must use `CopyForDeref`")
|
||||
}
|
||||
}
|
||||
StatementKind::AscribeUserType(..) => {
|
||||
|
|
@ -1594,4 +1613,22 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
|
|||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue