33// SPDX-License-Identifier: MIT OR Apache-2.0
44
55use rustc_data_structures:: fx:: { FxHashMap , FxHashSet } ;
6+ use rustc_errors:: { Diag , DiagCtxtHandle , Diagnostic , Level } ;
67use rustc_lint:: { LateContext , LateLintPass , LintContext } ;
78use rustc_middle:: mir:: mono:: MonoItem ;
89use rustc_middle:: ty:: Instance ;
@@ -20,6 +21,16 @@ declare_tool_lint! {
2021
2122declare_lint_pass ! ( InfallibleAllocation => [ INFALLIBLE_ALLOCATION ] ) ;
2223
24+ struct ClosureDiag < F : FnOnce ( & mut Diag < ' _ , ( ) > ) > ( F ) ;
25+
26+ impl < ' a , F : FnOnce ( & mut Diag < ' _ , ( ) > ) > Diagnostic < ' a , ( ) > for ClosureDiag < F > {
27+ fn into_diag ( self , dcx : DiagCtxtHandle < ' a > , level : Level ) -> Diag < ' a , ( ) > {
28+ let mut lint = Diag :: new ( dcx, level, "" ) ;
29+ ( self . 0 ) ( & mut lint) ;
30+ lint
31+ }
32+ }
33+
2334fn is_generic_fn < ' tcx > ( instance : Instance < ' tcx > ) -> bool {
2435 instance. args . non_erasable_generics ( ) . next ( ) . is_some ( )
2536}
@@ -174,73 +185,77 @@ impl<'tcx> LateLintPass<'tcx> for InfallibleAllocation {
174185 . tcx
175186 . def_path_str_with_args ( accessee. def_id ( ) , accessee. args ) ;
176187
177- cx. span_lint ( INFALLIBLE_ALLOCATION , item. span , |diag| {
178- diag. primary_message ( format ! (
179- "`{}` can perform infallible allocation{}" ,
180- accessee_path, generic_note
181- ) ) ;
182- // For generic functions try to display a stacktrace until a non-generic one.
183- let mut caller = * accessor;
184- let mut visited = FxHashSet :: default ( ) ;
185- visited. insert ( * accessor) ;
186- visited. insert ( accessee) ;
187- while is_generic_fn ( caller) {
188- let spanned_caller = match backward
189- . get ( & caller)
190- . map ( |x| & * * x)
191- . unwrap_or ( & [ ] )
192- . iter ( )
193- . find ( |x| !visited. contains ( & x. node ) )
194- {
195- Some ( v) => * v,
196- None => break ,
197- } ;
198- caller = spanned_caller. node ;
199- visited. insert ( caller) ;
200-
201- diag. span_note (
202- spanned_caller. span ,
203- format ! (
204- "which is called from `{}`" ,
205- cx. tcx. def_path_str_with_args( caller. def_id( ) , caller. args)
206- ) ,
207- ) ;
208- }
209-
210- // Generate some help messages for why the function is determined to be infallible.
211- let mut msg: & str = & format ! (
212- "`{}` is determined to be infallible because it" ,
213- accessee_path
214- ) ;
215- let mut callee = accessee;
216- loop {
217- let callee_callee = match forward
218- . get ( & callee)
219- . map ( |x| & * * x)
220- . unwrap_or ( & [ ] )
221- . iter ( )
222- . find ( |x| {
223- infallible. contains ( & x. node ) && !visited. contains ( & x. node )
224- } ) {
225- Some ( v) => v,
226- None => break ,
227- } ;
228- callee = callee_callee. node ;
229- visited. insert ( callee) ;
230-
231- diag. span_note (
232- callee_callee. span ,
233- format ! (
234- "{} calls into `{}`" ,
235- msg,
236- cx. tcx. def_path_str_with_args( callee. def_id( ) , callee. args)
237- ) ,
188+ cx. emit_span_lint (
189+ INFALLIBLE_ALLOCATION ,
190+ item. span ,
191+ ClosureDiag ( |diag| {
192+ diag. primary_message ( format ! (
193+ "`{}` can perform infallible allocation{}" ,
194+ accessee_path, generic_note
195+ ) ) ;
196+ // For generic functions try to display a stacktrace until a non-generic one.
197+ let mut caller = * accessor;
198+ let mut visited = FxHashSet :: default ( ) ;
199+ visited. insert ( * accessor) ;
200+ visited. insert ( accessee) ;
201+ while is_generic_fn ( caller) {
202+ let spanned_caller = match backward
203+ . get ( & caller)
204+ . map ( |x| & * * x)
205+ . unwrap_or ( & [ ] )
206+ . iter ( )
207+ . find ( |x| !visited. contains ( & x. node ) )
208+ {
209+ Some ( v) => * v,
210+ None => break ,
211+ } ;
212+ caller = spanned_caller. node ;
213+ visited. insert ( caller) ;
214+
215+ diag. span_note (
216+ spanned_caller. span ,
217+ format ! (
218+ "which is called from `{}`" ,
219+ cx. tcx. def_path_str_with_args( caller. def_id( ) , caller. args)
220+ ) ,
221+ ) ;
222+ }
223+
224+ // Generate some help messages for why the function is determined to be infallible.
225+ let mut msg: & str = & format ! (
226+ "`{}` is determined to be infallible because it" ,
227+ accessee_path
238228 ) ;
239- msg = "which" ;
240- }
241-
242- diag. note ( format ! ( "{} may call alloc_error_handler" , msg) ) ;
243- } ) ;
229+ let mut callee = accessee;
230+ loop {
231+ let callee_callee = match forward
232+ . get ( & callee)
233+ . map ( |x| & * * x)
234+ . unwrap_or ( & [ ] )
235+ . iter ( )
236+ . find ( |x| {
237+ infallible. contains ( & x. node ) && !visited. contains ( & x. node )
238+ } ) {
239+ Some ( v) => v,
240+ None => break ,
241+ } ;
242+ callee = callee_callee. node ;
243+ visited. insert ( callee) ;
244+
245+ diag. span_note (
246+ callee_callee. span ,
247+ format ! (
248+ "{} calls into `{}`" ,
249+ msg,
250+ cx. tcx. def_path_str_with_args( callee. def_id( ) , callee. args)
251+ ) ,
252+ ) ;
253+ msg = "which" ;
254+ }
255+
256+ diag. note ( format ! ( "{} may call alloc_error_handler" , msg) ) ;
257+ } ) ,
258+ ) ;
244259 }
245260 }
246261 }
0 commit comments