Skip to content

Commit 90f44f8

Browse files
committed
ExprUseVisitor: remove maybe_read_scrutinee
The split between walk_pat and maybe_read_scrutinee has now become redundant. Due to this change, one testcase within the testsuite has become similar enough to a known ICE to also break. I am leaving this as future work, as it requires feature(type_alias_impl_trait)
1 parent 8ed61e4 commit 90f44f8

12 files changed

+156
-262
lines changed

compiler/rustc_hir_typeck/src/expr_use_visitor.rs

+23-147
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,7 @@
77
88
use std::cell::{Ref, RefCell};
99
use std::ops::Deref;
10-
use std::slice::from_ref;
1110

12-
use hir::Expr;
1311
use hir::def::DefKind;
1412
use hir::pat_util::EnumerateAndAdjustIterator as _;
1513
use rustc_abi::{FIRST_VARIANT, FieldIdx, VariantIdx};
@@ -312,7 +310,8 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
312310

313311
let param_place = self.cat_rvalue(param.hir_id, param_ty);
314312

315-
self.walk_irrefutable_pat(&param_place, param.pat)?;
313+
self.fake_read_scrutinee(&param_place, false)?;
314+
self.walk_pat(&param_place, param.pat, false)?;
316315
}
317316

318317
self.consume_expr(body.value)?;
@@ -454,13 +453,9 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
454453

455454
hir::ExprKind::Match(discr, arms, _) => {
456455
let discr_place = self.cat_expr(discr)?;
457-
self.maybe_read_scrutinee(
458-
discr,
459-
discr_place.clone(),
460-
arms.iter().map(|arm| arm.pat),
461-
)?;
456+
self.fake_read_scrutinee(&discr_place, true)?;
457+
self.walk_expr(discr)?;
462458

463-
// treatment of the discriminant is handled while walking the arms.
464459
for arm in arms {
465460
self.walk_arm(&discr_place, arm)?;
466461
}
@@ -597,115 +592,25 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
597592
Ok(())
598593
}
599594

