@@ -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