@@ -174,132 +174,164 @@ impl<'a> HashStable<StableHashingContext<'a>> for LintLevelMap {
174
174
}
175
175
}
176
176
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 ,
179
194
lint : & ' static Lint ,
180
195
level : Level ,
181
196
src : LintSource ,
182
197
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
+ } ;
192
221
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
+ }
213
243
}
214
- }
215
244
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 => {
234
248
sess. diag_note_once (
235
249
& mut err,
236
250
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) ,
251
252
) ;
252
253
}
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
+ }
257
282
}
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 (
267
288
& mut err,
268
289
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" ,
273
292
) ;
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
+ }
274
304
}
275
305
}
276
- }
277
306
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
+ }
301
330
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) )
303
335
}
304
336
305
337
/// Returns whether `span` originates in a foreign crate's external macro.
0 commit comments