600-
fn maybe_read_scrutinee<'t>(
595+
#[instrument(skip(self), level = "debug")]
596+
fn fake_read_scrutinee(
601597
&self,
602-
discr: &Expr<'_>,
603-
discr_place: PlaceWithHirId<'tcx>,
604-
pats: impl Iterator<Item = &'t hir::Pat<'t>>,
598+
discr_place: &PlaceWithHirId<'tcx>,
599+
refutable: bool,
605600
) -> Result<(), Cx::Error> {
606-
// Matching should not always be considered a use of the place, hence
607-
// discr does not necessarily need to be borrowed.
608-
// We only want to borrow discr if the pattern contain something other
609-
// than wildcards.
610-
let mut needs_to_be_read = false;
611-
for pat in pats {
612-
self.cat_pattern(discr_place.clone(), pat, &mut |place, pat| {
613-
match &pat.kind {
614-
PatKind::Binding(.., opt_sub_pat) => {
615-
// If the opt_sub_pat is None, then the binding does not count as
616-
// a wildcard for the purpose of borrowing discr.
617-
if opt_sub_pat.is_none() {
618-
needs_to_be_read = true;
619-
}
620-
}
621-
PatKind::Never => {
622-
// A never pattern reads the value.
623-
// FIXME(never_patterns): does this do what I expect?
624-
needs_to_be_read = true;
625-
}
626-
PatKind::Expr(PatExpr { kind: PatExprKind::Path(qpath), hir_id, span }) => {
627-
// A `Path` pattern is just a name like `Foo`. This is either a
628-
// named constant or else it refers to an ADT variant
629-
630-
let res = self.cx.typeck_results().qpath_res(qpath, *hir_id);
631-
match res {
632-
Res::Def(DefKind::Const, _) | Res::Def(DefKind::AssocConst, _) => {
633-
// Named constants have to be equated with the value
634-
// being matched, so that's a read of the value being matched.
635-
//
636-
// FIXME: We don't actually reads for ZSTs.
637-
needs_to_be_read = true;
638-
}
639-
_ => {
640-
// Otherwise, this is a struct/enum variant, and so it's
641-
// only a read if we need to read the discriminant.
642-
needs_to_be_read |=
643-
self.is_multivariant_adt(place.place.ty(), *span);
644-
}
645-
}
646-
}
647-
PatKind::TupleStruct(..) | PatKind::Struct(..) | PatKind::Tuple(..) => {
648-
// For `Foo(..)`, `Foo { ... }` and `(...)` patterns, check if we are matching
649-
// against a multivariant enum or struct. In that case, we have to read
650-
// the discriminant. Otherwise this kind of pattern doesn't actually
651-
// read anything (we'll get invoked for the `...`, which may indeed
652-
// perform some reads).
653-
654-
let place_ty = place.place.ty();
655-
needs_to_be_read |= self.is_multivariant_adt(place_ty, pat.span);
656-
}
657-
PatKind::Expr(_) | PatKind::Range(..) => {
658-
// If the PatKind is a Lit or a Range then we want
659-
// to borrow discr.
660-
needs_to_be_read = true;
661-
}
662-
PatKind::Slice(lhs, wild, rhs) => {
663-
// We don't need to test the length if the pattern is `[..]`
664-
if matches!((lhs, wild, rhs), (&[], Some(_), &[]))
665-
// Arrays have a statically known size, so
666-
// there is no need to read their length
667-
|| place.place.ty().peel_refs().is_array()
668-
{
669-
} else {
670-
needs_to_be_read = true;
671-
}
672-
}
673-
PatKind::Or(_)
674-
| PatKind::Box(_)
675-
| PatKind::Deref(_)
676-
| PatKind::Ref(..)
677-
| PatKind::Guard(..)
678-
| PatKind::Wild
679-
| PatKind::Err(_) => {
680-
// If the PatKind is Or, Box, or Ref, the decision is made later
681-
// as these patterns contains subpatterns
682-
// If the PatKind is Wild or Err, the decision is made based on the other patterns
683-
// being examined
684-
}
685-
}
686-
687-
Ok(())
688-
})?
689-
}
601+
let closure_def_id = match discr_place.place.base {
602+
PlaceBase::Upvar(upvar_id) => Some(upvar_id.closure_expr_id),
603+
_ => None,
604+
};
690605

691-
if needs_to_be_read {
692-
self.borrow_expr(discr, BorrowKind::Immutable)?;
606+
let cause = if refutable {
607+
FakeReadCause::ForMatchedPlace(closure_def_id)
693608
} else {
694-
let closure_def_id = match discr_place.place.base {
695-
PlaceBase::Upvar(upvar_id) => Some(upvar_id.closure_expr_id),
696-
_ => None,
697-
};
609+
FakeReadCause::ForLet(closure_def_id)
610+
};
698611

699-
self.delegate.borrow_mut().fake_read(
700-
&discr_place,
701-
FakeReadCause::ForMatchedPlace(closure_def_id),
702-
discr_place.hir_id,
703-
);
612+
self.delegate.borrow_mut().fake_read(discr_place, cause, discr_place.hir_id);
704613

705-
// We always want to walk the discriminant. We want to make sure, for instance,
706-
// that the discriminant has been initialized.
707-
self.walk_expr(discr)?;
708-
}
709614
Ok(())
710615
}
711616

@@ -722,12 +627,11 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
722627
self.walk_expr(expr)?;
723628
let expr_place = self.cat_expr(expr)?;
724629
f()?;
630+
self.fake_read_scrutinee(&expr_place, els.is_some())?;
631+
self.walk_pat(&expr_place, pat, false)?;
725632
if let Some(els) = els {
726-
// borrowing because we need to test the discriminant
727-
self.maybe_read_scrutinee(expr, expr_place.clone(), from_ref(pat).iter())?;
728633
self.walk_block(els)?;
729634
}
730-
self.walk_irrefutable_pat(&expr_place, pat)?;
731635
Ok(())
732636
}
733637

