11use rustc_data_structures:: fx:: FxIndexSet ;
2+ use rustc_data_structures:: unord:: UnordSet ;
23use rustc_errors:: { Applicability , LintDiagnostic } ;
34use rustc_hir as hir;
45use rustc_hir:: def:: DefKind ;
56use rustc_hir:: def_id:: { DefId , LocalDefId } ;
67use rustc_hir:: intravisit;
8+ use rustc_macros:: LintDiagnostic ;
9+ use rustc_middle:: middle:: resolve_bound_vars:: ResolvedArg ;
710use rustc_middle:: ty:: {
811 self , Ty , TyCtxt , TypeSuperVisitable , TypeVisitable , TypeVisitableExt , TypeVisitor ,
912} ;
@@ -14,21 +17,30 @@ use rustc_span::{BytePos, Span};
1417use crate :: fluent_generated as fluent;
1518use crate :: { LateContext , LateLintPass } ;
1619
20+ // TODO: feature gate these too
21+
1722declare_lint ! {
1823 /// UwU
1924 pub IMPL_TRAIT_OVERCAPTURES ,
20- Warn ,
25+ Allow ,
2126 "will capture more lifetimes than possibly intended in edition 2024" ,
2227 @future_incompatible = FutureIncompatibleInfo {
2328 reason: FutureIncompatibilityReason :: EditionSemanticsChange ( Edition :: Edition2024 ) ,
2429 reference: "<https://doc.rust-lang.org/nightly/edition-guide/rust-2021/IntoIterator-for-arrays.html>" ,
2530 } ;
2631}
2732
33+ declare_lint ! {
34+ /// UwU
35+ pub IMPL_TRAIT_REDUNDANT_CAPTURES ,
36+ Warn ,
37+ "uwu 2"
38+ }
39+
2840declare_lint_pass ! (
2941 /// Lint for opaque types that will begin capturing in-scope but unmentioned lifetimes
3042 /// in edition 2024.
31- ImplTraitOvercaptures => [ IMPL_TRAIT_OVERCAPTURES ]
43+ ImplTraitOvercaptures => [ IMPL_TRAIT_OVERCAPTURES , IMPL_TRAIT_REDUNDANT_CAPTURES ]
3244) ;
3345
3446impl < ' tcx > LateLintPass < ' tcx > for ImplTraitOvercaptures {
@@ -109,14 +121,11 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for VisitOpaqueTypes<'tcx> {
109121 let unique = self . in_scope_parameters . insert ( def_id) ;
110122 assert ! ( unique) ;
111123 }
112- ty:: BoundVariableKind :: Ty ( _) => {
113- todo ! ( "we don't support late-bound type params in `impl Trait`" )
114- }
115- ty:: BoundVariableKind :: Region ( ..) => {
116- unreachable ! ( "all AST-derived bound regions should have a name" )
117- }
118- ty:: BoundVariableKind :: Const => {
119- unreachable ! ( "non-lifetime binder consts are not allowed" )
124+ _ => {
125+ self . tcx . dcx ( ) . span_delayed_bug (
126+ self . tcx . def_span ( self . parent_def_id ) ,
127+ format ! ( "unsupported bound variable kind: {arg:?}" ) ,
128+ ) ;
120129 }
121130 }
122131 }
@@ -144,8 +153,6 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for VisitOpaqueTypes<'tcx> {
144153 self . tcx . hir_node_by_def_id ( opaque_def_id) . expect_item ( ) . expect_opaque_ty ( )
145154 && let hir:: OpaqueTyOrigin :: FnReturn ( parent_def_id) = opaque. origin
146155 && parent_def_id == self . parent_def_id
147- // And if the opaque doesn't already have `use<>` syntax on it...
148- && opaque. precise_capturing_args . is_none ( )
149156 {
150157 // Compute the set of args that are captured by the opaque...
151158 let mut captured = FxIndexSet :: default ( ) ;
@@ -178,9 +185,16 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for VisitOpaqueTypes<'tcx> {
178185 . map ( |def_id| self . tcx . def_span ( def_id) )
179186 . collect ( ) ;
180187
181- if !uncaptured_spans. is_empty ( ) {
182- let opaque_span = self . tcx . def_span ( opaque_def_id) ;
188+ let opaque_span = self . tcx . def_span ( opaque_def_id) ;
189+ let new_capture_rules =
190+ opaque_span. at_least_rust_2024 ( ) || self . tcx . features ( ) . lifetime_capture_rules_2024 ;
183191
192+ // If we have uncaptured args, and if the opaque doesn't already have
193+ // `use<>` syntax on it, and we're < edition 2024, then warn the user.
194+ if !new_capture_rules
195+ && opaque. precise_capturing_args . is_none ( )
196+ && !uncaptured_spans. is_empty ( )
197+ {
184198 let suggestion = if let Ok ( snippet) =
185199 self . tcx . sess . source_map ( ) . span_to_snippet ( opaque_span)
186200 && snippet. starts_with ( "impl " )
@@ -207,18 +221,72 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for VisitOpaqueTypes<'tcx> {
207221 None
208222 } ;
209223
210- self . tcx . emit_node_lint (
224+ self . tcx . emit_node_span_lint (
211225 IMPL_TRAIT_OVERCAPTURES ,
212226 self . tcx . local_def_id_to_hir_id ( opaque_def_id) ,
227+ opaque_span,
213228 ImplTraitOvercapturesLint {
214- opaque_span,
215229 self_ty : t,
216230 num_captured : uncaptured_spans. len ( ) ,
217231 uncaptured_spans,
218232 suggestion,
219233 } ,
220234 ) ;
221235 }
236+ // Otherwise, if we are edition 2024, have `use<>` syntax, and
237+ // have no uncaptured args, then we should warn to the user that
238+ // it's redundant to capture all args explicitly.
239+ else if new_capture_rules
240+ && let Some ( ( captured_args, capturing_span) ) = opaque. precise_capturing_args
241+ {
242+ let mut explicitly_captured = UnordSet :: default ( ) ;
243+ for arg in captured_args {
244+ match self . tcx . named_bound_var ( arg. hir_id ( ) ) {
245+ Some (
246+ ResolvedArg :: EarlyBound ( def_id) | ResolvedArg :: LateBound ( _, _, def_id) ,
247+ ) => {
248+ if self . tcx . def_kind ( self . tcx . parent ( def_id) ) == DefKind :: OpaqueTy {
249+ let ( ty:: ReEarlyParam ( ty:: EarlyParamRegion { def_id, .. } )
250+ | ty:: ReLateParam ( ty:: LateParamRegion {
251+ bound_region : ty:: BoundRegionKind :: BrNamed ( def_id, _) ,
252+ ..
253+ } ) ) = self
254+ . tcx
255+ . map_opaque_lifetime_to_parent_lifetime ( def_id. expect_local ( ) )
256+ . kind ( )
257+ else {
258+ span_bug ! (
259+ self . tcx. def_span( def_id) ,
260+ "variable should have been duplicated from a parent"
261+ ) ;
262+ } ;
263+ explicitly_captured. insert ( def_id) ;
264+ } else {
265+ explicitly_captured. insert ( def_id) ;
266+ }
267+ }
268+ _ => {
269+ self . tcx . dcx ( ) . span_delayed_bug (
270+ self . tcx ( ) . hir ( ) . span ( arg. hir_id ( ) ) ,
271+ "no valid for captured arg" ,
272+ ) ;
273+ }
274+ }
275+ }
276+
277+ if self
278+ . in_scope_parameters
279+ . iter ( )
280+ . all ( |def_id| explicitly_captured. contains ( def_id) )
281+ {
282+ self . tcx . emit_node_span_lint (
283+ IMPL_TRAIT_REDUNDANT_CAPTURES ,
284+ self . tcx . local_def_id_to_hir_id ( opaque_def_id) ,
285+ opaque_span,
286+ ImplTraitRedundantCapturesLint { capturing_span } ,
287+ ) ;
288+ }
289+ }
222290
223291 // Walk into the bounds of the opaque, too, since we want to get nested opaques
224292 // in this lint as well. Interestingly, one place that I expect this lint to fire
@@ -236,7 +304,6 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for VisitOpaqueTypes<'tcx> {
236304}
237305
238306struct ImplTraitOvercapturesLint < ' tcx > {
239- opaque_span : Span ,
240307 uncaptured_spans : Vec < Span > ,
241308 self_ty : Ty < ' tcx > ,
242309 num_captured : usize ,
@@ -247,7 +314,6 @@ impl<'a> LintDiagnostic<'a, ()> for ImplTraitOvercapturesLint<'_> {
247314 fn decorate_lint < ' b > ( self , diag : & ' b mut rustc_errors:: Diag < ' a , ( ) > ) {
248315 diag. arg ( "self_ty" , self . self_ty . to_string ( ) )
249316 . arg ( "num_captured" , self . num_captured )
250- . span ( self . opaque_span )
251317 . span_note ( self . uncaptured_spans , fluent:: lint_note)
252318 . note ( fluent:: lint_note2) ;
253319 if let Some ( ( suggestion, span) ) = self . suggestion {
@@ -265,6 +331,13 @@ impl<'a> LintDiagnostic<'a, ()> for ImplTraitOvercapturesLint<'_> {
265331 }
266332}
267333
334+ #[ derive( LintDiagnostic ) ]
335+ #[ diag( lint_impl_trait_redundant_captures) ]
336+ struct ImplTraitRedundantCapturesLint {
337+ #[ suggestion( lint_suggestion, code = "" , applicability = "machine-applicable" ) ]
338+ capturing_span : Span ,
339+ }
340+
268341fn extract_def_id_from_arg < ' tcx > (
269342 tcx : TyCtxt < ' tcx > ,
270343 generics : & ' tcx ty:: Generics ,
0 commit comments