Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Revamp the support for "future incompatible" lints #30787

Merged
merged 6 commits into from
Jan 15, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 0 additions & 3 deletions src/librustc/lint/builtin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
43 changes: 37 additions & 6 deletions src/librustc/lint/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -75,10 +75,22 @@ pub struct LintStore {
/// is true if the lint group was added by a plugin.
lint_groups: FnvHashMap<&'static str, (Vec<LintId>, bool)>,

/// Extra info for future incompatibility lints, descibing the
/// issue or RFC that caused the incompatibility.
future_incompatible: FnvHashMap<LintId, FutureIncompatibleInfo>,

/// Maximum level a lint can be
lint_cap: Option<Level>,
}

/// 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
Expand Down Expand Up @@ -123,6 +135,7 @@ impl LintStore {
late_passes: Some(vec!()),
by_name: FnvHashMap(),
levels: FnvHashMap(),
future_incompatible: FnvHashMap(),
lint_groups: FnvHashMap(),
lint_cap: None,
}
Expand Down Expand Up @@ -182,6 +195,20 @@ impl LintStore {
}
}

pub fn register_future_incompatible(&mut self,
sess: Option<&Session>,
lints: Vec<FutureIncompatibleInfo>) {
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<LintId>) {
Expand Down Expand Up @@ -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);
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/librustc/lint/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)]
Expand Down
27 changes: 24 additions & 3 deletions src/librustc_lint/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ pub use rustc::util as util;

use session::Session;
use lint::LintId;
use lint::FutureIncompatibleInfo;

mod bad_style;
mod builtin;
Expand Down Expand Up @@ -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 <https://github.com/rust-lang/rust/pull/30724>",
},
FutureIncompatibleInfo {
id: LintId::of(MATCH_OF_UNIT_VARIANT_VIA_PAREN_DOTDOT),
reference: "RFC 218 <https://github.com/rust-lang/rfcs/blob/\
master/text/0218-empty-struct-with-braces.md>",
},
]);

// We have one lint pass defined specially
store.register_late_pass(sess, false, box lint::GatherNodeLevels);
Expand Down
2 changes: 1 addition & 1 deletion src/librustc_privacy/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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"),
);
}
}
Expand Down
6 changes: 1 addition & 5 deletions src/librustc_typeck/check/_match.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand Down
4 changes: 2 additions & 2 deletions src/librustc_typeck/collect.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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`"));
}
}

Expand Down
18 changes: 18 additions & 0 deletions src/libsyntax/errors/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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)
Expand Down
2 changes: 2 additions & 0 deletions src/test/compile-fail/empty-struct-unit-pat.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,14 @@ 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 {
// E::Empty2() => () // ERROR `E::Empty2` does not name a tuple variant or a tuple struct
// }
match e2 {
E::Empty2(..) => () //~ WARN `E::Empty2` does not name a tuple variant or a tuple struct
//~^ WARN hard error
}
}
36 changes: 36 additions & 0 deletions src/test/compile-fail/private-in-public-warn.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
}

Expand All @@ -53,14 +64,21 @@ mod traits {

pub type Alias<T: PrivTr> = 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<T: PrivTr> {} //~ 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<T: PrivTr>(arg: T) {} //~ WARN private trait in public interface
//~^ WARNING hard error
}
impl<T: PrivTr> Pub<T> {} //~ WARN private trait in public interface
//~^ WARNING hard error
impl<T: PrivTr> PubTr for Pub<T> {} //~ WARN private trait in public interface
//~^ WARNING hard error
}

mod traits_where {
Expand All @@ -69,12 +87,17 @@ mod traits_where {
pub trait PubTr {}

pub type Alias<T> where T: PrivTr = T; //~ WARN private trait in public interface
//~^ WARNING hard error
pub trait Tr2<T> where T: PrivTr {} //~ WARN private trait in public interface
//~^ WARNING hard error
pub trait Tr3 {
fn f<T>(arg: T) where T: PrivTr {} //~ WARN private trait in public interface
//~^ WARNING hard error
}
impl<T> Pub<T> where T: PrivTr {} //~ WARN private trait in public interface
//~^ WARNING hard error
impl<T> PubTr for Pub<T> where T: PrivTr {} //~ WARN private trait in public interface
//~^ WARNING hard error
}

mod generics {
Expand All @@ -84,9 +107,13 @@ mod generics {
pub trait PubTr<T> {}

pub trait Tr1: PrivTr<Pub> {} //~ WARN private trait in public interface
//~^ WARNING hard error
pub trait Tr2: PubTr<Priv> {} //~ 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<Pub<Priv>> {} //~ WARN private type in public interface
//~^ WARNING hard error
}

mod impls {
Expand All @@ -113,6 +140,7 @@ mod impls {
}
impl PubTr for Pub {
type Alias = Priv; //~ WARN private type in public interface
//~^ WARNING hard error
}
}

Expand Down Expand Up @@ -179,22 +207,27 @@ mod aliases_pub {
pub trait Tr1: PrivUseAliasTr {} // OK
// This should be OK, if type aliases are substituted
pub trait Tr2: PrivUseAliasTr<PrivAlias> {} //~ 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 <Priv as PrivTr>::AssocAlias {
// pub fn f(arg: Priv) {} // WARN private type in public interface
// }
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 <Priv as PrivTr>::AssocAlias {
type Check = Priv; //~ WARN private type in public interface
//~^ WARNING hard error
}
}

Expand All @@ -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<PrivAlias> {} //~ 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
Expand Down
4 changes: 4 additions & 0 deletions src/test/compile-fail/private-variant-reexport.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 }
Expand Down
2 changes: 1 addition & 1 deletion src/test/compile-fail/type-parameter-invalid-lint.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,5 +13,5 @@

fn avg<T=i32>(_: T) {}
//~^ ERROR defaults for type parameters are only allowed
//~| NOTE HARD ERROR
//~| WARNING hard error
fn main() {}