Use the entire type of a dropped local to compute variance (edge direction) for Polonius alpha - #161305
Conversation
|
r? @mejrs rustbot has assigned @mejrs. Use Why was this reviewer chosen?The reviewer was selected based on:
|
| /// points `live_at`. | ||
| fn add_use_live_facts_for(&mut self, value: Ty<'tcx>, live_at: &IntervalSet<PointIndex>) { | ||
| debug!("add_use_live_facts_for(value={:?})", value); | ||
| Self::record_polonius_region_variance_from_type(self.typeck, value); |
There was a problem hiding this comment.
I'm surprised we don't have a check elsewhere that asserts that we've recorded the variance for all regions.
(For the issue I was looking, I was thinking that we might want to ensure that liveness for every region var is recorded.)
There was a problem hiding this comment.
We have the exact opposite in fact! An unwrap-or-default for when we haven’t!
There was a problem hiding this comment.
What's the fallout for just an expect there?
There was a problem hiding this comment.
(That would be the fallback case that activates if I removed some type from the drop liveness, and it’s fail safe into bidirectional edges)
There was a problem hiding this comment.
that we've recorded the variance for all regions.
we don't propagate loans to dead regions throughout the CFG so I may be misunderstanding what you mean
There was a problem hiding this comment.
And the default case for a region whose variance we haven't recorded is to create bidir edges, so it wouldn't have helped to record the variance for all regions, depending on what you mean by "all". This case has to be because the variance is different in different types/drop kinds with some shared free region, and we're not recording all of these different contexts, not missing regions.
So the fun thing here looks to be the local is either not drop-live but some of its """drop kinds""" are, or it is and we needed to also, or only, record the variance of free regions in its type instead of just of the ones the actual drop-live drop kinds. Remember: NLL only records the regions in the drop kinds as live. The fact that the variance changes between these and the local's type is just the cherry on top.
There was a problem hiding this comment.
the local is either not drop-live but some of its """drop kinds""" are
That's possibly what's happening, though I'm not sure because all the parameter names seem to suggest the local is indeed drop live. The local becomes (drop) live in the next statement (I'm pretty sure, haven't fully checked), but for some reason, possibly due to assignment, its own type isn't among the drop-live kinds (only one layer in, for some reason). This might well be a bug or (more likely) an undocumented optimisation in drop live kind computation, but I don't know what it's supposed to do so I didn't dare touch it.
Before this apparently nobody needed the entire type of the local being dropped in all cases, but we do for the variance.
If the drop kinds never add anything to the variance, this PR is correct and may in fact be a slight optimisation, who knows, since it doesn't use the kinds to compute variance. If they may contain regions not in the type of the dropped local, I may lose variance information for them. This is a potential soundness issue if they appear somewhere else with an edge in only one direction, but otherwise just a risk of a compile failure (because we fail safe to a bidir edge). This can be trivially fixed by doing the variance computation on all the live kinds, at the risk of doing duplicate work.
I intentionally don't touch liveness, since it should be correct (tm).
|
@lqd and I were looking at this a bit today First, this example is a bit more minimal, which should help to understand the MIR a bit more. struct D<T: HasArg>(T::Arg);
trait HasArg {
type Arg;
}
impl<'a, T> HasArg for fn(&'a T) {
type Arg = &'a T;
}
impl<T: HasArg> Drop for D<T> {
fn drop(&mut self) {}
}
fn mk<'a, T>(r: &'a T) -> D<fn(&'a T)> {
D(r)
}
fn main() {
let b = Box::new(0u8);
let d;
d = mk(&*b);
drop(b); // ERROR: move out of borrowed...
}One thing we noticed was that the |
This comment has been minimized.
This comment has been minimized.
| /// `live_kind` is the type of a use-live of drop-live local. | ||
| /// Record the variance of any region(s) appearing in it for | ||
| /// Polonius. Does nothing if Polonius is not active. | ||
| fn record_polonius_region_variance_from_type( |
There was a problem hiding this comment.
We can name this something simpler like record_variance or something, and we shouldn't to need it to be generic and can use a Ty.
There was a problem hiding this comment.
This was resolved but looks incomplete.
There was a problem hiding this comment.
I did change the name (I picked record_variance()), but I couldn't change the type because of make_all_regions_live(), and then there's a cascade. In principle they should all be GenericArgs or Tys, but the problem is the "or". However, I could make it into a GenericArg by converting a bunch of Tys and I guess that's as good as it's going to get.
There was a problem hiding this comment.
(I'm scared of unwrapping a Ty out of them in case there's a weird edge case)
This comment has been minimized.
This comment has been minimized.
7679b11 to
92e4034
Compare
|
This PR was rebased onto a different main commit. Here's a range-diff highlighting what actually changed. Rebasing is a normal part of keeping PRs up to date, so no action is needed—this note is just to help reviewers. |
Btw, the reason that this is the case: let d = mk(&*b);introduces a FakeRead for the local, but let d;
d = mk(&*b);does not. That FakeRead is treated a use-live. This also compiles with alpha: let (d,) = (mk(&*b),);(see #53695) |
|
Thanks for looking into that! I’ve been badly swamped with teaching and admin stuff the last two weeks and haven’t had time to do much of anything really. Is there anything else we need to investigate to determine if we merge this? |
|
I had also left a couple of comments which I don't think were completed yet. |
which? |
|
I've unresolved the two. |
d78dc1d to
d406015
Compare
|
Should be fixed now! I left the commits unsquashed in case anyone wants to check I didn't mess up. |
|
Thanks! @bors squash message="Use the entire type of the live variable to compute region variance" |
|
Things are squashed (GH had added the coauthor for one of the suggestions that were applied, but ok ..., if you don't want that please force push it away), let's |
|
Confirmed the coauthorship is fine on zulip. @bors r=lqd,jackh726 rollup |
…jackh726 Use the entire type of a dropped local to compute variance (edge direction) for Polonius alpha Fixes: rust-lang#160670 The soundness issue is caused by (as suggested by the text extruder) the incorrect variance for a region, which is supposed to be bidirectional (invariant) but is registered as contravariant. Starting with this example (from the issue): ```rust use std::fmt::Debug; struct D<T: HasArg>(T::Arg); trait HasArg { type Arg: Debug; } impl<'a, T: Debug> HasArg for fn(&'a T) { type Arg = &'a T; } impl<T: HasArg> Drop for D<T> { fn drop(&mut self) { println!("{:?}", self.0); } } fn mk<'a, T: Debug>(r: &'a T) -> D<fn(&'a T)> { D(r) } fn main() { let b = Box::new(vec![vec![1]]); let d; d = mk(&*b); drop(b); // ERROR: move out of borrowed... } ``` This generates a path through MIR on the way to a drop that looks like this: ```MIR _1 = move _2 /// ... drop(_1) ``` In this instance, the types of `_1` and `_2` are `D<fn(&'?1 Vec<...>)` and `D<fn(&'?2 Vec<...>)` respectively. During liveness computation (in `liveness::trace`) region liveness is computed from drop liveness and use liveness. Additionally, for each live region (drop-live or use-live), region variance is computed for Polonius' loan propagation. Variance determines the direction of propagation across program flow. For drop-live locals (variables), the types reported in ` DropckOutlivesResult::kinds` are used to register drop live regions and compute their variances. However, instead of using the full type `D<...>` for the left-hand side of this assignment statement, `kinds` starts with a `Binder {...}` and the function type inside of it. From that it finds region `'?1` and records it as contravariant (backwards propagated). This PR addresses the issue by using the entire type of the drop-live local to compute the variance of any regions referenced inside it, at the cost of potentially doing unnecessary extra work, ~~either when iteration continues over `DropckOutlivesResult::kinds` (which should be redundant with it in most cases), or~~ if the local contains a region whose variance is actually not needed for computation or in regard to drop liveness (assuming that ever happens). It also adds some debug statements that helped me debug the issue, and a ui test for the soundness issue.
…jackh726 Use the entire type of a dropped local to compute variance (edge direction) for Polonius alpha Fixes: rust-lang#160670 The soundness issue is caused by (as suggested by the text extruder) the incorrect variance for a region, which is supposed to be bidirectional (invariant) but is registered as contravariant. Starting with this example (from the issue): ```rust use std::fmt::Debug; struct D<T: HasArg>(T::Arg); trait HasArg { type Arg: Debug; } impl<'a, T: Debug> HasArg for fn(&'a T) { type Arg = &'a T; } impl<T: HasArg> Drop for D<T> { fn drop(&mut self) { println!("{:?}", self.0); } } fn mk<'a, T: Debug>(r: &'a T) -> D<fn(&'a T)> { D(r) } fn main() { let b = Box::new(vec![vec![1]]); let d; d = mk(&*b); drop(b); // ERROR: move out of borrowed... } ``` This generates a path through MIR on the way to a drop that looks like this: ```MIR _1 = move _2 /// ... drop(_1) ``` In this instance, the types of `_1` and `_2` are `D<fn(&'?1 Vec<...>)` and `D<fn(&'?2 Vec<...>)` respectively. During liveness computation (in `liveness::trace`) region liveness is computed from drop liveness and use liveness. Additionally, for each live region (drop-live or use-live), region variance is computed for Polonius' loan propagation. Variance determines the direction of propagation across program flow. For drop-live locals (variables), the types reported in ` DropckOutlivesResult::kinds` are used to register drop live regions and compute their variances. However, instead of using the full type `D<...>` for the left-hand side of this assignment statement, `kinds` starts with a `Binder {...}` and the function type inside of it. From that it finds region `'?1` and records it as contravariant (backwards propagated). This PR addresses the issue by using the entire type of the drop-live local to compute the variance of any regions referenced inside it, at the cost of potentially doing unnecessary extra work, ~~either when iteration continues over `DropckOutlivesResult::kinds` (which should be redundant with it in most cases), or~~ if the local contains a region whose variance is actually not needed for computation or in regard to drop liveness (assuming that ever happens). It also adds some debug statements that helped me debug the issue, and a ui test for the soundness issue.
…uwer Rollup of 8 pull requests Successful merges: - #162796 (libtest: do not early exit from test runners) - #162844 (Add loan reachability traces to polonius MIR dumps) - #158186 (Guarantee 8 bytes of alignment of RawWakerVTable) - #160108 (Stabilize `windows_process_extensions_main_thread_handle`) - #161305 (Use the entire type of a dropped local to compute variance (edge direction) for Polonius alpha) - #161838 (tests: accept LLVM 24 optimization in this test) - #162825 (core: Add examples for `debug_closure_helpers`) - #162856 (Stabilize CommandExt::show_window)
…jackh726 Use the entire type of a dropped local to compute variance (edge direction) for Polonius alpha Fixes: rust-lang#160670 The soundness issue is caused by (as suggested by the text extruder) the incorrect variance for a region, which is supposed to be bidirectional (invariant) but is registered as contravariant. Starting with this example (from the issue): ```rust use std::fmt::Debug; struct D<T: HasArg>(T::Arg); trait HasArg { type Arg: Debug; } impl<'a, T: Debug> HasArg for fn(&'a T) { type Arg = &'a T; } impl<T: HasArg> Drop for D<T> { fn drop(&mut self) { println!("{:?}", self.0); } } fn mk<'a, T: Debug>(r: &'a T) -> D<fn(&'a T)> { D(r) } fn main() { let b = Box::new(vec![vec![1]]); let d; d = mk(&*b); drop(b); // ERROR: move out of borrowed... } ``` This generates a path through MIR on the way to a drop that looks like this: ```MIR _1 = move _2 /// ... drop(_1) ``` In this instance, the types of `_1` and `_2` are `D<fn(&'?1 Vec<...>)` and `D<fn(&'?2 Vec<...>)` respectively. During liveness computation (in `liveness::trace`) region liveness is computed from drop liveness and use liveness. Additionally, for each live region (drop-live or use-live), region variance is computed for Polonius' loan propagation. Variance determines the direction of propagation across program flow. For drop-live locals (variables), the types reported in ` DropckOutlivesResult::kinds` are used to register drop live regions and compute their variances. However, instead of using the full type `D<...>` for the left-hand side of this assignment statement, `kinds` starts with a `Binder {...}` and the function type inside of it. From that it finds region `'?1` and records it as contravariant (backwards propagated). This PR addresses the issue by using the entire type of the drop-live local to compute the variance of any regions referenced inside it, at the cost of potentially doing unnecessary extra work, ~~either when iteration continues over `DropckOutlivesResult::kinds` (which should be redundant with it in most cases), or~~ if the local contains a region whose variance is actually not needed for computation or in regard to drop liveness (assuming that ever happens). It also adds some debug statements that helped me debug the issue, and a ui test for the soundness issue.
Rollup of 12 pull requests Successful merges: - #161596 (coretests: Add more pattern tests.) - #162796 (libtest: do not early exit from test runners) - #162844 (Add loan reachability traces to polonius MIR dumps) - #158186 (Guarantee 8 bytes of alignment of RawWakerVTable) - #160108 (Stabilize `windows_process_extensions_main_thread_handle`) - #160212 (traits: Fix rigid alias liveness matching) - #160544 (Stabilize `feature(trim_prefix_suffix)` (`{str, [T], Path}::trim_prefix` and `{str, [T]}::trim_suffix`)) - #161305 (Use the entire type of a dropped local to compute variance (edge direction) for Polonius alpha) - #161838 (tests: accept LLVM 24 optimization in this test) - #162805 (Add `must_use` lint to `ExitCode`) - #162825 (core: Add examples for `debug_closure_helpers`) - #162856 (Stabilize CommandExt::show_window)
…jackh726 Use the entire type of a dropped local to compute variance (edge direction) for Polonius alpha Fixes: rust-lang#160670 The soundness issue is caused by (as suggested by the text extruder) the incorrect variance for a region, which is supposed to be bidirectional (invariant) but is registered as contravariant. Starting with this example (from the issue): ```rust use std::fmt::Debug; struct D<T: HasArg>(T::Arg); trait HasArg { type Arg: Debug; } impl<'a, T: Debug> HasArg for fn(&'a T) { type Arg = &'a T; } impl<T: HasArg> Drop for D<T> { fn drop(&mut self) { println!("{:?}", self.0); } } fn mk<'a, T: Debug>(r: &'a T) -> D<fn(&'a T)> { D(r) } fn main() { let b = Box::new(vec![vec![1]]); let d; d = mk(&*b); drop(b); // ERROR: move out of borrowed... } ``` This generates a path through MIR on the way to a drop that looks like this: ```MIR _1 = move _2 /// ... drop(_1) ``` In this instance, the types of `_1` and `_2` are `D<fn(&'?1 Vec<...>)` and `D<fn(&'?2 Vec<...>)` respectively. During liveness computation (in `liveness::trace`) region liveness is computed from drop liveness and use liveness. Additionally, for each live region (drop-live or use-live), region variance is computed for Polonius' loan propagation. Variance determines the direction of propagation across program flow. For drop-live locals (variables), the types reported in ` DropckOutlivesResult::kinds` are used to register drop live regions and compute their variances. However, instead of using the full type `D<...>` for the left-hand side of this assignment statement, `kinds` starts with a `Binder {...}` and the function type inside of it. From that it finds region `'?1` and records it as contravariant (backwards propagated). This PR addresses the issue by using the entire type of the drop-live local to compute the variance of any regions referenced inside it, at the cost of potentially doing unnecessary extra work, ~~either when iteration continues over `DropckOutlivesResult::kinds` (which should be redundant with it in most cases), or~~ if the local contains a region whose variance is actually not needed for computation or in regard to drop liveness (assuming that ever happens). It also adds some debug statements that helped me debug the issue, and a ui test for the soundness issue.
…jackh726 Use the entire type of a dropped local to compute variance (edge direction) for Polonius alpha Fixes: rust-lang#160670 The soundness issue is caused by (as suggested by the text extruder) the incorrect variance for a region, which is supposed to be bidirectional (invariant) but is registered as contravariant. Starting with this example (from the issue): ```rust use std::fmt::Debug; struct D<T: HasArg>(T::Arg); trait HasArg { type Arg: Debug; } impl<'a, T: Debug> HasArg for fn(&'a T) { type Arg = &'a T; } impl<T: HasArg> Drop for D<T> { fn drop(&mut self) { println!("{:?}", self.0); } } fn mk<'a, T: Debug>(r: &'a T) -> D<fn(&'a T)> { D(r) } fn main() { let b = Box::new(vec![vec![1]]); let d; d = mk(&*b); drop(b); // ERROR: move out of borrowed... } ``` This generates a path through MIR on the way to a drop that looks like this: ```MIR _1 = move _2 /// ... drop(_1) ``` In this instance, the types of `_1` and `_2` are `D<fn(&'?1 Vec<...>)` and `D<fn(&'?2 Vec<...>)` respectively. During liveness computation (in `liveness::trace`) region liveness is computed from drop liveness and use liveness. Additionally, for each live region (drop-live or use-live), region variance is computed for Polonius' loan propagation. Variance determines the direction of propagation across program flow. For drop-live locals (variables), the types reported in ` DropckOutlivesResult::kinds` are used to register drop live regions and compute their variances. However, instead of using the full type `D<...>` for the left-hand side of this assignment statement, `kinds` starts with a `Binder {...}` and the function type inside of it. From that it finds region `'?1` and records it as contravariant (backwards propagated). This PR addresses the issue by using the entire type of the drop-live local to compute the variance of any regions referenced inside it, at the cost of potentially doing unnecessary extra work, ~~either when iteration continues over `DropckOutlivesResult::kinds` (which should be redundant with it in most cases), or~~ if the local contains a region whose variance is actually not needed for computation or in regard to drop liveness (assuming that ever happens). It also adds some debug statements that helped me debug the issue, and a ui test for the soundness issue.
Rollup of 16 pull requests Successful merges: - #161596 (coretests: Add more pattern tests.) - #162796 (libtest: do not early exit from test runners) - #162844 (Add loan reachability traces to polonius MIR dumps) - #162876 (Move operations out of `rustc_middle::query::job`) - #160108 (Stabilize `windows_process_extensions_main_thread_handle`) - #160212 (traits: Fix rigid alias liveness matching) - #160544 (Stabilize `feature(trim_prefix_suffix)` (`{str, [T], Path}::trim_prefix` and `{str, [T]}::trim_suffix`)) - #161246 (Normalize non-rigid aliases in ty_known_to_outlive) - #161305 (Use the entire type of a dropped local to compute variance (edge direction) for Polonius alpha) - #161838 (tests: accept LLVM 24 optimization in this test) - #162805 (Add `must_use` lint to `ExitCode`) - #162825 (core: Add examples for `debug_closure_helpers`) - #162841 (enable asm tests for xtensa targets) - #162842 (reintroduce check RibKind::ConstParamTy did in direct consts) - #162845 (mgca: fix issue with mismatched array valtree/valtree tys) - #162856 (Stabilize CommandExt::show_window)
…jackh726 Use the entire type of a dropped local to compute variance (edge direction) for Polonius alpha Fixes: rust-lang#160670 The soundness issue is caused by (as suggested by the text extruder) the incorrect variance for a region, which is supposed to be bidirectional (invariant) but is registered as contravariant. Starting with this example (from the issue): ```rust use std::fmt::Debug; struct D<T: HasArg>(T::Arg); trait HasArg { type Arg: Debug; } impl<'a, T: Debug> HasArg for fn(&'a T) { type Arg = &'a T; } impl<T: HasArg> Drop for D<T> { fn drop(&mut self) { println!("{:?}", self.0); } } fn mk<'a, T: Debug>(r: &'a T) -> D<fn(&'a T)> { D(r) } fn main() { let b = Box::new(vec![vec![1]]); let d; d = mk(&*b); drop(b); // ERROR: move out of borrowed... } ``` This generates a path through MIR on the way to a drop that looks like this: ```MIR _1 = move _2 /// ... drop(_1) ``` In this instance, the types of `_1` and `_2` are `D<fn(&'?1 Vec<...>)` and `D<fn(&'?2 Vec<...>)` respectively. During liveness computation (in `liveness::trace`) region liveness is computed from drop liveness and use liveness. Additionally, for each live region (drop-live or use-live), region variance is computed for Polonius' loan propagation. Variance determines the direction of propagation across program flow. For drop-live locals (variables), the types reported in ` DropckOutlivesResult::kinds` are used to register drop live regions and compute their variances. However, instead of using the full type `D<...>` for the left-hand side of this assignment statement, `kinds` starts with a `Binder {...}` and the function type inside of it. From that it finds region `'?1` and records it as contravariant (backwards propagated). This PR addresses the issue by using the entire type of the drop-live local to compute the variance of any regions referenced inside it, at the cost of potentially doing unnecessary extra work, ~~either when iteration continues over `DropckOutlivesResult::kinds` (which should be redundant with it in most cases), or~~ if the local contains a region whose variance is actually not needed for computation or in regard to drop liveness (assuming that ever happens). It also adds some debug statements that helped me debug the issue, and a ui test for the soundness issue.
…uwer Rollup of 24 pull requests Successful merges: - #161596 (coretests: Add more pattern tests.) - #162177 (Properly implement the gpu-kernel ABI for amdgpu) - #162411 (Make Receiver `#[rustc_dyn_incompatible_trait]`) - #162760 (yeet alias new_from_def_id) - #162796 (libtest: do not early exit from test runners) - #162844 (Add loan reachability traces to polonius MIR dumps) - #162876 (Move operations out of `rustc_middle::query::job`) - #160108 (Stabilize `windows_process_extensions_main_thread_handle`) - #160212 (traits: Fix rigid alias liveness matching) - #160544 (Stabilize `feature(trim_prefix_suffix)` (`{str, [T], Path}::trim_prefix` and `{str, [T]}::trim_suffix`)) - #161305 (Use the entire type of a dropped local to compute variance (edge direction) for Polonius alpha) - #161838 (tests: accept LLVM 24 optimization in this test) - #162312 (core: Rewrite docs for try_as_dyn) - #162785 (Avoid creating overlapping assignments in MatchBranchSimplification) - #162805 (Add `must_use` lint to `ExitCode`) - #162825 (core: Add examples for `debug_closure_helpers`) - #162841 (enable asm tests for xtensa targets) - #162842 (reintroduce check RibKind::ConstParamTy did in direct consts) - #162845 (mgca: fix issue with mismatched array valtree/valtree tys) - #162856 (Stabilize CommandExt::show_window) - #162865 (Complex conjugate, negation and default) - #162874 (Add support for `annotate_snippets::snippet::AnnotationKind::Visible`) - #162881 (Simplify the macro for forwarding Decoder methods ) - #162888 (Fix a typo on the Armv7-R platform docs page)
…uwer Rollup of 23 pull requests Successful merges: - #161596 (coretests: Add more pattern tests.) - #162411 (Make Receiver `#[rustc_dyn_incompatible_trait]`) - #162760 (yeet alias new_from_def_id) - #162796 (libtest: do not early exit from test runners) - #162844 (Add loan reachability traces to polonius MIR dumps) - #162876 (Move operations out of `rustc_middle::query::job`) - #160108 (Stabilize `windows_process_extensions_main_thread_handle`) - #160212 (traits: Fix rigid alias liveness matching) - #160544 (Stabilize `feature(trim_prefix_suffix)` (`{str, [T], Path}::trim_prefix` and `{str, [T]}::trim_suffix`)) - #161305 (Use the entire type of a dropped local to compute variance (edge direction) for Polonius alpha) - #161838 (tests: accept LLVM 24 optimization in this test) - #162312 (core: Rewrite docs for try_as_dyn) - #162785 (Avoid creating overlapping assignments in MatchBranchSimplification) - #162805 (Add `must_use` lint to `ExitCode`) - #162825 (core: Add examples for `debug_closure_helpers`) - #162841 (enable asm tests for xtensa targets) - #162842 (reintroduce check RibKind::ConstParamTy did in direct consts) - #162845 (mgca: fix issue with mismatched array valtree/valtree tys) - #162856 (Stabilize CommandExt::show_window) - #162865 (Complex conjugate, negation and default) - #162874 (Add support for `annotate_snippets::snippet::AnnotationKind::Visible`) - #162881 (Simplify the macro for forwarding Decoder methods ) - #162888 (Fix a typo on the Armv7-R platform docs page)
Rollup merge of #161305 - amandasystems:issue-160670, r=lqd,jackh726 Use the entire type of a dropped local to compute variance (edge direction) for Polonius alpha Fixes: #160670 The soundness issue is caused by (as suggested by the text extruder) the incorrect variance for a region, which is supposed to be bidirectional (invariant) but is registered as contravariant. Starting with this example (from the issue): ```rust use std::fmt::Debug; struct D<T: HasArg>(T::Arg); trait HasArg { type Arg: Debug; } impl<'a, T: Debug> HasArg for fn(&'a T) { type Arg = &'a T; } impl<T: HasArg> Drop for D<T> { fn drop(&mut self) { println!("{:?}", self.0); } } fn mk<'a, T: Debug>(r: &'a T) -> D<fn(&'a T)> { D(r) } fn main() { let b = Box::new(vec![vec![1]]); let d; d = mk(&*b); drop(b); // ERROR: move out of borrowed... } ``` This generates a path through MIR on the way to a drop that looks like this: ```MIR _1 = move _2 /// ... drop(_1) ``` In this instance, the types of `_1` and `_2` are `D<fn(&'?1 Vec<...>)` and `D<fn(&'?2 Vec<...>)` respectively. During liveness computation (in `liveness::trace`) region liveness is computed from drop liveness and use liveness. Additionally, for each live region (drop-live or use-live), region variance is computed for Polonius' loan propagation. Variance determines the direction of propagation across program flow. For drop-live locals (variables), the types reported in ` DropckOutlivesResult::kinds` are used to register drop live regions and compute their variances. However, instead of using the full type `D<...>` for the left-hand side of this assignment statement, `kinds` starts with a `Binder {...}` and the function type inside of it. From that it finds region `'?1` and records it as contravariant (backwards propagated). This PR addresses the issue by using the entire type of the drop-live local to compute the variance of any regions referenced inside it, at the cost of potentially doing unnecessary extra work, ~~either when iteration continues over `DropckOutlivesResult::kinds` (which should be redundant with it in most cases), or~~ if the local contains a region whose variance is actually not needed for computation or in regard to drop liveness (assuming that ever happens). It also adds some debug statements that helped me debug the issue, and a ui test for the soundness issue.
|
Note This PR was benchmarked as part of triage of its containing rollup: triage URL. Finished benchmarking commit (1c9b0c4): comparison URL. Overall result: ❌✅ regressions and improvements - please read:Our benchmarks found a performance regression caused by this PR. Next Steps:
@rustbot label: +perf-regression Instruction countOur most reliable metric. Used to determine the overall result above. However, even this metric can be noisy.
Max RSS (memory usage)Results (primary -0.4%, secondary -2.2%)A less reliable metric. May be of interest, but not used to determine the overall result above.
CyclesResults (primary 2.6%, secondary 3.8%)A less reliable metric. May be of interest, but not used to determine the overall result above.
Binary sizeThis perf run didn't have relevant results for this metric. Bootstrap: missing data |
|
This is fine:
@rustbot label: +perf-regression-triaged |
View all comments
Fixes: #160670
The soundness issue is caused by (as suggested by the text extruder) the incorrect variance for a region, which is supposed to be bidirectional (invariant) but is registered as contravariant.
Starting with this example (from the issue):
This generates a path through MIR on the way to a drop that looks like this:
In this instance, the types of
_1and_2areD<fn(&'?1 Vec<...>)andD<fn(&'?2 Vec<...>)respectively.During liveness computation (in
liveness::trace) region liveness is computed from drop liveness and use liveness. Additionally, for each live region (drop-live or use-live), region variance is computed for Polonius' loan propagation. Variance determines the direction of propagation across program flow.For drop-live locals (variables), the types reported in
DropckOutlivesResult::kindsare used to register drop live regions and compute their variances. However, instead of using the full typeD<...>for the left-hand side of this assignment statement,kindsstarts with aBinder {...}and the function type inside of it. From that it finds region'?1and records it as contravariant (backwards propagated).This PR addresses the issue by using the entire type of the drop-live local to compute the variance of any regions referenced inside it, at the cost of potentially doing unnecessary extra work,
either when iteration continues overif the local contains a region whose variance is actually not needed for computation or in regard to drop liveness (assuming that ever happens).DropckOutlivesResult::kinds(which should be redundant with it in most cases), orIt also adds some debug statements that helped me debug the issue, and a ui test for the soundness issue.