ExprUseVisitor: properly report discriminant reads
This solves the "can't find the upvar" ICEs that resulted from `maybe_read_scrutinee` being unfit for purpose.
This commit is contained in:
parent
68f11a11b6
commit
9cb47c6e8e
14 changed files with 426 additions and 92 deletions
|
|
@ -943,6 +943,19 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
|
|||
}
|
||||
|
||||
/// The core driver for walking a pattern
|
||||
///
|
||||
/// This should mirror how pattern-matching gets lowered to MIR, as
|
||||
/// otherwise lowering will ICE when trying to resolve the upvars.
|
||||
///
|
||||
/// However, it is okay to approximate it here by doing *more* accesses than
|
||||
/// the actual MIR builder will, which is useful when some checks are too
|
||||
/// cumbersome to perform here. For example, if after typeck it becomes
|
||||
/// clear that only one variant of an enum is inhabited, and therefore a
|
||||
/// read of the discriminant is not necessary, `walk_pat` will have
|
||||
/// over-approximated the necessary upvar capture granularity.
|
||||
///
|
||||
/// Do note that discrepancies like these do still create obscure corners
|
||||
/// in the semantics of the language, and should be avoided if possible.
|
||||
#[instrument(skip(self), level = "debug")]
|
||||
fn walk_pat(
|
||||
&self,
|
||||
|
|
@ -952,6 +965,11 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
|
|||
) -> Result<(), Cx::Error> {
|
||||
let tcx = self.cx.tcx();
|
||||
self.cat_pattern(discr_place.clone(), pat, &mut |place, pat| {
|
||||
debug!("walk_pat: pat.kind={:?}", pat.kind);
|
||||
let read_discriminant = || {
|
||||
self.delegate.borrow_mut().borrow(place, discr_place.hir_id, BorrowKind::Immutable);
|
||||
};
|
||||
|
||||
match pat.kind {
|
||||
PatKind::Binding(_, canonical_id, ..) => {
|
||||
debug!("walk_pat: binding place={:?} pat={:?}", place, pat);
|
||||
|
|
@ -974,11 +992,7 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
|
|||
// binding when lowering pattern guards to ensure that the guard does not
|
||||
// modify the scrutinee.
|
||||
if has_guard {
|
||||
self.delegate.borrow_mut().borrow(
|
||||
place,
|
||||
discr_place.hir_id,
|
||||
BorrowKind::Immutable,
|
||||
);
|
||||
read_discriminant();
|
||||
}
|
||||
|
||||
// It is also a borrow or copy/move of the value being matched.
|
||||
|
|
@ -1014,13 +1028,71 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
|
|||
PatKind::Never => {
|
||||
// A `!` pattern always counts as an immutable read of the discriminant,
|
||||
// even in an irrefutable pattern.
|
||||
self.delegate.borrow_mut().borrow(
|
||||
place,
|
||||
discr_place.hir_id,
|
||||
BorrowKind::Immutable,
|
||||
);
|
||||
read_discriminant();
|
||||
}
|
||||
PatKind::Expr(PatExpr { kind: PatExprKind::Path(qpath), hir_id, span }) => {
|
||||
// A `Path` pattern is just a name like `Foo`. This is either a
|
||||
// named constant or else it refers to an ADT variant
|
||||
|
||||
let res = self.cx.typeck_results().qpath_res(qpath, *hir_id);
|
||||
match res {
|
||||
Res::Def(DefKind::Const, _) | Res::Def(DefKind::AssocConst, _) => {
|
||||
// Named constants have to be equated with the value
|
||||
// being matched, so that's a read of the value being matched.
|
||||
//
|
||||
// FIXME: Does the MIR code skip this read when matching on a ZST?
|
||||
// If so, we can also skip it here.
|
||||
read_discriminant();
|
||||
}
|
||||
_ => {
|
||||
// Otherwise, this is a struct/enum variant, and so it's
|
||||
// only a read if we need to read the discriminant.
|
||||
if self.is_multivariant_adt(place.place.ty(), *span) {
|
||||
read_discriminant();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
PatKind::Expr(_) | PatKind::Range(..) => {
|
||||
// When matching against a literal or range, we need to
|
||||
// borrow the place to compare it against the pattern.
|
||||
//
|
||||
// FIXME: What if the type being matched only has one
|
||||
// possible value?
|
||||
// FIXME: What if the range is the full range of the type
|
||||
// and doesn't actually require a discriminant read?
|
||||
read_discriminant();
|
||||
}
|
||||
PatKind::Struct(..) | PatKind::TupleStruct(..) => {
|
||||
if self.is_multivariant_adt(place.place.ty(), pat.span) {
|
||||
read_discriminant();
|
||||
}
|
||||
}
|
||||
PatKind::Slice(lhs, wild, rhs) => {
|
||||
// We don't need to test the length if the pattern is `[..]`
|
||||
if matches!((lhs, wild, rhs), (&[], Some(_), &[]))
|
||||
// Arrays have a statically known size, so
|
||||
// there is no need to read their length
|
||||
|| place.place.ty().peel_refs().is_array()
|
||||
{
|
||||
// No read necessary
|
||||
} else {
|
||||
read_discriminant();
|
||||
}
|
||||
}
|
||||
PatKind::Or(_)
|
||||
| PatKind::Box(_)
|
||||
| PatKind::Ref(..)
|
||||
| PatKind::Guard(..)
|
||||
| PatKind::Tuple(..)
|
||||
| PatKind::Wild
|
||||
| PatKind::Missing
|
||||
| PatKind::Err(_) => {
|
||||
// If the PatKind is Or, Box, Ref, Guard, or Tuple, the relevant accesses
|
||||
// are made later as these patterns contains subpatterns.
|
||||
// If the PatKind is Missing, Wild or Err, any relevant accesses are made when processing
|
||||
// the other patterns that are part of the match
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
|
@ -1904,6 +1976,14 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
|
|||
}
|
||||
}
|
||||
|
||||
/// Checks whether a type has multiple variants, and therefore, whether a
|
||||
/// read of the discriminant might be necessary. Note that the actual MIR
|
||||
/// builder code does a more specific check, filtering out variants that
|
||||
/// happen to be uninhabited.
|
||||
///
|
||||
/// Here, we cannot perform such an accurate checks, because querying
|
||||
/// whether a type is inhabited requires that it has been fully inferred,
|
||||
/// which cannot be guaranteed at this point.
|
||||
fn is_multivariant_adt(&self, ty: Ty<'tcx>, span: Span) -> bool {
|
||||
if let ty::Adt(def, _) = self.cx.structurally_resolve_type(span, ty).kind() {
|
||||
// Note that if a non-exhaustive SingleVariant is defined in another crate, we need
|
||||
|
|
|
|||
|
|
@ -1,17 +0,0 @@
|
|||
//@ known-bug: #137467
|
||||
//@ edition: 2021
|
||||
enum Camera {
|
||||
Normal { base_transform: i32 },
|
||||
Volume { transform: i32 },
|
||||
}
|
||||
|
||||
fn draw_ui(camera: &mut Camera) {
|
||||
|| {
|
||||
let (Camera::Normal {
|
||||
base_transform: _transform,
|
||||
}
|
||||
| Camera::Volume {
|
||||
transform: _transform,
|
||||
}) = camera;
|
||||
};
|
||||
}
|
||||
|
|
@ -1,18 +0,0 @@
|
|||
//@ known-bug: #137467
|
||||
//@ edition: 2021
|
||||
|
||||
enum Camera {
|
||||
Normal { base_transform: i32 },
|
||||
Volume { transform: i32 },
|
||||
}
|
||||
|
||||
fn draw_ui(camera: &mut Camera) {
|
||||
|| {
|
||||
let (Camera::Normal {
|
||||
base_transform: _,
|
||||
}
|
||||
| Camera::Volume {
|
||||
transform: _,
|
||||
}) = camera;
|
||||
};
|
||||
}
|
||||
|
|
@ -1,8 +0,0 @@
|
|||
//@ known-bug: #137467
|
||||
//@ edition: 2021
|
||||
|
||||
fn meow(x: (u32, u32, u32)) {
|
||||
let f = || {
|
||||
let ((0, a, _) | (_, _, a)) = x;
|
||||
};
|
||||
}
|
||||
|
|
@ -22,6 +22,7 @@ fn multi_variant_enum() {
|
|||
//~| ERROR Min Capture analysis includes:
|
||||
if let Info::Point(_, _, str) = point {
|
||||
//~^ NOTE: Capturing point[] -> Immutable
|
||||
//~| NOTE: Capturing point[] -> Immutable
|
||||
//~| NOTE: Capturing point[(2, 0)] -> ByValue
|
||||
//~| NOTE: Min Capture point[] -> ByValue
|
||||
println!("{}", str);
|
||||
|
|
@ -29,6 +30,7 @@ fn multi_variant_enum() {
|
|||
|
||||
if let Info::Meta(_, v) = meta {
|
||||
//~^ NOTE: Capturing meta[] -> Immutable
|
||||
//~| NOTE: Capturing meta[] -> Immutable
|
||||
//~| NOTE: Capturing meta[(1, 1)] -> ByValue
|
||||
//~| NOTE: Min Capture meta[] -> ByValue
|
||||
println!("{:?}", v);
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ LL | let c = #[rustc_capture_analysis]
|
|||
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
|
||||
|
||||
error[E0658]: attributes on expressions are experimental
|
||||
--> $DIR/capture-enums.rs:48:13
|
||||
--> $DIR/capture-enums.rs:50:13
|
||||
|
|
||||
LL | let c = #[rustc_capture_analysis]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
@ -34,18 +34,28 @@ note: Capturing point[] -> Immutable
|
|||
|
|
||||
LL | if let Info::Point(_, _, str) = point {
|
||||
| ^^^^^
|
||||
note: Capturing point[] -> Immutable
|
||||
--> $DIR/capture-enums.rs:23:41
|
||||
|
|
||||
LL | if let Info::Point(_, _, str) = point {
|
||||
| ^^^^^
|
||||
note: Capturing point[(2, 0)] -> ByValue
|
||||
--> $DIR/capture-enums.rs:23:41
|
||||
|
|
||||
LL | if let Info::Point(_, _, str) = point {
|
||||
| ^^^^^
|
||||
note: Capturing meta[] -> Immutable
|
||||
--> $DIR/capture-enums.rs:30:35
|
||||
--> $DIR/capture-enums.rs:31:35
|
||||
|
|
||||
LL | if let Info::Meta(_, v) = meta {
|
||||
| ^^^^
|
||||
note: Capturing meta[] -> Immutable
|
||||
--> $DIR/capture-enums.rs:31:35
|
||||
|
|
||||
LL | if let Info::Meta(_, v) = meta {
|
||||
| ^^^^
|
||||
note: Capturing meta[(1, 1)] -> ByValue
|
||||
--> $DIR/capture-enums.rs:30:35
|
||||
--> $DIR/capture-enums.rs:31:35
|
||||
|
|
||||
LL | if let Info::Meta(_, v) = meta {
|
||||
| ^^^^
|
||||
|
|
@ -67,13 +77,13 @@ note: Min Capture point[] -> ByValue
|
|||
LL | if let Info::Point(_, _, str) = point {
|
||||
| ^^^^^
|
||||
note: Min Capture meta[] -> ByValue
|
||||
--> $DIR/capture-enums.rs:30:35
|
||||
--> $DIR/capture-enums.rs:31:35
|
||||
|
|
||||
LL | if let Info::Meta(_, v) = meta {
|
||||
| ^^^^
|
||||
|
||||
error: First Pass analysis includes:
|
||||
--> $DIR/capture-enums.rs:52:5
|
||||
--> $DIR/capture-enums.rs:54:5
|
||||
|
|
||||
LL | / || {
|
||||
LL | |
|
||||
|
|
@ -85,13 +95,13 @@ LL | | };
|
|||
| |_____^
|
||||
|
|
||||
note: Capturing point[(2, 0)] -> ByValue
|
||||
--> $DIR/capture-enums.rs:55:47
|
||||
--> $DIR/capture-enums.rs:57:47
|
||||
|
|
||||
LL | let SingleVariant::Point(_, _, str) = point;
|
||||
| ^^^^^
|
||||
|
||||
error: Min Capture analysis includes:
|
||||
--> $DIR/capture-enums.rs:52:5
|
||||
--> $DIR/capture-enums.rs:54:5
|
||||
|
|
||||
LL | / || {
|
||||
LL | |
|
||||
|
|
@ -103,7 +113,7 @@ LL | | };
|
|||
| |_____^
|
||||
|
|
||||
note: Min Capture point[(2, 0)] -> ByValue
|
||||
--> $DIR/capture-enums.rs:55:47
|
||||
--> $DIR/capture-enums.rs:57:47
|
||||
|
|
||||
LL | let SingleVariant::Point(_, _, str) = point;
|
||||
| ^^^^^
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ fn test_1_should_capture() {
|
|||
//~| ERROR Min Capture analysis includes:
|
||||
match variant {
|
||||
//~^ NOTE: Capturing variant[] -> Immutable
|
||||
//~| NOTE: Capturing variant[] -> Immutable
|
||||
//~| NOTE: Min Capture variant[] -> Immutable
|
||||
Some(_) => {}
|
||||
_ => {}
|
||||
|
|
@ -132,6 +133,7 @@ fn test_5_should_capture_multi_variant() {
|
|||
//~| ERROR Min Capture analysis includes:
|
||||
match variant {
|
||||
//~^ NOTE: Capturing variant[] -> Immutable
|
||||
//~| NOTE: Capturing variant[] -> Immutable
|
||||
//~| NOTE: Min Capture variant[] -> Immutable
|
||||
MVariant::A => {}
|
||||
_ => {}
|
||||
|
|
@ -150,6 +152,7 @@ fn test_7_should_capture_slice_len() {
|
|||
//~| ERROR Min Capture analysis includes:
|
||||
match slice {
|
||||
//~^ NOTE: Capturing slice[] -> Immutable
|
||||
//~| NOTE: Capturing slice[Deref] -> Immutable
|
||||
//~| NOTE: Min Capture slice[] -> Immutable
|
||||
[_,_,_] => {},
|
||||
_ => {}
|
||||
|
|
@ -162,6 +165,7 @@ fn test_7_should_capture_slice_len() {
|
|||
//~| ERROR Min Capture analysis includes:
|
||||
match slice {
|
||||
//~^ NOTE: Capturing slice[] -> Immutable
|
||||
//~| NOTE: Capturing slice[Deref] -> Immutable
|
||||
//~| NOTE: Min Capture slice[] -> Immutable
|
||||
[] => {},
|
||||
_ => {}
|
||||
|
|
@ -174,6 +178,7 @@ fn test_7_should_capture_slice_len() {
|
|||
//~| ERROR Min Capture analysis includes:
|
||||
match slice {
|
||||
//~^ NOTE: Capturing slice[] -> Immutable
|
||||
//~| NOTE: Capturing slice[Deref] -> Immutable
|
||||
//~| NOTE: Min Capture slice[] -> Immutable
|
||||
[_, .. ,_] => {},
|
||||
_ => {}
|
||||
|
|
|
|||
|
|
@ -14,6 +14,11 @@ note: Capturing variant[] -> Immutable
|
|||
|
|
||||
LL | match variant {
|
||||
| ^^^^^^^
|
||||
note: Capturing variant[] -> Immutable
|
||||
--> $DIR/patterns-capture-analysis.rs:15:15
|
||||
|
|
||||
LL | match variant {
|
||||
| ^^^^^^^
|
||||
|
||||
error: Min Capture analysis includes:
|
||||
--> $DIR/patterns-capture-analysis.rs:12:5
|
||||
|
|
@ -33,7 +38,7 @@ LL | match variant {
|
|||
| ^^^^^^^
|
||||
|
||||
error: First Pass analysis includes:
|
||||
--> $DIR/patterns-capture-analysis.rs:30:5
|
||||
--> $DIR/patterns-capture-analysis.rs:31:5
|
||||
|
|
||||
LL | / || {
|
||||
LL | |
|
||||
|
|
@ -44,7 +49,7 @@ LL | | };
|
|||
| |_____^
|
||||
|
||||
error: First Pass analysis includes:
|
||||
--> $DIR/patterns-capture-analysis.rs:49:5
|
||||
--> $DIR/patterns-capture-analysis.rs:50:5
|
||||
|
|
||||
LL | / || {
|
||||
LL | |
|
||||
|
|
@ -55,7 +60,7 @@ LL | | };
|
|||
| |_____^
|
||||
|
||||
error: First Pass analysis includes:
|
||||
--> $DIR/patterns-capture-analysis.rs:63:5
|
||||
--> $DIR/patterns-capture-analysis.rs:64:5
|
||||
|
|
||||
LL | / || {
|
||||
LL | |
|
||||
|
|
@ -66,18 +71,18 @@ LL | | };
|
|||
| |_____^
|
||||
|
|
||||
note: Capturing variant[] -> Immutable
|
||||
--> $DIR/patterns-capture-analysis.rs:66:15
|
||||
--> $DIR/patterns-capture-analysis.rs:67:15
|
||||
|
|
||||
LL | match variant {
|
||||
| ^^^^^^^
|
||||
note: Capturing variant[(0, 0)] -> Immutable
|
||||
--> $DIR/patterns-capture-analysis.rs:66:15
|
||||
--> $DIR/patterns-capture-analysis.rs:67:15
|
||||
|
|
||||
LL | match variant {
|
||||
| ^^^^^^^
|
||||
|
||||
error: Min Capture analysis includes:
|
||||
--> $DIR/patterns-capture-analysis.rs:63:5
|
||||
--> $DIR/patterns-capture-analysis.rs:64:5
|
||||
|
|
||||
LL | / || {
|
||||
LL | |
|
||||
|
|
@ -88,13 +93,13 @@ LL | | };
|
|||
| |_____^
|
||||
|
|
||||
note: Min Capture variant[] -> Immutable
|
||||
--> $DIR/patterns-capture-analysis.rs:66:15
|
||||
--> $DIR/patterns-capture-analysis.rs:67:15
|
||||
|
|
||||
LL | match variant {
|
||||
| ^^^^^^^
|
||||
|
||||
error: First Pass analysis includes:
|
||||
--> $DIR/patterns-capture-analysis.rs:83:5
|
||||
--> $DIR/patterns-capture-analysis.rs:84:5
|
||||
|
|
||||
LL | / || {
|
||||
LL | |
|
||||
|
|
@ -105,7 +110,7 @@ LL | | };
|
|||
| |_____^
|
||||
|
||||
error: First Pass analysis includes:
|
||||
--> $DIR/patterns-capture-analysis.rs:95:5
|
||||
--> $DIR/patterns-capture-analysis.rs:96:5
|
||||
|
|
||||
LL | / || {
|
||||
LL | |
|
||||
|
|
@ -116,7 +121,7 @@ LL | | };
|
|||
| |_____^
|
||||
|
||||
error: First Pass analysis includes:
|
||||
--> $DIR/patterns-capture-analysis.rs:108:5
|
||||
--> $DIR/patterns-capture-analysis.rs:109:5
|
||||
|
|
||||
LL | / || {
|
||||
LL | |
|
||||
|
|
@ -127,7 +132,7 @@ LL | | };
|
|||
| |_____^
|
||||
|
||||
error: First Pass analysis includes:
|
||||
--> $DIR/patterns-capture-analysis.rs:130:5
|
||||
--> $DIR/patterns-capture-analysis.rs:131:5
|
||||
|
|
||||
LL | / || {
|
||||
LL | |
|
||||
|
|
@ -138,13 +143,18 @@ LL | | };
|
|||
| |_____^
|
||||
|
|
||||
note: Capturing variant[] -> Immutable
|
||||
--> $DIR/patterns-capture-analysis.rs:133:15
|
||||
--> $DIR/patterns-capture-analysis.rs:134:15
|
||||
|
|
||||
LL | match variant {
|
||||
| ^^^^^^^
|
||||
note: Capturing variant[] -> Immutable
|
||||
--> $DIR/patterns-capture-analysis.rs:134:15
|
||||
|
|
||||
LL | match variant {
|
||||
| ^^^^^^^
|
||||
|
||||
error: Min Capture analysis includes:
|
||||
--> $DIR/patterns-capture-analysis.rs:130:5
|
||||
--> $DIR/patterns-capture-analysis.rs:131:5
|
||||
|
|
||||
LL | / || {
|
||||
LL | |
|
||||
|
|
@ -155,13 +165,13 @@ LL | | };
|
|||
| |_____^
|
||||
|
|
||||
note: Min Capture variant[] -> Immutable
|
||||
--> $DIR/patterns-capture-analysis.rs:133:15
|
||||
--> $DIR/patterns-capture-analysis.rs:134:15
|
||||
|
|
||||
LL | match variant {
|
||||
| ^^^^^^^
|
||||
|
||||
error: First Pass analysis includes:
|
||||
--> $DIR/patterns-capture-analysis.rs:148:5
|
||||
--> $DIR/patterns-capture-analysis.rs:150:5
|
||||
|
|
||||
LL | / || {
|
||||
LL | |
|
||||
|
|
@ -172,13 +182,18 @@ LL | | };
|
|||
| |_____^
|
||||
|
|
||||
note: Capturing slice[] -> Immutable
|
||||
--> $DIR/patterns-capture-analysis.rs:151:15
|
||||
--> $DIR/patterns-capture-analysis.rs:153:15
|
||||
|
|
||||
LL | match slice {
|
||||
| ^^^^^
|
||||
note: Capturing slice[Deref] -> Immutable
|
||||
--> $DIR/patterns-capture-analysis.rs:153:15
|
||||
|
|
||||
LL | match slice {
|
||||
| ^^^^^
|
||||
|
||||
error: Min Capture analysis includes:
|
||||
--> $DIR/patterns-capture-analysis.rs:148:5
|
||||
--> $DIR/patterns-capture-analysis.rs:150:5
|
||||
|
|
||||
LL | / || {
|
||||
LL | |
|
||||
|
|
@ -189,13 +204,13 @@ LL | | };
|
|||
| |_____^
|
||||
|
|
||||
note: Min Capture slice[] -> Immutable
|
||||
--> $DIR/patterns-capture-analysis.rs:151:15
|
||||
--> $DIR/patterns-capture-analysis.rs:153:15
|
||||
|
|
||||
LL | match slice {
|
||||
| ^^^^^
|
||||
|
||||
error: First Pass analysis includes:
|
||||
--> $DIR/patterns-capture-analysis.rs:160:5
|
||||
--> $DIR/patterns-capture-analysis.rs:163:5
|
||||
|
|
||||
LL | / || {
|
||||
LL | |
|
||||
|
|
@ -206,13 +221,18 @@ LL | | };
|
|||
| |_____^
|
||||
|
|
||||
note: Capturing slice[] -> Immutable
|
||||
--> $DIR/patterns-capture-analysis.rs:163:15
|
||||
--> $DIR/patterns-capture-analysis.rs:166:15
|
||||
|
|
||||
LL | match slice {
|
||||
| ^^^^^
|
||||
note: Capturing slice[Deref] -> Immutable
|
||||
--> $DIR/patterns-capture-analysis.rs:166:15
|
||||
|
|
||||
LL | match slice {
|
||||
| ^^^^^
|
||||
|
||||
error: Min Capture analysis includes:
|
||||
--> $DIR/patterns-capture-analysis.rs:160:5
|
||||
--> $DIR/patterns-capture-analysis.rs:163:5
|
||||
|
|
||||
LL | / || {
|
||||
LL | |
|
||||
|
|
@ -223,13 +243,13 @@ LL | | };
|
|||
| |_____^
|
||||
|
|
||||
note: Min Capture slice[] -> Immutable
|
||||
--> $DIR/patterns-capture-analysis.rs:163:15
|
||||
--> $DIR/patterns-capture-analysis.rs:166:15
|
||||
|
|
||||
LL | match slice {
|
||||
| ^^^^^
|
||||
|
||||
error: First Pass analysis includes:
|
||||
--> $DIR/patterns-capture-analysis.rs:172:5
|
||||
--> $DIR/patterns-capture-analysis.rs:176:5
|
||||
|
|
||||
LL | / || {
|
||||
LL | |
|
||||
|
|
@ -240,13 +260,18 @@ LL | | };
|
|||
| |_____^
|
||||
|
|
||||
note: Capturing slice[] -> Immutable
|
||||
--> $DIR/patterns-capture-analysis.rs:175:15
|
||||
--> $DIR/patterns-capture-analysis.rs:179:15
|
||||
|
|
||||
LL | match slice {
|
||||
| ^^^^^
|
||||
note: Capturing slice[Deref] -> Immutable
|
||||
--> $DIR/patterns-capture-analysis.rs:179:15
|
||||
|
|
||||
LL | match slice {
|
||||
| ^^^^^
|
||||
|
||||
error: Min Capture analysis includes:
|
||||
--> $DIR/patterns-capture-analysis.rs:172:5
|
||||
--> $DIR/patterns-capture-analysis.rs:176:5
|
||||
|
|
||||
LL | / || {
|
||||
LL | |
|
||||
|
|
@ -257,13 +282,13 @@ LL | | };
|
|||
| |_____^
|
||||
|
|
||||
note: Min Capture slice[] -> Immutable
|
||||
--> $DIR/patterns-capture-analysis.rs:175:15
|
||||
--> $DIR/patterns-capture-analysis.rs:179:15
|
||||
|
|
||||
LL | match slice {
|
||||
| ^^^^^
|
||||
|
||||
error: First Pass analysis includes:
|
||||
--> $DIR/patterns-capture-analysis.rs:189:5
|
||||
--> $DIR/patterns-capture-analysis.rs:194:5
|
||||
|
|
||||
LL | / || {
|
||||
LL | |
|
||||
|
|
|
|||
|
|
@ -0,0 +1,23 @@
|
|||
// This example used to compile, but the fact that it should was never properly
|
||||
// discussed. With further experience, we concluded that capture precision
|
||||
// depending on whether some types are inhabited goes too far, introducing a
|
||||
// bunch of headaches without much benefit.
|
||||
//@ edition:2021
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
|
||||
enum Void {}
|
||||
|
||||
pub fn main() {
|
||||
let mut r = Result::<Void, (u32, u32)>::Err((0, 0));
|
||||
let mut f = || {
|
||||
let Err((ref mut a, _)) = r;
|
||||
*a = 1;
|
||||
};
|
||||
let mut g = || {
|
||||
//~^ ERROR: cannot borrow `r` as mutable more than once at a time
|
||||
let Err((_, ref mut b)) = r;
|
||||
*b = 2;
|
||||
};
|
||||
f();
|
||||
g();
|
||||
assert_eq!(r, Err((1, 2)));
|
||||
}
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
error[E0499]: cannot borrow `r` as mutable more than once at a time
|
||||
--> $DIR/only-inhabited-variant-stable.rs:15:17
|
||||
|
|
||||
LL | let mut f = || {
|
||||
| -- first mutable borrow occurs here
|
||||
LL | let Err((ref mut a, _)) = r;
|
||||
| - first borrow occurs due to use of `r` in closure
|
||||
...
|
||||
LL | let mut g = || {
|
||||
| ^^ second mutable borrow occurs here
|
||||
LL |
|
||||
LL | let Err((_, ref mut b)) = r;
|
||||
| - second borrow occurs due to use of `r` in closure
|
||||
...
|
||||
LL | f();
|
||||
| - first borrow later used here
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0499`.
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
error[E0499]: cannot borrow `r` as mutable more than once at a time
|
||||
--> $DIR/only-inhabited-variant.rs:16:17
|
||||
|
|
||||
LL | let mut f = || {
|
||||
| -- first mutable borrow occurs here
|
||||
LL | let Err((ref mut a, _)) = r;
|
||||
| - first borrow occurs due to use of `r` in closure
|
||||
...
|
||||
LL | let mut g = || {
|
||||
| ^^ second mutable borrow occurs here
|
||||
LL |
|
||||
LL | let Err((_, ref mut b)) = r;
|
||||
| - second borrow occurs due to use of `r` in closure
|
||||
...
|
||||
LL | f();
|
||||
| - first borrow later used here
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0499`.
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
error[E0499]: cannot borrow `r` as mutable more than once at a time
|
||||
--> $DIR/only-inhabited-variant.rs:16:17
|
||||
|
|
||||
LL | let mut f = || {
|
||||
| -- first mutable borrow occurs here
|
||||
LL | let Err((ref mut a, _)) = r;
|
||||
| - first borrow occurs due to use of `r` in closure
|
||||
...
|
||||
LL | let mut g = || {
|
||||
| ^^ second mutable borrow occurs here
|
||||
LL |
|
||||
LL | let Err((_, ref mut b)) = r;
|
||||
| - second borrow occurs due to use of `r` in closure
|
||||
...
|
||||
LL | f();
|
||||
| - first borrow later used here
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0499`.
|
||||
|
|
@ -1,8 +1,9 @@
|
|||
// Test precise capture of a multi-variant enum (when remaining variants are
|
||||
// visibly uninhabited).
|
||||
// This example used to compile, but the fact that it should was never properly
|
||||
// discussed. With further experience, we concluded that capture precision
|
||||
// depending on whether some types are inhabited goes too far, introducing a
|
||||
// bunch of headaches without much benefit.
|
||||
//@ revisions: normal exhaustive_patterns
|
||||
//@ edition:2021
|
||||
//@ run-pass
|
||||
#![cfg_attr(exhaustive_patterns, feature(exhaustive_patterns))]
|
||||
#![feature(never_type)]
|
||||
|
||||
|
|
@ -13,6 +14,7 @@ pub fn main() {
|
|||
*a = 1;
|
||||
};
|
||||
let mut g = || {
|
||||
//~^ ERROR: cannot borrow `r` as mutable more than once at a time
|
||||
let Err((_, ref mut b)) = r;
|
||||
*b = 2;
|
||||
};
|
||||
170
tests/ui/closures/or-patterns-issue-137467.rs
Normal file
170
tests/ui/closures/or-patterns-issue-137467.rs
Normal file
|
|
@ -0,0 +1,170 @@
|
|||
//@ edition:2024
|
||||
//@ check-pass
|
||||
|
||||
const X: u32 = 0;
|
||||
|
||||
fn match_literal(x: (u32, u32, u32)) {
|
||||
let _ = || {
|
||||
let ((0, a, _) | (_, _, a)) = x;
|
||||
a
|
||||
};
|
||||
}
|
||||
|
||||
fn match_range(x: (u32, u32, u32)) {
|
||||
let _ = || {
|
||||
let ((0..5, a, _) | (_, _, a)) = x;
|
||||
a
|
||||
};
|
||||
}
|
||||
|
||||
fn match_const(x: (u32, u32, u32)) {
|
||||
let _ = || {
|
||||
let ((X, a, _) | (_, _, a)) = x;
|
||||
a
|
||||
};
|
||||
}
|
||||
|
||||
enum Choice { A, B }
|
||||
|
||||
fn match_unit_variant(x: (Choice, u32, u32)) {
|
||||
let _ = || {
|
||||
let ((Choice::A, a, _) | (Choice::B, _, a)) = x;
|
||||
a
|
||||
};
|
||||
}
|
||||
|
||||
struct Unit;
|
||||
|
||||
fn match_unit_struct(mut x: (Unit, u32)) {
|
||||
let r = &mut x.0;
|
||||
let _ = || {
|
||||
let (Unit, a) = x;
|
||||
a
|
||||
};
|
||||
|
||||
let _ = *r;
|
||||
}
|
||||
|
||||
enum Also { Unit }
|
||||
|
||||
fn match_unit_enum(mut x: (Also, u32)) {
|
||||
let r = &mut x.0;
|
||||
let _ = || {
|
||||
let (Also::Unit, a) = x;
|
||||
a
|
||||
};
|
||||
|
||||
let _ = *r;
|
||||
}
|
||||
|
||||
enum TEnum {
|
||||
A(u32),
|
||||
B(u32),
|
||||
}
|
||||
|
||||
enum SEnum {
|
||||
A { a: u32 },
|
||||
B { a: u32 },
|
||||
}
|
||||
|
||||
fn match_tuple_enum(x: TEnum) {
|
||||
let _ = || {
|
||||
let (TEnum::A(a) | TEnum::B(a)) = x;
|
||||
a
|
||||
};
|
||||
}
|
||||
|
||||
fn match_struct_enum(x: SEnum) {
|
||||
let _ = || {
|
||||
let (SEnum::A { a } | SEnum::B { a }) = x;
|
||||
a
|
||||
};
|
||||
}
|
||||
|
||||
enum TSingle {
|
||||
A(u32, u32),
|
||||
}
|
||||
|
||||
enum SSingle {
|
||||
A { a: u32, b: u32 },
|
||||
}
|
||||
|
||||
struct TStruct(u32, u32);
|
||||
struct SStruct { a: u32, b: u32 }
|
||||
|
||||
fn match_struct(mut x: SStruct) {
|
||||
let r = &mut x.a;
|
||||
let _ = || {
|
||||
let SStruct { b, .. } = x;
|
||||
b
|
||||
};
|
||||
|
||||
let _ = *r;
|
||||
}
|
||||
|
||||
fn match_tuple_struct(mut x: TStruct) {
|
||||
let r = &mut x.0;
|
||||
let _ = || {
|
||||
let TStruct(_, a) = x;
|
||||
a
|
||||
};
|
||||
|
||||
let _ = *r;
|
||||
}
|
||||
|
||||
fn match_singleton(mut x: SSingle) {
|
||||
let SSingle::A { a: ref mut r, .. } = x;
|
||||
let _ = || {
|
||||
let SSingle::A { b, .. } = x;
|
||||
b
|
||||
};
|
||||
|
||||
let _ = *r;
|
||||
}
|
||||
|
||||
fn match_tuple_singleton(mut x: TSingle) {
|
||||
let TSingle::A(ref mut r, _) = x;
|
||||
let _ = || {
|
||||
let TSingle::A(_, a) = x;
|
||||
a
|
||||
};
|
||||
|
||||
let _ = *r;
|
||||
}
|
||||
|
||||
fn match_slice(x: (&[u32], u32, u32)) {
|
||||
let _ = || {
|
||||
let (([], a, _) | ([_, ..], _, a)) = x;
|
||||
a
|
||||
};
|
||||
}
|
||||
|
||||
// Original testcase, for completeness
|
||||
enum Camera {
|
||||
Normal { base_transform: i32 },
|
||||
Volume { transform: i32 },
|
||||
}
|
||||
|
||||
fn draw_ui(camera: &mut Camera) {
|
||||
|| {
|
||||
let (Camera::Normal {
|
||||
base_transform: _transform,
|
||||
}
|
||||
| Camera::Volume {
|
||||
transform: _transform,
|
||||
}) = camera;
|
||||
};
|
||||
}
|
||||
|
||||
fn draw_ui2(camera: &mut Camera) {
|
||||
|| {
|
||||
let (Camera::Normal {
|
||||
base_transform: _,
|
||||
}
|
||||
| Camera::Volume {
|
||||
transform: _,
|
||||
}) = camera;
|
||||
};
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
Loading…
Add table
Add a link
Reference in a new issue