22//! normal visitor, which just walks the entire body in one shot, the
33//! `ExprUseVisitor` determines how expressions are being used.
44
5- pub use self :: ConsumeMode :: * ;
6-
75// Export these here so that Clippy can use them.
86pub use rustc_middle:: hir:: place:: { Place , PlaceBase , PlaceWithHirId , Projection } ;
97
@@ -28,19 +26,20 @@ use crate::mem_categorization as mc;
2826/// This trait defines the callbacks you can expect to receive when
2927/// employing the ExprUseVisitor.
3028pub trait Delegate < ' tcx > {
31- // The value found at `place` is either copied or moved, depending
29+ // The value found at `place` is moved, depending
3230 // on `mode`. Where `diag_expr_id` is the id used for diagnostics for `place`.
3331 //
32+ // Use of a `Copy` type in a ByValue context is considered a use
33+ // by `ImmBorrow` and `borrow` is called instead. This is because
34+ // a shared borrow is the "minimum access" that would be needed
35+ // to perform a copy.
36+ //
37+ //
3438 // The parameter `diag_expr_id` indicates the HIR id that ought to be used for
3539 // diagnostics. Around pattern matching such as `let pat = expr`, the diagnostic
3640 // id will be the id of the expression `expr` but the place itself will have
3741 // the id of the binding in the pattern `pat`.
38- fn consume (
39- & mut self ,
40- place_with_id : & PlaceWithHirId < ' tcx > ,
41- diag_expr_id : hir:: HirId ,
42- mode : ConsumeMode ,
43- ) ;
42+ fn consume ( & mut self , place_with_id : & PlaceWithHirId < ' tcx > , diag_expr_id : hir:: HirId ) ;
4443
4544 // The value found at `place` is being borrowed with kind `bk`.
4645 // `diag_expr_id` is the id used for diagnostics (see `consume` for more details).
@@ -60,7 +59,7 @@ pub trait Delegate<'tcx> {
6059}
6160
6261#[ derive( Copy , Clone , PartialEq , Debug ) ]
63- pub enum ConsumeMode {
62+ enum ConsumeMode {
6463 Copy , // reference to x where x has a type that copies
6564 Move , // reference to x where x has a type that moves
6665}
@@ -141,10 +140,7 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
141140 }
142141
143142 fn delegate_consume ( & mut self , place_with_id : & PlaceWithHirId < ' tcx > , diag_expr_id : hir:: HirId ) {
144- debug ! ( "delegate_consume(place_with_id={:?})" , place_with_id) ;
145-
146- let mode = copy_or_move ( & self . mc , place_with_id) ;
147- self . delegate . consume ( place_with_id, diag_expr_id, mode) ;
143+ delegate_consume ( & self . mc , self . delegate , place_with_id, diag_expr_id)
148144 }
149145
150146 fn consume_exprs ( & mut self , exprs : & [ hir:: Expr < ' _ > ] ) {
@@ -256,12 +252,16 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
256252 | PatKind :: Path ( ..)
257253 | PatKind :: Struct ( ..)
258254 | PatKind :: Tuple ( ..) => {
259- // If the PatKind is a TupleStruct, Struct or Tuple then we want to check
255+ // If the PatKind is a TupleStruct, Path, Struct or Tuple then we want to check
260256 // whether the Variant is a MultiVariant or a SingleVariant. We only want
261257 // to borrow discr if it is a MultiVariant.
262258 // If it is a SingleVariant and creates a binding we will handle that when
263259 // this callback gets called again.
264- if let ty:: Adt ( def, _) = place. place. base_ty. kind( ) {
260+
261+ // Get the type of the Place after all projections have been applied
262+ let place_ty = place. place. ty( ) ;
263+
264+ if let ty:: Adt ( def, _) = place_ty. kind( ) {
265265 if def. variants. len( ) > 1 {
266266 needs_to_be_read = true ;
267267 }
@@ -653,9 +653,8 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
653653 delegate. borrow( place, discr_place. hir_id, bk) ;
654654 }
655655 ty:: BindByValue ( ..) => {
656- let mode = copy_or_move( mc, & place) ;
657656 debug!( "walk_pat binding consuming pat" ) ;
658- delegate . consume ( place, discr_place. hir_id, mode ) ;
657+ delegate_consume ( mc , * delegate , place, discr_place. hir_id) ;
659658 }
660659 }
661660 }
@@ -773,8 +772,7 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
773772
774773 match capture_info. capture_kind {
775774 ty:: UpvarCapture :: ByValue ( _) => {
776- let mode = copy_or_move ( & self . mc , & place_with_id) ;
777- self . delegate . consume ( & place_with_id, place_with_id. hir_id , mode) ;
775+ self . delegate_consume ( & place_with_id, place_with_id. hir_id ) ;
778776 }
779777 ty:: UpvarCapture :: ByRef ( upvar_borrow) => {
780778 self . delegate . borrow (
@@ -798,8 +796,28 @@ fn copy_or_move<'a, 'tcx>(
798796 place_with_id. place . ty ( ) ,
799797 mc. tcx ( ) . hir ( ) . span ( place_with_id. hir_id ) ,
800798 ) {
801- Move
799+ ConsumeMode :: Move
802800 } else {
803- Copy
801+ ConsumeMode :: Copy
802+ }
803+ }
804+
805+ // - If a place is used in a `ByValue` context then move it if it's not a `Copy` type.
806+ // - If the place that is a `Copy` type consider it a `ImmBorrow`.
807+ fn delegate_consume < ' a , ' tcx > (
808+ mc : & mc:: MemCategorizationContext < ' a , ' tcx > ,
809+ delegate : & mut ( dyn Delegate < ' tcx > + ' a ) ,
810+ place_with_id : & PlaceWithHirId < ' tcx > ,
811+ diag_expr_id : hir:: HirId ,
812+ ) {
813+ debug ! ( "delegate_consume(place_with_id={:?})" , place_with_id) ;
814+
815+ let mode = copy_or_move ( & mc, place_with_id) ;
816+
817+ match mode {
818+ ConsumeMode :: Move => delegate. consume ( place_with_id, diag_expr_id) ,
819+ ConsumeMode :: Copy => {
820+ delegate. borrow ( place_with_id, diag_expr_id, ty:: BorrowKind :: ImmBorrow )
821+ }
804822 }
805823}
0 commit comments