Skip to content

Commit 8f5aabe

Browse files
authored
Rollup merge of rust-lang#148407 - Urgau:suspicious_int_mutable_consts, r=JonathanBrouwer
Warn against calls which mutate an interior mutable `const`-item ## `const_item_interior_mutations` ~~`interior_mutable_const_item_mutations`~~ ~~`suspicious_mutation_of_interior_mutable_consts`~~ *warn-by-default* The `const_item_interior_mutations` lint checks for calls which mutates an interior mutable const-item. ### Example ```rust use std::sync::Once; const INIT: Once = Once::new(); // using `INIT` will always create a temporary and // never modify it-self on use, should be a `static` // instead for shared use fn init() { INIT.call_once(|| { println!("Once::call_once first call"); }); } ``` ```text warning: mutation of an interior mutable `const` item with call to `call_once` --> a.rs:11:5 | 11 | INIT.call_once(|| { | ^--- | | | _____`INIT` is a interior mutable `const` item of type `std::sync::Once` | | 12 | | println!("Once::call_once first call"); 13 | | }); | |______^ | = note: each usage of a `const` item creates a new temporary = note: only the temporaries and never the original `const INIT` will be modified = help: for more details on interior mutability see <https://doc.rust-lang.org/reference/interior-mutability.html> = note: `#[warn(const_item_interior_mutations)]` on by default help: for a shared instance of `INIT`, consider making it a `static` item instead | 6 - const INIT: Once = Once::new(); // using `INIT` will always create a temporary and 6 + static INIT: Once = Once::new(); // using `INIT` will always create a temporary and | ``` ### Explanation Calling a method which mutates an interior mutable type has no effect as const-item are essentially inlined wherever they are used, meaning that they are copied directly into the relevant context when used rendering modification through interior mutability ineffective across usage of that const-item. The current implementation of this lint only warns on significant `std` and `core` interior mutable types, like `Once`, `AtomicI32`, ... this is done out of prudence and may be extended in the future. ---- This PR is an targeted alternative to rust-lang#132146. It avoids false-positives by adding an internal-only attribute `#[rustc_should_not_be_called_on_const_items]` on methods and functions that mutates an interior mutale type through a shared reference (mutable refrences are already linted by the `const_item_mutation` lint). It should also be noted that this is NOT an uplift of the more general [`clippy::borrow_interior_mutable_const`](https://rust-lang.github.io/rust-clippy/master/index.html#/borrow_interior_mutable_const) lint, which is a much more general lint regarding borrow of interior mutable types, but has false-positives that are completly avoided by this lint. A simple [GitHub Search](https://github.com/search?q=lang%3Arust+%2F%28%3F-i%29const+%5Ba-zA-Z0-9_%5D*%3A+Once%2F&type=code) reveals many instance where the user probably wanted to use a `static`-item instead. ---- ````@rustbot```` labels +I-lang-nominated +T-lang cc ````@traviscross```` r? compiler Fixes [IRLO - Forbidding creation of constant mutexes, etc](https://internals.rust-lang.org/t/forbidding-creation-of-constant-mutexes-etc/19005) Fixes rust-lang#132028 Fixes rust-lang#40543
2 parents d6270ad + cdfb3dc commit 8f5aabe

File tree

10 files changed

+97
-0
lines changed

10 files changed

+97
-0
lines changed

