Auto merge of #22801 - huonw:crateify-lint, r=kmcallister

This pulls out the implementations of most built-in lints into a
separate crate, to reduce edit-compile-test iteration times with
librustc_lint and increase parallelism. This should enable lints to be
refactored, added and deleted much more easily as it slashes the
edit-compile cycle to get a minimal working compiler to test with (`make
rustc-stage1`) from

    librustc -> librustc_typeck -> ... -> librustc_driver ->
        libcore -> ... -> libstd

to

    librustc_lint -> librustc_driver -> libcore -> ... libstd

which is significantly faster, mainly due to avoiding the librustc build
itself.

The intention would be to move as much as possible of the infrastructure
into the crate too, but the plumbing is deeply intertwined with librustc
itself at the moment. Also, there are lints for which diagnostics are
registered directly in the compiler code, not in their own crate
traversal, and their definitions have to remain in librustc.

This is a [breaking-change] for direct users of the compiler APIs:
callers of `rustc::session::build_session` or
`rustc::session::build_session_` need to manually call
`rustc_lint::register_builtins` on their return value.

This should make #22206 easier.
This commit is contained in:
bors 2015-02-28 06:06:18 +00:00
commit 48aeaba934
15 changed files with 2267 additions and 2167 deletions

View File

@ -54,7 +54,7 @@ TARGET_CRATES := libc std flate arena term \
log graphviz core rbml alloc \
unicode rustc_bitflags
RUSTC_CRATES := rustc rustc_typeck rustc_borrowck rustc_resolve rustc_driver \
rustc_trans rustc_back rustc_llvm rustc_privacy
rustc_trans rustc_back rustc_llvm rustc_privacy rustc_lint
HOST_CRATES := syntax $(RUSTC_CRATES) rustdoc fmt_macros
CRATES := $(TARGET_CRATES) $(HOST_CRATES)
TOOLS := compiletest rustdoc rustc rustbook
@ -70,7 +70,7 @@ DEPS_graphviz := std
DEPS_syntax := std term serialize log fmt_macros arena libc
DEPS_rustc_driver := arena flate getopts graphviz libc rustc rustc_back rustc_borrowck \
rustc_typeck rustc_resolve log syntax serialize rustc_llvm \
rustc_trans rustc_privacy
rustc_trans rustc_privacy rustc_lint
DEPS_rustc_trans := arena flate getopts graphviz libc rustc rustc_back \
log syntax serialize rustc_llvm
@ -78,12 +78,13 @@ DEPS_rustc_typeck := rustc syntax
DEPS_rustc_borrowck := rustc log graphviz syntax
DEPS_rustc_resolve := rustc log syntax
DEPS_rustc_privacy := rustc log syntax
DEPS_rustc_lint := rustc log syntax
DEPS_rustc := syntax flate arena serialize getopts rbml \
log graphviz rustc_llvm rustc_back
DEPS_rustc_llvm := native:rustllvm libc std
DEPS_rustc_back := std syntax rustc_llvm flate log libc
DEPS_rustdoc := rustc rustc_driver native:hoedown serialize getopts \
test
test rustc_lint
DEPS_rustc_bitflags := core
DEPS_flate := std native:miniz
DEPS_arena := std
@ -128,11 +129,13 @@ DOC_CRATES := $(filter-out rustc, \
$(filter-out rustc_resolve, \
$(filter-out rustc_driver, \
$(filter-out rustc_privacy, \
$(filter-out rustc_lint, \
$(filter-out log, \
$(filter-out getopts, \
$(filter-out syntax, $(CRATES)))))))))))
$(filter-out syntax, $(CRATES))))))))))))
COMPILER_DOC_CRATES := rustc rustc_trans rustc_borrowck rustc_resolve \
rustc_typeck rustc_driver syntax rustc_privacy
rustc_typeck rustc_driver syntax rustc_privacy \
rustc_lint
# This macro creates some simple definitions for each crate being built, just
# some munging of all of the parameters above.

View File

