diff options
| author | Jonas Schievink <jonasschievink@gmail.com> | 2020-10-03 00:31:12 +0200 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2020-10-03 00:31:12 +0200 |
| commit | 65228686649c68f491d3b763e9dde52c23fea9d7 (patch) | |
| tree | f2868cb1c2c8fb3c56235745a1232c4b76b7501a | |
| parent | ccc020ab42b4209940b821ba4fd0e1240d3f7561 (diff) | |
| parent | 804d159c6276025e26ade90a6ef013bda33207c3 (diff) | |
Rollup merge of #77251 - dtolnay:drop, r=Aaron1011
Bypass const_item_mutation if const's type has Drop impl
Follow-up to #75573. This PR disables the const_item_mutation lint in cases that the const has a Drop impl which observes the mutation.
```rust
struct Log { msg: &'static str }
const LOG: Log = Log { msg: "" };
impl Drop for Log {
fn drop(&mut self) { println!("{}", self.msg); }
}
LOG.msg = "wow"; // prints "wow"
```
r? @Aaron1011
| -rw-r--r-- | compiler/rustc_mir/src/transform/check_const_item_mutation.rs | 31 | ||||
| -rw-r--r-- | src/test/ui/lint/lint-const-item-mutation.rs | 21 | ||||
| -rw-r--r-- | src/test/ui/lint/lint-const-item-mutation.stderr | 64 |
3 files changed, 102 insertions, 14 deletions
diff --git a/compiler/rustc_mir/src/transform/check_const_item_mutation.rs b/compiler/rustc_mir/src/transform/check_const_item_mutation.rs index 0281c478a6c..b6d57b899dd 100644 --- a/compiler/rustc_mir/src/transform/check_const_item_mutation.rs +++ b/compiler/rustc_mir/src/transform/check_const_item_mutation.rs @@ -31,6 +31,35 @@ impl<'a, 'tcx> ConstMutationChecker<'a, 'tcx> { None } } + + fn is_const_item_without_destructor(&self, local: Local) -> Option<DefId> { + let def_id = self.is_const_item(local)?; + let mut any_dtor = |_tcx, _def_id| Ok(()); + + // We avoid linting mutation of a const item if the const's type has a + // Drop impl. The Drop logic observes the mutation which was performed. + // + // pub struct Log { msg: &'static str } + // pub const LOG: Log = Log { msg: "" }; + // impl Drop for Log { + // fn drop(&mut self) { println!("{}", self.msg); } + // } + // + // LOG.msg = "wow"; // prints "wow" + // + // FIXME(https://github.com/rust-lang/rust/issues/77425): + // Drop this exception once there is a stable attribute to suppress the + // const item mutation lint for a single specific const only. Something + // equivalent to: + // + // #[const_mutation_allowed] + // pub const LOG: Log = Log { msg: "" }; + match self.tcx.calculate_dtor(def_id, &mut any_dtor) { + Some(_) => None, + None => Some(def_id), + } + } + fn lint_const_item_usage( &self, const_item: DefId, @@ -59,7 +88,7 @@ impl<'a, 'tcx> Visitor<'tcx> for ConstMutationChecker<'a, 'tcx> { // Assigning directly to a constant (e.g. `FOO = true;`) is a hard error, // so emitting a lint would be redundant. if !lhs.projection.is_empty() { - if let Some(def_id) = self.is_const_item(lhs.local) { + if let Some(def_id) = self.is_const_item_without_destructor(lhs.local) { // Don't lint on writes through a pointer // (e.g. `unsafe { *FOO = 0; *BAR.field = 1; }`) if !matches!(lhs.projection.last(), Some(PlaceElem::Deref)) { diff --git a/src/test/ui/lint/lint-const-item-mutation.rs b/src/test/ui/lint/lint-const-item-mutation.rs index 43371560e02..c49a13f1065 100644 --- a/src/test/ui/lint/lint-const-item-mutation.rs +++ b/src/test/ui/lint/lint-const-item-mutation.rs @@ -9,9 +9,26 @@ impl MyStruct { fn use_mut(&mut self) {} } +struct Mutable { + msg: &'static str, +} +impl Drop for Mutable { + fn drop(&mut self) { + println!("{}", self.msg); + } +} + +struct Mutable2 { // this one has drop glue but not a Drop impl + msg: &'static str, + other: String, +} + const ARRAY: [u8; 1] = [25]; const MY_STRUCT: MyStruct = MyStruct { field: true, inner_array: ['a'], raw_ptr: 2 as *mut u8 }; const RAW_PTR: *mut u8 = 1 as *mut u8; +const MUTABLE: Mutable = Mutable { msg: "" }; +const MUTABLE2: Mutable2 = Mutable2 { msg: "", other: String::new() }; +const VEC: Vec<i32> = Vec::new(); fn main() { ARRAY[0] = 5; //~ WARN attempting to modify @@ -29,4 +46,8 @@ fn main() { *RAW_PTR = 0; *MY_STRUCT.raw_ptr = 0; } + + MUTABLE.msg = "wow"; // no warning, because Drop observes the mutation + MUTABLE2.msg = "wow"; //~ WARN attempting to modify + VEC.push(0); //~ WARN taking a mutable reference to a `const` item } diff --git a/src/test/ui/lint/lint-const-item-mutation.stderr b/src/test/ui/lint/lint-const-item-mutation.stderr index c5a221128ff..11b5124b2d2 100644 --- a/src/test/ui/lint/lint-const-item-mutation.stderr +++ b/src/test/ui/lint/lint-const-item-mutation.stderr @@ -1,5 +1,5 @@ warning: attempting to modify a `const` item - --> $DIR/lint-const-item-mutation.rs:17:5 + --> $DIR/lint-const-item-mutation.rs:34:5 | LL | ARRAY[0] = 5; | ^^^^^^^^^^^^ @@ -7,39 +7,39 @@ LL | ARRAY[0] = 5; = note: `#[warn(const_item_mutation)]` on by default = note: each usage of a `const` item creates a new temporary - the original `const` item will not be modified note: `const` item defined here - --> $DIR/lint-const-item-mutation.rs:12:1 + --> $DIR/lint-const-item-mutation.rs:26:1 | LL | const ARRAY: [u8; 1] = [25]; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: attempting to modify a `const` item - --> $DIR/lint-const-item-mutation.rs:18:5 + --> $DIR/lint-const-item-mutation.rs:35:5 | LL | MY_STRUCT.field = false; | ^^^^^^^^^^^^^^^^^^^^^^^ | = note: each usage of a `const` item creates a new temporary - the original `const` item will not be modified note: `const` item defined here - --> $DIR/lint-const-item-mutation.rs:13:1 + --> $DIR/lint-const-item-mutation.rs:27:1 | LL | const MY_STRUCT: MyStruct = MyStruct { field: true, inner_array: ['a'], raw_ptr: 2 as *mut u8 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: attempting to modify a `const` item - --> $DIR/lint-const-item-mutation.rs:19:5 + --> $DIR/lint-const-item-mutation.rs:36:5 | LL | MY_STRUCT.inner_array[0] = 'b'; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: each usage of a `const` item creates a new temporary - the original `const` item will not be modified note: `const` item defined here - --> $DIR/lint-const-item-mutation.rs:13:1 + --> $DIR/lint-const-item-mutation.rs:27:1 | LL | const MY_STRUCT: MyStruct = MyStruct { field: true, inner_array: ['a'], raw_ptr: 2 as *mut u8 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: taking a mutable reference to a `const` item - --> $DIR/lint-const-item-mutation.rs:20:5 + --> $DIR/lint-const-item-mutation.rs:37:5 | LL | MY_STRUCT.use_mut(); | ^^^^^^^^^^^^^^^^^^^ @@ -52,13 +52,13 @@ note: mutable reference created due to call to this method LL | fn use_mut(&mut self) {} | ^^^^^^^^^^^^^^^^^^^^^ note: `const` item defined here - --> $DIR/lint-const-item-mutation.rs:13:1 + --> $DIR/lint-const-item-mutation.rs:27:1 | LL | const MY_STRUCT: MyStruct = MyStruct { field: true, inner_array: ['a'], raw_ptr: 2 as *mut u8 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: taking a mutable reference to a `const` item - --> $DIR/lint-const-item-mutation.rs:21:5 + --> $DIR/lint-const-item-mutation.rs:38:5 | LL | &mut MY_STRUCT; | ^^^^^^^^^^^^^^ @@ -66,13 +66,13 @@ LL | &mut MY_STRUCT; = note: each usage of a `const` item creates a new temporary = note: the mutable reference will refer to this temporary, not the original `const` item note: `const` item defined here - --> $DIR/lint-const-item-mutation.rs:13:1 + --> $DIR/lint-const-item-mutation.rs:27:1 | LL | const MY_STRUCT: MyStruct = MyStruct { field: true, inner_array: ['a'], raw_ptr: 2 as *mut u8 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: taking a mutable reference to a `const` item - --> $DIR/lint-const-item-mutation.rs:22:5 + --> $DIR/lint-const-item-mutation.rs:39:5 | LL | (&mut MY_STRUCT).use_mut(); | ^^^^^^^^^^^^^^^^ @@ -80,10 +80,48 @@ LL | (&mut MY_STRUCT).use_mut(); = note: each usage of a `const` item creates a new temporary = note: the mutable reference will refer to this temporary, not the original `const` item note: `const` item defined here - --> $DIR/lint-const-item-mutation.rs:13:1 + --> $DIR/lint-const-item-mutation.rs:27:1 | LL | const MY_STRUCT: MyStruct = MyStruct { field: true, inner_array: ['a'], raw_ptr: 2 as *mut u8 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -warning: 6 warnings emitted +warning: attempting to modify a `const` item + --> $DIR/lint-const-item-mutation.rs:51:5 + | +LL | MUTABLE2.msg = "wow"; + | ^^^^^^^^^^^^^^^^^^^^ + | + = note: each usage of a `const` item creates a new temporary - the original `const` item will not be modified +note: `const` item defined here + --> $DIR/lint-const-item-mutation.rs:30:1 + | +LL | const MUTABLE2: Mutable2 = Mutable2 { msg: "", other: String::new() }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: taking a mutable reference to a `const` item + --> $DIR/lint-const-item-mutation.rs:52:5 + | +LL | VEC.push(0); + | ^^^^^^^^^^^ + | + = note: each usage of a `const` item creates a new temporary + = note: the mutable reference will refer to this temporary, not the original `const` item +note: mutable reference created due to call to this method + --> $SRC_DIR/alloc/src/vec.rs:LL:COL + | +LL | / pub fn push(&mut self, value: T) { +LL | | // This will panic or abort if we would allocate > isize::MAX bytes +LL | | // or if the length increment would overflow for zero-sized types. +LL | | if self.len == self.buf.capacity() { +... | +LL | | } +LL | | } + | |_____^ +note: `const` item defined here + --> $DIR/lint-const-item-mutation.rs:31:1 + | +LL | const VEC: Vec<i32> = Vec::new(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: 8 warnings emitted |
