Skip to content

Commit fb38d75

Browse files
committed
Simplify implementation.
1 parent 031929c commit fb38d75

File tree

1 file changed

+33
-34
lines changed

1 file changed

+33
-34
lines changed

compiler/rustc_mir_transform/src/deduce_param_attrs.rs

Lines changed: 33 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -8,53 +8,56 @@
88
use rustc_hir::def_id::LocalDefId;
99
use rustc_index::bit_set::DenseBitSet;
1010
use rustc_middle::mir::visit::{NonMutatingUseContext, PlaceContext, Visitor};
11-
use rustc_middle::mir::{Body, Location, Operand, Place, RETURN_PLACE, Terminator, TerminatorKind};
11+
use rustc_middle::mir::*;
1212
use rustc_middle::ty::{self, DeducedParamAttrs, Ty, TyCtxt};
1313
use rustc_session::config::OptLevel;
1414

1515
/// A visitor that determines which arguments have been mutated. We can't use the mutability field
1616
/// on LocalDecl for this because it has no meaning post-optimization.
1717
struct DeduceReadOnly {
1818
/// Each bit is indexed by argument number, starting at zero (so 0 corresponds to local decl
19-
/// 1). The bit is true if the argument may have been mutated or false if we know it hasn't
19+
/// 1). The bit is false if the argument may have been mutated or true if we know it hasn't
2020
/// been up to the point we're at.
21-
mutable_args: DenseBitSet<usize>,
21+
read_only: DenseBitSet<usize>,
2222
}
2323

2424
impl DeduceReadOnly {
2525
/// Returns a new DeduceReadOnly instance.
2626
fn new(arg_count: usize) -> Self {
27-
Self { mutable_args: DenseBitSet::new_empty(arg_count) }
27+
Self { read_only: DenseBitSet::new_filled(arg_count) }
28+
}
29+
30+
/// Returns whether the given local is a parameter and its index.
31+
fn as_param(&self, local: Local) -> Option<usize> {
32+
// Locals and parameters are shifted by `RETURN_PLACE`.
33+
let param_index = local.as_usize().checked_sub(1)?;
34+
if param_index < self.read_only.domain_size() { Some(param_index) } else { None }
2835
}
2936
}
3037

3138
impl<'tcx> Visitor<'tcx> for DeduceReadOnly {
3239
fn visit_place(&mut self, place: &Place<'tcx>, context: PlaceContext, _location: Location) {
3340
// We're only interested in arguments.
34-
if place.local == RETURN_PLACE || place.local.index() > self.mutable_args.domain_size() {
35-
return;
36-
}
41+
let Some(param_index) = self.as_param(place.local) else { return };
3742

3843
let mark_as_mutable = match context {
39-
PlaceContext::MutatingUse(..) => {
40-
// This is a mutation, so mark it as such.
41-
true
42-
}
43-
PlaceContext::NonMutatingUse(NonMutatingUseContext::RawBorrow) => {
44-
// Whether mutating though a `&raw const` is allowed is still undecided, so we
45-
// disable any sketchy `readonly` optimizations for now. But we only need to do
46-
// this if the pointer would point into the argument. IOW: for indirect places,
47-
// like `&raw (*local).field`, this surely cannot mutate `local`.
48-
!place.is_indirect()
49-
}
50-
PlaceContext::NonMutatingUse(..) | PlaceContext::NonUse(..) => {
51-
// Not mutating, so it's fine.
52-
false
53-
}
44+
// Not mutating, so it's fine.
45+
PlaceContext::NonUse(..) => false,
46+
// Dereference is not a mutation.
47+
_ if place.is_indirect_first_projection() => false,
48+
// This is a mutation, so mark it as such.
49+
PlaceContext::MutatingUse(..) => true,
50+
// Whether mutating though a `&raw const` is allowed is still undecided, so we
51+
// disable any sketchy `readonly` optimizations for now. But we only need to do
52+
// this if the pointer would point into the argument. IOW: for indirect places,
53+
// like `&raw (*local).field`, this surely cannot mutate `local`.
54+
PlaceContext::NonMutatingUse(NonMutatingUseContext::RawBorrow) => true,
55+
// Not mutating, so it's fine.
56+
PlaceContext::NonMutatingUse(..) => false,
5457
};
5558

5659
if mark_as_mutable {
57-
self.mutable_args.insert(place.local.index() - 1);
60+
self.read_only.remove(param_index);
5861
}
5962
}
6063

@@ -82,16 +85,12 @@ impl<'tcx> Visitor<'tcx> for DeduceReadOnly {
8285
// from.
8386
if let TerminatorKind::Call { ref args, .. } = terminator.kind {
8487
for arg in args {
85-
if let Operand::Move(place) = arg.node {
86-
let local = place.local;
87-
if place.is_indirect()
88-
|| local == RETURN_PLACE
89-
|| local.index() > self.mutable_args.domain_size()
90-
{
91-
continue;
92-
}
93-
94-
self.mutable_args.insert(local.index() - 1);
88+
if let Operand::Move(place) = arg.node
89+
// We're only interested in arguments.
90+
&& let Some(param_index) = self.as_param(place.local)
91+
&& !place.is_indirect_first_projection()
92+
{
93+
self.read_only.remove(param_index);
9594
}
9695
}
9796
};
@@ -170,7 +169,7 @@ pub(super) fn deduced_param_attrs<'tcx>(
170169
//
171170
// [1]: https://github.com/rust-lang/rust/pull/103172#discussion_r999139997
172171
let mut deduced_param_attrs = tcx.arena.alloc_from_iter((0..body.arg_count).map(|arg_index| {
173-
DeducedParamAttrs { read_only: !deduce_read_only.mutable_args.contains(arg_index) }
172+
DeducedParamAttrs { read_only: deduce_read_only.read_only.contains(arg_index) }
174173
}));
175174

176175
// Trailing parameters past the size of the `deduced_param_attrs` array are assumed to have the

0 commit comments

Comments
 (0)