Skip to content

[WIP] Underefer refactoring #145344

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 2 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion compiler/rustc_borrowck/src/def_use.rs
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,8 @@ pub(crate) fn categorize(context: PlaceContext) -> Option<DefUse> {
// Backwards incompatible drop hint is not a use, just a marker for linting.
PlaceContext::NonUse(NonUseContext::BackwardIncompatibleDropHint) => None,

PlaceContext::MutatingUse(MutatingUseContext::Deinit | MutatingUseContext::SetDiscriminant) => {
PlaceContext::MutatingUse(MutatingUseContext::Deinit | MutatingUseContext::SetDiscriminant) |
PlaceContext::NonUse(NonUseContext::DerefTempDecl) => {
bug!("These statements are not allowed in this MIR phase")
}
}
Expand Down
20 changes: 2 additions & 18 deletions compiler/rustc_borrowck/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1473,24 +1473,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::Len(place) | Rvalue::Discriminant(place)) => {
let af = match *rvalue {
Rvalue::Len(..) => Some(ArtificialField::ArrayLength),
Expand Down Expand Up @@ -1553,6 +1535,8 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
Rvalue::WrapUnsafeBinder(op, _) => {
self.consume_operand(location, (op, span), state);
}

Rvalue::CopyForDeref(_) => bug!("`CopyForDeref` in borrowck"),
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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::Len(place) | Rvalue::Discriminant(place)) => {
let af = match rvalue {
Rvalue::Len(..) => Some(ArtificialField::ArrayLength),
Expand Down Expand Up @@ -336,6 +331,8 @@ impl<'a, 'tcx> LoanInvalidationsGenerator<'a, 'tcx> {
Rvalue::WrapUnsafeBinder(op, _) => {
self.consume_operand(location, op);
}

Rvalue::CopyForDeref(_) => bug!("`CopyForDeref` in borrowck"),
}
}

Expand Down
6 changes: 1 addition & 5 deletions compiler/rustc_codegen_cranelift/src/base.rs
Original file line number Diff line number Diff line change
Expand Up @@ -601,11 +601,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());
Expand Down Expand Up @@ -935,6 +930,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(_)
Expand Down
4 changes: 1 addition & 3 deletions compiler/rustc_codegen_ssa/src/mir/rvalue.rs
Original file line number Diff line number Diff line change
Expand Up @@ -494,9 +494,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())
Expand Down Expand Up @@ -740,6 +737,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"),
}
}

Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_const_eval/src/check_consts/qualifs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -236,7 +236,7 @@ where
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, _)
Expand Down
5 changes: 1 addition & 4 deletions compiler/rustc_const_eval/src/interpret/step.rs
Original file line number Diff line number Diff line change
Expand Up @@ -185,10 +185,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);
Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_middle/src/mir/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1110,7 +1110,7 @@ pub enum LocalInfo<'tcx> {
/// and subject to Edition 2024 temporary lifetime rules
IfThenRescopeTemp { if_then: HirId },
/// A temporary created during the pass `Derefer` to avoid it's retagging
DerefTemp,
DerefTemp { alias_for: Place<'tcx> },
/// A temporary created for borrow checking.
FakeBorrow,
/// A local without anything interesting about it.
Expand Down Expand Up @@ -1191,7 +1191,7 @@ impl<'tcx> LocalDecl<'tcx> {
/// Returns `true` if this is a DerefTemp
pub fn is_deref_temp(&self) -> bool {
match self.local_info() {
LocalInfo::DerefTemp => true,
LocalInfo::DerefTemp { .. } => true,
_ => false,
}
}
Expand Down
2 changes: 2 additions & 0 deletions compiler/rustc_middle/src/mir/syntax.rs
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,9 @@ pub enum RuntimePhase {
/// * [`TerminatorKind::Yield`]
/// * [`TerminatorKind::CoroutineDrop`]
/// * [`Rvalue::Aggregate`] for any `AggregateKind` except `Array`
/// * [`Rvalue::CopyForDeref`]
/// * [`PlaceElem::OpaqueCast`]
/// * [`LocalInfo::DerefTemp`]
///
/// And the following variants are allowed:
/// * [`StatementKind::Retag`]
Expand Down
21 changes: 19 additions & 2 deletions compiler/rustc_middle/src/mir/visit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -864,7 +864,7 @@ macro_rules! make_mir_visitor {
ty,
user_ty,
source_info,
local_info: _,
local_info,
} = local_decl;

self.visit_source_info(source_info);
Expand All @@ -878,6 +878,17 @@ macro_rules! make_mir_visitor {
self.visit_user_type_projection(user_ty);
}
}

let location = Location::START;

// FIXME: ?
if let ClearCrossCrate::Set(box LocalInfo::DerefTemp { alias_for }) = local_info {
self.visit_place(
alias_for,
PlaceContext::NonUse(NonUseContext::DerefTempDecl),
location
);
}
}

fn super_local(
Expand Down Expand Up @@ -1373,6 +1384,8 @@ pub enum NonUseContext {
VarDebugInfo,
/// A `BackwardIncompatibleDropHint` statement, meant for edition 2024 lints.
BackwardIncompatibleDropHint,
/// `LocalInfo::DerefTemp`
DerefTempDecl,
}

#[derive(Copy, Clone, Debug, PartialEq, Eq)]
Expand Down Expand Up @@ -1448,7 +1461,11 @@ impl PlaceContext {
match self {
PlaceContext::MutatingUse(_) => ty::Invariant,
PlaceContext::NonUse(
StorageDead | StorageLive | VarDebugInfo | BackwardIncompatibleDropHint,
StorageDead
| StorageLive
| VarDebugInfo
| BackwardIncompatibleDropHint
| DerefTempDecl,
) => ty::Invariant,
PlaceContext::NonMutatingUse(
Inspect | Copy | Move | PlaceMention | SharedBorrow | FakeBorrow | RawBorrow
Expand Down
13 changes: 7 additions & 6 deletions compiler/rustc_mir_dataflow/src/move_paths/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ use super::{
Init, InitIndex, InitKind, InitLocation, LocationMap, LookupResult, MoveData, MoveOut,
MoveOutIndex, MovePath, MovePathIndex, MovePathLookup,
};
use crate::un_derefer::UnDerefer;

struct MoveDataBuilder<'a, 'tcx, F> {
body: &'a Body<'tcx>,
Expand Down Expand Up @@ -58,7 +59,7 @@ impl<'a, 'tcx, F: Fn(Ty<'tcx>) -> bool> MoveDataBuilder<'a, 'tcx, F> {
rev_lookup: MovePathLookup {
locals,
projections: Default::default(),
un_derefer: Default::default(),
un_derefer: UnDerefer::from_local_decls(&body.local_decls),
},
move_paths,
path_map,
Expand Down Expand Up @@ -342,15 +343,15 @@ impl<'a, 'tcx, F: Fn(Ty<'tcx>) -> bool> MoveDataBuilder<'a, 'tcx, F> {
fn gather_statement(&mut self, stmt: &Statement<'tcx>) {
debug!("gather_statement({:?}, {:?})", self.loc, stmt);
match &stmt.kind {
StatementKind::Assign(box (place, Rvalue::CopyForDeref(reffed))) => {
StatementKind::Assign(box (place, Rvalue::CopyForDeref(_reffed))) => {
let local = place.as_local().unwrap();
assert!(self.body.local_decls[local].is_deref_temp());

let rev_lookup = &mut self.data.rev_lookup;
//let rev_lookup = &mut self.data.rev_lookup;

rev_lookup.un_derefer.insert(local, reffed.as_ref());
let base_local = rev_lookup.un_derefer.deref_chain(local).first().unwrap().local;
rev_lookup.locals[local] = rev_lookup.locals[base_local];
//rev_lookup.un_derefer.insert(local, reffed.as_ref());
//let base_local = rev_lookup.un_derefer.deref_chain(local).first().unwrap().local;
//rev_lookup.locals[local] = rev_lookup.locals[base_local];
}
StatementKind::Assign(box (place, rval)) => {
self.create_move_path(*place);
Expand Down
13 changes: 13 additions & 0 deletions compiler/rustc_mir_dataflow/src/un_derefer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,19 @@ pub(crate) struct UnDerefer<'tcx> {
}

impl<'tcx> UnDerefer<'tcx> {
#[inline]
pub(crate) fn from_local_decls(local_decls: &LocalDecls<'tcx>) -> Self {
let mut this = Self::default();

for (local, decl) in local_decls.iter_enumerated() {
if let LocalInfo::DerefTemp { alias_for } = decl.local_info() {
this.insert(local, alias_for.as_ref());
}
}

this
}

#[inline]
pub(crate) fn insert(&mut self, local: Local, reffed: PlaceRef<'tcx>) {
let mut chain = self.deref_chains.remove(&reffed.local).unwrap_or_default();
Expand Down
9 changes: 3 additions & 6 deletions compiler/rustc_mir_transform/src/copy_prop.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
};

Expand All @@ -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);
}
}
Expand Down Expand Up @@ -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();
Expand Down
11 changes: 2 additions & 9 deletions compiler/rustc_mir_transform/src/dataflow_const_prop.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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`.
Expand Down Expand Up @@ -492,9 +487,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;
Expand Down
11 changes: 6 additions & 5 deletions compiler/rustc_mir_transform/src/deref_separator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,17 +36,18 @@ impl<'a, 'tcx> MutVisitor<'tcx> for DerefChecker<'a, 'tcx> {
for (idx, (p_ref, p_elem)) in place.iter_projections().enumerate() {
if !p_ref.projection.is_empty() && p_elem == ProjectionElem::Deref {
let ty = p_ref.ty(self.local_decls, self.tcx).ty;
let temp = self.patcher.new_local_with_info(
ty,
self.local_decls[p_ref.local].source_info.span,
LocalInfo::DerefTemp,
);

// We are adding current p_ref's projections to our
// temp value, excluding projections we already covered.
let deref_place = Place::from(place_local)
.project_deeper(&p_ref.projection[last_len..], self.tcx);

let temp = self.patcher.new_local_with_info(
ty,
self.local_decls[p_ref.local].source_info.span,
LocalInfo::DerefTemp { alias_for: deref_place },
);

self.patcher.add_assign(
loc,
Place::from(temp),
Expand Down
5 changes: 2 additions & 3 deletions compiler/rustc_mir_transform/src/dest_prop.rs
Original file line number Diff line number Diff line change
Expand Up @@ -317,8 +317,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 {
Expand Down Expand Up @@ -751,7 +750,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, dest)) = places_to_candidate_pair(*lhs, *rhs, self.body) else {
Expand Down
41 changes: 41 additions & 0 deletions compiler/rustc_mir_transform/src/erase_deref_temps.rs
Original file line number Diff line number Diff line change
@@ -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
}
}
Loading
Loading