@@ -51,10 +51,11 @@ impl<'a, 'tcx> Visitor<'tcx> for FunctionItemRefChecker<'a, 'tcx> {
51
51
let arg_ty = args[ 0 ] . ty ( self . body , self . tcx ) ;
52
52
for generic_inner_ty in arg_ty. walk ( ) {
53
53
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
+ {
56
57
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) ;
58
59
}
59
60
}
60
61
}
@@ -66,6 +67,7 @@ impl<'a, 'tcx> Visitor<'tcx> for FunctionItemRefChecker<'a, 'tcx> {
66
67
}
67
68
self . super_terminator ( terminator, location) ;
68
69
}
70
+
69
71
/// Emits a lint for function references formatted with `fmt::Pointer::fmt` by macros. These
70
72
/// cases are handled as operands instead of call terminators to avoid any dependence on
71
73
/// 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> {
76
78
if let ty:: FnDef ( def_id, substs_ref) = * op_ty. kind ( ) {
77
79
if self . tcx . is_diagnostic_item ( sym:: pointer_trait_fmt, def_id) {
78
80
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) {
80
82
// The operand's ctxt wouldn't display the lint since it's inside a macro so
81
83
// we have to use the callsite's ctxt.
82
84
let callsite_ctxt = source_info. span . source_callsite ( ) . ctxt ( ) ;
83
85
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) ;
86
87
}
87
88
}
88
89
}
@@ -115,10 +116,11 @@ impl<'a, 'tcx> FunctionItemRefChecker<'a, 'tcx> {
115
116
if TyS :: same_type ( inner_ty, bound_ty) {
116
117
// Do a substitution using the parameters from the callsite
117
118
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
+ {
120
122
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) ;
122
124
}
123
125
}
124
126
}
@@ -127,6 +129,7 @@ impl<'a, 'tcx> FunctionItemRefChecker<'a, 'tcx> {
127
129
}
128
130
}
129
131
}
132
+
130
133
/// If the given predicate is the trait `fmt::Pointer`, returns the bound parameter type.
131
134
fn is_pointer_trait ( & self , bound : & PredicateAtom < ' tcx > ) -> Option < Ty < ' tcx > > {
132
135
if let ty:: PredicateAtom :: Trait ( predicate, _) = bound {
@@ -139,22 +142,26 @@ impl<'a, 'tcx> FunctionItemRefChecker<'a, 'tcx> {
139
142
None
140
143
}
141
144
}
145
+
142
146
/// 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 > ) > {
145
149
let referent_ty = match ty. kind ( ) {
146
150
ty:: Ref ( _, referent_ty, _) => Some ( referent_ty) ,
147
151
ty:: RawPtr ( ty_and_mut) => Some ( & ty_and_mut. ty ) ,
148
152
_ => None ,
149
153
} ;
150
154
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
+ } )
156
162
. unwrap_or ( None )
157
163
}
164
+
158
165
fn nth_arg_span ( & self , args : & Vec < Operand < ' tcx > > , n : usize ) -> Span {
159
166
match & args[ n] {
160
167
Operand :: Copy ( place) | Operand :: Move ( place) => {
@@ -163,7 +170,14 @@ impl<'a, 'tcx> FunctionItemRefChecker<'a, 'tcx> {
163
170
Operand :: Constant ( constant) => constant. span ,
164
171
}
165
172
}
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
+ ) {
167
181
let lint_root = self . body . source_scopes [ source_info. scope ]
168
182
. local_data
169
183
. as_ref ( )
@@ -180,6 +194,10 @@ impl<'a, 'tcx> FunctionItemRefChecker<'a, 'tcx> {
180
194
s
181
195
}
182
196
} ;
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 ( ", " ) ;
183
201
let num_args = fn_sig. inputs ( ) . map_bound ( |inputs| inputs. len ( ) ) . skip_binder ( ) ;
184
202
let variadic = if fn_sig. c_variadic ( ) { ", ..." } else { "" } ;
185
203
let ret = if fn_sig. output ( ) . skip_binder ( ) . is_unit ( ) { "" } else { " -> _" } ;
@@ -190,7 +208,7 @@ impl<'a, 'tcx> FunctionItemRefChecker<'a, 'tcx> {
190
208
& format ! ( "cast `{}` to obtain a function pointer" , ident) ,
191
209
format ! (
192
210
"{} as {}{}fn({}{}){}" ,
193
- ident,
211
+ if params . is_empty ( ) { ident } else { format! ( "{}::<{}>" , ident , params ) } ,
194
212
unsafety,
195
213
abi,
196
214
vec![ "_" ; num_args] . join( ", " ) ,
0 commit comments