Skip to content

Commit f57835b

Browse files
committed
Rollup merge of #48461 - Manishearth:epoch-dyn-trait, r=nmatsakis
Fixes #47311. r? @nrc
2 parents 6b5519d + 0cb3672 commit f57835b

File tree

14 files changed

+234
-46
lines changed

14 files changed

+234
-46
lines changed

src/librustc/hir/lowering.rs

+20-4
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ use hir::HirVec;
4646
use hir::map::{Definitions, DefKey, DefPathData};
4747
use hir::def_id::{DefIndex, DefId, CRATE_DEF_INDEX, DefIndexAddressSpace};
4848
use hir::def::{Def, PathResolution};
49-
use lint::builtin::PARENTHESIZED_PARAMS_IN_TYPES_AND_MODULES;
49+
use lint::builtin::{self, PARENTHESIZED_PARAMS_IN_TYPES_AND_MODULES};
5050
use middle::cstore::CrateStore;
5151
use rustc_data_structures::indexed_vec::IndexVec;
5252
use session::Session;
@@ -912,7 +912,11 @@ impl<'a> LoweringContext<'a> {
912912
TyKind::Path(ref qself, ref path) => {
913913
let id = self.lower_node_id(t.id);
914914
let qpath = self.lower_qpath(t.id, qself, path, ParamMode::Explicit, itctx);
915-
return self.ty_path(id, t.span, qpath);
915+
let ty = self.ty_path(id, t.span, qpath);
916+
if let hir::TyTraitObject(..) = ty.node {
917+
self.maybe_lint_bare_trait(t.span, t.id, qself.is_none() && path.is_global());
918+
}
919+
return ty;
916920
}
917921
TyKind::ImplicitSelf => {
918922
hir::TyPath(hir::QPath::Resolved(None, P(hir::Path {
@@ -931,7 +935,7 @@ impl<'a> LoweringContext<'a> {
931935
let expr = self.lower_body(None, |this| this.lower_expr(expr));
932936
hir::TyTypeof(expr)
933937
}
934-
TyKind::TraitObject(ref bounds, ..) => {
938+
TyKind::TraitObject(ref bounds, kind) => {
935939
let mut lifetime_bound = None;
936940
let bounds = bounds.iter().filter_map(|bound| {
937941
match *bound {
@@ -950,6 +954,9 @@ impl<'a> LoweringContext<'a> {
950954
let lifetime_bound = lifetime_bound.unwrap_or_else(|| {
951955
self.elided_lifetime(t.span)
952956
});
957+
if kind != TraitObjectSyntax::Dyn {
958+
self.maybe_lint_bare_trait(t.span, t.id, false);
959+
}
953960
hir::TyTraitObject(bounds, lifetime_bound)
954961
}
955962
TyKind::ImplTrait(ref bounds) => {
@@ -3685,7 +3692,6 @@ impl<'a> LoweringContext<'a> {
36853692
// The original ID is taken by the `PolyTraitRef`,
36863693
// so the `Ty` itself needs a different one.
36873694
id = self.next_id();
3688-
36893695
hir::TyTraitObject(hir_vec![principal], self.elided_lifetime(span))
36903696
} else {
36913697
hir::TyPath(hir::QPath::Resolved(None, path))
@@ -3703,6 +3709,16 @@ impl<'a> LoweringContext<'a> {
37033709
name: hir::LifetimeName::Implicit,
37043710
}
37053711
}
3712+
3713+
fn maybe_lint_bare_trait(&self, span: Span, id: NodeId, is_global: bool) {
3714+
if self.sess.features.borrow().dyn_trait {
3715+
self.sess.buffer_lint_with_diagnostic(
3716+
builtin::BARE_TRAIT_OBJECT, id, span,
3717+
"trait objects without an explicit `dyn` are deprecated",
3718+
builtin::BuiltinLintDiagnostics::BareTraitObject(span, is_global)
3719+
)
3720+
}
3721+
}
37063722
}
37073723

37083724
fn body_ids(bodies: &BTreeMap<hir::BodyId, hir::Body>) -> Vec<hir::BodyId> {

src/librustc/lib.rs

+2
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,8 @@
4141
html_root_url = "https://doc.rust-lang.org/nightly/")]
4242
#![deny(warnings)]
4343

44+
#![cfg_attr(not(stage0), allow(bare_trait_object))]
45+
4446
#![feature(box_patterns)]
4547
#![feature(box_syntax)]
4648
#![feature(conservative_impl_trait)]

src/librustc/lint/builtin.rs

+37-2
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,11 @@
1414
//! compiler code, rather than using their own custom pass. Those
1515
//! lints are all available in `rustc_lint::builtin`.
1616
17+
use errors::DiagnosticBuilder;
1718
use lint::{LintPass, LateLintPass, LintArray};
19+
use session::Session;
20+
use session::config::Epoch;
21+
use syntax::codemap::Span;
1822

1923
declare_lint! {
2024
pub CONST_ERR,
@@ -252,6 +256,13 @@ declare_lint! {
252256
"hidden lifetime parameters are deprecated, try `Foo<'_>`"
253257
}
254258

259+
declare_lint! {
260+
pub BARE_TRAIT_OBJECT,
261+
Warn,
262+
"suggest using `dyn Trait` for trait objects",
263+
Epoch::Epoch2018
264+
}
265+
255266
/// Does nothing as a lint pass, but registers some `Lint`s
256267
/// which are used by other parts of the compiler.
257268
#[derive(Copy, Clone)]
@@ -298,10 +309,34 @@ impl LintPass for HardwiredLints {
298309
COERCE_NEVER,
299310
SINGLE_USE_LIFETIME,
300311
TYVAR_BEHIND_RAW_POINTER,
301-
ELIDED_LIFETIME_IN_PATH
302-
312+
ELIDED_LIFETIME_IN_PATH,
313+
BARE_TRAIT_OBJECT
303314
)
304315
}
305316
}
306317

318+
// this could be a closure, but then implementing derive traits
319+
// becomes hacky (and it gets allocated)
320+
#[derive(PartialEq, RustcEncodable, RustcDecodable, Debug)]
321+
pub enum BuiltinLintDiagnostics {
322+
Normal,
323+
BareTraitObject(Span, /* is_global */ bool)
324+
}
325+
326+
impl BuiltinLintDiagnostics {
327+
pub fn run(self, sess: &Session, db: &mut DiagnosticBuilder) {
328+
match self {
329+
BuiltinLintDiagnostics::Normal => (),
330+
BuiltinLintDiagnostics::BareTraitObject(span, is_global) => {
331+
let sugg = match sess.codemap().span_to_snippet(span) {
332+
Ok(ref s) if is_global => format!("dyn ({})", s),
333+
Ok(s) => format!("dyn {}", s),
334+
Err(_) => format!("dyn <type>")
335+
};
336+
db.span_suggestion(span, "use `dyn`", sugg);
337+
}
338+
}
339+
}
340+
}
341+
307342
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for HardwiredLints {}

src/librustc/lint/context.rs

+39-9
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ use self::TargetLint::*;
2929
use std::slice;
3030
use lint::{EarlyLintPassObject, LateLintPassObject};
3131
use lint::{Level, Lint, LintId, LintPass, LintBuffer};
32+
use lint::builtin::BuiltinLintDiagnostics;
3233
use lint::levels::{LintLevelSets, LintLevelsBuilder};
3334
use middle::privacy::AccessLevels;
3435
use rustc_serialize::{Decoder, Decodable, Encoder, Encodable};
@@ -92,14 +93,19 @@ pub struct BufferedEarlyLint {
9293
pub ast_id: ast::NodeId,
9394
pub span: MultiSpan,
9495
pub msg: String,
96+
pub diagnostic: BuiltinLintDiagnostics,
9597
}
9698

9799
/// Extra information for a future incompatibility lint. See the call
98100
/// to `register_future_incompatible` in `librustc_lint/lib.rs` for
99101
/// guidelines.
100102
pub struct FutureIncompatibleInfo {
101103
pub id: LintId,
102-
pub reference: &'static str // e.g., a URL for an issue/PR/RFC or error code
104+
/// e.g., a URL for an issue/PR/RFC or error code
105+
pub reference: &'static str,
106+
/// If this is an epoch fixing lint, the epoch in which
107+
/// this lint becomes obsolete
108+
pub epoch: Option<config::Epoch>,
103109
}
104110

105111
/// The target of the `by_name` map, which accounts for renaming/deprecation.
@@ -194,11 +200,24 @@ impl LintStore {
194200
pub fn register_future_incompatible(&mut self,
195201
sess: Option<&Session>,
196202
lints: Vec<FutureIncompatibleInfo>) {
197-
let ids = lints.iter().map(|f| f.id).collect();
198-
self.register_group(sess, false, "future_incompatible", ids);
199-
for info in lints {
200-
self.future_incompatible.insert(info.id, info);
203+
204+
for epoch in config::ALL_EPOCHS {
205+
let lints = lints.iter().filter(|f| f.epoch == Some(*epoch)).map(|f| f.id)
206+
.collect::<Vec<_>>();
207+
if !lints.is_empty() {
208+
self.register_group(sess, false, epoch.lint_name(), lints)
209+
}
201210
}
211+
212+
let mut future_incompatible = vec![];
213+
for lint in lints {
214+
future_incompatible.push(lint.id);
215+
self.future_incompatible.insert(lint.id, lint);
216+
}
217+
218+
self.register_group(sess, false, "future_incompatible", future_incompatible);
219+
220+
202221
}
203222

204223
pub fn future_incompatible(&self, id: LintId) -> Option<&FutureIncompatibleInfo> {
@@ -429,6 +448,16 @@ pub trait LintContext<'tcx>: Sized {
429448
self.lookup(lint, span, msg).emit();
430449
}
431450

451+
fn lookup_and_emit_with_diagnostics<S: Into<MultiSpan>>(&self,
452+
lint: &'static Lint,
453+
span: Option<S>,
454+
msg: &str,
455+
diagnostic: BuiltinLintDiagnostics) {
456+
let mut db = self.lookup(lint, span, msg);
457+
diagnostic.run(self.sess(), &mut db);
458+
db.emit();
459+
}
460+
432461
fn lookup<S: Into<MultiSpan>>(&self,
433462
lint: &'static Lint,
434463
span: Option<S>,
@@ -499,9 +528,10 @@ impl<'a> EarlyContext<'a> {
499528

500529
fn check_id(&mut self, id: ast::NodeId) {
501530
for early_lint in self.buffered.take(id) {
502-
self.lookup_and_emit(early_lint.lint_id.lint,
503-
Some(early_lint.span.clone()),
504-
&early_lint.msg);
531+
self.lookup_and_emit_with_diagnostics(early_lint.lint_id.lint,
532+
Some(early_lint.span.clone()),
533+
&early_lint.msg,
534+
early_lint.diagnostic);
505535
}
506536
}
507537
}
@@ -1054,7 +1084,7 @@ pub fn check_ast_crate(sess: &Session, krate: &ast::Crate) {
10541084
if !sess.opts.actually_rustdoc {
10551085
for (_id, lints) in cx.buffered.map {
10561086
for early_lint in lints {
1057-
span_bug!(early_lint.span, "failed to process buffered lint here");
1087+
sess.delay_span_bug(early_lint.span, "failed to process buffered lint here");
10581088
}
10591089
}
10601090
}

src/librustc/lint/levels.rs

+10-7
Original file line numberDiff line numberDiff line change
@@ -89,14 +89,15 @@ impl LintLevelSets {
8989
fn get_lint_level(&self,
9090
lint: &'static Lint,
9191
idx: u32,
92-
aux: Option<&FxHashMap<LintId, (Level, LintSource)>>)
92+
aux: Option<&FxHashMap<LintId, (Level, LintSource)>>,
93+
sess: &Session)
9394
-> (Level, LintSource)
9495
{
9596
let (level, mut src) = self.get_lint_id_level(LintId::of(lint), idx, aux);
9697

9798
// If `level` is none then we actually assume the default level for this
9899
// lint.
99-
let mut level = level.unwrap_or(lint.default_level);
100+
let mut level = level.unwrap_or(lint.default_level(sess));
100101

101102
// If we're about to issue a warning, check at the last minute for any
102103
// directives against the warnings "lint". If, for example, there's an
@@ -235,7 +236,8 @@ impl<'a> LintLevelsBuilder<'a> {
235236
let lint = builtin::RENAMED_AND_REMOVED_LINTS;
236237
let (level, src) = self.sets.get_lint_level(lint,
237238
self.cur,
238-
Some(&specs));
239+
Some(&specs),
240+
&sess);
239241
lint::struct_lint_level(self.sess,
240242
lint,
241243
level,
@@ -248,7 +250,8 @@ impl<'a> LintLevelsBuilder<'a> {
248250
let lint = builtin::UNKNOWN_LINTS;
249251
let (level, src) = self.sets.get_lint_level(lint,
250252
self.cur,
251-
Some(&specs));
253+
Some(&specs),
254+
self.sess);
252255
let msg = format!("unknown lint: `{}`", name);
253256
let mut db = lint::struct_lint_level(self.sess,
254257
lint,
@@ -342,7 +345,7 @@ impl<'a> LintLevelsBuilder<'a> {
342345
msg: &str)
343346
-> DiagnosticBuilder<'a>
344347
{
345-
let (level, src) = self.sets.get_lint_level(lint, self.cur, None);
348+
let (level, src) = self.sets.get_lint_level(lint, self.cur, None, self.sess);
346349
lint::struct_lint_level(self.sess, lint, level, src, span, msg)
347350
}
348351

@@ -377,11 +380,11 @@ impl LintLevelMap {
377380
/// If the `id` was not previously registered, returns `None`. If `None` is
378381
/// returned then the parent of `id` should be acquired and this function
379382
/// should be called again.
380-
pub fn level_and_source(&self, lint: &'static Lint, id: HirId)
383+
pub fn level_and_source(&self, lint: &'static Lint, id: HirId, session: &Session)
381384
-> Option<(Level, LintSource)>
382385
{
383386
self.id_to_set.get(&id).map(|idx| {
384-
self.sets.get_lint_level(lint, *idx, None)
387+
self.sets.get_lint_level(lint, *idx, None, session)
385388
})
386389
}
387390

src/librustc/lint/mod.rs

+29-5
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,8 @@ use errors::{DiagnosticBuilder, DiagnosticId};
3737
use hir::def_id::{CrateNum, LOCAL_CRATE};
3838
use hir::intravisit::{self, FnKind};
3939
use hir;
40-
use session::{Session, DiagnosticMessageId};
40+
use lint::builtin::BuiltinLintDiagnostics;
41+
use session::{config, Session, DiagnosticMessageId};
4142
use std::hash;
4243
use syntax::ast;
4344
use syntax::codemap::MultiSpan;
@@ -74,25 +75,46 @@ pub struct Lint {
7475
///
7576
/// e.g. "imports that are never used"
7677
pub desc: &'static str,
78+
79+
/// Deny lint after this epoch
80+
pub epoch_deny: Option<config::Epoch>,
7781
}
7882

7983
impl Lint {
8084
/// Get the lint's name, with ASCII letters converted to lowercase.
8185
pub fn name_lower(&self) -> String {
8286
self.name.to_ascii_lowercase()
8387
}
88+
89+
pub fn default_level(&self, session: &Session) -> Level {
90+
if let Some(epoch_deny) = self.epoch_deny {
91+
if session.epoch() >= epoch_deny {
92+
return Level::Deny
93+
}
94+
}
95+
self.default_level
96+
}
8497
}
8598

8699
/// Declare a static item of type `&'static Lint`.
87100
#[macro_export]
88101
macro_rules! declare_lint {
102+
($vis: vis $NAME: ident, $Level: ident, $desc: expr, $epoch: expr) => (
103+
$vis static $NAME: &$crate::lint::Lint = &$crate::lint::Lint {
104+
name: stringify!($NAME),
105+
default_level: $crate::lint::$Level,
106+
desc: $desc,
107+
epoch_deny: Some($epoch)
108+
};
109+
);
89110
($vis: vis $NAME: ident, $Level: ident, $desc: expr) => (
90111
$vis static $NAME: &$crate::lint::Lint = &$crate::lint::Lint {
91112
name: stringify!($NAME),
92113
default_level: $crate::lint::$Level,
93-
desc: $desc
114+
desc: $desc,
115+
epoch_deny: None,
94116
};
95-
)
117+
);
96118
}
97119

98120
/// Declare a static `LintArray` and return it as an expression.
@@ -304,7 +326,7 @@ impl LintId {
304326
/// Setting for how to handle a lint.
305327
#[derive(Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Debug, Hash)]
306328
pub enum Level {
307-
Allow, Warn, Deny, Forbid
329+
Allow, Warn, Deny, Forbid,
308330
}
309331

310332
impl_stable_hash_for!(enum self::Level {
@@ -378,12 +400,14 @@ impl LintBuffer {
378400
lint: &'static Lint,
379401
id: ast::NodeId,
380402
sp: MultiSpan,
381-
msg: &str) {
403+
msg: &str,
404+
diagnostic: BuiltinLintDiagnostics) {
382405
let early_lint = BufferedEarlyLint {
383406
lint_id: LintId::of(lint),
384407
ast_id: id,
385408
span: sp,
386409
msg: msg.to_string(),
410+
diagnostic
387411
};
388412
let arr = self.map.entry(id).or_insert(Vec::new());
389413
if !arr.contains(&early_lint) {

0 commit comments

Comments
 (0)