@@ -899,16 +803,6 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
899803
discr_place: &PlaceWithHirId<'tcx>,
900804
arm: &hir::Arm<'_>,
901805
) -> Result<(), Cx::Error> {
902-
let closure_def_id = match discr_place.place.base {
903-
PlaceBase::Upvar(upvar_id) => Some(upvar_id.closure_expr_id),
904-
_ => None,
905-
};
906-
907-
self.delegate.borrow_mut().fake_read(
908-
discr_place,
909-
FakeReadCause::ForMatchedPlace(closure_def_id),
910-
discr_place.hir_id,
911-
);
912806
self.walk_pat(discr_place, arm.pat, arm.guard.is_some())?;
913807

914808
if let Some(ref e) = arm.guard {
@@ -919,27 +813,6 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
919813
Ok(())
920814
}
921815

922-
/// Walks a pat that occurs in isolation (i.e., top-level of fn argument or
923-
/// let binding, and *not* a match arm or nested pat.)
924-
fn walk_irrefutable_pat(
925-
&self,
926-
discr_place: &PlaceWithHirId<'tcx>,
927-
pat: &hir::Pat<'_>,
928-
) -> Result<(), Cx::Error> {
929-
let closure_def_id = match discr_place.place.base {
930-
PlaceBase::Upvar(upvar_id) => Some(upvar_id.closure_expr_id),
931-
_ => None,
932-
};
933-
934-
self.delegate.borrow_mut().fake_read(
935-
discr_place,
936-
FakeReadCause::ForLet(closure_def_id),
937-
discr_place.hir_id,
938-
);
939-
self.walk_pat(discr_place, pat, false)?;
940-
Ok(())
941-
}
942-
943816
/// The core driver for walking a pattern
944817
///
945818
/// This should mirror how pattern-matching gets lowered to MIR, as
@@ -1928,8 +1801,11 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
19281801
/// Here, we cannot perform such an accurate checks, because querying
19291802
/// whether a type is inhabited requires that it has been fully inferred,
19301803
/// which cannot be guaranteed at this point.
1804+
#[instrument(skip(self, span), level = "debug")]
19311805
fn is_multivariant_adt(&self, ty: Ty<'tcx>, span: Span) -> bool {
1932-
if let ty::Adt(def, _) = self.cx.try_structurally_resolve_type(span, ty).kind() {
1806+
let ty = self.cx.try_structurally_resolve_type(span, ty);
1807+
debug!(?ty, "is_multivariant_adt: resolved");
1808+
if let ty::Adt(def, _) = ty.kind() {
19331809
// Note that if a non-exhaustive SingleVariant is defined in another crate, we need
19341810
// to assume that more cases will be added to the variant in the future. This mean
19351811
// that we should handle non-exhaustive SingleVariant the same way we would handle

compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs

+1
Original file line numberDiff line numberDiff line change
@@ -1447,6 +1447,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
14471447
pub(crate) fn try_structurally_resolve_type(&self, sp: Span, ty: Ty<'tcx>) -> Ty<'tcx> {
14481448
let ty = self.resolve_vars_with_obligations(ty);
14491449

1450+
debug!("next_solver = {:?}", self.next_trait_solver());
14501451
if self.next_trait_solver()
14511452
&& let ty::Alias(..) = ty.kind()
14521453
{
File renamed without changes.

tests/crashes/119786-2.rs

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
//@ known-bug: #119786
2+
//@ edition:2021
3+
4+
fn enum_upvar() {
5+
type T = impl Copy;
6+
let foo: T = Some((1u32, 2u32));
7+
let x = move || {
8+
match foo {
9+
None => (),
10+
Some(_) => (),
11+
}
12+
};
13+
}
14+
15+
pub fn main() {}

tests/crashes/119786-3.rs

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
//@ known-bug: #119786
2+
//@ edition:2021
3+
4+
fn enum_upvar() {
5+
type T = impl Copy;
6+
let foo: T = Some((1u32, 2u32));
7+
let x = move || {
8+
match foo {
9+
None => (),
10+
Some((a, b)) => (),
11+
}
12+
};
13+
}
14+
15+
pub fn main() {}

tests/mir-opt/async_closure_fake_read_for_by_move.foo-{closure#0}-{closure#0}.built.after.mir

+12-17
Original file line numberDiff line numberDiff line change
@@ -4,18 +4,16 @@ fn foo::{closure#0}::{closure#0}(_1: {async closure body@$DIR/async_closure_fake
44
yields ()
55
{
66
debug _task_context => _2;
7-
debug f => (*(_1.0: &&Foo));
7+
debug f => (*(_1.0: &Foo));
88
let mut _0: ();
99
let mut _3: &Foo;
1010
let mut _4: &&Foo;
11-
let mut _5: &&&Foo;
12-
let mut _6: isize;
13-
let mut _7: bool;
11+
let mut _5: isize;
12+
let mut _6: bool;
1413

1514
bb0: {
16-
PlaceMention((*(_1.0: &&Foo)));
17-
_6 = discriminant((*(*(_1.0: &&Foo))));
18-
switchInt(move _6) -> [0: bb2, otherwise: bb1];
15+
_5 = discriminant((*(_1.0: &Foo)));
16+
switchInt(move _5) -> [0: bb2, otherwise: bb1];
1917
}
2018

2119
bb1: {
@@ -32,28 +30,25 @@ yields ()
3230
}
3331

3432
bb4: {
35-
FakeRead(ForMatchedPlace(None), (*(_1.0: &&Foo)));
3633
unreachable;
3734
}
3835

3936
bb5: {
40-
_3 = &fake shallow (*(*(_1.0: &&Foo)));
41-
_4 = &fake shallow (*(_1.0: &&Foo));
42-
_5 = &fake shallow (_1.0: &&Foo);
43-
StorageLive(_7);
44-
_7 = const true;
45-
switchInt(move _7) -> [0: bb8, otherwise: bb7];
37+
_3 = &fake shallow (*(_1.0: &Foo));
38+
_4 = &fake shallow (_1.0: &Foo);
39+
StorageLive(_6);
40+
_6 = const true;
41+
switchInt(move _6) -> [0: bb8, otherwise: bb7];
4642
}
4743

4844
bb6: {
4945
falseEdge -> [real: bb3, imaginary: bb1];
5046
}
5147

5248
bb7: {
53-
StorageDead(_7);
49+
StorageDead(_6);
5450
FakeRead(ForMatchGuard, _3);
5551
FakeRead(ForMatchGuard, _4);
56-
FakeRead(ForMatchGuard, _5);
5752
_0 = const ();
5853
goto -> bb10;
5954
}
@@ -63,7 +58,7 @@ yields ()
6358
}
6459

6560
bb9: {
66-
StorageDead(_7);
61+
StorageDead(_6);
6762
goto -> bb6;
6863
}
6964

tests/mir-opt/async_closure_fake_read_for_by_move.foo-{closure#0}-{closure#1}.built.after.mir

+10-14
Original file line numberDiff line numberDiff line change
@@ -4,18 +4,16 @@ fn foo::{closure#0}::{closure#1}(_1: {async closure body@$DIR/async_closure_fake
44
yields ()
55
{
66
debug _task_context => _2;
7-
debug f => (_1.0: &Foo);
7+
debug f => (*(_1.0: &Foo));
88
let mut _0: ();
99
let mut _3: &Foo;
1010
let mut _4: &&Foo;
11-
let mut _5: &&&Foo;
12-
let mut _6: isize;
13-
let mut _7: bool;
11+
let mut _5: isize;
12+
let mut _6: bool;
1413

1514
bb0: {
16-
PlaceMention((_1.0: &Foo));
17-
_6 = discriminant((*(_1.0: &Foo)));
18-
switchInt(move _6) -> [0: bb2, otherwise: bb1];
15+
_5 = discriminant((*(_1.0: &Foo)));
16+
switchInt(move _5) -> [0: bb2, otherwise: bb1];
1917
}
2018

2119
bb1: {
@@ -29,24 +27,22 @@ yields ()
2927

3028
bb3: {
3129
_3 = &fake shallow (*(_1.0: &Foo));
32-
_4 = &fake shallow (_1.0: &Foo);
3330
nop;
34-
StorageLive(_7);
35-
_7 = const true;
36-
switchInt(move _7) -> [0: bb5, otherwise: bb4];
31+
StorageLive(_6);
32+
_6 = const true;
33+
switchInt(move _6) -> [0: bb5, otherwise: bb4];
3734
}
3835

3936
bb4: {
40-
StorageDead(_7);
37+
StorageDead(_6);
4138
FakeRead(ForMatchGuard, _3);
4239
FakeRead(ForMatchGuard, _4);
43-
FakeRead(ForMatchGuard, _5);
4440
_0 = const ();
4541
goto -> bb6;
4642
}
4743

4844
bb5: {
49-
StorageDead(_7);
45+
StorageDead(_6);
5046
falseEdge -> [real: bb1, imaginary: bb1];
5147
}
5248

0 commit comments

Comments
 (0)