@ -21,7 +21,7 @@ $(eval $(call RUST_CRATE,coretest))
TEST_TARGET_CRATES = $(filter-out core unicode,$(TARGET_CRATES)) coretest
TEST_DOC_CRATES = $(DOC_CRATES)
TEST_HOST_CRATES = $(filter-out rustc_typeck rustc_borrowck rustc_resolve rustc_trans,\
TEST_HOST_CRATES = $(filter-out rustc_typeck rustc_borrowck rustc_resolve rustc_trans rustc_lint,\
$(HOST_CRATES))
TEST_CRATES = $(TEST_TARGET_CRATES) $(TEST_HOST_CRATES)

View File

@ -39,7 +39,6 @@
#![feature(unsafe_destructor)]
#![feature(staged_api)]
#![feature(std_misc)]
#![feature(unicode)]
#![feature(os)]
#![cfg_attr(test, feature(test))]

File diff suppressed because it is too large Load Diff

View File

@ -159,7 +159,7 @@ impl LintStore {
}
}
fn register_renamed(&mut self, old_name: &str, new_name: &str) {
pub fn register_renamed(&mut self, old_name: &str, new_name: &str) {
let target = match self.by_name.get(new_name) {
Some(&Id(lint_id)) => lint_id.clone(),
_ => panic!("invalid lint renaming of {} to {}", old_name, new_name)
@ -167,80 +167,6 @@ impl LintStore {
self.by_name.insert(old_name.to_string(), Renamed(new_name.to_string(), target));
}
pub fn register_builtin(&mut self, sess: Option<&Session>) {
macro_rules! add_builtin {
($sess:ident, $($name:ident),*,) => (
{$(
self.register_pass($sess, false, box builtin::$name as LintPassObject);
)*}
)
}
macro_rules! add_builtin_with_new {
($sess:ident, $($name:ident),*,) => (
{$(
self.register_pass($sess, false, box builtin::$name::new() as LintPassObject);
)*}
)
}
macro_rules! add_lint_group {
($sess:ident, $name:expr, $($lint:ident),*) => (
self.register_group($sess, false, $name, vec![$(LintId::of(builtin::$lint)),*]);
)
}
add_builtin!(sess,
HardwiredLints,
WhileTrue,
UnusedCasts,
ImproperCTypes,
BoxPointers,
UnusedAttributes,
PathStatements,
UnusedResults,
NonCamelCaseTypes,
NonSnakeCase,
NonUpperCaseGlobals,
UnusedParens,
UnusedImportBraces,
NonShorthandFieldPatterns,
UnusedUnsafe,
UnsafeCode,
UnusedMut,
UnusedAllocation,
MissingCopyImplementations,
UnstableFeatures,
Stability,
UnconditionalRecursion,
InvalidNoMangleItems,
PluginAsLibrary,
);
add_builtin_with_new!(sess,
TypeLimits,
RawPointerDerive,
MissingDoc,
MissingDebugImplementations,
);
add_lint_group!(sess, "bad_style",
NON_CAMEL_CASE_TYPES, NON_SNAKE_CASE, NON_UPPER_CASE_GLOBALS);
add_lint_group!(sess, "unused",
UNUSED_IMPORTS, UNUSED_VARIABLES, UNUSED_ASSIGNMENTS, DEAD_CODE,
UNUSED_MUT, UNREACHABLE_CODE, UNUSED_MUST_USE,
UNUSED_UNSAFE, PATH_STATEMENTS);
// We have one lint pass defined in this module.
self.register_pass(sess, false, box GatherNodeLevels as LintPassObject);
// Insert temporary renamings for a one-time deprecation
self.register_renamed("raw_pointer_deriving", "raw_pointer_derive");
self.register_renamed("unknown_features", "unused_features");
}
#[allow(unused_variables)]
fn find_lint(&self, lint_name: &str, sess: &Session, span: Option<Span>)
-> Option<LintId>
@ -741,7 +667,7 @@ impl<'a, 'tcx> IdVisitingOperation for Context<'a, 'tcx> {
// nodes, so that the variant size difference check in trans can call
// `raw_emit_lint`.
struct GatherNodeLevels;
pub struct GatherNodeLevels;
impl LintPass for GatherNodeLevels {
fn get_lints(&self) -> LintArray {

View File

@ -37,7 +37,8 @@ use syntax::codemap::Span;
use syntax::visit::FnKind;
use syntax::ast;
pub use lint::context::{Context, LintStore, raw_emit_lint, check_crate, gather_attrs};
pub use lint::context::{Context, LintStore, raw_emit_lint, check_crate, gather_attrs,
GatherNodeLevels};
/// Specification of a single lint.
#[derive(Copy, Debug)]

View File

@ -8,7 +8,6 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use lint;
use metadata::cstore::CStore;
use metadata::filesearch;
@ -389,7 +388,6 @@ pub fn build_session_(sopts: config::Options,
can_print_warnings: can_print_warnings
};
sess.lint_store.borrow_mut().register_builtin(Some(&sess));
sess
}

View File

@ -47,6 +47,7 @@ extern crate libc;
extern crate rustc;
extern crate rustc_back;
extern crate rustc_borrowck;
extern crate rustc_lint;
extern crate rustc_privacy;
extern crate rustc_resolve;
extern crate rustc_trans;
@ -133,6 +134,7 @@ pub fn run_compiler<'a>(args: &[String],
};
let mut sess = build_session(sopts, input_file_path, descriptions);
rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess));
if sess.unstable_options() {
sess.opts.show_span = matches.opt_str("show-span");
}
@ -299,11 +301,12 @@ impl<'a> CompilerCalls<'a> for RustcDefaultCalls {
0 => {
if sopts.describe_lints {
let mut ls = lint::LintStore::new();
ls.register_builtin(None);
rustc_lint::register_builtins(&mut ls, None);
describe_lints(&ls, false);
return None;
}
let sess = build_session(sopts.clone(), None, descriptions.clone());
rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess));
let should_stop = RustcDefaultCalls::print_crate_info(&sess, None, odir, ofile);
if should_stop == Compilation::Stop {
return None;
@ -844,4 +847,3 @@ pub fn main() {
let result = run(env::args().collect());
std::env::set_exit_status(result as i32);
}

View File

@ -13,6 +13,7 @@
use diagnostic;
use diagnostic::Emitter;
use driver;
use rustc_lint;
use rustc_resolve as resolve;
use rustc_typeck::middle::lang_items;
use rustc_typeck::middle::region::{self, CodeExtent, DestructionScopeData};
@ -108,6 +109,7 @@ fn test_env<F>(source_string: &str,
diagnostic::mk_span_handler(diagnostic_handler, codemap);
let sess = session::build_session_(options, None, span_diagnostic_handler);
rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess));
let krate_config = Vec::new();
let input = config::Input::Str(source_string.to_string());
let krate = driver::phase_1_parse_input(&sess, krate_config, &input);

2098
src/librustc_lint/builtin.rs Normal file

File diff suppressed because it is too large Load Diff

137
src/librustc_lint/lib.rs Normal file
View File

@ -0,0 +1,137 @@
// 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.
//! Lints in the Rust compiler.
//!
//! This currently only contains the definitions and implementations
//! of most of the lints that `rustc` supports directly, it does not
//! contain the infrastructure for defining/registering lints. That is
//! available in `rustc::lint` and `rustc::plugin` respectively.
//!
//! # Note
//!
//! This API is completely unstable and subject to change.
#![crate_name = "rustc_lint"]
#![unstable(feature = "rustc_private")]
#![staged_api]
#![crate_type = "dylib"]
#![crate_type = "rlib"]
#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
html_favicon_url = "http://www.rust-lang.org/favicon.ico",
html_root_url = "http://doc.rust-lang.org/nightly/")]
#![feature(box_patterns)]
#![feature(box_syntax)]
#![feature(collections)]
#![feature(core)]
#![feature(int_uint)]
#![feature(quote)]
#![feature(rustc_diagnostic_macros)]
#![feature(rustc_private)]
#![feature(unsafe_destructor)]
#![feature(staged_api)]
#![feature(std_misc)]
#![feature(unicode)]
#![cfg_attr(test, feature(test))]
extern crate syntax;
#[macro_use]
extern crate rustc;
#[macro_use]
extern crate log;
pub use rustc::lint as lint;
pub use rustc::metadata as metadata;
pub use rustc::middle as middle;
pub use rustc::session as session;
pub use rustc::util as util;
use session::Session;
use lint::{LintPassObject, LintId};
mod builtin;
/// Tell the `LintStore` about all the built-in lints (the ones
/// defined in this crate and the ones defined in
/// `rustc::lint::builtin`).
pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) {
macro_rules! add_builtin {
($sess:ident, $($name:ident),*,) => (
{$(
store.register_pass($sess, false, box builtin::$name as LintPassObject);
)*}
)
}
macro_rules! add_builtin_with_new {
($sess:ident, $($name:ident),*,) => (
{$(
store.register_pass($sess, false, box builtin::$name::new() as LintPassObject);
)*}
)
}
macro_rules! add_lint_group {
($sess:ident, $name:expr, $($lint:ident),*) => (
store.register_group($sess, false, $name, vec![$(LintId::of(builtin::$lint)),*]);
)
}
add_builtin!(sess,
HardwiredLints,
WhileTrue,
UnusedCasts,
ImproperCTypes,
BoxPointers,
UnusedAttributes,
PathStatements,
UnusedResults,
NonCamelCaseTypes,
NonSnakeCase,
NonUpperCaseGlobals,
UnusedParens,
UnusedImportBraces,
NonShorthandFieldPatterns,
UnusedUnsafe,
UnsafeCode,
UnusedMut,
UnusedAllocation,
MissingCopyImplementations,
UnstableFeatures,
Stability,
UnconditionalRecursion,
InvalidNoMangleItems,
PluginAsLibrary,
);
add_builtin_with_new!(sess,
TypeLimits,
RawPointerDerive,
MissingDoc,
MissingDebugImplementations,
);
add_lint_group!(sess, "bad_style",
NON_CAMEL_CASE_TYPES, NON_SNAKE_CASE, NON_UPPER_CASE_GLOBALS);
add_lint_group!(sess, "unused",
UNUSED_IMPORTS, UNUSED_VARIABLES, UNUSED_ASSIGNMENTS, DEAD_CODE,
UNUSED_MUT, UNREACHABLE_CODE, UNUSED_MUST_USE,
UNUSED_UNSAFE, PATH_STATEMENTS);
// We have one lint pass defined specially
store.register_pass(sess, false, box lint::GatherNodeLevels as LintPassObject);
// Insert temporary renamings for a one-time deprecation
store.register_renamed("raw_pointer_deriving", "raw_pointer_derive");
store.register_renamed("unknown_features", "unused_features");
}

