diff options
| author | bors <bors@rust-lang.org> | 2014-05-26 00:16:27 -0700 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2014-05-26 00:16:27 -0700 |
| commit | ba77c602707fe7adba2c631db87ba7ad7f4dc812 (patch) | |
| tree | 261f466073c7117fe27dc91dc6e55d27109f821f /src/librustc/middle/trans | |
| parent | a7ab73344dcf3bf0973317ae165f751f6bb42766 (diff) | |
| parent | d8467e23e74fba8447c4a48f75cc9fa78d66b1c3 (diff) | |
| download | rust-ba77c602707fe7adba2c631db87ba7ad7f4dc812.tar.gz rust-ba77c602707fe7adba2c631db87ba7ad7f4dc812.zip | |
auto merge of #14300 : cmr/rust/enum-size-lint, r=kballard
See commits for details.
Diffstat (limited to 'src/librustc/middle/trans')
| -rw-r--r-- | src/librustc/middle/trans/base.rs | 58 |
1 files changed, 55 insertions, 3 deletions
diff --git a/src/librustc/middle/trans/base.rs b/src/librustc/middle/trans/base.rs index 0be4396f713..def521fd49b 100644 --- a/src/librustc/middle/trans/base.rs +++ b/src/librustc/middle/trans/base.rs @@ -36,6 +36,7 @@ use lib::llvm::{ModuleRef, ValueRef, BasicBlockRef}; use lib::llvm::{llvm, Vector}; use lib; use metadata::{csearch, encoder}; +use middle::lint; use middle::astencode; use middle::lang_items::{LangItem, ExchangeMallocFnLangItem, StartFnLangItem}; use middle::weak_lang_items; @@ -57,7 +58,7 @@ use middle::trans::foreign; use middle::trans::glue; use middle::trans::inline; use middle::trans::machine; -use middle::trans::machine::{llalign_of_min, llsize_of}; +use middle::trans::machine::{llalign_of_min, llsize_of, llsize_of_real}; use middle::trans::meth; use middle::trans::monomorphize; use middle::trans::tvec; @@ -1489,7 +1490,7 @@ fn trans_enum_variant_or_tuple_like_struct(ccx: &CrateContext, } fn trans_enum_def(ccx: &CrateContext, enum_definition: &ast::EnumDef, - id: ast::NodeId, vi: &[Rc<ty::VariantInfo>], + sp: Span, id: ast::NodeId, vi: &[Rc<ty::VariantInfo>], i: &mut uint) { for &variant in enum_definition.variants.iter() { let disr_val = vi[*i].disr_val; @@ -1509,6 +1510,57 @@ fn trans_enum_def(ccx: &CrateContext, enum_definition: &ast::EnumDef, } } } + + enum_variant_size_lint(ccx, enum_definition, sp, id); +} + +fn enum_variant_size_lint(ccx: &CrateContext, enum_def: &ast::EnumDef, sp: Span, id: ast::NodeId) { + let mut sizes = Vec::new(); // does no allocation if no pushes, thankfully + + let (lvl, src) = ccx.tcx.node_lint_levels.borrow() + .find(&(id, lint::VariantSizeDifference)) + .map_or((lint::Allow, lint::Default), |&(lvl,src)| (lvl, src)); + + if lvl != lint::Allow { + let avar = adt::represent_type(ccx, ty::node_id_to_type(ccx.tcx(), id)); + match *avar { + adt::General(_, ref variants) => { + for var in variants.iter() { + let mut size = 0; + for field in var.fields.iter().skip(1) { + // skip the dicriminant + size += llsize_of_real(ccx, sizing_type_of(ccx, *field)); + } + sizes.push(size); + } + }, + _ => { /* its size is either constant or unimportant */ } + } + + let (largest, slargest, largest_index) = sizes.iter().enumerate().fold((0, 0, 0), + |(l, s, li), (idx, &size)| + if size > l { + (size, l, idx) + } else if size > s { + (l, size, li) + } else { + (l, s, li) + } + ); + + // we only warn if the largest variant is at least thrice as large as + // the second-largest. + if largest > slargest * 3 && slargest > 0 { + lint::emit_lint(lvl, src, + format!("enum variant is more than three times larger \ + ({} bytes) than the next largest (ignoring padding)", + largest).as_slice(), + sp, lint::lint_to_str(lint::VariantSizeDifference), ccx.tcx()); + + ccx.sess().span_note(enum_def.variants.get(largest_index).span, + "this variant is the largest"); + } + } } pub struct TransItemVisitor<'a> { @@ -1555,7 +1607,7 @@ pub fn trans_item(ccx: &CrateContext, item: &ast::Item) { if !generics.is_type_parameterized() { let vi = ty::enum_variants(ccx.tcx(), local_def(item.id)); let mut i = 0; - trans_enum_def(ccx, enum_definition, item.id, vi.as_slice(), &mut i); + trans_enum_def(ccx, enum_definition, item.span, item.id, vi.as_slice(), &mut i); } } ast::ItemStatic(_, m, expr) => { |
