@@ -191,134 +191,146 @@ impl<'a> LintDiagnosticBuilder<'a> {
191191 }
192192}
193193
194- pub fn struct_lint_level < ' s > (
194+ pub fn struct_lint_level < ' s , ' d > (
195195 sess : & ' s Session ,
196196 lint : & ' static Lint ,
197197 level : Level ,
198198 src : LintSource ,
199199 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+ } ;
210220
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+ }
231242 }
232- }
233243
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 => {
252247 sess. diag_note_once (
253248 & mut err,
254249 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) ,
269251 ) ;
270252 }
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+ }
275281 }
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 (
285287 & mut err,
286288 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" ,
291291 ) ;
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+ }
292303 }
293304 }
294- }
295305
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+ }
319329
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) )
322334}
323335
324336/// Returns whether `span` originates in a foreign crate's external macro.
0 commit comments