Skip to content

Commit 5c69a4f

Browse files
authored
Auto merge of #34755 - jonas-schievink:minor-differences, r=eddyb
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
2 parents 2539c15 + fd2b65e commit 5c69a4f

File tree

12 files changed

+135
-254
lines changed

12 files changed

+135
-254
lines changed

src/librustc/lint/builtin.rs

-7
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

+2-42
Original file line numberDiff line numberDiff line change
@@ -29,13 +29,12 @@ 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;
3737

38-
use std::cell::RefCell;
3938
use std::cmp;
4039
use std::default::Default as StdDefault;
4140
use std::mem;
@@ -311,10 +310,6 @@ pub struct LateContext<'a, 'tcx: 'a> {
311310
/// levels, this stack keeps track of the previous lint levels of whatever
312311
/// was modified.
313312
level_stack: Vec<(LintId, LevelSource)>,
314-
315-
/// Level of lints for certain NodeIds, stored here because the body of
316-
/// the lint needs to run in trans.
317-
node_levels: RefCell<FnvHashMap<(ast::NodeId, LintId), LevelSource>>,
318313
}
319314

320315
/// Context for lint checking of the AST, after expansion, before lowering to
@@ -664,7 +659,6 @@ impl<'a, 'tcx> LateContext<'a, 'tcx> {
664659
access_levels: access_levels,
665660
lints: lint_store,
666661
level_stack: vec![],
667-
node_levels: RefCell::new(FnvHashMap()),
668662
}
669663
}
670664

@@ -1064,38 +1058,6 @@ impl<'a, 'tcx> IdVisitingOperation for LateContext<'a, 'tcx> {
10641058
}
10651059
}
10661060

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-
10991061
enum CheckLintNameResult {
11001062
Ok,
11011063
// Lint doesn't exist
@@ -1234,8 +1196,6 @@ pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
12341196
}
12351197
}
12361198

1237-
*tcx.node_lint_levels.borrow_mut() = cx.node_levels.into_inner();
1238-
12391199
// Put the lint store back in the session.
12401200
mem::replace(&mut *tcx.sess.lint_store.borrow_mut(), cx.lints);
12411201
}

src/librustc/lint/mod.rs

+1-1
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

-2
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

-3
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/ty/context.rs

-5
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@
1212
1313
use dep_graph::{DepGraph, DepTrackingMap};
1414
use session::Session;
15-
use lint;
1615
use middle;
1716
use middle::cstore::LOCAL_CRATE;
1817
use hir::def::DefMap;
@@ -415,9 +414,6 @@ pub struct GlobalCtxt<'tcx> {
415414
/// Cache used by const_eval when decoding extern const fns
416415
pub extern_const_fns: RefCell<DefIdMap<NodeId>>,
417416

418-
pub node_lint_levels: RefCell<FnvHashMap<(NodeId, lint::LintId),
419-
lint::LevelSource>>,
420-
421417
/// Maps any item's def-id to its stability index.
422418
pub stability: RefCell<stability::Index<'tcx>>,
423419

@@ -726,7 +722,6 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
726722
populated_external_primitive_impls: RefCell::new(DefIdSet()),
727723
extern_const_statics: RefCell::new(DefIdMap()),
728724
extern_const_fns: RefCell::new(DefIdMap()),
729-
node_lint_levels: RefCell::new(FnvHashMap()),
730725
stability: RefCell::new(stability),
731726
selection_cache: traits::SelectionCache::new(),
732727
evaluation_cache: traits::EvaluationCache::new(),

src/librustc_lint/lib.rs

+1-3
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

+69
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;
@@ -76,6 +78,12 @@ declare_lint! {
7678
"shift exceeds the type's number of bits"
7779
}
7880

81+
declare_lint! {
82+
VARIANT_SIZE_DIFFERENCES,
83+
Allow,
84+
"detects enums with widely varying variant sizes"
85+
}
86+
7987
#[derive(Copy, Clone)]
8088
pub struct TypeLimits {
8189
/// Id of the last visited negated expression
@@ -675,3 +683,64 @@ impl LateLintPass for ImproperCTypes {
675683
}
676684
}
677685
}
686+
687+
pub struct VariantSizeDifferences;
688+
689+
impl LintPass for VariantSizeDifferences {
690+
fn get_lints(&self) -> LintArray {
691+
lint_array!(VARIANT_SIZE_DIFFERENCES)
692+
}
693+
}
694+
695+
impl LateLintPass for VariantSizeDifferences {
696+
fn check_item(&mut self, cx: &LateContext, it: &hir::Item) {
697+
if let hir::ItemEnum(ref enum_definition, ref gens) = it.node {
698+
if gens.ty_params.is_empty() { // sizes only make sense for non-generic types
699+
let t = cx.tcx.node_id_to_type(it.id);
700+
let layout = cx.tcx.normalizing_infer_ctxt(ProjectionMode::Any).enter(|infcx| {
701+
t.layout(&infcx).unwrap_or_else(|e| {
702+
bug!("failed to get layout for `{}`: {}", t, e)
703+
})
704+
});
705+
706+
if let Layout::General { ref variants, ref size, discr, .. } = *layout {
707+
let discr_size = Primitive::Int(discr).size(&cx.tcx.data_layout).bytes();
708+
709+
debug!("enum `{}` is {} bytes large", t, size.bytes());
710+
711+
let (largest, slargest, largest_index) = enum_definition.variants
712+
.iter()
713+
.zip(variants)
714+
.map(|(variant, variant_layout)| {
715+
// Subtract the size of the enum discriminant
716+
let bytes = variant_layout.min_size().bytes()
717+
.saturating_sub(discr_size);
718+
719+
debug!("- variant `{}` is {} bytes large", variant.node.name, bytes);
720+
bytes
721+
})
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)