@@ -5,11 +5,10 @@ use rustc_data_structures::fx::FxHashSet;
55use rustc_hir as hir;
66use rustc_hir:: def:: DefKind ;
77use rustc_infer:: infer:: outlives:: env:: OutlivesEnvironment ;
8- use rustc_infer:: infer:: { SubregionOrigin , TyCtxtInferExt } ;
8+ use rustc_infer:: infer:: TyCtxtInferExt ;
99use rustc_macros:: LintDiagnostic ;
1010use rustc_middle:: ty:: { self , TyCtxt } ;
1111use rustc_session:: lint:: builtin:: UNUSED_LIFETIMES ;
12- use rustc_span:: DUMMY_SP ;
1312use rustc_trait_selection:: traits:: { outlives_bounds:: InferCtxtExt , ObligationCtxt } ;
1413
1514use crate :: { LateContext , LateLintPass } ;
@@ -80,17 +79,6 @@ fn check<'tcx>(tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, owner_id: hir::
8079 | DefKind :: Closure => return ,
8180 }
8281
83- let infcx = & tcx. infer_ctxt ( ) . build ( ) ;
84- let ocx = ObligationCtxt :: new ( infcx) ;
85-
86- // Compute the implied outlives bounds for the item. This ensures that we treat
87- // a signature with an argument like `&'a &'b ()` as implicitly having `'b: 'a`.
88- let Ok ( assumed_wf_types) = ocx. assumed_wf_types ( param_env, owner_id. def_id ) else {
89- return ;
90- } ;
91- let implied_bounds = infcx. implied_bounds_tys ( param_env, owner_id. def_id , assumed_wf_types) ;
92- let outlives_env = & OutlivesEnvironment :: with_bounds ( param_env, implied_bounds) ;
93-
9482 // The ordering of this lifetime map is a bit subtle.
9583 //
9684 // Specifically, we want to find a "candidate" lifetime that precedes a "victim" lifetime,
@@ -111,6 +99,22 @@ fn check<'tcx>(tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, owner_id: hir::
11199 }
112100 }
113101
102+ // No lifetimes except for `'static` to check.
103+ if lifetimes. len ( ) == 1 {
104+ return ;
105+ }
106+
107+ let infcx = & tcx. infer_ctxt ( ) . build ( ) ;
108+ let ocx = ObligationCtxt :: new ( infcx) ;
109+
110+ // Compute the implied outlives bounds for the item. This ensures that we treat
111+ // a signature with an argument like `&'a &'b ()` as implicitly having `'b: 'a`.
112+ let Ok ( assumed_wf_types) = ocx. assumed_wf_types ( param_env, owner_id. def_id ) else {
113+ return ;
114+ } ;
115+ let implied_bounds = infcx. implied_bounds_tys ( param_env, owner_id. def_id , assumed_wf_types) ;
116+ let outlives_env = & OutlivesEnvironment :: with_bounds ( param_env, implied_bounds) ;
117+
114118 // Keep track of lifetimes which have already been replaced with other lifetimes.
115119 // This makes sure that if `'a = 'b = 'c`, we don't say `'c` should be replaced by
116120 // both `'a` and `'b`.
@@ -128,6 +132,11 @@ fn check<'tcx>(tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, owner_id: hir::
128132 }
129133
130134 for & victim in & lifetimes[ ( idx + 1 ) ..] {
135+ // We should not suggest renaming `'_` in `&'static &'_ str`.
136+ if !victim. has_name ( ) {
137+ continue ;
138+ }
139+
131140 // We only care about lifetimes that are "real", i.e. that have a def-id.
132141 let ( ty:: ReEarlyParam ( ty:: EarlyParamRegion { def_id, .. } )
133142 | ty:: ReLateParam ( ty:: LateParamRegion {
@@ -146,14 +155,10 @@ fn check<'tcx>(tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, owner_id: hir::
146155 continue ;
147156 }
148157
149- let infcx = infcx. fork ( ) ;
150-
151- // Require that `'candidate = 'victim`
152- infcx. sub_regions ( SubregionOrigin :: RelateRegionParamBound ( DUMMY_SP ) , candidate, victim) ;
153- infcx. sub_regions ( SubregionOrigin :: RelateRegionParamBound ( DUMMY_SP ) , victim, candidate) ;
154-
155158 // If there are no lifetime errors, then we have proven that `'candidate = 'victim`!
156- if infcx. resolve_regions ( outlives_env) . is_empty ( ) {
159+ if outlives_env. free_region_map ( ) . sub_free_regions ( tcx, candidate, victim)
160+ && outlives_env. free_region_map ( ) . sub_free_regions ( tcx, victim, candidate)
161+ {
157162 shadowed. insert ( victim) ;
158163 tcx. emit_spanned_lint (
159164 UNUSED_LIFETIMES ,
0 commit comments