@@ -72,7 +72,7 @@ use syntax::parse::token;
72
72
use syntax:: visit:: Visitor ;
73
73
use syntax:: { ast, ast_util, visit} ;
74
74
75
- #[ deriving( Clone , Eq , Ord , TotalEq , TotalOrd ) ]
75
+ #[ deriving( Clone , Show , Eq , Ord , TotalEq , TotalOrd ) ]
76
76
pub enum Lint {
77
77
CTypes ,
78
78
UnusedImports ,
@@ -93,6 +93,7 @@ pub enum Lint {
93
93
UnknownFeatures ,
94
94
UnknownCrateType ,
95
95
UnsignedNegate ,
96
+ VariantSizeDifference ,
96
97
97
98
ManagedHeapMemory ,
98
99
OwnedHeapMemory ,
@@ -146,8 +147,9 @@ pub struct LintSpec {
146
147
147
148
pub type LintDict = HashMap < & ' static str , LintSpec > ;
148
149
150
+ // this is public for the lints that run in trans
149
151
#[ deriving( Eq ) ]
150
- enum LintSource {
152
+ pub enum LintSource {
151
153
Node ( Span ) ,
152
154
Default ,
153
155
CommandLine
@@ -399,6 +401,13 @@ static lint_table: &'static [(&'static str, LintSpec)] = &[
399
401
default : Warn
400
402
} ) ,
401
403
404
+ ( "variant_size_difference" ,
405
+ LintSpec {
406
+ lint : VariantSizeDifference ,
407
+ desc : "detects enums with widely varying variant sizes" ,
408
+ default : Allow ,
409
+ } ) ,
410
+
402
411
( "unused_must_use" ,
403
412
LintSpec {
404
413
lint : UnusedMustUse ,
@@ -461,6 +470,54 @@ struct Context<'a> {
461
470
462
471
/// Ids of structs/enums which have been checked for raw_pointer_deriving
463
472
checked_raw_pointers : NodeSet ,
473
+
474
+ /// Level of EnumSizeVariance lint for each enum, stored here because the
475
+ /// body of the lint needs to run in trans.
476
+ enum_levels : HashMap < ast:: NodeId , ( Level , LintSource ) > ,
477
+ }
478
+
479
+ pub fn emit_lint ( level : Level , src : LintSource , msg : & str , span : Span ,
480
+ lint_str : & str , tcx : & ty:: ctxt ) {
481
+ if level == Allow { return }
482
+
483
+ let mut note = None ;
484
+ let msg = match src {
485
+ Default => {
486
+ format ! ( "{}, \\ #[{}({})] on by default" , msg,
487
+ level_to_str( level) , lint_str)
488
+ } ,
489
+ CommandLine => {
490
+ format ! ( "{} [-{} {}]" , msg,
491
+ match level {
492
+ Warn => 'W' , Deny => 'D' , Forbid => 'F' ,
493
+ Allow => fail!( )
494
+ } , lint_str. replace( "_" , "-" ) )
495
+ } ,
496
+ Node ( src) => {
497
+ note = Some ( src) ;
498
+ msg. to_str ( )
499
+ }
500
+ } ;
501
+
502
+ match level {
503
+ Warn => { tcx. sess . span_warn ( span, msg. as_slice ( ) ) ; }
504
+ Deny | Forbid => { tcx. sess . span_err ( span, msg. as_slice ( ) ) ; }
505
+ Allow => fail ! ( ) ,
506
+ }
507
+
508
+ for & span in note. iter ( ) {
509
+ tcx. sess . span_note ( span, "lint level defined here" ) ;
510
+ }
511
+ }
512
+
513
+ pub fn lint_to_str ( lint : Lint ) -> & ' static str {
514
+ for & ( name, lspec) in lint_table. iter ( ) {
515
+ if lspec. lint == lint {
516
+ return name;
517
+ }
518
+ }
519
+
520
+ fail ! ( "unrecognized lint: {}" , lint) ;
464
521
}
465
522
466
523
impl < ' a > Context < ' a > {
@@ -492,7 +549,7 @@ impl<'a> Context<'a> {
492
549
return * k;
493
550
}
494
551
}
495
- fail ! ( "unregistered lint {:? }" , lint) ;
552
+ fail ! ( "unregistered lint {}" , lint) ;
496
553
}
497
554
498
555
fn span_lint ( & self , lint : Lint , span : Span , msg : & str ) {
@@ -501,37 +558,8 @@ impl<'a> Context<'a> {
501
558
Some ( & ( Warn , src) ) => ( self . get_level ( Warnings ) , src) ,
502
559
Some ( & pair) => pair,
503
560
} ;
504
- if level == Allow { return }
505
-
506
- let mut note = None ;
507
- let msg = match src {
508
- Default => {
509
- format_strbuf ! ( "{}, \\ #[{}({})] on by default" ,
510
- msg,
511
- level_to_str( level) ,
512
- self . lint_to_str( lint) )
513
- } ,
514
- CommandLine => {
515
- format ! ( "{} [-{} {}]" , msg,
516
- match level {
517
- Warn => 'W' , Deny => 'D' , Forbid => 'F' ,
518
- Allow => fail!( )
519
- } , self . lint_to_str( lint) . replace( "_" , "-" ) )
520
- } ,
521
- Node ( src) => {
522
- note = Some ( src) ;
523
- msg. to_str ( )
524
- }
525
- } ;
526
- match level {
527
- Warn => self . tcx . sess . span_warn ( span, msg. as_slice ( ) ) ,
528
- Deny | Forbid => self . tcx . sess . span_err ( span, msg. as_slice ( ) ) ,
529
- Allow => fail ! ( ) ,
530
- }
531
561
532
- for & span in note. iter ( ) {
533
- self . tcx . sess . span_note ( span, "lint level defined here" ) ;
534
- }
562
+ emit_lint ( level, src, msg, span, self . lint_to_str ( lint) , self . tcx ) ;
535
563
}
536
564
537
565
/**
@@ -1685,9 +1713,24 @@ fn check_stability(cx: &Context, e: &ast::Expr) {
1685
1713
cx. span_lint ( lint, e. span , msg. as_slice ( ) ) ;
1686
1714
}
1687
1715
1716
+ fn check_enum_variant_sizes ( cx : & mut Context , it : & ast:: Item ) {
1717
+ match it. node {
1718
+ ast:: ItemEnum ( ..) => {
1719
+ match cx. cur . find ( & ( VariantSizeDifference as uint ) ) {
1720
+ Some ( & ( lvl, src) ) if lvl != Allow => {
1721
+ cx. node_levels . insert ( ( it. id , VariantSizeDifference ) , ( lvl, src) ) ;
1722
+ } ,
1723
+ _ => { }
1724
+ }
1725
+ } ,
1726
+ _ => { }
1727
+ }
1728
+ }
1729
+
1688
1730
impl < ' a > Visitor < ( ) > for Context < ' a > {
1689
1731
fn visit_item ( & mut self , it : & ast:: Item , _: ( ) ) {
1690
1732
self . with_lint_attrs ( it. attrs . as_slice ( ) , |cx| {
1733
+ check_enum_variant_sizes ( cx, it) ;
1691
1734
check_item_ctypes ( cx, it) ;
1692
1735
check_item_non_camel_case_types ( cx, it) ;
1693
1736
check_item_non_uppercase_statics ( cx, it) ;
@@ -1878,6 +1921,7 @@ pub fn check_crate(tcx: &ty::ctxt,
1878
1921
lint_stack : Vec :: new ( ) ,
1879
1922
negated_expr_id : -1 ,
1880
1923
checked_raw_pointers : NodeSet :: new ( ) ,
1924
+ enum_levels : HashMap :: new ( ) ,
1881
1925
} ;
1882
1926
1883
1927
// Install default lint levels, followed by the command line levels, and
@@ -1913,13 +1957,11 @@ pub fn check_crate(tcx: &ty::ctxt,
1913
1957
// in the iteration code.
1914
1958
for ( id, v) in tcx. sess . lints . borrow ( ) . iter ( ) {
1915
1959
for & ( lint, span, ref msg) in v. iter ( ) {
1916
- tcx. sess . span_bug ( span,
1917
- format ! ( "unprocessed lint {:?} at {}: {}" ,
1918
- lint,
1919
- tcx. map. node_to_str( * id) ,
1920
- * msg) . as_slice ( ) )
1960
+ tcx. sess . span_bug ( span, format ! ( "unprocessed lint {} at {}: {}" ,
1961
+ lint, tcx. map. node_to_str( * id) , * msg) . as_slice ( ) )
1921
1962
}
1922
1963
}
1923
1964
1924
1965
tcx. sess . abort_if_errors ( ) ;
1966
+ * tcx. enum_lint_levels . borrow_mut ( ) = cx. enum_levels ;
1925
1967
}
0 commit comments