diff --git a/src/librustc/lint/builtin.rs b/src/librustc/lint/builtin.rs index 93a46090b90eb..3689312bed1d4 100644 --- a/src/librustc/lint/builtin.rs +++ b/src/librustc/lint/builtin.rs @@ -16,9 +16,6 @@ use lint::{LintPass, LateLintPass, LintArray}; -// name of the future-incompatible group -pub const FUTURE_INCOMPATIBLE: &'static str = "future_incompatible"; - declare_lint! { pub CONST_ERR, Warn, diff --git a/src/librustc/lint/context.rs b/src/librustc/lint/context.rs index 08fba2dc56fee..80eff67170532 100644 --- a/src/librustc/lint/context.rs +++ b/src/librustc/lint/context.rs @@ -75,10 +75,22 @@ pub struct LintStore { /// is true if the lint group was added by a plugin. lint_groups: FnvHashMap<&'static str, (Vec, bool)>, + /// Extra info for future incompatibility lints, descibing the + /// issue or RFC that caused the incompatibility. + future_incompatible: FnvHashMap, + /// Maximum level a lint can be lint_cap: Option, } +/// Extra information for a future incompatibility lint. See the call +/// to `register_future_incompatible` in `librustc_lint/lib.rs` for +/// guidelines. +pub struct FutureIncompatibleInfo { + pub id: LintId, + pub reference: &'static str // e.g., a URL for an issue/PR/RFC or error code +} + /// The targed of the `by_name` map, which accounts for renaming/deprecation. enum TargetLint { /// A direct lint target @@ -123,6 +135,7 @@ impl LintStore { late_passes: Some(vec!()), by_name: FnvHashMap(), levels: FnvHashMap(), + future_incompatible: FnvHashMap(), lint_groups: FnvHashMap(), lint_cap: None, } @@ -182,6 +195,20 @@ 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); + } + } + + pub fn future_incompatible(&self, id: LintId) -> Option<&FutureIncompatibleInfo> { + self.future_incompatible.get(&id) + } + pub fn register_group(&mut self, sess: Option<&Session>, from_plugin: bool, name: &'static str, to: Vec) { @@ -417,14 +444,18 @@ pub fn raw_struct_lint<'a>(sess: &'a Session, }; // Check for future incompatibility lints and issue a stronger warning. - let future_incompat_lints = &lints.lint_groups[builtin::FUTURE_INCOMPATIBLE]; - let this_id = LintId::of(lint); - if future_incompat_lints.0.iter().any(|&id| id == this_id) { - let msg = "this lint will become a HARD ERROR in a future release!"; + 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); if let Some(sp) = span { - err.span_note(sp, msg); + err.fileline_warn(sp, &explanation); + err.fileline_note(sp, &citation); } else { - err.note(msg); + err.warn(&explanation); + err.note(&citation); } } diff --git a/src/librustc/lint/mod.rs b/src/librustc/lint/mod.rs index 9c689daab86a7..6061525ef398c 100644 --- a/src/librustc/lint/mod.rs +++ b/src/librustc/lint/mod.rs @@ -41,7 +41,7 @@ use rustc_front::hir; pub use lint::context::{LateContext, EarlyContext, LintContext, LintStore, raw_emit_lint, check_crate, check_ast_crate, gather_attrs, - raw_struct_lint, GatherNodeLevels}; + raw_struct_lint, GatherNodeLevels, FutureIncompatibleInfo}; /// Specification of a single lint. #[derive(Copy, Clone, Debug)] diff --git a/src/librustc_lint/lib.rs b/src/librustc_lint/lib.rs index 825dee9f659f5..53acbe3af6743 100644 --- a/src/librustc_lint/lib.rs +++ b/src/librustc_lint/lib.rs @@ -54,6 +54,7 @@ pub use rustc::util as util; use session::Session; use lint::LintId; +use lint::FutureIncompatibleInfo; mod bad_style; mod builtin; @@ -144,9 +145,29 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) { UNUSED_MUT, UNREACHABLE_CODE, UNUSED_MUST_USE, UNUSED_UNSAFE, PATH_STATEMENTS, UNUSED_ATTRIBUTES); - add_lint_group!(sess, FUTURE_INCOMPATIBLE, - PRIVATE_IN_PUBLIC, INVALID_TYPE_PARAM_DEFAULT, - MATCH_OF_UNIT_VARIANT_VIA_PAREN_DOTDOT); + // Guidelines for creating a future incompatibility lint: + // + // - Create a lint defaulting to warn as normal, with ideally the same error + // message you would normally give + // - Add a suitable reference, typically an RFC or tracking issue. Go ahead + // and include the full URL. + // - Later, change lint to error + // - Eventually, remove lint + store.register_future_incompatible(sess, vec![ + FutureIncompatibleInfo { + id: LintId::of(PRIVATE_IN_PUBLIC), + reference: "the explanation for E0446 (`--explain E0446`)", + }, + FutureIncompatibleInfo { + id: LintId::of(INVALID_TYPE_PARAM_DEFAULT), + reference: "PR 30742 ", + }, + FutureIncompatibleInfo { + id: LintId::of(MATCH_OF_UNIT_VARIANT_VIA_PAREN_DOTDOT), + reference: "RFC 218 ", + }, + ]); // We have one lint pass defined specially store.register_late_pass(sess, false, box lint::GatherNodeLevels); diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs index 955e68be0b006..73a1ecf7fc5dc 100644 --- a/src/librustc_privacy/lib.rs +++ b/src/librustc_privacy/lib.rs @@ -1528,7 +1528,7 @@ impl<'a, 'tcx: 'a, 'v> Visitor<'v> for SearchInterfaceForPrivateItemsVisitor<'a, lint::builtin::PRIVATE_IN_PUBLIC, node_id, ty.span, - "private type in public interface (error E0446)".to_string() + format!("private type in public interface"), ); } } diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs index 93ceaf8b11f12..dfa144699b217 100644 --- a/src/librustc_typeck/check/_match.rs +++ b/src/librustc_typeck/check/_match.rs @@ -595,14 +595,10 @@ fn bad_struct_kind_err(sess: &Session, pat: &hir::Pat, path: &hir::Path, lint: b let name = pprust::path_to_string(path); let msg = format!("`{}` does not name a tuple variant or a tuple struct", name); if lint { - let expanded_msg = - format!("{}; RFC 218 disallowed matching of unit variants or unit structs via {}(..)", - msg, - name); sess.add_lint(lint::builtin::MATCH_OF_UNIT_VARIANT_VIA_PAREN_DOTDOT, pat.id, pat.span, - expanded_msg); + msg); } else { span_err!(sess, pat.span, E0164, "{}", msg); } diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index fbbd2f02908f1..af2824d0930d2 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -1917,8 +1917,8 @@ fn get_or_create_type_parameter_def<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, lint::builtin::INVALID_TYPE_PARAM_DEFAULT, param.id, param.span, - format!("defaults for type parameters are only allowed \ - on `struct` or `enum` definitions (see issue #27336)")); + format!("defaults for type parameters are only allowed on type definitions, \ + like `struct` or `enum`")); } } diff --git a/src/libsyntax/errors/mod.rs b/src/libsyntax/errors/mod.rs index a2fae975148f9..05398d10a94a2 100644 --- a/src/libsyntax/errors/mod.rs +++ b/src/libsyntax/errors/mod.rs @@ -160,6 +160,17 @@ impl<'a> DiagnosticBuilder<'a> { self.sub(Level::Note, msg, Some(sp), None); self } + pub fn warn(&mut self, msg: &str) -> &mut DiagnosticBuilder<'a> { + self.sub(Level::Warning, msg, None, None); + self + } + pub fn span_warn(&mut self, + sp: Span, + msg: &str) + -> &mut DiagnosticBuilder<'a> { + self.sub(Level::Warning, msg, Some(sp), None); + self + } pub fn help(&mut self , msg: &str) -> &mut DiagnosticBuilder<'a> { self.sub(Level::Help, msg, None, None); self @@ -189,6 +200,13 @@ impl<'a> DiagnosticBuilder<'a> { self.sub(Level::Note, msg, Some(sp), Some(EndSpan(sp))); self } + pub fn fileline_warn(&mut self , + sp: Span, + msg: &str) + -> &mut DiagnosticBuilder<'a> { + self.sub(Level::Warning, msg, Some(sp), Some(FileLine(sp))); + self + } pub fn fileline_note(&mut self , sp: Span, msg: &str) diff --git a/src/test/compile-fail/empty-struct-unit-pat.rs b/src/test/compile-fail/empty-struct-unit-pat.rs index 7e13f539bb043..cffd9fd9b4938 100644 --- a/src/test/compile-fail/empty-struct-unit-pat.rs +++ b/src/test/compile-fail/empty-struct-unit-pat.rs @@ -32,6 +32,7 @@ fn main() { //~ ERROR: compilation successful // } match e1 { Empty1(..) => () //~ WARN `Empty1` does not name a tuple variant or a tuple struct + //~^ WARN hard error } // Rejected by parser as yet // match e2 { @@ -39,5 +40,6 @@ fn main() { //~ ERROR: compilation successful // } match e2 { E::Empty2(..) => () //~ WARN `E::Empty2` does not name a tuple variant or a tuple struct + //~^ WARN hard error } } diff --git a/src/test/compile-fail/private-in-public-warn.rs b/src/test/compile-fail/private-in-public-warn.rs index 2d1de3ca2823e..9aab06ce14ee1 100644 --- a/src/test/compile-fail/private-in-public-warn.rs +++ b/src/test/compile-fail/private-in-public-warn.rs @@ -26,23 +26,34 @@ mod types { } pub type Alias = Priv; //~ WARN private type in public interface + //~^ WARNING hard error pub enum E { V1(Priv), //~ WARN private type in public interface + //~^ WARNING hard error V2 { field: Priv }, //~ WARN private type in public interface + //~^ WARNING hard error } pub trait Tr { const C: Priv = Priv; //~ WARN private type in public interface + //~^ WARNING hard error type Alias = Priv; //~ WARN private type in public interface + //~^ WARNING hard error fn f1(arg: Priv) {} //~ WARN private type in public interface + //~^ WARNING hard error fn f2() -> Priv { panic!() } //~ WARN private type in public interface + //~^ WARNING hard error } extern { pub static ES: Priv; //~ WARN private type in public interface + //~^ WARNING hard error pub fn ef1(arg: Priv); //~ WARN private type in public interface + //~^ WARNING hard error pub fn ef2() -> Priv; //~ WARN private type in public interface + //~^ WARNING hard error } impl PubTr for Pub { type Alias = Priv; //~ WARN private type in public interface + //~^ WARNING hard error } } @@ -53,14 +64,21 @@ mod traits { pub type Alias = T; //~ WARN private trait in public interface //~^ WARN trait bounds are not (yet) enforced in type definitions + //~| WARNING hard error pub trait Tr1: PrivTr {} //~ WARN private trait in public interface + //~^ WARNING hard error pub trait Tr2 {} //~ WARN private trait in public interface + //~^ WARNING hard error pub trait Tr3 { type Alias: PrivTr; //~ WARN private trait in public interface + //~^ WARNING hard error fn f(arg: T) {} //~ WARN private trait in public interface + //~^ WARNING hard error } impl Pub {} //~ WARN private trait in public interface + //~^ WARNING hard error impl PubTr for Pub {} //~ WARN private trait in public interface + //~^ WARNING hard error } mod traits_where { @@ -69,12 +87,17 @@ mod traits_where { pub trait PubTr {} pub type Alias where T: PrivTr = T; //~ WARN private trait in public interface + //~^ WARNING hard error pub trait Tr2 where T: PrivTr {} //~ WARN private trait in public interface + //~^ WARNING hard error pub trait Tr3 { fn f(arg: T) where T: PrivTr {} //~ WARN private trait in public interface + //~^ WARNING hard error } impl Pub where T: PrivTr {} //~ WARN private trait in public interface + //~^ WARNING hard error impl PubTr for Pub where T: PrivTr {} //~ WARN private trait in public interface + //~^ WARNING hard error } mod generics { @@ -84,9 +107,13 @@ mod generics { pub trait PubTr {} pub trait Tr1: PrivTr {} //~ WARN private trait in public interface + //~^ WARNING hard error pub trait Tr2: PubTr {} //~ WARN private type in public interface + //~^ WARNING hard error pub trait Tr3: PubTr<[Priv; 1]> {} //~ WARN private type in public interface + //~^ WARNING hard error pub trait Tr4: PubTr> {} //~ WARN private type in public interface + //~^ WARNING hard error } mod impls { @@ -113,6 +140,7 @@ mod impls { } impl PubTr for Pub { type Alias = Priv; //~ WARN private type in public interface + //~^ WARNING hard error } } @@ -179,9 +207,11 @@ mod aliases_pub { pub trait Tr1: PrivUseAliasTr {} // OK // This should be OK, if type aliases are substituted pub trait Tr2: PrivUseAliasTr {} //~ WARN private type in public interface + //~^ WARNING hard error impl PrivAlias { pub fn f(arg: Priv) {} //~ WARN private type in public interface + //~^ WARNING hard error } // This doesn't even parse // impl ::AssocAlias { @@ -189,12 +219,15 @@ mod aliases_pub { // } impl PrivUseAliasTr for PrivUseAlias { type Check = Priv; //~ WARN private type in public interface + //~^ WARNING hard error } impl PrivUseAliasTr for PrivAlias { type Check = Priv; //~ WARN private type in public interface + //~^ WARNING hard error } impl PrivUseAliasTr for ::AssocAlias { type Check = Priv; //~ WARN private type in public interface + //~^ WARNING hard error } } @@ -217,8 +250,11 @@ mod aliases_priv { impl PrivTr for Priv {} pub trait Tr1: PrivUseAliasTr {} //~ WARN private trait in public interface + //~^ WARNING hard error pub trait Tr2: PrivUseAliasTr {} //~ WARN private trait in public interface //~^ WARN private type in public interface + //~| WARNING hard error + //~| WARNING hard error impl PrivUseAlias { pub fn f(arg: Priv) {} // OK diff --git a/src/test/compile-fail/private-variant-reexport.rs b/src/test/compile-fail/private-variant-reexport.rs index 39698fa593a28..06f08dc13c6b4 100644 --- a/src/test/compile-fail/private-variant-reexport.rs +++ b/src/test/compile-fail/private-variant-reexport.rs @@ -13,18 +13,22 @@ mod m1 { pub use ::E::V; //~ WARN variant `V` is private, and cannot be reexported + //~^ WARNING hard error } mod m2 { pub use ::E::{V}; //~ WARN variant `V` is private, and cannot be reexported + //~^ WARNING hard error } mod m3 { pub use ::E::V::{self}; //~ WARN variant `V` is private, and cannot be reexported + //~^ WARNING hard error } mod m4 { pub use ::E::*; //~ WARN variant `V` is private, and cannot be reexported + //~^ WARNING hard error } enum E { V } diff --git a/src/test/compile-fail/type-parameter-invalid-lint.rs b/src/test/compile-fail/type-parameter-invalid-lint.rs index a3ecbfa84f0a8..9291329fac37f 100644 --- a/src/test/compile-fail/type-parameter-invalid-lint.rs +++ b/src/test/compile-fail/type-parameter-invalid-lint.rs @@ -13,5 +13,5 @@ fn avg(_: T) {} //~^ ERROR defaults for type parameters are only allowed -//~| NOTE HARD ERROR +//~| WARNING hard error fn main() {}