From d9438c30d59bbe7c4442e4a824a41a2bd00372ac Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Thu, 22 Feb 2018 15:25:31 -0800 Subject: [PATCH 1/8] Add ToString and FromStr impls for Epoch --- src/librustc/session/config.rs | 38 +++++++++++++++++++++++++++++----- 1 file changed, 33 insertions(+), 5 deletions(-) diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs index cfbf233297cf8..ef85ef8e37e70 100644 --- a/src/librustc/session/config.rs +++ b/src/librustc/session/config.rs @@ -41,7 +41,7 @@ use std::collections::btree_map::Iter as BTreeMapIter; use std::collections::btree_map::Keys as BTreeMapKeysIter; use std::collections::btree_map::Values as BTreeMapValuesIter; -use std::fmt; +use std::{fmt, str}; use std::hash::Hasher; use std::collections::hash_map::DefaultHasher; use std::collections::HashSet; @@ -137,6 +137,28 @@ pub enum Epoch { // as well as changing the default Cargo template. } +pub const ALL_EPOCHS: &[Epoch] = &[Epoch::Epoch2015, Epoch::Epoch2018]; + +impl ToString for Epoch { + fn to_string(&self) -> String { + match *self { + Epoch::Epoch2015 => "2015".into(), + Epoch::Epoch2018 => "2018".into(), + } + } +} + +impl str::FromStr for Epoch { + type Err = (); + fn from_str(s: &str) -> Result { + match s { + "2015" => Ok(Epoch::Epoch2015), + "2018" => Ok(Epoch::Epoch2018), + _ => Err(()) + } + } +} + impl_stable_hash_for!(enum self::OutputType { Bitcode, Assembly, @@ -1021,11 +1043,17 @@ macro_rules! options { fn parse_epoch(slot: &mut Epoch, v: Option<&str>) -> bool { match v { - Some("2015") => *slot = Epoch::Epoch2015, - Some("2018") => *slot = Epoch::Epoch2018, - _ => return false, + Some(s) => { + let epoch = s.parse(); + if let Ok(parsed) = epoch { + *slot = parsed; + true + } else { + false + } + } + _ => false, } - true } } ) } From da9dc0507bc86104db8bf7a99e849bfd995fb1ef Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Thu, 22 Feb 2018 16:51:42 -0800 Subject: [PATCH 2/8] Allow future-incompat lints to mention an epoch --- src/librustc/lint/context.rs | 27 ++++++++++++++++++++++----- src/librustc/lint/levels.rs | 17 ++++++++++------- src/librustc/lint/mod.rs | 29 +++++++++++++++++++++++++---- src/librustc/session/config.rs | 11 ++++++++++- src/librustc/session/mod.rs | 4 ++++ src/librustc/ty/context.rs | 2 +- src/librustc_driver/driver.rs | 2 +- src/librustc_driver/lib.rs | 20 ++++++++++---------- src/librustc_lint/lib.rs | 18 ++++++++++++++++++ 9 files changed, 101 insertions(+), 29 deletions(-) diff --git a/src/librustc/lint/context.rs b/src/librustc/lint/context.rs index ed937046e5ed7..870b52c221f37 100644 --- a/src/librustc/lint/context.rs +++ b/src/librustc/lint/context.rs @@ -99,7 +99,11 @@ pub struct BufferedEarlyLint { /// guidelines. pub struct FutureIncompatibleInfo { pub id: LintId, - pub reference: &'static str // e.g., a URL for an issue/PR/RFC or error code + /// e.g., a URL for an issue/PR/RFC or error code + pub reference: &'static str, + /// If this is an epoch fixing lint, the epoch in which + /// this lint becomes obsolete + pub epoch: Option, } /// The target of the `by_name` map, which accounts for renaming/deprecation. @@ -194,11 +198,24 @@ impl LintStore { pub fn register_future_incompatible(&mut self, sess: Option<&Session>, lints: Vec) { - let ids = lints.iter().map(|f| f.id).collect(); - self.register_group(sess, false, "future_incompatible", ids); - for info in lints { - self.future_incompatible.insert(info.id, info); + + for epoch in config::ALL_EPOCHS { + let lints = lints.iter().filter(|f| f.epoch == Some(*epoch)).map(|f| f.id) + .collect::>(); + if !lints.is_empty() { + self.register_group(sess, false, epoch.lint_name(), lints) + } + } + + let mut future_incompatible = vec![]; + for lint in lints { + future_incompatible.push(lint.id); + self.future_incompatible.insert(lint.id, lint); } + + self.register_group(sess, false, "future_incompatible", future_incompatible); + + } pub fn future_incompatible(&self, id: LintId) -> Option<&FutureIncompatibleInfo> { diff --git a/src/librustc/lint/levels.rs b/src/librustc/lint/levels.rs index 4bc37747f2a76..909904b4fc36c 100644 --- a/src/librustc/lint/levels.rs +++ b/src/librustc/lint/levels.rs @@ -89,14 +89,15 @@ impl LintLevelSets { fn get_lint_level(&self, lint: &'static Lint, idx: u32, - aux: Option<&FxHashMap>) + aux: Option<&FxHashMap>, + sess: &Session) -> (Level, LintSource) { let (level, mut src) = self.get_lint_id_level(LintId::of(lint), idx, aux); // If `level` is none then we actually assume the default level for this // lint. - let mut level = level.unwrap_or(lint.default_level); + let mut level = level.unwrap_or(lint.default_level(sess)); // 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 @@ -235,7 +236,8 @@ impl<'a> LintLevelsBuilder<'a> { let lint = builtin::RENAMED_AND_REMOVED_LINTS; let (level, src) = self.sets.get_lint_level(lint, self.cur, - Some(&specs)); + Some(&specs), + &sess); lint::struct_lint_level(self.sess, lint, level, @@ -248,7 +250,8 @@ impl<'a> LintLevelsBuilder<'a> { let lint = builtin::UNKNOWN_LINTS; let (level, src) = self.sets.get_lint_level(lint, self.cur, - Some(&specs)); + Some(&specs), + self.sess); let msg = format!("unknown lint: `{}`", name); let mut db = lint::struct_lint_level(self.sess, lint, @@ -342,7 +345,7 @@ impl<'a> LintLevelsBuilder<'a> { msg: &str) -> DiagnosticBuilder<'a> { - let (level, src) = self.sets.get_lint_level(lint, self.cur, None); + let (level, src) = self.sets.get_lint_level(lint, self.cur, None, self.sess); lint::struct_lint_level(self.sess, lint, level, src, span, msg) } @@ -377,11 +380,11 @@ impl LintLevelMap { /// 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) + pub fn level_and_source(&self, lint: &'static Lint, id: HirId, session: &Session) -> Option<(Level, LintSource)> { self.id_to_set.get(&id).map(|idx| { - self.sets.get_lint_level(lint, *idx, None) + self.sets.get_lint_level(lint, *idx, None, session) }) } diff --git a/src/librustc/lint/mod.rs b/src/librustc/lint/mod.rs index b2a9859f68a3e..e28cc9c201d02 100644 --- a/src/librustc/lint/mod.rs +++ b/src/librustc/lint/mod.rs @@ -37,7 +37,7 @@ use errors::{DiagnosticBuilder, DiagnosticId}; use hir::def_id::{CrateNum, LOCAL_CRATE}; use hir::intravisit::{self, FnKind}; use hir; -use session::{Session, DiagnosticMessageId}; +use session::{config, Session, DiagnosticMessageId}; use std::hash; use syntax::ast; use syntax::codemap::MultiSpan; @@ -74,6 +74,9 @@ pub struct Lint { /// /// e.g. "imports that are never used" pub desc: &'static str, + + /// Deny lint after this epoch + pub epoch_deny: Option, } impl Lint { @@ -81,18 +84,36 @@ impl Lint { pub fn name_lower(&self) -> String { self.name.to_ascii_lowercase() } + + pub fn default_level(&self, session: &Session) -> Level { + if let Some(epoch_deny) = self.epoch_deny { + if session.epoch() >= epoch_deny { + return Level::Deny + } + } + self.default_level + } } /// Declare a static item of type `&'static Lint`. #[macro_export] macro_rules! declare_lint { + ($vis: vis $NAME: ident, $Level: ident, $desc: expr, $epoch: expr) => ( + $vis static $NAME: &$crate::lint::Lint = &$crate::lint::Lint { + name: stringify!($NAME), + default_level: $crate::lint::$Level, + desc: $desc, + epoch_deny: Some($epoch) + }; + ); ($vis: vis $NAME: ident, $Level: ident, $desc: expr) => ( $vis static $NAME: &$crate::lint::Lint = &$crate::lint::Lint { name: stringify!($NAME), default_level: $crate::lint::$Level, - desc: $desc + desc: $desc, + epoch_deny: None, }; - ) + ); } /// Declare a static `LintArray` and return it as an expression. @@ -304,7 +325,7 @@ impl LintId { /// Setting for how to handle a lint. #[derive(Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Debug, Hash)] pub enum Level { - Allow, Warn, Deny, Forbid + Allow, Warn, Deny, Forbid, } impl_stable_hash_for!(enum self::Level { diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs index ef85ef8e37e70..beb828ab91bf7 100644 --- a/src/librustc/session/config.rs +++ b/src/librustc/session/config.rs @@ -113,7 +113,7 @@ pub enum OutputType { } /// The epoch of the compiler (RFC 2052) -#[derive(Clone, Copy, Hash, PartialOrd, Ord, Eq, PartialEq)] +#[derive(Clone, Copy, Hash, PartialOrd, Ord, Eq, PartialEq, Debug)] #[non_exhaustive] pub enum Epoch { // epochs must be kept in order, newest to oldest @@ -148,6 +148,15 @@ impl ToString for Epoch { } } +impl Epoch { + pub fn lint_name(&self) -> &'static str { + match *self { + Epoch::Epoch2015 => "epoch_2015", + Epoch::Epoch2018 => "epoch_2018", + } + } +} + impl str::FromStr for Epoch { type Err = (); fn from_str(s: &str) -> Result { diff --git a/src/librustc/session/mod.rs b/src/librustc/session/mod.rs index 9d7a9acc3d533..6901674a6cf8d 100644 --- a/src/librustc/session/mod.rs +++ b/src/librustc/session/mod.rs @@ -869,6 +869,10 @@ impl Session { pub fn rust_2018(&self) -> bool { self.opts.debugging_opts.epoch >= Epoch::Epoch2018 } + + pub fn epoch(&self) -> Epoch { + self.opts.debugging_opts.epoch + } } pub fn build_session(sopts: config::Options, diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index e4e07454c97ac..414ddb9efb2c2 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -2234,7 +2234,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { 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) { + if let Some(pair) = sets.level_and_source(lint, hir_id, self.sess) { return pair } let next = self.hir.get_parent_node(id); diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index b8a1fe9910540..943d690d76710 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -735,7 +735,7 @@ pub fn phase_2_configure_and_expand_inner<'a, F>(sess: &'a Session, // Lint plugins are registered; now we can process command line flags. if sess.opts.describe_lints { - super::describe_lints(&sess.lint_store.borrow(), true); + super::describe_lints(&sess, &sess.lint_store.borrow(), true); return Err(CompileIncomplete::Stopped); } diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs index 05dcaf731352a..5f0d106877c08 100644 --- a/src/librustc_driver/lib.rs +++ b/src/librustc_driver/lib.rs @@ -774,15 +774,15 @@ impl<'a> CompilerCalls<'a> for RustcDefaultCalls { -> Option<(Input, Option)> { match matches.free.len() { 0 => { + let mut sess = build_session(sopts.clone(), + None, + descriptions.clone()); if sopts.describe_lints { let mut ls = lint::LintStore::new(); - rustc_lint::register_builtins(&mut ls, None); - describe_lints(&ls, false); + rustc_lint::register_builtins(&mut ls, Some(&sess)); + describe_lints(&sess, &ls, false); return None; } - let mut sess = build_session(sopts.clone(), - None, - descriptions.clone()); rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess)); let mut cfg = config::build_configuration(&sess, cfg.clone()); let trans = get_trans(&sess); @@ -1121,7 +1121,7 @@ fn usage(verbose: bool, include_unstable_options: bool) { verbose_help); } -fn describe_lints(lint_store: &lint::LintStore, loaded_plugins: bool) { +fn describe_lints(sess: &Session, lint_store: &lint::LintStore, loaded_plugins: bool) { println!(" Available lint options: -W Warn about @@ -1133,10 +1133,10 @@ Available lint options: "); - fn sort_lints(lints: Vec<(&'static Lint, bool)>) -> Vec<&'static Lint> { + fn sort_lints(sess: &Session, lints: Vec<(&'static Lint, bool)>) -> Vec<&'static Lint> { let mut lints: Vec<_> = lints.into_iter().map(|(x, _)| x).collect(); lints.sort_by(|x: &&Lint, y: &&Lint| { - match x.default_level.cmp(&y.default_level) { + match x.default_level(sess).cmp(&y.default_level(sess)) { // The sort doesn't case-fold but it's doubtful we care. Equal => x.name.cmp(y.name), r => r, @@ -1159,8 +1159,8 @@ Available lint options: .iter() .cloned() .partition(|&(_, p)| p); - let plugin = sort_lints(plugin); - let builtin = sort_lints(builtin); + let plugin = sort_lints(sess, plugin); + let builtin = sort_lints(sess, builtin); let (plugin_groups, builtin_groups): (Vec<_>, _) = lint_store.get_lint_groups() .iter() diff --git a/src/librustc_lint/lib.rs b/src/librustc_lint/lib.rs index 699765dde03ff..c35a3fbe419d1 100644 --- a/src/librustc_lint/lib.rs +++ b/src/librustc_lint/lib.rs @@ -185,74 +185,92 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) { FutureIncompatibleInfo { id: LintId::of(PRIVATE_IN_PUBLIC), reference: "issue #34537 ", + epoch: None, }, FutureIncompatibleInfo { id: LintId::of(PUB_USE_OF_PRIVATE_EXTERN_CRATE), reference: "issue #34537 ", + epoch: None, }, FutureIncompatibleInfo { id: LintId::of(PATTERNS_IN_FNS_WITHOUT_BODY), reference: "issue #35203 ", + epoch: None, }, FutureIncompatibleInfo { id: LintId::of(SAFE_EXTERN_STATICS), reference: "issue #36247 ", + epoch: None, }, FutureIncompatibleInfo { id: LintId::of(INVALID_TYPE_PARAM_DEFAULT), reference: "issue #36887 ", + epoch: None, }, FutureIncompatibleInfo { id: LintId::of(LEGACY_DIRECTORY_OWNERSHIP), reference: "issue #37872 ", + epoch: None, }, FutureIncompatibleInfo { id: LintId::of(LEGACY_IMPORTS), reference: "issue #38260 ", + epoch: None, }, FutureIncompatibleInfo { id: LintId::of(LEGACY_CONSTRUCTOR_VISIBILITY), reference: "issue #39207 ", + epoch: None, }, FutureIncompatibleInfo { id: LintId::of(RESOLVE_TRAIT_ON_DEFAULTED_UNIT), reference: "issue #39216 ", + epoch: None, }, FutureIncompatibleInfo { id: LintId::of(MISSING_FRAGMENT_SPECIFIER), reference: "issue #40107 ", + epoch: None, }, FutureIncompatibleInfo { id: LintId::of(ILLEGAL_FLOATING_POINT_LITERAL_PATTERN), reference: "issue #41620 ", + epoch: None, }, FutureIncompatibleInfo { id: LintId::of(ANONYMOUS_PARAMETERS), reference: "issue #41686 ", + epoch: None, }, FutureIncompatibleInfo { id: LintId::of(PARENTHESIZED_PARAMS_IN_TYPES_AND_MODULES), reference: "issue #42238 ", + epoch: None, }, FutureIncompatibleInfo { id: LintId::of(LATE_BOUND_LIFETIME_ARGUMENTS), reference: "issue #42868 ", + epoch: None, }, FutureIncompatibleInfo { id: LintId::of(SAFE_PACKED_BORROWS), reference: "issue #46043 ", + epoch: None, }, FutureIncompatibleInfo { id: LintId::of(INCOHERENT_FUNDAMENTAL_IMPLS), reference: "issue #46205 ", + epoch: None, }, FutureIncompatibleInfo { id: LintId::of(COERCE_NEVER), reference: "issue #46325 ", + epoch: None, }, FutureIncompatibleInfo { id: LintId::of(TYVAR_BEHIND_RAW_POINTER), reference: "issue #46906 ", + epoch: None, }, ]); From 3eeabe7b7d13f8ca2d29e117f45cd420d6f73da4 Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Thu, 22 Feb 2018 22:14:08 -0800 Subject: [PATCH 3/8] Add hardwired lint for dyn trait --- src/librustc/lint/builtin.rs | 12 ++++++++++-- src/librustc_lint/lib.rs | 5 +++++ 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/src/librustc/lint/builtin.rs b/src/librustc/lint/builtin.rs index 0577800f3f411..2b1ff8a0e7881 100644 --- a/src/librustc/lint/builtin.rs +++ b/src/librustc/lint/builtin.rs @@ -15,6 +15,7 @@ //! lints are all available in `rustc_lint::builtin`. use lint::{LintPass, LateLintPass, LintArray}; +use session::config::Epoch; declare_lint! { pub CONST_ERR, @@ -252,6 +253,13 @@ declare_lint! { "hidden lifetime parameters are deprecated, try `Foo<'_>`" } +declare_lint! { + pub BARE_TRAIT_OBJECT, + Warn, + "suggest using `dyn Trait` for trait objects", + Epoch::Epoch2018 +} + /// Does nothing as a lint pass, but registers some `Lint`s /// which are used by other parts of the compiler. #[derive(Copy, Clone)] @@ -298,8 +306,8 @@ impl LintPass for HardwiredLints { COERCE_NEVER, SINGLE_USE_LIFETIME, TYVAR_BEHIND_RAW_POINTER, - ELIDED_LIFETIME_IN_PATH - + ELIDED_LIFETIME_IN_PATH, + BARE_TRAIT_OBJECT ) } } diff --git a/src/librustc_lint/lib.rs b/src/librustc_lint/lib.rs index c35a3fbe419d1..c162b8409af6a 100644 --- a/src/librustc_lint/lib.rs +++ b/src/librustc_lint/lib.rs @@ -272,6 +272,11 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) { reference: "issue #46906 ", epoch: None, }, + FutureIncompatibleInfo { + id: LintId::of(lint::builtin::BARE_TRAIT_OBJECT), + reference: "issue #48457 ", + epoch: Some(session::config::Epoch::Epoch2018), + } ]); // Register renamed and removed lints From bd29696218c9363d0e6dff7824c53f040eab76fc Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Thu, 22 Feb 2018 22:34:06 -0800 Subject: [PATCH 4/8] Add ability for hardwired lints to operate on the diagnostic builder --- src/librustc/lint/builtin.rs | 26 ++++++++++++++++++++++++++ src/librustc/lint/context.rs | 19 ++++++++++++++++--- src/librustc/lint/mod.rs | 5 ++++- src/librustc/session/mod.rs | 14 +++++++++++++- 4 files changed, 59 insertions(+), 5 deletions(-) diff --git a/src/librustc/lint/builtin.rs b/src/librustc/lint/builtin.rs index 2b1ff8a0e7881..cc7c5dc06660c 100644 --- a/src/librustc/lint/builtin.rs +++ b/src/librustc/lint/builtin.rs @@ -14,8 +14,11 @@ //! compiler code, rather than using their own custom pass. Those //! lints are all available in `rustc_lint::builtin`. +use errors::DiagnosticBuilder; use lint::{LintPass, LateLintPass, LintArray}; +use session::Session; use session::config::Epoch; +use syntax::codemap::Span; declare_lint! { pub CONST_ERR, @@ -312,4 +315,27 @@ impl LintPass for HardwiredLints { } } +// this could be a closure, but then implementing derive traits +// becomes hacky (and it gets allocated) +#[derive(PartialEq, RustcEncodable, RustcDecodable, Debug)] +pub enum BuiltinLintDiagnostics { + Normal, + BareTraitObject(Span) +} + +impl BuiltinLintDiagnostics { + pub fn run(self, sess: &Session, db: &mut DiagnosticBuilder) { + match self { + BuiltinLintDiagnostics::Normal => (), + BuiltinLintDiagnostics::BareTraitObject(span) => { + let sugg = match sess.codemap().span_to_snippet(span) { + Ok(s) => format!("dyn {}", s), + Err(_) => format!("dyn ") + }; + db.span_suggestion(span, "use `dyn`", sugg); + } + } + } +} + impl<'a, 'tcx> LateLintPass<'a, 'tcx> for HardwiredLints {} diff --git a/src/librustc/lint/context.rs b/src/librustc/lint/context.rs index 870b52c221f37..a9c023d14309d 100644 --- a/src/librustc/lint/context.rs +++ b/src/librustc/lint/context.rs @@ -29,6 +29,7 @@ use self::TargetLint::*; use std::slice; use lint::{EarlyLintPassObject, LateLintPassObject}; use lint::{Level, Lint, LintId, LintPass, LintBuffer}; +use lint::builtin::BuiltinLintDiagnostics; use lint::levels::{LintLevelSets, LintLevelsBuilder}; use middle::privacy::AccessLevels; use rustc_serialize::{Decoder, Decodable, Encoder, Encodable}; @@ -92,6 +93,7 @@ pub struct BufferedEarlyLint { pub ast_id: ast::NodeId, pub span: MultiSpan, pub msg: String, + pub diagnostic: BuiltinLintDiagnostics, } /// Extra information for a future incompatibility lint. See the call @@ -446,6 +448,16 @@ pub trait LintContext<'tcx>: Sized { self.lookup(lint, span, msg).emit(); } + fn lookup_and_emit_with_diagnostics>(&self, + lint: &'static Lint, + span: Option, + msg: &str, + diagnostic: BuiltinLintDiagnostics) { + let mut db = self.lookup(lint, span, msg); + diagnostic.run(self.sess(), &mut db); + db.emit(); + } + fn lookup>(&self, lint: &'static Lint, span: Option, @@ -516,9 +528,10 @@ impl<'a> EarlyContext<'a> { 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); + self.lookup_and_emit_with_diagnostics(early_lint.lint_id.lint, + Some(early_lint.span.clone()), + &early_lint.msg, + early_lint.diagnostic); } } } diff --git a/src/librustc/lint/mod.rs b/src/librustc/lint/mod.rs index e28cc9c201d02..a51d06c06edd3 100644 --- a/src/librustc/lint/mod.rs +++ b/src/librustc/lint/mod.rs @@ -37,6 +37,7 @@ use errors::{DiagnosticBuilder, DiagnosticId}; use hir::def_id::{CrateNum, LOCAL_CRATE}; use hir::intravisit::{self, FnKind}; use hir; +use lint::builtin::BuiltinLintDiagnostics; use session::{config, Session, DiagnosticMessageId}; use std::hash; use syntax::ast; @@ -399,12 +400,14 @@ impl LintBuffer { lint: &'static Lint, id: ast::NodeId, sp: MultiSpan, - msg: &str) { + msg: &str, + diagnostic: BuiltinLintDiagnostics) { let early_lint = BufferedEarlyLint { lint_id: LintId::of(lint), ast_id: id, span: sp, msg: msg.to_string(), + diagnostic }; let arr = self.map.entry(id).or_insert(Vec::new()); if !arr.contains(&early_lint) { diff --git a/src/librustc/session/mod.rs b/src/librustc/session/mod.rs index 6901674a6cf8d..7041efbd5bc5e 100644 --- a/src/librustc/session/mod.rs +++ b/src/librustc/session/mod.rs @@ -16,6 +16,7 @@ use ich::Fingerprint; use ich; use lint; +use lint::builtin::BuiltinLintDiagnostics; use middle::allocator::AllocatorKind; use middle::dependency_format; use session::search_paths::PathKind; @@ -341,7 +342,18 @@ impl Session { sp: S, msg: &str) { match *self.buffered_lints.borrow_mut() { - Some(ref mut buffer) => buffer.add_lint(lint, id, sp.into(), msg), + Some(ref mut buffer) => buffer.add_lint(lint, id, sp.into(), + msg, BuiltinLintDiagnostics::Normal), + None => bug!("can't buffer lints after HIR lowering"), + } + } + + pub fn buffer_lint_with_diagnostic>(&self, + lint: &'static lint::Lint, id: ast::NodeId, sp: S, + msg: &str, diagnostic: BuiltinLintDiagnostics) { + match *self.buffered_lints.borrow_mut() { + Some(ref mut buffer) => buffer.add_lint(lint, id, sp.into(), + msg, diagnostic), None => bug!("can't buffer lints after HIR lowering"), } } From 63168f72756da88c7488865160c7dfbd446bb0aa Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Thu, 22 Feb 2018 22:44:44 -0800 Subject: [PATCH 5/8] Lint bare traits --- src/librustc/hir/lowering.rs | 24 ++++++++++++++++++++---- src/librustc/lib.rs | 2 ++ src/librustc_mir/lib.rs | 1 + 3 files changed, 23 insertions(+), 4 deletions(-) diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index 55dcb16c3c95f..aeccf133fa86a 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -46,7 +46,7 @@ use hir::HirVec; use hir::map::{Definitions, DefKey, DefPathData}; use hir::def_id::{DefIndex, DefId, CRATE_DEF_INDEX, DefIndexAddressSpace}; use hir::def::{Def, PathResolution}; -use lint::builtin::PARENTHESIZED_PARAMS_IN_TYPES_AND_MODULES; +use lint::builtin::{self, PARENTHESIZED_PARAMS_IN_TYPES_AND_MODULES}; use middle::cstore::CrateStore; use rustc_data_structures::indexed_vec::IndexVec; use session::Session; @@ -912,7 +912,11 @@ impl<'a> LoweringContext<'a> { TyKind::Path(ref qself, ref path) => { let id = self.lower_node_id(t.id); let qpath = self.lower_qpath(t.id, qself, path, ParamMode::Explicit, itctx); - return self.ty_path(id, t.span, qpath); + let ty = self.ty_path(id, t.span, qpath); + if let hir::TyTraitObject(..) = ty.node { + self.maybe_lint_bare_trait(t.span, t.id); + } + return ty; } TyKind::ImplicitSelf => { hir::TyPath(hir::QPath::Resolved(None, P(hir::Path { @@ -931,7 +935,7 @@ impl<'a> LoweringContext<'a> { let expr = self.lower_body(None, |this| this.lower_expr(expr)); hir::TyTypeof(expr) } - TyKind::TraitObject(ref bounds, ..) => { + TyKind::TraitObject(ref bounds, kind) => { let mut lifetime_bound = None; let bounds = bounds.iter().filter_map(|bound| { match *bound { @@ -950,6 +954,9 @@ impl<'a> LoweringContext<'a> { let lifetime_bound = lifetime_bound.unwrap_or_else(|| { self.elided_lifetime(t.span) }); + if kind != TraitObjectSyntax::Dyn { + self.maybe_lint_bare_trait(t.span, t.id); + } hir::TyTraitObject(bounds, lifetime_bound) } TyKind::ImplTrait(ref bounds) => { @@ -3685,7 +3692,6 @@ impl<'a> LoweringContext<'a> { // The original ID is taken by the `PolyTraitRef`, // so the `Ty` itself needs a different one. id = self.next_id(); - hir::TyTraitObject(hir_vec![principal], self.elided_lifetime(span)) } else { hir::TyPath(hir::QPath::Resolved(None, path)) @@ -3703,6 +3709,16 @@ impl<'a> LoweringContext<'a> { name: hir::LifetimeName::Implicit, } } + + fn maybe_lint_bare_trait(&self, span: Span, id: NodeId) { + if self.sess.features.borrow().dyn_trait { + self.sess.buffer_lint_with_diagnostic( + builtin::BARE_TRAIT_OBJECT, id, span, + "trait objects without an explicit `dyn` are deprecated", + builtin::BuiltinLintDiagnostics::BareTraitObject(span) + ) + } + } } fn body_ids(bodies: &BTreeMap) -> Vec { diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs index a7a2619505931..e1ca4665df8bb 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -40,6 +40,8 @@ html_root_url = "https://doc.rust-lang.org/nightly/")] #![deny(warnings)] +#![cfg_attr(not(stage0), allow(bare_trait_object))] + #![feature(box_patterns)] #![feature(box_syntax)] #![feature(conservative_impl_trait)] diff --git a/src/librustc_mir/lib.rs b/src/librustc_mir/lib.rs index 1699ad0f19cf6..7905065bc1d8f 100644 --- a/src/librustc_mir/lib.rs +++ b/src/librustc_mir/lib.rs @@ -15,6 +15,7 @@ Rust MIR: a lowered representation of Rust. Also: an experiment! */ #![deny(warnings)] +#![cfg_attr(not(stage0), allow(bare_trait_object))] #![feature(box_patterns)] #![feature(box_syntax)] From 177271f91401852841c647ae01b4072253d69234 Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Fri, 23 Feb 2018 00:10:37 -0800 Subject: [PATCH 6/8] span_bug doesn't work well at this stage, use the session directly --- src/librustc/lint/context.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc/lint/context.rs b/src/librustc/lint/context.rs index a9c023d14309d..bfd2034dd6cfe 100644 --- a/src/librustc/lint/context.rs +++ b/src/librustc/lint/context.rs @@ -1084,7 +1084,7 @@ pub fn check_ast_crate(sess: &Session, krate: &ast::Crate) { if !sess.opts.actually_rustdoc { for (_id, lints) in cx.buffered.map { for early_lint in lints { - span_bug!(early_lint.span, "failed to process buffered lint here"); + sess.delay_span_bug(early_lint.span, "failed to process buffered lint here"); } } } From dd67fe17276e4bf8cd054d2a8453dc58e0571447 Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Fri, 23 Feb 2018 13:00:11 -0800 Subject: [PATCH 7/8] Silence warning in test --- src/test/compile-fail/trait-bounds-not-on-struct.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/test/compile-fail/trait-bounds-not-on-struct.rs b/src/test/compile-fail/trait-bounds-not-on-struct.rs index 6cd439167314b..0dd1a4e7d7335 100644 --- a/src/test/compile-fail/trait-bounds-not-on-struct.rs +++ b/src/test/compile-fail/trait-bounds-not-on-struct.rs @@ -9,6 +9,7 @@ // except according to those terms. #![feature(dyn_trait)] +#![allow(bare_trait_object)] struct Foo; From 0cb367266b0a336c0a18ae999beeadd3235961a2 Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Fri, 23 Feb 2018 13:52:28 -0800 Subject: [PATCH 8/8] Emit parentheses in suggestion for global paths --- src/librustc/hir/lowering.rs | 8 ++++---- src/librustc/lint/builtin.rs | 5 +++-- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index aeccf133fa86a..9d4011fa7ad9f 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -914,7 +914,7 @@ impl<'a> LoweringContext<'a> { let qpath = self.lower_qpath(t.id, qself, path, ParamMode::Explicit, itctx); let ty = self.ty_path(id, t.span, qpath); if let hir::TyTraitObject(..) = ty.node { - self.maybe_lint_bare_trait(t.span, t.id); + self.maybe_lint_bare_trait(t.span, t.id, qself.is_none() && path.is_global()); } return ty; } @@ -955,7 +955,7 @@ impl<'a> LoweringContext<'a> { self.elided_lifetime(t.span) }); if kind != TraitObjectSyntax::Dyn { - self.maybe_lint_bare_trait(t.span, t.id); + self.maybe_lint_bare_trait(t.span, t.id, false); } hir::TyTraitObject(bounds, lifetime_bound) } @@ -3710,12 +3710,12 @@ impl<'a> LoweringContext<'a> { } } - fn maybe_lint_bare_trait(&self, span: Span, id: NodeId) { + fn maybe_lint_bare_trait(&self, span: Span, id: NodeId, is_global: bool) { if self.sess.features.borrow().dyn_trait { self.sess.buffer_lint_with_diagnostic( builtin::BARE_TRAIT_OBJECT, id, span, "trait objects without an explicit `dyn` are deprecated", - builtin::BuiltinLintDiagnostics::BareTraitObject(span) + builtin::BuiltinLintDiagnostics::BareTraitObject(span, is_global) ) } } diff --git a/src/librustc/lint/builtin.rs b/src/librustc/lint/builtin.rs index cc7c5dc06660c..b68b7dc6c0672 100644 --- a/src/librustc/lint/builtin.rs +++ b/src/librustc/lint/builtin.rs @@ -320,15 +320,16 @@ impl LintPass for HardwiredLints { #[derive(PartialEq, RustcEncodable, RustcDecodable, Debug)] pub enum BuiltinLintDiagnostics { Normal, - BareTraitObject(Span) + BareTraitObject(Span, /* is_global */ bool) } impl BuiltinLintDiagnostics { pub fn run(self, sess: &Session, db: &mut DiagnosticBuilder) { match self { BuiltinLintDiagnostics::Normal => (), - BuiltinLintDiagnostics::BareTraitObject(span) => { + BuiltinLintDiagnostics::BareTraitObject(span, is_global) => { let sugg = match sess.codemap().span_to_snippet(span) { + Ok(ref s) if is_global => format!("dyn ({})", s), Ok(s) => format!("dyn {}", s), Err(_) => format!("dyn ") };