diff --git a/src/librustc/dep_graph/dep_node.rs b/src/librustc/dep_graph/dep_node.rs index c6f9cb2fceadd..5b609f192e1c2 100644 --- a/src/librustc/dep_graph/dep_node.rs +++ b/src/librustc/dep_graph/dep_node.rs @@ -521,6 +521,7 @@ define_dep_nodes!( <'tcx> [] IsAllocator(DefId), [] IsPanicRuntime(DefId), [] ExternCrate(DefId), + [] LintLevels, ); trait DepNodeParams<'a, 'gcx: 'tcx + 'a, 'tcx: 'a> : fmt::Debug { diff --git a/src/librustc/ich/impls_ty.rs b/src/librustc/ich/impls_ty.rs index 5269ec90def5c..cd64348044fcb 100644 --- a/src/librustc/ich/impls_ty.rs +++ b/src/librustc/ich/impls_ty.rs @@ -625,8 +625,6 @@ for ty::TypeckTables<'tcx> { ref cast_kinds, - // FIXME(#41184): This is still ignored at the moment. - lints: _, ref used_trait_imports, tainted_by_errors, ref free_region_map, diff --git a/src/librustc/lint/context.rs b/src/librustc/lint/context.rs index d67bca1df3022..6ee06dc0a8163 100644 --- a/src/librustc/lint/context.rs +++ b/src/librustc/lint/context.rs @@ -23,29 +23,25 @@ //! 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. + use self::TargetLint::*; +use rustc_back::slice; +use lint::{EarlyLintPassObject, LateLintPassObject}; +use lint::{Level, Lint, LintId, LintPass, LintBuffer}; +use lint::levels::{LintLevelSets, LintLevelsBuilder}; use middle::privacy::AccessLevels; +use rustc_serialize::{Decoder, Decodable, Encoder, Encodable}; +use session::{config, early_error, Session}; use traits::Reveal; use ty::{self, TyCtxt}; -use session::{config, early_error, Session}; -use lint::{Level, LevelSource, Lint, LintId, LintPass, LintSource}; -use lint::{EarlyLintPassObject, LateLintPassObject}; -use lint::{Default, CommandLine, Node, Allow, Warn, Deny, Forbid}; -use lint::builtin; -use rustc_serialize::{Decoder, Decodable, Encoder, Encodable}; use util::nodemap::FxHashMap; -use std::cmp; use std::default::Default as StdDefault; -use std::mem; -use std::fmt; use std::cell::{Ref, RefCell}; -use syntax::attr; use syntax::ast; -use syntax::symbol::Symbol; use syntax_pos::{MultiSpan, Span}; -use errors::{self, Diagnostic, DiagnosticBuilder}; +use errors::DiagnosticBuilder; use hir; use hir::def_id::LOCAL_CRATE; use hir::intravisit as hir_visit; @@ -69,9 +65,6 @@ pub struct LintStore { /// Lints indexed by name. by_name: FxHashMap, - /// Current levels of each lint, and where they were set. - levels: LintLevels, - /// Map of registered lint groups to what lints they expand to. The bool /// is true if the lint group was added by a plugin. lint_groups: FxHashMap<&'static str, (Vec, bool)>, @@ -81,78 +74,23 @@ pub struct LintStore { future_incompatible: FxHashMap, } - -#[derive(Default)] -struct LintLevels { - /// Current levels of each lint, and where they were set. - levels: FxHashMap, - - /// Maximum level a lint can be - lint_cap: Option, -} - - pub struct LintSession<'a, PassObject> { /// Reference to the store of registered lints. lints: Ref<'a, LintStore>, - /// The current lint levels. - levels: LintLevels, - - /// 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. - stack: Vec<(LintId, LevelSource)>, - /// Trait objects for each lint pass. passes: Option>, } -/// When you call `add_lint` on the session, you wind up storing one -/// of these, which records a "potential lint" at a particular point. -#[derive(PartialEq, RustcEncodable, RustcDecodable)] -pub struct EarlyLint { - /// what lint is this? (e.g., `dead_code`) - pub id: LintId, - - /// the main message - pub diagnostic: Diagnostic, -} - -impl fmt::Debug for EarlyLint { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_struct("EarlyLint") - .field("id", &self.id) - .field("span", &self.diagnostic.span) - .field("diagnostic", &self.diagnostic) - .finish() - } -} - -pub trait IntoEarlyLint { - fn into_early_lint(self, id: LintId) -> EarlyLint; -} - -impl<'a, S: Into> IntoEarlyLint for (S, &'a str) { - fn into_early_lint(self, id: LintId) -> EarlyLint { - let (span, msg) = self; - let mut diagnostic = Diagnostic::new(errors::Level::Warning, msg); - diagnostic.set_span(span); - EarlyLint { - id, - diagnostic, - } - } -} - -impl IntoEarlyLint for Diagnostic { - fn into_early_lint(self, id: LintId) -> EarlyLint { - EarlyLint { - id, - diagnostic: self, - } - } +/// Lints that are buffered up early on in the `Session` before the +/// `LintLevels` is calculated +#[derive(PartialEq, RustcEncodable, RustcDecodable, Debug)] +pub struct BufferedEarlyLint { + pub lint_id: LintId, + pub ast_id: ast::NodeId, + pub span: MultiSpan, + pub msg: String, } /// Extra information for a future incompatibility lint. See the call @@ -176,11 +114,20 @@ enum TargetLint { Removed(String), } -enum FindLintError { +pub enum FindLintError { NotFound, Removed, } +pub enum CheckLintNameResult<'a> { + Ok(&'a [LintId]), + // Lint doesn't exist + NoLint, + // The lint is either renamed or removed. This is the warning + // message. + Warning(String), +} + impl LintStore { pub fn new() -> LintStore { LintStore { @@ -188,7 +135,6 @@ impl LintStore { early_passes: Some(vec![]), late_passes: Some(vec![]), by_name: FxHashMap(), - levels: LintLevels::default(), future_incompatible: FxHashMap(), lint_groups: FxHashMap(), } @@ -241,8 +187,6 @@ impl LintStore { (Some(sess), true) => sess.err(&msg[..]), } } - - self.levels.set(id, (lint.default_level, Default)); } } @@ -291,96 +235,93 @@ impl LintStore { self.by_name.insert(name.into(), Removed(reason.into())); } - fn find_lint(&self, lint_name: &str) -> Result { + pub fn find_lints(&self, lint_name: &str) -> Result, FindLintError> { match self.by_name.get(lint_name) { - Some(&Id(lint_id)) => Ok(lint_id), + Some(&Id(lint_id)) => Ok(vec![lint_id]), Some(&Renamed(_, lint_id)) => { - Ok(lint_id) + Ok(vec![lint_id]) }, Some(&Removed(_)) => { Err(FindLintError::Removed) }, - None => Err(FindLintError::NotFound) - } - } - - pub fn process_command_line(&mut self, sess: &Session) { - for &(ref lint_name, level) in &sess.opts.lint_opts { - check_lint_name_cmdline(sess, self, - &lint_name[..], level); - - let lint_flag_val = Symbol::intern(&lint_name); - match self.find_lint(&lint_name[..]) { - Ok(lint_id) => self.levels.set(lint_id, (level, CommandLine(lint_flag_val))), - Err(FindLintError::Removed) => { } - Err(_) => { - match self.lint_groups.iter().map(|(&x, pair)| (x, pair.0.clone())) - .collect::>>() - .get(&lint_name[..]) { - Some(v) => { - for lint_id in v { - self.levels.set(*lint_id, (level, CommandLine(lint_flag_val))); - } - } - None => { - // The lint or lint group doesn't exist. - // This is an error, but it was handled - // by check_lint_name_cmdline. - } - } + None => { + match self.lint_groups.get(lint_name) { + Some(v) => Ok(v.0.clone()), + None => Err(FindLintError::Removed) } } } - - self.levels.set_lint_cap(sess.opts.lint_cap); } -} - -impl LintLevels { - fn get_source(&self, lint: LintId) -> LevelSource { - match self.levels.get(&lint) { - Some(&s) => s, - None => (Allow, Default), - } - } + // Checks the validity of lint names derived from the command line + pub fn check_lint_name_cmdline(&self, + sess: &Session, + lint_name: &str, + level: Level) { + let db = match self.check_lint_name(lint_name) { + CheckLintNameResult::Ok(_) => None, + CheckLintNameResult::Warning(ref msg) => { + Some(sess.struct_warn(msg)) + }, + CheckLintNameResult::NoLint => { + Some(struct_err!(sess, E0602, "unknown lint: `{}`", lint_name)) + } + }; - fn set(&mut self, lint: LintId, mut lvlsrc: LevelSource) { - if let Some(cap) = self.lint_cap { - lvlsrc.0 = cmp::min(lvlsrc.0, cap); - } - if lvlsrc.0 == Allow { - self.levels.remove(&lint); - } else { - self.levels.insert(lint, lvlsrc); + if let Some(mut db) = db { + let msg = format!("requested on the command line with `{} {}`", + match level { + Level::Allow => "-A", + Level::Warn => "-W", + Level::Deny => "-D", + Level::Forbid => "-F", + }, + lint_name); + db.note(&msg); + db.emit(); } } - fn set_lint_cap(&mut self, lint_cap: Option) { - self.lint_cap = lint_cap; - if let Some(cap) = lint_cap { - for (_, level) in &mut self.levels { - level.0 = cmp::min(level.0, cap); + /// Checks the name of a lint for its existence, and whether it was + /// renamed or removed. Generates a DiagnosticBuilder containing a + /// warning for renamed and removed lints. This is over both lint + /// names from attributes and those passed on the command line. Since + /// it emits non-fatal warnings and there are *two* lint passes that + /// inspect attributes, this is only run from the late pass to avoid + /// printing duplicate warnings. + pub fn check_lint_name(&self, lint_name: &str) -> CheckLintNameResult { + match self.by_name.get(lint_name) { + Some(&Renamed(ref new_name, _)) => { + CheckLintNameResult::Warning( + format!("lint {} has been renamed to {}", lint_name, new_name) + ) + }, + Some(&Removed(ref reason)) => { + CheckLintNameResult::Warning( + format!("lint {} has been removed: {}", lint_name, reason) + ) + }, + None => { + match self.lint_groups.get(lint_name) { + None => CheckLintNameResult::NoLint, + Some(ids) => CheckLintNameResult::Ok(&ids.0), + } } + Some(&Id(ref id)) => CheckLintNameResult::Ok(slice::ref_slice(id)), } } } - impl<'a, PassObject: LintPassObject> LintSession<'a, PassObject> { /// Creates a new `LintSession`, by moving out the `LintStore`'s initial /// lint levels and pass objects. These can be restored using the `restore` /// method. fn new(store: &'a RefCell) -> LintSession<'a, PassObject> { let mut s = store.borrow_mut(); - let levels = mem::replace(&mut s.levels, LintLevels::default()); let passes = PassObject::take_passes(&mut *s); drop(s); LintSession { lints: store.borrow(), - stack: Vec::new(), - levels, passes, } } @@ -389,17 +330,10 @@ impl<'a, PassObject: LintPassObject> LintSession<'a, PassObject> { fn restore(self, store: &RefCell) { drop(self.lints); let mut s = store.borrow_mut(); - s.levels = self.levels; PassObject::restore_passes(&mut *s, self.passes); } - - fn get_source(&self, lint_id: LintId) -> LevelSource { - self.levels.get_source(lint_id) - } } - - /// Context for lint checking after type checking. pub struct LateContext<'a, 'tcx: 'a> { /// Type context we're checking in. @@ -416,6 +350,8 @@ pub struct LateContext<'a, 'tcx: 'a> { /// The store of registered lints and the lint levels. lint_sess: LintSession<'tcx, LateLintPassObject>, + + last_ast_node_with_lint_attrs: ast::NodeId, } /// Context for lint checking of the AST, after expansion, before lowering to @@ -427,8 +363,12 @@ pub struct EarlyContext<'a> { /// The crate being checked. pub krate: &'a ast::Crate, + builder: LintLevelsBuilder<'a>, + /// The store of registered lints and the lint levels. lint_sess: LintSession<'a, EarlyLintPassObject>, + + buffered: LintBuffer, } /// Convenience macro for calling a `LintPass` method on every pass in the context. @@ -442,135 +382,6 @@ macro_rules! run_lints { ($cx:expr, $f:ident, $ps:ident, $($args:expr),*) => ({ $cx.lint_sess_mut().passes = Some(passes); }) } -/// Parse the lint attributes into a vector, with `Err`s for malformed lint -/// attributes. Writing this as an iterator is an enormous mess. -// See also the hir version just below. -pub fn gather_attrs(attrs: &[ast::Attribute]) -> Vec> { - let mut out = vec![]; - for attr in attrs { - let r = gather_attr(attr); - out.extend(r.into_iter()); - } - out -} - -pub fn gather_attr(attr: &ast::Attribute) -> Vec> { - let mut out = vec![]; - - let level = match attr.name().and_then(|name| Level::from_str(&name.as_str())) { - None => return out, - Some(lvl) => lvl, - }; - - let meta = unwrap_or!(attr.meta(), return out); - attr::mark_used(attr); - - let metas = if let Some(metas) = meta.meta_item_list() { - metas - } else { - out.push(Err(meta.span)); - return out; - }; - - for li in metas { - out.push(li.word().map_or(Err(li.span), |word| Ok((word.name(), level, word.span)))); - } - - out -} - -/// 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, - lints: &LintStore, - lint: &'static Lint, - lvlsrc: LevelSource, - span: Option, - msg: &str) { - raw_struct_lint(sess, lints, lint, lvlsrc, span, msg).emit(); -} - -pub fn raw_struct_lint<'a, S>(sess: &'a Session, - lints: &LintStore, - lint: &'static Lint, - lvlsrc: LevelSource, - span: Option, - msg: &str) - -> DiagnosticBuilder<'a> - where S: Into -{ - let (level, source) = lvlsrc; - if level == Allow { - return sess.diagnostic().struct_dummy(); - } - - let name = lint.name_lower(); - - // Except for possible note details, forbid behaves like deny. - let effective_level = if level == Forbid { Deny } else { level }; - - let mut err = match (effective_level, span) { - (Warn, Some(sp)) => sess.struct_span_warn(sp, &msg[..]), - (Warn, None) => sess.struct_warn(&msg[..]), - (Deny, Some(sp)) => sess.struct_span_err(sp, &msg[..]), - (Deny, None) => sess.struct_err(&msg[..]), - _ => bug!("impossible level in raw_emit_lint"), - }; - - match source { - Default => { - sess.diag_note_once(&mut err, lint, - &format!("#[{}({})] on by default", level.as_str(), name)); - }, - CommandLine(lint_flag_val) => { - let flag = match level { - Warn => "-W", Deny => "-D", Forbid => "-F", - Allow => bug!("earlier conditional return should handle Allow case") - }; - let hyphen_case_lint_name = name.replace("_", "-"); - if lint_flag_val.as_str() == name { - sess.diag_note_once(&mut err, lint, - &format!("requested on the command line with `{} {}`", - flag, hyphen_case_lint_name)); - } else { - let hyphen_case_flag_val = lint_flag_val.as_str().replace("_", "-"); - sess.diag_note_once(&mut err, lint, - &format!("`{} {}` implied by `{} {}`", - flag, hyphen_case_lint_name, flag, - hyphen_case_flag_val)); - } - }, - Node(lint_attr_name, src) => { - sess.diag_span_note_once(&mut err, lint, src, "lint level defined here"); - if lint_attr_name.as_str() != name { - let level_str = level.as_str(); - sess.diag_note_once(&mut err, lint, - &format!("#[{}({})] implied by #[{}({})]", - level_str, name, level_str, lint_attr_name)); - } - } - } - - // Check for future incompatibility lints and issue a stronger warning. - if let Some(future_incompatible) = lints.future_incompatible(LintId::of(lint)) { - let explanation = format!("this was previously accepted by the compiler \ - but is being phased out; \ - it will become a hard error in a future release!"); - let citation = format!("for more information, see {}", - future_incompatible.reference); - err.warn(&explanation); - err.note(&citation); - } - - err -} - - pub trait LintPassObject: Sized { fn take_passes(store: &mut LintStore) -> Option>; fn restore_passes(store: &mut LintStore, passes: Option>); @@ -607,67 +418,24 @@ pub trait LintContext<'tcx>: Sized { fn enter_attrs(&mut self, attrs: &'tcx [ast::Attribute]); fn exit_attrs(&mut self, attrs: &'tcx [ast::Attribute]); - /// Get the level of `lint` at the current position of the lint - /// traversal. - fn current_level(&self, lint: &'static Lint) -> Level { - self.lint_sess().get_source(LintId::of(lint)).0 - } - - fn level_src(&self, lint: &'static Lint) -> Option { - let ref levels = self.lint_sess().levels; - levels.levels.get(&LintId::of(lint)).map(|ls| match ls { - &(Warn, _) => { - let lint_id = LintId::of(builtin::WARNINGS); - let warn_src = levels.get_source(lint_id); - if warn_src.0 != Warn { - warn_src - } else { - *ls - } - } - _ => *ls - }) - } - fn lookup_and_emit>(&self, lint: &'static Lint, span: Option, msg: &str) { - let (level, src) = match self.level_src(lint) { - None => return, - Some(pair) => pair, - }; - - raw_emit_lint(&self.sess(), self.lints(), lint, (level, src), span, msg); + self.lookup(lint, span, msg).emit(); } fn lookup>(&self, lint: &'static Lint, span: Option, msg: &str) - -> DiagnosticBuilder { - let (level, src) = match self.level_src(lint) { - None => return self.sess().diagnostic().struct_dummy(), - Some(pair) => pair, - }; - - raw_struct_lint(&self.sess(), self.lints(), lint, (level, src), span, msg) - } + -> DiagnosticBuilder; /// Emit a lint at the appropriate level, for a particular span. fn span_lint>(&self, lint: &'static Lint, span: S, msg: &str) { self.lookup_and_emit(lint, Some(span), msg); } - fn early_lint(&self, early_lint: &EarlyLint) { - let span = early_lint.diagnostic.span.primary_span().expect("early lint w/o primary span"); - let mut err = self.struct_span_lint(early_lint.id.lint, - span, - &early_lint.diagnostic.message()); - err.copy_details_not_message(&early_lint.diagnostic); - err.emit(); - } - fn struct_span_lint>(&self, lint: &'static Lint, span: S, @@ -680,12 +448,10 @@ pub trait LintContext<'tcx>: Sized { fn span_lint_note(&self, lint: &'static Lint, span: Span, msg: &str, note_span: Span, note: &str) { let mut err = self.lookup(lint, Some(span), msg); - if self.current_level(lint) != Level::Allow { - if note_span == span { - err.note(note); - } else { - err.span_note(note_span, note); - } + if note_span == span { + err.note(note); + } else { + err.span_note(note_span, note); } err.emit(); } @@ -695,9 +461,7 @@ pub trait LintContext<'tcx>: Sized { msg: &str, help: &str) { let mut err = self.lookup(lint, Some(span), msg); self.span_lint(lint, span, msg); - if self.current_level(lint) != Level::Allow { - err.span_help(span, help); - } + err.span_help(span, help); err.emit(); } @@ -710,94 +474,10 @@ pub trait LintContext<'tcx>: Sized { /// current lint context, call the provided function, then reset the /// lints in effect to their previous state. fn with_lint_attrs(&mut self, + id: ast::NodeId, attrs: &'tcx [ast::Attribute], f: F) - where F: FnOnce(&mut Self), - { - // 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 = 0; - - for result in gather_attrs(attrs) { - let (is_group, lint_level_spans) = match result { - Err(span) => { - span_err!(self.sess(), span, E0452, - "malformed lint attribute"); - continue; - } - Ok((lint_name, level, span)) => { - match self.lints().find_lint(&lint_name.as_str()) { - Ok(lint_id) => (false, vec![(lint_id, level, span)]), - Err(FindLintError::NotFound) => { - match self.lints().lint_groups.get(&*lint_name.as_str()) { - Some(&(ref v, _)) => (true, - v.iter() - .map(|lint_id: &LintId| - (*lint_id, level, span)) - .collect()), - None => { - // The lint or lint group doesn't exist. - // This is an error, but it was handled - // by check_lint_name_attribute. - continue; - } - } - } - Err(FindLintError::Removed) => continue, - } - } - }; - - let lint_attr_name = result.expect("lint attribute should be well-formed").0; - - for (lint_id, level, span) in lint_level_spans { - let (now, now_source) = self.lint_sess().get_source(lint_id); - if now == Forbid && level != Forbid { - let forbidden_lint_name = match now_source { - LintSource::Default => lint_id.to_string(), - LintSource::Node(name, _) => name.to_string(), - LintSource::CommandLine(name) => name.to_string(), - }; - let mut diag_builder = struct_span_err!(self.sess(), span, E0453, - "{}({}) overruled by outer forbid({})", - level.as_str(), lint_attr_name, - forbidden_lint_name); - diag_builder.span_label(span, "overruled by previous forbid"); - match now_source { - LintSource::Default => &mut diag_builder, - LintSource::Node(_, forbid_source_span) => { - diag_builder.span_label(forbid_source_span, - "`forbid` level set here") - }, - LintSource::CommandLine(_) => { - diag_builder.note("`forbid` lint level was set on command line") - } - }.emit(); - if is_group { // don't set a separate error for every lint in the group - break; - } - } else if now != level { - let cx = self.lint_sess_mut(); - cx.stack.push((lint_id, (now, now_source))); - pushed += 1; - cx.levels.set(lint_id, (level, Node(lint_attr_name, span))); - } - } - } - - self.enter_attrs(attrs); - f(self); - self.exit_attrs(attrs); - - // rollback - let cx = self.lint_sess_mut(); - for _ in 0..pushed { - let (lint, lvlsrc) = cx.stack.pop().unwrap(); - cx.levels.set(lint, lvlsrc); - } - } + where F: FnOnce(&mut Self); } @@ -808,6 +488,16 @@ impl<'a> EarlyContext<'a> { sess, krate, lint_sess: LintSession::new(&sess.lint_store), + builder: LintLevelSets::builder(sess), + buffered: sess.buffered_lints.borrow_mut().take().unwrap(), + } + } + + fn check_id(&mut self, id: ast::NodeId) { + for early_lint in self.buffered.take(id) { + self.lookup_and_emit(early_lint.lint_id.lint, + Some(early_lint.span.clone()), + &early_lint.msg); } } } @@ -841,6 +531,32 @@ impl<'a, 'tcx> LintContext<'tcx> for LateContext<'a, 'tcx> { debug!("late context: exit_attrs({:?})", attrs); run_lints!(self, exit_lint_attrs, late_passes, attrs); } + + fn lookup>(&self, + lint: &'static Lint, + span: Option, + msg: &str) + -> DiagnosticBuilder { + let id = self.last_ast_node_with_lint_attrs; + match span { + Some(s) => self.tcx.struct_span_lint_node(lint, id, s, msg), + None => self.tcx.struct_lint_node(lint, id, msg), + } + } + + fn with_lint_attrs(&mut self, + id: ast::NodeId, + attrs: &'tcx [ast::Attribute], + f: F) + where F: FnOnce(&mut Self) + { + let prev = self.last_ast_node_with_lint_attrs; + self.last_ast_node_with_lint_attrs = id; + self.enter_attrs(attrs); + f(self); + self.exit_attrs(attrs); + self.last_ast_node_with_lint_attrs = prev; + } } impl<'a> LintContext<'a> for EarlyContext<'a> { @@ -872,6 +588,28 @@ impl<'a> LintContext<'a> for EarlyContext<'a> { debug!("early context: exit_attrs({:?})", attrs); run_lints!(self, exit_lint_attrs, early_passes, attrs); } + + fn lookup>(&self, + lint: &'static Lint, + span: Option, + msg: &str) + -> DiagnosticBuilder { + self.builder.struct_lint(lint, span.map(|s| s.into()), msg) + } + + fn with_lint_attrs(&mut self, + id: ast::NodeId, + attrs: &'a [ast::Attribute], + f: F) + where F: FnOnce(&mut Self) + { + let push = self.builder.push(attrs); + self.check_id(id); + self.enter_attrs(attrs); + f(self); + self.exit_attrs(attrs); + self.builder.pop(push); + } } impl<'a, 'tcx> LateContext<'a, 'tcx> { @@ -893,15 +631,6 @@ impl<'a, 'tcx> hir_visit::Visitor<'tcx> for LateContext<'a, 'tcx> { hir_visit::NestedVisitorMap::All(&self.tcx.hir) } - // Output any lints that were previously added to the session. - fn visit_id(&mut self, id: ast::NodeId) { - let lints = self.sess().lints.borrow_mut().take(id); - for early_lint in lints.iter().chain(self.tables.lints.get(id)) { - debug!("LateContext::visit_id: id={:?} early_lint={:?}", id, early_lint); - self.early_lint(early_lint); - } - } - fn visit_nested_body(&mut self, body: hir::BodyId) { let old_tables = self.tables; self.tables = self.tcx.body_tables(body); @@ -917,7 +646,7 @@ impl<'a, 'tcx> hir_visit::Visitor<'tcx> for LateContext<'a, 'tcx> { } fn visit_item(&mut self, it: &'tcx hir::Item) { - self.with_lint_attrs(&it.attrs, |cx| { + self.with_lint_attrs(it.id, &it.attrs, |cx| { cx.with_param_env(it.id, |cx| { run_lints!(cx, check_item, late_passes, it); hir_visit::walk_item(cx, it); @@ -927,7 +656,7 @@ impl<'a, 'tcx> hir_visit::Visitor<'tcx> for LateContext<'a, 'tcx> { } fn visit_foreign_item(&mut self, it: &'tcx hir::ForeignItem) { - self.with_lint_attrs(&it.attrs, |cx| { + self.with_lint_attrs(it.id, &it.attrs, |cx| { cx.with_param_env(it.id, |cx| { run_lints!(cx, check_foreign_item, late_passes, it); hir_visit::walk_foreign_item(cx, it); @@ -942,7 +671,7 @@ impl<'a, 'tcx> hir_visit::Visitor<'tcx> for LateContext<'a, 'tcx> { } fn visit_expr(&mut self, e: &'tcx hir::Expr) { - self.with_lint_attrs(&e.attrs, |cx| { + self.with_lint_attrs(e.id, &e.attrs, |cx| { run_lints!(cx, check_expr, late_passes, e); hir_visit::walk_expr(cx, e); run_lints!(cx, check_expr_post, late_passes, e); @@ -984,7 +713,7 @@ impl<'a, 'tcx> hir_visit::Visitor<'tcx> for LateContext<'a, 'tcx> { } fn visit_struct_field(&mut self, s: &'tcx hir::StructField) { - self.with_lint_attrs(&s.attrs, |cx| { + self.with_lint_attrs(s.id, &s.attrs, |cx| { run_lints!(cx, check_struct_field, late_passes, s); hir_visit::walk_struct_field(cx, s); }) @@ -994,7 +723,7 @@ impl<'a, 'tcx> hir_visit::Visitor<'tcx> for LateContext<'a, 'tcx> { v: &'tcx hir::Variant, g: &'tcx hir::Generics, item_id: ast::NodeId) { - self.with_lint_attrs(&v.node.attrs, |cx| { + self.with_lint_attrs(v.node.data.id(), &v.node.attrs, |cx| { run_lints!(cx, check_variant, late_passes, v, g); hir_visit::walk_variant(cx, v, g, item_id); run_lints!(cx, check_variant_post, late_passes, v, g); @@ -1017,7 +746,7 @@ impl<'a, 'tcx> hir_visit::Visitor<'tcx> for LateContext<'a, 'tcx> { } fn visit_local(&mut self, l: &'tcx hir::Local) { - self.with_lint_attrs(&l.attrs, |cx| { + self.with_lint_attrs(l.id, &l.attrs, |cx| { run_lints!(cx, check_local, late_passes, l); hir_visit::walk_local(cx, l); }) @@ -1045,7 +774,7 @@ impl<'a, 'tcx> hir_visit::Visitor<'tcx> for LateContext<'a, 'tcx> { } fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem) { - self.with_lint_attrs(&trait_item.attrs, |cx| { + self.with_lint_attrs(trait_item.id, &trait_item.attrs, |cx| { cx.with_param_env(trait_item.id, |cx| { run_lints!(cx, check_trait_item, late_passes, trait_item); hir_visit::walk_trait_item(cx, trait_item); @@ -1055,7 +784,7 @@ impl<'a, 'tcx> hir_visit::Visitor<'tcx> for LateContext<'a, 'tcx> { } fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem) { - self.with_lint_attrs(&impl_item.attrs, |cx| { + self.with_lint_attrs(impl_item.id, &impl_item.attrs, |cx| { cx.with_param_env(impl_item.id, |cx| { run_lints!(cx, check_impl_item, late_passes, impl_item); hir_visit::walk_impl_item(cx, impl_item); @@ -1080,14 +809,13 @@ impl<'a, 'tcx> hir_visit::Visitor<'tcx> for LateContext<'a, 'tcx> { } fn visit_attribute(&mut self, attr: &'tcx ast::Attribute) { - check_lint_name_attribute(self, attr); run_lints!(self, check_attribute, late_passes, attr); } } impl<'a> ast_visit::Visitor<'a> for EarlyContext<'a> { fn visit_item(&mut self, it: &'a ast::Item) { - self.with_lint_attrs(&it.attrs, |cx| { + self.with_lint_attrs(it.id, &it.attrs, |cx| { run_lints!(cx, check_item, early_passes, it); ast_visit::walk_item(cx, it); run_lints!(cx, check_item_post, early_passes, it); @@ -1095,7 +823,7 @@ impl<'a> ast_visit::Visitor<'a> for EarlyContext<'a> { } fn visit_foreign_item(&mut self, it: &'a ast::ForeignItem) { - self.with_lint_attrs(&it.attrs, |cx| { + self.with_lint_attrs(it.id, &it.attrs, |cx| { run_lints!(cx, check_foreign_item, early_passes, it); ast_visit::walk_foreign_item(cx, it); run_lints!(cx, check_foreign_item_post, early_passes, it); @@ -1104,11 +832,12 @@ impl<'a> ast_visit::Visitor<'a> for EarlyContext<'a> { fn visit_pat(&mut self, p: &'a ast::Pat) { run_lints!(self, check_pat, early_passes, p); + self.check_id(p.id); ast_visit::walk_pat(self, p); } fn visit_expr(&mut self, e: &'a ast::Expr) { - self.with_lint_attrs(&e.attrs, |cx| { + self.with_lint_attrs(e.id, &e.attrs, |cx| { run_lints!(cx, check_expr, early_passes, e); ast_visit::walk_expr(cx, e); }) @@ -1116,12 +845,14 @@ impl<'a> ast_visit::Visitor<'a> for EarlyContext<'a> { fn visit_stmt(&mut self, s: &'a ast::Stmt) { run_lints!(self, check_stmt, early_passes, s); + self.check_id(s.id); ast_visit::walk_stmt(self, s); } fn visit_fn(&mut self, fk: ast_visit::FnKind<'a>, decl: &'a ast::FnDecl, span: Span, id: ast::NodeId) { run_lints!(self, check_fn, early_passes, fk, decl, span, id); + self.check_id(id); ast_visit::walk_fn(self, fk, decl, span); run_lints!(self, check_fn_post, early_passes, fk, decl, span, id); } @@ -1133,19 +864,20 @@ impl<'a> ast_visit::Visitor<'a> for EarlyContext<'a> { item_id: ast::NodeId, _: Span) { run_lints!(self, check_struct_def, early_passes, s, ident, g, item_id); + self.check_id(s.id()); ast_visit::walk_struct_def(self, s); run_lints!(self, check_struct_def_post, early_passes, s, ident, g, item_id); } fn visit_struct_field(&mut self, s: &'a ast::StructField) { - self.with_lint_attrs(&s.attrs, |cx| { + self.with_lint_attrs(s.id, &s.attrs, |cx| { run_lints!(cx, check_struct_field, early_passes, s); ast_visit::walk_struct_field(cx, s); }) } fn visit_variant(&mut self, v: &'a ast::Variant, g: &'a ast::Generics, item_id: ast::NodeId) { - self.with_lint_attrs(&v.node.attrs, |cx| { + self.with_lint_attrs(item_id, &v.node.attrs, |cx| { run_lints!(cx, check_variant, early_passes, v, g); ast_visit::walk_variant(cx, v, g, item_id); run_lints!(cx, check_variant_post, early_passes, v, g); @@ -1154,6 +886,7 @@ impl<'a> ast_visit::Visitor<'a> for EarlyContext<'a> { fn visit_ty(&mut self, t: &'a ast::Ty) { run_lints!(self, check_ty, early_passes, t); + self.check_id(t.id); ast_visit::walk_ty(self, t); } @@ -1163,12 +896,13 @@ impl<'a> ast_visit::Visitor<'a> for EarlyContext<'a> { fn visit_mod(&mut self, m: &'a ast::Mod, s: Span, _a: &[ast::Attribute], n: ast::NodeId) { run_lints!(self, check_mod, early_passes, m, s, n); + self.check_id(n); ast_visit::walk_mod(self, m); run_lints!(self, check_mod_post, early_passes, m, s, n); } fn visit_local(&mut self, l: &'a ast::Local) { - self.with_lint_attrs(&l.attrs, |cx| { + self.with_lint_attrs(l.id, &l.attrs, |cx| { run_lints!(cx, check_local, early_passes, l); ast_visit::walk_local(cx, l); }) @@ -1176,6 +910,7 @@ impl<'a> ast_visit::Visitor<'a> for EarlyContext<'a> { fn visit_block(&mut self, b: &'a ast::Block) { run_lints!(self, check_block, early_passes, b); + self.check_id(b.id); ast_visit::walk_block(self, b); run_lints!(self, check_block_post, early_passes, b); } @@ -1195,7 +930,7 @@ impl<'a> ast_visit::Visitor<'a> for EarlyContext<'a> { } fn visit_trait_item(&mut self, trait_item: &'a ast::TraitItem) { - self.with_lint_attrs(&trait_item.attrs, |cx| { + self.with_lint_attrs(trait_item.id, &trait_item.attrs, |cx| { run_lints!(cx, check_trait_item, early_passes, trait_item); ast_visit::walk_trait_item(cx, trait_item); run_lints!(cx, check_trait_item_post, early_passes, trait_item); @@ -1203,7 +938,7 @@ impl<'a> ast_visit::Visitor<'a> for EarlyContext<'a> { } fn visit_impl_item(&mut self, impl_item: &'a ast::ImplItem) { - self.with_lint_attrs(&impl_item.attrs, |cx| { + self.with_lint_attrs(impl_item.id, &impl_item.attrs, |cx| { run_lints!(cx, check_impl_item, early_passes, impl_item); ast_visit::walk_impl_item(cx, impl_item); run_lints!(cx, check_impl_item_post, early_passes, impl_item); @@ -1212,6 +947,7 @@ impl<'a> ast_visit::Visitor<'a> for EarlyContext<'a> { fn visit_lifetime(&mut self, lt: &'a ast::Lifetime) { run_lints!(self, check_lifetime, early_passes, lt); + self.check_id(lt.id); } fn visit_lifetime_def(&mut self, lt: &'a ast::LifetimeDef) { @@ -1220,11 +956,13 @@ impl<'a> ast_visit::Visitor<'a> for EarlyContext<'a> { fn visit_path(&mut self, p: &'a ast::Path, id: ast::NodeId) { run_lints!(self, check_path, early_passes, p, id); + self.check_id(id); ast_visit::walk_path(self, p); } fn visit_path_list_item(&mut self, prefix: &'a ast::Path, item: &'a ast::PathListItem) { run_lints!(self, check_path_list_item, early_passes, item); + self.check_id(item.node.id); ast_visit::walk_path_list_item(self, prefix, item); } @@ -1233,110 +971,7 @@ impl<'a> ast_visit::Visitor<'a> for EarlyContext<'a> { } fn visit_mac_def(&mut self, _mac: &'a ast::MacroDef, id: ast::NodeId) { - let lints = self.sess.lints.borrow_mut().take(id); - for early_lint in lints { - self.early_lint(&early_lint); - } - } -} - -enum CheckLintNameResult { - Ok, - // Lint doesn't exist - NoLint, - // The lint is either renamed or removed. This is the warning - // message. - Warning(String), -} - -/// Checks the name of a lint for its existence, and whether it was -/// renamed or removed. Generates a DiagnosticBuilder containing a -/// warning for renamed and removed lints. This is over both lint -/// names from attributes and those passed on the command line. Since -/// it emits non-fatal warnings and there are *two* lint passes that -/// inspect attributes, this is only run from the late pass to avoid -/// printing duplicate warnings. -fn check_lint_name(lint_cx: &LintStore, - lint_name: &str) -> CheckLintNameResult { - match lint_cx.by_name.get(lint_name) { - Some(&Renamed(ref new_name, _)) => { - CheckLintNameResult::Warning( - format!("lint {} has been renamed to {}", lint_name, new_name) - ) - }, - Some(&Removed(ref reason)) => { - CheckLintNameResult::Warning( - format!("lint {} has been removed: {}", lint_name, reason) - ) - }, - None => { - match lint_cx.lint_groups.get(lint_name) { - None => { - CheckLintNameResult::NoLint - } - Some(_) => { - /* lint group exists */ - CheckLintNameResult::Ok - } - } - } - Some(_) => { - /* lint exists */ - CheckLintNameResult::Ok - } - } -} - -// Checks the validity of lint names derived from attributes -fn check_lint_name_attribute(cx: &LateContext, attr: &ast::Attribute) { - for result in gather_attr(attr) { - match result { - Err(_) => { - // Malformed lint attr. Reported by with_lint_attrs - continue; - } - Ok((lint_name, _, span)) => { - match check_lint_name(&cx.lint_sess.lints, &lint_name.as_str()) { - CheckLintNameResult::Ok => (), - CheckLintNameResult::Warning(ref msg) => { - cx.span_lint(builtin::RENAMED_AND_REMOVED_LINTS, - span, msg); - } - CheckLintNameResult::NoLint => { - cx.span_lint(builtin::UNKNOWN_LINTS, span, - &format!("unknown lint: `{}`", - lint_name)); - } - } - } - } - } -} - -// Checks the validity of lint names derived from the command line -fn check_lint_name_cmdline(sess: &Session, lint_cx: &LintStore, - lint_name: &str, level: Level) { - let db = match check_lint_name(lint_cx, lint_name) { - CheckLintNameResult::Ok => None, - CheckLintNameResult::Warning(ref msg) => { - Some(sess.struct_warn(msg)) - }, - CheckLintNameResult::NoLint => { - Some(struct_err!(sess, E0602, "unknown lint: `{}`", lint_name)) - } - }; - - if let Some(mut db) = db { - let msg = format!("requested on the command line with `{} {}`", - match level { - Level::Allow => "-A", - Level::Warn => "-W", - Level::Deny => "-D", - Level::Forbid => "-F", - }, - lint_name); - db.note(&msg); - db.emit(); + self.check_id(id); } } @@ -1355,10 +990,11 @@ pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { param_env: ty::ParamEnv::empty(Reveal::UserFacing), access_levels, lint_sess: LintSession::new(&tcx.sess.lint_store), + last_ast_node_with_lint_attrs: ast::CRATE_NODE_ID, }; // Visit the whole crate. - cx.with_lint_attrs(&krate.attrs, |cx| { + cx.with_lint_attrs(ast::CRATE_NODE_ID, &krate.attrs, |cx| { // since the root module isn't visited as an item (because it isn't an // item), warn for it here. run_lints!(cx, check_crate, late_passes, krate); @@ -1368,16 +1004,6 @@ pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { run_lints!(cx, check_crate_post, late_passes, krate); }); - // If we missed any lints added to the session, then there's a bug somewhere - // in the iteration code. - if let Some((id, v)) = tcx.sess.lints.borrow().get_any() { - for early_lint in v { - span_bug!(early_lint.diagnostic.span.clone(), - "unprocessed lint {:?} at {}", - early_lint, tcx.hir.node_to_string(*id)); - } - } - // Put the lint store levels and passes back in the session. cx.lint_sess.restore(&tcx.sess.lint_store); } @@ -1386,13 +1012,7 @@ pub fn check_ast_crate(sess: &Session, krate: &ast::Crate) { let mut cx = EarlyContext::new(sess, krate); // Visit the whole crate. - cx.with_lint_attrs(&krate.attrs, |cx| { - // Lints may be assigned to the whole crate. - let lints = cx.sess.lints.borrow_mut().take(ast::CRATE_NODE_ID); - for early_lint in lints { - cx.early_lint(&early_lint); - } - + cx.with_lint_attrs(ast::CRATE_NODE_ID, &krate.attrs, |cx| { // since the root module isn't visited as an item (because it isn't an // item), warn for it here. run_lints!(cx, check_crate, early_passes, krate); @@ -1405,11 +1025,11 @@ pub fn check_ast_crate(sess: &Session, krate: &ast::Crate) { // Put the lint store levels and passes back in the session. cx.lint_sess.restore(&sess.lint_store); - // If we missed any lints added to the session, then there's a bug somewhere - // in the iteration code. - for (_, v) in sess.lints.borrow().get_any() { - for early_lint in v { - span_bug!(early_lint.diagnostic.span.clone(), "unprocessed lint {:?}", early_lint); + // Emit all buffered lints from early on in the session now that we've + // calculated the lint levels for all AST nodes. + for (_id, lints) in cx.buffered.map { + for early_lint in lints { + span_bug!(early_lint.span, "failed to process bufferd lint here"); } } } @@ -1425,8 +1045,13 @@ impl Decodable for LintId { fn decode(d: &mut D) -> Result { let s = d.read_str()?; ty::tls::with(|tcx| { - match tcx.sess.lint_store.borrow().find_lint(&s) { - Ok(id) => Ok(id), + match tcx.sess.lint_store.borrow().find_lints(&s) { + Ok(ids) => { + if ids.len() != 0 { + panic!("invalid lint-id `{}`", s); + } + Ok(ids[0]) + } Err(_) => panic!("invalid lint-id `{}`", s), } }) diff --git a/src/librustc/lint/levels.rs b/src/librustc/lint/levels.rs new file mode 100644 index 0000000000000..ab9d4f75597b9 --- /dev/null +++ b/src/librustc/lint/levels.rs @@ -0,0 +1,343 @@ +// Copyright 2017 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. + +use std::cmp; + +use errors::DiagnosticBuilder; +use hir::HirId; +use lint::builtin; +use lint::context::CheckLintNameResult; +use lint::{self, Lint, LintId, Level, LintSource}; +use session::Session; +use syntax::ast; +use syntax::attr; +use syntax::codemap::MultiSpan; +use syntax::symbol::Symbol; +use util::nodemap::FxHashMap; + +pub struct LintLevelSets { + list: Vec, + lint_cap: Level, +} + +enum LintSet { + CommandLine { + // -A,-W,-D flags, a `Symbol` for the flag itself and `Level` for which + // flag. + specs: FxHashMap, + }, + + Node { + specs: FxHashMap, + parent: u32, + }, +} + +impl LintLevelSets { + pub fn new(sess: &Session) -> LintLevelSets { + let mut me = LintLevelSets { + list: Vec::new(), + lint_cap: Level::Forbid, + }; + me.process_command_line(sess); + return me + } + + pub fn builder(sess: &Session) -> LintLevelsBuilder { + LintLevelsBuilder::new(sess, LintLevelSets::new(sess)) + } + + fn process_command_line(&mut self, sess: &Session) { + let store = sess.lint_store.borrow(); + let mut specs = FxHashMap(); + self.lint_cap = sess.opts.lint_cap.unwrap_or(Level::Forbid); + + for &(ref lint_name, level) in &sess.opts.lint_opts { + store.check_lint_name_cmdline(sess, &lint_name, level); + + // If the cap is less than this specified level, e.g. if we've got + // `--cap-lints allow` but we've also got `-D foo` then we ignore + // this specification as the lint cap will set it to allow anyway. + let level = cmp::min(level, self.lint_cap); + + let lint_flag_val = Symbol::intern(lint_name); + let ids = match store.find_lints(&lint_name) { + Ok(ids) => ids, + Err(_) => continue, // errors handled in check_lint_name_cmdline above + }; + for id in ids { + let src = LintSource::CommandLine(lint_flag_val); + specs.insert(id, (level, src)); + } + } + + self.list.push(LintSet::CommandLine { + specs: specs, + }); + } + + fn get_lint_level(&self, lint: &'static Lint, idx: u32) + -> (Level, LintSource) + { + let (level, mut src) = self.get_lint_id_level(LintId::of(lint), idx); + + // If `level` is none then we actually assume the default level for this + // lint. + let mut level = level.unwrap_or(lint.default_level); + + // If we're about to issue a warning, check at the last minute for any + // directives against the warnings "lint". If, for example, there's an + // `allow(warnings)` in scope then we want to respect that instead. + if level == Level::Warn { + let (warnings_level, warnings_src) = + self.get_lint_id_level(LintId::of(lint::builtin::WARNINGS), idx); + if let Some(configured_warning_level) = warnings_level { + if configured_warning_level != Level::Warn { + level = configured_warning_level; + src = warnings_src; + } + } + } + + // Ensure that we never exceed the `--cap-lints` argument. + level = cmp::min(level, self.lint_cap); + + return (level, src) + } + + fn get_lint_id_level(&self, id: LintId, mut idx: u32) + -> (Option, LintSource) + { + loop { + match self.list[idx as usize] { + LintSet::CommandLine { ref specs } => { + if let Some(&(level, src)) = specs.get(&id) { + return (Some(level), src) + } + return (None, LintSource::Default) + } + LintSet::Node { ref specs, parent } => { + if let Some(&(level, src)) = specs.get(&id) { + return (Some(level), src) + } + idx = parent; + } + } + } + } +} + +pub struct LintLevelsBuilder<'a> { + sess: &'a Session, + sets: LintLevelSets, + id_to_set: FxHashMap, + cur: u32, + warn_about_weird_lints: bool, +} + +pub struct BuilderPush { + prev: u32, +} + +impl<'a> LintLevelsBuilder<'a> { + pub fn new(sess: &'a Session, sets: LintLevelSets) -> LintLevelsBuilder<'a> { + assert_eq!(sets.list.len(), 1); + LintLevelsBuilder { + sess, + sets, + cur: 0, + id_to_set: FxHashMap(), + warn_about_weird_lints: sess.buffered_lints.borrow().is_some(), + } + } + + /// Pushes a list of AST lint attributes onto this context. + /// + /// This function will return a `BuilderPush` object which should be be + /// passed to `pop` when this scope for the attributes provided is exited. + /// + /// This function will perform a number of tasks: + /// + /// * It'll validate all lint-related attributes in `attrs` + /// * It'll mark all lint-related attriutes as used + /// * Lint levels will be updated based on the attributes provided + /// * Lint attributes are validated, e.g. a #[forbid] can't be switched to + /// #[allow] + /// + /// Don't forget to call `pop`! + pub fn push(&mut self, attrs: &[ast::Attribute]) -> BuilderPush { + let mut specs = FxHashMap(); + let store = self.sess.lint_store.borrow(); + let sess = self.sess; + let bad_attr = |span| { + span_err!(sess, span, E0452, + "malformed lint attribute"); + }; + for attr in attrs { + let level = match attr.name().and_then(|name| Level::from_str(&name.as_str())) { + None => continue, + Some(lvl) => lvl, + }; + + let meta = unwrap_or!(attr.meta(), continue); + attr::mark_used(attr); + + let metas = if let Some(metas) = meta.meta_item_list() { + metas + } else { + bad_attr(meta.span); + continue + }; + + for li in metas { + let word = match li.word() { + Some(word) => word, + None => { + bad_attr(li.span); + continue + } + }; + let name = word.name(); + match store.check_lint_name(&name.as_str()) { + CheckLintNameResult::Ok(ids) => { + let src = LintSource::Node(name, li.span); + for id in ids { + specs.insert(*id, (level, src)); + } + } + CheckLintNameResult::Warning(ref msg) => { + if self.warn_about_weird_lints { + self.struct_lint(builtin::RENAMED_AND_REMOVED_LINTS, + Some(li.span.into()), + msg) + .emit(); + } + } + CheckLintNameResult::NoLint => { + if self.warn_about_weird_lints { + self.struct_lint(builtin::UNKNOWN_LINTS, + Some(li.span.into()), + &format!("unknown lint: `{}`", name)) + .emit(); + } + } + } + } + } + + for (id, &(level, ref src)) in specs.iter() { + if level == Level::Forbid { + continue + } + let forbid_src = match self.sets.get_lint_id_level(*id, self.cur) { + (Some(Level::Forbid), src) => src, + _ => continue, + }; + let forbidden_lint_name = match forbid_src { + LintSource::Default => id.to_string(), + LintSource::Node(name, _) => name.to_string(), + LintSource::CommandLine(name) => name.to_string(), + }; + let (lint_attr_name, lint_attr_span) = match *src { + LintSource::Node(name, span) => (name, span), + _ => continue, + }; + let mut diag_builder = struct_span_err!(self.sess, + lint_attr_span, + E0453, + "{}({}) overruled by outer forbid({})", + level.as_str(), + lint_attr_name, + forbidden_lint_name); + diag_builder.span_label(lint_attr_span, "overruled by previous forbid"); + match forbid_src { + LintSource::Default => &mut diag_builder, + LintSource::Node(_, forbid_source_span) => { + diag_builder.span_label(forbid_source_span, + "`forbid` level set here") + }, + LintSource::CommandLine(_) => { + diag_builder.note("`forbid` lint level was set on command line") + } + }.emit(); + // don't set a separate error for every lint in the group + break + } + + let prev = self.cur; + if specs.len() > 0 { + self.cur = self.sets.list.len() as u32; + self.sets.list.push(LintSet::Node { + specs: specs, + parent: prev, + }); + } + + BuilderPush { + prev: prev, + } + } + + /// Called after `push` when the scope of a set of attributes are exited. + pub fn pop(&mut self, push: BuilderPush) { + self.cur = push.prev; + } + + /// Used to emit a lint-related diagnostic based on the current state of + /// this lint context. + pub fn struct_lint(&self, + lint: &'static Lint, + span: Option, + msg: &str) + -> DiagnosticBuilder<'a> + { + let (level, src) = self.sets.get_lint_level(lint, self.cur); + lint::struct_lint_level(self.sess, lint, level, src, span, msg) + } + + /// Registers the ID provided with the current set of lints stored in + /// this context. + pub fn register_id(&mut self, id: HirId) { + self.id_to_set.insert(id, self.cur); + } + + pub fn build(self) -> LintLevelSets { + self.sets + } + + pub fn build_map(self) -> LintLevelMap { + LintLevelMap { + sets: self.sets, + id_to_set: self.id_to_set, + } + } +} + +pub struct LintLevelMap { + sets: LintLevelSets, + id_to_set: FxHashMap, +} + +impl LintLevelMap { + /// If the `id` was previously registered with `register_id` when building + /// this `LintLevelMap` this returns the corresponding lint level and source + /// of the lint level for the lint provided. + /// + /// If the `id` was not previously registered, returns `None`. If `None` is + /// returned then the parent of `id` should be acquired and this function + /// should be called again. + pub fn level_and_source(&self, lint: &'static Lint, id: HirId) + -> Option<(Level, LintSource)> + { + self.id_to_set.get(&id).map(|idx| { + self.sets.get_lint_level(lint, *idx) + }) + } +} diff --git a/src/librustc/lint/mod.rs b/src/librustc/lint/mod.rs index f9222ac9400af..c64e1c08082a5 100644 --- a/src/librustc/lint/mod.rs +++ b/src/librustc/lint/mod.rs @@ -31,20 +31,27 @@ pub use self::Level::*; pub use self::LintSource::*; +use std::rc::Rc; + +use errors::DiagnosticBuilder; +use hir::def_id::{CrateNum, LOCAL_CRATE}; +use hir::intravisit::{self, FnKind}; use hir; -use hir::intravisit::FnKind; -use std::hash; +use session::Session; use std::ascii::AsciiExt; -use syntax_pos::Span; -use syntax::visit as ast_visit; +use std::hash; use syntax::ast; +use syntax::codemap::MultiSpan; use syntax::symbol::Symbol; +use syntax::visit as ast_visit; +use syntax_pos::Span; +use ty::TyCtxt; +use ty::maps::Providers; +use util::nodemap::NodeMap; pub use lint::context::{LateContext, EarlyContext, LintContext, LintStore, - raw_emit_lint, check_crate, check_ast_crate, gather_attrs, - raw_struct_lint, FutureIncompatibleInfo, EarlyLint, IntoEarlyLint}; - -pub use lint::table::LintTable; + check_crate, check_ast_crate, + FutureIncompatibleInfo, BufferedEarlyLint}; /// Specification of a single lint. #[derive(Copy, Clone, Debug)] @@ -351,4 +358,215 @@ pub type LevelSource = (Level, LintSource); pub mod builtin; mod context; -mod table; +mod levels; + +pub use self::levels::{LintLevelSets, LintLevelMap}; + +pub struct LintBuffer { + map: NodeMap>, +} + +impl LintBuffer { + pub fn new() -> LintBuffer { + LintBuffer { map: NodeMap() } + } + + pub fn add_lint(&mut self, + lint: &'static Lint, + id: ast::NodeId, + sp: MultiSpan, + msg: &str) { + let early_lint = BufferedEarlyLint { + lint_id: LintId::of(lint), + ast_id: id, + span: sp, + msg: msg.to_string(), + }; + let arr = self.map.entry(id).or_insert(Vec::new()); + if !arr.contains(&early_lint) { + arr.push(early_lint); + } + } + + pub fn take(&mut self, id: ast::NodeId) -> Vec { + self.map.remove(&id).unwrap_or(Vec::new()) + } + + pub fn get_any(&self) -> Option<&[BufferedEarlyLint]> { + let key = self.map.keys().next().map(|k| *k); + key.map(|k| &self.map[&k][..]) + } +} + +pub fn struct_lint_level<'a>(sess: &'a Session, + lint: &'static Lint, + level: Level, + src: LintSource, + span: Option, + msg: &str) + -> DiagnosticBuilder<'a> +{ + let mut err = match (level, span) { + (Level::Allow, _) => return sess.diagnostic().struct_dummy(), + (Level::Warn, Some(span)) => sess.struct_span_warn(span, msg), + (Level::Warn, None) => sess.struct_warn(msg), + (Level::Deny, Some(span)) | + (Level::Forbid, Some(span)) => sess.struct_span_err(span, msg), + (Level::Deny, None) | + (Level::Forbid, None) => sess.struct_err(msg), + }; + + let name = lint.name_lower(); + match src { + LintSource::Default => { + sess.diag_note_once( + &mut err, + lint, + &format!("#[{}({})] on by default", level.as_str(), name)); + } + LintSource::CommandLine(lint_flag_val) => { + let flag = match level { + Level::Warn => "-W", + Level::Deny => "-D", + Level::Forbid => "-F", + Level::Allow => panic!(), + }; + let hyphen_case_lint_name = name.replace("_", "-"); + if lint_flag_val.as_str() == name { + sess.diag_note_once( + &mut err, + lint, + &format!("requested on the command line with `{} {}`", + flag, hyphen_case_lint_name)); + } else { + let hyphen_case_flag_val = lint_flag_val.as_str().replace("_", "-"); + sess.diag_note_once( + &mut err, + lint, + &format!("`{} {}` implied by `{} {}`", + flag, hyphen_case_lint_name, flag, + hyphen_case_flag_val)); + } + } + LintSource::Node(lint_attr_name, src) => { + sess.diag_span_note_once(&mut err, lint, src, "lint level defined here"); + if lint_attr_name.as_str() != name { + let level_str = level.as_str(); + sess.diag_note_once(&mut err, lint, + &format!("#[{}({})] implied by #[{}({})]", + level_str, name, level_str, lint_attr_name)); + } + } + } + + // Check for future incompatibility lints and issue a stronger warning. + let lints = sess.lint_store.borrow(); + if let Some(future_incompatible) = lints.future_incompatible(LintId::of(lint)) { + let explanation = format!("this was previously accepted by the compiler \ + but is being phased out; \ + it will become a hard error in a future release!"); + let citation = format!("for more information, see {}", + future_incompatible.reference); + err.warn(&explanation); + err.note(&citation); + } + + return err +} + +fn lint_levels<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, cnum: CrateNum) + -> Rc +{ + assert_eq!(cnum, LOCAL_CRATE); + let mut builder = LintLevelMapBuilder { + levels: LintLevelSets::builder(tcx.sess), + tcx: tcx, + }; + let krate = tcx.hir.krate(); + + builder.with_lint_attrs(ast::CRATE_NODE_ID, &krate.attrs, |builder| { + intravisit::walk_crate(builder, krate); + }); + + Rc::new(builder.levels.build_map()) +} + +struct LintLevelMapBuilder<'a, 'tcx: 'a> { + levels: levels::LintLevelsBuilder<'tcx>, + tcx: TyCtxt<'a, 'tcx, 'tcx>, +} + +impl<'a, 'tcx> LintLevelMapBuilder<'a, 'tcx> { + fn with_lint_attrs(&mut self, + id: ast::NodeId, + attrs: &[ast::Attribute], + f: F) + where F: FnOnce(&mut Self) + { + let push = self.levels.push(attrs); + self.levels.register_id(self.tcx.hir.definitions().node_to_hir_id(id)); + f(self); + self.levels.pop(push); + } +} + +impl<'a, 'tcx> intravisit::Visitor<'tcx> for LintLevelMapBuilder<'a, 'tcx> { + fn nested_visit_map<'this>(&'this mut self) -> intravisit::NestedVisitorMap<'this, 'tcx> { + intravisit::NestedVisitorMap::All(&self.tcx.hir) + } + + fn visit_item(&mut self, it: &'tcx hir::Item) { + self.with_lint_attrs(it.id, &it.attrs, |builder| { + intravisit::walk_item(builder, it); + }); + } + + fn visit_foreign_item(&mut self, it: &'tcx hir::ForeignItem) { + self.with_lint_attrs(it.id, &it.attrs, |builder| { + intravisit::walk_foreign_item(builder, it); + }) + } + + fn visit_expr(&mut self, e: &'tcx hir::Expr) { + self.with_lint_attrs(e.id, &e.attrs, |builder| { + intravisit::walk_expr(builder, e); + }) + } + + fn visit_struct_field(&mut self, s: &'tcx hir::StructField) { + self.with_lint_attrs(s.id, &s.attrs, |builder| { + intravisit::walk_struct_field(builder, s); + }) + } + + fn visit_variant(&mut self, + v: &'tcx hir::Variant, + g: &'tcx hir::Generics, + item_id: ast::NodeId) { + self.with_lint_attrs(v.node.data.id(), &v.node.attrs, |builder| { + intravisit::walk_variant(builder, v, g, item_id); + }) + } + + fn visit_local(&mut self, l: &'tcx hir::Local) { + self.with_lint_attrs(l.id, &l.attrs, |builder| { + intravisit::walk_local(builder, l); + }) + } + + fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem) { + self.with_lint_attrs(trait_item.id, &trait_item.attrs, |builder| { + intravisit::walk_trait_item(builder, trait_item); + }); + } + + fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem) { + self.with_lint_attrs(impl_item.id, &impl_item.attrs, |builder| { + intravisit::walk_impl_item(builder, impl_item); + }); + } +} + +pub fn provide(providers: &mut Providers) { + providers.lint_levels = lint_levels; +} diff --git a/src/librustc/lint/table.rs b/src/librustc/lint/table.rs deleted file mode 100644 index f2dab25229ae4..0000000000000 --- a/src/librustc/lint/table.rs +++ /dev/null @@ -1,71 +0,0 @@ -// Copyright 2012-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. - -use syntax::ast; -use syntax_pos::MultiSpan; -use util::nodemap::NodeMap; - -use super::{Lint, LintId, EarlyLint, IntoEarlyLint}; - -#[derive(RustcEncodable, RustcDecodable)] -pub struct LintTable { - map: NodeMap> -} - -impl LintTable { - pub fn new() -> Self { - LintTable { map: NodeMap() } - } - - pub fn add_lint>(&mut self, - lint: &'static Lint, - id: ast::NodeId, - sp: S, - msg: String) - { - self.add_lint_diagnostic(lint, id, (sp, &msg[..])) - } - - pub fn add_lint_diagnostic(&mut self, - lint: &'static Lint, - id: ast::NodeId, - msg: M) - where M: IntoEarlyLint, - { - let lint_id = LintId::of(lint); - let early_lint = msg.into_early_lint(lint_id); - let arr = self.map.entry(id).or_insert(vec![]); - if !arr.contains(&early_lint) { - arr.push(early_lint); - } - } - - pub fn get(&self, id: ast::NodeId) -> &[EarlyLint] { - self.map.get(&id).map(|v| &v[..]).unwrap_or(&[]) - } - - pub fn take(&mut self, id: ast::NodeId) -> Vec { - self.map.remove(&id).unwrap_or(vec![]) - } - - pub fn transfer(&mut self, into: &mut LintTable) { - into.map.extend(self.map.drain()); - } - - /// Returns the first (id, lint) pair that is non-empty. Used to - /// implement a sanity check in lints that all node-ids are - /// visited. - pub fn get_any(&self) -> Option<(&ast::NodeId, &Vec)> { - self.map.iter() - .filter(|&(_, v)| !v.is_empty()) - .next() - } -} - diff --git a/src/librustc/middle/dead.rs b/src/librustc/middle/dead.rs index a525b4e13b78d..4e08bc90c7c3a 100644 --- a/src/librustc/middle/dead.rs +++ b/src/librustc/middle/dead.rs @@ -17,11 +17,11 @@ use hir::{self, Item_, PatKind}; use hir::intravisit::{self, Visitor, NestedVisitorMap}; use hir::itemlikevisit::ItemLikeVisitor; -use middle::privacy; -use ty::{self, TyCtxt}; use hir::def::Def; use hir::def_id::{DefId, LOCAL_CRATE}; use lint; +use middle::privacy; +use ty::{self, TyCtxt}; use util::nodemap::FxHashSet; use syntax::{ast, codemap}; @@ -299,7 +299,9 @@ impl<'a, 'tcx> Visitor<'tcx> for MarkSymbolVisitor<'a, 'tcx> { } } -fn has_allow_dead_code_or_lang_attr(attrs: &[ast::Attribute]) -> bool { +fn has_allow_dead_code_or_lang_attr(tcx: TyCtxt, + id: ast::NodeId, + attrs: &[ast::Attribute]) -> bool { if attr::contains_name(attrs, "lang") { return true; } @@ -315,14 +317,7 @@ fn has_allow_dead_code_or_lang_attr(attrs: &[ast::Attribute]) -> bool { return true; } - let dead_code = lint::builtin::DEAD_CODE.name_lower(); - for attr in lint::gather_attrs(attrs) { - match attr { - Ok((name, lint::Allow, _)) if name == &*dead_code => return true, - _ => (), - } - } - false + tcx.lint_level_at_node(lint::builtin::DEAD_CODE, id).0 == lint::Allow } // This visitor seeds items that @@ -338,14 +333,17 @@ fn has_allow_dead_code_or_lang_attr(attrs: &[ast::Attribute]) -> bool { // or // 2) We are not sure to be live or not // * Implementation of a trait method -struct LifeSeeder<'k> { +struct LifeSeeder<'k, 'tcx: 'k> { worklist: Vec, krate: &'k hir::Crate, + tcx: TyCtxt<'k, 'tcx, 'tcx>, } -impl<'v, 'k> ItemLikeVisitor<'v> for LifeSeeder<'k> { +impl<'v, 'k, 'tcx> ItemLikeVisitor<'v> for LifeSeeder<'k, 'tcx> { fn visit_item(&mut self, item: &hir::Item) { - let allow_dead_code = has_allow_dead_code_or_lang_attr(&item.attrs); + let allow_dead_code = has_allow_dead_code_or_lang_attr(self.tcx, + item.id, + &item.attrs); if allow_dead_code { self.worklist.push(item.id); } @@ -360,7 +358,9 @@ impl<'v, 'k> ItemLikeVisitor<'v> for LifeSeeder<'k> { match trait_item.node { hir::TraitItemKind::Const(_, Some(_)) | hir::TraitItemKind::Method(_, hir::TraitMethod::Provided(_)) => { - if has_allow_dead_code_or_lang_attr(&trait_item.attrs) { + if has_allow_dead_code_or_lang_attr(self.tcx, + trait_item.id, + &trait_item.attrs) { self.worklist.push(trait_item.id); } } @@ -372,7 +372,9 @@ impl<'v, 'k> ItemLikeVisitor<'v> for LifeSeeder<'k> { for impl_item_ref in impl_item_refs { let impl_item = self.krate.impl_item(impl_item_ref.id); if opt_trait.is_some() || - has_allow_dead_code_or_lang_attr(&impl_item.attrs) { + has_allow_dead_code_or_lang_attr(self.tcx, + impl_item.id, + &impl_item.attrs) { self.worklist.push(impl_item_ref.id.node_id); } } @@ -408,6 +410,7 @@ fn create_and_seed_worklist<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let mut life_seeder = LifeSeeder { worklist, krate, + tcx, }; krate.visit_all_item_likes(&mut life_seeder); @@ -472,17 +475,19 @@ impl<'a, 'tcx> DeadVisitor<'a, 'tcx> { !field.is_positional() && !self.symbol_is_live(field.id, None) && !is_marker_field - && !has_allow_dead_code_or_lang_attr(&field.attrs) + && !has_allow_dead_code_or_lang_attr(self.tcx, field.id, &field.attrs) } fn should_warn_about_variant(&mut self, variant: &hir::Variant_) -> bool { !self.symbol_is_live(variant.data.id(), None) - && !has_allow_dead_code_or_lang_attr(&variant.attrs) + && !has_allow_dead_code_or_lang_attr(self.tcx, + variant.data.id(), + &variant.attrs) } fn should_warn_about_foreign_item(&mut self, fi: &hir::ForeignItem) -> bool { !self.symbol_is_live(fi.id, None) - && !has_allow_dead_code_or_lang_attr(&fi.attrs) + && !has_allow_dead_code_or_lang_attr(self.tcx, fi.id, &fi.attrs) } // id := node id of an item's definition. @@ -528,11 +533,10 @@ impl<'a, 'tcx> DeadVisitor<'a, 'tcx> { node_type: &str) { if !name.as_str().starts_with("_") { self.tcx - .sess - .add_lint(lint::builtin::DEAD_CODE, - id, - span, - format!("{} is never used: `{}`", node_type, name)); + .lint_node(lint::builtin::DEAD_CODE, + id, + span, + &format!("{} is never used: `{}`", node_type, name)); } } } diff --git a/src/librustc/middle/effect.rs b/src/librustc/middle/effect.rs index abd5cbcb89e33..fcf366788b223 100644 --- a/src/librustc/middle/effect.rs +++ b/src/librustc/middle/effect.rs @@ -56,11 +56,11 @@ impl<'a, 'tcx> EffectCheckVisitor<'a, 'tcx> { match self.unsafe_context.root { SafeContext => { if is_lint { - self.tcx.sess.add_lint(lint::builtin::SAFE_EXTERN_STATICS, - node_id, - span, - format!("{} requires unsafe function or \ - block (error E0133)", description)); + self.tcx.lint_node(lint::builtin::SAFE_EXTERN_STATICS, + node_id, + span, + &format!("{} requires unsafe function or \ + block (error E0133)", description)); } else { // Report an error. struct_span_err!( diff --git a/src/librustc/middle/liveness.rs b/src/librustc/middle/liveness.rs index 551a550442b3d..070ad5159086e 100644 --- a/src/librustc/middle/liveness.rs +++ b/src/librustc/middle/liveness.rs @@ -1482,12 +1482,12 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { }; if is_assigned { - self.ir.tcx.sess.add_lint(lint::builtin::UNUSED_VARIABLES, id, sp, - format!("variable `{}` is assigned to, but never used", - name)); + self.ir.tcx.lint_node(lint::builtin::UNUSED_VARIABLES, id, sp, + &format!("variable `{}` is assigned to, but never used", + name)); } else if name != "self" { - self.ir.tcx.sess.add_lint(lint::builtin::UNUSED_VARIABLES, id, sp, - format!("unused variable: `{}`", name)); + self.ir.tcx.lint_node(lint::builtin::UNUSED_VARIABLES, id, sp, + &format!("unused variable: `{}`", name)); } } true @@ -1509,11 +1509,11 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { fn report_dead_assign(&self, id: NodeId, sp: Span, var: Variable, is_argument: bool) { if let Some(name) = self.should_warn(var) { if is_argument { - self.ir.tcx.sess.add_lint(lint::builtin::UNUSED_ASSIGNMENTS, id, sp, - format!("value passed to `{}` is never read", name)); + self.ir.tcx.lint_node(lint::builtin::UNUSED_ASSIGNMENTS, id, sp, + &format!("value passed to `{}` is never read", name)); } else { - self.ir.tcx.sess.add_lint(lint::builtin::UNUSED_ASSIGNMENTS, id, sp, - format!("value assigned to `{}` is never read", name)); + self.ir.tcx.lint_node(lint::builtin::UNUSED_ASSIGNMENTS, id, sp, + &format!("value assigned to `{}` is never read", name)); } } } diff --git a/src/librustc/middle/stability.rs b/src/librustc/middle/stability.rs index 68c01db544a66..5158c7e94af4c 100644 --- a/src/librustc/middle/stability.rs +++ b/src/librustc/middle/stability.rs @@ -493,7 +493,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { format!("use of deprecated item") }; - self.sess.add_lint(lint::builtin::DEPRECATED, id, span, msg); + self.lint_node(lint::builtin::DEPRECATED, id, span, &msg); }; // Deprecated attributes apply in-crate and cross-crate. @@ -737,10 +737,10 @@ pub fn check_unused_or_stable_features<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { for &(ref stable_lang_feature, span) in &sess.features.borrow().declared_stable_lang_features { let version = find_lang_feature_accepted_version(&stable_lang_feature.as_str()) .expect("unexpectedly couldn't find version feature was stabilized"); - sess.add_lint(lint::builtin::STABLE_FEATURES, + tcx.lint_node(lint::builtin::STABLE_FEATURES, ast::CRATE_NODE_ID, span, - format_stable_since_msg(version)); + &format_stable_since_msg(version)); } let index = tcx.stability.borrow(); @@ -748,10 +748,10 @@ pub fn check_unused_or_stable_features<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { match remaining_lib_features.remove(used_lib_feature) { Some(span) => { if let &attr::StabilityLevel::Stable { since: ref version } = level { - sess.add_lint(lint::builtin::STABLE_FEATURES, + tcx.lint_node(lint::builtin::STABLE_FEATURES, ast::CRATE_NODE_ID, span, - format_stable_since_msg(&version.as_str())); + &format_stable_since_msg(&version.as_str())); } } None => ( /* used but undeclared, handled during the previous ast visit */ ) @@ -759,9 +759,9 @@ pub fn check_unused_or_stable_features<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { } for &span in remaining_lib_features.values() { - sess.add_lint(lint::builtin::UNUSED_FEATURES, + tcx.lint_node(lint::builtin::UNUSED_FEATURES, ast::CRATE_NODE_ID, span, - "unused or unknown feature".to_string()); + "unused or unknown feature"); } } diff --git a/src/librustc/session/mod.rs b/src/librustc/session/mod.rs index fe6b24f3e1f2a..be39f95b98899 100644 --- a/src/librustc/session/mod.rs +++ b/src/librustc/session/mod.rs @@ -79,7 +79,7 @@ pub struct Session { // if the value stored here has been affected by path remapping. pub working_dir: (String, bool), pub lint_store: RefCell, - pub lints: RefCell, + pub buffered_lints: RefCell>, /// Set of (LintId, Option, message) tuples tracking lint /// (sub)diagnostics that have been set once, but should not be set again, /// in order to avoid redundantly verbose output (Issue #24690). @@ -307,22 +307,15 @@ impl Session { self.diagnostic().unimpl(msg) } - pub fn add_lint>(&self, - lint: &'static lint::Lint, - id: ast::NodeId, - sp: S, - msg: String) - { - self.lints.borrow_mut().add_lint(lint, id, sp, msg); - } - - pub fn add_lint_diagnostic(&self, - lint: &'static lint::Lint, - id: ast::NodeId, - msg: M) - where M: lint::IntoEarlyLint, - { - self.lints.borrow_mut().add_lint_diagnostic(lint, id, msg); + pub fn buffer_lint>(&self, + lint: &'static lint::Lint, + id: ast::NodeId, + sp: S, + msg: &str) { + match *self.buffered_lints.borrow_mut() { + Some(ref mut buffer) => buffer.add_lint(lint, id, sp.into(), msg), + None => bug!("can't buffer lints after HIR lowering"), + } } pub fn reserve_node_ids(&self, count: usize) -> ast::NodeId { @@ -708,7 +701,7 @@ pub fn build_session_(sopts: config::Options, local_crate_source_file, working_dir, lint_store: RefCell::new(lint::LintStore::new()), - lints: RefCell::new(lint::LintTable::new()), + buffered_lints: RefCell::new(Some(lint::LintBuffer::new())), one_time_diagnostics: RefCell::new(FxHashSet()), plugin_llvm_passes: RefCell::new(Vec::new()), plugin_attributes: RefCell::new(Vec::new()), diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index 65c0a9f8ffd58..f0fc6998c9e51 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -499,11 +499,21 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { // weird effect -- the diagnostic is reported as a lint, and // the builder which is returned is marked as canceled. - let mut err = - struct_span_err!(self.tcx.sess, - error_span, - E0276, - "impl has stricter requirements than trait"); + let msg = "impl has stricter requirements than trait"; + let mut err = match lint_id { + Some(node_id) => { + self.tcx.struct_span_lint_node(EXTRA_REQUIREMENT_IN_IMPL, + node_id, + error_span, + msg) + } + None => { + struct_span_err!(self.tcx.sess, + error_span, + E0276, + "{}", msg) + } + }; if let Some(trait_item_span) = self.tcx.hir.span_if_local(trait_item_def_id) { let span = self.tcx.sess.codemap().def_span(trait_item_span); @@ -514,13 +524,6 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { error_span, format!("impl has extra requirement {}", requirement)); - if let Some(node_id) = lint_id { - self.tcx.sess.add_lint_diagnostic(EXTRA_REQUIREMENT_IN_IMPL, - node_id, - (*err).clone()); - err.cancel(); - } - err } diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs index c2feb54c4dbe6..e843ba35ce520 100644 --- a/src/librustc/traits/select.rs +++ b/src/librustc/traits/select.rs @@ -512,11 +512,11 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { } if raise_warning { - tcx.sess.add_lint(lint::builtin::RESOLVE_TRAIT_ON_DEFAULTED_UNIT, - obligation.cause.body_id, - obligation.cause.span, - format!("code relies on type inference rules which are likely \ - to change")); + tcx.lint_node(lint::builtin::RESOLVE_TRAIT_ON_DEFAULTED_UNIT, + obligation.cause.body_id, + obligation.cause.span, + &format!("code relies on type inference rules which are likely \ + to change")); } } Ok(ret) diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index be3cd99426d4d..6b9cbabf20e97 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -11,14 +11,15 @@ //! type context book-keeping use dep_graph::DepGraph; +use errors::DiagnosticBuilder; use session::Session; -use lint; use middle; use hir::TraitMap; use hir::def::{Def, ExportMap}; use hir::def_id::{CrateNum, DefId, LOCAL_CRATE}; use hir::map as hir_map; use hir::map::DefPathHash; +use lint::{self, Lint}; use middle::free_region::FreeRegionMap; use middle::lang_items; use middle::resolve_lifetime; @@ -58,6 +59,7 @@ use std::rc::Rc; use syntax::abi; use syntax::ast::{self, Name, NodeId}; use syntax::attr; +use syntax::codemap::MultiSpan; use syntax::symbol::{Symbol, keywords}; use syntax_pos::Span; @@ -254,9 +256,6 @@ pub struct TypeckTables<'tcx> { /// *from* expression of the cast, not the cast itself. pub cast_kinds: NodeMap, - /// Lints for the body of this fn generated by typeck. - pub lints: lint::LintTable, - /// Set of trait imports actually used in the method resolution. /// This is used for warning unused imports. pub used_trait_imports: DefIdSet, @@ -285,7 +284,6 @@ impl<'tcx> TypeckTables<'tcx> { liberated_fn_sigs: NodeMap(), fru_field_types: NodeMap(), cast_kinds: NodeMap(), - lints: lint::LintTable::new(), used_trait_imports: DefIdSet(), tainted_by_errors: false, free_region_map: FreeRegionMap::new(), @@ -1515,6 +1513,59 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { { self.mk_substs(iter::once(s).chain(t.into_iter().cloned()).map(Kind::from)) } + + pub fn lint_node>(self, + lint: &'static Lint, + id: NodeId, + span: S, + msg: &str) { + self.struct_span_lint_node(lint, id, span.into(), msg).emit() + } + + pub fn lint_level_at_node(self, lint: &'static Lint, mut id: NodeId) + -> (lint::Level, lint::LintSource) + { + // Right now we insert a `with_ignore` node in the dep graph here to + // ignore the fact that `lint_levels` below depends on the entire crate. + // For now this'll prevent false positives of recompiling too much when + // anything changes. + // + // Once red/green incremental compilation lands we should be able to + // remove this because while the crate changes often the lint level map + // will change rarely. + self.dep_graph.with_ignore(|| { + let sets = self.lint_levels(LOCAL_CRATE); + loop { + let hir_id = self.hir.definitions().node_to_hir_id(id); + if let Some(pair) = sets.level_and_source(lint, hir_id) { + return pair + } + let next = self.hir.get_parent_node(id); + if next == id { + bug!("lint traversal reached the root of the crate"); + } + id = next; + } + }) + } + + pub fn struct_span_lint_node>(self, + lint: &'static Lint, + id: NodeId, + span: S, + msg: &str) + -> DiagnosticBuilder<'tcx> + { + let (level, src) = self.lint_level_at_node(lint, id); + lint::struct_lint_level(self.sess, lint, level, src, Some(span.into()), msg) + } + + pub fn struct_lint_node(self, lint: &'static Lint, id: NodeId, msg: &str) + -> DiagnosticBuilder<'tcx> + { + let (level, src) = self.lint_level_at_node(lint, id); + lint::struct_lint_level(self.sess, lint, level, src, None, msg) + } } pub trait InternAs { diff --git a/src/librustc/ty/maps.rs b/src/librustc/ty/maps.rs index 5d25ce2fbeca3..b871b36c94850 100644 --- a/src/librustc/ty/maps.rs +++ b/src/librustc/ty/maps.rs @@ -12,6 +12,7 @@ use dep_graph::{DepConstructor, DepNode, DepNodeIndex}; use hir::def_id::{CrateNum, DefId, LOCAL_CRATE}; use hir::def::Def; use hir; +use lint; use middle::const_val; use middle::cstore::{ExternCrate, LinkagePreference}; use middle::privacy::AccessLevels; @@ -506,6 +507,12 @@ impl<'tcx> QueryDescription for queries::extern_crate<'tcx> { } } +impl<'tcx> QueryDescription for queries::lint_levels<'tcx> { + fn describe(_tcx: TyCtxt, _: CrateNum) -> String { + format!("computing the lint levels for items in this crate") + } +} + macro_rules! define_maps { (<$tcx:tt> $($(#[$attr:meta])* @@ -988,6 +995,8 @@ define_maps! { <'tcx> [] is_panic_runtime: IsPanicRuntime(DefId) -> bool, [] extern_crate: ExternCrate(DefId) -> Rc>, + + [] lint_levels: lint_levels(CrateNum) -> Rc, } fn type_param_predicates<'tcx>((item_id, param_id): (DefId, DefId)) -> DepConstructor<'tcx> { @@ -1059,3 +1068,7 @@ fn needs_drop_dep_node<'tcx>(_: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> DepConstruct fn layout_dep_node<'tcx>(_: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> DepConstructor<'tcx> { DepConstructor::Layout } + +fn lint_levels<'tcx>(_: CrateNum) -> DepConstructor<'tcx> { + DepConstructor::LintLevels +} diff --git a/src/librustc_const_eval/check_match.rs b/src/librustc_const_eval/check_match.rs index 060ff503d4e58..a3f8aae472cae 100644 --- a/src/librustc_const_eval/check_match.rs +++ b/src/librustc_const_eval/check_match.rs @@ -23,7 +23,7 @@ use rustc::session::Session; use rustc::ty::{self, Ty, TyCtxt}; use rustc::ty::subst::Substs; use rustc::lint; -use rustc_errors::{Diagnostic, Level, DiagnosticBuilder}; +use rustc_errors::DiagnosticBuilder; use rustc::hir::def::*; use rustc::hir::intravisit::{self, Visitor, FnKind, NestedVisitorMap}; @@ -351,12 +351,10 @@ fn check_arms<'a, 'tcx>(cx: &mut MatchCheckCtxt<'a, 'tcx>, match arm_index { // The arm with the user-specified pattern. 0 => { - let mut diagnostic = Diagnostic::new(Level::Warning, - "unreachable pattern"); - diagnostic.set_span(pat.span); - cx.tcx.sess.add_lint_diagnostic( + cx.tcx.lint_node( lint::builtin::UNREACHABLE_PATTERNS, - hir_pat.id, diagnostic); + hir_pat.id, pat.span, + "unreachable pattern"); }, // The arm with the wildcard pattern. 1 => { @@ -371,16 +369,18 @@ fn check_arms<'a, 'tcx>(cx: &mut MatchCheckCtxt<'a, 'tcx>, hir::MatchSource::ForLoopDesugar | hir::MatchSource::Normal => { - let mut diagnostic = Diagnostic::new(Level::Warning, - "unreachable pattern"); - diagnostic.set_span(pat.span); + let mut err = cx.tcx.struct_span_lint_node( + lint::builtin::UNREACHABLE_PATTERNS, + hir_pat.id, + pat.span, + "unreachable pattern", + ); // if we had a catchall pattern, hint at that if let Some(catchall) = catchall { - diagnostic.span_label(pat.span, "this is an unreachable pattern"); - diagnostic.span_note(catchall, "this pattern matches any value"); + err.span_label(pat.span, "this is an unreachable pattern"); + err.span_note(catchall, "this pattern matches any value"); } - cx.tcx.sess.add_lint_diagnostic(lint::builtin::UNREACHABLE_PATTERNS, - hir_pat.id, diagnostic); + err.emit(); }, // Unreachable patterns in try expressions occur when one of the arms diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index 12cb556afdabc..3c01d4bafab22 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -638,7 +638,6 @@ pub fn phase_2_configure_and_expand(sess: &Session, super::describe_lints(&sess.lint_store.borrow(), true); return Err(CompileIncomplete::Stopped); } - sess.track_errors(|| sess.lint_store.borrow_mut().process_command_line(sess))?; // Currently, we ignore the name resolution data structures for the purposes of dependency // tracking. Instead we will run name resolution and include its output in the hash of each @@ -708,8 +707,8 @@ pub fn phase_2_configure_and_expand(sess: &Session, missing_fragment_specifiers.sort(); for span in missing_fragment_specifiers { let lint = lint::builtin::MISSING_FRAGMENT_SPECIFIER; - let msg = "missing fragment specifier".to_string(); - sess.add_lint(lint, ast::CRATE_NODE_ID, span, msg); + let msg = "missing fragment specifier"; + sess.buffer_lint(lint, ast::CRATE_NODE_ID, span, msg); } if ecx.parse_sess.span_diagnostic.err_count() - ecx.resolve_err_count > err_count { ecx.parse_sess.span_diagnostic.abort_if_errors(); @@ -772,10 +771,6 @@ pub fn phase_2_configure_and_expand(sess: &Session, "checking for inline asm in case the target doesn't support it", || no_asm::check_crate(sess, &krate)); - time(time_passes, - "early lint checks", - || lint::check_ast_crate(sess, &krate)); - time(time_passes, "AST validation", || ast_validation::check_crate(sess, &krate)); @@ -800,6 +795,10 @@ pub fn phase_2_configure_and_expand(sess: &Session, }) })?; + time(time_passes, + "early lint checks", + || lint::check_ast_crate(sess, &krate)); + // Lower ast -> hir. let hir_forest = time(time_passes, "lowering ast -> hir", || { let hir_crate = lower_crate(sess, &krate, &mut resolver); @@ -908,6 +907,7 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session, rustc_const_eval::provide(&mut local_providers); middle::region::provide(&mut local_providers); cstore::provide_local(&mut local_providers); + lint::provide(&mut local_providers); let mut extern_providers = ty::maps::Providers::default(); cstore::provide(&mut extern_providers); @@ -1194,10 +1194,10 @@ pub fn collect_crate_types(session: &Session, attrs: &[ast::Attribute]) -> Vec Some(config::CrateTypeExecutable), Some(_) => { - session.add_lint(lint::builtin::UNKNOWN_CRATE_TYPES, - ast::CRATE_NODE_ID, - a.span, - "invalid `crate_type` value".to_string()); + session.buffer_lint(lint::builtin::UNKNOWN_CRATE_TYPES, + ast::CRATE_NODE_ID, + a.span, + "invalid `crate_type` value"); None } _ => { diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index db27fa874f4e9..88432e6429031 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -36,7 +36,7 @@ use rustc::ty::{self, Ty}; use rustc::traits::{self, Reveal}; use rustc::hir::map as hir_map; use util::nodemap::NodeSet; -use lint::{Level, LateContext, LintContext, LintArray}; +use lint::{LateContext, LintContext, LintArray}; use lint::{LintPass, LateLintPass, EarlyLintPass, EarlyContext}; use std::collections::HashSet; @@ -876,16 +876,13 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnconditionalRecursion { let mut db = cx.struct_span_lint(UNCONDITIONAL_RECURSION, sp, "function cannot return without recurring"); - // FIXME #19668: these could be span_lint_note's instead of this manual guard. - if cx.current_level(UNCONDITIONAL_RECURSION) != Level::Allow { - // offer some help to the programmer. - for call in &self_call_spans { - db.span_note(*call, "recursive call site"); - } - db.help("a `loop` may express intention \ - better if this is on purpose"); + // offer some help to the programmer. + for call in &self_call_spans { + db.span_note(*call, "recursive call site"); } + db.help("a `loop` may express intention \ + better if this is on purpose"); db.emit(); } diff --git a/src/librustc_passes/ast_validation.rs b/src/librustc_passes/ast_validation.rs index 38d8555334c35..2643ed2a3c074 100644 --- a/src/librustc_passes/ast_validation.rs +++ b/src/librustc_passes/ast_validation.rs @@ -237,10 +237,11 @@ impl<'a> Visitor<'a> for AstValidator<'a> { self.check_trait_fn_not_const(sig.constness); if block.is_none() { self.check_decl_no_pat(&sig.decl, |span, _| { - self.session.add_lint(lint::builtin::PATTERNS_IN_FNS_WITHOUT_BODY, - trait_item.id, span, - "patterns aren't allowed in methods \ - without bodies".to_string()); + self.session.buffer_lint( + lint::builtin::PATTERNS_IN_FNS_WITHOUT_BODY, + trait_item.id, span, + "patterns aren't allowed in methods \ + without bodies"); }); } } @@ -252,7 +253,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> { if item.attrs.iter().any(|attr| attr.check_name("warn_directory_ownership")) { let lint = lint::builtin::LEGACY_DIRECTORY_OWNERSHIP; let msg = "cannot declare a new module at this location"; - self.session.add_lint(lint, item.id, item.span, msg.to_string()); + self.session.buffer_lint(lint, item.id, item.span, msg); } } ItemKind::Union(ref vdata, _) => { diff --git a/src/librustc_passes/consts.rs b/src/librustc_passes/consts.rs index a881bf9eac7bf..8443cc8267d1c 100644 --- a/src/librustc_passes/consts.rs +++ b/src/librustc_passes/consts.rs @@ -76,12 +76,12 @@ impl<'a, 'gcx> CheckCrateVisitor<'a, 'gcx> { ErroneousReferencedConstant(_) => {} TypeckError => {} _ => { - self.tcx.sess.add_lint(CONST_ERR, - expr.id, - expr.span, - format!("constant evaluation error: {}. This will \ - become a HARD ERROR in the future", - err.description().into_oneline())) + self.tcx.lint_node(CONST_ERR, + expr.id, + expr.span, + &format!("constant evaluation error: {}. This will \ + become a HARD ERROR in the future", + err.description().into_oneline())); } } } @@ -260,10 +260,10 @@ impl<'a, 'tcx> Visitor<'tcx> for CheckCrateVisitor<'a, 'tcx> { kind: LayoutError(ty::layout::LayoutError::Unknown(_)), .. }) => {} Err(msg) => { - self.tcx.sess.add_lint(CONST_ERR, - ex.id, - msg.span, - msg.description().into_oneline().into_owned()) + self.tcx.lint_node(CONST_ERR, + ex.id, + msg.span, + &msg.description().into_oneline().into_owned()); } } } diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs index 64af24d92eecb..180d3dedf4b9b 100644 --- a/src/librustc_privacy/lib.rs +++ b/src/librustc_privacy/lib.rs @@ -1345,11 +1345,11 @@ impl<'a, 'tcx: 'a> SearchInterfaceForPrivateItemsVisitor<'a, 'tcx> { "private trait can't be public")) .emit(); } else { - self.tcx.sess.add_lint(lint::builtin::PRIVATE_IN_PUBLIC, - node_id, - self.span, - format!("private trait `{}` in public \ - interface (error E0445)", trait_ref)); + self.tcx.lint_node(lint::builtin::PRIVATE_IN_PUBLIC, + node_id, + self.span, + &format!("private trait `{}` in public \ + interface (error E0445)", trait_ref)); } } } @@ -1393,11 +1393,11 @@ impl<'a, 'tcx: 'a> TypeVisitor<'tcx> for SearchInterfaceForPrivateItemsVisitor<' err.span_label(self.span, "can't leak private type"); err.emit(); } else { - self.tcx.sess.add_lint(lint::builtin::PRIVATE_IN_PUBLIC, - node_id, - self.span, - format!("private type `{}` in public \ - interface (error E0446)", ty)); + self.tcx.lint_node(lint::builtin::PRIVATE_IN_PUBLIC, + node_id, + self.span, + &format!("private type `{}` in public \ + interface (error E0446)", ty)); } } } diff --git a/src/librustc_resolve/check_unused.rs b/src/librustc_resolve/check_unused.rs index d150ff1ff81f5..a8bb6619bbdda 100644 --- a/src/librustc_resolve/check_unused.rs +++ b/src/librustc_resolve/check_unused.rs @@ -122,13 +122,13 @@ pub fn check_crate(resolver: &mut Resolver, krate: &ast::Crate) { directive.span.source_equal(&DUMMY_SP) => {} ImportDirectiveSubclass::ExternCrate => { let lint = lint::builtin::UNUSED_EXTERN_CRATES; - let msg = "unused extern crate".to_string(); - resolver.session.add_lint(lint, directive.id, directive.span, msg); + let msg = "unused extern crate"; + ; resolver.session.buffer_lint(lint, directive.id, directive.span, msg) } ImportDirectiveSubclass::MacroUse => { let lint = lint::builtin::UNUSED_IMPORTS; - let msg = "unused `#[macro_use]` import".to_string(); - resolver.session.add_lint(lint, directive.id, directive.span, msg); + let msg = "unused `#[macro_use]` import"; + resolver.session.buffer_lint(lint, directive.id, directive.span, msg); } _ => {} } @@ -160,9 +160,6 @@ pub fn check_crate(resolver: &mut Resolver, krate: &ast::Crate) { } else { String::new() }); - visitor.session.add_lint(lint::builtin::UNUSED_IMPORTS, - *id, - ms, - msg); + visitor.session.buffer_lint(lint::builtin::UNUSED_IMPORTS, *id, ms, &msg); } } diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 2317e36a0ab89..b4f9ba4e8f78f 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -2552,9 +2552,10 @@ impl<'a> Resolver<'a> { = self.struct_constructors.get(&def_id).cloned() { if is_expected(ctor_def) && self.is_accessible(ctor_vis) { let lint = lint::builtin::LEGACY_CONSTRUCTOR_VISIBILITY; - self.session.add_lint(lint, id, span, + self.session.buffer_lint(lint, id, span, "private struct constructors are not usable through \ - reexports in outer modules".to_string()); + reexports in outer modules", + ); res = Some(PathResolution::new(ctor_def)); } } @@ -2748,7 +2749,7 @@ impl<'a> Resolver<'a> { }; if result.base_def() == unqualified_result { let lint = lint::builtin::UNUSED_QUALIFICATIONS; - self.session.add_lint(lint, id, span, "unnecessary qualification".to_string()); + self.session.buffer_lint(lint, id, span, "unnecessary qualification") } } @@ -3486,7 +3487,7 @@ impl<'a> Resolver<'a> { span.push_span_label(b1.span, msg1); span.push_span_label(b2.span, msg2); let msg = format!("`{}` is ambiguous", name); - self.session.add_lint(lint::builtin::LEGACY_IMPORTS, id, span, msg); + self.session.buffer_lint(lint::builtin::LEGACY_IMPORTS, id, span, &msg); } else { let mut err = self.session.struct_span_err(span, &format!("`{}` is ambiguous", name)); @@ -3607,8 +3608,8 @@ impl<'a> Resolver<'a> { fn warn_legacy_self_import(&self, directive: &'a ImportDirective<'a>) { let (id, span) = (directive.id, directive.span); - let msg = "`self` no longer imports values".to_string(); - self.session.add_lint(lint::builtin::LEGACY_IMPORTS, id, span, msg); + let msg = "`self` no longer imports values"; + self.session.buffer_lint(lint::builtin::LEGACY_IMPORTS, id, span, msg); } fn check_proc_macro_attrs(&mut self, attrs: &[ast::Attribute]) { diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs index 4d4f6aadce4df..98eaa056177ef 100644 --- a/src/librustc_resolve/macros.rs +++ b/src/librustc_resolve/macros.rs @@ -319,8 +319,8 @@ impl<'a> base::Resolver for Resolver<'a> { }; if let Some((id, span)) = id_span { let lint = lint::builtin::UNUSED_MACROS; - let msg = "unused macro definition".to_string(); - self.session.add_lint(lint, id, span, msg); + let msg = "unused macro definition"; + self.session.buffer_lint(lint, id, span, msg); } else { bug!("attempted to create unused macro error, but span not available"); } diff --git a/src/librustc_resolve/resolve_imports.rs b/src/librustc_resolve/resolve_imports.rs index 5e799b14f209c..984ef3a44e1a1 100644 --- a/src/librustc_resolve/resolve_imports.rs +++ b/src/librustc_resolve/resolve_imports.rs @@ -745,8 +745,10 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { let msg = format!("extern crate `{}` is private, and cannot be reexported \ (error E0365), consider declaring with `pub`", ident); - self.session.add_lint(PUB_USE_OF_PRIVATE_EXTERN_CRATE, - directive.id, directive.span, msg); + self.session.buffer_lint(PUB_USE_OF_PRIVATE_EXTERN_CRATE, + directive.id, + directive.span, + &msg); } else if ns == TypeNS { struct_span_err!(self.session, directive.span, E0365, "`{}` is private, and cannot be reexported", ident) diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 1ec850ad7f349..2910d25486ed5 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -985,9 +985,9 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { .span_label(data.span, "only traits may use parentheses") .emit(); } else { - let msg = "parenthesized parameters may only be used with a trait".to_string(); - self.tcx().sess.add_lint(PARENTHESIZED_PARAMS_IN_TYPES_AND_MODULES, - ast::CRATE_NODE_ID, data.span, msg); + let msg = "parenthesized parameters may only be used with a trait"; + self.tcx().lint_node(PARENTHESIZED_PARAMS_IN_TYPES_AND_MODULES, + ast::CRATE_NODE_ID, data.span, msg); } } } diff --git a/src/librustc_typeck/check/cast.rs b/src/librustc_typeck/check/cast.rs index b3f62de5b570b..5f256eab9a9c8 100644 --- a/src/librustc_typeck/check/cast.rs +++ b/src/librustc_typeck/check/cast.rs @@ -291,25 +291,25 @@ impl<'a, 'gcx, 'tcx> CastCheck<'tcx> { let t_cast = self.cast_ty; let t_expr = self.expr_ty; if t_cast.is_numeric() && t_expr.is_numeric() { - fcx.tables.borrow_mut().lints.add_lint( + fcx.tcx.lint_node( lint::builtin::TRIVIAL_NUMERIC_CASTS, self.expr.id, self.span, - format!("trivial numeric cast: `{}` as `{}`. Cast can be \ - replaced by coercion, this might require type \ - ascription or a temporary variable", - fcx.ty_to_string(t_expr), - fcx.ty_to_string(t_cast))); + &format!("trivial numeric cast: `{}` as `{}`. Cast can be \ + replaced by coercion, this might require type \ + ascription or a temporary variable", + fcx.ty_to_string(t_expr), + fcx.ty_to_string(t_cast))); } else { - fcx.tables.borrow_mut().lints.add_lint( + fcx.tcx.lint_node( lint::builtin::TRIVIAL_CASTS, self.expr.id, self.span, - format!("trivial cast: `{}` as `{}`. Cast can be \ - replaced by coercion, this might require type \ - ascription or a temporary variable", - fcx.ty_to_string(t_expr), - fcx.ty_to_string(t_cast))); + &format!("trivial cast: `{}` as `{}`. Cast can be \ + replaced by coercion, this might require type \ + ascription or a temporary variable", + fcx.ty_to_string(t_expr), + fcx.ty_to_string(t_cast))); } } diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index e53e5e7b08c97..6c9a6524d6781 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -1713,10 +1713,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { debug!("warn_if_unreachable: id={:?} span={:?} kind={}", id, span, kind); - self.tables.borrow_mut().lints.add_lint( + self.tcx().lint_node( lint::builtin::UNREACHABLE_CODE, id, span, - format!("unreachable {}", kind)); + &format!("unreachable {}", kind)); } } @@ -4746,8 +4746,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } else { let mut multispan = MultiSpan::from_span(lifetimes[0].span); multispan.push_span_label(span_late, note_msg.to_string()); - self.tcx.sess.add_lint(lint::builtin::LATE_BOUND_LIFETIME_ARGUMENTS, - lifetimes[0].id, multispan, primary_msg.to_string()); + self.tcx.lint_node(lint::builtin::LATE_BOUND_LIFETIME_ARGUMENTS, + lifetimes[0].id, multispan, primary_msg); } return; } diff --git a/src/librustc_typeck/check/writeback.rs b/src/librustc_typeck/check/writeback.rs index 0a323efabec1d..9e5cf5137c21f 100644 --- a/src/librustc_typeck/check/writeback.rs +++ b/src/librustc_typeck/check/writeback.rs @@ -43,7 +43,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { wbcx.visit_fru_field_types(); wbcx.visit_anon_types(); wbcx.visit_cast_types(); - wbcx.visit_lints(); wbcx.visit_free_region_map(); let used_trait_imports = mem::replace(&mut self.tables.borrow_mut().used_trait_imports, @@ -234,10 +233,6 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> { self.fcx.tables.borrow().cast_kinds.iter().map(|(&key, &value)| (key, value))); } - fn visit_lints(&mut self) { - self.fcx.tables.borrow_mut().lints.transfer(&mut self.tables.lints); - } - fn visit_free_region_map(&mut self) { let free_region_map = self.tcx().lift_to_global(&self.fcx.tables.borrow().free_region_map); let free_region_map = free_region_map.expect("all regions in free-region-map are global"); diff --git a/src/librustc_typeck/check_unused.rs b/src/librustc_typeck/check_unused.rs index 1af55d4d840d9..e95d49f00bf76 100644 --- a/src/librustc_typeck/check_unused.rs +++ b/src/librustc_typeck/check_unused.rs @@ -39,7 +39,7 @@ impl<'a, 'tcx> CheckVisitor<'a, 'tcx> { } else { "unused import".to_string() }; - self.tcx.sess.add_lint(lint::builtin::UNUSED_IMPORTS, id, span, msg); + self.tcx.lint_node(lint::builtin::UNUSED_IMPORTS, id, span, &msg); } } diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index f25a6cf58a79e..fba32dbb889d9 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -999,12 +999,12 @@ fn generics_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, if !allow_defaults && p.default.is_some() { if !tcx.sess.features.borrow().default_type_parameter_fallback { - tcx.sess.add_lint( + tcx.lint_node( lint::builtin::INVALID_TYPE_PARAM_DEFAULT, p.id, p.span, - format!("defaults for type parameters are only allowed in `struct`, \ - `enum`, `type`, or `trait` definitions.")); + &format!("defaults for type parameters are only allowed in `struct`, \ + `enum`, `type`, or `trait` definitions.")); } } diff --git a/src/test/compile-fail-fulldeps/proc-macro/attributes-included.rs b/src/test/compile-fail-fulldeps/proc-macro/attributes-included.rs index 508f8dac57119..f42d1006bf5c1 100644 --- a/src/test/compile-fail-fulldeps/proc-macro/attributes-included.rs +++ b/src/test/compile-fail-fulldeps/proc-macro/attributes-included.rs @@ -11,6 +11,7 @@ // aux-build:attributes-included.rs #![feature(proc_macro, rustc_attrs)] +#![warn(unused)] extern crate attributes_included; diff --git a/src/test/compile-fail/E0010.rs b/src/test/compile-fail/E0010.rs index 8a666168c86fd..ccaf01932d466 100644 --- a/src/test/compile-fail/E0010.rs +++ b/src/test/compile-fail/E0010.rs @@ -9,6 +9,7 @@ // except according to those terms. #![feature(box_syntax)] +#![allow(warnings)] const CON : Box = box 0; //~ ERROR E0010 //~| NOTE allocation not allowed in diff --git a/src/test/compile-fail/E0394.rs b/src/test/compile-fail/E0394.rs index e35d038248c81..c7d5665cd2c58 100644 --- a/src/test/compile-fail/E0394.rs +++ b/src/test/compile-fail/E0394.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#![allow(warnings)] + static A: u32 = 0; static B: u32 = A; //~^ ERROR E0394 diff --git a/src/test/compile-fail/bad-lint-cap2.rs b/src/test/compile-fail/bad-lint-cap2.rs index 5a97d7b1a79a1..cb9fb973a0193 100644 --- a/src/test/compile-fail/bad-lint-cap2.rs +++ b/src/test/compile-fail/bad-lint-cap2.rs @@ -10,6 +10,7 @@ // compile-flags: --cap-lints deny +#![warn(unused)] #![deny(warnings)] use std::option; //~ ERROR diff --git a/src/test/compile-fail/bad-lint-cap3.rs b/src/test/compile-fail/bad-lint-cap3.rs index e03ba6ecb6440..c9394954c5fbd 100644 --- a/src/test/compile-fail/bad-lint-cap3.rs +++ b/src/test/compile-fail/bad-lint-cap3.rs @@ -10,6 +10,7 @@ // compile-flags: --cap-lints warn +#![warn(unused)] #![deny(warnings)] #![feature(rustc_attrs)] diff --git a/src/test/compile-fail/check-static-values-constraints.rs b/src/test/compile-fail/check-static-values-constraints.rs index f65968e0e1192..3642add32597b 100644 --- a/src/test/compile-fail/check-static-values-constraints.rs +++ b/src/test/compile-fail/check-static-values-constraints.rs @@ -12,6 +12,7 @@ // gate-test-drop_types_in_const +#![allow(warnings)] #![feature(box_syntax)] use std::marker; diff --git a/src/test/compile-fail/const-eval-overflow-2.rs b/src/test/compile-fail/const-eval-overflow-2.rs index 9b045ed1d02cc..0fd41a17b2c9c 100644 --- a/src/test/compile-fail/const-eval-overflow-2.rs +++ b/src/test/compile-fail/const-eval-overflow-2.rs @@ -11,7 +11,7 @@ // Evaluation of constants in refutable patterns goes through // different compiler control-flow paths. -#![allow(unused_imports)] +#![allow(unused_imports, warnings)] use std::fmt; use std::{i8, i16, i32, i64, isize}; diff --git a/src/test/compile-fail/const-match-pattern-arm.rs b/src/test/compile-fail/const-match-pattern-arm.rs index 452aa87d6ba56..bc944948f3d8b 100644 --- a/src/test/compile-fail/const-match-pattern-arm.rs +++ b/src/test/compile-fail/const-match-pattern-arm.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#![allow(warnings)] + const x: bool = match Some(true) { Some(value) => true, //~^ ERROR: constant contains unimplemented expression type [E0019] diff --git a/src/test/compile-fail/feature-gate-dropck-ugeh.rs b/src/test/compile-fail/feature-gate-dropck-ugeh.rs index d9664fda2b339..360895d30b0b7 100644 --- a/src/test/compile-fail/feature-gate-dropck-ugeh.rs +++ b/src/test/compile-fail/feature-gate-dropck-ugeh.rs @@ -28,7 +28,6 @@ struct Foo { data: Vec } impl Drop for Foo { #[unsafe_destructor_blind_to_params] // This is the UGEH attribute //~^ ERROR unsafe_destructor_blind_to_params has been replaced - //~^^ WARN: use of deprecated attribute fn drop(&mut self) { } } diff --git a/src/test/compile-fail/issue-14227.rs b/src/test/compile-fail/issue-14227.rs index c4846a64f29be..d8f9f5543e439 100644 --- a/src/test/compile-fail/issue-14227.rs +++ b/src/test/compile-fail/issue-14227.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#![allow(safe_extern_statics, warnings)] + extern { pub static symbol: (); } diff --git a/src/test/compile-fail/issue-16538.rs b/src/test/compile-fail/issue-16538.rs index 6c41450796c74..08c3f7a7c1545 100644 --- a/src/test/compile-fail/issue-16538.rs +++ b/src/test/compile-fail/issue-16538.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#![allow(safe_extern_statics)] + mod Y { pub type X = usize; extern { diff --git a/src/test/compile-fail/issue-17450.rs b/src/test/compile-fail/issue-17450.rs index 5471d8522dffd..cde1bbbe4927a 100644 --- a/src/test/compile-fail/issue-17450.rs +++ b/src/test/compile-fail/issue-17450.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![allow(dead_code)] +#![allow(dead_code, warnings)] static mut x: isize = 3; static mut y: isize = unsafe { diff --git a/src/test/compile-fail/issue-17718-const-naming.rs b/src/test/compile-fail/issue-17718-const-naming.rs index 06719e2756b19..4857c2fb446b5 100644 --- a/src/test/compile-fail/issue-17718-const-naming.rs +++ b/src/test/compile-fail/issue-17718-const-naming.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#![warn(unused)] #[deny(warnings)] const foo: isize = 3; diff --git a/src/test/compile-fail/issue-17718-references.rs b/src/test/compile-fail/issue-17718-references.rs index c159168030b8c..8e0df283cdbeb 100644 --- a/src/test/compile-fail/issue-17718-references.rs +++ b/src/test/compile-fail/issue-17718-references.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#![allow(warnings)] + struct Struct { a: usize } const C: usize = 1; diff --git a/src/test/compile-fail/issue-18937.rs b/src/test/compile-fail/issue-18937.rs index f57f3477a8a86..5996c8e543878 100644 --- a/src/test/compile-fail/issue-18937.rs +++ b/src/test/compile-fail/issue-18937.rs @@ -26,7 +26,7 @@ trait A<'a> { } impl<'a> A<'a> for B { - fn foo(&mut self, f: F) //~ ERROR E0276 + fn foo(&mut self, f: F) //~ ERROR impl has stricter //~^ WARNING future release where F: fmt::Debug + 'static, { diff --git a/src/test/compile-fail/issue-28075.rs b/src/test/compile-fail/issue-28075.rs index cd73a45641111..057c99f930510 100644 --- a/src/test/compile-fail/issue-28075.rs +++ b/src/test/compile-fail/issue-28075.rs @@ -12,7 +12,7 @@ // aux-build:lint_stability.rs -#![allow(unused_imports)] +#![allow(warnings)] extern crate lint_stability; diff --git a/src/test/compile-fail/issue-28113.rs b/src/test/compile-fail/issue-28113.rs index 5c697b69c80b1..7d2541966a481 100644 --- a/src/test/compile-fail/issue-28113.rs +++ b/src/test/compile-fail/issue-28113.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#![allow(warnings)] + const X: u8 = || -> u8 { 5 }() //~^ ERROR calls in constants are limited to constant functions diff --git a/src/test/compile-fail/issue-28324.rs b/src/test/compile-fail/issue-28324.rs index 13ce41f4dcc54..3c4d6b42b503d 100644 --- a/src/test/compile-fail/issue-28324.rs +++ b/src/test/compile-fail/issue-28324.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#![allow(safe_extern_statics)] + extern { static error_message_count: u32; } diff --git a/src/test/compile-fail/issue-30730.rs b/src/test/compile-fail/issue-30730.rs index 086938334c78a..d1af39a6c1872 100644 --- a/src/test/compile-fail/issue-30730.rs +++ b/src/test/compile-fail/issue-30730.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#![warn(unused)] #![deny(warnings)] //~ NOTE: lint level defined here use std::thread; //~^ ERROR: unused import diff --git a/src/test/compile-fail/issue-37515.rs b/src/test/compile-fail/issue-37515.rs index fa452d6e74a05..d5733f9819387 100644 --- a/src/test/compile-fail/issue-37515.rs +++ b/src/test/compile-fail/issue-37515.rs @@ -9,6 +9,7 @@ // except according to those terms. #![feature(rustc_attrs)] +#![warn(unused)] type Z = for<'x> Send; //~^ WARN type alias is never used diff --git a/src/test/compile-fail/issue-7364.rs b/src/test/compile-fail/issue-7364.rs index 16b407baad178..bd32317ae7808 100644 --- a/src/test/compile-fail/issue-7364.rs +++ b/src/test/compile-fail/issue-7364.rs @@ -10,6 +10,7 @@ #![feature(box_syntax)] #![feature(const_fn)] +#![allow(warnings)] use std::cell::RefCell; diff --git a/src/test/compile-fail/lint-removed-allow.rs b/src/test/compile-fail/lint-removed-allow.rs index 1498ed4d17ed7..9f84190ea18a1 100644 --- a/src/test/compile-fail/lint-removed-allow.rs +++ b/src/test/compile-fail/lint-removed-allow.rs @@ -11,7 +11,8 @@ // No warnings about removed lint when // allow(renamed_and_removed_lints) +#![allow(renamed_and_removed_lints)] + #[deny(raw_pointer_derive)] -#[allow(renamed_and_removed_lints)] #[deny(unused_variables)] fn main() { let unused = (); } //~ ERROR unused diff --git a/src/test/compile-fail/lint-removed-cmdline.rs b/src/test/compile-fail/lint-removed-cmdline.rs index d6bfd1eec39a6..e1da5086612fd 100644 --- a/src/test/compile-fail/lint-removed-cmdline.rs +++ b/src/test/compile-fail/lint-removed-cmdline.rs @@ -16,5 +16,7 @@ // error-pattern:lint raw_pointer_derive has been removed // error-pattern:requested on the command line with `-D raw_pointer_derive` +#![warn(unused)] + #[deny(warnings)] fn main() { let unused = (); } diff --git a/src/test/compile-fail/lint-renamed-allow.rs b/src/test/compile-fail/lint-renamed-allow.rs index ea26c3656e691..ae010b64bfdfc 100644 --- a/src/test/compile-fail/lint-renamed-allow.rs +++ b/src/test/compile-fail/lint-renamed-allow.rs @@ -11,7 +11,8 @@ // No warnings about renamed lint when // allow(renamed_and_removed_lints) +#![allow(renamed_and_removed_lints)] + #[deny(unknown_features)] -#[allow(renamed_and_removed_lints)] #[deny(unused)] fn main() { let unused = (); } //~ ERROR unused diff --git a/src/test/compile-fail/lint-stability-deprecated.rs b/src/test/compile-fail/lint-stability-deprecated.rs index d8813b6a6101a..8443518b3f568 100644 --- a/src/test/compile-fail/lint-stability-deprecated.rs +++ b/src/test/compile-fail/lint-stability-deprecated.rs @@ -13,9 +13,9 @@ // aux-build:stability_cfg1.rs // aux-build:stability_cfg2.rs -#![deny(deprecated)] +#![warn(deprecated)] #![allow(dead_code)] -#![feature(staged_api, test_feature)] +#![feature(staged_api, test_feature, rustc_attrs)] #![stable(feature = "rust1", since = "1.0.0")] @@ -32,41 +32,41 @@ mod cross_crate { type Foo = MethodTester; let foo = MethodTester; - deprecated(); //~ ERROR use of deprecated item - foo.method_deprecated(); //~ ERROR use of deprecated item - Foo::method_deprecated(&foo); //~ ERROR use of deprecated item - ::method_deprecated(&foo); //~ ERROR use of deprecated item - foo.trait_deprecated(); //~ ERROR use of deprecated item - Trait::trait_deprecated(&foo); //~ ERROR use of deprecated item - ::trait_deprecated(&foo); //~ ERROR use of deprecated item - ::trait_deprecated(&foo); //~ ERROR use of deprecated item - - deprecated_text(); //~ ERROR use of deprecated item: text - foo.method_deprecated_text(); //~ ERROR use of deprecated item: text - Foo::method_deprecated_text(&foo); //~ ERROR use of deprecated item: text - ::method_deprecated_text(&foo); //~ ERROR use of deprecated item: text - foo.trait_deprecated_text(); //~ ERROR use of deprecated item: text - Trait::trait_deprecated_text(&foo); //~ ERROR use of deprecated item: text - ::trait_deprecated_text(&foo); //~ ERROR use of deprecated item: text - ::trait_deprecated_text(&foo); //~ ERROR use of deprecated item: text - - deprecated_unstable(); //~ ERROR use of deprecated item - foo.method_deprecated_unstable(); //~ ERROR use of deprecated item - Foo::method_deprecated_unstable(&foo); //~ ERROR use of deprecated item - ::method_deprecated_unstable(&foo); //~ ERROR use of deprecated item - foo.trait_deprecated_unstable(); //~ ERROR use of deprecated item - Trait::trait_deprecated_unstable(&foo); //~ ERROR use of deprecated item - ::trait_deprecated_unstable(&foo); //~ ERROR use of deprecated item - ::trait_deprecated_unstable(&foo); //~ ERROR use of deprecated item - - deprecated_unstable_text(); //~ ERROR use of deprecated item: text - foo.method_deprecated_unstable_text(); //~ ERROR use of deprecated item: text - Foo::method_deprecated_unstable_text(&foo); //~ ERROR use of deprecated item: text - ::method_deprecated_unstable_text(&foo); //~ ERROR use of deprecated item: text - foo.trait_deprecated_unstable_text(); //~ ERROR use of deprecated item: text - Trait::trait_deprecated_unstable_text(&foo); //~ ERROR use of deprecated item: text - ::trait_deprecated_unstable_text(&foo); //~ ERROR use of deprecated item: text - ::trait_deprecated_unstable_text(&foo); //~ ERROR use of deprecated item: text + deprecated(); //~ WARN use of deprecated item + foo.method_deprecated(); //~ WARN use of deprecated item + Foo::method_deprecated(&foo); //~ WARN use of deprecated item + ::method_deprecated(&foo); //~ WARN use of deprecated item + foo.trait_deprecated(); //~ WARN use of deprecated item + Trait::trait_deprecated(&foo); //~ WARN use of deprecated item + ::trait_deprecated(&foo); //~ WARN use of deprecated item + ::trait_deprecated(&foo); //~ WARN use of deprecated item + + deprecated_text(); //~ WARN use of deprecated item: text + foo.method_deprecated_text(); //~ WARN use of deprecated item: text + Foo::method_deprecated_text(&foo); //~ WARN use of deprecated item: text + ::method_deprecated_text(&foo); //~ WARN use of deprecated item: text + foo.trait_deprecated_text(); //~ WARN use of deprecated item: text + Trait::trait_deprecated_text(&foo); //~ WARN use of deprecated item: text + ::trait_deprecated_text(&foo); //~ WARN use of deprecated item: text + ::trait_deprecated_text(&foo); //~ WARN use of deprecated item: text + + deprecated_unstable(); //~ WARN use of deprecated item + foo.method_deprecated_unstable(); //~ WARN use of deprecated item + Foo::method_deprecated_unstable(&foo); //~ WARN use of deprecated item + ::method_deprecated_unstable(&foo); //~ WARN use of deprecated item + foo.trait_deprecated_unstable(); //~ WARN use of deprecated item + Trait::trait_deprecated_unstable(&foo); //~ WARN use of deprecated item + ::trait_deprecated_unstable(&foo); //~ WARN use of deprecated item + ::trait_deprecated_unstable(&foo); //~ WARN use of deprecated item + + deprecated_unstable_text(); //~ WARN use of deprecated item: text + foo.method_deprecated_unstable_text(); //~ WARN use of deprecated item: text + Foo::method_deprecated_unstable_text(&foo); //~ WARN use of deprecated item: text + ::method_deprecated_unstable_text(&foo); //~ WARN use of deprecated item: text + foo.trait_deprecated_unstable_text(); //~ WARN use of deprecated item: text + Trait::trait_deprecated_unstable_text(&foo); //~ WARN use of deprecated item: text + ::trait_deprecated_unstable_text(&foo); //~ WARN use of deprecated item: text + ::trait_deprecated_unstable_text(&foo); //~ WARN use of deprecated item: text unstable(); foo.method_unstable(); @@ -106,30 +106,30 @@ mod cross_crate { struct S1(T::TypeUnstable); struct S2(T::TypeDeprecated); - //~^ ERROR use of deprecated item + //~^ WARN use of deprecated item - let _ = DeprecatedStruct { //~ ERROR use of deprecated item - i: 0 //~ ERROR use of deprecated item + let _ = DeprecatedStruct { //~ WARN use of deprecated item + i: 0 //~ WARN use of deprecated item }; let _ = DeprecatedUnstableStruct { - //~^ ERROR use of deprecated item - i: 0 //~ ERROR use of deprecated item + //~^ WARN use of deprecated item + i: 0 //~ WARN use of deprecated item }; let _ = UnstableStruct { i: 0 }; let _ = StableStruct { i: 0 }; - let _ = DeprecatedUnitStruct; //~ ERROR use of deprecated item - let _ = DeprecatedUnstableUnitStruct; //~ ERROR use of deprecated item + let _ = DeprecatedUnitStruct; //~ WARN use of deprecated item + let _ = DeprecatedUnstableUnitStruct; //~ WARN use of deprecated item let _ = UnstableUnitStruct; let _ = StableUnitStruct; - let _ = Enum::DeprecatedVariant; //~ ERROR use of deprecated item - let _ = Enum::DeprecatedUnstableVariant; //~ ERROR use of deprecated item + let _ = Enum::DeprecatedVariant; //~ WARN use of deprecated item + let _ = Enum::DeprecatedUnstableVariant; //~ WARN use of deprecated item let _ = Enum::UnstableVariant; let _ = Enum::StableVariant; - let _ = DeprecatedTupleStruct (1); //~ ERROR use of deprecated item - let _ = DeprecatedUnstableTupleStruct (1); //~ ERROR use of deprecated item + let _ = DeprecatedTupleStruct (1); //~ WARN use of deprecated item + let _ = DeprecatedUnstableTupleStruct (1); //~ WARN use of deprecated item let _ = UnstableTupleStruct (1); let _ = StableTupleStruct (1); @@ -138,28 +138,28 @@ mod cross_crate { // Eventually, we will want to lint the contents of the // macro in the module *defining* it. Also, stability levels // on macros themselves are not yet linted. - macro_test_arg!(deprecated_text()); //~ ERROR use of deprecated item: text - macro_test_arg!(deprecated_unstable_text()); //~ ERROR use of deprecated item: text - macro_test_arg!(macro_test_arg!(deprecated_text())); //~ ERROR use of deprecated item: text + macro_test_arg!(deprecated_text()); //~ WARN use of deprecated item: text + macro_test_arg!(deprecated_unstable_text()); //~ WARN use of deprecated item: text + macro_test_arg!(macro_test_arg!(deprecated_text())); //~ WARN use of deprecated item: text } fn test_method_param(foo: Foo) { - foo.trait_deprecated(); //~ ERROR use of deprecated item - Trait::trait_deprecated(&foo); //~ ERROR use of deprecated item - ::trait_deprecated(&foo); //~ ERROR use of deprecated item - ::trait_deprecated(&foo); //~ ERROR use of deprecated item - foo.trait_deprecated_text(); //~ ERROR use of deprecated item: text - Trait::trait_deprecated_text(&foo); //~ ERROR use of deprecated item: text - ::trait_deprecated_text(&foo); //~ ERROR use of deprecated item: text - ::trait_deprecated_text(&foo); //~ ERROR use of deprecated item: text - foo.trait_deprecated_unstable(); //~ ERROR use of deprecated item - Trait::trait_deprecated_unstable(&foo); //~ ERROR use of deprecated item - ::trait_deprecated_unstable(&foo); //~ ERROR use of deprecated item - ::trait_deprecated_unstable(&foo); //~ ERROR use of deprecated item - foo.trait_deprecated_unstable_text(); //~ ERROR use of deprecated item: text - Trait::trait_deprecated_unstable_text(&foo); //~ ERROR use of deprecated item: text - ::trait_deprecated_unstable_text(&foo); //~ ERROR use of deprecated item: text - ::trait_deprecated_unstable_text(&foo); //~ ERROR use of deprecated item: text + foo.trait_deprecated(); //~ WARN use of deprecated item + Trait::trait_deprecated(&foo); //~ WARN use of deprecated item + ::trait_deprecated(&foo); //~ WARN use of deprecated item + ::trait_deprecated(&foo); //~ WARN use of deprecated item + foo.trait_deprecated_text(); //~ WARN use of deprecated item: text + Trait::trait_deprecated_text(&foo); //~ WARN use of deprecated item: text + ::trait_deprecated_text(&foo); //~ WARN use of deprecated item: text + ::trait_deprecated_text(&foo); //~ WARN use of deprecated item: text + foo.trait_deprecated_unstable(); //~ WARN use of deprecated item + Trait::trait_deprecated_unstable(&foo); //~ WARN use of deprecated item + ::trait_deprecated_unstable(&foo); //~ WARN use of deprecated item + ::trait_deprecated_unstable(&foo); //~ WARN use of deprecated item + foo.trait_deprecated_unstable_text(); //~ WARN use of deprecated item: text + Trait::trait_deprecated_unstable_text(&foo); //~ WARN use of deprecated item: text + ::trait_deprecated_unstable_text(&foo); //~ WARN use of deprecated item: text + ::trait_deprecated_unstable_text(&foo); //~ WARN use of deprecated item: text foo.trait_unstable(); Trait::trait_unstable(&foo); ::trait_unstable(&foo); @@ -175,10 +175,10 @@ mod cross_crate { } fn test_method_object(foo: &Trait) { - foo.trait_deprecated(); //~ ERROR use of deprecated item - foo.trait_deprecated_text(); //~ ERROR use of deprecated item: text - foo.trait_deprecated_unstable(); //~ ERROR use of deprecated item - foo.trait_deprecated_unstable_text(); //~ ERROR use of deprecated item: text + foo.trait_deprecated(); //~ WARN use of deprecated item + foo.trait_deprecated_text(); //~ WARN use of deprecated item: text + foo.trait_deprecated_unstable(); //~ WARN use of deprecated item + foo.trait_deprecated_unstable_text(); //~ WARN use of deprecated item: text foo.trait_unstable(); foo.trait_unstable_text(); foo.trait_stable(); @@ -187,9 +187,9 @@ mod cross_crate { struct S; impl UnstableTrait for S { } - impl DeprecatedTrait for S {} //~ ERROR use of deprecated item: text + impl DeprecatedTrait for S {} //~ WARN use of deprecated item: text trait LocalTrait : UnstableTrait { } - trait LocalTrait2 : DeprecatedTrait { } //~ ERROR use of deprecated item: text + trait LocalTrait2 : DeprecatedTrait { } //~ WARN use of deprecated item: text impl Trait for S { fn trait_stable(&self) {} @@ -208,7 +208,7 @@ mod inheritance { stable_mod::unstable(); stable_mod::stable(); - unstable_mod::deprecated(); //~ ERROR use of deprecated item + unstable_mod::deprecated(); //~ WARN use of deprecated item unstable_mod::unstable(); let _ = Unstable::UnstableVariant; @@ -330,23 +330,23 @@ mod this_crate { type Foo = MethodTester; let foo = MethodTester; - deprecated(); //~ ERROR use of deprecated item - foo.method_deprecated(); //~ ERROR use of deprecated item - Foo::method_deprecated(&foo); //~ ERROR use of deprecated item - ::method_deprecated(&foo); //~ ERROR use of deprecated item - foo.trait_deprecated(); //~ ERROR use of deprecated item - Trait::trait_deprecated(&foo); //~ ERROR use of deprecated item - ::trait_deprecated(&foo); //~ ERROR use of deprecated item - ::trait_deprecated(&foo); //~ ERROR use of deprecated item - - deprecated_text(); //~ ERROR use of deprecated item: text - foo.method_deprecated_text(); //~ ERROR use of deprecated item: text - Foo::method_deprecated_text(&foo); //~ ERROR use of deprecated item: text - ::method_deprecated_text(&foo); //~ ERROR use of deprecated item: text - foo.trait_deprecated_text(); //~ ERROR use of deprecated item: text - Trait::trait_deprecated_text(&foo); //~ ERROR use of deprecated item: text - ::trait_deprecated_text(&foo); //~ ERROR use of deprecated item: text - ::trait_deprecated_text(&foo); //~ ERROR use of deprecated item: text + deprecated(); //~ WARN use of deprecated item + foo.method_deprecated(); //~ WARN use of deprecated item + Foo::method_deprecated(&foo); //~ WARN use of deprecated item + ::method_deprecated(&foo); //~ WARN use of deprecated item + foo.trait_deprecated(); //~ WARN use of deprecated item + Trait::trait_deprecated(&foo); //~ WARN use of deprecated item + ::trait_deprecated(&foo); //~ WARN use of deprecated item + ::trait_deprecated(&foo); //~ WARN use of deprecated item + + deprecated_text(); //~ WARN use of deprecated item: text + foo.method_deprecated_text(); //~ WARN use of deprecated item: text + Foo::method_deprecated_text(&foo); //~ WARN use of deprecated item: text + ::method_deprecated_text(&foo); //~ WARN use of deprecated item: text + foo.trait_deprecated_text(); //~ WARN use of deprecated item: text + Trait::trait_deprecated_text(&foo); //~ WARN use of deprecated item: text + ::trait_deprecated_text(&foo); //~ WARN use of deprecated item: text + ::trait_deprecated_text(&foo); //~ WARN use of deprecated item: text unstable(); foo.method_unstable(); @@ -385,34 +385,34 @@ mod this_crate { ::trait_stable_text(&foo); let _ = DeprecatedStruct { - //~^ ERROR use of deprecated item - i: 0 //~ ERROR use of deprecated item + //~^ WARN use of deprecated item + i: 0 //~ WARN use of deprecated item }; let _ = UnstableStruct { i: 0 }; let _ = StableStruct { i: 0 }; - let _ = DeprecatedUnitStruct; //~ ERROR use of deprecated item + let _ = DeprecatedUnitStruct; //~ WARN use of deprecated item let _ = UnstableUnitStruct; let _ = StableUnitStruct; - let _ = Enum::DeprecatedVariant; //~ ERROR use of deprecated item + let _ = Enum::DeprecatedVariant; //~ WARN use of deprecated item let _ = Enum::UnstableVariant; let _ = Enum::StableVariant; - let _ = DeprecatedTupleStruct (1); //~ ERROR use of deprecated item + let _ = DeprecatedTupleStruct (1); //~ WARN use of deprecated item let _ = UnstableTupleStruct (1); let _ = StableTupleStruct (1); } fn test_method_param(foo: Foo) { - foo.trait_deprecated(); //~ ERROR use of deprecated item - Trait::trait_deprecated(&foo); //~ ERROR use of deprecated item - ::trait_deprecated(&foo); //~ ERROR use of deprecated item - ::trait_deprecated(&foo); //~ ERROR use of deprecated item - foo.trait_deprecated_text(); //~ ERROR use of deprecated item: text - Trait::trait_deprecated_text(&foo); //~ ERROR use of deprecated item: text - ::trait_deprecated_text(&foo); //~ ERROR use of deprecated item: text - ::trait_deprecated_text(&foo); //~ ERROR use of deprecated item: text + foo.trait_deprecated(); //~ WARN use of deprecated item + Trait::trait_deprecated(&foo); //~ WARN use of deprecated item + ::trait_deprecated(&foo); //~ WARN use of deprecated item + ::trait_deprecated(&foo); //~ WARN use of deprecated item + foo.trait_deprecated_text(); //~ WARN use of deprecated item: text + Trait::trait_deprecated_text(&foo); //~ WARN use of deprecated item: text + ::trait_deprecated_text(&foo); //~ WARN use of deprecated item: text + ::trait_deprecated_text(&foo); //~ WARN use of deprecated item: text foo.trait_unstable(); Trait::trait_unstable(&foo); ::trait_unstable(&foo); @@ -428,8 +428,8 @@ mod this_crate { } fn test_method_object(foo: &Trait) { - foo.trait_deprecated(); //~ ERROR use of deprecated item - foo.trait_deprecated_text(); //~ ERROR use of deprecated item: text + foo.trait_deprecated(); //~ WARN use of deprecated item + foo.trait_deprecated_text(); //~ WARN use of deprecated item: text foo.trait_unstable(); foo.trait_unstable_text(); foo.trait_stable(); @@ -439,7 +439,7 @@ mod this_crate { #[rustc_deprecated(since = "1.0.0", reason = "text")] fn test_fn_body() { fn fn_in_body() {} - fn_in_body(); //~ ERROR use of deprecated item: text + fn_in_body(); //~ WARN use of deprecated item: text } impl MethodTester { @@ -447,7 +447,7 @@ mod this_crate { #[rustc_deprecated(since = "1.0.0", reason = "text")] fn test_method_body(&self) { fn fn_in_body() {} - fn_in_body(); //~ ERROR use of deprecated item: text + fn_in_body(); //~ WARN use of deprecated item: text } } @@ -459,9 +459,9 @@ mod this_crate { struct S; - impl DeprecatedTrait for S { } //~ ERROR use of deprecated item + impl DeprecatedTrait for S { } //~ WARN use of deprecated item - trait LocalTrait : DeprecatedTrait { } //~ ERROR use of deprecated item + trait LocalTrait : DeprecatedTrait { } //~ WARN use of deprecated item } -fn main() {} +#[rustc_error] fn main() {} //~ ERROR: compilation successful diff --git a/src/test/compile-fail/lint-type-overflow2.rs b/src/test/compile-fail/lint-type-overflow2.rs index d399fda328625..5593499758346 100644 --- a/src/test/compile-fail/lint-type-overflow2.rs +++ b/src/test/compile-fail/lint-type-overflow2.rs @@ -9,16 +9,18 @@ // except according to those terms. // -#![deny(overflowing_literals)] -#![deny(const_err)] +#![warn(overflowing_literals)] +#![warn(const_err)] +#![feature(rustc_attrs)] #[allow(unused_variables)] -fn main() { - let x2: i8 = --128; //~ error: literal out of range for i8 - //~^ error: attempt to negate with overflow +#[rustc_error] +fn main() { //~ ERROR: compilation successful + let x2: i8 = --128; //~ warn: literal out of range for i8 + //~^ warn: attempt to negate with overflow - let x = -3.40282357e+38_f32; //~ error: literal out of range for f32 - let x = 3.40282357e+38_f32; //~ error: literal out of range for f32 - let x = -1.7976931348623159e+308_f64; //~ error: literal out of range for f64 - let x = 1.7976931348623159e+308_f64; //~ error: literal out of range for f64 + let x = -3.40282357e+38_f32; //~ warn: literal out of range for f32 + let x = 3.40282357e+38_f32; //~ warn: literal out of range for f32 + let x = -1.7976931348623159e+308_f64; //~ warn: literal out of range for f64 + let x = 1.7976931348623159e+308_f64; //~ warn: literal out of range for f64 } diff --git a/src/test/compile-fail/lint-uppercase-variables.rs b/src/test/compile-fail/lint-uppercase-variables.rs index 1615af400713c..1d947684792dd 100644 --- a/src/test/compile-fail/lint-uppercase-variables.rs +++ b/src/test/compile-fail/lint-uppercase-variables.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#![warn(unused)] #![allow(dead_code)] #![deny(non_snake_case)] diff --git a/src/test/compile-fail/liveness-unused.rs b/src/test/compile-fail/liveness-unused.rs index 3aab953eb7940..d056d6be806f7 100644 --- a/src/test/compile-fail/liveness-unused.rs +++ b/src/test/compile-fail/liveness-unused.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#![warn(unused)] #![deny(unused_variables)] #![deny(unused_assignments)] #![allow(dead_code, non_camel_case_types, trivial_numeric_casts)] diff --git a/src/test/compile-fail/never-assign-dead-code.rs b/src/test/compile-fail/never-assign-dead-code.rs index d8752e1c050fc..1e0cc0f5357fb 100644 --- a/src/test/compile-fail/never-assign-dead-code.rs +++ b/src/test/compile-fail/never-assign-dead-code.rs @@ -10,12 +10,12 @@ // Test that an assignment of type ! makes the rest of the block dead code. -#![feature(never_type)] -#![deny(unused, unreachable_code)] +#![feature(never_type, rustc_attrs)] +#![warn(unused)] -fn main() { - let x: ! = panic!("aah"); //~ ERROR unused - drop(x); //~ ERROR unreachable - //~^ ERROR unreachable +#[rustc_error] +fn main() { //~ ERROR: compilation successful + let x: ! = panic!("aah"); //~ WARN unused + drop(x); //~ WARN unreachable + //~^ WARN unreachable } - diff --git a/src/test/compile-fail/private-inferred-type.rs b/src/test/compile-fail/private-inferred-type.rs index 140891027d5f0..4d41f8ba47d01 100644 --- a/src/test/compile-fail/private-inferred-type.rs +++ b/src/test/compile-fail/private-inferred-type.rs @@ -11,6 +11,7 @@ #![feature(associated_consts)] #![feature(conservative_impl_trait)] #![feature(decl_macro)] +#![allow(warnings)] mod m { fn priv_fn() {} diff --git a/src/test/compile-fail/private-type-in-interface.rs b/src/test/compile-fail/private-type-in-interface.rs index 925d692f8ae6b..a5581664f7418 100644 --- a/src/test/compile-fail/private-type-in-interface.rs +++ b/src/test/compile-fail/private-type-in-interface.rs @@ -11,6 +11,7 @@ // aux-build:private-inferred-type.rs #![feature(conservative_impl_trait)] +#![allow(warnings)] extern crate private_inferred_type as ext; diff --git a/src/test/compile-fail/static-mut-not-constant.rs b/src/test/compile-fail/static-mut-not-constant.rs index 7c37abf765769..a855b08f06691 100644 --- a/src/test/compile-fail/static-mut-not-constant.rs +++ b/src/test/compile-fail/static-mut-not-constant.rs @@ -14,6 +14,7 @@ static mut a: Box = box 3; //~^ ERROR allocations are not allowed in statics -//~^^ ERROR destructors in statics are an unstable feature +//~| ERROR destructors in statics are an unstable feature +//~| WARN: constant evaluation error fn main() {} diff --git a/src/test/compile-fail/unreachable-try-pattern.rs b/src/test/compile-fail/unreachable-try-pattern.rs index f4817ba33b518..46ea4a06a3bd8 100644 --- a/src/test/compile-fail/unreachable-try-pattern.rs +++ b/src/test/compile-fail/unreachable-try-pattern.rs @@ -8,9 +8,9 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(never_type)] -#![deny(unreachable_code)] -#![deny(unreachable_patterns)] +#![feature(never_type, rustc_attrs)] +#![warn(unreachable_code)] +#![warn(unreachable_patterns)] enum Void {} @@ -26,8 +26,8 @@ fn bar(x: Result) -> Result { fn foo(x: Result) -> Result { let y = (match x { Ok(n) => Ok(n as u32), Err(e) => Err(e) })?; - //~^ ERROR unreachable pattern - //~| ERROR unreachable expression + //~^ WARN unreachable pattern + //~| WARN unreachable expression Ok(y) } @@ -37,11 +37,12 @@ fn qux(x: Result) -> Result { fn vom(x: Result) -> Result { let y = (match x { Ok(n) => Ok(n), Err(e) => Err(e) })?; - //~^ ERROR unreachable pattern + //~^ WARN unreachable pattern Ok(y) } -fn main() { +#[rustc_error] +fn main() { //~ ERROR: compilation successful let _ = bar(Err(123)); let _ = foo(Err(123)); let _ = qux(Ok(123)); diff --git a/src/test/ui-fulldeps/lint-plugin-cmdline-allow.rs b/src/test/ui-fulldeps/lint-plugin-cmdline-allow.rs index 1e428629cc2ff..19ce236213454 100644 --- a/src/test/ui-fulldeps/lint-plugin-cmdline-allow.rs +++ b/src/test/ui-fulldeps/lint-plugin-cmdline-allow.rs @@ -14,6 +14,7 @@ // compile-flags: -A test-lint #![feature(plugin)] +#![warn(unused)] #![plugin(lint_plugin_test)] fn lintme() { } diff --git a/src/test/ui-fulldeps/lint-plugin-cmdline-allow.stderr b/src/test/ui-fulldeps/lint-plugin-cmdline-allow.stderr index b8513b95d36c0..7c9c4e9903908 100644 --- a/src/test/ui-fulldeps/lint-plugin-cmdline-allow.stderr +++ b/src/test/ui-fulldeps/lint-plugin-cmdline-allow.stderr @@ -1,8 +1,13 @@ warning: function is never used: `lintme` - --> $DIR/lint-plugin-cmdline-allow.rs:19:1 + --> $DIR/lint-plugin-cmdline-allow.rs:20:1 | -19 | fn lintme() { } +20 | fn lintme() { } | ^^^^^^^^^^^^^^^ | - = note: #[warn(dead_code)] on by default +note: lint level defined here + --> $DIR/lint-plugin-cmdline-allow.rs:17:9 + | +17 | #![warn(unused)] + | ^^^^^^ + = note: #[warn(dead_code)] implied by #[warn(unused)] diff --git a/src/test/ui/check_match/issue-43253.rs b/src/test/ui/check_match/issue-43253.rs index c77fa74f6e0e5..108d7e1ea22a1 100644 --- a/src/test/ui/check_match/issue-43253.rs +++ b/src/test/ui/check_match/issue-43253.rs @@ -9,6 +9,7 @@ // except according to those terms. #![feature(exclusive_range_pattern)] +#![warn(unreachable_patterns)] fn main() { // These cases should generate no warning. @@ -48,4 +49,4 @@ fn main() { 9...9 => {}, _ => {}, } -} \ No newline at end of file +} diff --git a/src/test/ui/check_match/issue-43253.stderr b/src/test/ui/check_match/issue-43253.stderr index 0d4a2ecf512de..a1cb3963914c9 100644 --- a/src/test/ui/check_match/issue-43253.stderr +++ b/src/test/ui/check_match/issue-43253.stderr @@ -1,20 +1,24 @@ warning: unreachable pattern - --> $DIR/issue-43253.rs:36:9 + --> $DIR/issue-43253.rs:37:9 | -36 | 9 => {}, +37 | 9 => {}, | ^ | - = note: #[warn(unreachable_patterns)] on by default +note: lint level defined here + --> $DIR/issue-43253.rs:12:9 + | +12 | #![warn(unreachable_patterns)] + | ^^^^^^^^^^^^^^^^^^^^ warning: unreachable pattern - --> $DIR/issue-43253.rs:42:9 + --> $DIR/issue-43253.rs:43:9 | -42 | 8...9 => {}, +43 | 8...9 => {}, | ^^^^^ warning: unreachable pattern - --> $DIR/issue-43253.rs:48:9 + --> $DIR/issue-43253.rs:49:9 | -48 | 9...9 => {}, +49 | 9...9 => {}, | ^^^^^ diff --git a/src/test/ui/compare-method/proj-outlives-region.stderr b/src/test/ui/compare-method/proj-outlives-region.stderr index b1b5aedea70d8..e58251c846f8d 100644 --- a/src/test/ui/compare-method/proj-outlives-region.stderr +++ b/src/test/ui/compare-method/proj-outlives-region.stderr @@ -1,4 +1,4 @@ -error[E0276]: impl has stricter requirements than trait +error: impl has stricter requirements than trait --> $DIR/proj-outlives-region.rs:19:5 | 14 | fn foo() where T: 'a; diff --git a/src/test/ui/compare-method/region-unrelated.stderr b/src/test/ui/compare-method/region-unrelated.stderr index b02aa5eeb2f54..95db68fea5cf7 100644 --- a/src/test/ui/compare-method/region-unrelated.stderr +++ b/src/test/ui/compare-method/region-unrelated.stderr @@ -1,4 +1,4 @@ -error[E0276]: impl has stricter requirements than trait +error: impl has stricter requirements than trait --> $DIR/region-unrelated.rs:19:5 | 14 | fn foo() where T: 'a; diff --git a/src/test/ui/lint/fn_must_use.rs b/src/test/ui/lint/fn_must_use.rs index ea2197f3fd1a0..5aea5f2ca0642 100644 --- a/src/test/ui/lint/fn_must_use.rs +++ b/src/test/ui/lint/fn_must_use.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#![warn(unused_must_use)] struct MyStruct { n: usize diff --git a/src/test/ui/lint/fn_must_use.stderr b/src/test/ui/lint/fn_must_use.stderr index 7057c8e9aaad1..20eb7452aea71 100644 --- a/src/test/ui/lint/fn_must_use.stderr +++ b/src/test/ui/lint/fn_must_use.stderr @@ -1,14 +1,18 @@ warning: unused return value of `need_to_use_this_value` which must be used: it's important - --> $DIR/fn_must_use.rs:29:5 + --> $DIR/fn_must_use.rs:30:5 | -29 | need_to_use_this_value(); +30 | need_to_use_this_value(); | ^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: #[warn(unused_must_use)] on by default +note: lint level defined here + --> $DIR/fn_must_use.rs:11:9 + | +11 | #![warn(unused_must_use)] + | ^^^^^^^^^^^^^^^ warning: unused return value of `MyStruct::need_to_use_this_method_value` which must be used - --> $DIR/fn_must_use.rs:32:5 + --> $DIR/fn_must_use.rs:33:5 | -32 | m.need_to_use_this_method_value(); +33 | m.need_to_use_this_method_value(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/lint/outer-forbid.rs b/src/test/ui/lint/outer-forbid.rs index d71da58829a72..a79dacbc1c959 100644 --- a/src/test/ui/lint/outer-forbid.rs +++ b/src/test/ui/lint/outer-forbid.rs @@ -16,7 +16,13 @@ #![forbid(unused, non_snake_case)] -#[allow(unused, unused_variables, bad_style)] +#[allow(unused_variables)] +fn foo() {} + +#[allow(unused)] +fn bar() {} + +#[allow(bad_style)] fn main() { println!("hello forbidden world") } diff --git a/src/test/ui/lint/outer-forbid.stderr b/src/test/ui/lint/outer-forbid.stderr index df62f5acc0074..67a1f4f88adc6 100644 --- a/src/test/ui/lint/outer-forbid.stderr +++ b/src/test/ui/lint/outer-forbid.stderr @@ -1,29 +1,29 @@ -error[E0453]: allow(unused) overruled by outer forbid(unused) +error[E0453]: allow(unused_variables) overruled by outer forbid(unused) --> $DIR/outer-forbid.rs:19:9 | 17 | #![forbid(unused, non_snake_case)] | ------ `forbid` level set here 18 | -19 | #[allow(unused, unused_variables, bad_style)] - | ^^^^^^ overruled by previous forbid +19 | #[allow(unused_variables)] + | ^^^^^^^^^^^^^^^^ overruled by previous forbid -error[E0453]: allow(unused_variables) overruled by outer forbid(unused) - --> $DIR/outer-forbid.rs:19:17 +error[E0453]: allow(unused) overruled by outer forbid(unused) + --> $DIR/outer-forbid.rs:22:9 | 17 | #![forbid(unused, non_snake_case)] | ------ `forbid` level set here -18 | -19 | #[allow(unused, unused_variables, bad_style)] - | ^^^^^^^^^^^^^^^^ overruled by previous forbid +... +22 | #[allow(unused)] + | ^^^^^^ overruled by previous forbid error[E0453]: allow(bad_style) overruled by outer forbid(non_snake_case) - --> $DIR/outer-forbid.rs:19:35 + --> $DIR/outer-forbid.rs:25:9 | 17 | #![forbid(unused, non_snake_case)] | -------------- `forbid` level set here -18 | -19 | #[allow(unused, unused_variables, bad_style)] - | ^^^^^^^^^ overruled by previous forbid +... +25 | #[allow(bad_style)] + | ^^^^^^^^^ overruled by previous forbid error: aborting due to 3 previous errors diff --git a/src/test/ui/path-lookahead.rs b/src/test/ui/path-lookahead.rs index c43f2229cdc33..367a256015558 100644 --- a/src/test/ui/path-lookahead.rs +++ b/src/test/ui/path-lookahead.rs @@ -10,6 +10,8 @@ // run-pass +#![warn(unused)] + // Parser test for #37765 fn with_parens(arg: T) -> String { //~WARN function is never used: `with_parens` diff --git a/src/test/ui/path-lookahead.stderr b/src/test/ui/path-lookahead.stderr index 8fd1b8de68787..9936a1eb81e2a 100644 --- a/src/test/ui/path-lookahead.stderr +++ b/src/test/ui/path-lookahead.stderr @@ -1,26 +1,31 @@ warning: unnecessary parentheses around `return` value - --> $DIR/path-lookahead.rs:16:10 + --> $DIR/path-lookahead.rs:18:10 | -16 | return (::to_string(&arg)); //~WARN unnecessary parentheses around `return` value +18 | return (::to_string(&arg)); //~WARN unnecessary parentheses around `return` value | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: #[warn(unused_parens)] on by default warning: function is never used: `with_parens` - --> $DIR/path-lookahead.rs:15:1 + --> $DIR/path-lookahead.rs:17:1 | -15 | / fn with_parens(arg: T) -> String { //~WARN function is never used: `with_parens` -16 | | return (::to_string(&arg)); //~WARN unnecessary parentheses around `return` value -17 | | } +17 | / fn with_parens(arg: T) -> String { //~WARN function is never used: `with_parens` +18 | | return (::to_string(&arg)); //~WARN unnecessary parentheses around `return` value +19 | | } | |_^ | - = note: #[warn(dead_code)] on by default +note: lint level defined here + --> $DIR/path-lookahead.rs:13:9 + | +13 | #![warn(unused)] + | ^^^^^^ + = note: #[warn(dead_code)] implied by #[warn(unused)] warning: function is never used: `no_parens` - --> $DIR/path-lookahead.rs:19:1 + --> $DIR/path-lookahead.rs:21:1 | -19 | / fn no_parens(arg: T) -> String { //~WARN function is never used: `no_parens` -20 | | return ::to_string(&arg); -21 | | } +21 | / fn no_parens(arg: T) -> String { //~WARN function is never used: `no_parens` +22 | | return ::to_string(&arg); +23 | | } | |_^ diff --git a/src/test/ui/reachable/expr_unary.stderr b/src/test/ui/reachable/expr_unary.stderr index 328b75fd236bc..9f4562fe29718 100644 --- a/src/test/ui/reachable/expr_unary.stderr +++ b/src/test/ui/reachable/expr_unary.stderr @@ -1,8 +1,20 @@ +error: unreachable expression + --> $DIR/expr_unary.rs:18:28 + | +18 | let x: ! = ! { return; 22 }; + | ^^ + | +note: lint level defined here + --> $DIR/expr_unary.rs:14:9 + | +14 | #![deny(unreachable_code)] + | ^^^^^^^^^^^^^^^^ + error[E0600]: cannot apply unary operator `!` to type `!` --> $DIR/expr_unary.rs:18:16 | 18 | let x: ! = ! { return; 22 }; | ^^^^^^^^^^^^^^^^ -error: aborting due to previous error +error: aborting due to 2 previous errors diff --git a/src/test/ui/span/issue-24690.rs b/src/test/ui/span/issue-24690.rs index def0d9aced3c3..f59d2845108fb 100644 --- a/src/test/ui/span/issue-24690.rs +++ b/src/test/ui/span/issue-24690.rs @@ -11,10 +11,13 @@ //! A test to ensure that helpful `note` messages aren't emitted more often //! than necessary. -// Although there are three errors, we should only get two "lint level defined +#![feature(rustc_attrs)] + +// Although there are three warnings, we should only get two "lint level defined // here" notes pointing at the `warnings` span, one for each error type. -#![deny(warnings)] +#![warn(unused)] +#[rustc_error] fn main() { let theTwo = 2; let theOtherTwo = 2; diff --git a/src/test/ui/span/issue-24690.stderr b/src/test/ui/span/issue-24690.stderr index 8332ba50a73dc..4f1c870d87457 100644 --- a/src/test/ui/span/issue-24690.stderr +++ b/src/test/ui/span/issue-24690.stderr @@ -1,34 +1,37 @@ -error: variable `theTwo` should have a snake case name such as `the_two` - --> $DIR/issue-24690.rs:19:9 +warning: unused variable: `theOtherTwo` + --> $DIR/issue-24690.rs:23:9 | -19 | let theTwo = 2; - | ^^^^^^ +23 | let theOtherTwo = 2; + | ^^^^^^^^^^^ | note: lint level defined here - --> $DIR/issue-24690.rs:16:9 + --> $DIR/issue-24690.rs:18:9 | -16 | #![deny(warnings)] - | ^^^^^^^^ - = note: #[deny(non_snake_case)] implied by #[deny(warnings)] +18 | #![warn(unused)] + | ^^^^^^ + = note: #[warn(unused_variables)] implied by #[warn(unused)] -error: variable `theOtherTwo` should have a snake case name such as `the_other_two` - --> $DIR/issue-24690.rs:20:9 +warning: variable `theTwo` should have a snake case name such as `the_two` + --> $DIR/issue-24690.rs:22:9 | -20 | let theOtherTwo = 2; - | ^^^^^^^^^^^ +22 | let theTwo = 2; + | ^^^^^^ + | + = note: #[warn(non_snake_case)] on by default -error: unused variable: `theOtherTwo` - --> $DIR/issue-24690.rs:20:9 +warning: variable `theOtherTwo` should have a snake case name such as `the_other_two` + --> $DIR/issue-24690.rs:23:9 | -20 | let theOtherTwo = 2; +23 | let theOtherTwo = 2; | ^^^^^^^^^^^ - | -note: lint level defined here - --> $DIR/issue-24690.rs:16:9 - | -16 | #![deny(warnings)] - | ^^^^^^^^ - = note: #[deny(unused_variables)] implied by #[deny(warnings)] -error: aborting due to 3 previous errors +error: compilation successful + --> $DIR/issue-24690.rs:21:1 + | +21 | / fn main() { +22 | | let theTwo = 2; +23 | | let theOtherTwo = 2; +24 | | println!("{}", theTwo); +25 | | } + | |_^ diff --git a/src/test/ui/span/macro-span-replacement.rs b/src/test/ui/span/macro-span-replacement.rs index d779bec4ace53..b7aae39c46927 100644 --- a/src/test/ui/span/macro-span-replacement.rs +++ b/src/test/ui/span/macro-span-replacement.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#![warn(unused)] + macro_rules! m { ($a:tt $b:tt) => { $b $a; diff --git a/src/test/ui/span/macro-span-replacement.stderr b/src/test/ui/span/macro-span-replacement.stderr index e7336697f48e7..af03aa6a36908 100644 --- a/src/test/ui/span/macro-span-replacement.stderr +++ b/src/test/ui/span/macro-span-replacement.stderr @@ -1,11 +1,16 @@ warning: struct is never used: `S` - --> $DIR/macro-span-replacement.rs:13:9 + --> $DIR/macro-span-replacement.rs:15:9 | -13 | $b $a; +15 | $b $a; | ^^^^^^ ... -18 | m!(S struct); +20 | m!(S struct); | ------------- in this macro invocation | - = note: #[warn(dead_code)] on by default +note: lint level defined here + --> $DIR/macro-span-replacement.rs:11:9 + | +11 | #![warn(unused)] + | ^^^^^^ + = note: #[warn(dead_code)] implied by #[warn(unused)] diff --git a/src/test/ui/span/multispan-import-lint.rs b/src/test/ui/span/multispan-import-lint.rs index 43b6cd8f85f82..66536b29c0298 100644 --- a/src/test/ui/span/multispan-import-lint.rs +++ b/src/test/ui/span/multispan-import-lint.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#![warn(unused)] + use std::cmp::{Eq, Ord, min, PartialEq, PartialOrd}; fn main() { diff --git a/src/test/ui/span/multispan-import-lint.stderr b/src/test/ui/span/multispan-import-lint.stderr index 4b1ca7f98bbf6..1fecdea7d0d06 100644 --- a/src/test/ui/span/multispan-import-lint.stderr +++ b/src/test/ui/span/multispan-import-lint.stderr @@ -1,8 +1,13 @@ warning: unused imports: `Eq`, `Ord`, `PartialEq`, `PartialOrd` - --> $DIR/multispan-import-lint.rs:11:16 + --> $DIR/multispan-import-lint.rs:13:16 | -11 | use std::cmp::{Eq, Ord, min, PartialEq, PartialOrd}; +13 | use std::cmp::{Eq, Ord, min, PartialEq, PartialOrd}; | ^^ ^^^ ^^^^^^^^^ ^^^^^^^^^^ | - = note: #[warn(unused_imports)] on by default +note: lint level defined here + --> $DIR/multispan-import-lint.rs:11:9 + | +11 | #![warn(unused)] + | ^^^^^^ + = note: #[warn(unused_imports)] implied by #[warn(unused)] diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index 9369656170873..769748c63c02d 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -1156,9 +1156,21 @@ actual:\n\ fn compile_test(&self) -> ProcRes { let aux_dir = self.aux_output_dir_name(); // FIXME (#9639): This needs to handle non-utf8 paths - let link_args = vec!["-L".to_owned(), - aux_dir.to_str().unwrap().to_owned()]; - let args = self.make_compile_args(link_args, + let mut extra_args = vec!["-L".to_owned(), + aux_dir.to_str().unwrap().to_owned()]; + match self.config.mode { + CompileFail | Ui => { + // compile-fail and ui tests tend to have tons of unused code as + // it's just testing various pieces of the compile, but we don't + // want to actually assert warnings about all this code. Instead + // let's just ignore unused code warnings by defaults and tests + // can turn it back on if needed. + extra_args.push("-A".to_owned()); + extra_args.push("unused".to_owned()); + } + _ => {} + } + let args = self.make_compile_args(extra_args, &self.testpaths.file, TargetLocation::ThisFile(self.make_exe_name())); self.compose_and_run_compiler(args, None)