Skip to content

Commit 8e4a971

Browse files
extract method to read scrutinee conditionally
1 parent 1cd30e7 commit 8e4a971

File tree

2 files changed

+105
-103
lines changed

2 files changed

+105
-103
lines changed

compiler/rustc_ast_lowering/src/block.rs

+2-16
Original file line numberDiff line numberDiff line change
@@ -36,20 +36,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
3636
match s.kind {
3737
StmtKind::Local(ref local) => {
3838
let hir_id = self.lower_node_id(s.id);
39-
let els = if let LocalKind::InitElse(_, els) = &local.kind {
40-
if !self.tcx.features().let_else {
41-
feature_err(
42-
&self.tcx.sess.parse_sess,
43-
sym::let_else,
44-
s.span,
45-
"`let...else` statements are unstable",
46-
)
47-
.emit();
48-
}
49-
Some(self.lower_block(els, false))
50-
} else {
51-
None
52-
};
5339
let local = self.lower_local(local);
5440
self.alias_attrs(hir_id, local.hir_id);
5541
let kind = hir::StmtKind::Local(local);
@@ -106,9 +92,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
10692
let hir_id = self.lower_node_id(l.id);
10793
let pat = self.lower_pat(&l.pat);
10894
let els = if let LocalKind::InitElse(_, els) = &l.kind {
109-
if !self.sess.features_untracked().let_else {
95+
if !self.tcx.features().let_else {
11096
feature_err(
111-
&self.sess.parse_sess,
97+
&self.tcx.sess.parse_sess,
11298
sym::let_else,
11399
l.span,
114100
"`let...else` statements are unstable",

compiler/rustc_typeck/src/expr_use_visitor.rs

+103-87
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,10 @@
22
//! normal visitor, which just walks the entire body in one shot, the
33
//! `ExprUseVisitor` determines how expressions are being used.
44
5+
use std::slice::from_ref;
6+
57
use hir::def::DefKind;
8+
use hir::Expr;
69
// Export these here so that Clippy can use them.
710
pub use rustc_middle::hir::place::{Place, PlaceBase, PlaceWithHirId, Projection};
811

@@ -257,91 +260,11 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
257260

258261
hir::ExprKind::Match(ref discr, arms, _) => {
259262
let discr_place = return_if_err!(self.mc.cat_expr(discr));
260-
261-
// Matching should not always be considered a use of the place, hence
262-
// discr does not necessarily need to be borrowed.
263-
// We only want to borrow discr if the pattern contain something other
264-
// than wildcards.
265-
let ExprUseVisitor { ref mc, body_owner: _, delegate: _ } = *self;
266-
let mut needs_to_be_read = false;
267-
for arm in arms.iter() {
268-
return_if_err!(mc.cat_pattern(discr_place.clone(), arm.pat, |place, pat| {
269-
match &pat.kind {
270-
PatKind::Binding(.., opt_sub_pat) => {
271-
// If the opt_sub_pat is None, than the binding does not count as
272-
// a wildcard for the purpose of borrowing discr.
273-
if opt_sub_pat.is_none() {
274-
needs_to_be_read = true;
275-
}
276-
}
277-
PatKind::Path(qpath) => {
278-
// A `Path` pattern is just a name like `Foo`. This is either a
279-
// named constant or else it refers to an ADT variant
280-
281-
let res = self.mc.typeck_results.qpath_res(qpath, pat.hir_id);
282-
match res {
283-
Res::Def(DefKind::Const, _)
284-
| Res::Def(DefKind::AssocConst, _) => {
285-
// Named constants have to be equated with the value
286-
// being matched, so that's a read of the value being matched.
287-
//
288-
// FIXME: We don't actually reads for ZSTs.
289-
needs_to_be_read = true;
290-
}
291-
_ => {
292-
// Otherwise, this is a struct/enum variant, and so it's
293-
// only a read if we need to read the discriminant.
294-
needs_to_be_read |= is_multivariant_adt(place.place.ty());
295-
}
296-
}
297-
}
298-
PatKind::TupleStruct(..) | PatKind::Struct(..) | PatKind::Tuple(..) => {
299-
// For `Foo(..)`, `Foo { ... }` and `(...)` patterns, check if we are matching
300-
// against a multivariant enum or struct. In that case, we have to read
301-
// the discriminant. Otherwise this kind of pattern doesn't actually
302-
// read anything (we'll get invoked for the `...`, which may indeed
303-
// perform some reads).
304-
305-
let place_ty = place.place.ty();
306-
needs_to_be_read |= is_multivariant_adt(place_ty);
307-
}
308-
PatKind::Lit(_) | PatKind::Range(..) => {
309-
// If the PatKind is a Lit or a Range then we want
310-
// to borrow discr.
311-
needs_to_be_read = true;
312-
}
313-
PatKind::Or(_)
314-
| PatKind::Box(_)
315-
| PatKind::Slice(..)
316-
| PatKind::Ref(..)
317-
| PatKind::Wild => {
318-
// If the PatKind is Or, Box, Slice or Ref, the decision is made later
319-
// as these patterns contains subpatterns
320-
// If the PatKind is Wild, the decision is made based on the other patterns being
321-
// examined
322-
}
323-
}
324-
}));
325-
}
326-
327-
if needs_to_be_read {
328-
self.borrow_expr(discr, ty::ImmBorrow);
329-
} else {
330-
let closure_def_id = match discr_place.place.base {
331-
PlaceBase::Upvar(upvar_id) => Some(upvar_id.closure_expr_id.to_def_id()),
332-
_ => None,
333-
};
334-
335-
self.delegate.fake_read(
336-
&discr_place,
337-
FakeReadCause::ForMatchedPlace(closure_def_id),
338-
discr_place.hir_id,
339-
);
340-
341-
// We always want to walk the discriminant. We want to make sure, for instance,
342-
// that the discriminant has been initialized.
343-
self.walk_expr(discr);
344-
}
263+
self.maybe_read_scrutinee(
264+
discr,
265+
discr_place.clone(),
266+
arms.iter().map(|arm| arm.pat),
267+
);
345268

346269
// treatment of the discriminant is handled while walking the arms.
347270
for arm in arms {
@@ -470,6 +393,97 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
470393
}
471394
}
472395

396+
fn maybe_read_scrutinee<'t>(
397+
&mut self,
398+
discr: &Expr<'_>,
399+
discr_place: PlaceWithHirId<'tcx>,
400+
pats: impl Iterator<Item = &'t hir::Pat<'t>>,
401+
) {
402+
// Matching should not always be considered a use of the place, hence
403+
// discr does not necessarily need to be borrowed.
404+
// We only want to borrow discr if the pattern contain something other
405+
// than wildcards.
406+
let ExprUseVisitor { ref mc, body_owner: _, delegate: _ } = *self;
407+
let mut needs_to_be_read = false;
408+
for pat in pats {
409+
return_if_err!(mc.cat_pattern(discr_place.clone(), pat, |place, pat| {
410+
match &pat.kind {
411+
PatKind::Binding(.., opt_sub_pat) => {
412+
// If the opt_sub_pat is None, than the binding does not count as
413+
// a wildcard for the purpose of borrowing discr.
414+
if opt_sub_pat.is_none() {
415+
needs_to_be_read = true;
416+
}
417+
}
418+
PatKind::Path(qpath) => {
419+
// A `Path` pattern is just a name like `Foo`. This is either a
420+
// named constant or else it refers to an ADT variant
421+
422+
let res = self.mc.typeck_results.qpath_res(qpath, pat.hir_id);
423+
match res {
424+
Res::Def(DefKind::Const, _) | Res::Def(DefKind::AssocConst, _) => {
425+
// Named constants have to be equated with the value
426+
// being matched, so that's a read of the value being matched.
427+
//
428+
// FIXME: We don't actually reads for ZSTs.
429+
needs_to_be_read = true;
430+
}
431+
_ => {
432+
// Otherwise, this is a struct/enum variant, and so it's
433+
// only a read if we need to read the discriminant.
434+
needs_to_be_read |= is_multivariant_adt(place.place.ty());
435+
}
436+
}
437+
}
438+
PatKind::TupleStruct(..) | PatKind::Struct(..) | PatKind::Tuple(..) => {
439+
// For `Foo(..)`, `Foo { ... }` and `(...)` patterns, check if we are matching
440+
// against a multivariant enum or struct. In that case, we have to read
441+
// the discriminant. Otherwise this kind of pattern doesn't actually
442+
// read anything (we'll get invoked for the `...`, which may indeed
443+
// perform some reads).
444+
445+
let place_ty = place.place.ty();
446+
needs_to_be_read |= is_multivariant_adt(place_ty);
447+
}
448+
PatKind::Lit(_) | PatKind::Range(..) => {
449+
// If the PatKind is a Lit or a Range then we want
450+
// to borrow discr.
451+
needs_to_be_read = true;
452+
}
453+
PatKind::Or(_)
454+
| PatKind::Box(_)
455+
| PatKind::Slice(..)
456+
| PatKind::Ref(..)
457+
| PatKind::Wild => {
458+
// If the PatKind is Or, Box, Slice or Ref, the decision is made later
459+
// as these patterns contains subpatterns
460+
// If the PatKind is Wild, the decision is made based on the other patterns being
461+
// examined
462+
}
463+
}
464+
}));
465+
}
466+
467+
if needs_to_be_read {
468+
self.borrow_expr(discr, ty::ImmBorrow);
469+
} else {
470+
let closure_def_id = match discr_place.place.base {
471+
PlaceBase::Upvar(upvar_id) => Some(upvar_id.closure_expr_id.to_def_id()),
472+
_ => None,
473+
};
474+
475+
self.delegate.fake_read(
476+
&discr_place,
477+
FakeReadCause::ForMatchedPlace(closure_def_id),
478+
discr_place.hir_id,
479+
);
480+
481+
// We always want to walk the discriminant. We want to make sure, for instance,
482+
// that the discriminant has been initialized.
483+
self.walk_expr(discr);
484+
}
485+
}
486+
473487
fn walk_local<F>(
474488
&mut self,
475489
expr: &hir::Expr<'_>,
@@ -484,10 +498,12 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
484498
f(self);
485499
if let Some(els) = els {
486500
// borrowing because we need to test the descriminant
487-
self.borrow_expr(expr, ImmBorrow);
501+
// self.borrow_expr(expr, ImmBorrow);
502+
self.maybe_read_scrutinee(expr, expr_place, from_ref(pat).iter());
488503
self.walk_block(els)
504+
} else {
505+
self.walk_irrefutable_pat(&expr_place, &pat);
489506
}
490-
self.walk_irrefutable_pat(&expr_place, &pat);
491507
}
492508

493509
/// Indicates that the value of `blk` will be consumed, meaning either copied or moved

0 commit comments

Comments
 (0)