2014-06-06 15:49:48 -07:00
|
|
|
// Copyright 2012-2014 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.
|
|
|
|
|
|
|
|
//! Implementation of lint checking.
|
|
|
|
//!
|
|
|
|
//! The lint checking is mostly consolidated into one pass which runs just
|
|
|
|
//! before translation to LLVM bytecode. Throughout compilation, lint warnings
|
|
|
|
//! can be added via the `add_lint` method on the Session structure. This
|
|
|
|
//! requires a span and an id of the node that the lint is being added to. The
|
|
|
|
//! lint isn't actually emitted at that time because it is unknown what the
|
|
|
|
//! actual lint level at that location is.
|
|
|
|
//!
|
|
|
|
//! To actually emit lint warnings/errors, a separate pass is used just before
|
|
|
|
//! translation. A context keeps track of the current state of all lint levels.
|
|
|
|
//! Upon entering a node of the ast which can modify the lint settings, the
|
|
|
|
//! previous lint state is pushed onto a stack and the ast is then recursed
|
|
|
|
//! upon. As the ast is traversed, this keeps track of the current lint level
|
|
|
|
//! for all lint attributes.
|
2014-11-06 00:05:53 -08:00
|
|
|
use self::TargetLint::*;
|
2014-06-06 15:49:48 -07:00
|
|
|
|
|
|
|
use middle::privacy::ExportedItems;
|
2015-01-03 22:42:21 -05:00
|
|
|
use middle::ty::{self, Ty};
|
2014-11-15 20:30:33 -05:00
|
|
|
use session::{early_error, Session};
|
Preliminary feature staging
This partially implements the feature staging described in the
[release channel RFC][rc]. It does not yet fully conform to the RFC as
written, but does accomplish its goals sufficiently for the 1.0 alpha
release.
It has three primary user-visible effects:
* On the nightly channel, use of unstable APIs generates a warning.
* On the beta channel, use of unstable APIs generates a warning.
* On the beta channel, use of feature gates generates a warning.
Code that does not trigger these warnings is considered 'stable',
modulo pre-1.0 bugs.
Disabling the warnings for unstable APIs continues to be done in the
existing (i.e. old) style, via `#[allow(...)]`, not that specified in
the RFC. I deem this marginally acceptable since any code that must do
this is not using the stable dialect of Rust.
Use of feature gates is itself gated with the new 'unstable_features'
lint, on nightly set to 'allow', and on beta 'warn'.
The attribute scheme used here corresponds to an older version of the
RFC, with the `#[staged_api]` crate attribute toggling the staging
behavior of the stability attributes, but the user impact is only
in-tree so I'm not concerned about having to make design changes later
(and I may ultimately prefer the scheme here after all, with the
`#[staged_api]` crate attribute).
Since the Rust codebase itself makes use of unstable features the
compiler and build system to a midly elaborate dance to allow it to
bootstrap while disobeying these lints (which would otherwise be
errors because Rust builds with `-D warnings`).
This patch includes one significant hack that causes a
regression. Because the `format_args!` macro emits calls to unstable
APIs it would trigger the lint. I added a hack to the lint to make it
not trigger, but this in turn causes arguments to `println!` not to be
checked for feature gates. I don't presently understand macro
expansion well enough to fix. This is bug #20661.
Closes #16678
[rc]: https://github.com/rust-lang/rfcs/blob/master/text/0507-release-channels.md
2015-01-06 06:26:08 -08:00
|
|
|
use session::config::UnstableFeatures;
|
2014-06-06 15:49:48 -07:00
|
|
|
use lint::{Level, LevelSource, Lint, LintId, LintArray, LintPass, LintPassObject};
|
Preliminary feature staging
This partially implements the feature staging described in the
[release channel RFC][rc]. It does not yet fully conform to the RFC as
written, but does accomplish its goals sufficiently for the 1.0 alpha
release.
It has three primary user-visible effects:
* On the nightly channel, use of unstable APIs generates a warning.
* On the beta channel, use of unstable APIs generates a warning.
* On the beta channel, use of feature gates generates a warning.
Code that does not trigger these warnings is considered 'stable',
modulo pre-1.0 bugs.
Disabling the warnings for unstable APIs continues to be done in the
existing (i.e. old) style, via `#[allow(...)]`, not that specified in
the RFC. I deem this marginally acceptable since any code that must do
this is not using the stable dialect of Rust.
Use of feature gates is itself gated with the new 'unstable_features'
lint, on nightly set to 'allow', and on beta 'warn'.
The attribute scheme used here corresponds to an older version of the
RFC, with the `#[staged_api]` crate attribute toggling the staging
behavior of the stability attributes, but the user impact is only
in-tree so I'm not concerned about having to make design changes later
(and I may ultimately prefer the scheme here after all, with the
`#[staged_api]` crate attribute).
Since the Rust codebase itself makes use of unstable features the
compiler and build system to a midly elaborate dance to allow it to
bootstrap while disobeying these lints (which would otherwise be
errors because Rust builds with `-D warnings`).
This patch includes one significant hack that causes a
regression. Because the `format_args!` macro emits calls to unstable
APIs it would trigger the lint. I added a hack to the lint to make it
not trigger, but this in turn causes arguments to `println!` not to be
checked for feature gates. I don't presently understand macro
expansion well enough to fix. This is bug #20661.
Closes #16678
[rc]: https://github.com/rust-lang/rfcs/blob/master/text/0507-release-channels.md
2015-01-06 06:26:08 -08:00
|
|
|
use lint::{Default, CommandLine, Node, Allow, Warn, Deny, Forbid, ReleaseChannel};
|
2014-06-06 15:49:48 -07:00
|
|
|
use lint::builtin;
|
2014-11-10 00:59:56 +02:00
|
|
|
use util::nodemap::FnvHashMap;
|
2014-06-06 15:49:48 -07:00
|
|
|
|
|
|
|
use std::cell::RefCell;
|
|
|
|
use std::mem;
|
|
|
|
use syntax::ast_util::IdVisitingOperation;
|
|
|
|
use syntax::attr::AttrMetaMethods;
|
|
|
|
use syntax::attr;
|
|
|
|
use syntax::codemap::Span;
|
|
|
|
use syntax::visit::{Visitor, FnKind};
|
2014-06-13 15:03:26 -07:00
|
|
|
use syntax::parse::token::InternedString;
|
2014-06-06 15:49:48 -07:00
|
|
|
use syntax::{ast, ast_util, visit};
|
|
|
|
|
|
|
|
/// Information about the registered lints.
|
|
|
|
///
|
|
|
|
/// This is basically the subset of `Context` that we can
|
|
|
|
/// build early in the compile pipeline.
|
|
|
|
pub struct LintStore {
|
|
|
|
/// Registered lints. The bool is true if the lint was
|
|
|
|
/// added by a plugin.
|
|
|
|
lints: Vec<(&'static Lint, bool)>,
|
|
|
|
|
|
|
|
/// Trait objects for each lint pass.
|
2014-06-13 00:00:49 -07:00
|
|
|
/// This is only `None` while iterating over the objects. See the definition
|
|
|
|
/// of run_lints.
|
|
|
|
passes: Option<Vec<LintPassObject>>,
|
2014-06-06 15:49:48 -07:00
|
|
|
|
|
|
|
/// Lints indexed by name.
|
2014-11-10 00:59:56 +02:00
|
|
|
by_name: FnvHashMap<String, TargetLint>,
|
2014-06-06 15:49:48 -07:00
|
|
|
|
|
|
|
/// Current levels of each lint, and where they were set.
|
2014-11-10 00:59:56 +02:00
|
|
|
levels: FnvHashMap<LintId, LevelSource>,
|
2014-07-21 15:27:59 +12:00
|
|
|
|
|
|
|
/// Map of registered lint groups to what lints they expand to. The bool
|
|
|
|
/// is true if the lint group was added by a plugin.
|
2014-11-10 00:59:56 +02:00
|
|
|
lint_groups: FnvHashMap<&'static str, (Vec<LintId>, bool)>,
|
2014-06-06 15:49:48 -07:00
|
|
|
}
|
|
|
|
|
2014-10-14 11:32:31 -07:00
|
|
|
/// The targed of the `by_name` map, which accounts for renaming/deprecation.
|
|
|
|
enum TargetLint {
|
|
|
|
/// A direct lint target
|
|
|
|
Id(LintId),
|
|
|
|
|
|
|
|
/// Temporary renaming, used for easing migration pain; see #16545
|
|
|
|
Renamed(String, LintId),
|
|
|
|
}
|
|
|
|
|
2014-06-06 15:49:48 -07:00
|
|
|
impl LintStore {
|
|
|
|
fn get_level_source(&self, lint: LintId) -> LevelSource {
|
2014-11-06 12:25:16 -05:00
|
|
|
match self.levels.get(&lint) {
|
2014-06-06 15:49:48 -07:00
|
|
|
Some(&s) => s,
|
|
|
|
None => (Allow, Default),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn set_level(&mut self, lint: LintId, lvlsrc: LevelSource) {
|
2014-12-09 12:21:18 -05:00
|
|
|
if lvlsrc.0 == Allow {
|
2014-06-06 15:49:48 -07:00
|
|
|
self.levels.remove(&lint);
|
|
|
|
} else {
|
|
|
|
self.levels.insert(lint, lvlsrc);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn new() -> LintStore {
|
|
|
|
LintStore {
|
|
|
|
lints: vec!(),
|
2014-06-13 00:00:49 -07:00
|
|
|
passes: Some(vec!()),
|
2014-11-10 00:59:56 +02:00
|
|
|
by_name: FnvHashMap::new(),
|
|
|
|
levels: FnvHashMap::new(),
|
|
|
|
lint_groups: FnvHashMap::new(),
|
2014-06-06 15:49:48 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn get_lints<'t>(&'t self) -> &'t [(&'static Lint, bool)] {
|
2015-01-07 11:58:31 -05:00
|
|
|
&self.lints[]
|
2014-06-06 15:49:48 -07:00
|
|
|
}
|
|
|
|
|
2014-07-21 15:27:59 +12:00
|
|
|
pub fn get_lint_groups<'t>(&'t self) -> Vec<(&'static str, Vec<LintId>, bool)> {
|
2014-09-05 01:24:04 +01:00
|
|
|
self.lint_groups.iter().map(|(k, v)| (*k,
|
2014-12-09 12:21:18 -05:00
|
|
|
v.0.clone(),
|
|
|
|
v.1)).collect()
|
2014-07-21 15:27:59 +12:00
|
|
|
}
|
|
|
|
|
2014-06-06 15:49:48 -07:00
|
|
|
pub fn register_pass(&mut self, sess: Option<&Session>,
|
|
|
|
from_plugin: bool, pass: LintPassObject) {
|
|
|
|
for &lint in pass.get_lints().iter() {
|
2014-10-06 17:30:54 -07:00
|
|
|
self.lints.push((*lint, from_plugin));
|
2014-06-06 15:49:48 -07:00
|
|
|
|
2014-10-06 17:30:54 -07:00
|
|
|
let id = LintId::of(*lint);
|
2014-11-06 12:25:16 -05:00
|
|
|
if self.by_name.insert(lint.name_lower(), Id(id)).is_some() {
|
2014-06-13 13:04:52 -07:00
|
|
|
let msg = format!("duplicate specification of lint {}", lint.name_lower());
|
2014-06-06 15:49:48 -07:00
|
|
|
match (sess, from_plugin) {
|
|
|
|
// We load builtin lints first, so a duplicate is a compiler bug.
|
|
|
|
// Use early_error when handling -W help with no crate.
|
2015-01-07 11:58:31 -05:00
|
|
|
(None, _) => early_error(&msg[]),
|
|
|
|
(Some(sess), false) => sess.bug(&msg[]),
|
2014-06-06 15:49:48 -07:00
|
|
|
|
|
|
|
// A duplicate name from a plugin is a user error.
|
2015-01-07 11:58:31 -05:00
|
|
|
(Some(sess), true) => sess.err(&msg[]),
|
2014-06-06 15:49:48 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if lint.default_level != Allow {
|
|
|
|
self.levels.insert(id, (lint.default_level, Default));
|
|
|
|
}
|
|
|
|
}
|
2014-10-14 23:05:01 -07:00
|
|
|
self.passes.as_mut().unwrap().push(pass);
|
2014-06-06 15:49:48 -07:00
|
|
|
}
|
|
|
|
|
2014-07-21 15:27:59 +12:00
|
|
|
pub fn register_group(&mut self, sess: Option<&Session>,
|
|
|
|
from_plugin: bool, name: &'static str,
|
|
|
|
to: Vec<LintId>) {
|
2014-11-06 12:25:16 -05:00
|
|
|
let new = self.lint_groups.insert(name, (to, from_plugin)).is_none();
|
2014-07-21 15:27:59 +12:00
|
|
|
|
|
|
|
if !new {
|
|
|
|
let msg = format!("duplicate specification of lint group {}", name);
|
|
|
|
match (sess, from_plugin) {
|
|
|
|
// We load builtin lints first, so a duplicate is a compiler bug.
|
|
|
|
// Use early_error when handling -W help with no crate.
|
2015-01-07 11:58:31 -05:00
|
|
|
(None, _) => early_error(&msg[]),
|
|
|
|
(Some(sess), false) => sess.bug(&msg[]),
|
2014-07-21 15:27:59 +12:00
|
|
|
|
|
|
|
// A duplicate name from a plugin is a user error.
|
2015-01-07 11:58:31 -05:00
|
|
|
(Some(sess), true) => sess.err(&msg[]),
|
2014-07-21 15:27:59 +12:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-10-14 11:32:31 -07:00
|
|
|
fn register_renamed(&mut self, old_name: &str, new_name: &str) {
|
2014-11-12 15:51:51 -08:00
|
|
|
let target = match self.by_name.get(new_name) {
|
2014-10-14 11:32:31 -07:00
|
|
|
Some(&Id(lint_id)) => lint_id.clone(),
|
2014-10-09 15:17:22 -04:00
|
|
|
_ => panic!("invalid lint renaming of {} to {}", old_name, new_name)
|
2014-10-14 11:32:31 -07:00
|
|
|
};
|
|
|
|
self.by_name.insert(old_name.to_string(), Renamed(new_name.to_string(), target));
|
|
|
|
}
|
|
|
|
|
2014-06-06 15:49:48 -07:00
|
|
|
pub fn register_builtin(&mut self, sess: Option<&Session>) {
|
2015-01-02 14:44:21 -08:00
|
|
|
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)),*]);
|
|
|
|
)
|
|
|
|
}
|
2014-07-21 15:27:59 +12:00
|
|
|
|
2014-06-18 12:35:48 -07:00
|
|
|
add_builtin!(sess,
|
|
|
|
HardwiredLints,
|
|
|
|
WhileTrue,
|
|
|
|
UnusedCasts,
|
2014-10-14 11:37:16 -07:00
|
|
|
ImproperCTypes,
|
|
|
|
BoxPointers,
|
|
|
|
UnusedAttributes,
|
|
|
|
PathStatements,
|
|
|
|
UnusedResults,
|
2014-06-18 12:35:48 -07:00
|
|
|
NonCamelCaseTypes,
|
2014-07-19 00:45:17 +12:00
|
|
|
NonSnakeCase,
|
2014-10-14 11:37:16 -07:00
|
|
|
NonUpperCaseGlobals,
|
|
|
|
UnusedParens,
|
|
|
|
UnusedImportBraces,
|
2014-10-06 13:36:53 +13:00
|
|
|
NonShorthandFieldPatterns,
|
2014-06-18 12:35:48 -07:00
|
|
|
UnusedUnsafe,
|
2014-10-14 11:37:16 -07:00
|
|
|
UnsafeBlocks,
|
2014-06-18 12:35:48 -07:00
|
|
|
UnusedMut,
|
2014-10-14 11:37:16 -07:00
|
|
|
UnusedAllocation,
|
librustc: Make `Copy` opt-in.
This change makes the compiler no longer infer whether types (structures
and enumerations) implement the `Copy` trait (and thus are implicitly
copyable). Rather, you must implement `Copy` yourself via `impl Copy for
MyType {}`.
A new warning has been added, `missing_copy_implementations`, to warn
you if a non-generic public type has been added that could have
implemented `Copy` but didn't.
For convenience, you may *temporarily* opt out of this behavior by using
`#![feature(opt_out_copy)]`. Note though that this feature gate will never be
accepted and will be removed by the time that 1.0 is released, so you should
transition your code away from using it.
This breaks code like:
#[deriving(Show)]
struct Point2D {
x: int,
y: int,
}
fn main() {
let mypoint = Point2D {
x: 1,
y: 1,
};
let otherpoint = mypoint;
println!("{}{}", mypoint, otherpoint);
}
Change this code to:
#[deriving(Show)]
struct Point2D {
x: int,
y: int,
}
impl Copy for Point2D {}
fn main() {
let mypoint = Point2D {
x: 1,
y: 1,
};
let otherpoint = mypoint;
println!("{}{}", mypoint, otherpoint);
}
This is the backwards-incompatible part of #13231.
Part of RFC #3.
[breaking-change]
2014-12-05 17:01:33 -08:00
|
|
|
MissingCopyImplementations,
|
Preliminary feature staging
This partially implements the feature staging described in the
[release channel RFC][rc]. It does not yet fully conform to the RFC as
written, but does accomplish its goals sufficiently for the 1.0 alpha
release.
It has three primary user-visible effects:
* On the nightly channel, use of unstable APIs generates a warning.
* On the beta channel, use of unstable APIs generates a warning.
* On the beta channel, use of feature gates generates a warning.
Code that does not trigger these warnings is considered 'stable',
modulo pre-1.0 bugs.
Disabling the warnings for unstable APIs continues to be done in the
existing (i.e. old) style, via `#[allow(...)]`, not that specified in
the RFC. I deem this marginally acceptable since any code that must do
this is not using the stable dialect of Rust.
Use of feature gates is itself gated with the new 'unstable_features'
lint, on nightly set to 'allow', and on beta 'warn'.
The attribute scheme used here corresponds to an older version of the
RFC, with the `#[staged_api]` crate attribute toggling the staging
behavior of the stability attributes, but the user impact is only
in-tree so I'm not concerned about having to make design changes later
(and I may ultimately prefer the scheme here after all, with the
`#[staged_api]` crate attribute).
Since the Rust codebase itself makes use of unstable features the
compiler and build system to a midly elaborate dance to allow it to
bootstrap while disobeying these lints (which would otherwise be
errors because Rust builds with `-D warnings`).
This patch includes one significant hack that causes a
regression. Because the `format_args!` macro emits calls to unstable
APIs it would trigger the lint. I added a hack to the lint to make it
not trigger, but this in turn causes arguments to `println!` not to be
checked for feature gates. I don't presently understand macro
expansion well enough to fix. This is bug #20661.
Closes #16678
[rc]: https://github.com/rust-lang/rfcs/blob/master/text/0507-release-channels.md
2015-01-06 06:26:08 -08:00
|
|
|
UnstableFeatures,
|
2014-11-14 09:18:10 -08:00
|
|
|
);
|
2014-06-12 22:20:47 -07:00
|
|
|
|
|
|
|
add_builtin_with_new!(sess,
|
2014-06-18 12:35:48 -07:00
|
|
|
TypeLimits,
|
2015-01-04 00:09:18 -06:00
|
|
|
RawPointerDerive,
|
2014-06-18 12:35:48 -07:00
|
|
|
MissingDoc,
|
2015-01-07 15:48:16 -08:00
|
|
|
Stability,
|
2014-11-14 09:18:10 -08:00
|
|
|
);
|
2014-06-06 15:49:48 -07:00
|
|
|
|
2014-07-21 15:27:59 +12:00
|
|
|
add_lint_group!(sess, "bad_style",
|
2014-11-14 09:18:10 -08:00
|
|
|
NON_CAMEL_CASE_TYPES, NON_SNAKE_CASE, NON_UPPER_CASE_GLOBALS);
|
2014-07-21 15:27:59 +12:00
|
|
|
|
|
|
|
add_lint_group!(sess, "unused",
|
2014-10-14 11:37:16 -07:00
|
|
|
UNUSED_IMPORTS, UNUSED_VARIABLES, UNUSED_ASSIGNMENTS, DEAD_CODE,
|
2014-10-11 14:27:37 +13:00
|
|
|
UNUSED_MUT, UNREACHABLE_CODE, UNUSED_MUST_USE,
|
2014-11-14 09:18:10 -08:00
|
|
|
UNUSED_UNSAFE, PATH_STATEMENTS);
|
2014-07-21 15:27:59 +12:00
|
|
|
|
2014-06-06 15:49:48 -07:00
|
|
|
// We have one lint pass defined in this module.
|
|
|
|
self.register_pass(sess, false, box GatherNodeLevels as LintPassObject);
|
2014-10-14 11:32:31 -07:00
|
|
|
|
|
|
|
// Insert temporary renamings for a one-time deprecation (#16545)
|
|
|
|
self.register_renamed("unnecessary_typecast", "unused_typecasts");
|
|
|
|
self.register_renamed("unsigned_negate", "unsigned_negation");
|
|
|
|
self.register_renamed("type_limits", "unused_comparisons");
|
|
|
|
self.register_renamed("type_overflow", "overflowing_literals");
|
|
|
|
self.register_renamed("ctypes", "improper_ctypes");
|
|
|
|
self.register_renamed("owned_heap_memory", "box_pointers");
|
|
|
|
self.register_renamed("unused_attribute", "unused_attributes");
|
|
|
|
self.register_renamed("path_statement", "path_statements");
|
|
|
|
self.register_renamed("unused_result", "unused_results");
|
|
|
|
self.register_renamed("non_uppercase_statics", "non_upper_case_globals");
|
|
|
|
self.register_renamed("unnecessary_parens", "unused_parens");
|
|
|
|
self.register_renamed("unnecessary_import_braces", "unused_import_braces");
|
|
|
|
self.register_renamed("unsafe_block", "unsafe_blocks");
|
|
|
|
self.register_renamed("unnecessary_allocation", "unused_allocation");
|
|
|
|
self.register_renamed("missing_doc", "missing_docs");
|
|
|
|
self.register_renamed("unused_extern_crate", "unused_extern_crates");
|
|
|
|
self.register_renamed("unnecessary_qualification", "unused_qualifications");
|
|
|
|
self.register_renamed("unrecognized_lint", "unknown_lints");
|
|
|
|
self.register_renamed("unused_variable", "unused_variables");
|
|
|
|
self.register_renamed("dead_assignment", "unused_assignments");
|
|
|
|
self.register_renamed("unknown_crate_type", "unknown_crate_types");
|
|
|
|
self.register_renamed("variant_size_difference", "variant_size_differences");
|
|
|
|
self.register_renamed("transmute_fat_ptr", "fat_ptr_transmutes");
|
2015-01-04 00:09:18 -06:00
|
|
|
self.register_renamed("raw_pointer_deriving", "raw_pointer_derive");
|
2014-10-14 11:32:31 -07:00
|
|
|
|
|
|
|
}
|
|
|
|
|
2014-10-30 09:13:02 -07:00
|
|
|
#[allow(unused_variables)]
|
2014-10-14 11:32:31 -07:00
|
|
|
fn find_lint(&self, lint_name: &str, sess: &Session, span: Option<Span>)
|
|
|
|
-> Option<LintId>
|
|
|
|
{
|
2014-11-12 15:51:51 -08:00
|
|
|
match self.by_name.get(lint_name) {
|
2014-10-14 11:32:31 -07:00
|
|
|
Some(&Id(lint_id)) => Some(lint_id),
|
|
|
|
Some(&Renamed(ref new_name, lint_id)) => {
|
2014-10-27 15:37:29 -07:00
|
|
|
let warning = format!("lint {} has been renamed to {}",
|
|
|
|
lint_name, new_name);
|
|
|
|
match span {
|
2015-01-07 11:58:31 -05:00
|
|
|
Some(span) => sess.span_warn(span, &warning[]),
|
|
|
|
None => sess.warn(&warning[]),
|
2014-10-27 15:37:29 -07:00
|
|
|
};
|
2014-10-14 11:32:31 -07:00
|
|
|
Some(lint_id)
|
|
|
|
}
|
|
|
|
None => None
|
|
|
|
}
|
2014-06-06 15:49:48 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
pub fn process_command_line(&mut self, sess: &Session) {
|
|
|
|
for &(ref lint_name, level) in sess.opts.lint_opts.iter() {
|
2015-01-07 11:58:31 -05:00
|
|
|
match self.find_lint(&lint_name[], sess, None) {
|
2014-10-14 11:32:31 -07:00
|
|
|
Some(lint_id) => self.set_level(lint_id, (level, CommandLine)),
|
2014-07-21 15:27:59 +12:00
|
|
|
None => {
|
2014-12-09 12:21:18 -05:00
|
|
|
match self.lint_groups.iter().map(|(&x, pair)| (x, pair.0.clone()))
|
2014-11-10 00:59:56 +02:00
|
|
|
.collect::<FnvHashMap<&'static str,
|
|
|
|
Vec<LintId>>>()
|
2015-01-07 11:58:31 -05:00
|
|
|
.get(&lint_name[]) {
|
2014-07-21 15:27:59 +12:00
|
|
|
Some(v) => {
|
|
|
|
v.iter()
|
|
|
|
.map(|lint_id: &LintId|
|
|
|
|
self.set_level(*lint_id, (level, CommandLine)))
|
|
|
|
.collect::<Vec<()>>();
|
|
|
|
}
|
2015-01-07 11:58:31 -05:00
|
|
|
None => sess.err(&format!("unknown {} flag: {}",
|
|
|
|
level.as_str(), lint_name)[]),
|
2014-07-21 15:27:59 +12:00
|
|
|
}
|
|
|
|
}
|
2014-06-06 15:49:48 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
Preliminary feature staging
This partially implements the feature staging described in the
[release channel RFC][rc]. It does not yet fully conform to the RFC as
written, but does accomplish its goals sufficiently for the 1.0 alpha
release.
It has three primary user-visible effects:
* On the nightly channel, use of unstable APIs generates a warning.
* On the beta channel, use of unstable APIs generates a warning.
* On the beta channel, use of feature gates generates a warning.
Code that does not trigger these warnings is considered 'stable',
modulo pre-1.0 bugs.
Disabling the warnings for unstable APIs continues to be done in the
existing (i.e. old) style, via `#[allow(...)]`, not that specified in
the RFC. I deem this marginally acceptable since any code that must do
this is not using the stable dialect of Rust.
Use of feature gates is itself gated with the new 'unstable_features'
lint, on nightly set to 'allow', and on beta 'warn'.
The attribute scheme used here corresponds to an older version of the
RFC, with the `#[staged_api]` crate attribute toggling the staging
behavior of the stability attributes, but the user impact is only
in-tree so I'm not concerned about having to make design changes later
(and I may ultimately prefer the scheme here after all, with the
`#[staged_api]` crate attribute).
Since the Rust codebase itself makes use of unstable features the
compiler and build system to a midly elaborate dance to allow it to
bootstrap while disobeying these lints (which would otherwise be
errors because Rust builds with `-D warnings`).
This patch includes one significant hack that causes a
regression. Because the `format_args!` macro emits calls to unstable
APIs it would trigger the lint. I added a hack to the lint to make it
not trigger, but this in turn causes arguments to `println!` not to be
checked for feature gates. I don't presently understand macro
expansion well enough to fix. This is bug #20661.
Closes #16678
[rc]: https://github.com/rust-lang/rfcs/blob/master/text/0507-release-channels.md
2015-01-06 06:26:08 -08:00
|
|
|
|
|
|
|
fn maybe_stage_features(&mut self, sess: &Session) {
|
|
|
|
let lvl = match sess.opts.unstable_features {
|
|
|
|
UnstableFeatures::Default => return,
|
|
|
|
UnstableFeatures::Disallow => Warn,
|
|
|
|
UnstableFeatures::Cheat => Allow
|
|
|
|
};
|
|
|
|
match self.by_name.get("unstable_features") {
|
2015-01-07 15:48:16 -08:00
|
|
|
Some(&Id(lint_id)) => if self.get_level_source(lint_id).0 != Forbid {
|
|
|
|
self.set_level(lint_id, (lvl, ReleaseChannel))
|
|
|
|
},
|
|
|
|
Some(&Renamed(_, lint_id)) => if self.get_level_source(lint_id).0 != Forbid {
|
|
|
|
self.set_level(lint_id, (lvl, ReleaseChannel))
|
|
|
|
},
|
Preliminary feature staging
This partially implements the feature staging described in the
[release channel RFC][rc]. It does not yet fully conform to the RFC as
written, but does accomplish its goals sufficiently for the 1.0 alpha
release.
It has three primary user-visible effects:
* On the nightly channel, use of unstable APIs generates a warning.
* On the beta channel, use of unstable APIs generates a warning.
* On the beta channel, use of feature gates generates a warning.
Code that does not trigger these warnings is considered 'stable',
modulo pre-1.0 bugs.
Disabling the warnings for unstable APIs continues to be done in the
existing (i.e. old) style, via `#[allow(...)]`, not that specified in
the RFC. I deem this marginally acceptable since any code that must do
this is not using the stable dialect of Rust.
Use of feature gates is itself gated with the new 'unstable_features'
lint, on nightly set to 'allow', and on beta 'warn'.
The attribute scheme used here corresponds to an older version of the
RFC, with the `#[staged_api]` crate attribute toggling the staging
behavior of the stability attributes, but the user impact is only
in-tree so I'm not concerned about having to make design changes later
(and I may ultimately prefer the scheme here after all, with the
`#[staged_api]` crate attribute).
Since the Rust codebase itself makes use of unstable features the
compiler and build system to a midly elaborate dance to allow it to
bootstrap while disobeying these lints (which would otherwise be
errors because Rust builds with `-D warnings`).
This patch includes one significant hack that causes a
regression. Because the `format_args!` macro emits calls to unstable
APIs it would trigger the lint. I added a hack to the lint to make it
not trigger, but this in turn causes arguments to `println!` not to be
checked for feature gates. I don't presently understand macro
expansion well enough to fix. This is bug #20661.
Closes #16678
[rc]: https://github.com/rust-lang/rfcs/blob/master/text/0507-release-channels.md
2015-01-06 06:26:08 -08:00
|
|
|
None => unreachable!()
|
|
|
|
}
|
2015-01-07 15:48:16 -08:00
|
|
|
match self.by_name.get("unstable") {
|
|
|
|
Some(&Id(lint_id)) => if self.get_level_source(lint_id).0 != Forbid {
|
|
|
|
self.set_level(lint_id, (lvl, ReleaseChannel))
|
|
|
|
},
|
|
|
|
Some(&Renamed(_, lint_id)) => if self.get_level_source(lint_id).0 != Forbid {
|
|
|
|
self.set_level(lint_id, (lvl, ReleaseChannel))
|
|
|
|
},
|
Preliminary feature staging
This partially implements the feature staging described in the
[release channel RFC][rc]. It does not yet fully conform to the RFC as
written, but does accomplish its goals sufficiently for the 1.0 alpha
release.
It has three primary user-visible effects:
* On the nightly channel, use of unstable APIs generates a warning.
* On the beta channel, use of unstable APIs generates a warning.
* On the beta channel, use of feature gates generates a warning.
Code that does not trigger these warnings is considered 'stable',
modulo pre-1.0 bugs.
Disabling the warnings for unstable APIs continues to be done in the
existing (i.e. old) style, via `#[allow(...)]`, not that specified in
the RFC. I deem this marginally acceptable since any code that must do
this is not using the stable dialect of Rust.
Use of feature gates is itself gated with the new 'unstable_features'
lint, on nightly set to 'allow', and on beta 'warn'.
The attribute scheme used here corresponds to an older version of the
RFC, with the `#[staged_api]` crate attribute toggling the staging
behavior of the stability attributes, but the user impact is only
in-tree so I'm not concerned about having to make design changes later
(and I may ultimately prefer the scheme here after all, with the
`#[staged_api]` crate attribute).
Since the Rust codebase itself makes use of unstable features the
compiler and build system to a midly elaborate dance to allow it to
bootstrap while disobeying these lints (which would otherwise be
errors because Rust builds with `-D warnings`).
This patch includes one significant hack that causes a
regression. Because the `format_args!` macro emits calls to unstable
APIs it would trigger the lint. I added a hack to the lint to make it
not trigger, but this in turn causes arguments to `println!` not to be
checked for feature gates. I don't presently understand macro
expansion well enough to fix. This is bug #20661.
Closes #16678
[rc]: https://github.com/rust-lang/rfcs/blob/master/text/0507-release-channels.md
2015-01-06 06:26:08 -08:00
|
|
|
None => unreachable!()
|
|
|
|
}
|
|
|
|
}
|
2014-06-06 15:49:48 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Context for lint checking.
|
2014-04-22 15:56:37 +03:00
|
|
|
pub struct Context<'a, 'tcx: 'a> {
|
2014-06-06 15:49:48 -07:00
|
|
|
/// Type context we're checking in.
|
2014-04-22 15:56:37 +03:00
|
|
|
pub tcx: &'a ty::ctxt<'tcx>,
|
2014-06-06 15:49:48 -07:00
|
|
|
|
2014-06-17 16:55:34 -07:00
|
|
|
/// The crate being checked.
|
|
|
|
pub krate: &'a ast::Crate,
|
|
|
|
|
|
|
|
/// Items exported from the crate being checked.
|
|
|
|
pub exported_items: &'a ExportedItems,
|
|
|
|
|
2014-06-06 15:49:48 -07:00
|
|
|
/// The store of registered lints.
|
|
|
|
lints: LintStore,
|
|
|
|
|
|
|
|
/// When recursing into an attributed node of the ast which modifies lint
|
|
|
|
/// levels, this stack keeps track of the previous lint levels of whatever
|
|
|
|
/// was modified.
|
|
|
|
level_stack: Vec<(LintId, LevelSource)>,
|
|
|
|
|
|
|
|
/// Level of lints for certain NodeIds, stored here because the body of
|
|
|
|
/// the lint needs to run in trans.
|
2014-11-10 00:59:56 +02:00
|
|
|
node_levels: RefCell<FnvHashMap<(ast::NodeId, LintId), LevelSource>>,
|
2014-06-06 15:49:48 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Convenience macro for calling a `LintPass` method on every pass in the context.
|
2014-11-14 09:18:10 -08:00
|
|
|
macro_rules! run_lints { ($cx:expr, $f:ident, $($args:expr),*) => ({
|
2014-06-13 00:00:49 -07:00
|
|
|
// Move the vector of passes out of `$cx` so that we can
|
|
|
|
// iterate over it mutably while passing `$cx` to the methods.
|
2014-08-18 17:52:38 -07:00
|
|
|
let mut passes = $cx.lints.passes.take().unwrap();
|
2014-09-14 20:27:36 -07:00
|
|
|
for obj in passes.iter_mut() {
|
2014-06-13 00:00:49 -07:00
|
|
|
obj.$f($cx, $($args),*);
|
2014-06-06 15:49:48 -07:00
|
|
|
}
|
2014-06-13 00:00:49 -07:00
|
|
|
$cx.lints.passes = Some(passes);
|
2014-11-14 09:18:10 -08:00
|
|
|
}) }
|
2014-06-06 15:49:48 -07:00
|
|
|
|
2014-06-13 15:03:26 -07:00
|
|
|
/// Parse the lint attributes into a vector, with `Err`s for malformed lint
|
|
|
|
/// attributes. Writing this as an iterator is an enormous mess.
|
|
|
|
pub fn gather_attrs(attrs: &[ast::Attribute])
|
|
|
|
-> Vec<Result<(InternedString, Level, Span), Span>> {
|
|
|
|
let mut out = vec!();
|
|
|
|
for attr in attrs.iter() {
|
|
|
|
let level = match Level::from_str(attr.name().get()) {
|
|
|
|
None => continue,
|
|
|
|
Some(lvl) => lvl,
|
|
|
|
};
|
|
|
|
|
|
|
|
attr::mark_used(attr);
|
|
|
|
|
2014-09-07 20:09:06 +03:00
|
|
|
let meta = &attr.node.value;
|
2014-06-13 15:03:26 -07:00
|
|
|
let metas = match meta.node {
|
|
|
|
ast::MetaList(_, ref metas) => metas,
|
|
|
|
_ => {
|
|
|
|
out.push(Err(meta.span));
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
for meta in metas.iter() {
|
|
|
|
out.push(match meta.node {
|
|
|
|
ast::MetaWord(ref lint_name) => Ok((lint_name.clone(), level, meta.span)),
|
|
|
|
_ => Err(meta.span),
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
out
|
|
|
|
}
|
|
|
|
|
2014-06-06 15:49:48 -07:00
|
|
|
/// Emit a lint as a warning or an error (or not at all)
|
|
|
|
/// according to `level`.
|
|
|
|
///
|
|
|
|
/// This lives outside of `Context` so it can be used by checks
|
|
|
|
/// in trans that run after the main lint pass is finished. Most
|
|
|
|
/// lints elsewhere in the compiler should call
|
|
|
|
/// `Session::add_lint()` instead.
|
|
|
|
pub fn raw_emit_lint(sess: &Session, lint: &'static Lint,
|
|
|
|
lvlsrc: LevelSource, span: Option<Span>, msg: &str) {
|
|
|
|
let (mut level, source) = lvlsrc;
|
|
|
|
if level == Allow { return }
|
|
|
|
|
2014-06-13 13:04:52 -07:00
|
|
|
let name = lint.name_lower();
|
Preliminary feature staging
This partially implements the feature staging described in the
[release channel RFC][rc]. It does not yet fully conform to the RFC as
written, but does accomplish its goals sufficiently for the 1.0 alpha
release.
It has three primary user-visible effects:
* On the nightly channel, use of unstable APIs generates a warning.
* On the beta channel, use of unstable APIs generates a warning.
* On the beta channel, use of feature gates generates a warning.
Code that does not trigger these warnings is considered 'stable',
modulo pre-1.0 bugs.
Disabling the warnings for unstable APIs continues to be done in the
existing (i.e. old) style, via `#[allow(...)]`, not that specified in
the RFC. I deem this marginally acceptable since any code that must do
this is not using the stable dialect of Rust.
Use of feature gates is itself gated with the new 'unstable_features'
lint, on nightly set to 'allow', and on beta 'warn'.
The attribute scheme used here corresponds to an older version of the
RFC, with the `#[staged_api]` crate attribute toggling the staging
behavior of the stability attributes, but the user impact is only
in-tree so I'm not concerned about having to make design changes later
(and I may ultimately prefer the scheme here after all, with the
`#[staged_api]` crate attribute).
Since the Rust codebase itself makes use of unstable features the
compiler and build system to a midly elaborate dance to allow it to
bootstrap while disobeying these lints (which would otherwise be
errors because Rust builds with `-D warnings`).
This patch includes one significant hack that causes a
regression. Because the `format_args!` macro emits calls to unstable
APIs it would trigger the lint. I added a hack to the lint to make it
not trigger, but this in turn causes arguments to `println!` not to be
checked for feature gates. I don't presently understand macro
expansion well enough to fix. This is bug #20661.
Closes #16678
[rc]: https://github.com/rust-lang/rfcs/blob/master/text/0507-release-channels.md
2015-01-06 06:26:08 -08:00
|
|
|
let mut def = None;
|
2014-06-06 15:49:48 -07:00
|
|
|
let mut note = None;
|
|
|
|
let msg = match source {
|
|
|
|
Default => {
|
|
|
|
format!("{}, #[{}({})] on by default", msg,
|
2014-06-17 17:41:50 -07:00
|
|
|
level.as_str(), name)
|
2014-06-06 15:49:48 -07:00
|
|
|
},
|
|
|
|
CommandLine => {
|
|
|
|
format!("{} [-{} {}]", msg,
|
2014-06-17 17:41:50 -07:00
|
|
|
match level {
|
|
|
|
Warn => 'W', Deny => 'D', Forbid => 'F',
|
2014-10-09 15:17:22 -04:00
|
|
|
Allow => panic!()
|
2014-06-17 17:41:50 -07:00
|
|
|
}, name.replace("_", "-"))
|
2014-06-06 15:49:48 -07:00
|
|
|
},
|
|
|
|
Node(src) => {
|
Preliminary feature staging
This partially implements the feature staging described in the
[release channel RFC][rc]. It does not yet fully conform to the RFC as
written, but does accomplish its goals sufficiently for the 1.0 alpha
release.
It has three primary user-visible effects:
* On the nightly channel, use of unstable APIs generates a warning.
* On the beta channel, use of unstable APIs generates a warning.
* On the beta channel, use of feature gates generates a warning.
Code that does not trigger these warnings is considered 'stable',
modulo pre-1.0 bugs.
Disabling the warnings for unstable APIs continues to be done in the
existing (i.e. old) style, via `#[allow(...)]`, not that specified in
the RFC. I deem this marginally acceptable since any code that must do
this is not using the stable dialect of Rust.
Use of feature gates is itself gated with the new 'unstable_features'
lint, on nightly set to 'allow', and on beta 'warn'.
The attribute scheme used here corresponds to an older version of the
RFC, with the `#[staged_api]` crate attribute toggling the staging
behavior of the stability attributes, but the user impact is only
in-tree so I'm not concerned about having to make design changes later
(and I may ultimately prefer the scheme here after all, with the
`#[staged_api]` crate attribute).
Since the Rust codebase itself makes use of unstable features the
compiler and build system to a midly elaborate dance to allow it to
bootstrap while disobeying these lints (which would otherwise be
errors because Rust builds with `-D warnings`).
This patch includes one significant hack that causes a
regression. Because the `format_args!` macro emits calls to unstable
APIs it would trigger the lint. I added a hack to the lint to make it
not trigger, but this in turn causes arguments to `println!` not to be
checked for feature gates. I don't presently understand macro
expansion well enough to fix. This is bug #20661.
Closes #16678
[rc]: https://github.com/rust-lang/rfcs/blob/master/text/0507-release-channels.md
2015-01-06 06:26:08 -08:00
|
|
|
def = Some(src);
|
|
|
|
msg.to_string()
|
|
|
|
}
|
|
|
|
ReleaseChannel => {
|
|
|
|
let release_channel = option_env!("CFG_RELEASE_CHANNEL").unwrap_or("(unknown)");
|
|
|
|
note = Some(format!("this feature may not be used in the {} release channel",
|
|
|
|
release_channel));
|
2014-06-06 15:49:48 -07:00
|
|
|
msg.to_string()
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
// For purposes of printing, we can treat forbid as deny.
|
|
|
|
if level == Forbid { level = Deny; }
|
|
|
|
|
|
|
|
match (level, span) {
|
2015-01-07 11:58:31 -05:00
|
|
|
(Warn, Some(sp)) => sess.span_warn(sp, &msg[]),
|
|
|
|
(Warn, None) => sess.warn(&msg[]),
|
|
|
|
(Deny, Some(sp)) => sess.span_err(sp, &msg[]),
|
|
|
|
(Deny, None) => sess.err(&msg[]),
|
2014-06-06 15:49:48 -07:00
|
|
|
_ => sess.bug("impossible level in raw_emit_lint"),
|
|
|
|
}
|
|
|
|
|
Preliminary feature staging
This partially implements the feature staging described in the
[release channel RFC][rc]. It does not yet fully conform to the RFC as
written, but does accomplish its goals sufficiently for the 1.0 alpha
release.
It has three primary user-visible effects:
* On the nightly channel, use of unstable APIs generates a warning.
* On the beta channel, use of unstable APIs generates a warning.
* On the beta channel, use of feature gates generates a warning.
Code that does not trigger these warnings is considered 'stable',
modulo pre-1.0 bugs.
Disabling the warnings for unstable APIs continues to be done in the
existing (i.e. old) style, via `#[allow(...)]`, not that specified in
the RFC. I deem this marginally acceptable since any code that must do
this is not using the stable dialect of Rust.
Use of feature gates is itself gated with the new 'unstable_features'
lint, on nightly set to 'allow', and on beta 'warn'.
The attribute scheme used here corresponds to an older version of the
RFC, with the `#[staged_api]` crate attribute toggling the staging
behavior of the stability attributes, but the user impact is only
in-tree so I'm not concerned about having to make design changes later
(and I may ultimately prefer the scheme here after all, with the
`#[staged_api]` crate attribute).
Since the Rust codebase itself makes use of unstable features the
compiler and build system to a midly elaborate dance to allow it to
bootstrap while disobeying these lints (which would otherwise be
errors because Rust builds with `-D warnings`).
This patch includes one significant hack that causes a
regression. Because the `format_args!` macro emits calls to unstable
APIs it would trigger the lint. I added a hack to the lint to make it
not trigger, but this in turn causes arguments to `println!` not to be
checked for feature gates. I don't presently understand macro
expansion well enough to fix. This is bug #20661.
Closes #16678
[rc]: https://github.com/rust-lang/rfcs/blob/master/text/0507-release-channels.md
2015-01-06 06:26:08 -08:00
|
|
|
for note in note.into_iter() {
|
2015-01-07 18:53:58 -08:00
|
|
|
sess.note(¬e[]);
|
Preliminary feature staging
This partially implements the feature staging described in the
[release channel RFC][rc]. It does not yet fully conform to the RFC as
written, but does accomplish its goals sufficiently for the 1.0 alpha
release.
It has three primary user-visible effects:
* On the nightly channel, use of unstable APIs generates a warning.
* On the beta channel, use of unstable APIs generates a warning.
* On the beta channel, use of feature gates generates a warning.
Code that does not trigger these warnings is considered 'stable',
modulo pre-1.0 bugs.
Disabling the warnings for unstable APIs continues to be done in the
existing (i.e. old) style, via `#[allow(...)]`, not that specified in
the RFC. I deem this marginally acceptable since any code that must do
this is not using the stable dialect of Rust.
Use of feature gates is itself gated with the new 'unstable_features'
lint, on nightly set to 'allow', and on beta 'warn'.
The attribute scheme used here corresponds to an older version of the
RFC, with the `#[staged_api]` crate attribute toggling the staging
behavior of the stability attributes, but the user impact is only
in-tree so I'm not concerned about having to make design changes later
(and I may ultimately prefer the scheme here after all, with the
`#[staged_api]` crate attribute).
Since the Rust codebase itself makes use of unstable features the
compiler and build system to a midly elaborate dance to allow it to
bootstrap while disobeying these lints (which would otherwise be
errors because Rust builds with `-D warnings`).
This patch includes one significant hack that causes a
regression. Because the `format_args!` macro emits calls to unstable
APIs it would trigger the lint. I added a hack to the lint to make it
not trigger, but this in turn causes arguments to `println!` not to be
checked for feature gates. I don't presently understand macro
expansion well enough to fix. This is bug #20661.
Closes #16678
[rc]: https://github.com/rust-lang/rfcs/blob/master/text/0507-release-channels.md
2015-01-06 06:26:08 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
for span in def.into_iter() {
|
2014-06-06 15:49:48 -07:00
|
|
|
sess.span_note(span, "lint level defined here");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-04-22 15:56:37 +03:00
|
|
|
impl<'a, 'tcx> Context<'a, 'tcx> {
|
|
|
|
fn new(tcx: &'a ty::ctxt<'tcx>,
|
2014-06-17 16:55:34 -07:00
|
|
|
krate: &'a ast::Crate,
|
2014-04-22 15:56:37 +03:00
|
|
|
exported_items: &'a ExportedItems) -> Context<'a, 'tcx> {
|
2014-06-06 15:49:48 -07:00
|
|
|
// We want to own the lint store, so move it out of the session.
|
|
|
|
let lint_store = mem::replace(&mut *tcx.sess.lint_store.borrow_mut(),
|
2014-06-17 17:41:50 -07:00
|
|
|
LintStore::new());
|
2014-06-06 15:49:48 -07:00
|
|
|
|
|
|
|
Context {
|
|
|
|
tcx: tcx,
|
2014-06-17 16:55:34 -07:00
|
|
|
krate: krate,
|
|
|
|
exported_items: exported_items,
|
|
|
|
lints: lint_store,
|
2014-07-21 15:27:59 +12:00
|
|
|
level_stack: vec![],
|
2014-11-10 00:59:56 +02:00
|
|
|
node_levels: RefCell::new(FnvHashMap::new()),
|
2014-06-06 15:49:48 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Get the overall compiler `Session` object.
|
|
|
|
pub fn sess(&'a self) -> &'a Session {
|
|
|
|
&self.tcx.sess
|
|
|
|
}
|
|
|
|
|
2014-07-17 20:07:43 +10:00
|
|
|
/// Get the level of `lint` at the current position of the lint
|
|
|
|
/// traversal.
|
|
|
|
pub fn current_level(&self, lint: &'static Lint) -> Level {
|
2014-11-06 12:25:16 -05:00
|
|
|
self.lints.levels.get(&LintId::of(lint)).map_or(Allow, |&(lvl, _)| lvl)
|
2014-07-17 20:07:43 +10:00
|
|
|
}
|
|
|
|
|
2014-06-06 15:49:48 -07:00
|
|
|
fn lookup_and_emit(&self, lint: &'static Lint, span: Option<Span>, msg: &str) {
|
2014-11-06 12:25:16 -05:00
|
|
|
let (level, src) = match self.lints.levels.get(&LintId::of(lint)) {
|
2014-06-06 15:49:48 -07:00
|
|
|
None => return,
|
|
|
|
Some(&(Warn, src)) => {
|
2014-06-13 13:13:05 -07:00
|
|
|
let lint_id = LintId::of(builtin::WARNINGS);
|
2014-12-09 12:21:18 -05:00
|
|
|
(self.lints.get_level_source(lint_id).0, src)
|
2014-06-06 15:49:48 -07:00
|
|
|
}
|
|
|
|
Some(&pair) => pair,
|
|
|
|
};
|
|
|
|
|
|
|
|
raw_emit_lint(&self.tcx.sess, lint, (level, src), span, msg);
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Emit a lint at the appropriate level, with no associated span.
|
|
|
|
pub fn lint(&self, lint: &'static Lint, msg: &str) {
|
|
|
|
self.lookup_and_emit(lint, None, msg);
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Emit a lint at the appropriate level, for a particular span.
|
|
|
|
pub fn span_lint(&self, lint: &'static Lint, span: Span, msg: &str) {
|
|
|
|
self.lookup_and_emit(lint, Some(span), msg);
|
|
|
|
}
|
|
|
|
|
2014-11-24 20:06:06 -05:00
|
|
|
/// Merge the lints specified by any lint attributes into the
|
|
|
|
/// current lint context, call the provided function, then reset the
|
|
|
|
/// lints in effect to their previous state.
|
2014-12-08 20:26:43 -05:00
|
|
|
fn with_lint_attrs<F>(&mut self,
|
|
|
|
attrs: &[ast::Attribute],
|
|
|
|
f: F) where
|
|
|
|
F: FnOnce(&mut Context),
|
|
|
|
{
|
2014-06-06 15:49:48 -07:00
|
|
|
// Parse all of the lint attributes, and then add them all to the
|
|
|
|
// current dictionary of lint information. Along the way, keep a history
|
|
|
|
// of what we changed so we can roll everything back after invoking the
|
|
|
|
// specified closure
|
|
|
|
let mut pushed = 0u;
|
2014-06-13 15:03:26 -07:00
|
|
|
|
2014-09-14 20:27:36 -07:00
|
|
|
for result in gather_attrs(attrs).into_iter() {
|
2014-07-21 15:27:59 +12:00
|
|
|
let v = match result {
|
2014-06-13 15:03:26 -07:00
|
|
|
Err(span) => {
|
|
|
|
self.tcx.sess.span_err(span, "malformed lint attribute");
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
Ok((lint_name, level, span)) => {
|
2014-10-14 11:32:31 -07:00
|
|
|
match self.lints.find_lint(lint_name.get(), &self.tcx.sess, Some(span)) {
|
|
|
|
Some(lint_id) => vec![(lint_id, level, span)],
|
2014-06-13 15:03:26 -07:00
|
|
|
None => {
|
2014-11-12 15:51:51 -08:00
|
|
|
match self.lints.lint_groups.get(lint_name.get()) {
|
2014-07-21 15:27:59 +12:00
|
|
|
Some(&(ref v, _)) => v.iter()
|
|
|
|
.map(|lint_id: &LintId|
|
|
|
|
(*lint_id, level, span))
|
|
|
|
.collect(),
|
|
|
|
None => {
|
2014-10-14 11:37:16 -07:00
|
|
|
self.span_lint(builtin::UNKNOWN_LINTS, span,
|
2014-07-21 15:27:59 +12:00
|
|
|
format!("unknown `{}` attribute: `{}`",
|
2015-01-04 17:43:24 +13:00
|
|
|
level.as_str(), lint_name).as_slice());
|
2014-07-21 15:27:59 +12:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
2014-06-13 15:03:26 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2014-09-14 20:27:36 -07:00
|
|
|
for (lint_id, level, span) in v.into_iter() {
|
2014-12-09 12:21:18 -05:00
|
|
|
let now = self.lints.get_level_source(lint_id).0;
|
2014-07-21 15:27:59 +12:00
|
|
|
if now == Forbid && level != Forbid {
|
|
|
|
let lint_name = lint_id.as_str();
|
|
|
|
self.tcx.sess.span_err(span,
|
2015-01-07 11:58:31 -05:00
|
|
|
&format!("{}({}) overruled by outer forbid({})",
|
2014-07-21 15:27:59 +12:00
|
|
|
level.as_str(), lint_name,
|
2015-01-07 11:58:31 -05:00
|
|
|
lint_name)[]);
|
2014-07-21 15:27:59 +12:00
|
|
|
} else if now != level {
|
2014-12-09 12:21:18 -05:00
|
|
|
let src = self.lints.get_level_source(lint_id).1;
|
2014-07-21 15:27:59 +12:00
|
|
|
self.level_stack.push((lint_id, (now, src)));
|
|
|
|
pushed += 1;
|
|
|
|
self.lints.set_level(lint_id, (level, Node(span)));
|
|
|
|
}
|
2014-06-06 15:49:48 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
run_lints!(self, enter_lint_attrs, attrs);
|
|
|
|
f(self);
|
|
|
|
run_lints!(self, exit_lint_attrs, attrs);
|
|
|
|
|
|
|
|
// rollback
|
|
|
|
for _ in range(0, pushed) {
|
|
|
|
let (lint, lvlsrc) = self.level_stack.pop().unwrap();
|
|
|
|
self.lints.set_level(lint, lvlsrc);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-12-08 20:26:43 -05:00
|
|
|
fn visit_ids<F>(&mut self, f: F) where
|
|
|
|
F: FnOnce(&mut ast_util::IdVisitor<Context>)
|
|
|
|
{
|
2014-06-06 15:49:48 -07:00
|
|
|
let mut v = ast_util::IdVisitor {
|
|
|
|
operation: self,
|
|
|
|
pass_through_items: false,
|
|
|
|
visited_outermost: false,
|
|
|
|
};
|
|
|
|
f(&mut v);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-09-10 01:54:36 +03:00
|
|
|
impl<'a, 'tcx, 'v> Visitor<'v> for Context<'a, 'tcx> {
|
2014-09-12 13:10:30 +03:00
|
|
|
fn visit_item(&mut self, it: &ast::Item) {
|
2015-01-07 11:58:31 -05:00
|
|
|
self.with_lint_attrs(&it.attrs[], |cx| {
|
2014-06-06 15:49:48 -07:00
|
|
|
run_lints!(cx, check_item, it);
|
2014-09-12 13:10:30 +03:00
|
|
|
cx.visit_ids(|v| v.visit_item(it));
|
|
|
|
visit::walk_item(cx, it);
|
2014-06-06 15:49:48 -07:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2014-09-12 13:10:30 +03:00
|
|
|
fn visit_foreign_item(&mut self, it: &ast::ForeignItem) {
|
2015-01-07 11:58:31 -05:00
|
|
|
self.with_lint_attrs(&it.attrs[], |cx| {
|
2014-06-06 15:49:48 -07:00
|
|
|
run_lints!(cx, check_foreign_item, it);
|
2014-09-12 13:10:30 +03:00
|
|
|
visit::walk_foreign_item(cx, it);
|
2014-06-06 15:49:48 -07:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2014-09-12 13:10:30 +03:00
|
|
|
fn visit_view_item(&mut self, i: &ast::ViewItem) {
|
2015-01-07 11:58:31 -05:00
|
|
|
self.with_lint_attrs(&i.attrs[], |cx| {
|
2014-06-06 15:49:48 -07:00
|
|
|
run_lints!(cx, check_view_item, i);
|
2014-09-12 13:10:30 +03:00
|
|
|
cx.visit_ids(|v| v.visit_view_item(i));
|
|
|
|
visit::walk_view_item(cx, i);
|
2014-06-06 15:49:48 -07:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2014-09-12 13:10:30 +03:00
|
|
|
fn visit_pat(&mut self, p: &ast::Pat) {
|
2014-06-06 15:49:48 -07:00
|
|
|
run_lints!(self, check_pat, p);
|
2014-09-12 13:10:30 +03:00
|
|
|
visit::walk_pat(self, p);
|
2014-06-06 15:49:48 -07:00
|
|
|
}
|
|
|
|
|
2014-09-12 13:10:30 +03:00
|
|
|
fn visit_expr(&mut self, e: &ast::Expr) {
|
2014-06-06 15:49:48 -07:00
|
|
|
run_lints!(self, check_expr, e);
|
2014-09-12 13:10:30 +03:00
|
|
|
visit::walk_expr(self, e);
|
2014-06-06 15:49:48 -07:00
|
|
|
}
|
|
|
|
|
2014-09-12 13:10:30 +03:00
|
|
|
fn visit_stmt(&mut self, s: &ast::Stmt) {
|
2014-06-06 15:49:48 -07:00
|
|
|
run_lints!(self, check_stmt, s);
|
2014-09-12 13:10:30 +03:00
|
|
|
visit::walk_stmt(self, s);
|
2014-06-06 15:49:48 -07:00
|
|
|
}
|
|
|
|
|
2014-09-10 01:54:36 +03:00
|
|
|
fn visit_fn(&mut self, fk: FnKind<'v>, decl: &'v ast::FnDecl,
|
|
|
|
body: &'v ast::Block, span: Span, id: ast::NodeId) {
|
|
|
|
match fk {
|
2014-06-06 15:49:48 -07:00
|
|
|
visit::FkMethod(_, _, m) => {
|
2015-01-07 11:58:31 -05:00
|
|
|
self.with_lint_attrs(&m.attrs[], |cx| {
|
2014-06-06 15:49:48 -07:00
|
|
|
run_lints!(cx, check_fn, fk, decl, body, span, id);
|
|
|
|
cx.visit_ids(|v| {
|
2014-09-12 13:10:30 +03:00
|
|
|
v.visit_fn(fk, decl, body, span, id);
|
2014-06-06 15:49:48 -07:00
|
|
|
});
|
2014-09-12 13:10:30 +03:00
|
|
|
visit::walk_fn(cx, fk, decl, body, span);
|
2014-06-06 15:49:48 -07:00
|
|
|
})
|
|
|
|
},
|
|
|
|
_ => {
|
|
|
|
run_lints!(self, check_fn, fk, decl, body, span, id);
|
2014-09-12 13:10:30 +03:00
|
|
|
visit::walk_fn(self, fk, decl, body, span);
|
2014-06-06 15:49:48 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-09-12 13:10:30 +03:00
|
|
|
fn visit_ty_method(&mut self, t: &ast::TypeMethod) {
|
2015-01-07 11:58:31 -05:00
|
|
|
self.with_lint_attrs(&t.attrs[], |cx| {
|
2014-06-06 15:49:48 -07:00
|
|
|
run_lints!(cx, check_ty_method, t);
|
2014-09-12 13:10:30 +03:00
|
|
|
visit::walk_ty_method(cx, t);
|
2014-06-06 15:49:48 -07:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
fn visit_struct_def(&mut self,
|
|
|
|
s: &ast::StructDef,
|
|
|
|
ident: ast::Ident,
|
|
|
|
g: &ast::Generics,
|
2014-09-12 13:10:30 +03:00
|
|
|
id: ast::NodeId) {
|
2014-06-06 15:49:48 -07:00
|
|
|
run_lints!(self, check_struct_def, s, ident, g, id);
|
2014-09-12 13:10:30 +03:00
|
|
|
visit::walk_struct_def(self, s);
|
2014-06-06 15:49:48 -07:00
|
|
|
run_lints!(self, check_struct_def_post, s, ident, g, id);
|
|
|
|
}
|
|
|
|
|
2014-09-12 13:10:30 +03:00
|
|
|
fn visit_struct_field(&mut self, s: &ast::StructField) {
|
2015-01-07 11:58:31 -05:00
|
|
|
self.with_lint_attrs(&s.node.attrs[], |cx| {
|
2014-06-06 15:49:48 -07:00
|
|
|
run_lints!(cx, check_struct_field, s);
|
2014-09-12 13:10:30 +03:00
|
|
|
visit::walk_struct_field(cx, s);
|
2014-06-06 15:49:48 -07:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2014-09-12 13:10:30 +03:00
|
|
|
fn visit_variant(&mut self, v: &ast::Variant, g: &ast::Generics) {
|
2015-01-07 11:58:31 -05:00
|
|
|
self.with_lint_attrs(&v.node.attrs[], |cx| {
|
2014-06-06 15:49:48 -07:00
|
|
|
run_lints!(cx, check_variant, v, g);
|
2014-09-12 13:10:30 +03:00
|
|
|
visit::walk_variant(cx, v, g);
|
2014-11-15 17:57:54 -08:00
|
|
|
run_lints!(cx, check_variant_post, v, g);
|
2014-06-06 15:49:48 -07:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
// FIXME(#10894) should continue recursing
|
2014-09-12 13:10:30 +03:00
|
|
|
fn visit_ty(&mut self, t: &ast::Ty) {
|
2014-06-06 15:49:48 -07:00
|
|
|
run_lints!(self, check_ty, t);
|
|
|
|
}
|
|
|
|
|
2014-09-12 13:10:30 +03:00
|
|
|
fn visit_ident(&mut self, sp: Span, id: ast::Ident) {
|
2014-06-06 15:49:48 -07:00
|
|
|
run_lints!(self, check_ident, sp, id);
|
|
|
|
}
|
|
|
|
|
2014-09-12 13:10:30 +03:00
|
|
|
fn visit_mod(&mut self, m: &ast::Mod, s: Span, n: ast::NodeId) {
|
2014-06-06 15:49:48 -07:00
|
|
|
run_lints!(self, check_mod, m, s, n);
|
2014-09-12 13:10:30 +03:00
|
|
|
visit::walk_mod(self, m);
|
2014-06-06 15:49:48 -07:00
|
|
|
}
|
|
|
|
|
2014-09-12 13:10:30 +03:00
|
|
|
fn visit_local(&mut self, l: &ast::Local) {
|
2014-06-06 15:49:48 -07:00
|
|
|
run_lints!(self, check_local, l);
|
2014-09-12 13:10:30 +03:00
|
|
|
visit::walk_local(self, l);
|
2014-06-06 15:49:48 -07:00
|
|
|
}
|
|
|
|
|
2014-09-12 13:10:30 +03:00
|
|
|
fn visit_block(&mut self, b: &ast::Block) {
|
2014-06-06 15:49:48 -07:00
|
|
|
run_lints!(self, check_block, b);
|
2014-09-12 13:10:30 +03:00
|
|
|
visit::walk_block(self, b);
|
2014-06-06 15:49:48 -07:00
|
|
|
}
|
|
|
|
|
2014-09-12 13:10:30 +03:00
|
|
|
fn visit_arm(&mut self, a: &ast::Arm) {
|
2014-06-06 15:49:48 -07:00
|
|
|
run_lints!(self, check_arm, a);
|
2014-09-12 13:10:30 +03:00
|
|
|
visit::walk_arm(self, a);
|
2014-06-06 15:49:48 -07:00
|
|
|
}
|
|
|
|
|
2014-09-12 13:10:30 +03:00
|
|
|
fn visit_decl(&mut self, d: &ast::Decl) {
|
2014-06-06 15:49:48 -07:00
|
|
|
run_lints!(self, check_decl, d);
|
2014-09-12 13:10:30 +03:00
|
|
|
visit::walk_decl(self, d);
|
2014-06-06 15:49:48 -07:00
|
|
|
}
|
|
|
|
|
2014-09-12 13:10:30 +03:00
|
|
|
fn visit_expr_post(&mut self, e: &ast::Expr) {
|
2014-06-06 15:49:48 -07:00
|
|
|
run_lints!(self, check_expr_post, e);
|
|
|
|
}
|
|
|
|
|
2014-09-12 13:10:30 +03:00
|
|
|
fn visit_generics(&mut self, g: &ast::Generics) {
|
2014-06-06 15:49:48 -07:00
|
|
|
run_lints!(self, check_generics, g);
|
2014-09-12 13:10:30 +03:00
|
|
|
visit::walk_generics(self, g);
|
2014-06-06 15:49:48 -07:00
|
|
|
}
|
|
|
|
|
2014-09-12 13:10:30 +03:00
|
|
|
fn visit_trait_item(&mut self, m: &ast::TraitItem) {
|
2014-06-06 15:49:48 -07:00
|
|
|
run_lints!(self, check_trait_method, m);
|
2014-09-12 13:10:30 +03:00
|
|
|
visit::walk_trait_item(self, m);
|
2014-06-06 15:49:48 -07:00
|
|
|
}
|
|
|
|
|
2014-09-12 13:10:30 +03:00
|
|
|
fn visit_opt_lifetime_ref(&mut self, sp: Span, lt: &Option<ast::Lifetime>) {
|
2014-06-06 15:49:48 -07:00
|
|
|
run_lints!(self, check_opt_lifetime_ref, sp, lt);
|
|
|
|
}
|
|
|
|
|
2014-09-12 13:10:30 +03:00
|
|
|
fn visit_lifetime_ref(&mut self, lt: &ast::Lifetime) {
|
2014-06-06 15:49:48 -07:00
|
|
|
run_lints!(self, check_lifetime_ref, lt);
|
|
|
|
}
|
|
|
|
|
2014-11-18 17:39:16 +01:00
|
|
|
fn visit_lifetime_def(&mut self, lt: &ast::LifetimeDef) {
|
|
|
|
run_lints!(self, check_lifetime_def, lt);
|
2014-06-06 15:49:48 -07:00
|
|
|
}
|
|
|
|
|
2014-09-12 13:10:30 +03:00
|
|
|
fn visit_explicit_self(&mut self, es: &ast::ExplicitSelf) {
|
2014-06-06 15:49:48 -07:00
|
|
|
run_lints!(self, check_explicit_self, es);
|
2014-09-12 13:10:30 +03:00
|
|
|
visit::walk_explicit_self(self, es);
|
2014-06-06 15:49:48 -07:00
|
|
|
}
|
|
|
|
|
2014-09-12 13:10:30 +03:00
|
|
|
fn visit_mac(&mut self, mac: &ast::Mac) {
|
2014-06-06 15:49:48 -07:00
|
|
|
run_lints!(self, check_mac, mac);
|
2014-09-12 13:10:30 +03:00
|
|
|
visit::walk_mac(self, mac);
|
2014-06-06 15:49:48 -07:00
|
|
|
}
|
|
|
|
|
2014-09-12 13:10:30 +03:00
|
|
|
fn visit_path(&mut self, p: &ast::Path, id: ast::NodeId) {
|
2014-06-06 15:49:48 -07:00
|
|
|
run_lints!(self, check_path, p, id);
|
2014-09-12 13:10:30 +03:00
|
|
|
visit::walk_path(self, p);
|
2014-06-06 15:49:48 -07:00
|
|
|
}
|
|
|
|
|
2014-09-12 13:10:30 +03:00
|
|
|
fn visit_attribute(&mut self, attr: &ast::Attribute) {
|
2014-06-06 15:49:48 -07:00
|
|
|
run_lints!(self, check_attribute, attr);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Output any lints that were previously added to the session.
|
2014-04-22 15:56:37 +03:00
|
|
|
impl<'a, 'tcx> IdVisitingOperation for Context<'a, 'tcx> {
|
2014-10-25 22:27:15 +03:00
|
|
|
fn visit_id(&mut self, id: ast::NodeId) {
|
2014-11-06 12:25:16 -05:00
|
|
|
match self.tcx.sess.lints.borrow_mut().remove(&id) {
|
2014-06-06 15:49:48 -07:00
|
|
|
None => {}
|
|
|
|
Some(lints) => {
|
2014-09-14 20:27:36 -07:00
|
|
|
for (lint_id, span, msg) in lints.into_iter() {
|
2015-01-07 11:58:31 -05:00
|
|
|
self.span_lint(lint_id.lint, span, &msg[])
|
2014-06-06 15:49:48 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// This lint pass is defined here because it touches parts of the `Context`
|
|
|
|
// that we don't want to expose. It records the lint level at certain AST
|
|
|
|
// nodes, so that the variant size difference check in trans can call
|
|
|
|
// `raw_emit_lint`.
|
|
|
|
|
|
|
|
struct GatherNodeLevels;
|
|
|
|
|
|
|
|
impl LintPass for GatherNodeLevels {
|
|
|
|
fn get_lints(&self) -> LintArray {
|
|
|
|
lint_array!()
|
|
|
|
}
|
|
|
|
|
|
|
|
fn check_item(&mut self, cx: &Context, it: &ast::Item) {
|
|
|
|
match it.node {
|
|
|
|
ast::ItemEnum(..) => {
|
2014-10-14 11:37:16 -07:00
|
|
|
let lint_id = LintId::of(builtin::VARIANT_SIZE_DIFFERENCES);
|
2014-07-28 11:33:06 -07:00
|
|
|
let lvlsrc = cx.lints.get_level_source(lint_id);
|
|
|
|
match lvlsrc {
|
|
|
|
(lvl, _) if lvl != Allow => {
|
2014-06-06 15:49:48 -07:00
|
|
|
cx.node_levels.borrow_mut()
|
|
|
|
.insert((it.id, lint_id), lvlsrc);
|
|
|
|
},
|
|
|
|
_ => { }
|
|
|
|
}
|
|
|
|
},
|
|
|
|
_ => { }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Perform lint checking on a crate.
|
|
|
|
///
|
|
|
|
/// Consumes the `lint_store` field of the `Session`.
|
|
|
|
pub fn check_crate(tcx: &ty::ctxt,
|
|
|
|
exported_items: &ExportedItems) {
|
Preliminary feature staging
This partially implements the feature staging described in the
[release channel RFC][rc]. It does not yet fully conform to the RFC as
written, but does accomplish its goals sufficiently for the 1.0 alpha
release.
It has three primary user-visible effects:
* On the nightly channel, use of unstable APIs generates a warning.
* On the beta channel, use of unstable APIs generates a warning.
* On the beta channel, use of feature gates generates a warning.
Code that does not trigger these warnings is considered 'stable',
modulo pre-1.0 bugs.
Disabling the warnings for unstable APIs continues to be done in the
existing (i.e. old) style, via `#[allow(...)]`, not that specified in
the RFC. I deem this marginally acceptable since any code that must do
this is not using the stable dialect of Rust.
Use of feature gates is itself gated with the new 'unstable_features'
lint, on nightly set to 'allow', and on beta 'warn'.
The attribute scheme used here corresponds to an older version of the
RFC, with the `#[staged_api]` crate attribute toggling the staging
behavior of the stability attributes, but the user impact is only
in-tree so I'm not concerned about having to make design changes later
(and I may ultimately prefer the scheme here after all, with the
`#[staged_api]` crate attribute).
Since the Rust codebase itself makes use of unstable features the
compiler and build system to a midly elaborate dance to allow it to
bootstrap while disobeying these lints (which would otherwise be
errors because Rust builds with `-D warnings`).
This patch includes one significant hack that causes a
regression. Because the `format_args!` macro emits calls to unstable
APIs it would trigger the lint. I added a hack to the lint to make it
not trigger, but this in turn causes arguments to `println!` not to be
checked for feature gates. I don't presently understand macro
expansion well enough to fix. This is bug #20661.
Closes #16678
[rc]: https://github.com/rust-lang/rfcs/blob/master/text/0507-release-channels.md
2015-01-06 06:26:08 -08:00
|
|
|
|
|
|
|
// If this is a feature-staged build of rustc then flip several lints to 'forbid'
|
|
|
|
tcx.sess.lint_store.borrow_mut().maybe_stage_features(&tcx.sess);
|
|
|
|
|
2014-09-07 20:09:06 +03:00
|
|
|
let krate = tcx.map.krate();
|
2014-06-17 16:55:34 -07:00
|
|
|
let mut cx = Context::new(tcx, krate, exported_items);
|
2014-06-06 15:49:48 -07:00
|
|
|
|
|
|
|
// Visit the whole crate.
|
2015-01-07 11:58:31 -05:00
|
|
|
cx.with_lint_attrs(&krate.attrs[], |cx| {
|
2014-06-06 15:49:48 -07:00
|
|
|
cx.visit_id(ast::CRATE_NODE_ID);
|
|
|
|
cx.visit_ids(|v| {
|
|
|
|
v.visited_outermost = true;
|
2014-09-12 13:10:30 +03:00
|
|
|
visit::walk_crate(v, krate);
|
2014-06-06 15:49:48 -07:00
|
|
|
});
|
|
|
|
|
|
|
|
// since the root module isn't visited as an item (because it isn't an
|
|
|
|
// item), warn for it here.
|
2014-06-17 17:06:04 -07:00
|
|
|
run_lints!(cx, check_crate, krate);
|
2014-06-06 15:49:48 -07:00
|
|
|
|
2014-09-12 13:10:30 +03:00
|
|
|
visit::walk_crate(cx, krate);
|
2014-06-06 15:49:48 -07:00
|
|
|
});
|
|
|
|
|
|
|
|
// If we missed any lints added to the session, then there's a bug somewhere
|
|
|
|
// in the iteration code.
|
|
|
|
for (id, v) in tcx.sess.lints.borrow().iter() {
|
|
|
|
for &(lint, span, ref msg) in v.iter() {
|
|
|
|
tcx.sess.span_bug(span,
|
2014-06-17 17:41:50 -07:00
|
|
|
format!("unprocessed lint {} at {}: {}",
|
2015-01-04 17:43:24 +13:00
|
|
|
lint.as_str(), tcx.map.node_to_string(*id), *msg).as_slice())
|
2014-06-06 15:49:48 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
tcx.sess.abort_if_errors();
|
2014-11-20 09:23:43 -08:00
|
|
|
*tcx.node_lint_levels.borrow_mut() = cx.node_levels.into_inner();
|
2014-06-06 15:49:48 -07:00
|
|
|
}
|