@@ -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- it will become a hard error";
283-
284- let explanation = if lint_id == LintId :: of ( builtin:: UNSTABLE_NAME_COLLISIONS ) {
285- "once this method is added to the standard library, \
286- the ambiguity may cause an error or change in behavior!"
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- and may become a hard error in the future"
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