Skip to content

Add lint for large const items #21632

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion src/librustc/lint/builtin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)]
Expand All @@ -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
)
}
}
Expand Down
23 changes: 12 additions & 11 deletions src/librustc/lint/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
},
_ => { }
}
Expand Down
27 changes: 27 additions & 0 deletions src/librustc_trans/trans/base.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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>,
}
Expand Down Expand Up @@ -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
Expand Down
2 changes: 2 additions & 0 deletions src/libstd/thread_local/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 },
Expand All @@ -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);
Expand Down
19 changes: 19 additions & 0 deletions src/test/compile-fail/lint-large-const-items.rs
Original file line number Diff line number Diff line change
@@ -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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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() { }