Skip to content

Commit baba668

Browse files
committedNov 3, 2021
Auto merge of #90413 - tmiasko:addr-of-mutable, r=RalfJung,oli-obk
`addr_of!` grants mutable access, maybe? The exact set of permissions granted when forming a raw reference is currently undecided #56604. To avoid presupposing any particular outcome, adjust the const qualification to be compatible with decision where raw reference constructed from `addr_of!` grants mutable access. Additionally, to avoid keeping `MaybeMutBorrowedLocals` in sync with const qualification, remove it. It's no longer used. `@rust-lang/wg-const-eval`
2 parents 7734cb8 + bc4931e commit baba668

File tree

10 files changed

+88
-218
lines changed

10 files changed

+88
-218
lines changed
 

‎compiler/rustc_const_eval/src/transform/check_consts/resolver.rs

+13-5
Original file line numberDiff line numberDiff line change
@@ -94,11 +94,10 @@ where
9494
}
9595
}
9696

97-
fn address_of_allows_mutation(&self, mt: mir::Mutability, place: mir::Place<'tcx>) -> bool {
98-
match mt {
99-
mir::Mutability::Mut => true,
100-
mir::Mutability::Not => self.shared_borrow_allows_mutation(place),
101-
}
97+
fn address_of_allows_mutation(&self, _mt: mir::Mutability, _place: mir::Place<'tcx>) -> bool {
98+
// Exact set of permissions granted by AddressOf is undecided. Conservatively assume that
99+
// it might allow mutation until resolution of #56604.
100+
true
102101
}
103102

104103
fn ref_allows_mutation(&self, kind: mir::BorrowKind, place: mir::Place<'tcx>) -> bool {
@@ -110,6 +109,15 @@ where
110109
}
111110
}
112111

