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