@@ -40,8 +40,10 @@ use std::cmp;
4040use std:: default:: Default as StdDefault ;
4141use std:: mem;
4242use std:: fmt;
43+ use std:: ops:: Deref ;
4344use syntax:: attr;
4445use syntax:: ast;
46+ use syntax:: symbol:: Symbol ;
4547use syntax_pos:: { MultiSpan , Span } ;
4648use errors:: { self , Diagnostic , DiagnosticBuilder } ;
4749use hir;
@@ -299,8 +301,9 @@ impl LintStore {
299301 check_lint_name_cmdline ( sess, self ,
300302 & lint_name[ ..] , level) ;
301303
304+ let lint_flag_val = Symbol :: intern ( & lint_name) ;
302305 match self . find_lint ( & lint_name[ ..] , sess, None ) {
303- Ok ( lint_id) => self . set_level ( lint_id, ( level, CommandLine ) ) ,
306+ Ok ( lint_id) => self . set_level ( lint_id, ( level, CommandLine ( lint_flag_val ) ) ) ,
304307 Err ( FindLintError :: Removed ) => { }
305308 Err ( _) => {
306309 match self . lint_groups . iter ( ) . map ( |( & x, pair) | ( x, pair. 0 . clone ( ) ) )
@@ -310,7 +313,7 @@ impl LintStore {
310313 Some ( v) => {
311314 v. iter ( )
312315 . map ( |lint_id : & LintId |
313- self . set_level ( * lint_id, ( level, CommandLine ) ) )
316+ self . set_level ( * lint_id, ( level, CommandLine ( lint_flag_val ) ) ) )
314317 . collect :: < Vec < ( ) > > ( ) ;
315318 }
316319 None => {
@@ -446,42 +449,54 @@ pub fn raw_struct_lint<'a, S>(sess: &'a Session,
446449 -> DiagnosticBuilder < ' a >
447450 where S : Into < MultiSpan >
448451{
449- let ( mut level, source) = lvlsrc;
452+ let ( level, source) = lvlsrc;
450453 if level == Allow {
451454 return sess. diagnostic ( ) . struct_dummy ( ) ;
452455 }
453456
454457 let name = lint. name_lower ( ) ;
455458 let mut def = None ;
456- let msg = match source {
457- Default => {
458- format ! ( "{}, #[{}({})] on by default" , msg,
459- level. as_str( ) , name)
460- } ,
461- CommandLine => {
462- format ! ( "{} [-{} {}]" , msg,
463- match level {
464- Warn => 'W' , Deny => 'D' , Forbid => 'F' ,
465- Allow => bug!( )
466- } , name. replace( "_" , "-" ) )
467- } ,
468- Node ( src) => {
469- def = Some ( src) ;
470- msg. to_string ( )
471- }
472- } ;
473459
474- // For purposes of printing, we can treat forbid as deny.
475- if level == Forbid { level = Deny ; }
460+ // Except for possible note details, forbid behaves like deny.
461+ let effective_level = if level == Forbid { Deny } else { level } ;
476462
477- let mut err = match ( level , span) {
463+ let mut err = match ( effective_level , span) {
478464 ( Warn , Some ( sp) ) => sess. struct_span_warn ( sp, & msg[ ..] ) ,
479465 ( Warn , None ) => sess. struct_warn ( & msg[ ..] ) ,
480466 ( Deny , Some ( sp) ) => sess. struct_span_err ( sp, & msg[ ..] ) ,
481467 ( Deny , None ) => sess. struct_err ( & msg[ ..] ) ,
482468 _ => bug ! ( "impossible level in raw_emit_lint" ) ,
483469 } ;
484470
471+ match source {
472+ Default => {
473+ err. note ( & format ! ( "#[{}({})] on by default" , level. as_str( ) , name) ) ;
474+ } ,
475+ CommandLine ( lint_flag_val) => {
476+ let flag = match level {
477+ Warn => "-W" , Deny => "-D" , Forbid => "-F" ,
478+ Allow => bug ! ( "earlier conditional return should handle Allow case" )
479+ } ;
480+ let hyphen_case_lint_name = name. replace ( "_" , "-" ) ;
481+ if lint_flag_val. as_str ( ) . deref ( ) == name {
482+ err. note ( & format ! ( "requested on the command line with `{} {}`" ,
483+ flag, hyphen_case_lint_name) ) ;
484+ } else {
485+ let hyphen_case_flag_val = lint_flag_val. as_str ( ) . replace ( "_" , "-" ) ;
486+ err. note ( & format ! ( "`{} {}` implied by `{} {}`" ,
487+ flag, hyphen_case_lint_name, flag, hyphen_case_flag_val) ) ;
488+ }
489+ } ,
490+ Node ( lint_attr_name, src) => {
491+ def = Some ( src) ;
492+ if lint_attr_name. as_str ( ) . deref ( ) != name {
493+ let level_str = level. as_str ( ) ;
494+ err. note ( & format ! ( "#[{}({})] implied by #[{}({})]" ,
495+ level_str, name, level_str, lint_attr_name) ) ;
496+ }
497+ }
498+ }
499+
485500 // Check for future incompatibility lints and issue a stronger warning.
486501 if let Some ( future_incompatible) = lints. future_incompatible ( LintId :: of ( lint) ) {
487502 let explanation = format ! ( "this was previously accepted by the compiler \
@@ -649,6 +664,8 @@ pub trait LintContext<'tcx>: Sized {
649664 }
650665 } ;
651666
667+ let lint_attr_name = result. expect ( "lint attribute should be well-formed" ) . 0 ;
668+
652669 for ( lint_id, level, span) in v {
653670 let ( now, now_source) = self . lints ( ) . get_level_source ( lint_id) ;
654671 if now == Forbid && level != Forbid {
@@ -660,19 +677,19 @@ pub trait LintContext<'tcx>: Sized {
660677 diag_builder. span_label ( span, & format ! ( "overruled by previous forbid" ) ) ;
661678 match now_source {
662679 LintSource :: Default => & mut diag_builder,
663- LintSource :: Node ( forbid_source_span) => {
680+ LintSource :: Node ( _ , forbid_source_span) => {
664681 diag_builder. span_label ( forbid_source_span,
665682 & format ! ( "`forbid` level set here" ) )
666683 } ,
667- LintSource :: CommandLine => {
684+ LintSource :: CommandLine ( _ ) => {
668685 diag_builder. note ( "`forbid` lint level was set on command line" )
669686 }
670687 } . emit ( )
671688 } else if now != level {
672689 let src = self . lints ( ) . get_level_source ( lint_id) . 1 ;
673690 self . level_stack ( ) . push ( ( lint_id, ( now, src) ) ) ;
674691 pushed += 1 ;
675- self . mut_lints ( ) . set_level ( lint_id, ( level, Node ( span) ) ) ;
692+ self . mut_lints ( ) . set_level ( lint_id, ( level, Node ( lint_attr_name , span) ) ) ;
676693 }
677694 }
678695 }
0 commit comments