@@ -191,134 +191,146 @@ impl<'a> LintDiagnosticBuilder<'a> {
191
191
}
192
192
}
193
193
194
- pub fn struct_lint_level < ' s > (
194
+ pub fn struct_lint_level < ' s , ' d > (
195
195
sess : & ' s Session ,
196
196
lint : & ' static Lint ,
197
197
level : Level ,
198
198
src : LintSource ,
199
199
span : Option < MultiSpan > ,
200
- decorate : impl for < ' a > FnOnce ( LintDiagnosticBuilder < ' a > ) ) {
201
-
202
- // FIXME: Move the guts of this function into a fn which takes dyn Fn to reduce code bloat.
203
- let mut err = match ( level, span) {
204
- ( Level :: Allow , _) => { return ; } ,
205
- ( Level :: Warn , Some ( span) ) => sess. struct_span_warn ( span, "" ) ,
206
- ( Level :: Warn , None ) => sess. struct_warn ( "" ) ,
207
- ( Level :: Deny , Some ( span) ) | ( Level :: Forbid , Some ( span) ) => sess. struct_span_err ( span, "" ) ,
208
- ( Level :: Deny , None ) | ( Level :: Forbid , None ) => sess. struct_err ( "" ) ,
209
- } ;
200
+ decorate : impl for < ' a > FnOnce ( LintDiagnosticBuilder < ' a > ) + ' d ,
201
+ ) {
202
+ // Avoid codegen bloat from monomorphization by immediately doing dyn dispatch of `decorate` to
203
+ // the "real" work.
204
+ fn struct_lint_level_impl (
205
+ sess : & ' s Session ,
206
+ lint : & ' static Lint ,
207
+ level : Level ,
208
+ src : LintSource ,
209
+ span : Option < MultiSpan > ,
210
+ decorate : Box < dyn for < ' b > FnOnce ( LintDiagnosticBuilder < ' b > ) + ' d > ) {
211
+ let mut err = match ( level, span) {
212
+ ( Level :: Allow , _) => {
213
+ return ;
214
+ }
215
+ ( Level :: Warn , Some ( span) ) => sess. struct_span_warn ( span, "" ) ,
216
+ ( Level :: Warn , None ) => sess. struct_warn ( "" ) ,
217
+ ( Level :: Deny , Some ( span) ) | ( Level :: Forbid , Some ( span) ) => sess. struct_span_err ( span, "" ) ,
218
+ ( Level :: Deny , None ) | ( Level :: Forbid , None ) => sess. struct_err ( "" ) ,
219
+ } ;
210
220
211
- // Check for future incompatibility lints and issue a stronger warning.
212
- let lint_id = LintId :: of ( lint) ;
213
- let future_incompatible = lint. future_incompatible ;
214
-
215
- // If this code originates in a foreign macro, aka something that this crate
216
- // did not itself author, then it's likely that there's nothing this crate
217
- // can do about it. We probably want to skip the lint entirely.
218
- if err. span . primary_spans ( ) . iter ( ) . any ( |s| in_external_macro ( sess, * s) ) {
219
- // Any suggestions made here are likely to be incorrect, so anything we
220
- // emit shouldn't be automatically fixed by rustfix.
221
- err. allow_suggestions ( false ) ;
222
-
223
- // If this is a future incompatible lint it'll become a hard error, so
224
- // we have to emit *something*. Also allow lints to whitelist themselves
225
- // on a case-by-case basis for emission in a foreign macro.
226
- if future_incompatible. is_none ( ) && !lint. report_in_external_macro {
227
- err. cancel ( ) ;
228
- // Don't continue further, since we don't want to have
229
- // `diag_span_note_once` called for a diagnostic that isn't emitted.
230
- return ;
221
+ // Check for future incompatibility lints and issue a stronger warning.
222
+ let lint_id = LintId :: of ( lint) ;
223
+ let future_incompatible = lint. future_incompatible ;
224
+
225
+ // If this code originates in a foreign macro, aka something that this crate
226
+ // did not itself author, then it's likely that there's nothing this crate
227
+ // can do about it. We probably want to skip the lint entirely.
228
+ if err. span . primary_spans ( ) . iter ( ) . any ( |s| in_external_macro ( sess, * s) ) {
229
+ // Any suggestions made here are likely to be incorrect, so anything we
230
+ // emit shouldn't be automatically fixed by rustfix.
231
+ err. allow_suggestions ( false ) ;
232
+
233
+ // If this is a future incompatible lint it'll become a hard error, so
234
+ // we have to emit *something*. Also allow lints to whitelist themselves
235
+ // on a case-by-case basis for emission in a foreign macro.
236
+ if future_incompatible. is_none ( ) && !lint. report_in_external_macro {
237
+ err. cancel ( ) ;
238
+ // Don't continue further, since we don't want to have
239
+ // `diag_span_note_once` called for a diagnostic that isn't emitted.
240
+ return ;
241
+ }
231
242
}
232
- }
233
243
234
- let name = lint. name_lower ( ) ;
235
- match src {
236
- LintSource :: Default => {
237
- sess. diag_note_once (
238
- & mut err,
239
- DiagnosticMessageId :: from ( lint) ,
240
- & format ! ( "`#[{}({})]` on by default" , level. as_str( ) , name) ,
241
- ) ;
242
- }
243
- LintSource :: CommandLine ( lint_flag_val) => {
244
- let flag = match level {
245
- Level :: Warn => "-W" ,
246
- Level :: Deny => "-D" ,
247
- Level :: Forbid => "-F" ,
248
- Level :: Allow => panic ! ( ) ,
249
- } ;
250
- let hyphen_case_lint_name = name. replace ( "_" , "-" ) ;
251
- if lint_flag_val. as_str ( ) == name {
244
+ let name = lint. name_lower ( ) ;
245
+ match src {
246
+ LintSource :: Default => {
252
247
sess. diag_note_once (
253
248
& mut err,
254
249
DiagnosticMessageId :: from ( lint) ,
255
- & format ! (
256
- "requested on the command line with `{} {}`" ,
257
- flag, hyphen_case_lint_name
258
- ) ,
259
- ) ;
260
- } else {
261
- let hyphen_case_flag_val = lint_flag_val. as_str ( ) . replace ( "_" , "-" ) ;
262
- sess. diag_note_once (
263
- & mut err,
264
- DiagnosticMessageId :: from ( lint) ,
265
- & format ! (
266
- "`{} {}` implied by `{} {}`" ,
267
- flag, hyphen_case_lint_name, flag, hyphen_case_flag_val
268
- ) ,
250
+ & format ! ( "`#[{}({})]` on by default" , level. as_str( ) , name) ,
269
251
) ;
270
252
}
271
- }
272
- LintSource :: Node ( lint_attr_name, src, reason) => {
273
- if let Some ( rationale) = reason {
274
- err. note ( & rationale. as_str ( ) ) ;
253
+ LintSource :: CommandLine ( lint_flag_val) => {
254
+ let flag = match level {
255
+ Level :: Warn => "-W" ,
256
+ Level :: Deny => "-D" ,
257
+ Level :: Forbid => "-F" ,
258
+ Level :: Allow => panic ! ( ) ,
259
+ } ;
260
+ let hyphen_case_lint_name = name. replace ( "_" , "-" ) ;
261
+ if lint_flag_val. as_str ( ) == name {
262
+ sess. diag_note_once (
263
+ & mut err,
264
+ DiagnosticMessageId :: from ( lint) ,
265
+ & format ! (
266
+ "requested on the command line with `{} {}`" ,
267
+ flag, hyphen_case_lint_name
268
+ ) ,
269
+ ) ;
270
+ } else {
271
+ let hyphen_case_flag_val = lint_flag_val. as_str ( ) . replace ( "_" , "-" ) ;
272
+ sess. diag_note_once (
273
+ & mut err,
274
+ DiagnosticMessageId :: from ( lint) ,
275
+ & format ! (
276
+ "`{} {}` implied by `{} {}`" ,
277
+ flag, hyphen_case_lint_name, flag, hyphen_case_flag_val
278
+ ) ,
279
+ ) ;
280
+ }
275
281
}
276
- sess. diag_span_note_once (
277
- & mut err,
278
- DiagnosticMessageId :: from ( lint) ,
279
- src,
280
- "the lint level is defined here" ,
281
- ) ;
282
- if lint_attr_name. as_str ( ) != name {
283
- let level_str = level. as_str ( ) ;
284
- sess. diag_note_once (
282
+ LintSource :: Node ( lint_attr_name, src, reason) => {
283
+ if let Some ( rationale) = reason {
284
+ err. note ( & rationale. as_str ( ) ) ;
285
+ }
286
+ sess. diag_span_note_once (
285
287
& mut err,
286
288
DiagnosticMessageId :: from ( lint) ,
287
- & format ! (
288
- "`#[{}({})]` implied by `#[{}({})]`" ,
289
- level_str, name, level_str, lint_attr_name
290
- ) ,
289
+ src,
290
+ "the lint level is defined here" ,
291
291
) ;
292
+ if lint_attr_name. as_str ( ) != name {
293
+ let level_str = level. as_str ( ) ;
294
+ sess. diag_note_once (
295
+ & mut err,
296
+ DiagnosticMessageId :: from ( lint) ,
297
+ & format ! (
298
+ "`#[{}({})]` implied by `#[{}({})]`" ,
299
+ level_str, name, level_str, lint_attr_name
300
+ ) ,
301
+ ) ;
302
+ }
292
303
}
293
304
}
294
- }
295
305
296
- err. code ( DiagnosticId :: Lint ( name) ) ;
297
-
298
- if let Some ( future_incompatible) = future_incompatible {
299
- const STANDARD_MESSAGE : & str = "this was previously accepted by the compiler but is being phased out; \
300
- it will become a hard error";
301
-
302
- let explanation = if lint_id == LintId :: of ( builtin:: UNSTABLE_NAME_COLLISIONS ) {
303
- "once this method is added to the standard library, \
304
- the ambiguity may cause an error or change in behavior!"
305
- . to_owned ( )
306
- } else if lint_id == LintId :: of ( builtin:: MUTABLE_BORROW_RESERVATION_CONFLICT ) {
307
- "this borrowing pattern was not meant to be accepted, \
308
- and may become a hard error in the future"
309
- . to_owned ( )
310
- } else if let Some ( edition) = future_incompatible. edition {
311
- format ! ( "{} in the {} edition!" , STANDARD_MESSAGE , edition)
312
- } else {
313
- format ! ( "{} in a future release!" , STANDARD_MESSAGE )
314
- } ;
315
- let citation = format ! ( "for more information, see {}" , future_incompatible. reference) ;
316
- err. warn ( & explanation) ;
317
- err. note ( & citation) ;
318
- }
306
+ err. code ( DiagnosticId :: Lint ( name) ) ;
307
+
308
+ if let Some ( future_incompatible) = future_incompatible {
309
+ const STANDARD_MESSAGE : & str = "this was previously accepted by the compiler but is being phased out; \
310
+ it will become a hard error";
311
+
312
+ let explanation = if lint_id == LintId :: of ( builtin:: UNSTABLE_NAME_COLLISIONS ) {
313
+ "once this method is added to the standard library, \
314
+ the ambiguity may cause an error or change in behavior!"
315
+ . to_owned ( )
316
+ } else if lint_id == LintId :: of ( builtin:: MUTABLE_BORROW_RESERVATION_CONFLICT ) {
317
+ "this borrowing pattern was not meant to be accepted, \
318
+ and may become a hard error in the future"
319
+ . to_owned ( )
320
+ } else if let Some ( edition) = future_incompatible. edition {
321
+ format ! ( "{} in the {} edition!" , STANDARD_MESSAGE , edition)
322
+ } else {
323
+ format ! ( "{} in a future release!" , STANDARD_MESSAGE )
324
+ } ;
325
+ let citation = format ! ( "for more information, see {}" , future_incompatible. reference) ;
326
+ err. warn ( & explanation) ;
327
+ err. note ( & citation) ;
328
+ }
319
329
320
- // Finally, run `decorate`. This function is also responsible for emitting the diagnostic.
321
- decorate ( LintDiagnosticBuilder :: new ( err) ) ;
330
+ // Finally, run `decorate`. This function is also responsible for emitting the diagnostic.
331
+ decorate ( LintDiagnosticBuilder :: new ( err) ) ;
332
+ }
333
+ struct_lint_level_impl ( sess, lint, level, src, span, Box :: new ( decorate) )
322
334
}
323
335
324
336
/// Returns whether `span` originates in a foreign crate's external macro.
0 commit comments