Simplify implementation.
This commit is contained in:
@@ -8,7 +8,7 @@
|
|||||||
use rustc_hir::def_id::LocalDefId;
|
use rustc_hir::def_id::LocalDefId;
|
||||||
use rustc_index::bit_set::DenseBitSet;
|
use rustc_index::bit_set::DenseBitSet;
|
||||||
use rustc_middle::mir::visit::{NonMutatingUseContext, PlaceContext, Visitor};
|
use rustc_middle::mir::visit::{NonMutatingUseContext, PlaceContext, Visitor};
|
||||||
use rustc_middle::mir::{Body, Location, Operand, Place, RETURN_PLACE, Terminator, TerminatorKind};
|
use rustc_middle::mir::*;
|
||||||
use rustc_middle::ty::{self, DeducedParamAttrs, Ty, TyCtxt};
|
use rustc_middle::ty::{self, DeducedParamAttrs, Ty, TyCtxt};
|
||||||
use rustc_session::config::OptLevel;
|
use rustc_session::config::OptLevel;
|
||||||
|
|
||||||
@@ -16,45 +16,48 @@ use rustc_session::config::OptLevel;
|
|||||||
/// on LocalDecl for this because it has no meaning post-optimization.
|
/// on LocalDecl for this because it has no meaning post-optimization.
|
||||||
struct DeduceReadOnly {
|
struct DeduceReadOnly {
|
||||||
/// Each bit is indexed by argument number, starting at zero (so 0 corresponds to local decl
|
/// Each bit is indexed by argument number, starting at zero (so 0 corresponds to local decl
|
||||||
/// 1). The bit is true if the argument may have been mutated or false if we know it hasn't
|
/// 1). The bit is false if the argument may have been mutated or true if we know it hasn't
|
||||||
/// been up to the point we're at.
|
/// been up to the point we're at.
|
||||||
mutable_args: DenseBitSet<usize>,
|
read_only: DenseBitSet<usize>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DeduceReadOnly {
|
impl DeduceReadOnly {
|
||||||
/// Returns a new DeduceReadOnly instance.
|
/// Returns a new DeduceReadOnly instance.
|
||||||
fn new(arg_count: usize) -> Self {
|
fn new(arg_count: usize) -> Self {
|
||||||
Self { mutable_args: DenseBitSet::new_empty(arg_count) }
|
Self { read_only: DenseBitSet::new_filled(arg_count) }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns whether the given local is a parameter and its index.
|
||||||
|
fn as_param(&self, local: Local) -> Option<usize> {
|
||||||
|
// Locals and parameters are shifted by `RETURN_PLACE`.
|
||||||
|
let param_index = local.as_usize().checked_sub(1)?;
|
||||||
|
if param_index < self.read_only.domain_size() { Some(param_index) } else { None }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx> Visitor<'tcx> for DeduceReadOnly {
|
impl<'tcx> Visitor<'tcx> for DeduceReadOnly {
|
||||||
fn visit_place(&mut self, place: &Place<'tcx>, context: PlaceContext, _location: Location) {
|
fn visit_place(&mut self, place: &Place<'tcx>, context: PlaceContext, _location: Location) {
|
||||||
// We're only interested in arguments.
|
// We're only interested in arguments.
|
||||||
if place.local == RETURN_PLACE || place.local.index() > self.mutable_args.domain_size() {
|
let Some(param_index) = self.as_param(place.local) else { return };
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let mark_as_mutable = match context {
|
let mark_as_mutable = match context {
|
||||||
PlaceContext::MutatingUse(..) => {
|
// Not mutating, so it's fine.
|
||||||
// This is a mutation, so mark it as such.
|
PlaceContext::NonUse(..) => false,
|
||||||
true
|
// Dereference is not a mutation.
|
||||||
}
|
_ if place.is_indirect_first_projection() => false,
|
||||||
PlaceContext::NonMutatingUse(NonMutatingUseContext::RawBorrow) => {
|
// This is a mutation, so mark it as such.
|
||||||
// Whether mutating though a `&raw const` is allowed is still undecided, so we
|
PlaceContext::MutatingUse(..) => true,
|
||||||
// disable any sketchy `readonly` optimizations for now. But we only need to do
|
// Whether mutating though a `&raw const` is allowed is still undecided, so we
|
||||||
// this if the pointer would point into the argument. IOW: for indirect places,
|
// disable any sketchy `readonly` optimizations for now. But we only need to do
|
||||||
// like `&raw (*local).field`, this surely cannot mutate `local`.
|
// this if the pointer would point into the argument. IOW: for indirect places,
|
||||||
!place.is_indirect()
|
// like `&raw (*local).field`, this surely cannot mutate `local`.
|
||||||
}
|
PlaceContext::NonMutatingUse(NonMutatingUseContext::RawBorrow) => true,
|
||||||
PlaceContext::NonMutatingUse(..) | PlaceContext::NonUse(..) => {
|
// Not mutating, so it's fine.
|
||||||
// Not mutating, so it's fine.
|
PlaceContext::NonMutatingUse(..) => false,
|
||||||
false
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
if mark_as_mutable {
|
if mark_as_mutable {
|
||||||
self.mutable_args.insert(place.local.index() - 1);
|
self.read_only.remove(param_index);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -82,16 +85,12 @@ impl<'tcx> Visitor<'tcx> for DeduceReadOnly {
|
|||||||
// from.
|
// from.
|
||||||
if let TerminatorKind::Call { ref args, .. } = terminator.kind {
|
if let TerminatorKind::Call { ref args, .. } = terminator.kind {
|
||||||
for arg in args {
|
for arg in args {
|
||||||
if let Operand::Move(place) = arg.node {
|
if let Operand::Move(place) = arg.node
|
||||||
let local = place.local;
|
// We're only interested in arguments.
|
||||||
if place.is_indirect()
|
&& let Some(param_index) = self.as_param(place.local)
|
||||||
|| local == RETURN_PLACE
|
&& !place.is_indirect_first_projection()
|
||||||
|| local.index() > self.mutable_args.domain_size()
|
{
|
||||||
{
|
self.read_only.remove(param_index);
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
self.mutable_args.insert(local.index() - 1);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -170,7 +169,7 @@ pub(super) fn deduced_param_attrs<'tcx>(
|
|||||||
//
|
//
|
||||||
// [1]: https://github.com/rust-lang/rust/pull/103172#discussion_r999139997
|
// [1]: https://github.com/rust-lang/rust/pull/103172#discussion_r999139997
|
||||||
let mut deduced_param_attrs = tcx.arena.alloc_from_iter((0..body.arg_count).map(|arg_index| {
|
let mut deduced_param_attrs = tcx.arena.alloc_from_iter((0..body.arg_count).map(|arg_index| {
|
||||||
DeducedParamAttrs { read_only: !deduce_read_only.mutable_args.contains(arg_index) }
|
DeducedParamAttrs { read_only: deduce_read_only.read_only.contains(arg_index) }
|
||||||
}));
|
}));
|
||||||
|
|
||||||
// Trailing parameters past the size of the `deduced_param_attrs` array are assumed to have the
|
// Trailing parameters past the size of the `deduced_param_attrs` array are assumed to have the
|
||||||
|
|||||||
Reference in New Issue
Block a user