Skip to content

Commit 7d7004d

Browse files
authored
Rollup merge of #116421 - Urgau:inter-mut-invalid_ref_casting, r=oli-obk
Clarify `invalid_reference_casting` lint around interior mutable types This is PR intends to clarify the `invalid_reference_casting` lint around interior mutable types by adding a note for them saying that they should go through `UnsafeCell::get`. So for this code: ```rust let cell = &std::cell::UnsafeCell::new(0); let _num = &mut *(cell as *const _ as *mut i32); ``` the following note will be added to the lint output: ```diff error: casting `&T` to `&mut T` is undefined behavior, even if the reference is unused, consider instead using an `UnsafeCell` --> $DIR/reference_casting.rs:68:16 | LL | let _num = &mut *(cell as *const _ as *mut i32); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: for more information, visit <https://doc.rust-lang.org/book/ch15-05-interior-mutability.html> + = note: even for types with interior mutability, the only legal way to obtain a mutable pointer from a shared reference is through `UnsafeCell::get` ``` Suggestion are welcome around the note contents. Fixes #116410 cc `@RalfJung`
2 parents 579be69 + e46236c commit 7d7004d

File tree

5 files changed

+68
-32
lines changed

5 files changed

+68
-32
lines changed

compiler/rustc_lint/messages.ftl

+2
Original file line numberDiff line numberDiff line change
@@ -323,6 +323,8 @@ lint_invalid_reference_casting_borrow_as_mut = casting `&T` to `&mut T` is undef
323323
324324
lint_invalid_reference_casting_note_book = for more information, visit <https://doc.rust-lang.org/book/ch15-05-interior-mutability.html>
325325
326+
lint_invalid_reference_casting_note_ty_has_interior_mutability = even for types with interior mutability, the only legal way to obtain a mutable pointer from a shared reference is through `UnsafeCell::get`
327+
326328
lint_lintpass_by_hand = implementing `LintPass` by hand
327329
.help = try using `declare_lint_pass!` or `impl_lint_pass!` instead
328330

compiler/rustc_lint/src/lints.rs

+4
Original file line numberDiff line numberDiff line change
@@ -771,12 +771,16 @@ pub enum InvalidReferenceCastingDiag {
771771
BorrowAsMut {
772772
#[label]
773773
orig_cast: Option<Span>,
774+
#[note(lint_invalid_reference_casting_note_ty_has_interior_mutability)]
775+
ty_has_interior_mutability: Option<()>,
774776
},
775777
#[diag(lint_invalid_reference_casting_assign_to_ref)]
776778
#[note(lint_invalid_reference_casting_note_book)]
777779
AssignToRef {
778780
#[label]
779781
orig_cast: Option<Span>,
782+
#[note(lint_invalid_reference_casting_note_ty_has_interior_mutability)]
783+
ty_has_interior_mutability: Option<()>,
780784
},
781785
}
782786

compiler/rustc_lint/src/reference_casting.rs

+15-11
Original file line numberDiff line numberDiff line change
@@ -43,19 +43,19 @@ impl<'tcx> LateLintPass<'tcx> for InvalidReferenceCasting {
4343

4444
let init = cx.expr_or_init(e);
4545

46-
let orig_cast = if is_cast_from_const_to_mut(cx, init) {
47-
if init.span != e.span { Some(init.span) } else { None }
48-
} else {
46+
let Some(ty_has_interior_mutability) = is_cast_from_const_to_mut(cx, init) else {
4947
return;
5048
};
49+
let orig_cast = if init.span != e.span { Some(init.span) } else { None };
50+
let ty_has_interior_mutability = ty_has_interior_mutability.then_some(());
5151

5252
cx.emit_spanned_lint(
5353
INVALID_REFERENCE_CASTING,
5454
expr.span,
5555
if is_assignment {
56-
InvalidReferenceCastingDiag::AssignToRef { orig_cast }
56+
InvalidReferenceCastingDiag::AssignToRef { orig_cast, ty_has_interior_mutability }
5757
} else {
58-
InvalidReferenceCastingDiag::BorrowAsMut { orig_cast }
58+
InvalidReferenceCastingDiag::BorrowAsMut { orig_cast, ty_has_interior_mutability }
5959
},
6060
);
6161
}
@@ -104,15 +104,18 @@ fn is_operation_we_care_about<'tcx>(
104104
deref_assign_or_addr_of(e).or_else(|| ptr_write(cx, e))
105105
}
106106

