@@ -199,8 +199,7 @@ impl<'a> LintLevelsBuilder<'a> {
199199 let store = self . sess . lint_store . borrow ( ) ;
200200 let sess = self . sess ;
201201 let bad_attr = |span| {
202- span_err ! ( sess, span, E0452 ,
203- "malformed lint attribute" ) ;
202+ struct_span_err ! ( sess, span, E0452 , "malformed lint attribute" )
204203 } ;
205204 for attr in attrs {
206205 let level = match Level :: from_str ( & attr. name ( ) . as_str ( ) ) {
@@ -214,17 +213,45 @@ impl<'a> LintLevelsBuilder<'a> {
214213 let metas = if let Some ( metas) = meta. meta_item_list ( ) {
215214 metas
216215 } else {
217- bad_attr ( meta. span ) ;
216+ let mut err = bad_attr ( meta. span ) ;
217+ err. emit ( ) ;
218218 continue
219219 } ;
220220
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+
221251 for li in metas {
222252 let word = match li. word ( ) {
223253 Some ( word) => word,
224- None => {
225- bad_attr ( li. span ) ;
226- continue
227- }
254+ None => { continue ; }
228255 } ;
229256 let tool_name = if let Some ( lint_tool) = word. is_scoped ( ) {
230257 if !attr:: is_known_lint_tool ( lint_tool) {
@@ -245,7 +272,7 @@ impl<'a> LintLevelsBuilder<'a> {
245272 let name = word. name ( ) ;
246273 match store. check_lint_name ( & name. as_str ( ) , tool_name) {
247274 CheckLintNameResult :: Ok ( ids) => {
248- let src = LintSource :: Node ( name, li. span ) ;
275+ let src = LintSource :: Node ( name, li. span , reason ) ;
249276 for id in ids {
250277 specs. insert ( * id, ( level, src) ) ;
251278 }
@@ -255,7 +282,9 @@ impl<'a> LintLevelsBuilder<'a> {
255282 match result {
256283 Ok ( ids) => {
257284 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+ ) ;
259288 for id in ids {
260289 specs. insert ( * id, ( level, src) ) ;
261290 }
@@ -286,7 +315,9 @@ impl<'a> LintLevelsBuilder<'a> {
286315 Applicability :: MachineApplicable ,
287316 ) . emit ( ) ;
288317
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+ ) ;
290321 for id in ids {
291322 specs. insert ( * id, ( level, src) ) ;
292323 }
@@ -368,11 +399,11 @@ impl<'a> LintLevelsBuilder<'a> {
368399 } ;
369400 let forbidden_lint_name = match forbid_src {
370401 LintSource :: Default => id. to_string ( ) ,
371- LintSource :: Node ( name, _) => name. to_string ( ) ,
402+ LintSource :: Node ( name, _, _ ) => name. to_string ( ) ,
372403 LintSource :: CommandLine ( name) => name. to_string ( ) ,
373404 } ;
374405 let ( lint_attr_name, lint_attr_span) = match * src {
375- LintSource :: Node ( name, span) => ( name, span) ,
406+ LintSource :: Node ( name, span, _ ) => ( name, span) ,
376407 _ => continue ,
377408 } ;
378409 let mut diag_builder = struct_span_err ! ( self . sess,
@@ -384,15 +415,19 @@ impl<'a> LintLevelsBuilder<'a> {
384415 forbidden_lint_name) ;
385416 diag_builder. span_label ( lint_attr_span, "overruled by previous forbid" ) ;
386417 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 ) => {
389420 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+ }
391425 } ,
392426 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" ) ;
394428 }
395- } . emit ( ) ;
429+ }
430+ diag_builder. emit ( ) ;
396431 // don't set a separate error for every lint in the group
397432 break
398433 }
0 commit comments