@@ -72,7 +72,7 @@ use syntax::parse::token;
7272use syntax:: visit:: Visitor ;
7373use syntax:: { ast, ast_util, visit} ;
7474
75- #[ deriving( Clone , Eq , Ord , TotalEq , TotalOrd ) ]
75+ #[ deriving( Clone , Show , Eq , Ord , TotalEq , TotalOrd , Hash ) ]
7676pub enum Lint {
7777 CTypes ,
7878 UnusedImports ,
@@ -94,6 +94,7 @@ pub enum Lint {
9494 UnknownFeatures ,
9595 UnknownCrateType ,
9696 UnsignedNegate ,
97+ VariantSizeDifference ,
9798
9899 ManagedHeapMemory ,
99100 OwnedHeapMemory ,
@@ -147,8 +148,9 @@ pub struct LintSpec {
147148
148149pub type LintDict = HashMap < & ' static str , LintSpec > ;
149150
151+ // this is public for the lints that run in trans
150152#[ deriving( Eq ) ]
151- enum LintSource {
153+ pub enum LintSource {
152154 Node ( Span ) ,
153155 Default ,
154156 CommandLine
@@ -407,6 +409,13 @@ static lint_table: &'static [(&'static str, LintSpec)] = &[
407409 default : Warn
408410 } ) ,
409411
412+ ( "variant_size_difference" ,
413+ LintSpec {
414+ lint : VariantSizeDifference ,
415+ desc : "detects enums with widely varying variant sizes" ,
416+ default : Allow ,
417+ } ) ,
418+
410419 ( "unused_must_use" ,
411420 LintSpec {
412421 lint : UnusedMustUse ,
@@ -445,30 +454,78 @@ pub fn get_lint_dict() -> LintDict {
445454}
446455
447456struct Context < ' a > {
448- // All known lint modes (string versions)
457+ /// All known lint modes (string versions)
449458 dict : LintDict ,
450- // Current levels of each lint warning
459+ /// Current levels of each lint warning
451460 cur : SmallIntMap < ( Level , LintSource ) > ,
452- // context we're checking in (used to access fields like sess)
461+ /// Context we're checking in (used to access fields like sess)
453462 tcx : & ' a ty:: ctxt ,
454- // Items exported by the crate; used by the missing_doc lint.
463+ /// Items exported by the crate; used by the missing_doc lint.
455464 exported_items : & ' a privacy:: ExportedItems ,
456- // The id of the current `ast::StructDef` being walked.
465+ /// The id of the current `ast::StructDef` being walked.
457466 cur_struct_def_id : ast:: NodeId ,
458- // Whether some ancestor of the current node was marked
459- // #[doc(hidden)].
467+ /// Whether some ancestor of the current node was marked
468+ /// #[doc(hidden)].
460469 is_doc_hidden : bool ,
461470
462- // When recursing into an attributed node of the ast which modifies lint
463- // levels, this stack keeps track of the previous lint levels of whatever
464- // was modified.
471+ /// When recursing into an attributed node of the ast which modifies lint
472+ /// levels, this stack keeps track of the previous lint levels of whatever
473+ /// was modified.
465474 lint_stack : Vec < ( Lint , Level , LintSource ) > ,
466475
467- // id of the last visited negated expression
476+ /// Id of the last visited negated expression
468477 negated_expr_id : ast:: NodeId ,
469478
470- // ids of structs/enums which have been checked for raw_pointer_deriving
479+ /// Ids of structs/enums which have been checked for raw_pointer_deriving
471480 checked_raw_pointers : NodeSet ,
481+
482+ /// Level of lints for certain NodeIds, stored here because the body of
483+ /// the lint needs to run in trans.
484+ node_levels : HashMap < ( ast:: NodeId , Lint ) , ( Level , LintSource ) > ,
485+ }
486+
487+ pub fn emit_lint ( level : Level , src : LintSource , msg : & str , span : Span ,
488+ lint_str : & str , tcx : & ty:: ctxt ) {
489+ if level == Allow { return }
490+
491+ let mut note = None ;
492+ let msg = match src {
493+ Default => {
494+ format ! ( "{}, \\ #[{}({})] on by default" , msg,
495+ level_to_str( level) , lint_str)
496+ } ,
497+ CommandLine => {
498+ format ! ( "{} [-{} {}]" , msg,
499+ match level {
500+ Warn => 'W' , Deny => 'D' , Forbid => 'F' ,
501+ Allow => fail!( )
502+ } , lint_str. replace( "_" , "-" ) )
503+ } ,
504+ Node ( src) => {
505+ note = Some ( src) ;
506+ msg. to_str ( )
507+ }
508+ } ;
509+
510+ match level {
511+ Warn => { tcx. sess . span_warn ( span, msg. as_slice ( ) ) ; }
512+ Deny | Forbid => { tcx. sess . span_err ( span, msg. as_slice ( ) ) ; }
513+ Allow => fail ! ( ) ,
514+ }
515+
516+ for & span in note. iter ( ) {
517+ tcx. sess . span_note ( span, "lint level defined here" ) ;
518+ }
519+ }
520+
521+ pub fn lint_to_str ( lint : Lint ) -> & ' static str {
522+ for & ( name, lspec) in lint_table. iter ( ) {
523+ if lspec. lint == lint {
524+ return name;
525+ }
526+ }
527+
528+ fail ! ( "unrecognized lint: {}" , lint) ;
472529}
473530
474531impl < ' a > Context < ' a > {
@@ -500,7 +557,7 @@ impl<'a> Context<'a> {
500557 return * k;
501558 }
502559 }
503- fail ! ( "unregistered lint {:? }" , lint) ;
560+ fail ! ( "unregistered lint {}" , lint) ;
504561 }
505562
506563 fn span_lint ( & self , lint : Lint , span : Span , msg : & str ) {
@@ -509,37 +566,8 @@ impl<'a> Context<'a> {
509566 Some ( & ( Warn , src) ) => ( self . get_level ( Warnings ) , src) ,
510567 Some ( & pair) => pair,
511568 } ;
512- if level == Allow { return }
513-
514- let mut note = None ;
515- let msg = match src {
516- Default => {
517- format_strbuf ! ( "{}, \\ #[{}({})] on by default" ,
518- msg,
519- level_to_str( level) ,
520- self . lint_to_str( lint) )
521- } ,
522- CommandLine => {
523- format ! ( "{} [-{} {}]" , msg,
524- match level {
525- Warn => 'W' , Deny => 'D' , Forbid => 'F' ,
526- Allow => fail!( )
527- } , self . lint_to_str( lint) . replace( "_" , "-" ) )
528- } ,
529- Node ( src) => {
530- note = Some ( src) ;
531- msg. to_str ( )
532- }
533- } ;
534- match level {
535- Warn => self . tcx . sess . span_warn ( span, msg. as_slice ( ) ) ,
536- Deny | Forbid => self . tcx . sess . span_err ( span, msg. as_slice ( ) ) ,
537- Allow => fail ! ( ) ,
538- }
539569
540- for & span in note. iter ( ) {
541- self . tcx . sess . span_note ( span, "lint level defined here" ) ;
542- }
570+ emit_lint ( level, src, msg, span, self . lint_to_str ( lint) , self . tcx ) ;
543571 }
544572
545573 /**
@@ -618,8 +646,8 @@ impl<'a> Context<'a> {
618646 }
619647}
620648
621- // Check that every lint from the list of attributes satisfies `f`.
622- // Return true if that's the case. Otherwise return false.
649+ /// Check that every lint from the list of attributes satisfies `f`.
650+ /// Return true if that's the case. Otherwise return false.
623651pub fn each_lint ( sess : & session:: Session ,
624652 attrs : & [ ast:: Attribute ] ,
625653 f : |@ast:: MetaItem , Level , InternedString | -> bool)
@@ -653,8 +681,8 @@ pub fn each_lint(sess: &session::Session,
653681 true
654682}
655683
656- // Check from a list of attributes if it contains the appropriate
657- // `#[level(lintname)]` attribute (e.g. `#[allow(dead_code)]).
684+ /// Check from a list of attributes if it contains the appropriate
685+ /// `#[level(lintname)]` attribute (e.g. `#[allow(dead_code)]).
658686pub fn contains_lint ( attrs : & [ ast:: Attribute ] ,
659687 level : Level ,
660688 lintname : & ' static str )
@@ -1739,9 +1767,24 @@ fn check_stability(cx: &Context, e: &ast::Expr) {
17391767 cx. span_lint ( lint, e. span , msg. as_slice ( ) ) ;
17401768}
17411769
1770+ fn check_enum_variant_sizes ( cx : & mut Context , it : & ast:: Item ) {
1771+ match it. node {
1772+ ast:: ItemEnum ( ..) => {
1773+ match cx. cur . find ( & ( VariantSizeDifference as uint ) ) {
1774+ Some ( & ( lvl, src) ) if lvl != Allow => {
1775+ cx. node_levels . insert ( ( it. id , VariantSizeDifference ) , ( lvl, src) ) ;
1776+ } ,
1777+ _ => { }
1778+ }
1779+ } ,
1780+ _ => { }
1781+ }
1782+ }
1783+
17421784impl < ' a > Visitor < ( ) > for Context < ' a > {
17431785 fn visit_item ( & mut self , it : & ast:: Item , _: ( ) ) {
17441786 self . with_lint_attrs ( it. attrs . as_slice ( ) , |cx| {
1787+ check_enum_variant_sizes ( cx, it) ;
17451788 check_item_ctypes ( cx, it) ;
17461789 check_item_non_camel_case_types ( cx, it) ;
17471790 check_item_non_uppercase_statics ( cx, it) ;
@@ -1933,6 +1976,7 @@ pub fn check_crate(tcx: &ty::ctxt,
19331976 lint_stack : Vec :: new ( ) ,
19341977 negated_expr_id : -1 ,
19351978 checked_raw_pointers : NodeSet :: new ( ) ,
1979+ node_levels : HashMap :: new ( ) ,
19361980 } ;
19371981
19381982 // Install default lint levels, followed by the command line levels, and
@@ -1969,13 +2013,11 @@ pub fn check_crate(tcx: &ty::ctxt,
19692013 // in the iteration code.
19702014 for ( id, v) in tcx. sess . lints . borrow ( ) . iter ( ) {
19712015 for & ( lint, span, ref msg) in v. iter ( ) {
1972- tcx. sess . span_bug ( span,
1973- format ! ( "unprocessed lint {:?} at {}: {}" ,
1974- lint,
1975- tcx. map. node_to_str( * id) ,
1976- * msg) . as_slice ( ) )
2016+ tcx. sess . span_bug ( span, format ! ( "unprocessed lint {} at {}: {}" ,
2017+ lint, tcx. map. node_to_str( * id) , * msg) . as_slice ( ) )
19772018 }
19782019 }
19792020
19802021 tcx. sess . abort_if_errors ( ) ;
2022+ * tcx. node_lint_levels . borrow_mut ( ) = cx. node_levels ;
19812023}
0 commit comments