107-
fn is_cast_from_const_to_mut<'tcx>(cx: &LateContext<'tcx>, orig_expr: &'tcx Expr<'tcx>) -> bool {
107+
fn is_cast_from_const_to_mut<'tcx>(
108+
cx: &LateContext<'tcx>,
109+
orig_expr: &'tcx Expr<'tcx>,
110+
) -> Option<bool> {
108111
let mut need_check_freeze = false;
109112
let mut e = orig_expr;
110113

111114
let end_ty = cx.typeck_results().node_type(orig_expr.hir_id);
112115

113116
// Bail out early if the end type is **not** a mutable pointer.
114117
if !matches!(end_ty.kind(), ty::RawPtr(TypeAndMut { ty: _, mutbl: Mutability::Mut })) {
115-
return false;
118+
return None;
116119
}
117120

118121
loop {
@@ -155,10 +158,11 @@ fn is_cast_from_const_to_mut<'tcx>(cx: &LateContext<'tcx>, orig_expr: &'tcx Expr
155158
//
156159
// We also consider non concrete skeleton types (ie generics)
157160
// to be an issue since there is no way to make it safe for abitrary types.
158-
!need_check_freeze
159-
|| inner_ty.is_freeze(cx.tcx, cx.param_env)
160-
|| !inner_ty.has_concrete_skeleton()
161+
let inner_ty_has_interior_mutability =
162+
!inner_ty.is_freeze(cx.tcx, cx.param_env) && inner_ty.has_concrete_skeleton();
163+
(!need_check_freeze || !inner_ty_has_interior_mutability)
164+
.then_some(inner_ty_has_interior_mutability)
161165
} else {
162-
false
166+
None
163167
}
164168
}

tests/ui/lint/reference_casting.rs

