diff --git a/src/librustc/lint/builtin.rs b/src/librustc/lint/builtin.rs index 7d4a18c2a570b..1f8c7f0064ed9 100644 --- a/src/librustc/lint/builtin.rs +++ b/src/librustc/lint/builtin.rs @@ -304,6 +304,12 @@ declare_lint! { "warn about documentation intra links resolution failure" } +declare_lint! { + pub WHERE_CLAUSES_OBJECT_SAFETY, + Warn, + "checks the object safety of where clauses" +} + /// Does nothing as a lint pass, but registers some `Lint`s /// which are used by other parts of the compiler. #[derive(Copy, Clone)] @@ -358,6 +364,7 @@ impl LintPass for HardwiredLints { DUPLICATE_ASSOCIATED_TYPE_BINDINGS, DUPLICATE_MACRO_EXPORTS, INTRA_DOC_LINK_RESOLUTION_FAILURE, + WHERE_CLAUSES_OBJECT_SAFETY, ) } } diff --git a/src/librustc/traits/object_safety.rs b/src/librustc/traits/object_safety.rs index 9dc1f06fc1133..85bd5853d18a7 100644 --- a/src/librustc/traits/object_safety.rs +++ b/src/librustc/traits/object_safety.rs @@ -20,14 +20,16 @@ use super::elaborate_predicates; use hir::def_id::DefId; +use lint; use traits; use ty::{self, Ty, TyCtxt, TypeFoldable}; use ty::subst::Substs; use ty::util::ExplicitSelf; use std::borrow::Cow; use syntax::ast; +use syntax_pos::Span; -#[derive(Clone, Debug, PartialEq, Eq, Hash)] +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] pub enum ObjectSafetyViolation { /// Self : Sized declared on the trait SizedSelf, @@ -56,6 +58,9 @@ impl ObjectSafetyViolation { ObjectSafetyViolation::Method(name, MethodViolationCode::ReferencesSelf) => format!("method `{}` references the `Self` type \ in its arguments or return type", name).into(), + ObjectSafetyViolation::Method(name, + MethodViolationCode::WhereClauseReferencesSelf(_)) => + format!("method `{}` references the `Self` type in where clauses", name).into(), ObjectSafetyViolation::Method(name, MethodViolationCode::Generic) => format!("method `{}` has generic type parameters", name).into(), ObjectSafetyViolation::Method(name, MethodViolationCode::NonStandardSelfType) => @@ -75,6 +80,9 @@ pub enum MethodViolationCode { /// e.g., `fn foo(&self, x: Self)` or `fn foo(&self) -> Self` ReferencesSelf, + /// e.g. `fn foo(&self) where Self: Clone` + WhereClauseReferencesSelf(Span), + /// e.g., `fn foo()` Generic, @@ -123,6 +131,22 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { .filter_map(|item| { self.object_safety_violation_for_method(trait_def_id, &item) .map(|code| ObjectSafetyViolation::Method(item.name, code)) + }).filter(|violation| { + if let ObjectSafetyViolation::Method(_, + MethodViolationCode::WhereClauseReferencesSelf(span)) = violation { + // Using`CRATE_NODE_ID` is wrong, but it's hard to get a more precise id. + // It's also hard to get a use site span, so we use the method definition span. + self.lint_node_note( + lint::builtin::WHERE_CLAUSES_OBJECT_SAFETY, + ast::CRATE_NODE_ID, + *span, + &format!("the trait `{}` cannot be made into an object", + self.item_path_str(trait_def_id)), + &violation.error_msg()); + false + } else { + true + } }).collect(); // Check the trait itself. @@ -245,7 +269,10 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { return false; } - self.virtual_call_violation_for_method(trait_def_id, method).is_none() + match self.virtual_call_violation_for_method(trait_def_id, method) { + None | Some(MethodViolationCode::WhereClauseReferencesSelf(_)) => true, + Some(_) => false, + } } /// Returns `Some(_)` if this method cannot be called on a trait @@ -296,7 +323,8 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { // Do a shallow visit so that `contains_illegal_self_type_reference` // may apply it's custom visiting. .visit_tys_shallow(|t| self.contains_illegal_self_type_reference(trait_def_id, t)) { - return Some(MethodViolationCode::ReferencesSelf); + let span = self.def_span(method.def_id); + return Some(MethodViolationCode::WhereClauseReferencesSelf(span)); } None diff --git a/src/librustc_lint/lib.rs b/src/librustc_lint/lib.rs index 9ac22f8dceb05..ef12df795a61f 100644 --- a/src/librustc_lint/lib.rs +++ b/src/librustc_lint/lib.rs @@ -292,6 +292,11 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) { reference: "issue TBD", edition: Some(Edition::Edition2018), }, + FutureIncompatibleInfo { + id: LintId::of(WHERE_CLAUSES_OBJECT_SAFETY), + reference: "issue TBD", + edition: None, + }, FutureIncompatibleInfo { id: LintId::of(DUPLICATE_ASSOCIATED_TYPE_BINDINGS), reference: "issue #50589 ", diff --git a/src/test/compile-fail/issue-43431.rs b/src/test/compile-fail/issue-43431.rs index e9f6215288814..1e6366e068a89 100644 --- a/src/test/compile-fail/issue-43431.rs +++ b/src/test/compile-fail/issue-43431.rs @@ -11,7 +11,7 @@ #![feature(fn_traits)] trait CallSingle { - fn call(&self, a: A) -> B where Self: Fn(A) -> B; + fn call(&self, a: A) -> B where Self: Sized, Self: Fn(A) -> B; } impl B> CallSingle for F { diff --git a/src/test/compile-fail/wf-trait-fn-where-clause.rs b/src/test/compile-fail/wf-trait-fn-where-clause.rs index f59dca93bb90a..f46a54504a0b5 100644 --- a/src/test/compile-fail/wf-trait-fn-where-clause.rs +++ b/src/test/compile-fail/wf-trait-fn-where-clause.rs @@ -17,7 +17,7 @@ struct Bar { value: Box } trait Foo { - fn bar(&self) where Bar: Copy; + fn bar(&self) where Self: Sized, Bar: Copy; //~^ ERROR E0277 // // Here, Eq ought to be implemented. diff --git a/src/test/ui/issue-50781.rs b/src/test/ui/issue-50781.rs index 3974fd54cf62b..43830869da7f2 100644 --- a/src/test/ui/issue-50781.rs +++ b/src/test/ui/issue-50781.rs @@ -8,10 +8,13 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#![deny(where_clauses_object_safety)] + trait Trait {} trait X { - fn foo(&self) where Self: Trait; + fn foo(&self) where Self: Trait; //~ ERROR the trait `X` cannot be made into an object + //~^ WARN this was previously accepted by the compiler but is being phased out } impl X for () { @@ -19,7 +22,6 @@ impl X for () { } impl Trait for dyn X {} -//~^ ERROR the trait `X` cannot be made into an object pub fn main() { // Check that this does not segfault. diff --git a/src/test/ui/issue-50781.stderr b/src/test/ui/issue-50781.stderr index 34d7303a9a544..ec24445e468b6 100644 --- a/src/test/ui/issue-50781.stderr +++ b/src/test/ui/issue-50781.stderr @@ -1,11 +1,17 @@ -error[E0038]: the trait `X` cannot be made into an object - --> $DIR/issue-50781.rs:21:6 +error: the trait `X` cannot be made into an object + --> $DIR/issue-50781.rs:16:5 | -LL | impl Trait for dyn X {} - | ^^^^^ the trait `X` cannot be made into an object +LL | fn foo(&self) where Self: Trait; //~ ERROR the trait `X` cannot be made into an object + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: method `foo` references the `Self` type in its arguments or return type +note: lint level defined here + --> $DIR/issue-50781.rs:11:9 + | +LL | #![deny(where_clauses_object_safety)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue TBD + = note: method `foo` references the `Self` type in where clauses error: aborting due to previous error -For more information about this error, try `rustc --explain E0038`.