about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/librustc/lint/builtin.rs7
-rw-r--r--src/librustc/traits/object_safety.rs34
-rw-r--r--src/librustc_lint/lib.rs5
-rw-r--r--src/test/compile-fail/issue-43431.rs2
-rw-r--r--src/test/compile-fail/wf-trait-fn-where-clause.rs2
-rw-r--r--src/test/ui/issue-50781.rs6
-rw-r--r--src/test/ui/issue-50781.stderr18
7 files changed, 61 insertions, 13 deletions
diff --git a/src/librustc/lint/builtin.rs b/src/librustc/lint/builtin.rs
index 7d4a18c2a57..1f8c7f0064e 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 9dc1f06fc11..85bd5853d18 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<A>()`
     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 9ac22f8dceb..ef12df795a6 100644
--- a/src/librustc_lint/lib.rs
+++ b/src/librustc_lint/lib.rs
@@ -293,6 +293,11 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) {
             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 <https://github.com/rust-lang/rust/issues/50589>",
             edition: None,
diff --git a/src/test/compile-fail/issue-43431.rs b/src/test/compile-fail/issue-43431.rs
index e9f62152888..1e6366e068a 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<A, B> {
-    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<A, B, F: Fn(A) -> B> CallSingle<A, B> 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 f59dca93bb9..f46a54504a0 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<T:Eq+?Sized> { value: Box<T> }
 
 trait Foo {
-    fn bar(&self) where Bar<Self>: Copy;
+    fn bar(&self) where Self: Sized, Bar<Self>: 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 3974fd54cf6..43830869da7 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 34d7303a9a5..ec24445e468 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`.