+8
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,10 @@ unsafe fn ref_to_mut() {
6464
let _num = &mut *num;
6565
//~^ ERROR casting `&T` to `&mut T` is undefined behavior
6666

67+
let cell = &std::cell::UnsafeCell::new(0);
68+
let _num = &mut *(cell as *const _ as *mut i32);
69+
//~^ ERROR casting `&T` to `&mut T` is undefined behavior
70+
6771
unsafe fn generic_ref_cast_mut<T>(this: &T) -> &mut T {
6872
&mut *((this as *const _) as *mut _)
6973
//~^ ERROR casting `&T` to `&mut T` is undefined behavior
@@ -106,6 +110,8 @@ unsafe fn assign_to_ref() {
106110
std::mem::transmute::<*const i32, *mut i32>(num),
107111
-1i32,
108112
);
113+
*((&std::cell::UnsafeCell::new(0)) as *const _ as *mut i32) = 5;
114+
//~^ ERROR assigning to `&T` is undefined behavior
109115

110116
let value = num as *const i32 as *mut i32;
111117
*value = 1;
@@ -148,6 +154,8 @@ unsafe fn no_warn() {
148154
*RAW_PTR = 42; // RAW_PTR is defined outside the function body,
149155
// make sure we don't ICE on it when trying to
150156
// determine if we should lint on it or not.
157+
let cell = &std::cell::UnsafeCell::new(0);
158+
let _num = &mut *(cell.get() as *mut i32);
151159

152160
fn safe_as_mut<T>(x: &std::cell::UnsafeCell<T>) -> &mut T {
153161
unsafe { &mut *std::cell::UnsafeCell::raw_get(x as *const _ as *const _) }

tests/ui/lint/reference_casting.stderr

+39-21
Original file line numberDiff line numberDiff line change
@@ -158,95 +158,104 @@ LL | let _num = &mut *num;
158158
= note: for more information, visit <https://doc.rust-lang.org/book/ch15-05-interior-mutability.html>
159159

160160
error: casting `&T` to `&mut T` is undefined behavior, even if the reference is unused, consider instead using an `UnsafeCell`
161-
--> $DIR/reference_casting.rs:68:9
161+
--> $DIR/reference_casting.rs:68:16
162+
|
163+
LL | let _num = &mut *(cell as *const _ as *mut i32);
164+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
165+
|
166+
= note: for more information, visit <https://doc.rust-lang.org/book/ch15-05-interior-mutability.html>
167+
= note: even for types with interior mutability, the only legal way to obtain a mutable pointer from a shared reference is through `UnsafeCell::get`
168+
169+
error: casting `&T` to `&mut T` is undefined behavior, even if the reference is unused, consider instead using an `UnsafeCell`
170+
--> $DIR/reference_casting.rs:72:9
162171
|
163172
LL | &mut *((this as *const _) as *mut _)
164173
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
165174
|
166175
= note: for more information, visit <https://doc.rust-lang.org/book/ch15-05-interior-mutability.html>
167176

168177
error: casting `&T` to `&mut T` is undefined behavior, even if the reference is unused, consider instead using an `UnsafeCell`
169-
--> $DIR/reference_casting.rs:73:18
178+
--> $DIR/reference_casting.rs:77:18
170179
|
171180
LL | unsafe { &mut *std::cell::UnsafeCell::raw_get(x as *const _ as *const _) }
172181
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
173182
|
174183
= note: for more information, visit <https://doc.rust-lang.org/book/ch15-05-interior-mutability.html>
175184

176185
error: casting `&T` to `&mut T` is undefined behavior, even if the reference is unused, consider instead using an `UnsafeCell`
177-
--> $DIR/reference_casting.rs:78:18
186+
--> $DIR/reference_casting.rs:82:18
178187
|
179188
LL | unsafe { &mut *std::cell::UnsafeCell::raw_get(x as *const _ as *const _) }
180189
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
181190
|
182191
= note: for more information, visit <https://doc.rust-lang.org/book/ch15-05-interior-mutability.html>
183192

184193
error: assigning to `&T` is undefined behavior, consider using an `UnsafeCell`
185-
--> $DIR/reference_casting.rs:88:5
194+
--> $DIR/reference_casting.rs:92:5
186195
|
187196
LL | *(a as *const _ as *mut _) = String::from("Replaced");
188197
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
189198
|
190199
= note: for more information, visit <https://doc.rust-lang.org/book/ch15-05-interior-mutability.html>
191200

192201
error: assigning to `&T` is undefined behavior, consider using an `UnsafeCell`
193-
--> $DIR/reference_casting.rs:90:5
202+
--> $DIR/reference_casting.rs:94:5
194203
|
195204
LL | *(a as *const _ as *mut String) += " world";
196205
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
197206
|
198207
= note: for more information, visit <https://doc.rust-lang.org/book/ch15-05-interior-mutability.html>
199208

200209
error: assigning to `&T` is undefined behavior, consider using an `UnsafeCell`
201-
--> $DIR/reference_casting.rs:92:5
210+
--> $DIR/reference_casting.rs:96:5
202211
|
203212
LL | *std::ptr::from_ref(num).cast_mut() += 1;
204213
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
205214
|
206215
= note: for more information, visit <https://doc.rust-lang.org/book/ch15-05-interior-mutability.html>
207216

208217
error: assigning to `&T` is undefined behavior, consider using an `UnsafeCell`
209-
--> $DIR/reference_casting.rs:94:5
218+
--> $DIR/reference_casting.rs:98:5
210219
|
211220
LL | *std::ptr::from_ref({ num }).cast_mut() += 1;
212221
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
213222
|
214223
= note: for more information, visit <https://doc.rust-lang.org/book/ch15-05-interior-mutability.html>
215224

216225
error: assigning to `&T` is undefined behavior, consider using an `UnsafeCell`
217-
--> $DIR/reference_casting.rs:96:5
226+
--> $DIR/reference_casting.rs:100:5
218227
|
219228
LL | *{ std::ptr::from_ref(num) }.cast_mut() += 1;
220229
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
221230
|
222231
= note: for more information, visit <https://doc.rust-lang.org/book/ch15-05-interior-mutability.html>
223232

224233
error: assigning to `&T` is undefined behavior, consider using an `UnsafeCell`
225-
--> $DIR/reference_casting.rs:98:5
234+
--> $DIR/reference_casting.rs:102:5
226235
|
227236
LL | *(std::ptr::from_ref({ num }) as *mut i32) += 1;
228237
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
229238
|
230239
= note: for more information, visit <https://doc.rust-lang.org/book/ch15-05-interior-mutability.html>
231240

232241
error: assigning to `&T` is undefined behavior, consider using an `UnsafeCell`
233-
--> $DIR/reference_casting.rs:100:5
242+
--> $DIR/reference_casting.rs:104:5
234243
|
235244
LL | *std::mem::transmute::<_, *mut i32>(num) += 1;
236245
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
237246
|
238247
= note: for more information, visit <https://doc.rust-lang.org/book/ch15-05-interior-mutability.html>
239248

240249
error: assigning to `&T` is undefined behavior, consider using an `UnsafeCell`
241-
--> $DIR/reference_casting.rs:102:5
250+
--> $DIR/reference_casting.rs:106:5
242251
|
243252
LL | *(std::mem::transmute::<_, *mut i32>(num) as *mut i32) += 1;
244253
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
245254
|
246255
= note: for more information, visit <https://doc.rust-lang.org/book/ch15-05-interior-mutability.html>
247256

248257
error: assigning to `&T` is undefined behavior, consider using an `UnsafeCell`
249-
--> $DIR/reference_casting.rs:104:5
258+
--> $DIR/reference_casting.rs:108:5
250259
|
251260
LL | / std::ptr::write(
252261
LL | |
@@ -258,7 +267,16 @@ LL | | );
258267
= note: for more information, visit <https://doc.rust-lang.org/book/ch15-05-interior-mutability.html>
259268

260269
error: assigning to `&T` is undefined behavior, consider using an `UnsafeCell`
261-
--> $DIR/reference_casting.rs:111:5
270+
--> $DIR/reference_casting.rs:113:5
271+
|
272+
LL | *((&std::cell::UnsafeCell::new(0)) as *const _ as *mut i32) = 5;
273+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
274+
|
275+
= note: for more information, visit <https://doc.rust-lang.org/book/ch15-05-interior-mutability.html>
276+
= note: even for types with interior mutability, the only legal way to obtain a mutable pointer from a shared reference is through `UnsafeCell::get`
277+
278+
error: assigning to `&T` is undefined behavior, consider using an `UnsafeCell`
279+
--> $DIR/reference_casting.rs:117:5
262280
|
263281
LL | let value = num as *const i32 as *mut i32;
264282
| ----------------------------- casting happend here
@@ -268,7 +286,7 @@ LL | *value = 1;
268286
= note: for more information, visit <https://doc.rust-lang.org/book/ch15-05-interior-mutability.html>
269287

270288
error: assigning to `&T` is undefined behavior, consider using an `UnsafeCell`
271-
--> $DIR/reference_casting.rs:114:5
289+
--> $DIR/reference_casting.rs:120:5
272290
|
273291
LL | let value = num as *const i32 as *mut i32;
274292
| ----------------------------- casting happend here
@@ -279,23 +297,23 @@ LL | *value_rebind = 1;
279297
= note: for more information, visit <https://doc.rust-lang.org/book/ch15-05-interior-mutability.html>
280298

281299
error: assigning to `&T` is undefined behavior, consider using an `UnsafeCell`
282-
--> $DIR/reference_casting.rs:116:5
300+
--> $DIR/reference_casting.rs:122:5
283301
|
284302
LL | *(num as *const i32).cast::<i32>().cast_mut() = 2;
285303
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
286304
|
287305
= note: for more information, visit <https://doc.rust-lang.org/book/ch15-05-interior-mutability.html>
288306

289307
error: assigning to `&T` is undefined behavior, consider using an `UnsafeCell`
290-
--> $DIR/reference_casting.rs:118:5
308+
--> $DIR/reference_casting.rs:124:5
291309
|
292310
LL | *(num as *const _ as usize as *mut i32) = 2;
293311
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
294312
|
295313
= note: for more information, visit <https://doc.rust-lang.org/book/ch15-05-interior-mutability.html>
296314

297315
error: assigning to `&T` is undefined behavior, consider using an `UnsafeCell`
298-
--> $DIR/reference_casting.rs:120:5
316+
--> $DIR/reference_casting.rs:126:5
299317
|
300318
LL | let value = num as *const i32 as *mut i32;
301319
| ----------------------------- casting happend here
@@ -306,7 +324,7 @@ LL | std::ptr::write(value, 2);
306324
= note: for more information, visit <https://doc.rust-lang.org/book/ch15-05-interior-mutability.html>
307325

308326
error: assigning to `&T` is undefined behavior, consider using an `UnsafeCell`
309-
--> $DIR/reference_casting.rs:122:5
327+
--> $DIR/reference_casting.rs:128:5
310328
|
311329
LL | let value = num as *const i32 as *mut i32;
312330
| ----------------------------- casting happend here
@@ -317,7 +335,7 @@ LL | std::ptr::write_unaligned(value, 2);
317335
= note: for more information, visit <https://doc.rust-lang.org/book/ch15-05-interior-mutability.html>
318336

319337
error: assigning to `&T` is undefined behavior, consider using an `UnsafeCell`
320-
--> $DIR/reference_casting.rs:124:5
338+
--> $DIR/reference_casting.rs:130:5
321339
|
322340
LL | let value = num as *const i32 as *mut i32;
323341
| ----------------------------- casting happend here
@@ -328,12 +346,12 @@ LL | std::ptr::write_volatile(value, 2);
328346
= note: for more information, visit <https://doc.rust-lang.org/book/ch15-05-interior-mutability.html>
329347

330348
error: assigning to `&T` is undefined behavior, consider using an `UnsafeCell`
331-
--> $DIR/reference_casting.rs:128:9
349+
--> $DIR/reference_casting.rs:134:9
332350
|
333351
LL | *(this as *const _ as *mut _) = a;
334352
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
335353
|
336354
= note: for more information, visit <https://doc.rust-lang.org/book/ch15-05-interior-mutability.html>
337355

338-
error: aborting due to 38 previous errors
356+
error: aborting due to 40 previous errors
339357

0 commit comments

Comments
 (0)