From e2d4ac6d78bfe66bd259b1fb7e088a6076a7af93 Mon Sep 17 00:00:00 2001 From: we Date: Mon, 26 Jan 2015 00:37:52 +0300 Subject: [PATCH] Add lint for large `const` items --- src/librustc/lint/builtin.rs | 9 ++++++- src/librustc/lint/context.rs | 23 ++++++++-------- src/librustc_trans/trans/base.rs | 27 +++++++++++++++++++ src/libstd/thread_local/mod.rs | 2 ++ .../compile-fail/lint-large-const-items.rs | 19 +++++++++++++ 5 files changed, 68 insertions(+), 12 deletions(-) create mode 100644 src/test/compile-fail/lint-large-const-items.rs diff --git a/src/librustc/lint/builtin.rs b/src/librustc/lint/builtin.rs index fef1017b78285..4d0e01b0ddb4f 100644 --- a/src/librustc/lint/builtin.rs +++ b/src/librustc/lint/builtin.rs @@ -1872,6 +1872,12 @@ declare_lint! { "detects potentially-forgotten implementations of `Copy`" } +declare_lint! { + pub LARGE_CONST_ITEMS, + Warn, + "detects large `const` items" +} + /// Does nothing as a lint pass, but registers some `Lint`s /// which are used by other parts of the compiler. #[derive(Copy)] @@ -1892,7 +1898,8 @@ impl LintPass for HardwiredLints { UNKNOWN_FEATURES, UNKNOWN_CRATE_TYPES, VARIANT_SIZE_DIFFERENCES, - FAT_PTR_TRANSMUTES + FAT_PTR_TRANSMUTES, + LARGE_CONST_ITEMS ) } } diff --git a/src/librustc/lint/context.rs b/src/librustc/lint/context.rs index 4cbfcf7e91ad1..e932a8c38e27a 100644 --- a/src/librustc/lint/context.rs +++ b/src/librustc/lint/context.rs @@ -753,17 +753,18 @@ impl LintPass for GatherNodeLevels { } fn check_item(&mut self, cx: &Context, it: &ast::Item) { - match it.node { - ast::ItemEnum(..) => { - let lint_id = LintId::of(builtin::VARIANT_SIZE_DIFFERENCES); - let lvlsrc = cx.lints.get_level_source(lint_id); - match lvlsrc { - (lvl, _) if lvl != Allow => { - cx.node_levels.borrow_mut() - .insert((it.id, lint_id), lvlsrc); - }, - _ => { } - } + let lint = match it.node { + ast::ItemEnum(..) => builtin::VARIANT_SIZE_DIFFERENCES, + ast::ItemConst(..) => builtin::LARGE_CONST_ITEMS, + _ => return + }; + + let lint_id = LintId::of(lint); + let lvlsrc = cx.lints.get_level_source(lint_id); + match lvlsrc { + (lvl, _) if lvl != Allow => { + cx.node_levels.borrow_mut() + .insert((it.id, lint_id), lvlsrc); }, _ => { } } diff --git a/src/librustc_trans/trans/base.rs b/src/librustc_trans/trans/base.rs index 572dfd165eeda..89b15736b9164 100644 --- a/src/librustc_trans/trans/base.rs +++ b/src/librustc_trans/trans/base.rs @@ -2159,6 +2159,31 @@ fn enum_variant_size_lint(ccx: &CrateContext, enum_def: &ast::EnumDef, sp: Span, } } +fn const_size_lint(ccx: &CrateContext, sp: Span, id: ast::NodeId) { + let levels = ccx.tcx().node_lint_levels.borrow(); + let lint_id = lint::LintId::of(lint::builtin::LARGE_CONST_ITEMS); + let lvlsrc = levels.get(&(id, lint_id)); + let is_allow = lvlsrc.map_or(true, |&(lvl, _)| lvl == lint::Allow); + + if is_allow { + return + } + + let ty = ty::node_id_to_type(ccx.tcx(), id); + let size = machine::llsize_of_alloc(ccx, sizing_type_of(ccx, ty)); + + const MAX_CONST_SIZE: u64 = 64; + if size > MAX_CONST_SIZE { + // 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::LARGE_CONST_ITEMS, + *lvlsrc.unwrap(), Some(sp), + &*format!("using large `const` items ({} bytes) is not recommended, \ + consider replacing `const C: T = init` with `const C: \ + &'static T = &init` or `static C: T = init`", size)); + } +} + pub struct TransItemVisitor<'a, 'tcx: 'a> { pub ccx: &'a CrateContext<'a, 'tcx>, } @@ -2328,6 +2353,8 @@ pub fn trans_item(ccx: &CrateContext, item: &ast::Item) { // Recurse on the expression to catch items in blocks let mut v = TransItemVisitor{ ccx: ccx }; v.visit_expr(&**expr); + + const_size_lint(ccx, item.span, item.id); } ast::ItemStatic(_, m, ref expr) => { // Recurse on the expression to catch items in blocks diff --git a/src/libstd/thread_local/mod.rs b/src/libstd/thread_local/mod.rs index f7a2f8e10e926..4a961d9c113da 100644 --- a/src/libstd/thread_local/mod.rs +++ b/src/libstd/thread_local/mod.rs @@ -190,6 +190,7 @@ macro_rules! __thread_local_inner { ); ($init:expr, $t:ty) => ({ #[cfg(all(any(target_os = "macos", target_os = "linux"), not(target_arch = "aarch64")))] + #[cfg_attr(not(stage0), allow(large_const_items))] const _INIT: ::std::thread_local::__impl::KeyInner<$t> = { ::std::thread_local::__impl::KeyInner { inner: ::std::cell::UnsafeCell { value: $init }, @@ -199,6 +200,7 @@ macro_rules! __thread_local_inner { }; #[cfg(any(not(any(target_os = "macos", target_os = "linux")), target_arch = "aarch64"))] + #[cfg_attr(not(stage0), allow(large_const_items))] const _INIT: ::std::thread_local::__impl::KeyInner<$t> = { unsafe extern fn __destroy(ptr: *mut u8) { ::std::thread_local::__impl::destroy_value::<$t>(ptr); diff --git a/src/test/compile-fail/lint-large-const-items.rs b/src/test/compile-fail/lint-large-const-items.rs new file mode 100644 index 0000000000000..a37079168a124 --- /dev/null +++ b/src/test/compile-fail/lint-large-const-items.rs @@ -0,0 +1,19 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![forbid(large_const_items)] +#![allow(dead_code)] + +const FOO: [u8; 100] = [0; 100]; //~ ERROR using large `const` items (100 bytes) is not recommended + +const BAR: &'static [u8; 100] = &[0; 100]; +const BAZ: &'static str = "Hello!"; + +fn main() { }