112+
/// `&` only allow mutation if the borrowed place is `!Freeze`.
113+
///
114+
/// This assumes that it is UB to take the address of a struct field whose type is
115+
/// `Freeze`, then use pointer arithmetic to derive a pointer to a *different* field of
116+
/// that same struct whose type is `!Freeze`. If we decide that this is not UB, we will
117+
/// have to check the type of the borrowed **local** instead of the borrowed **place**
118+
/// below. See [rust-lang/unsafe-code-guidelines#134].
119+
///
120+
/// [rust-lang/unsafe-code-guidelines#134]: https://github.com/rust-lang/unsafe-code-guidelines/issues/134
113121
fn shared_borrow_allows_mutation(&self, place: mir::Place<'tcx>) -> bool {
114122
!place
115123
.ty(self.ccx.body, self.ccx.tcx)

‎compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs

+15-117
Original file line numberDiff line numberDiff line change
@@ -3,55 +3,26 @@ use super::*;
33
use crate::{AnalysisDomain, GenKill, GenKillAnalysis};
44
use rustc_middle::mir::visit::Visitor;
55
use rustc_middle::mir::*;
6-
use rustc_middle::ty::{ParamEnv, TyCtxt};
7-
use rustc_span::DUMMY_SP;
8-
9-
pub type MaybeMutBorrowedLocals<'mir, 'tcx> = MaybeBorrowedLocals<MutBorrow<'mir, 'tcx>>;
106

117
/// A dataflow analysis that tracks whether a pointer or reference could possibly exist that points
128
/// to a given local.
139
///
14-
/// The `K` parameter determines what kind of borrows are tracked. By default,
15-
/// `MaybeBorrowedLocals` looks for *any* borrow of a local. If you are only interested in borrows
16-
/// that might allow mutation, use the `MaybeMutBorrowedLocals` type alias instead.
17-
///
1810
/// At present, this is used as a very limited form of alias analysis. For example,
1911
/// `MaybeBorrowedLocals` is used to compute which locals are live during a yield expression for
20-
/// immovable generators. `MaybeMutBorrowedLocals` is used during const checking to prove that a
21-
/// local has not been mutated via indirect assignment (e.g., `*p = 42`), the side-effects of a
22-
/// function call or inline assembly.
23-
pub struct MaybeBorrowedLocals<K = AnyBorrow> {
24-
kind: K,
12+
/// immovable generators.
13+
pub struct MaybeBorrowedLocals {
2514
ignore_borrow_on_drop: bool,
2615
}
2716

2817
impl MaybeBorrowedLocals {
2918
/// A dataflow analysis that records whether a pointer or reference exists that may alias the
3019
/// given local.
3120
pub fn all_borrows() -> Self {
32-
MaybeBorrowedLocals { kind: AnyBorrow, ignore_borrow_on_drop: false }
33-
}
34-
}
35-
36-
impl MaybeMutBorrowedLocals<'mir, 'tcx> {
37-
/// A dataflow analysis that records whether a pointer or reference exists that may *mutably*
38-
/// alias the given local.
39-
///
40-
/// This includes `&mut` and pointers derived from an `&mut`, as well as shared borrows of
41-
/// types with interior mutability.
42-
pub fn mut_borrows_only(
43-
tcx: TyCtxt<'tcx>,
44-
body: &'mir mir::Body<'tcx>,
45-
param_env: ParamEnv<'tcx>,
46-
) -> Self {
47-
MaybeBorrowedLocals {
48-
kind: MutBorrow { body, tcx, param_env },
49-
ignore_borrow_on_drop: false,
50-
}
21+
MaybeBorrowedLocals { ignore_borrow_on_drop: false }
5122
}
5223
}
5324

54-
impl<K> MaybeBorrowedLocals<K> {
25+
impl MaybeBorrowedLocals {
5526
/// During dataflow analysis, ignore the borrow that may occur when a place is dropped.
5627
///
5728
/// Drop terminators may call custom drop glue (`Drop::drop`), which takes `&mut self` as a
@@ -69,21 +40,14 @@ impl<K> MaybeBorrowedLocals<K> {
6940
MaybeBorrowedLocals { ignore_borrow_on_drop: true, ..self }
7041
}
7142

72-
fn transfer_function<'a, T>(&'a self, trans: &'a mut T) -> TransferFunction<'a, T, K> {
73-
TransferFunction {
74-
kind: &self.kind,
75-
trans,
76-
ignore_borrow_on_drop: self.ignore_borrow_on_drop,
77-
}
43+
fn transfer_function<'a, T>(&'a self, trans: &'a mut T) -> TransferFunction<'a, T> {
44+
TransferFunction { trans, ignore_borrow_on_drop: self.ignore_borrow_on_drop }
7845
}
7946
}
8047

81-
impl<K> AnalysisDomain<'tcx> for MaybeBorrowedLocals<K>
82-
where
83-
K: BorrowAnalysisKind<'tcx>,
84-
{
48+
impl AnalysisDomain<'tcx> for MaybeBorrowedLocals {
8549
type Domain = BitSet<Local>;
86-
const NAME: &'static str = K::ANALYSIS_NAME;
50+
const NAME: &'static str = "maybe_borrowed_locals";
8751

8852
fn bottom_value(&self, body: &mir::Body<'tcx>) -> Self::Domain {
8953
// bottom = unborrowed
@@ -95,10 +59,7 @@ where
9559
}
9660
}
9761

98-
impl<K> GenKillAnalysis<'tcx> for MaybeBorrowedLocals<K>
99-
where
100-
K: BorrowAnalysisKind<'tcx>,
101-
{
62+
impl GenKillAnalysis<'tcx> for MaybeBorrowedLocals {
10263
type Idx = Local;
10364

10465
fn statement_effect(
@@ -131,16 +92,14 @@ where
13192
}
13293

13394
/// A `Visitor` that defines the transfer function for `MaybeBorrowedLocals`.
134-
struct TransferFunction<'a, T, K> {
95+
struct TransferFunction<'a, T> {
13596
trans: &'a mut T,
136-
kind: &'a K,
13797
ignore_borrow_on_drop: bool,
13898
}
13999

140-
impl<T, K> Visitor<'tcx> for TransferFunction<'a, T, K>
100+
impl<T> Visitor<'tcx> for TransferFunction<'a, T>
141101
where
142102
T: GenKill<Local>,
143-
K: BorrowAnalysisKind<'tcx>,
144103
{
145104
fn visit_statement(&mut self, stmt: &Statement<'tcx>, location: Location) {
146105
self.super_statement(stmt, location);
@@ -156,14 +115,14 @@ where
156115
self.super_rvalue(rvalue, location);
157116

158117
match rvalue {
159-
mir::Rvalue::AddressOf(mt, borrowed_place) => {
160-
if !borrowed_place.is_indirect() && self.kind.in_address_of(*mt, *borrowed_place) {
118+
mir::Rvalue::AddressOf(_mt, borrowed_place) => {
119+
if !borrowed_place.is_indirect() {
161120
self.trans.gen(borrowed_place.local);
162121
}
163122
}
164123

165-
mir::Rvalue::Ref(_, kind, borrowed_place) => {
166-
if !borrowed_place.is_indirect() && self.kind.in_ref(*kind, *borrowed_place) {
124+
mir::Rvalue::Ref(_, _kind, borrowed_place) => {
125+
if !borrowed_place.is_indirect() {
167126
self.trans.gen(borrowed_place.local);
168127
}
169128
}
@@ -211,64 +170,3 @@ where
211170
}
212171
}
213172
}
214-
215-
pub struct AnyBorrow;
216-
217-
pub struct MutBorrow<'mir, 'tcx> {
218-
tcx: TyCtxt<'tcx>,
219-
body: &'mir Body<'tcx>,
220-
param_env: ParamEnv<'tcx>,
221-
}
222-
223-
impl MutBorrow<'mir, 'tcx> {
224-
/// `&` and `&raw` only allow mutation if the borrowed place is `!Freeze`.
225-
///
226-
/// This assumes that it is UB to take the address of a struct field whose type is
227-
/// `Freeze`, then use pointer arithmetic to derive a pointer to a *different* field of
228-
/// that same struct whose type is `!Freeze`. If we decide that this is not UB, we will
229-
/// have to check the type of the borrowed **local** instead of the borrowed **place**
230-
/// below. See [rust-lang/unsafe-code-guidelines#134].
231-
///
232-
/// [rust-lang/unsafe-code-guidelines#134]: https://github.com/rust-lang/unsafe-code-guidelines/issues/134
233-
fn shared_borrow_allows_mutation(&self, place: Place<'tcx>) -> bool {
234-
!place.ty(self.body, self.tcx).ty.is_freeze(self.tcx.at(DUMMY_SP), self.param_env)
235-
}
236-
}
237-
238-
pub trait BorrowAnalysisKind<'tcx> {
239-
const ANALYSIS_NAME: &'static str;
240-
241-
fn in_address_of(&self, mt: Mutability, place: Place<'tcx>) -> bool;
242-
fn in_ref(&self, kind: mir::BorrowKind, place: Place<'tcx>) -> bool;
243-
}
244-
245-
impl BorrowAnalysisKind<'tcx> for AnyBorrow {
246-
const ANALYSIS_NAME: &'static str = "maybe_borrowed_locals";
247-
248-
fn in_ref(&self, _: mir::BorrowKind, _: Place<'_>) -> bool {
249-
true
250-
}
251-
fn in_address_of(&self, _: Mutability, _: Place<'_>) -> bool {
252-
true
253-
}
254-
}
255-
256-
impl BorrowAnalysisKind<'tcx> for MutBorrow<'mir, 'tcx> {
257-
const ANALYSIS_NAME: &'static str = "maybe_mut_borrowed_locals";
258-
259-
fn in_ref(&self, kind: mir::BorrowKind, place: Place<'tcx>) -> bool {
260-
match kind {
261-
mir::BorrowKind::Mut { .. } => true,
262-
mir::BorrowKind::Shared | mir::BorrowKind::Shallow | mir::BorrowKind::Unique => {
263-
self.shared_borrow_allows_mutation(place)
264-
}
265-
}
266-
}
267-
268-
fn in_address_of(&self, mt: Mutability, place: Place<'tcx>) -> bool {
269-
match mt {
270-
Mutability::Mut => true,
271-
Mutability::Not => self.shared_borrow_allows_mutation(place),
272-
}
273-
}
274-
}

‎compiler/rustc_mir_dataflow/src/impls/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ mod init_locals;
2222
mod liveness;
2323
mod storage_liveness;
2424

25-
pub use self::borrowed_locals::{MaybeBorrowedLocals, MaybeMutBorrowedLocals};
25+
pub use self::borrowed_locals::MaybeBorrowedLocals;
2626
pub use self::init_locals::MaybeInitializedLocals;
2727
pub use self::liveness::MaybeLiveLocals;
2828
pub use self::storage_liveness::{MaybeRequiresStorage, MaybeStorageLive};

‎compiler/rustc_mir_dataflow/src/rustc_peek.rs

+1-30
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,7 @@ use rustc_middle::mir::{self, Body, Local, Location};
1111
use rustc_middle::ty::{self, Ty, TyCtxt};
1212

1313
use crate::impls::{
14-
DefinitelyInitializedPlaces, MaybeInitializedPlaces, MaybeLiveLocals, MaybeMutBorrowedLocals,
15-
MaybeUninitializedPlaces,
14+
DefinitelyInitializedPlaces, MaybeInitializedPlaces, MaybeLiveLocals, MaybeUninitializedPlaces,
1615
};
1716
use crate::move_paths::{HasMoveData, MoveData};
1817
use crate::move_paths::{LookupResult, MovePathIndex};
@@ -62,14 +61,6 @@ impl<'tcx> MirPass<'tcx> for SanityCheck {
6261
sanity_check_via_rustc_peek(tcx, body, &attributes, &flow_def_inits);
6362
}
6463

65-
if has_rustc_mir_with(sess, &attributes, sym::rustc_peek_indirectly_mutable).is_some() {
66-
let flow_mut_borrowed = MaybeMutBorrowedLocals::mut_borrows_only(tcx, body, param_env)
67-
.into_engine(tcx, body)
68-
.iterate_to_fixpoint();
69-
70-
sanity_check_via_rustc_peek(tcx, body, &attributes, &flow_mut_borrowed);
71-
}
72-
7364
if has_rustc_mir_with(sess, &attributes, sym::rustc_peek_liveness).is_some() {
7465
let flow_liveness = MaybeLiveLocals.into_engine(tcx, body).iterate_to_fixpoint();
7566

@@ -281,26 +272,6 @@ where
281272
}
282273
}
283274

284-
impl<'tcx> RustcPeekAt<'tcx> for MaybeMutBorrowedLocals<'_, 'tcx> {
285-
fn peek_at(
286-
&self,
287-
tcx: TyCtxt<'tcx>,
288-
place: mir::Place<'tcx>,
289-
flow_state: &BitSet<Local>,
290-
call: PeekCall,
291-
) {
292-
info!(?place, "peek_at");
293-
let Some(local) = place.as_local() else {
294-
tcx.sess.span_err(call.span, "rustc_peek: argument was not a local");
295-
return;
296-
};
297-
298-
if !flow_state.contains(local) {
299-
tcx.sess.span_err(call.span, "rustc_peek: bit not set");
300-
}
301-
}
302-
}
303-
304275
impl<'tcx> RustcPeekAt<'tcx> for MaybeLiveLocals {
305276
fn peek_at(
306277
&self,

‎compiler/rustc_span/src/symbol.rs

-1
Original file line numberDiff line numberDiff line change
@@ -1128,7 +1128,6 @@ symbols! {
11281128
rustc_partition_reused,
11291129
rustc_peek,
11301130
rustc_peek_definite_init,
1131-
rustc_peek_indirectly_mutable,
11321131
rustc_peek_liveness,
11331132
rustc_peek_maybe_init,
11341133
rustc_peek_maybe_uninit,

‎src/test/ui/consts/qualif-indirect-mutation-fail.rs

+20
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
#![feature(const_mut_refs)]
33
#![feature(const_precise_live_drops)]
44
#![feature(const_swap)]
5+
#![feature(raw_ref_op)]
56

67
// Mutable borrow of a field with drop impl.
78
pub const fn f() {
@@ -42,3 +43,22 @@ pub const fn g2<T>() {
4243
let _ = x.is_some();
4344
let _y = x; //~ ERROR destructors cannot be evaluated
4445
}
46+
47+
// Mutable raw reference to a Drop type.
48+
pub const fn address_of_mut() {
49+
let mut x: Option<String> = None; //~ ERROR destructors cannot be evaluated
50+
&raw mut x;
51+
52+
let mut y: Option<String> = None; //~ ERROR destructors cannot be evaluated
53+
std::ptr::addr_of_mut!(y);
54+
}
55+
56+
// Const raw reference to a Drop type. Conservatively assumed to allow mutation
57+
// until resolution of https://github.com/rust-lang/rust/issues/56604.
58+
pub const fn address_of_const() {
59+
let x: Option<String> = None; //~ ERROR destructors cannot be evaluated
60+
&raw const x;
61+
62+
let y: Option<String> = None; //~ ERROR destructors cannot be evaluated
63+
std::ptr::addr_of!(y);
64+
}
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,57 @@
11
error[E0493]: destructors cannot be evaluated at compile-time
2-
--> $DIR/qualif-indirect-mutation-fail.rs:8:9
2+
--> $DIR/qualif-indirect-mutation-fail.rs:9:9
33
|
44
LL | let mut a: (u32, Option<String>) = (0, None);
55
| ^^^^^ constant functions cannot evaluate destructors
66

77
error[E0493]: destructors cannot be evaluated at compile-time
8-
--> $DIR/qualif-indirect-mutation-fail.rs:14:9
8+
--> $DIR/qualif-indirect-mutation-fail.rs:15:9
99
|
1010
LL | let mut x = None;
1111
| ^^^^^ constants cannot evaluate destructors
1212

1313
error[E0493]: destructors cannot be evaluated at compile-time
14-
--> $DIR/qualif-indirect-mutation-fail.rs:30:9
14+
--> $DIR/qualif-indirect-mutation-fail.rs:31:9
1515
|
1616
LL | let _z = x;
1717
| ^^ constants cannot evaluate destructors
1818

1919
error[E0493]: destructors cannot be evaluated at compile-time
20-
--> $DIR/qualif-indirect-mutation-fail.rs:35:9
20+
--> $DIR/qualif-indirect-mutation-fail.rs:36:9
2121
|
2222
LL | let x: Option<T> = None;
2323
| ^ constant functions cannot evaluate destructors
2424

2525
error[E0493]: destructors cannot be evaluated at compile-time
26-
--> $DIR/qualif-indirect-mutation-fail.rs:43:9
26+
--> $DIR/qualif-indirect-mutation-fail.rs:44:9
2727
|
2828
LL | let _y = x;
2929
| ^^ constant functions cannot evaluate destructors
3030

31-
error: aborting due to 5 previous errors
31+
error[E0493]: destructors cannot be evaluated at compile-time
32+
--> $DIR/qualif-indirect-mutation-fail.rs:52:9
33+
|
34+
LL | let mut y: Option<String> = None;
35+
| ^^^^^ constant functions cannot evaluate destructors
36+
37+
error[E0493]: destructors cannot be evaluated at compile-time
38+
--> $DIR/qualif-indirect-mutation-fail.rs:49:9
39+
|
40+
LL | let mut x: Option<String> = None;
41+
| ^^^^^ constant functions cannot evaluate destructors
42+
43+
error[E0493]: destructors cannot be evaluated at compile-time
44+
--> $DIR/qualif-indirect-mutation-fail.rs:62:9
45+
|
46+
LL | let y: Option<String> = None;
47+
| ^ constant functions cannot evaluate destructors
48+
49+
error[E0493]: destructors cannot be evaluated at compile-time
50+
--> $DIR/qualif-indirect-mutation-fail.rs:59:9
51+
|
52+
LL | let x: Option<String> = None;
53+
| ^ constant functions cannot evaluate destructors
54+
55+
error: aborting due to 9 previous errors
3256

3357
For more information about this error, try `rustc --explain E0493`.

‎src/test/ui/consts/qualif-indirect-mutation-pass.rs

+8
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,22 @@
33
#![feature(const_mut_refs)]
44
#![feature(const_precise_live_drops)]
55

6+
// Mutable reference allows only mutation of !Drop place.
67
pub const fn f() {
78
let mut x: (Option<String>, u32) = (None, 0);
89
let mut a = 10;
910
*(&mut a) = 11;
1011
x.1 = a;
1112
}
1213

14+
// Mutable reference allows only mutation of !Drop place.
1315
pub const fn g() {
1416
let mut a: (u32, Option<String>) = (0, None);
1517
let _ = &mut a.0;
1618
}
19+
20+
// Shared reference does not allow for mutation.
21+
pub const fn h() {
22+
let x: Option<String> = None;
23+
let _ = &x;
24+
}

‎src/test/ui/mir-dataflow/indirect-mutation-offset.rs

-48
This file was deleted.

‎src/test/ui/mir-dataflow/indirect-mutation-offset.stderr

-10
This file was deleted.

0 commit comments

Comments
 (0)
Please sign in to comment.