Join GitHub today
GitHub is home to over 31 million developers working together to host and review code, manage projects, and build software together.
Sign up[MIR] double drop with slice patterns #34708
Comments
arielb1
added
I-wrong
A-mir
labels
Jul 7, 2016
brson
added
I-nominated
T-lang
labels
Jul 7, 2016
This comment has been minimized.
This comment has been minimized.
|
Should this go on the mir milestone? |
This comment has been minimized.
This comment has been minimized.
|
|
arielb1
added
T-compiler
T-lang
and removed
T-lang
labels
Jul 8, 2016
This comment has been minimized.
This comment has been minimized.
|
Fixing the issue for arrays would be quite easy. The primary problem is that you can move out of slices #![feature(slice_patterns, advanced_slice_patterns, box_syntax, box_patterns)]
fn cond() -> bool { false }
fn make() -> Box<[Box<[Box<[String]>]>]> {
box [box [box ["hello".to_string(), "world".to_string()]]]
}
fn main() {
let b3 = make();
match (b3, cond()) {
(box [box [box [s, ..], ..], ..], true) => {
println!("{}", s);
}
(box [.., box [.., box [.., s]]], _) => {
println!("{}", s);
}
_ => {}
}
}Here we must drop only "hello" in the first branch, and only "world" in the second branch, but I do not see any reliable way of doing it. |
aturon
removed
the
I-nominated
label
Jul 14, 2016
This comment has been minimized.
This comment has been minimized.
|
This is not blocking the move to MIR, as @arielb1 notes. |
This comment has been minimized.
This comment has been minimized.
|
Still an issue in |
bluss
referenced this issue
Jan 8, 2017
Open
Tracking issue for RFC #495 (features `slice_patterns` and `advanced_slice_patterns`) #23121
Mark-Simulacrum
added
C-bug
and removed
I-wrong
labels
Jul 25, 2017
This comment has been minimized.
This comment has been minimized.
|
Note that since #36353 prohibits moves out of slices, we could presumably fix things for arrays alone at this point without too much trouble. |
arielb1
added
E-mentor
I-nominated
WG-compiler-nll
labels
Oct 16, 2017
This comment has been minimized.
This comment has been minimized.
|
This is the last thing that is stopping slice patterns from being stabilized, so I think we should go forward with it. I would like to mentor this issue so that I will not be the sole maintainer of the drop elaboration code. Mentoring NotesThe issue is that drop elaboration does not handle arrays correctly. BackgroundDuring MIR generation, #![feature(slice_patterns)]
struct NoisyDrop;
impl Drop for NoisyDrop {
fn drop(&mut self) { println!("splat!"); }
}
fn main() {
let [x] = [NoisyDrop];
}generates the following MIR:
To ensure that locals that have already been moved aren't dropped again, Rust uses flag-based dynamic drop. The compiler tracks which locals and parts of locals have been moved out, so a This is done by drop elaboration, which is implemented in rustc_mir::util::elaborate_drops (the codegen part for each individual drop), rustc_mir::transform::elaborate_drops (the transform sequence), and rustc_mir::dataflow (the analysis). Drop elaboration uses local variable "drop flags" to track the initialization state of each local fragment (called a "move path"), and rewrites each MIR drop into code that checks these drop flags and only drops what is initialized. The move path analysis is currently not implemented for arrays, so array fragments are currently shortcutted. This causes the double-drop - moves out of array elements are ignored when checking drop flags. Implementation notesSo, in order to remove the shortcut, we have to implement move paths for arrays. The code for handling move paths at rustc_mir::dataflow::move_paths::builder needs to be adapted, and the code at open_drop_for_array needs to be changed to consume the new move paths and only drop what is initialized (see e.g. the code for I think that a first implementation that works like structs, and creates a field for every array index, would work. Before we stabilize slice patterns, I would like to modify the implementation to consolidate ranges of indexes and generate only a single entry for them. Afterwards, I would like to see a good amount of tests in the dynamic-drop test using the runner there (see the existing tests - this tests that drops are handled correctly, including in panic paths), including tests for patterns matching from both ends with potential overlap - e.g. if maybe {
let [_, ..b] = array;
} else {
let [..b, _, _x] = array;
}The drop elaboration code is subtle code that can easily cause miscompilations, so the more tests, the better (if you find something that looks suspicious, adding a test and potentionally a bugfix would be very cool). Bonus Points - Slice PatternsI'll note that move paths off slices, which can have several lengths, aren't supported, because I have no good idea of how to track drop flags for something like this (you can match slices for both ends, and for small lengths you might have overlap): fn foo(x: Box<[Box<[Box<u32>]>]>) {
match rand() {
0 => match x {
box [box [x, ..], ..] => use(x)
},
1 => match x {
box [.., box [x, ..]] => use(x)
},
2 => match x {
box [_, box [_, x, ..], ..] => use(x)
}
// etc.
}
}Because I expect this sort of thing to be rare, for bonus points I would like it if you find some "brute-force" way of handling this that is exponential at these ugly cases but linear in sane situations. |
This comment has been minimized.
This comment has been minimized.
|
triage: P-medium @rust-lang/lang team agrees that when this is done we could consider stabilizing slice patterns. |
arielb1 commentedJul 7, 2016
Version
STR
Expected Result
NoisyDropgets dropped onceActual Result
NoisyDropis dropped twice