@@ -59,12 +59,12 @@ use rustc_data_structures::fx::FxHashMap;
5959use rustc_hir as hir;
6060use rustc_hir:: def:: { CtorKind , CtorOf , DefKind , Res } ;
6161use rustc_hir:: def_id:: { DefId , LOCAL_CRATE } ;
62- use rustc_hir:: intravisit:: { self , NestedVisitorMap , Visitor } ;
62+ use rustc_hir:: intravisit:: { self , walk_expr , ErasedMap , NestedVisitorMap , Visitor } ;
6363use rustc_hir:: {
64- def, Arm , BindingAnnotation , Block , Body , Constness , CrateItem , Expr , ExprKind , FnDecl , ForeignItem , GenericArgs ,
65- GenericParam , HirId , Impl , ImplItem , ImplItemKind , Item , ItemKind , LangItem , Lifetime , Local , MacroDef ,
66- MatchSource , Node , Param , Pat , PatKind , Path , PathSegment , QPath , Stmt , StructField , TraitItem , TraitItemKind ,
67- TraitRef , TyKind , Variant , Visibility ,
64+ def, Arm , BindingAnnotation , Block , Body , Constness , CrateItem , Destination , Expr , ExprKind , FnDecl , ForeignItem ,
65+ GenericArgs , GenericParam , HirId , Impl , ImplItem , ImplItemKind , Item , ItemKind , LangItem , Lifetime , Local ,
66+ MacroDef , MatchSource , Node , Param , Pat , PatKind , Path , PathSegment , QPath , Stmt , StmtKind , StructField , TraitItem ,
67+ TraitItemKind , TraitRef , TyKind , Variant , Visibility ,
6868} ;
6969use rustc_lint:: { LateContext , Level , Lint , LintContext } ;
7070use rustc_middle:: hir:: exports:: Export ;
@@ -81,7 +81,7 @@ use rustc_span::{Span, DUMMY_SP};
8181use rustc_target:: abi:: Integer ;
8282
8383use crate :: consts:: { constant, Constant } ;
84- use crate :: ty:: is_recursively_primitive_type;
84+ use crate :: ty:: { can_partially_move_ty , is_recursively_primitive_type} ;
8585
8686pub fn parse_msrv ( msrv : & str , sess : Option < & Session > , span : Option < Span > ) -> Option < RustcVersion > {
8787 if let Ok ( version) = RustcVersion :: parse ( msrv) {
@@ -515,6 +515,73 @@ pub fn trait_ref_of_method<'tcx>(cx: &LateContext<'tcx>, hir_id: HirId) -> Optio
515515 None
516516}
517517
518+ /// Checks if the top level expression can be moved into a closure as is.
519+ pub fn can_move_expr_to_closure_no_visit ( cx : & LateContext < ' tcx > , expr : & ' tcx Expr < ' _ > , jump_targets : & [ HirId ] ) -> bool {
520+ match expr. kind {
521+ ExprKind :: Break ( Destination { target_id : Ok ( id) , .. } , _)
522+ | ExprKind :: Continue ( Destination { target_id : Ok ( id) , .. } )
523+ if jump_targets. contains ( & id) =>
524+ {
525+ true
526+ } ,
527+ ExprKind :: Break ( ..)
528+ | ExprKind :: Continue ( _)
529+ | ExprKind :: Ret ( _)
530+ | ExprKind :: Yield ( ..)
531+ | ExprKind :: InlineAsm ( _)
532+ | ExprKind :: LlvmInlineAsm ( _) => false ,
533+ // Accessing a field of a local value can only be done if the type isn't
534+ // partially moved.
535+ ExprKind :: Field ( base_expr, _)
536+ if matches ! (
537+ base_expr. kind,
538+ ExprKind :: Path ( QPath :: Resolved ( _, Path { res: Res :: Local ( _) , .. } ) )
539+ ) && can_partially_move_ty ( cx, cx. typeck_results ( ) . expr_ty ( base_expr) ) =>
540+ {
541+ // TODO: check if the local has been partially moved. Assume it has for now.
542+ false
543+ }
544+ _ => true ,
545+ }
546+ }
547+
548+ /// Checks if the expression can be moved into a closure as is.
549+ pub fn can_move_expr_to_closure ( cx : & LateContext < ' tcx > , expr : & ' tcx Expr < ' _ > ) -> bool {
550+ struct V < ' cx , ' tcx > {
551+ cx : & ' cx LateContext < ' tcx > ,
552+ loops : Vec < HirId > ,
553+ allow_closure : bool ,
554+ }
555+ impl Visitor < ' tcx > for V < ' _ , ' tcx > {
556+ type Map = ErasedMap < ' tcx > ;
557+ fn nested_visit_map ( & mut self ) -> NestedVisitorMap < Self :: Map > {
558+ NestedVisitorMap :: None
559+ }
560+
561+ fn visit_expr ( & mut self , e : & ' tcx Expr < ' _ > ) {
562+ if !self . allow_closure {
563+ return ;
564+ }
565+ if let ExprKind :: Loop ( b, ..) = e. kind {
566+ self . loops . push ( e. hir_id ) ;
567+ self . visit_block ( b) ;
568+ self . loops . pop ( ) ;
569+ } else {
570+ self . allow_closure &= can_move_expr_to_closure_no_visit ( self . cx , e, & self . loops ) ;
571+ walk_expr ( self , e) ;
572+ }
573+ }
574+ }
575+
576+ let mut v = V {
577+ cx,
578+ allow_closure : true ,
579+ loops : Vec :: new ( ) ,
580+ } ;
581+ v. visit_expr ( expr) ;
582+ v. allow_closure
583+ }
584+
518585/// Returns the method names and argument list of nested method call expressions that make up
519586/// `expr`. method/span lists are sorted with the most recent call first.
520587pub fn method_calls < ' tcx > (
@@ -1254,6 +1321,48 @@ pub fn is_must_use_func_call(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
12541321 did. map_or ( false , |did| must_use_attr ( & cx. tcx . get_attrs ( did) ) . is_some ( ) )
12551322}
12561323
1324+ pub fn get_expr_use_node ( tcx : TyCtxt < ' tcx > , expr : & Expr < ' _ > ) -> Option < Node < ' tcx > > {
1325+ let map = tcx. hir ( ) ;
1326+ let mut child_id = expr. hir_id ;
1327+ let mut iter = map. parent_iter ( child_id) ;
1328+ loop {
1329+ match iter. next ( ) {
1330+ None => break None ,
1331+ Some ( ( id, Node :: Block ( _) ) ) => child_id = id,
1332+ Some ( ( id, Node :: Arm ( arm) ) ) if arm. body . hir_id == child_id => child_id = id,
1333+ Some ( ( _, Node :: Expr ( expr) ) ) => match expr. kind {
1334+ ExprKind :: Break (
1335+ Destination {
1336+ target_id : Ok ( dest) , ..
1337+ } ,
1338+ _,
1339+ ) => {
1340+ iter = map. parent_iter ( dest) ;
1341+ child_id = dest;
1342+ } ,
1343+ ExprKind :: DropTemps ( _) | ExprKind :: Block ( ..) => child_id = expr. hir_id ,
1344+ ExprKind :: If ( control_expr, ..) | ExprKind :: Match ( control_expr, ..)
1345+ if control_expr. hir_id != child_id =>
1346+ {
1347+ child_id = expr. hir_id
1348+ } ,
1349+ _ => break Some ( Node :: Expr ( expr) ) ,
1350+ } ,
1351+ Some ( ( _, node) ) => break Some ( node) ,
1352+ }
1353+ }
1354+ }
1355+
1356+ pub fn is_expr_used ( tcx : TyCtxt < ' _ > , expr : & Expr < ' _ > ) -> bool {
1357+ !matches ! (
1358+ get_expr_use_node( tcx, expr) ,
1359+ Some ( Node :: Stmt ( Stmt {
1360+ kind: StmtKind :: Expr ( _) | StmtKind :: Semi ( _) ,
1361+ ..
1362+ } ) )
1363+ )
1364+ }
1365+
12571366pub fn is_no_std_crate ( cx : & LateContext < ' _ > ) -> bool {
12581367 cx. tcx . hir ( ) . attrs ( hir:: CRATE_HIR_ID ) . iter ( ) . any ( |attr| {
12591368 if let ast:: AttrKind :: Normal ( ref attr, _) = attr. kind {
@@ -1413,28 +1522,43 @@ pub fn peel_hir_pat_refs(pat: &'a Pat<'a>) -> (&'a Pat<'a>, usize) {
14131522 peel ( pat, 0 )
14141523}
14151524
1525+ /// Peels of expressions while the given closure returns `Some`.
1526+ pub fn peel_hir_expr_while < ' tcx > (
1527+ mut expr : & ' tcx Expr < ' tcx > ,
1528+ mut f : impl FnMut ( & ' tcx Expr < ' tcx > ) -> Option < & ' tcx Expr < ' tcx > > ,
1529+ ) -> & ' tcx Expr < ' tcx > {
1530+ while let Some ( e) = f ( expr) {
1531+ expr = e;
1532+ }
1533+ expr
1534+ }
1535+
14161536/// Peels off up to the given number of references on the expression. Returns the underlying
14171537/// expression and the number of references removed.
14181538pub fn peel_n_hir_expr_refs ( expr : & ' a Expr < ' a > , count : usize ) -> ( & ' a Expr < ' a > , usize ) {
1419- fn f ( expr : & ' a Expr < ' a > , count : usize , target : usize ) -> ( & ' a Expr < ' a > , usize ) {
1420- match expr. kind {
1421- ExprKind :: AddrOf ( _, _, expr) if count != target => f ( expr, count + 1 , target) ,
1422- _ => ( expr, count) ,
1423- }
1424- }
1425- f ( expr, 0 , count)
1539+ let mut remaining = count;
1540+ let e = peel_hir_expr_while ( expr, |e| match e. kind {
1541+ ExprKind :: AddrOf ( BorrowKind :: Ref , _, e) if remaining != 0 => {
1542+ remaining -= 1 ;
1543+ Some ( e)
1544+ } ,
1545+ _ => None ,
1546+ } ) ;
1547+ ( e, count - remaining)
14261548}
14271549
14281550/// Peels off all references on the expression. Returns the underlying expression and the number of
14291551/// references removed.
14301552pub fn peel_hir_expr_refs ( expr : & ' a Expr < ' a > ) -> ( & ' a Expr < ' a > , usize ) {
1431- fn f ( expr : & ' a Expr < ' a > , count : usize ) -> ( & ' a Expr < ' a > , usize ) {
1432- match expr. kind {
1433- ExprKind :: AddrOf ( BorrowKind :: Ref , _, expr) => f ( expr, count + 1 ) ,
1434- _ => ( expr, count) ,
1435- }
1436- }
1437- f ( expr, 0 )
1553+ let mut count = 0 ;
1554+ let e = peel_hir_expr_while ( expr, |e| match e. kind {
1555+ ExprKind :: AddrOf ( BorrowKind :: Ref , _, e) => {
1556+ count += 1 ;
1557+ Some ( e)
1558+ } ,
1559+ _ => None ,
1560+ } ) ;
1561+ ( e, count)
14381562}
14391563
14401564#[ macro_export]
0 commit comments