Skip to content

Commit f5d29a3

Browse files
Move variant_size_differences out of trans
Also enhances the error message a bit, fixes #30505 on the way, and adds a test (which was missing). Closes #34018
1 parent 6871b3f commit f5d29a3

File tree

11 files changed

+123
-241
lines changed

11 files changed

+123
-241
lines changed

src/librustc/lint/builtin.rs

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -94,12 +94,6 @@ declare_lint! {
9494
"unknown crate type found in #[crate_type] directive"
9595
}
9696

97-
declare_lint! {
98-
pub VARIANT_SIZE_DIFFERENCES,
99-
Allow,
100-
"detects enums with widely varying variant sizes"
101-
}
102-
10397
declare_lint! {
10498
pub FAT_PTR_TRANSMUTES,
10599
Allow,
@@ -230,7 +224,6 @@ impl LintPass for HardwiredLints {
230224
UNUSED_FEATURES,
231225
STABLE_FEATURES,
232226
UNKNOWN_CRATE_TYPES,
233-
VARIANT_SIZE_DIFFERENCES,
234227
FAT_PTR_TRANSMUTES,
235228
TRIVIAL_CASTS,
236229
TRIVIAL_NUMERIC_CASTS,

src/librustc/lint/context.rs

Lines changed: 2 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,8 @@ use dep_graph::DepNode;
2929
use middle::privacy::AccessLevels;
3030
use ty::TyCtxt;
3131
use session::{config, early_error, Session};
32-
use lint::{Level, LevelSource, Lint, LintId, LintArray, LintPass};
33-
use lint::{EarlyLintPassObject, LateLintPass, LateLintPassObject};
32+
use lint::{Level, LevelSource, Lint, LintId, LintPass};
33+
use lint::{EarlyLintPassObject, LateLintPassObject};
3434
use lint::{Default, CommandLine, Node, Allow, Warn, Deny, Forbid};
3535
use lint::builtin;
3636
use util::nodemap::FnvHashMap;
@@ -1064,38 +1064,6 @@ impl<'a, 'tcx> IdVisitingOperation for LateContext<'a, 'tcx> {
10641064
}
10651065
}
10661066

1067-
// This lint pass is defined here because it touches parts of the `LateContext`
1068-
// that we don't want to expose. It records the lint level at certain AST
1069-
// nodes, so that the variant size difference check in trans can call
1070-
// `raw_emit_lint`.
1071-
1072-
pub struct GatherNodeLevels;
1073-
1074-
impl LintPass for GatherNodeLevels {
1075-
fn get_lints(&self) -> LintArray {
1076-
lint_array!()
1077-
}
1078-
}
1079-
1080-
impl LateLintPass for GatherNodeLevels {
1081-
fn check_item(&mut self, cx: &LateContext, it: &hir::Item) {
1082-
match it.node {
1083-
hir::ItemEnum(..) => {
1084-
let lint_id = LintId::of(builtin::VARIANT_SIZE_DIFFERENCES);
1085-
let lvlsrc = cx.lints.get_level_source(lint_id);
1086-
match lvlsrc {
1087-
(lvl, _) if lvl != Allow => {
1088-
cx.node_levels.borrow_mut()
1089-
.insert((it.id, lint_id), lvlsrc);
1090-
},
1091-
_ => { }
1092-
}
1093-
},
1094-
_ => { }
1095-
}
1096-
}
1097-
}
1098-
10991067
enum CheckLintNameResult {
11001068
Ok,
11011069
// Lint doesn't exist

src/librustc/lint/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ use hir;
4141

4242
pub use lint::context::{LateContext, EarlyContext, LintContext, LintStore,
4343
raw_emit_lint, check_crate, check_ast_crate, gather_attrs,
44-
raw_struct_lint, GatherNodeLevels, FutureIncompatibleInfo};
44+
raw_struct_lint, FutureIncompatibleInfo};
4545

4646
/// Specification of a single lint.
4747
#[derive(Copy, Clone, Debug)]

src/librustc/session/config.rs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -727,8 +727,6 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options,
727727
"load extra plugins"),
728728
unstable_options: bool = (false, parse_bool,
729729
"adds unstable command line options to rustc interface"),
730-
print_enum_sizes: bool = (false, parse_bool,
731-
"print the size of enums and their variants"),
732730
force_overflow_checks: Option<bool> = (None, parse_opt_bool,
733731
"force overflow checks on or off"),
734732
force_dropflag_checks: Option<bool> = (None, parse_opt_bool,

src/librustc/session/mod.rs

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -304,9 +304,6 @@ impl Session {
304304
pub fn unstable_options(&self) -> bool {
305305
self.opts.debugging_opts.unstable_options
306306
}
307-
pub fn print_enum_sizes(&self) -> bool {
308-
self.opts.debugging_opts.print_enum_sizes
309-
}
310307
pub fn nonzeroing_move_hints(&self) -> bool {
311308
self.opts.debugging_opts.enable_nonzeroing_move_hints
312309
}

src/librustc_lint/lib.rs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,7 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) {
108108
HardwiredLints,
109109
WhileTrue,
110110
ImproperCTypes,
111+
VariantSizeDifferences,
111112
BoxPointers,
112113
UnusedAttributes,
113114
PathStatements,
@@ -209,9 +210,6 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) {
209210
},
210211
]);
211212

