@@ -51,10 +51,11 @@ impl<'a, 'tcx> Visitor<'tcx> for FunctionItemRefChecker<'a, 'tcx> {
5151 let arg_ty = args[ 0 ] . ty ( self . body , self . tcx ) ;
5252 for generic_inner_ty in arg_ty. walk ( ) {
5353 if let GenericArgKind :: Type ( inner_ty) = generic_inner_ty. unpack ( ) {
54- if let Some ( fn_id) = FunctionItemRefChecker :: is_fn_ref ( inner_ty) {
55- let ident = self . tcx . item_name ( fn_id) . to_ident_string ( ) ;
54+ if let Some ( ( fn_id, fn_substs) ) =
55+ FunctionItemRefChecker :: is_fn_ref ( inner_ty)
56+ {
5657 let span = self . nth_arg_span ( & args, 0 ) ;
57- self . emit_lint ( ident , fn_id , source_info, span) ;
58+ self . emit_lint ( fn_id , fn_substs , source_info, span) ;
5859 }
5960 }
6061 }
@@ -66,6 +67,7 @@ impl<'a, 'tcx> Visitor<'tcx> for FunctionItemRefChecker<'a, 'tcx> {
6667 }
6768 self . super_terminator ( terminator, location) ;
6869 }
70+
6971 /// Emits a lint for function references formatted with `fmt::Pointer::fmt` by macros. These
7072 /// cases are handled as operands instead of call terminators to avoid any dependence on
7173 /// unstable, internal formatting details like whether `fmt` is called directly or not.
@@ -76,13 +78,12 @@ impl<'a, 'tcx> Visitor<'tcx> for FunctionItemRefChecker<'a, 'tcx> {
7678 if let ty:: FnDef ( def_id, substs_ref) = * op_ty. kind ( ) {
7779 if self . tcx . is_diagnostic_item ( sym:: pointer_trait_fmt, def_id) {
7880 let param_ty = substs_ref. type_at ( 0 ) ;
79- if let Some ( fn_id) = FunctionItemRefChecker :: is_fn_ref ( param_ty) {
81+ if let Some ( ( fn_id, fn_substs ) ) = FunctionItemRefChecker :: is_fn_ref ( param_ty) {
8082 // The operand's ctxt wouldn't display the lint since it's inside a macro so
8183 // we have to use the callsite's ctxt.
8284 let callsite_ctxt = source_info. span . source_callsite ( ) . ctxt ( ) ;
8385 let span = source_info. span . with_ctxt ( callsite_ctxt) ;
84- let ident = self . tcx . item_name ( fn_id) . to_ident_string ( ) ;
85- self . emit_lint ( ident, fn_id, source_info, span) ;
86+ self . emit_lint ( fn_id, fn_substs, source_info, span) ;
8687 }
8788 }
8889 }
@@ -115,10 +116,11 @@ impl<'a, 'tcx> FunctionItemRefChecker<'a, 'tcx> {
115116 if TyS :: same_type ( inner_ty, bound_ty) {
116117 // Do a substitution using the parameters from the callsite
117118 let subst_ty = inner_ty. subst ( self . tcx , substs_ref) ;
118- if let Some ( fn_id) = FunctionItemRefChecker :: is_fn_ref ( subst_ty) {
119- let ident = self . tcx . item_name ( fn_id) . to_ident_string ( ) ;
119+ if let Some ( ( fn_id, fn_substs) ) =
120+ FunctionItemRefChecker :: is_fn_ref ( subst_ty)
121+ {
120122 let span = self . nth_arg_span ( args, arg_num) ;
121- self . emit_lint ( ident , fn_id , source_info, span) ;
123+ self . emit_lint ( fn_id , fn_substs , source_info, span) ;
122124 }
123125 }
124126 }
@@ -127,6 +129,7 @@ impl<'a, 'tcx> FunctionItemRefChecker<'a, 'tcx> {
127129 }
128130 }
129131 }
132+
130133 /// If the given predicate is the trait `fmt::Pointer`, returns the bound parameter type.
131134 fn is_pointer_trait ( & self , bound : & PredicateAtom < ' tcx > ) -> Option < Ty < ' tcx > > {
132135 if let ty:: PredicateAtom :: Trait ( predicate, _) = bound {
@@ -139,22 +142,26 @@ impl<'a, 'tcx> FunctionItemRefChecker<'a, 'tcx> {
139142 None
140143 }
141144 }
145+
142146 /// If a type is a reference or raw pointer to the anonymous type of a function definition,
143- /// returns that function's `DefId`.
144- fn is_fn_ref ( ty : Ty < ' tcx > ) -> Option < DefId > {
147+ /// returns that function's `DefId` and `SubstsRef` .
148+ fn is_fn_ref ( ty : Ty < ' tcx > ) -> Option < ( DefId , SubstsRef < ' tcx > ) > {
145149 let referent_ty = match ty. kind ( ) {
146150 ty:: Ref ( _, referent_ty, _) => Some ( referent_ty) ,
147151 ty:: RawPtr ( ty_and_mut) => Some ( & ty_and_mut. ty ) ,
148152 _ => None ,
149153 } ;
150154 referent_ty
151- . map (
152- |ref_ty| {
153- if let ty:: FnDef ( def_id, _) = * ref_ty. kind ( ) { Some ( def_id) } else { None }
154- } ,
155- )
155+ . map ( |ref_ty| {
156+ if let ty:: FnDef ( def_id, substs_ref) = * ref_ty. kind ( ) {
157+ Some ( ( def_id, substs_ref) )
158+ } else {
159+ None
160+ }
161+ } )
156162 . unwrap_or ( None )
157163 }
164+
158165 fn nth_arg_span ( & self , args : & Vec < Operand < ' tcx > > , n : usize ) -> Span {
159166 match & args[ n] {
160167 Operand :: Copy ( place) | Operand :: Move ( place) => {
@@ -163,7 +170,14 @@ impl<'a, 'tcx> FunctionItemRefChecker<'a, 'tcx> {
163170 Operand :: Constant ( constant) => constant. span ,
164171 }
165172 }
166- fn emit_lint ( & self , ident : String , fn_id : DefId , source_info : SourceInfo , span : Span ) {
173+
174+ fn emit_lint (
175+ & self ,
176+ fn_id : DefId ,
177+ fn_substs : SubstsRef < ' tcx > ,
178+ source_info : SourceInfo ,
179+ span : Span ,
180+ ) {
167181 let lint_root = self . body . source_scopes [ source_info. scope ]
168182 . local_data
169183 . as_ref ( )
@@ -180,6 +194,10 @@ impl<'a, 'tcx> FunctionItemRefChecker<'a, 'tcx> {
180194 s
181195 }
182196 } ;
197+ let ident = self . tcx . item_name ( fn_id) . to_ident_string ( ) ;
198+ let ty_params = fn_substs. types ( ) . map ( |ty| format ! ( "{}" , ty) ) ;
199+ let const_params = fn_substs. consts ( ) . map ( |c| format ! ( "{}" , c) ) ;
200+ let params = ty_params. chain ( const_params) . collect :: < Vec < String > > ( ) . join ( ", " ) ;
183201 let num_args = fn_sig. inputs ( ) . map_bound ( |inputs| inputs. len ( ) ) . skip_binder ( ) ;
184202 let variadic = if fn_sig. c_variadic ( ) { ", ..." } else { "" } ;
185203 let ret = if fn_sig. output ( ) . skip_binder ( ) . is_unit ( ) { "" } else { " -> _" } ;
@@ -190,7 +208,7 @@ impl<'a, 'tcx> FunctionItemRefChecker<'a, 'tcx> {
190208 & format ! ( "cast `{}` to obtain a function pointer" , ident) ,
191209 format ! (
192210 "{} as {}{}fn({}{}){}" ,
193- ident,
211+ if params . is_empty ( ) { ident } else { format! ( "{}::<{}>" , ident , params ) } ,
194212 unsafety,
195213 abi,
196214 vec![ "_" ; num_args] . join( ", " ) ,
0 commit comments