Skip to content
This repository was archived by the owner on May 28, 2025. It is now read-only.

Commit d24d620

Browse files
committed
Deduce readonly attribute for !Freeze arguments
1 parent 91a0e16 commit d24d620

File tree

1 file changed

+34
-30
lines changed

1 file changed

+34
-30
lines changed

compiler/rustc_mir_transform/src/deduce_param_attrs.rs

Lines changed: 34 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -18,44 +18,47 @@ struct DeduceReadOnly {
1818
/// Each bit is indexed by argument number, starting at zero (so 0 corresponds to local decl
1919
/// 1). The bit is true if the argument may have been mutated or false 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>,
22+
read_only_when_freeze: DenseBitSet<usize>,
2223
}
2324

2425
impl DeduceReadOnly {
2526
/// Returns a new DeduceReadOnly instance.
2627
fn new(arg_count: usize) -> Self {
27-
Self { mutable_args: DenseBitSet::new_empty(arg_count) }
28+
Self {
29+
read_only: DenseBitSet::new_filled(arg_count),
30+
read_only_when_freeze: DenseBitSet::new_filled(arg_count),
31+
}
2832
}
2933
}
3034

3135
impl<'tcx> Visitor<'tcx> for DeduceReadOnly {
3236
fn visit_place(&mut self, place: &Place<'tcx>, context: PlaceContext, _location: Location) {
3337
// We're only interested in arguments.
34-
if place.local == RETURN_PLACE || place.local.index() > self.mutable_args.domain_size() {
38+
if place.local == RETURN_PLACE || place.local.index() > self.read_only.domain_size() {
3539
return;
3640
}
37-
38-
let mark_as_mutable = match context {
41+
let arg_index = place.local.index() - 1;
42+
if place.is_indirect() {
43+
return;
44+
}
45+
match context {
3946
PlaceContext::MutatingUse(..) => {
4047
// This is a mutation, so mark it as such.
41-
true
48+
self.read_only.remove(arg_index);
49+
self.read_only_when_freeze.remove(arg_index);
4250
}
4351
PlaceContext::NonMutatingUse(NonMutatingUseContext::RawBorrow) => {
4452
// 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()
53+
// disable any sketchy `readonly` optimizations for now.
54+
self.read_only.remove(arg_index);
55+
self.read_only_when_freeze.remove(arg_index);
4956
}
50-
PlaceContext::NonMutatingUse(..) | PlaceContext::NonUse(..) => {
51-
// Not mutating, so it's fine.
52-
false
57+
PlaceContext::NonMutatingUse(NonMutatingUseContext::SharedBorrow) => {
58+
self.read_only.remove(arg_index);
5359
}
60+
PlaceContext::NonMutatingUse(..) | PlaceContext::NonUse(..) => {}
5461
};
55-
56-
if mark_as_mutable {
57-
self.mutable_args.insert(place.local.index() - 1);
58-
}
5962
}
6063

6164
fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location) {
@@ -86,12 +89,13 @@ impl<'tcx> Visitor<'tcx> for DeduceReadOnly {
8689
let local = place.local;
8790
if place.is_indirect()
8891
|| local == RETURN_PLACE
89-
|| local.index() > self.mutable_args.domain_size()
92+
|| local.index() > self.read_only.domain_size()
9093
{
9194
continue;
9295
}
93-
94-
self.mutable_args.insert(local.index() - 1);
96+
let arg_index = local.index() - 1;
97+
self.read_only.remove(arg_index);
98+
self.read_only_when_freeze.remove(arg_index);
9599
}
96100
}
97101
};
@@ -158,8 +162,8 @@ pub(super) fn deduced_param_attrs<'tcx>(
158162

159163
// Grab the optimized MIR. Analyze it to determine which arguments have been mutated.
160164
let body: &Body<'tcx> = tcx.optimized_mir(def_id);
161-
let mut deduce_read_only = DeduceReadOnly::new(body.arg_count);
162-
deduce_read_only.visit_body(body);
165+
let mut deduce = DeduceReadOnly::new(body.arg_count);
166+
deduce.visit_body(body);
163167

164168
// Set the `readonly` attribute for every argument that we concluded is immutable and that
165169
// contains no UnsafeCells.
@@ -173,14 +177,14 @@ pub(super) fn deduced_param_attrs<'tcx>(
173177
let mut deduced_param_attrs = tcx.arena.alloc_from_iter(
174178
body.local_decls.iter().skip(1).take(body.arg_count).enumerate().map(
175179
|(arg_index, local_decl)| DeducedParamAttrs {
176-
read_only: !deduce_read_only.mutable_args.contains(arg_index)
177-
// We must normalize here to reveal opaques and normalize
178-
// their generic parameters, otherwise we'll see exponential
179-
// blow-up in compile times: #113372
180-
&& tcx
181-
.normalize_erasing_regions(typing_env, local_decl.ty)
182-
.is_freeze(tcx, typing_env),
183-
},
180+
read_only: deduce.read_only.contains(arg_index) || (
181+
deduce.read_only_when_freeze.contains(arg_index)
182+
// We must normalize here to reveal opaques and normalize
183+
// their generic parameters, otherwise we'll see exponential
184+
// blow-up in compile times: #113372
185+
&& tcx.normalize_erasing_regions(typing_env, local_decl.ty).is_freeze(tcx, typing_env))
186+
187+
}
184188
),
185189
);
186190

0 commit comments

Comments
 (0)