-
Notifications
You must be signed in to change notification settings - Fork 12.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
generator_interior: Count match pattern bindings as borrowed for the whole guard expression #97029
Changes from all commits
ab8c50f
577bf0f
d5b7205
7db4c02
d08efde
fce4c79
7d1dbdf
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -17,6 +17,7 @@ use rustc_middle::hir::place::ProjectionKind; | |
use rustc_middle::mir::FakeReadCause; | ||
use rustc_middle::ty::{self, adjustment, AdtKind, Ty, TyCtxt}; | ||
use rustc_target::abi::VariantIdx; | ||
use ty::BorrowKind::ImmBorrow; | ||
|
||
use crate::mem_categorization as mc; | ||
|
||
|
@@ -621,7 +622,7 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { | |
FakeReadCause::ForMatchedPlace(closure_def_id), | ||
discr_place.hir_id, | ||
); | ||
self.walk_pat(discr_place, arm.pat); | ||
self.walk_pat(discr_place, arm.pat, arm.guard.is_some()); | ||
|
||
if let Some(hir::Guard::If(e)) = arm.guard { | ||
self.consume_expr(e) | ||
|
@@ -645,12 +646,17 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { | |
FakeReadCause::ForLet(closure_def_id), | ||
discr_place.hir_id, | ||
); | ||
self.walk_pat(discr_place, pat); | ||
self.walk_pat(discr_place, pat, false); | ||
} | ||
|
||
/// The core driver for walking a pattern | ||
fn walk_pat(&mut self, discr_place: &PlaceWithHirId<'tcx>, pat: &hir::Pat<'_>) { | ||
debug!("walk_pat(discr_place={:?}, pat={:?})", discr_place, pat); | ||
fn walk_pat( | ||
&mut self, | ||
discr_place: &PlaceWithHirId<'tcx>, | ||
pat: &hir::Pat<'_>, | ||
has_guard: bool, | ||
) { | ||
debug!("walk_pat(discr_place={:?}, pat={:?}, has_guard={:?})", discr_place, pat, has_guard); | ||
|
||
let tcx = self.tcx(); | ||
let ExprUseVisitor { ref mc, body_owner: _, ref mut delegate } = *self; | ||
|
@@ -671,6 +677,13 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { | |
delegate.bind(binding_place, binding_place.hir_id); | ||
} | ||
|
||
// Subtle: MIR desugaring introduces immutable borrows for each pattern | ||
// binding when lowering pattern guards to ensure that the guard does not | ||
// modify the scrutinee. | ||
if has_guard { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The tests pass with or without this change, so arguably we should remove it. That said, this feels like the more correct behavior, so I think we should leave it in. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hmm. Yes, it seems correct, but it's interesting that the tests pass either way! There is a certain amount of redundancy, it seems, between the analysis of what is borrowed etc and the "what types appear in the generator". I think perhaps we could observe the difference with this test, but maybe not? I think this will compile successfully: #![feature(generators)]
fn is_send<T: Send>(_: T) { }
fn main() {
is_send(async move {
let x = std::rc::Rc::new(22);
//match x { ref y if foo().await => () }
drop(x);
foo().await;
});
}
async fn foo() -> bool {
true
} but if you remove the comment from I guess that to really eliminate this redundancy we would drive the "do we need to include &T" check based on some set generated by this code (e.g., "is lvalue borrowed" or whatever). There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The test you provided does compile successfully. When I uncomment the The behavior is the same with and without the |
||
delegate.borrow(place, discr_place.hir_id, ImmBorrow); | ||
} | ||
|
||
// It is also a borrow or copy/move of the value being matched. | ||
// In a cases of pattern like `let pat = upvar`, don't use the span | ||
// of the pattern, as this just looks confusing, instead use the span | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
// build-pass | ||
// edition:2018 | ||
// compile-flags: -Zdrop-tracking | ||
|
||
#![feature(generators)] | ||
|
||
fn main() { | ||
let _ = static |x: u8| match x { | ||
y if { yield } == y + 1 => (), | ||
_ => (), | ||
}; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yay for simpler