@@ -9,12 +9,14 @@ use rustc_hir::intravisit::{
99use rustc_hir:: FnRetTy :: Return ;
1010use rustc_hir:: {
1111 BareFnTy , BodyId , FnDecl , GenericArg , GenericBound , GenericParam , GenericParamKind , Generics , Impl , ImplItem ,
12- ImplItemKind , Item , ItemKind , LangItem , Lifetime , LifetimeName , LifetimeParamKind , ParamName , PolyTraitRef ,
13- PredicateOrigin , TraitBoundModifier , TraitFn , TraitItem , TraitItemKind , Ty , TyKind , WherePredicate ,
12+ ImplItemKind , Item , ItemKind , LangItem , Lifetime , LifetimeName , ParamName , PolyTraitRef , PredicateOrigin ,
13+ TraitBoundModifier , TraitFn , TraitItem , TraitItemKind , Ty , TyKind , WherePredicate ,
1414} ;
1515use rustc_lint:: { LateContext , LateLintPass } ;
1616use rustc_middle:: hir:: nested_filter as middle_nested_filter;
17+ use rustc_middle:: ty:: TyCtxt ;
1718use rustc_session:: { declare_lint_pass, declare_tool_lint} ;
19+ use rustc_span:: def_id:: LocalDefId ;
1820use rustc_span:: source_map:: Span ;
1921use rustc_span:: symbol:: { kw, Ident , Symbol } ;
2022
@@ -129,7 +131,7 @@ impl<'tcx> LateLintPass<'tcx> for Lifetimes {
129131enum RefLt {
130132 Unnamed ,
131133 Static ,
132- Named ( Symbol ) ,
134+ Named ( LocalDefId ) ,
133135}
134136
135137fn check_fn_inner < ' tcx > (
@@ -232,7 +234,7 @@ fn could_use_elision<'tcx>(
232234 // level of the current item.
233235
234236 // check named LTs
235- let allowed_lts = allowed_lts_from ( named_generics) ;
237+ let allowed_lts = allowed_lts_from ( cx . tcx , named_generics) ;
236238
237239 // these will collect all the lifetimes for references in arg/return types
238240 let mut input_visitor = RefVisitor :: new ( cx) ;
@@ -254,22 +256,6 @@ fn could_use_elision<'tcx>(
254256 return false ;
255257 }
256258
257- if allowed_lts
258- . intersection (
259- & input_visitor
260- . nested_elision_site_lts
261- . iter ( )
262- . chain ( output_visitor. nested_elision_site_lts . iter ( ) )
263- . cloned ( )
264- . filter ( |v| matches ! ( v, RefLt :: Named ( _) ) )
265- . collect ( ) ,
266- )
267- . next ( )
268- . is_some ( )
269- {
270- return false ;
271- }
272-
273259 let input_lts = input_visitor. lts ;
274260 let output_lts = output_visitor. lts ;
275261
@@ -303,6 +289,31 @@ fn could_use_elision<'tcx>(
303289 }
304290 }
305291
292+ // check for higher-ranked trait bounds
293+ if !input_visitor. nested_elision_site_lts . is_empty ( ) || !output_visitor. nested_elision_site_lts . is_empty ( ) {
294+ let allowed_lts: FxHashSet < _ > = allowed_lts
295+ . iter ( )
296+ . filter_map ( |lt| match lt {
297+ RefLt :: Named ( def_id) => Some ( cx. tcx . item_name ( def_id. to_def_id ( ) ) ) ,
298+ _ => None ,
299+ } )
300+ . collect ( ) ;
301+ for lt in input_visitor. nested_elision_site_lts {
302+ if let RefLt :: Named ( def_id) = lt {
303+ if allowed_lts. contains ( & cx. tcx . item_name ( def_id. to_def_id ( ) ) ) {
304+ return false ;
305+ }
306+ }
307+ }
308+ for lt in output_visitor. nested_elision_site_lts {
309+ if let RefLt :: Named ( def_id) = lt {
310+ if allowed_lts. contains ( & cx. tcx . item_name ( def_id. to_def_id ( ) ) ) {
311+ return false ;
312+ }
313+ }
314+ }
315+ }
316+
306317 // no input lifetimes? easy case!
307318 if input_lts. is_empty ( ) {
308319 false
@@ -335,14 +346,11 @@ fn could_use_elision<'tcx>(
335346 }
336347}
337348
338- fn allowed_lts_from ( named_generics : & [ GenericParam < ' _ > ] ) -> FxHashSet < RefLt > {
349+ fn allowed_lts_from ( tcx : TyCtxt < ' _ > , named_generics : & [ GenericParam < ' _ > ] ) -> FxHashSet < RefLt > {
339350 let mut allowed_lts = FxHashSet :: default ( ) ;
340351 for par in named_generics. iter ( ) {
341- if let GenericParamKind :: Lifetime {
342- kind : LifetimeParamKind :: Explicit ,
343- } = par. kind
344- {
345- allowed_lts. insert ( RefLt :: Named ( par. name . ident ( ) . name ) ) ;
352+ if let GenericParamKind :: Lifetime { .. } = par. kind {
353+ allowed_lts. insert ( RefLt :: Named ( tcx. hir ( ) . local_def_id ( par. hir_id ) ) ) ;
346354 }
347355 }
348356 allowed_lts. insert ( RefLt :: Unnamed ) ;
@@ -385,8 +393,10 @@ impl<'a, 'tcx> RefVisitor<'a, 'tcx> {
385393 self . lts . push ( RefLt :: Unnamed ) ;
386394 } else if lt. is_elided ( ) {
387395 self . lts . push ( RefLt :: Unnamed ) ;
396+ } else if let LifetimeName :: Param ( def_id, _) = lt. name {
397+ self . lts . push ( RefLt :: Named ( def_id) ) ;
388398 } else {
389- self . lts . push ( RefLt :: Named ( lt . name . ident ( ) . name ) ) ;
399+ self . lts . push ( RefLt :: Unnamed ) ;
390400 }
391401 } else {
392402 self . lts . push ( RefLt :: Unnamed ) ;
@@ -434,18 +444,22 @@ impl<'a, 'tcx> Visitor<'tcx> for RefVisitor<'a, 'tcx> {
434444 TyKind :: OpaqueDef ( item, bounds) => {
435445 let map = self . cx . tcx . hir ( ) ;
436446 let item = map. item ( item) ;
447+ let len = self . lts . len ( ) ;
437448 walk_item ( self , item) ;
438- walk_ty ( self , ty ) ;
449+ self . lts . truncate ( len ) ;
439450 self . lts . extend ( bounds. iter ( ) . filter_map ( |bound| match bound {
440- GenericArg :: Lifetime ( l) => Some ( RefLt :: Named ( l. name . ident ( ) . name ) ) ,
451+ GenericArg :: Lifetime ( l) => Some ( if let LifetimeName :: Param ( def_id, _) = l. name {
452+ RefLt :: Named ( def_id)
453+ } else {
454+ RefLt :: Unnamed
455+ } ) ,
441456 _ => None ,
442457 } ) ) ;
443458 } ,
444459 TyKind :: BareFn ( & BareFnTy { decl, .. } ) => {
445460 let mut sub_visitor = RefVisitor :: new ( self . cx ) ;
446461 sub_visitor. visit_fn_decl ( decl) ;
447462 self . nested_elision_site_lts . append ( & mut sub_visitor. all_lts ( ) ) ;
448- return ;
449463 } ,
450464 TyKind :: TraitObject ( bounds, ref lt, _) => {
451465 if !lt. is_elided ( ) {
@@ -454,11 +468,9 @@ impl<'a, 'tcx> Visitor<'tcx> for RefVisitor<'a, 'tcx> {
454468 for bound in bounds {
455469 self . visit_poly_trait_ref ( bound, TraitBoundModifier :: None ) ;
456470 }
457- return ;
458471 } ,
459- _ => ( ) ,
472+ _ => walk_ty ( self , ty ) ,
460473 }
461- walk_ty ( self , ty) ;
462474 }
463475}
464476
@@ -477,7 +489,7 @@ fn has_where_lifetimes<'tcx>(cx: &LateContext<'tcx>, generics: &'tcx Generics<'_
477489 return true ;
478490 }
479491 // if the bounds define new lifetimes, they are fine to occur
480- let allowed_lts = allowed_lts_from ( pred. bound_generic_params ) ;
492+ let allowed_lts = allowed_lts_from ( cx . tcx , pred. bound_generic_params ) ;
481493 // now walk the bounds
482494 for bound in pred. bounds . iter ( ) {
483495 walk_param_bound ( & mut visitor, bound) ;
@@ -601,7 +613,7 @@ struct BodyLifetimeChecker {
601613impl < ' tcx > Visitor < ' tcx > for BodyLifetimeChecker {
602614 // for lifetimes as parameters of generics
603615 fn visit_lifetime ( & mut self , lifetime : & ' tcx Lifetime ) {
604- if lifetime. name . ident ( ) . name != kw:: Empty && lifetime. name . ident ( ) . name != kw:: StaticLifetime {
616+ if lifetime. name . ident ( ) . name != kw:: UnderscoreLifetime && lifetime. name . ident ( ) . name != kw:: StaticLifetime {
605617 self . lifetimes_used_in_body = true ;
606618 }
607619 }
0 commit comments