@@ -199,8 +199,7 @@ impl<'a> LintLevelsBuilder<'a> {
199
199
let store = self . sess . lint_store . borrow ( ) ;
200
200
let sess = self . sess ;
201
201
let bad_attr = |span| {
202
- span_err ! ( sess, span, E0452 ,
203
- "malformed lint attribute" ) ;
202
+ struct_span_err ! ( sess, span, E0452 , "malformed lint attribute" )
204
203
} ;
205
204
for attr in attrs {
206
205
let level = match Level :: from_str ( & attr. name ( ) . as_str ( ) ) {
@@ -214,17 +213,45 @@ impl<'a> LintLevelsBuilder<'a> {
214
213
let metas = if let Some ( metas) = meta. meta_item_list ( ) {
215
214
metas
216
215
} else {
217
- bad_attr ( meta. span ) ;
216
+ let mut err = bad_attr ( meta. span ) ;
217
+ err. emit ( ) ;
218
218
continue
219
219
} ;
220
220
221
+ // Before processing the lint names, look for a reason (RFC 2383).
222
+ let mut reason = None ;
223
+ for li in metas {
224
+ if let Some ( item) = li. meta_item ( ) {
225
+ match item. node {
226
+ ast:: MetaItemKind :: Word => { } // actual lint names handled later
227
+ ast:: MetaItemKind :: NameValue ( ref name_value) => {
228
+ let name_ident = item. ident . segments [ 0 ] . ident ;
229
+ let name = name_ident. name . as_str ( ) ;
230
+ if name == "reason" {
231
+ if let ast:: LitKind :: Str ( rationale, _) = name_value. node {
232
+ reason = Some ( rationale) ;
233
+ } else {
234
+ let mut err = bad_attr ( name_value. span ) ;
235
+ err. help ( "reason must be a string literal" ) ;
236
+ err. emit ( ) ;
237
+ }
238
+ } else {
239
+ let mut err = bad_attr ( item. span ) ;
240
+ err. emit ( ) ;
241
+ }
242
+ } ,
243
+ ast:: MetaItemKind :: List ( _) => {
244
+ let mut err = bad_attr ( item. span ) ;
245
+ err. emit ( ) ;
246
+ }
247
+ }
248
+ }
249
+ }
250
+
221
251
for li in metas {
222
252
let word = match li. word ( ) {
223
253
Some ( word) => word,
224
- None => {
225
- bad_attr ( li. span ) ;
226
- continue
227
- }
254
+ None => { continue ; }
228
255
} ;
229
256
let tool_name = if let Some ( lint_tool) = word. is_scoped ( ) {
230
257
if !attr:: is_known_lint_tool ( lint_tool) {
@@ -245,7 +272,7 @@ impl<'a> LintLevelsBuilder<'a> {
245
272
let name = word. name ( ) ;
246
273
match store. check_lint_name ( & name. as_str ( ) , tool_name) {
247
274
CheckLintNameResult :: Ok ( ids) => {
248
- let src = LintSource :: Node ( name, li. span ) ;
275
+ let src = LintSource :: Node ( name, li. span , reason ) ;
249
276
for id in ids {
250
277
specs. insert ( * id, ( level, src) ) ;
251
278
}
@@ -255,7 +282,9 @@ impl<'a> LintLevelsBuilder<'a> {
255
282
match result {
256
283
Ok ( ids) => {
257
284
let complete_name = & format ! ( "{}::{}" , tool_name. unwrap( ) , name) ;
258
- let src = LintSource :: Node ( Symbol :: intern ( complete_name) , li. span ) ;
285
+ let src = LintSource :: Node (
286
+ Symbol :: intern ( complete_name) , li. span , reason
287
+ ) ;
259
288
for id in ids {
260
289
specs. insert ( * id, ( level, src) ) ;
261
290
}
@@ -286,7 +315,9 @@ impl<'a> LintLevelsBuilder<'a> {
286
315
Applicability :: MachineApplicable ,
287
316
) . emit ( ) ;
288
317
289
- let src = LintSource :: Node ( Symbol :: intern ( & new_lint_name) , li. span ) ;
318
+ let src = LintSource :: Node (
319
+ Symbol :: intern ( & new_lint_name) , li. span , reason
320
+ ) ;
290
321
for id in ids {
291
322
specs. insert ( * id, ( level, src) ) ;
292
323
}
@@ -368,11 +399,11 @@ impl<'a> LintLevelsBuilder<'a> {
368
399
} ;
369
400
let forbidden_lint_name = match forbid_src {
370
401
LintSource :: Default => id. to_string ( ) ,
371
- LintSource :: Node ( name, _) => name. to_string ( ) ,
402
+ LintSource :: Node ( name, _, _ ) => name. to_string ( ) ,
372
403
LintSource :: CommandLine ( name) => name. to_string ( ) ,
373
404
} ;
374
405
let ( lint_attr_name, lint_attr_span) = match * src {
375
- LintSource :: Node ( name, span) => ( name, span) ,
406
+ LintSource :: Node ( name, span, _ ) => ( name, span) ,
376
407
_ => continue ,
377
408
} ;
378
409
let mut diag_builder = struct_span_err ! ( self . sess,
@@ -384,15 +415,19 @@ impl<'a> LintLevelsBuilder<'a> {
384
415
forbidden_lint_name) ;
385
416
diag_builder. span_label ( lint_attr_span, "overruled by previous forbid" ) ;
386
417
match forbid_src {
387
- LintSource :: Default => & mut diag_builder ,
388
- LintSource :: Node ( _, forbid_source_span) => {
418
+ LintSource :: Default => { } ,
419
+ LintSource :: Node ( _, forbid_source_span, reason ) => {
389
420
diag_builder. span_label ( forbid_source_span,
390
- "`forbid` level set here" )
421
+ "`forbid` level set here" ) ;
422
+ if let Some ( rationale) = reason {
423
+ diag_builder. note ( & rationale. as_str ( ) ) ;
424
+ }
391
425
} ,
392
426
LintSource :: CommandLine ( _) => {
393
- diag_builder. note ( "`forbid` lint level was set on command line" )
427
+ diag_builder. note ( "`forbid` lint level was set on command line" ) ;
394
428
}
395
- } . emit ( ) ;
429
+ }
430
+ diag_builder. emit ( ) ;
396
431
// don't set a separate error for every lint in the group
397
432
break
398
433
}
0 commit comments