}
}
+impl Copy for TypeFlags {}
+
+macro_rules! sty_debug_print {
+ ($ctxt: expr, $($variant: ident),*) => {{
+ // curious inner module to allow variant names to be used as
+ // variable names.
+ mod inner {
+ use middle::ty;
+ struct DebugStat {
+ total: uint,
+ region_infer: uint,
+ ty_infer: uint,
+ both_infer: uint,
+ }
+
+ pub fn go(tcx: &ty::ctxt) {
+ let mut total = DebugStat {
+ total: 0,
+ region_infer: 0, ty_infer: 0, both_infer: 0,
+ };
+ $(let mut $variant = total;)*
+
+
+ for (_, t) in tcx.interner.borrow().iter() {
+ let variant = match t.sty {
+ ty::ty_bool | ty::ty_char | ty::ty_int(..) | ty::ty_uint(..) |
+ ty::ty_float(..) | ty::ty_str => continue,
+ ty::ty_err => /* unimportant */ continue,
+ $(ty::$variant(..) => &mut $variant,)*
+ };
+ let region = t.flags.intersects(ty::HAS_RE_INFER);
+ let ty = t.flags.intersects(ty::HAS_TY_INFER);
+
+ variant.total += 1;
+ total.total += 1;
+ if region { total.region_infer += 1; variant.region_infer += 1 }
+ if ty { total.ty_infer += 1; variant.ty_infer += 1 }
+ if region && ty { total.both_infer += 1; variant.both_infer += 1 }
+ }
+ println!("Ty interner total ty region both");
+ $(println!(" {:18}: {uses:6} {usespc:4.1}%, \
+{ty:4.1}% {region:5.1}% {both:4.1}%",
+ stringify!($variant),
+ uses = $variant.total,
+ usespc = $variant.total as f64 * 100.0 / total.total as f64,
+ ty = $variant.ty_infer as f64 * 100.0 / total.total as f64,
+ region = $variant.region_infer as f64 * 100.0 / total.total as f64,
+ both = $variant.both_infer as f64 * 100.0 / total.total as f64);
+ )*
+ println!(" total {uses:6} \
+{ty:4.1}% {region:5.1}% {both:4.1}%",
+ uses = total.total,
+ ty = total.ty_infer as f64 * 100.0 / total.total as f64,
+ region = total.region_infer as f64 * 100.0 / total.total as f64,
+ both = total.both_infer as f64 * 100.0 / total.total as f64)
+ }
+ }
+
+ inner::go($ctxt)
+ }}
+}
+
+impl<'tcx> ctxt<'tcx> {
+ pub fn print_debug_stats(&self) {
+ sty_debug_print!(
+ self,
+ ty_enum, ty_uniq, ty_vec, ty_ptr, ty_rptr, ty_bare_fn, ty_closure, ty_trait,
+ ty_struct, ty_unboxed_closure, ty_tup, ty_param, ty_open, ty_infer);
+ }
+}
+
#[deriving(Show)]
pub struct TyS<'tcx> {
pub sty: sty<'tcx>,
let type_arena = TypedArena::new();
let analysis = phase_3_run_analysis_passes(sess, ast_map, &type_arena, id);
phase_save_analysis(&analysis.ty_cx.sess, analysis.ty_cx.map.krate(), &analysis, outdir);
+
+ if log_enabled!(::log::INFO) {
+ println!("Pre-trans")
+ analysis.ty_cx.print_debug_stats();
+ }
+
if stop_after_phase_3(&analysis.ty_cx.sess) { return; }
let (tcx, trans) = phase_4_translate_to_llvm(analysis);
+ if log_enabled!(::log::INFO) {
+ println!("Post-trans")
+ tcx.print_debug_stats();
+ }
+
// Discard interned strings as they are no longer required.
token::get_ident_interner().clear();
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 print_info = log_enabled!(::log::INFO);
+
let levels = ccx.tcx().node_lint_levels.borrow();
let lint_id = lint::LintId::of(lint::builtin::VARIANT_SIZE_DIFFERENCES);
- let lvlsrc = match levels.get(&(id, lint_id)) {
- None | Some(&(lint::Allow, _)) => return,
- Some(&lvlsrc) => lvlsrc,
- };
+ let lvlsrc = levels.get(&(id, lint_id));
+ let is_allow = lvlsrc.map_or(true, |&(lvl, _)| lvl == lint::Allow);
+
+ if is_allow && !print_info {
+ // we're not interested in anything here
+ return
+ }
- let avar = adt::represent_type(ccx, ty::node_id_to_type(ccx.tcx(), id));
+ let ty = ty::node_id_to_type(ccx.tcx(), id);
+ let avar = adt::represent_type(ccx, ty);
match *avar {
adt::General(_, ref variants, _) => {
for var in variants.iter() {
}
);
+ if print_info {
+ let llty = type_of::sizing_type_of(ccx, ty);
+
+ let sess = &ccx.tcx().sess;
+ sess.span_note(sp, &*format!("total size: {} bytes", llsize_of_real(ccx, llty)));
+ match *avar {
+ adt::General(..) => {
+ for (i, var) in enum_def.variants.iter().enumerate() {
+ ccx.tcx().sess.span_note(var.span,
+ &*format!("variant data: {} bytes", sizes[i]));
+ }
+ }
+ _ => {}
+ }
+ }
+
// we only warn if the largest variant is at least thrice as large as
// the second-largest.
- if largest > slargest * 3 && slargest > 0 {
+ if !is_allow && largest > slargest * 3 && slargest > 0 {
// Use lint::raw_emit_lint rather than sess.add_lint because the lint-printing
// pass for the latter already ran.
lint::raw_emit_lint(&ccx.tcx().sess, lint::builtin::VARIANT_SIZE_DIFFERENCES,
- lvlsrc, Some(sp),
+ *lvlsrc.unwrap(), Some(sp),
format!("enum variant is more than three times larger \
({} bytes) than the next largest (ignoring padding)",
largest)[]);
ast::ItemMod(ref m) => {
trans_mod(&ccx.rotate(), m);
}
- ast::ItemEnum(ref enum_definition, _) => {
- enum_variant_size_lint(ccx, enum_definition, item.span, item.id);
+ ast::ItemEnum(ref enum_definition, ref gens) => {
+ if gens.ty_params.is_empty() {
+ // sizes only make sense for non-generic types
+
+ enum_variant_size_lint(ccx, enum_definition, item.span, item.id);
+ }
}
ast::ItemConst(_, ref expr) => {
// Recurse on the expression to catch items in blocks