forked from rust-lang/rust
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add lint for using a type with a destructor in a zero-length repeat expr
Currently, writing a zero-length array repeat expression (e.g. `[String::new(); 0]`) will cause the initializer value to be leaked. See rust-lang#74836 for more details There are three ways that we could potentially handle this case: 1. Run the destructor immediately after 'constructing' the zero-length array. 2. Run the destructor when the initializer value would otherwise be dropped (i.e. at the end of the lexical scope) 3. Keep the current behavior and continue to leak to the initializer Note that the 'obvious' choice (running the destructor when the array is dropped) does not work, since a zero-length array does not actually store the value we want to drop. All of these options seem likely to be surprising and inconsistent to users. Since any fully monomorphic constant can be used as the repeat length, this has the potential to cause confusing 'action at a distance' (e.g. changing a `const` from 0 to 1 results in drop order changing). Regardless of which option we decide on, we should tell users to use an empty array (`[]`) instead. This commit adds a new lint ZERO_REPEAT_WITH_DROP, which fires when a type that (potentially) has a destructor is used in a zero-length array repeat expression. If a type has no drop glue, we skip linting, since dropping it has no user-visible side effects. If we do not know if a type has drop glue (e.g. `Option<T>`), we lint anyway, since some choice of generic arguments could trigger the strange drop behavior. If the length const expression is not fully monomorphic (e.g. contains a generic parameter), the compiler requires the type used in the repeat expression to be `Copy`. Therefore, we don't need to lint in this case, since a `Copy` type can never have drop glue.
- Loading branch information
Showing
4 changed files
with
155 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
#![feature(const_generics)] | ||
#![allow(incomplete_features)] | ||
#![deny(zero_repeat_with_drop)] | ||
|
||
const ZERO: usize = 1 * 0; | ||
|
||
const fn make_val<T>(val: T) -> T { val } | ||
|
||
struct NoDropOrCopy; | ||
struct WithDropGlue(String); | ||
|
||
fn foo<T, V: Copy, F: Fn() -> T, const N: usize>(not_copy: F, copy: V) { | ||
// All of these should triger the lint | ||
let _ = [not_copy(); 0]; //~ ERROR used a type | ||
let _ = [not_copy(); 1 - 1]; //~ ERROR used a type | ||
let _ = [not_copy(); ZERO]; //~ ERROR used a type | ||
let _ = [Some(not_copy()); 0]; //~ ERROR used a type | ||
let _ = [None::<T>; 0]; //~ ERROR used a type | ||
let _ = [make_val(not_copy()); 0]; //~ ERROR used a type | ||
let _ = [String::new(); 0]; //~ ERROR used a type | ||
let _ = [WithDropGlue(String::new()); 0]; //~ ERROR used a type | ||
|
||
// None of these should trigger the lint | ||
let _ = [copy; 0]; | ||
let _ = [Some(copy); 0]; | ||
let _ = [NoDropOrCopy; 0]; | ||
let _ = [not_copy(); 1]; | ||
let _ = [copy; N]; | ||
} | ||
|
||
fn allow_it() { | ||
#[allow(zero_repeat_with_drop)] | ||
let _ = [WithDropGlue(String::new()); 1 - 1]; | ||
} | ||
|
||
fn main() {} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,79 @@ | ||
error: used a type with a destructor in a zero-length repeat expression | ||
--> $DIR/lint-zero-repeat-with-drop.rs:14:13 | ||
| | ||
LL | let _ = [not_copy(); 0]; | ||
| ^^^^^^^^^^^^^^^ help: consider using an empty array expression: `[]` | ||
| | ||
note: the lint level is defined here | ||
--> $DIR/lint-zero-repeat-with-drop.rs:3:9 | ||
| | ||
LL | #![deny(zero_repeat_with_drop)] | ||
| ^^^^^^^^^^^^^^^^^^^^^ | ||
= note: the value used here has type `T`, which may have a destructor | ||
= note: a length of zero is used, which will cause the value to be dropped in a strange location | ||
|
||
error: used a type with a destructor in a zero-length repeat expression | ||
--> $DIR/lint-zero-repeat-with-drop.rs:15:13 | ||
| | ||
LL | let _ = [not_copy(); 1 - 1]; | ||
| ^^^^^^^^^^^^^^^^^^^ help: consider using an empty array expression: `[]` | ||
| | ||
= note: the value used here has type `T`, which may have a destructor | ||
= note: a length of zero is used, which will cause the value to be dropped in a strange location | ||
|
||
error: used a type with a destructor in a zero-length repeat expression | ||
--> $DIR/lint-zero-repeat-with-drop.rs:16:13 | ||
| | ||
LL | let _ = [not_copy(); ZERO]; | ||
| ^^^^^^^^^^^^^^^^^^ help: consider using an empty array expression: `[]` | ||
| | ||
= note: the value used here has type `T`, which may have a destructor | ||
= note: a length of zero is used, which will cause the value to be dropped in a strange location | ||
|
||
error: used a type with a destructor in a zero-length repeat expression | ||
--> $DIR/lint-zero-repeat-with-drop.rs:17:13 | ||
| | ||
LL | let _ = [Some(not_copy()); 0]; | ||
| ^^^^^^^^^^^^^^^^^^^^^ help: consider using an empty array expression: `[]` | ||
| | ||
= note: the value used here has type `std::option::Option<T>`, which may have a destructor | ||
= note: a length of zero is used, which will cause the value to be dropped in a strange location | ||
|
||
error: used a type with a destructor in a zero-length repeat expression | ||
--> $DIR/lint-zero-repeat-with-drop.rs:18:13 | ||
| | ||
LL | let _ = [None::<T>; 0]; | ||
| ^^^^^^^^^^^^^^ help: consider using an empty array expression: `[]` | ||
| | ||
= note: the value used here has type `std::option::Option<T>`, which may have a destructor | ||
= note: a length of zero is used, which will cause the value to be dropped in a strange location | ||
|
||
error: used a type with a destructor in a zero-length repeat expression | ||
--> $DIR/lint-zero-repeat-with-drop.rs:19:13 | ||
| | ||
LL | let _ = [make_val(not_copy()); 0]; | ||
| ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using an empty array expression: `[]` | ||
| | ||
= note: the value used here has type `T`, which may have a destructor | ||
= note: a length of zero is used, which will cause the value to be dropped in a strange location | ||
|
||
error: used a type with a destructor in a zero-length repeat expression | ||
--> $DIR/lint-zero-repeat-with-drop.rs:20:13 | ||
| | ||
LL | let _ = [String::new(); 0]; | ||
| ^^^^^^^^^^^^^^^^^^ help: consider using an empty array expression: `[]` | ||
| | ||
= note: the value used here has type `std::string::String`, which may have a destructor | ||
= note: a length of zero is used, which will cause the value to be dropped in a strange location | ||
|
||
error: used a type with a destructor in a zero-length repeat expression | ||
--> $DIR/lint-zero-repeat-with-drop.rs:21:13 | ||
| | ||
LL | let _ = [WithDropGlue(String::new()); 0]; | ||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using an empty array expression: `[]` | ||
| | ||
= note: the value used here has type `WithDropGlue`, which may have a destructor | ||
= note: a length of zero is used, which will cause the value to be dropped in a strange location | ||
|
||
error: aborting due to 8 previous errors | ||
|