212-
// We have one lint pass defined specially
213-
store.register_late_pass(sess, false, box lint::GatherNodeLevels);
214-
215213
// Register renamed and removed lints
216214
store.register_renamed("unknown_features", "unused_features");
217215
store.register_removed("unsigned_negation", "replaced by negate_unsigned feature gate");

src/librustc_lint/types.rs

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@
1313
use rustc::hir::def_id::DefId;
1414
use rustc::ty::subst::Substs;
1515
use rustc::ty::{self, Ty, TyCtxt};
16+
use rustc::ty::layout::{Layout, Primitive};
17+
use rustc::traits::ProjectionMode;
1618
use middle::const_val::ConstVal;
1719
use rustc_const_eval::eval_const_expr_partial;
1820
use rustc_const_eval::EvalHint::ExprTypeChecked;
@@ -77,6 +79,12 @@ declare_lint! {
7779
"shift exceeds the type's number of bits"
7880
}
7981

82+
declare_lint! {
83+
VARIANT_SIZE_DIFFERENCES,
84+
Allow,
85+
"detects enums with widely varying variant sizes"
86+
}
87+
8088
#[derive(Copy, Clone)]
8189
pub struct TypeLimits {
8290
/// Id of the last visited negated expression
@@ -676,3 +684,63 @@ impl LateLintPass for ImproperCTypes {
676684
}
677685
}
678686
}
687+
688+
pub struct VariantSizeDifferences;
689+
690+
impl LintPass for VariantSizeDifferences {
691+
fn get_lints(&self) -> LintArray {
692+
lint_array!(VARIANT_SIZE_DIFFERENCES)
693+
}
694+
}
695+
696+
impl LateLintPass for VariantSizeDifferences {
697+
fn check_item(&mut self, cx: &LateContext, it: &hir::Item) {
698+
if let hir::ItemEnum(ref enum_definition, ref gens) = it.node {
699+
if gens.ty_params.is_empty() { // sizes only make sense for non-generic types
700+
let mut sizes = vec![];
701+
let t = cx.tcx.node_id_to_type(it.id);
702+
let layout = cx.tcx.normalizing_infer_ctxt(ProjectionMode::Any).enter(|infcx| {
703+
t.layout(&infcx).unwrap_or_else(|e| {
704+
bug!("failed to get layout for `{}`: {}", t, e)
705+
})
706+
});
707+
708+
if let Layout::General { ref variants, ref size, discr, .. } = *layout {
709+
let discr_size = Primitive::Int(discr).size(&cx.tcx.data_layout).bytes();
710+
711+
debug!("enum `{}` is {} bytes large", t, size.bytes());
712+
713+
for (variant, variant_layout) in enum_definition.variants.iter().zip(variants) {
714+
// Subtract the size of the enum discriminant
715+
let bytes = variant_layout.min_size().bytes().saturating_sub(discr_size);
716+
sizes.push(bytes);
717+
718+
debug!("- variant `{}` is {} bytes large", variant.node.name, bytes);
719+
}
720+
721+
let (largest, slargest, largest_index) = sizes.iter()
722+
.enumerate()
723+
.fold((0, 0, 0),
724+
|(l, s, li), (idx, &size)|
725+
if size > l {
726+
(size, l, idx)
727+
} else if size > s {
728+
(l, size, li)
729+
} else {
730+
(l, s, li)
731+
}
732+
);
733+
734+
// we only warn if the largest variant is at least thrice as large as
735+
// the second-largest.
736+
if largest > slargest * 3 && slargest > 0 {
737+
cx.span_lint(VARIANT_SIZE_DIFFERENCES,
738+
enum_definition.variants[largest_index].span,
739+
&format!("enum variant is more than three times larger \
740+
({} bytes) than the next largest", largest));
741+
}
742+
}
743+
}
744+
}
745+
}
746+
}

0 commit comments

Comments
 (0)