View File

@ -9,6 +9,7 @@
// except according to those terms.
pub use self::MaybeTyped::*;
use rustc_lint;
use rustc_driver::driver;
use rustc::session::{self, config};
use rustc::session::config::UnstableFeatures;
@ -114,6 +115,7 @@ pub fn run_core(search_paths: SearchPaths, cfgs: Vec<String>, externs: Externs,
let sess = session::build_session_(sessopts, cpath,
span_diagnostic_handler);
rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess));
let cfg = config::build_configuration(&sess);

View File

@ -42,6 +42,7 @@ extern crate rustc;
extern crate rustc_trans;
extern crate rustc_driver;
extern crate rustc_resolve;
extern crate rustc_lint;
extern crate serialize;
extern crate syntax;
extern crate "test" as testing;

View File

@ -20,6 +20,7 @@ use std::thunk::Thunk;
use std::collections::{HashSet, HashMap};
use testing;
use rustc_lint;
use rustc::session::{self, config};
use rustc::session::config::get_unstable_features_setting;
use rustc::session::search_paths::{SearchPaths, PathKind};
@ -62,6 +63,7 @@ pub fn run(input: &str,
let sess = session::build_session_(sessopts,
Some(input_path.clone()),
span_diagnostic_handler);
rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess));
let mut cfg = config::build_configuration(&sess);
cfg.extend(config::parse_cfgspecs(cfgs).into_iter());
@ -165,6 +167,7 @@ fn runtest(test: &str, cratename: &str, libs: SearchPaths,
let sess = session::build_session_(sessopts,
None,
span_diagnostic_handler);
rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess));
let outdir = TempDir::new("rustdoctest").ok().expect("rustdoc needs a tempdir");
let out = Some(outdir.path().clone());

View File

@ -10,6 +10,7 @@
extern crate rustc;
extern crate rustc_driver;
extern crate rustc_lint;
extern crate syntax;
use rustc::session::{build_session, Session};
@ -46,6 +47,7 @@ fn basic_sess(sysroot: Path) -> Session {
let descriptions = Registry::new(&rustc::diagnostics::DIAGNOSTICS);
let sess = build_session(opts, None, descriptions);
rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess));
sess
}