core/src/cell.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -430,6 +430,7 @@ impl<T> Cell<T> {
430430
#[inline]
431431
#[stable(feature = "rust1", since = "1.0.0")]
432432
#[rustc_const_unstable(feature = "const_cell_traits", issue = "147787")]
433+
#[rustc_should_not_be_called_on_const_items]
433434
pub const fn set(&self, val: T)
434435
where
435436
T: [const] Destruct,
@@ -461,6 +462,7 @@ impl<T> Cell<T> {
461462
/// ```
462463
#[inline]
463464
#[stable(feature = "move_cell", since = "1.17.0")]
465+
#[rustc_should_not_be_called_on_const_items]
464466
pub fn swap(&self, other: &Self) {
465467
// This function documents that it *will* panic, and intrinsics::is_nonoverlapping doesn't
466468
// do the check in const, so trying to use it here would be inviting unnecessary fragility.
@@ -505,6 +507,7 @@ impl<T> Cell<T> {
505507
#[stable(feature = "move_cell", since = "1.17.0")]
506508
#[rustc_const_stable(feature = "const_cell", since = "1.88.0")]
507509
#[rustc_confusables("swap")]
510+
#[rustc_should_not_be_called_on_const_items]
508511
pub const fn replace(&self, val: T) -> T {
509512
// SAFETY: This can cause data races if called from a separate thread,
510513
// but `Cell` is `!Sync` so this won't happen.
@@ -546,6 +549,7 @@ impl<T: Copy> Cell<T> {
546549
#[inline]
547550
#[stable(feature = "rust1", since = "1.0.0")]
548551
#[rustc_const_stable(feature = "const_cell", since = "1.88.0")]
552+
#[rustc_should_not_be_called_on_const_items]
549553
pub const fn get(&self) -> T {
550554
// SAFETY: This can cause data races if called from a separate thread,
551555
// but `Cell` is `!Sync` so this won't happen.
@@ -566,6 +570,7 @@ impl<T: Copy> Cell<T> {
566570
#[inline]
567571
#[stable(feature = "cell_update", since = "1.88.0")]
568572
#[rustc_const_unstable(feature = "const_cell_traits", issue = "147787")]
573+
#[rustc_should_not_be_called_on_const_items]
569574
pub const fn update(&self, f: impl [const] FnOnce(T) -> T)
570575
where
571576
// FIXME(const-hack): `Copy` should imply `const Destruct`
@@ -994,6 +999,7 @@ impl<T> RefCell<T> {
994999
#[track_caller]
9951000
#[rustc_confusables("swap")]
9961001
#[rustc_const_unstable(feature = "const_ref_cell", issue = "137844")]
1002+
#[rustc_should_not_be_called_on_const_items]
9971003
pub const fn replace(&self, t: T) -> T {
9981004
mem::replace(&mut self.borrow_mut(), t)
9991005
}
@@ -1017,6 +1023,7 @@ impl<T> RefCell<T> {
10171023
#[inline]
10181024
#[stable(feature = "refcell_replace_swap", since = "1.35.0")]
10191025
#[track_caller]
1026+
#[rustc_should_not_be_called_on_const_items]
10201027
pub fn replace_with<F: FnOnce(&mut T) -> T>(&self, f: F) -> T {
10211028
let mut_borrow = &mut *self.borrow_mut();
10221029
let replacement = f(mut_borrow);
@@ -1046,6 +1053,7 @@ impl<T> RefCell<T> {
10461053
#[inline]
10471054
#[stable(feature = "refcell_swap", since = "1.24.0")]
10481055
#[rustc_const_unstable(feature = "const_ref_cell", issue = "137844")]
1056+
#[rustc_should_not_be_called_on_const_items]
10491057
pub const fn swap(&self, other: &Self) {
10501058
mem::swap(&mut *self.borrow_mut(), &mut *other.borrow_mut())
10511059
}
@@ -1087,6 +1095,7 @@ impl<T: ?Sized> RefCell<T> {
10871095
#[inline]
10881096
#[track_caller]
10891097
#[rustc_const_unstable(feature = "const_ref_cell", issue = "137844")]
1098+
#[rustc_should_not_be_called_on_const_items]
10901099
pub const fn borrow(&self) -> Ref<'_, T> {
10911100
match self.try_borrow() {
10921101
Ok(b) => b,
@@ -1123,6 +1132,7 @@ impl<T: ?Sized> RefCell<T> {
11231132
#[inline]
11241133
#[cfg_attr(feature = "debug_refcell", track_caller)]
11251134
#[rustc_const_unstable(feature = "const_ref_cell", issue = "137844")]
1135+
#[rustc_should_not_be_called_on_const_items]
11261136
pub const fn try_borrow(&self) -> Result<Ref<'_, T>, BorrowError> {
11271137
match BorrowRef::new(&self.borrow) {
11281138
Some(b) => {
@@ -1185,6 +1195,7 @@ impl<T: ?Sized> RefCell<T> {
11851195
#[inline]
11861196
#[track_caller]
11871197
#[rustc_const_unstable(feature = "const_ref_cell", issue = "137844")]
1198+
#[rustc_should_not_be_called_on_const_items]
11881199
pub const fn borrow_mut(&self) -> RefMut<'_, T> {
11891200
match self.try_borrow_mut() {
11901201
Ok(b) => b,
@@ -1218,6 +1229,7 @@ impl<T: ?Sized> RefCell<T> {
12181229
#[inline]
12191230
#[cfg_attr(feature = "debug_refcell", track_caller)]
12201231
#[rustc_const_unstable(feature = "const_ref_cell", issue = "137844")]
1232+
#[rustc_should_not_be_called_on_const_items]
12211233
pub const fn try_borrow_mut(&self) -> Result<RefMut<'_, T>, BorrowMutError> {
12221234
match BorrowRefMut::new(&self.borrow) {
12231235
Some(b) => {
@@ -2356,6 +2368,7 @@ impl<T> UnsafeCell<T> {
23562368
/// ```
23572369
#[inline]
23582370
#[unstable(feature = "unsafe_cell_access", issue = "136327")]
2371+
#[rustc_should_not_be_called_on_const_items]
23592372
pub const unsafe fn replace(&self, value: T) -> T {
23602373
// SAFETY: pointer comes from `&self` so naturally satisfies invariants.
23612374
unsafe { ptr::replace(self.get(), value) }
@@ -2404,6 +2417,7 @@ impl<T: ?Sized> UnsafeCell<T> {
24042417
#[rustc_const_stable(feature = "const_unsafecell_get", since = "1.32.0")]
24052418
#[rustc_as_ptr]
24062419
#[rustc_never_returns_null_ptr]
2420+
#[rustc_should_not_be_called_on_const_items]
24072421
pub const fn get(&self) -> *mut T {
24082422
// We can just cast the pointer from `UnsafeCell<T>` to `T` because of
24092423
// #[repr(transparent)]. This exploits std's special status, there is
@@ -2493,6 +2507,7 @@ impl<T: ?Sized> UnsafeCell<T> {
24932507
/// ```
24942508
#[inline]
24952509
#[unstable(feature = "unsafe_cell_access", issue = "136327")]
2510+
#[rustc_should_not_be_called_on_const_items]
24962511
pub const unsafe fn as_ref_unchecked(&self) -> &T {
24972512
// SAFETY: pointer comes from `&self` so naturally satisfies ptr-to-ref invariants.
24982513
unsafe { self.get().as_ref_unchecked() }
@@ -2521,6 +2536,7 @@ impl<T: ?Sized> UnsafeCell<T> {
25212536
#[inline]
25222537
#[unstable(feature = "unsafe_cell_access", issue = "136327")]
25232538
#[allow(clippy::mut_from_ref)]
2539+
#[rustc_should_not_be_called_on_const_items]
25242540
pub const unsafe fn as_mut_unchecked(&self) -> &mut T {
25252541
// SAFETY: pointer comes from `&self` so naturally satisfies ptr-to-ref invariants.
25262542
unsafe { self.get().as_mut_unchecked() }
@@ -2608,6 +2624,7 @@ impl<T: ?Sized> SyncUnsafeCell<T> {
26082624
#[inline]
26092625
#[rustc_as_ptr]
26102626
#[rustc_never_returns_null_ptr]
2627+
#[rustc_should_not_be_called_on_const_items]
26112628
pub const fn get(&self) -> *mut T {
26122629
self.value.get()
26132630
}

core/src/cell/lazy.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,7 @@ impl<T, F: FnOnce() -> T> LazyCell<T, F> {
134134
/// ```
135135
#[inline]
136136
#[stable(feature = "lazy_cell", since = "1.80.0")]
137+
#[rustc_should_not_be_called_on_const_items]
137138
pub fn force(this: &LazyCell<T, F>) -> &T {
138139
// SAFETY:
139140
// This invalidates any mutable references to the data. The resulting

core/src/cell/once.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@ impl<T> OnceCell<T> {
8888
/// ```
8989
#[inline]
9090
#[stable(feature = "once_cell", since = "1.70.0")]
91+
#[rustc_should_not_be_called_on_const_items]
9192
pub fn set(&self, value: T) -> Result<(), T> {
9293
match self.try_insert(value) {
9394
Ok(_) => Ok(()),
@@ -120,6 +121,7 @@ impl<T> OnceCell<T> {
120121
/// ```
121122
#[inline]
122123
#[unstable(feature = "once_cell_try_insert", issue = "116693")]
124+
#[rustc_should_not_be_called_on_const_items]
123125
pub fn try_insert(&self, value: T) -> Result<&T, (&T, T)> {
124126
if let Some(old) = self.get() {
125127
return Err((old, value));
@@ -157,6 +159,7 @@ impl<T> OnceCell<T> {
157159
/// ```
158160
#[inline]
159161
#[stable(feature = "once_cell", since = "1.70.0")]
162+
#[rustc_should_not_be_called_on_const_items]
160163
pub fn get_or_init<F>(&self, f: F) -> &T
161164
where
162165
F: FnOnce() -> T,
@@ -231,6 +234,7 @@ impl<T> OnceCell<T> {
231234
/// assert_eq!(cell.get(), Some(&92))
232235
/// ```
233236
#[unstable(feature = "once_cell_try", issue = "109737")]
237+
#[rustc_should_not_be_called_on_const_items]
234238
pub fn get_or_try_init<F, E>(&self, f: F) -> Result<&T, E>
235239
where
236240
F: FnOnce() -> Result<T, E>,

0 commit comments

Comments
 (0)