about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMathias Blikstad <mathias@blikstad.se>2019-01-08 22:14:04 +0100
committerNiko Matsakis <niko@alum.mit.edu>2019-10-22 15:24:33 -0400
commitef5acdecebb48a02cb34d19fa17d1bd59e41a4d3 (patch)
treecb6e20d78485549efc93763e17677eefe09ab6fc
parentd28a9c38fe14396e86ae274c7847e20ee0f78ca9 (diff)
downloadrust-ef5acdecebb48a02cb34d19fa17d1bd59e41a4d3.tar.gz
rust-ef5acdecebb48a02cb34d19fa17d1bd59e41a4d3.zip
RFC 2027: "first draft" of implementation
These are a squashed series of commits.
-rw-r--r--src/librustc/infer/error_reporting/mod.rs24
-rw-r--r--src/librustc/traits/error_reporting.rs32
-rw-r--r--src/librustc/traits/mod.rs3
-rw-r--r--src/librustc/traits/select.rs8
-rw-r--r--src/librustc/traits/structural_impls.rs4
-rw-r--r--src/librustc/ty/error.rs3
-rw-r--r--src/librustc/ty/structural_impls.rs2
-rw-r--r--src/librustc/ty/wf.rs25
-rw-r--r--src/librustc_errors/diagnostic.rs26
-rw-r--r--src/librustc_errors/diagnostic_builder.rs5
-rw-r--r--src/librustc_typeck/astconv.rs3
-rw-r--r--src/librustc_typeck/check/cast.rs43
-rw-r--r--src/librustc_typeck/check/coercion.rs31
-rw-r--r--src/librustc_typeck/coherence/mod.rs5
-rw-r--r--src/libsyntax/feature_gate/active.rs3
-rw-r--r--src/libsyntax_pos/symbol.rs1
-rw-r--r--src/test/ui/coherence/coherence-unsafe-trait-object-impl.rs18
-rw-r--r--src/test/ui/coherence/coherence-unsafe-trait-object-impl.stderr12
-rw-r--r--src/test/ui/feature-gates/feature-gate-exhaustive-patterns.nll.stderr16
-rw-r--r--src/test/ui/feature-gates/feature-gate-object_safe_for_dispatch.rs41
-rw-r--r--src/test/ui/feature-gates/feature-gate-object_safe_for_dispatch.stderr46
-rw-r--r--src/test/ui/issues/issue-19538.stderr1
-rw-r--r--src/test/ui/issues/issue-20692.stderr1
-rw-r--r--src/test/ui/issues/issue-38604.stderr1
-rw-r--r--src/test/ui/kindck/kindck-inherited-copy-bound.curr.stderr (renamed from src/test/ui/kindck/kindck-inherited-copy-bound.stderr)7
-rw-r--r--src/test/ui/kindck/kindck-inherited-copy-bound.object_safe_for_dispatch.stderr25
-rw-r--r--src/test/ui/kindck/kindck-inherited-copy-bound.rs11
-rw-r--r--src/test/ui/object-safety/object-safety-associated-consts.curr.stderr (renamed from src/test/ui/object-safety/object-safety-associated-consts.stderr)2
-rw-r--r--src/test/ui/object-safety/object-safety-associated-consts.object_safe_for_dispatch.stderr15
-rw-r--r--src/test/ui/object-safety/object-safety-associated-consts.rs6
-rw-r--r--src/test/ui/object-safety/object-safety-generics.curr.stderr (renamed from src/test/ui/object-safety/object-safety-generics.stderr)4
-rw-r--r--src/test/ui/object-safety/object-safety-generics.object_safe_for_dispatch.stderr27
-rw-r--r--src/test/ui/object-safety/object-safety-generics.rs10
-rw-r--r--src/test/ui/object-safety/object-safety-mentions-Self.curr.stderr (renamed from src/test/ui/object-safety/object-safety-mentions-Self.stderr)8
-rw-r--r--src/test/ui/object-safety/object-safety-mentions-Self.object_safe_for_dispatch.stderr27
-rw-r--r--src/test/ui/object-safety/object-safety-mentions-Self.rs20
-rw-r--r--src/test/ui/object-safety/object-safety-no-static.curr.stderr12
-rw-r--r--src/test/ui/object-safety/object-safety-no-static.object_safe_for_dispatch.stderr15
-rw-r--r--src/test/ui/object-safety/object-safety-no-static.rs16
-rw-r--r--src/test/ui/object-safety/object-safety-sized-2.curr.stderr (renamed from src/test/ui/object-safety/object-safety-sized-2.stderr)2
-rw-r--r--src/test/ui/object-safety/object-safety-sized-2.object_safe_for_dispatch.stderr13
-rw-r--r--src/test/ui/object-safety/object-safety-sized-2.rs9
-rw-r--r--src/test/ui/object-safety/object-safety-sized.curr.stderr (renamed from src/test/ui/object-safety/object-safety-sized.stderr)2
-rw-r--r--src/test/ui/object-safety/object-safety-sized.object_safe_for_dispatch.stderr13
-rw-r--r--src/test/ui/object-safety/object-safety-sized.rs7
-rw-r--r--src/test/ui/rfc-2027-object-safe-for-dispatch/downcast-unsafe-trait-objects.rs23
-rw-r--r--src/test/ui/rfc-2027-object-safe-for-dispatch/manual-self-impl-for-unsafe-obj.rs69
-rw-r--r--src/test/ui/rfc-2027-object-safe-for-dispatch/static-dispatch-unsafe-object.rs37
-rw-r--r--src/test/ui/self/arbitrary-self-types-not-object-safe.curr.stderr24
-rw-r--r--src/test/ui/self/arbitrary-self-types-not-object-safe.object_safe_for_dispatch.stderr15
-rw-r--r--src/test/ui/self/arbitrary-self-types-not-object-safe.rs8
-rw-r--r--src/test/ui/traits/trait-object-safety.stderr1
-rw-r--r--src/test/ui/traits/trait-test-2.stderr1
-rw-r--r--src/test/ui/wf/wf-convert-unsafe-trait-obj-box.rs18
-rw-r--r--src/test/ui/wf/wf-convert-unsafe-trait-obj-box.stderr33
-rw-r--r--src/test/ui/wf/wf-convert-unsafe-trait-obj.rs18
-rw-r--r--src/test/ui/wf/wf-convert-unsafe-trait-obj.stderr33
-rw-r--r--src/test/ui/wf/wf-unsafe-trait-obj-match.rs29
-rw-r--r--src/test/ui/wf/wf-unsafe-trait-obj-match.stderr38
59 files changed, 847 insertions, 105 deletions
diff --git a/src/librustc/infer/error_reporting/mod.rs b/src/librustc/infer/error_reporting/mod.rs
index f1192c7ce10..8f2fa3067a2 100644
--- a/src/librustc/infer/error_reporting/mod.rs
+++ b/src/librustc/infer/error_reporting/mod.rs
@@ -1146,10 +1146,17 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
 
         let span = cause.span(self.tcx);
 
-        diag.span_label(span, terr.to_string());
-        if let Some((sp, msg)) = secondary_span {
-            diag.span_label(sp, msg);
-        }
+        // Ignore msg for object safe coercion
+        // since E0038 message will be printed
+        match terr {
+            TypeError::ObjectUnsafeCoercion(_) => {}
+            _ => {
+                diag.span_label(span, terr.to_string());
+                if let Some((sp, msg)) = secondary_span {
+                    diag.span_label(sp, msg);
+                }
+            }
+        };
 
         if let Some((expected, found)) = expected_found {
             match (terr, is_simple_error, expected == found) {
@@ -1169,6 +1176,9 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
                         &sort_string(values.found),
                     );
                 }
+                (TypeError::ObjectUnsafeCoercion(_), ..) => {
+                    diag.note_unsuccessfull_coercion(found, expected);
+                }
                 (_, false, _) => {
                     if let Some(exp_found) = exp_found {
                         self.suggest_as_ref_where_appropriate(span, &exp_found, diag);
@@ -1267,6 +1277,10 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
         let span = trace.cause.span(self.tcx);
         let failure_code = trace.cause.as_failure_code(terr);
         let mut diag = match failure_code {
+            FailureCode::Error0038(did) => {
+                let violations = self.tcx.object_safety_violations(did);
+                self.tcx.report_object_safety_error(span, did, violations)
+            }
             FailureCode::Error0317(failure_str) => {
                 struct_span_err!(self.tcx.sess, span, E0317, "{}", failure_str)
             }
@@ -1628,6 +1642,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
 }
 
 enum FailureCode {
+    Error0038(DefId),
     Error0317(&'static str),
     Error0580(&'static str),
     Error0308(&'static str),
@@ -1666,6 +1681,7 @@ impl<'tcx> ObligationCause<'tcx> {
                 TypeError::IntrinsicCast => {
                     Error0308("cannot coerce intrinsics to function pointers")
                 }
+                TypeError::ObjectUnsafeCoercion(did) => Error0038(did.clone()),
                 _ => Error0308("mismatched types"),
             },
         }
diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs
index 9eb91569ed5..aa376699c38 100644
--- a/src/librustc/traits/error_reporting.rs
+++ b/src/librustc/traits/error_reporting.rs
@@ -790,15 +790,11 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
 
                     ty::Predicate::ObjectSafe(trait_def_id) => {
                         let violations = self.tcx.object_safety_violations(trait_def_id);
-                        if let Some(err) = self.tcx.report_object_safety_error(
+                        self.tcx.report_object_safety_error(
                             span,
                             trait_def_id,
                             violations,
-                        ) {
-                            err
-                        } else {
-                            return;
-                        }
+                        )
                     }
 
                     ty::Predicate::ClosureKind(closure_def_id, closure_substs, kind) => {
@@ -934,11 +930,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
 
             TraitNotObjectSafe(did) => {
                 let violations = self.tcx.object_safety_violations(did);
-                if let Some(err) = self.tcx.report_object_safety_error(span, did, violations) {
-                    err
-                } else {
-                    return;
-                }
+                self.tcx.report_object_safety_error(span, did, violations)
             }
 
             // already reported in the query
@@ -1493,11 +1485,7 @@ impl<'tcx> TyCtxt<'tcx> {
         span: Span,
         trait_def_id: DefId,
         violations: Vec<ObjectSafetyViolation>,
-    ) -> Option<DiagnosticBuilder<'tcx>> {
-        if self.sess.trait_methods_not_found.borrow().contains(&span) {
-            // Avoid emitting error caused by non-existing method (#58734)
-            return None;
-        }
+    ) -> DiagnosticBuilder<'tcx> {
         let trait_str = self.def_path_str(trait_def_id);
         let span = self.sess.source_map().def_span(span);
         let mut err = struct_span_err!(
@@ -1515,7 +1503,13 @@ impl<'tcx> TyCtxt<'tcx> {
                 };
             }
         }
-        Some(err)
+
+        if self.sess.trait_methods_not_found.borrow().contains(&span) {
+            // Avoid emitting error caused by non-existing method (#58734)
+            err.cancel();
+        }
+
+        err
     }
 }
 
@@ -1926,6 +1920,10 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
                 err.note(&format!("required for the cast to the object type `{}`",
                                   self.ty_to_string(object_ty)));
             }
+            ObligationCauseCode::Coercion { source: _, target } => {
+                err.note(&format!("required by cast to type `{}`",
+                                  self.ty_to_string(target)));
+            }
             ObligationCauseCode::RepeatVec => {
                 err.note("the `Copy` trait is required because the \
                           repeated element will be copied");
diff --git a/src/librustc/traits/mod.rs b/src/librustc/traits/mod.rs
index d96330bf0a9..eb4b114eb30 100644
--- a/src/librustc/traits/mod.rs
+++ b/src/librustc/traits/mod.rs
@@ -188,6 +188,9 @@ pub enum ObligationCauseCode<'tcx> {
     /// Obligation incurred due to an object cast.
     ObjectCastObligation(/* Object type */ Ty<'tcx>),
 
+    /// Obligation incurred due to a coercion.
+    Coercion { source: Ty<'tcx>, target: Ty<'tcx> },
+
     // Various cases where expressions must be sized/copy/etc:
     /// L = X implies that L is Sized
     AssignmentLhsSized,
diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs
index 44d611ace77..d8a27f1e040 100644
--- a/src/librustc/traits/select.rs
+++ b/src/librustc/traits/select.rs
@@ -2246,7 +2246,13 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                     }
 
                     if let Some(principal) = data.principal() {
-                        principal.with_self_ty(self.tcx(), self_ty)
+                        if !self.infcx.tcx.features().object_safe_for_dispatch {
+                            principal.with_self_ty(self.tcx(), self_ty)
+                        } else if self.tcx().is_object_safe(principal.def_id()) {
+                            principal.with_self_ty(self.tcx(), self_ty)
+                        } else {
+                            return;
+                        }
                     } else {
                         // Only auto-trait bounds exist.
                         return;
diff --git a/src/librustc/traits/structural_impls.rs b/src/librustc/traits/structural_impls.rs
index dab62a6bcb5..9729368edfe 100644
--- a/src/librustc/traits/structural_impls.rs
+++ b/src/librustc/traits/structural_impls.rs
@@ -481,6 +481,10 @@ impl<'a, 'tcx> Lift<'tcx> for traits::ObligationCauseCode<'a> {
                    .and_then(|r| Some(super::ObjectTypeBound(ty, r)))
             ),
             super::ObjectCastObligation(ty) => tcx.lift(&ty).map(super::ObjectCastObligation),
+            super::Coercion { source, target } => Some(super::Coercion {
+                source: tcx.lift(&source)?,
+                target: tcx.lift(&target)?,
+            }),
             super::AssignmentLhsSized => Some(super::AssignmentLhsSized),
             super::TupleInitializerSized => Some(super::TupleInitializerSized),
             super::StructInitializerSized => Some(super::StructInitializerSized),
diff --git a/src/librustc/ty/error.rs b/src/librustc/ty/error.rs
index 5851a48a8d3..882f330e6c3 100644
--- a/src/librustc/ty/error.rs
+++ b/src/librustc/ty/error.rs
@@ -45,7 +45,7 @@ pub enum TypeError<'tcx> {
     ProjectionMismatched(ExpectedFound<DefId>),
     ProjectionBoundsLength(ExpectedFound<usize>),
     ExistentialMismatch(ExpectedFound<&'tcx ty::List<ty::ExistentialPredicate<'tcx>>>),
-
+    ObjectUnsafeCoercion(DefId),
     ConstMismatch(ExpectedFound<&'tcx ty::Const<'tcx>>),
 
     IntrinsicCast,
@@ -179,6 +179,7 @@ impl<'tcx> fmt::Display for TypeError<'tcx> {
             IntrinsicCast => {
                 write!(f, "cannot coerce intrinsics to function pointers")
             }
+            ObjectUnsafeCoercion(_) => write!(f, "coercion to object-unsafe trait object"),
         }
     }
 }
diff --git a/src/librustc/ty/structural_impls.rs b/src/librustc/ty/structural_impls.rs
index 8945e1a1deb..3a5b8b57741 100644
--- a/src/librustc/ty/structural_impls.rs
+++ b/src/librustc/ty/structural_impls.rs
@@ -749,6 +749,7 @@ impl<'a, 'tcx> Lift<'tcx> for ty::error::TypeError<'a> {
             ExistentialMismatch(ref x) => return tcx.lift(x).map(ExistentialMismatch),
             ConstMismatch(ref x) => return tcx.lift(x).map(ConstMismatch),
             IntrinsicCast => IntrinsicCast,
+            ObjectUnsafeCoercion(ref x) => return tcx.lift(x).map(ObjectUnsafeCoercion),
         })
     }
 }
@@ -1356,6 +1357,7 @@ EnumTypeFoldableImpl! {
         (ty::error::TypeError::ExistentialMismatch)(x),
         (ty::error::TypeError::ConstMismatch)(x),
         (ty::error::TypeError::IntrinsicCast),
+        (ty::error::TypeError::ObjectUnsafeCoercion)(x),
     }
 }
 
diff --git a/src/librustc/ty/wf.rs b/src/librustc/ty/wf.rs
index ecb075e30b1..b50e819c956 100644
--- a/src/librustc/ty/wf.rs
+++ b/src/librustc/ty/wf.rs
@@ -380,16 +380,21 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
                     // obligations that don't refer to Self and
                     // checking those
 
-                    let cause = self.cause(traits::MiscObligation);
-                    let component_traits =
-                        data.auto_traits().chain(data.principal_def_id());
-                    self.out.extend(
-                        component_traits.map(|did| traits::Obligation::new(
-                            cause.clone(),
-                            param_env,
-                            ty::Predicate::ObjectSafe(did)
-                        ))
-                    );
+                    let defer_to_coercion =
+                        self.infcx.tcx.features().object_safe_for_dispatch;
+
+                    if !defer_to_coercion {
+                        let cause = self.cause(traits::MiscObligation);
+                        let component_traits =
+                            data.auto_traits().chain(data.principal_def_id());
+                        self.out.extend(
+                            component_traits.map(|did| traits::Obligation::new(
+                                cause.clone(),
+                                param_env,
+                                ty::Predicate::ObjectSafe(did)
+                            ))
+                        );
+                    }
                 }
 
                 // Inference variables are the complicated case, since we don't
diff --git a/src/librustc_errors/diagnostic.rs b/src/librustc_errors/diagnostic.rs
index fd74d8673da..1781f2e1650 100644
--- a/src/librustc_errors/diagnostic.rs
+++ b/src/librustc_errors/diagnostic.rs
@@ -152,6 +152,32 @@ impl Diagnostic {
         self.note_expected_found_extra(label, expected, found, &"", &"")
     }
 
+    pub fn note_unsuccessfull_coercion(&mut self,
+                                       expected: DiagnosticStyledString,
+                                       found: DiagnosticStyledString)
+                                       -> &mut Self
+    {
+        let mut msg: Vec<_> =
+            vec![(format!("required when trying to coerce from type `"),
+                  Style::NoStyle)];
+        msg.extend(expected.0.iter()
+                   .map(|x| match *x {
+                       StringPart::Normal(ref s) => (s.to_owned(), Style::NoStyle),
+                       StringPart::Highlighted(ref s) => (s.to_owned(), Style::Highlight),
+                   }));
+        msg.push((format!("` to type '"), Style::NoStyle));
+        msg.extend(found.0.iter()
+                   .map(|x| match *x {
+                       StringPart::Normal(ref s) => (s.to_owned(), Style::NoStyle),
+                       StringPart::Highlighted(ref s) => (s.to_owned(), Style::Highlight),
+                   }));
+        msg.push((format!("`"), Style::NoStyle));
+
+        // For now, just attach these as notes
+        self.highlighted_note(msg);
+        self
+    }
+
     pub fn note_expected_found_extra(&mut self,
                                      label: &dyn fmt::Display,
                                      expected: DiagnosticStyledString,
diff --git a/src/librustc_errors/diagnostic_builder.rs b/src/librustc_errors/diagnostic_builder.rs
index cc60bf89c7e..40642dd14b8 100644
--- a/src/librustc_errors/diagnostic_builder.rs
+++ b/src/librustc_errors/diagnostic_builder.rs
@@ -209,6 +209,11 @@ impl<'a> DiagnosticBuilder<'a> {
                                               found_extra: &dyn fmt::Display,
                                               ) -> &mut Self);
 
+    forward!(pub fn note_unsuccessfull_coercion(&mut self,
+                                                expected: DiagnosticStyledString,
+                                                found: DiagnosticStyledString,
+                                                ) -> &mut Self);
+
     forward!(pub fn note(&mut self, msg: &str) -> &mut Self);
     forward!(pub fn span_note<S: Into<MultiSpan>>(&mut self,
                                                   sp: S,
diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs
index b8e2700803a..2ee5ecfbcdc 100644
--- a/src/librustc_typeck/astconv.rs
+++ b/src/librustc_typeck/astconv.rs
@@ -1275,8 +1275,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                     span,
                     item.trait_ref().def_id(),
                     object_safety_violations
-                )
-                    .map(|mut err| err.emit());
+                ).emit();
                 return tcx.types.err;
             }
         }
diff --git a/src/librustc_typeck/check/cast.rs b/src/librustc_typeck/check/cast.rs
index dfeb5fb958c..9cbde276ae9 100644
--- a/src/librustc_typeck/check/cast.rs
+++ b/src/librustc_typeck/check/cast.rs
@@ -428,21 +428,36 @@ impl<'a, 'tcx> CastCheck<'tcx> {
             self.report_cast_to_unsized_type(fcx);
         } else if self.expr_ty.references_error() || self.cast_ty.references_error() {
             // No sense in giving duplicate error messages
-        } else if self.try_coercion_cast(fcx) {
-            self.trivial_cast_lint(fcx);
-            debug!(" -> CoercionCast");
-            fcx.tables.borrow_mut().set_coercion_cast(self.expr.hir_id.local_id);
-
         } else {
-            match self.do_check(fcx) {
-                Ok(k) => {
-                    debug!(" -> {:?}", k);
+            match self.try_coercion_cast(fcx) {
+                Ok(()) => {
+                    self.trivial_cast_lint(fcx);
+                    debug!(" -> CoercionCast");
+                    fcx.tables.borrow_mut()
+                        .set_coercion_cast(self.expr.hir_id.local_id);
+                }
+                Err(ty::error::TypeError::ObjectUnsafeCoercion(did)) => {
+                    self.report_object_unsafe_cast(&fcx, did);
+                }
+                Err(_) => {
+                    match self.do_check(fcx) {
+                        Ok(k) => {
+                            debug!(" -> {:?}", k);
+                        }
+                        Err(e) => self.report_cast_error(fcx, e),
+                    };
                 }
-                Err(e) => self.report_cast_error(fcx, e),
             };
         }
     }
 
+    fn report_object_unsafe_cast(&self, fcx: &FnCtxt<'a, 'tcx>, did: DefId) {
+        let violations = fcx.tcx.object_safety_violations(did);
+        let mut err = fcx.tcx.report_object_safety_error(self.cast_span, did, violations);
+        err.note(&format!("required by cast to type '{}'", fcx.ty_to_string(self.cast_ty)));
+        err.emit();
+    }
+
     /// Checks a cast, and report an error if one exists. In some cases, this
     /// can return Ok and create type errors in the fcx rather than returning
     /// directly. coercion-cast is handled in check instead of here.
@@ -646,8 +661,14 @@ impl<'a, 'tcx> CastCheck<'tcx> {
         }
     }
 
-    fn try_coercion_cast(&self, fcx: &FnCtxt<'a, 'tcx>) -> bool {
-        fcx.try_coerce(self.expr, self.expr_ty, self.cast_ty, AllowTwoPhase::No).is_ok()
+    fn try_coercion_cast(
+        &self,
+        fcx: &FnCtxt<'a, 'tcx>,
+    ) -> Result<(), ty::error::TypeError<'_>> {
+        match fcx.try_coerce(self.expr, self.expr_ty, self.cast_ty, AllowTwoPhase::No) {
+            Ok(_) => Ok(()),
+            Err(err) => Err(err),
+        }
     }
 }
 
diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs
index 3a89cddda23..5c4c66bb64e 100644
--- a/src/librustc_typeck/check/coercion.rs
+++ b/src/librustc_typeck/check/coercion.rs
@@ -61,10 +61,11 @@ use rustc::traits::{self, ObligationCause, ObligationCauseCode};
 use rustc::ty::adjustment::{
     Adjustment, Adjust, AllowTwoPhase, AutoBorrow, AutoBorrowMutability, PointerCast
 };
-use rustc::ty::{self, TypeAndMut, Ty, subst::SubstsRef};
+use rustc::ty::{self, TypeAndMut, Ty};
 use rustc::ty::fold::TypeFoldable;
 use rustc::ty::error::TypeError;
 use rustc::ty::relate::RelateResult;
+use rustc::ty::subst::SubstsRef;
 use smallvec::{smallvec, SmallVec};
 use std::ops::Deref;
 use syntax::feature_gate;
@@ -196,9 +197,16 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
         // a "spurious" type variable, and we don't want to have that
         // type variable in memory if the coercion fails.
         let unsize = self.commit_if_ok(|_| self.coerce_unsized(a, b));
-        if unsize.is_ok() {
-            debug!("coerce: unsize successful");
-            return unsize;
+        match unsize {
+            Ok(_) => {
+                debug!("coerce: unsize successful");
+                return unsize;
+            }
+            Err(TypeError::ObjectUnsafeCoercion(did)) => {
+                debug!("coerce: unsize not object safe");
+                return Err(TypeError::ObjectUnsafeCoercion(did));
+            }
+            Err(_) => {}
         }
         debug!("coerce: unsize failed");
 
@@ -539,7 +547,11 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
         let mut selcx = traits::SelectionContext::new(self);
 
         // Create an obligation for `Source: CoerceUnsized<Target>`.
-        let cause = ObligationCause::misc(self.cause.span, self.body_id);
+        let cause = ObligationCause::new(
+            self.cause.span,
+            self.body_id,
+            ObligationCauseCode::Coercion { source, target },
+        );
 
         // Use a FIFO queue for this custom fulfillment procedure.
         //
@@ -566,14 +578,15 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
             let obligation = queue.remove(0);
             debug!("coerce_unsized resolve step: {:?}", obligation);
             let trait_ref = match obligation.predicate {
-                ty::Predicate::Trait(ref t) if traits.contains(&t.def_id()) => {
-                    if unsize_did == t.def_id() {
-                        if let ty::Tuple(..) = &t.skip_binder().input_types().nth(1).unwrap().kind {
+                ty::Predicate::Trait(ref tr) if traits.contains(&tr.def_id()) => {
+                    if unsize_did == tr.def_id() {
+                        let sty = &tr.skip_binder().input_types().nth(1).unwrap().kind;
+                        if let ty::Tuple(..) = sty {
                             debug!("coerce_unsized: found unsized tuple coercion");
                             has_unsized_tuple_coercion = true;
                         }
                     }
-                    t.clone()
+                    tr.clone()
                 }
                 _ => {
                     coercion.obligations.push(obligation);
diff --git a/src/librustc_typeck/coherence/mod.rs b/src/librustc_typeck/coherence/mod.rs
index a44c475e0f8..8adf4bb94a8 100644
--- a/src/librustc_typeck/coherence/mod.rs
+++ b/src/librustc_typeck/coherence/mod.rs
@@ -183,8 +183,11 @@ fn check_impl_overlap<'tcx>(tcx: TyCtxt<'tcx>, hir_id: HirId) {
 
         for component_def_id in component_def_ids {
             if !tcx.is_object_safe(component_def_id) {
-                // This is an error, but it will be reported by wfcheck.  Ignore it here.
+                // Without the 'object_safe_for_dispatch' feature this is an error
+                // which will be reported by wfcheck.  Ignore it here.
                 // This is tested by `coherence-impl-trait-for-trait-object-safe.rs`.
+                // With the feature enabled, the trait is not implemented automatically,
+                // so this is valid.
             } else {
                 let mut supertrait_def_ids =
                     traits::supertrait_def_ids(tcx, component_def_id);
diff --git a/src/libsyntax/feature_gate/active.rs b/src/libsyntax/feature_gate/active.rs
index 94f0995566f..1386eac48da 100644
--- a/src/libsyntax/feature_gate/active.rs
+++ b/src/libsyntax/feature_gate/active.rs
@@ -528,6 +528,9 @@ declare_features! (
     /// Enable accurate caller location reporting during panic (RFC 2091).
     (active, track_caller, "1.40.0", Some(47809), None),
 
+    /// Non-object safe trait objects safe to use but cannot be created in safe rust
+    (active, object_safe_for_dispatch, "1.40.0", Some(43561), None),
+
     // -------------------------------------------------------------------------
     // feature-group-end: actual feature gates
     // -------------------------------------------------------------------------
diff --git a/src/libsyntax_pos/symbol.rs b/src/libsyntax_pos/symbol.rs
index c37efde9923..b80c5f83830 100644
--- a/src/libsyntax_pos/symbol.rs
+++ b/src/libsyntax_pos/symbol.rs
@@ -459,6 +459,7 @@ symbols! {
         no_std,
         not,
         note,
+        object_safe_for_dispatch,
         Ok,
         omit_gdb_pretty_printer_section,
         on,
diff --git a/src/test/ui/coherence/coherence-unsafe-trait-object-impl.rs b/src/test/ui/coherence/coherence-unsafe-trait-object-impl.rs
new file mode 100644
index 00000000000..9859a226efd
--- /dev/null
+++ b/src/test/ui/coherence/coherence-unsafe-trait-object-impl.rs
@@ -0,0 +1,18 @@
+// Check that unsafe trait object do not implement themselves
+// automatically
+
+#![feature(object_safe_for_dispatch)]
+
+trait Trait: Sized {
+    fn call(&self);
+}
+
+fn takes_t<S: Trait>(s: S) {
+    s.call();
+}
+
+fn takes_t_obj(t: &dyn Trait) {
+    takes_t(t); //~ ERROR E0277
+}
+
+fn main() {}
diff --git a/src/test/ui/coherence/coherence-unsafe-trait-object-impl.stderr b/src/test/ui/coherence/coherence-unsafe-trait-object-impl.stderr
new file mode 100644
index 00000000000..b5a86acfb97
--- /dev/null
+++ b/src/test/ui/coherence/coherence-unsafe-trait-object-impl.stderr
@@ -0,0 +1,12 @@
+error[E0277]: the trait bound `&dyn Trait: Trait` is not satisfied
+  --> $DIR/coherence-unsafe-trait-object-impl.rs:15:13
+   |
+LL | fn takes_t<S: Trait>(s: S) {
+   |    -------    ----- required by this bound in `takes_t`
+...
+LL |     takes_t(t);
+   |             ^ the trait `Trait` is not implemented for `&dyn Trait`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/feature-gates/feature-gate-exhaustive-patterns.nll.stderr b/src/test/ui/feature-gates/feature-gate-exhaustive-patterns.nll.stderr
deleted file mode 100644
index d77fbc1e823..00000000000
--- a/src/test/ui/feature-gates/feature-gate-exhaustive-patterns.nll.stderr
+++ /dev/null
@@ -1,16 +0,0 @@
-error[E0005]: refutable pattern in local binding: `Err(_)` not covered
-  --> $DIR/feature-gate-exhaustive-patterns.rs:7:9
-   |
-LL |     let Ok(_x) = foo();
-   |         ^^^^^^ pattern `Err(_)` not covered
-   |
-   = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
-   = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
-help: you might want to use `if let` to ignore the variant that isn't matched
-   |
-LL |     if let Ok(_x) = foo() { /* */ }
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0005`.
diff --git a/src/test/ui/feature-gates/feature-gate-object_safe_for_dispatch.rs b/src/test/ui/feature-gates/feature-gate-object_safe_for_dispatch.rs
new file mode 100644
index 00000000000..8945360b7be
--- /dev/null
+++ b/src/test/ui/feature-gates/feature-gate-object_safe_for_dispatch.rs
@@ -0,0 +1,41 @@
+// Test that the use of the non object-safe trait objects
+// are gated by `object_safe_for_dispatch` feature gate.
+
+trait NonObjectSafe1: Sized {}
+
+trait NonObjectSafe2 {
+    fn static_fn() {}
+}
+
+trait NonObjectSafe3 {
+    fn foo<T>(&self);
+}
+
+trait NonObjectSafe4 {
+    fn foo(&self, &Self);
+}
+
+fn takes_non_object_safe_ref<T>(obj: &dyn NonObjectSafe1) {
+    //~^ ERROR E0038
+}
+
+fn return_non_object_safe_ref() -> &'static dyn NonObjectSafe2 {
+    //~^ ERROR E0038
+    loop {}
+}
+
+fn takes_non_object_safe_box(obj: Box<dyn NonObjectSafe3>) {
+    //~^ ERROR E0038
+}
+
+fn return_non_object_safe_rc() -> std::rc::Rc<dyn NonObjectSafe4> {
+    //~^ ERROR E0038
+    loop {}
+}
+
+trait Trait {}
+
+impl Trait for dyn NonObjectSafe1 {}
+//~^ ERROR E0038
+
+fn main() {}
diff --git a/src/test/ui/feature-gates/feature-gate-object_safe_for_dispatch.stderr b/src/test/ui/feature-gates/feature-gate-object_safe_for_dispatch.stderr
new file mode 100644
index 00000000000..54e64e2fc1b
--- /dev/null
+++ b/src/test/ui/feature-gates/feature-gate-object_safe_for_dispatch.stderr
@@ -0,0 +1,46 @@
+error[E0038]: the trait `NonObjectSafe1` cannot be made into an object
+  --> $DIR/feature-gate-object_safe_for_dispatch.rs:18:1
+   |
+LL | fn takes_non_object_safe_ref<T>(obj: &dyn NonObjectSafe1) {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `NonObjectSafe1` cannot be made into an object
+   |
+   = note: the trait cannot require that `Self : Sized`
+
+error[E0038]: the trait `NonObjectSafe2` cannot be made into an object
+  --> $DIR/feature-gate-object_safe_for_dispatch.rs:22:1
+   |
+LL |     fn static_fn() {}
+   |        --------- associated function `static_fn` has no `self` parameter
+...
+LL | fn return_non_object_safe_ref() -> &'static dyn NonObjectSafe2 {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `NonObjectSafe2` cannot be made into an object
+
+error[E0038]: the trait `NonObjectSafe3` cannot be made into an object
+  --> $DIR/feature-gate-object_safe_for_dispatch.rs:27:1
+   |
+LL |     fn foo<T>(&self);
+   |        --- method `foo` has generic type parameters
+...
+LL | fn takes_non_object_safe_box(obj: Box<dyn NonObjectSafe3>) {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `NonObjectSafe3` cannot be made into an object
+
+error[E0038]: the trait `NonObjectSafe4` cannot be made into an object
+  --> $DIR/feature-gate-object_safe_for_dispatch.rs:31:1
+   |
+LL |     fn foo(&self, &Self);
+   |        --- method `foo` references the `Self` type in its parameters or return type
+...
+LL | fn return_non_object_safe_rc() -> std::rc::Rc<dyn NonObjectSafe4> {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `NonObjectSafe4` cannot be made into an object
+
+error[E0038]: the trait `NonObjectSafe1` cannot be made into an object
+  --> $DIR/feature-gate-object_safe_for_dispatch.rs:38:6
+   |
+LL | impl Trait for dyn NonObjectSafe1 {}
+   |      ^^^^^ the trait `NonObjectSafe1` cannot be made into an object
+   |
+   = note: the trait cannot require that `Self : Sized`
+
+error: aborting due to 5 previous errors
+
+For more information about this error, try `rustc --explain E0038`.
diff --git a/src/test/ui/issues/issue-19538.stderr b/src/test/ui/issues/issue-19538.stderr
index 5415a45f7d6..83c03b514dd 100644
--- a/src/test/ui/issues/issue-19538.stderr
+++ b/src/test/ui/issues/issue-19538.stderr
@@ -17,6 +17,7 @@ LL |     let test: &mut dyn Bar = &mut thing;
    |                              ^^^^^^^^^^ the trait `Bar` cannot be made into an object
    |
    = note: required because of the requirements on the impl of `std::ops::CoerceUnsized<&mut dyn Bar>` for `&mut Thing`
+   = note: required by cast to type `&mut dyn Bar`
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/issues/issue-20692.stderr b/src/test/ui/issues/issue-20692.stderr
index 66309394a42..06c83f65be2 100644
--- a/src/test/ui/issues/issue-20692.stderr
+++ b/src/test/ui/issues/issue-20692.stderr
@@ -14,6 +14,7 @@ LL |     let _ = x
    |
    = note: the trait cannot require that `Self : Sized`
    = note: required because of the requirements on the impl of `std::ops::CoerceUnsized<&dyn Array>` for `&T`
+   = note: required by cast to type `&dyn Array`
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/issues/issue-38604.stderr b/src/test/ui/issues/issue-38604.stderr
index 8ef7d346cb3..8b923a2c6b2 100644
--- a/src/test/ui/issues/issue-38604.stderr
+++ b/src/test/ui/issues/issue-38604.stderr
@@ -14,6 +14,7 @@ LL |         Box::new(());
    |
    = note: the trait cannot use `Self` as a type parameter in the supertraits or where-clauses
    = note: required because of the requirements on the impl of `std::ops::CoerceUnsized<std::boxed::Box<dyn Foo>>` for `std::boxed::Box<()>`
+   = note: required by cast to type `std::boxed::Box<dyn Foo>`
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/kindck/kindck-inherited-copy-bound.stderr b/src/test/ui/kindck/kindck-inherited-copy-bound.curr.stderr
index 27901d06927..a93f4686496 100644
--- a/src/test/ui/kindck/kindck-inherited-copy-bound.stderr
+++ b/src/test/ui/kindck/kindck-inherited-copy-bound.curr.stderr
@@ -1,5 +1,5 @@
 error[E0277]: the trait bound `std::boxed::Box<{integer}>: std::marker::Copy` is not satisfied
-  --> $DIR/kindck-inherited-copy-bound.rs:18:16
+  --> $DIR/kindck-inherited-copy-bound.rs:21:16
    |
 LL | fn take_param<T:Foo>(foo: &T) { }
    |    ----------   --- required by this bound in `take_param`
@@ -10,7 +10,7 @@ LL |     take_param(&x);
    = note: required because of the requirements on the impl of `Foo` for `std::boxed::Box<{integer}>`
 
 error[E0038]: the trait `Foo` cannot be made into an object
-  --> $DIR/kindck-inherited-copy-bound.rs:24:19
+  --> $DIR/kindck-inherited-copy-bound.rs:28:19
    |
 LL |     let z = &x as &dyn Foo;
    |                   ^^^^^^^^ the trait `Foo` cannot be made into an object
@@ -18,13 +18,14 @@ LL |     let z = &x as &dyn Foo;
    = note: the trait cannot require that `Self : Sized`
 
 error[E0038]: the trait `Foo` cannot be made into an object
-  --> $DIR/kindck-inherited-copy-bound.rs:24:13
+  --> $DIR/kindck-inherited-copy-bound.rs:28:13
    |
 LL |     let z = &x as &dyn Foo;
    |             ^^ the trait `Foo` cannot be made into an object
    |
    = note: the trait cannot require that `Self : Sized`
    = note: required because of the requirements on the impl of `std::ops::CoerceUnsized<&dyn Foo>` for `&std::boxed::Box<{integer}>`
+   = note: required by cast to type `&dyn Foo`
 
 error: aborting due to 3 previous errors
 
diff --git a/src/test/ui/kindck/kindck-inherited-copy-bound.object_safe_for_dispatch.stderr b/src/test/ui/kindck/kindck-inherited-copy-bound.object_safe_for_dispatch.stderr
new file mode 100644
index 00000000000..7c67c5f9e95
--- /dev/null
+++ b/src/test/ui/kindck/kindck-inherited-copy-bound.object_safe_for_dispatch.stderr
@@ -0,0 +1,25 @@
+error[E0277]: the trait bound `std::boxed::Box<{integer}>: std::marker::Copy` is not satisfied
+  --> $DIR/kindck-inherited-copy-bound.rs:21:16
+   |
+LL | fn take_param<T:Foo>(foo: &T) { }
+   |    ----------   --- required by this bound in `take_param`
+...
+LL |     take_param(&x);
+   |                ^^ the trait `std::marker::Copy` is not implemented for `std::boxed::Box<{integer}>`
+   |
+   = note: required because of the requirements on the impl of `Foo` for `std::boxed::Box<{integer}>`
+
+error[E0038]: the trait `Foo` cannot be made into an object
+  --> $DIR/kindck-inherited-copy-bound.rs:28:13
+   |
+LL |     let z = &x as &dyn Foo;
+   |             ^^ the trait `Foo` cannot be made into an object
+   |
+   = note: the trait cannot require that `Self : Sized`
+   = note: required because of the requirements on the impl of `std::ops::CoerceUnsized<&dyn Foo>` for `&std::boxed::Box<i32>`
+   = note: required by cast to type `&dyn Foo`
+
+error: aborting due to 2 previous errors
+
+Some errors have detailed explanations: E0038, E0277.
+For more information about an error, try `rustc --explain E0038`.
diff --git a/src/test/ui/kindck/kindck-inherited-copy-bound.rs b/src/test/ui/kindck/kindck-inherited-copy-bound.rs
index 61e72908248..aad693e5b19 100644
--- a/src/test/ui/kindck/kindck-inherited-copy-bound.rs
+++ b/src/test/ui/kindck/kindck-inherited-copy-bound.rs
@@ -1,5 +1,8 @@
 // Test that Copy bounds inherited by trait are checked.
+//
+// revisions: curr object_safe_for_dispatch
 
+#![cfg_attr(object_safe_for_dispatch, feature(object_safe_for_dispatch))]
 #![feature(box_syntax)]
 
 use std::any::Any;
@@ -15,15 +18,17 @@ fn take_param<T:Foo>(foo: &T) { }
 
 fn a() {
     let x: Box<_> = box 3;
-    take_param(&x); //~ ERROR E0277
+    take_param(&x); //[curr]~ ERROR E0277
+    //[object_safe_for_dispatch]~^ ERROR E0277
 }
 
 fn b() {
     let x: Box<_> = box 3;
     let y = &x;
     let z = &x as &dyn Foo;
-    //~^ ERROR E0038
-    //~| ERROR E0038
+    //[curr]~^ ERROR E0038
+    //[curr]~| ERROR E0038
+    //[object_safe_for_dispatch]~^^^ ERROR E0038
 }
 
 fn main() { }
diff --git a/src/test/ui/object-safety/object-safety-associated-consts.stderr b/src/test/ui/object-safety/object-safety-associated-consts.curr.stderr
index 7d5aa00356e..67ef7a62f10 100644
--- a/src/test/ui/object-safety/object-safety-associated-consts.stderr
+++ b/src/test/ui/object-safety/object-safety-associated-consts.curr.stderr
@@ -1,5 +1,5 @@
 error[E0038]: the trait `Bar` cannot be made into an object
-  --> $DIR/object-safety-associated-consts.rs:9:1
+  --> $DIR/object-safety-associated-consts.rs:12:1
    |
 LL |     const X: usize;
    |           - the trait cannot contain associated consts like `X`
diff --git a/src/test/ui/object-safety/object-safety-associated-consts.object_safe_for_dispatch.stderr b/src/test/ui/object-safety/object-safety-associated-consts.object_safe_for_dispatch.stderr
new file mode 100644
index 00000000000..20993a680ba
--- /dev/null
+++ b/src/test/ui/object-safety/object-safety-associated-consts.object_safe_for_dispatch.stderr
@@ -0,0 +1,15 @@
+error[E0038]: the trait `Bar` cannot be made into an object
+  --> $DIR/object-safety-associated-consts.rs:14:5
+   |
+LL |     const X: usize;
+   |           - the trait cannot contain associated consts like `X`
+...
+LL |     t
+   |     ^ the trait `Bar` cannot be made into an object
+   |
+   = note: required because of the requirements on the impl of `std::ops::CoerceUnsized<&dyn Bar>` for `&T`
+   = note: required by cast to type `&dyn Bar`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0038`.
diff --git a/src/test/ui/object-safety/object-safety-associated-consts.rs b/src/test/ui/object-safety/object-safety-associated-consts.rs
index 5900019ea91..e1a772e5ab2 100644
--- a/src/test/ui/object-safety/object-safety-associated-consts.rs
+++ b/src/test/ui/object-safety/object-safety-associated-consts.rs
@@ -1,14 +1,18 @@
 // Check that we correctly prevent users from making trait objects
 // from traits with associated consts.
+//
+// revisions: curr object_safe_for_dispatch
 
+#![cfg_attr(object_safe_for_dispatch, feature(object_safe_for_dispatch))]
 
 trait Bar {
     const X: usize;
 }
 
 fn make_bar<T:Bar>(t: &T) -> &dyn Bar {
-    //~^ ERROR E0038
+    //[curr]~^ ERROR E0038
     t
+    //[object_safe_for_dispatch]~^ ERROR E0038
 }
 
 fn main() {
diff --git a/src/test/ui/object-safety/object-safety-generics.stderr b/src/test/ui/object-safety/object-safety-generics.curr.stderr
index b25e0052e41..8ae9236a5c3 100644
--- a/src/test/ui/object-safety/object-safety-generics.stderr
+++ b/src/test/ui/object-safety/object-safety-generics.curr.stderr
@@ -1,5 +1,5 @@
 error[E0038]: the trait `Bar` cannot be made into an object
-  --> $DIR/object-safety-generics.rs:14:1
+  --> $DIR/object-safety-generics.rs:18:1
    |
 LL |     fn bar<T>(&self, t: T);
    |        --- method `bar` has generic type parameters
@@ -8,7 +8,7 @@ LL | fn make_bar<T:Bar>(t: &T) -> &dyn Bar {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Bar` cannot be made into an object
 
 error[E0038]: the trait `Bar` cannot be made into an object
-  --> $DIR/object-safety-generics.rs:19:1
+  --> $DIR/object-safety-generics.rs:24:1
    |
 LL |     fn bar<T>(&self, t: T);
    |        --- method `bar` has generic type parameters
diff --git a/src/test/ui/object-safety/object-safety-generics.object_safe_for_dispatch.stderr b/src/test/ui/object-safety/object-safety-generics.object_safe_for_dispatch.stderr
new file mode 100644
index 00000000000..d3d8d368888
--- /dev/null
+++ b/src/test/ui/object-safety/object-safety-generics.object_safe_for_dispatch.stderr
@@ -0,0 +1,27 @@
+error[E0038]: the trait `Bar` cannot be made into an object
+  --> $DIR/object-safety-generics.rs:20:5
+   |
+LL |     fn bar<T>(&self, t: T);
+   |        --- method `bar` has generic type parameters
+...
+LL |     t
+   |     ^ the trait `Bar` cannot be made into an object
+   |
+   = note: required because of the requirements on the impl of `std::ops::CoerceUnsized<&dyn Bar>` for `&T`
+   = note: required by cast to type `&dyn Bar`
+
+error[E0038]: the trait `Bar` cannot be made into an object
+  --> $DIR/object-safety-generics.rs:26:5
+   |
+LL |     fn bar<T>(&self, t: T);
+   |        --- method `bar` has generic type parameters
+...
+LL |     t as &dyn Bar
+   |     ^ the trait `Bar` cannot be made into an object
+   |
+   = note: required because of the requirements on the impl of `std::ops::CoerceUnsized<&dyn Bar>` for `&T`
+   = note: required by cast to type `&dyn Bar`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0038`.
diff --git a/src/test/ui/object-safety/object-safety-generics.rs b/src/test/ui/object-safety/object-safety-generics.rs
index d63ea28c8f2..63dcd169925 100644
--- a/src/test/ui/object-safety/object-safety-generics.rs
+++ b/src/test/ui/object-safety/object-safety-generics.rs
@@ -1,6 +1,10 @@
 // Check that we correctly prevent users from making trait objects
 // from traits with generic methods, unless `where Self : Sized` is
 // present.
+// revisions: curr object_safe_for_dispatch
+
+#![cfg_attr(object_safe_for_dispatch, feature(object_safe_for_dispatch))]
+
 
 trait Bar {
     fn bar<T>(&self, t: T);
@@ -12,13 +16,15 @@ trait Quux {
 }
 
 fn make_bar<T:Bar>(t: &T) -> &dyn Bar {
-        //~^ ERROR E0038
+    //[curr]~^ ERROR E0038
     t
+    //[object_safe_for_dispatch]~^ ERROR E0038
 }
 
 fn make_bar_explicit<T:Bar>(t: &T) -> &dyn Bar {
-    //~^ ERROR E0038
+    //[curr]~^ ERROR E0038
     t as &dyn Bar
+    //[object_safe_for_dispatch]~^ ERROR E0038
 }
 
 fn make_quux<T:Quux>(t: &T) -> &dyn Quux {
diff --git a/src/test/ui/object-safety/object-safety-mentions-Self.stderr b/src/test/ui/object-safety/object-safety-mentions-Self.curr.stderr
index 971e79cb021..297cd876187 100644
--- a/src/test/ui/object-safety/object-safety-mentions-Self.stderr
+++ b/src/test/ui/object-safety/object-safety-mentions-Self.curr.stderr
@@ -1,5 +1,5 @@
 error[E0038]: the trait `Bar` cannot be made into an object
-  --> $DIR/object-safety-mentions-Self.rs:17:1
+  --> $DIR/object-safety-mentions-Self.rs:22:1
    |
 LL |     fn bar(&self, x: &Self);
    |        --- method `bar` references the `Self` type in its parameters or return type
@@ -8,10 +8,10 @@ LL | fn make_bar<T:Bar>(t: &T) -> &dyn Bar {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Bar` cannot be made into an object
 
 error[E0038]: the trait `Baz` cannot be made into an object
-  --> $DIR/object-safety-mentions-Self.rs:22:1
+  --> $DIR/object-safety-mentions-Self.rs:28:1
    |
-LL |     fn bar(&self) -> Self;
-   |        --- method `bar` references the `Self` type in its parameters or return type
+LL |     fn baz(&self) -> Self;
+   |        --- method `baz` references the `Self` type in its parameters or return type
 ...
 LL | fn make_baz<T:Baz>(t: &T) -> &dyn Baz {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Baz` cannot be made into an object
diff --git a/src/test/ui/object-safety/object-safety-mentions-Self.object_safe_for_dispatch.stderr b/src/test/ui/object-safety/object-safety-mentions-Self.object_safe_for_dispatch.stderr
new file mode 100644
index 00000000000..03b2b8da075
--- /dev/null
+++ b/src/test/ui/object-safety/object-safety-mentions-Self.object_safe_for_dispatch.stderr
@@ -0,0 +1,27 @@
+error[E0038]: the trait `Bar` cannot be made into an object
+  --> $DIR/object-safety-mentions-Self.rs:24:5
+   |
+LL |     fn bar(&self, x: &Self);
+   |        --- method `bar` references the `Self` type in its parameters or return type
+...
+LL |     t
+   |     ^ the trait `Bar` cannot be made into an object
+   |
+   = note: required because of the requirements on the impl of `std::ops::CoerceUnsized<&dyn Bar>` for `&T`
+   = note: required by cast to type `&dyn Bar`
+
+error[E0038]: the trait `Baz` cannot be made into an object
+  --> $DIR/object-safety-mentions-Self.rs:30:5
+   |
+LL |     fn baz(&self) -> Self;
+   |        --- method `baz` references the `Self` type in its parameters or return type
+...
+LL |     t
+   |     ^ the trait `Baz` cannot be made into an object
+   |
+   = note: required because of the requirements on the impl of `std::ops::CoerceUnsized<&dyn Baz>` for `&T`
+   = note: required by cast to type `&dyn Baz`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0038`.
diff --git a/src/test/ui/object-safety/object-safety-mentions-Self.rs b/src/test/ui/object-safety/object-safety-mentions-Self.rs
index f13ffe53626..412d16ff3c7 100644
--- a/src/test/ui/object-safety/object-safety-mentions-Self.rs
+++ b/src/test/ui/object-safety/object-safety-mentions-Self.rs
@@ -1,27 +1,34 @@
 // Check that we correctly prevent users from making trait objects
 // form traits that make use of `Self` in an argument or return
 // position, unless `where Self : Sized` is present..
+//
+// revisions: curr object_safe_for_dispatch
+
+#![cfg_attr(object_safe_for_dispatch, feature(object_safe_for_dispatch))]
+
 
 trait Bar {
     fn bar(&self, x: &Self);
 }
 
 trait Baz {
-    fn bar(&self) -> Self;
+    fn baz(&self) -> Self;
 }
 
 trait Quux {
-    fn get(&self, s: &Self) -> Self where Self : Sized;
+    fn quux(&self, s: &Self) -> Self where Self : Sized;
 }
 
 fn make_bar<T:Bar>(t: &T) -> &dyn Bar {
-        //~^ ERROR E0038
-    loop { }
+    //[curr]~^ ERROR E0038
+    t
+    //[object_safe_for_dispatch]~^ ERROR E0038
 }
 
 fn make_baz<T:Baz>(t: &T) -> &dyn Baz {
-        //~^ ERROR E0038
+    //[curr]~^ ERROR E0038
     t
+    //[object_safe_for_dispatch]~^ ERROR E0038
 }
 
 fn make_quux<T:Quux>(t: &T) -> &dyn Quux {
@@ -32,5 +39,4 @@ fn make_quux_explicit<T:Quux>(t: &T) -> &dyn Quux {
     t as &dyn Quux
 }
 
-fn main() {
-}
+fn main() {}
diff --git a/src/test/ui/object-safety/object-safety-no-static.curr.stderr b/src/test/ui/object-safety/object-safety-no-static.curr.stderr
new file mode 100644
index 00000000000..1641ce57771
--- /dev/null
+++ b/src/test/ui/object-safety/object-safety-no-static.curr.stderr
@@ -0,0 +1,12 @@
+error[E0038]: the trait `Foo` cannot be made into an object
+  --> $DIR/object-safety-no-static.rs:12:1
+   |
+LL |     fn foo() {}
+   |        --- associated function `foo` has no `self` parameter
+...
+LL | fn diverges() -> Box<dyn Foo> {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Foo` cannot be made into an object
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0038`.
diff --git a/src/test/ui/object-safety/object-safety-no-static.object_safe_for_dispatch.stderr b/src/test/ui/object-safety/object-safety-no-static.object_safe_for_dispatch.stderr
new file mode 100644
index 00000000000..91a9285b63c
--- /dev/null
+++ b/src/test/ui/object-safety/object-safety-no-static.object_safe_for_dispatch.stderr
@@ -0,0 +1,15 @@
+error[E0038]: the trait `Foo` cannot be made into an object
+  --> $DIR/object-safety-no-static.rs:22:27
+   |
+LL |     fn foo() {}
+   |        --- associated function `foo` has no `self` parameter
+...
+LL |     let b: Box<dyn Foo> = Box::new(Bar);
+   |                           ^^^^^^^^^^^^^ the trait `Foo` cannot be made into an object
+   |
+   = note: required because of the requirements on the impl of `std::ops::CoerceUnsized<std::boxed::Box<dyn Foo>>` for `std::boxed::Box<Bar>`
+   = note: required by cast to type `std::boxed::Box<dyn Foo>`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0038`.
diff --git a/src/test/ui/object-safety/object-safety-no-static.rs b/src/test/ui/object-safety/object-safety-no-static.rs
index 55d31ce8087..03b62217483 100644
--- a/src/test/ui/object-safety/object-safety-no-static.rs
+++ b/src/test/ui/object-safety/object-safety-no-static.rs
@@ -1,14 +1,24 @@
 // Check that we correctly prevent users from making trait objects
 // from traits with static methods.
+//
+// revisions: curr object_safe_for_dispatch
+
+#![cfg_attr(object_safe_for_dispatch, feature(object_safe_for_dispatch))]
 
 trait Foo {
-    fn foo();
+    fn foo() {}
 }
 
-fn foo_implicit<T:Foo+'static>(b: Box<T>) -> Box<dyn Foo + 'static> {
-    //~^ ERROR E0038
+fn diverges() -> Box<dyn Foo> {
+    //[curr]~^ ERROR E0038
     loop { }
 }
 
+struct Bar;
+
+impl Foo for Bar {}
+
 fn main() {
+    let b: Box<dyn Foo> = Box::new(Bar);
+    //[object_safe_for_dispatch]~^ ERROR E0038
 }
diff --git a/src/test/ui/object-safety/object-safety-sized-2.stderr b/src/test/ui/object-safety/object-safety-sized-2.curr.stderr
index dcaf2ff0bc2..1e1d2bf64c4 100644
--- a/src/test/ui/object-safety/object-safety-sized-2.stderr
+++ b/src/test/ui/object-safety/object-safety-sized-2.curr.stderr
@@ -1,5 +1,5 @@
 error[E0038]: the trait `Bar` cannot be made into an object
-  --> $DIR/object-safety-sized-2.rs:10:1
+  --> $DIR/object-safety-sized-2.rs:14:1
    |
 LL | fn make_bar<T:Bar>(t: &T) -> &dyn Bar {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Bar` cannot be made into an object
diff --git a/src/test/ui/object-safety/object-safety-sized-2.object_safe_for_dispatch.stderr b/src/test/ui/object-safety/object-safety-sized-2.object_safe_for_dispatch.stderr
new file mode 100644
index 00000000000..06ecfd019c8
--- /dev/null
+++ b/src/test/ui/object-safety/object-safety-sized-2.object_safe_for_dispatch.stderr
@@ -0,0 +1,13 @@
+error[E0038]: the trait `Bar` cannot be made into an object
+  --> $DIR/object-safety-sized-2.rs:16:5
+   |
+LL |     t
+   |     ^ the trait `Bar` cannot be made into an object
+   |
+   = note: the trait cannot require that `Self : Sized`
+   = note: required because of the requirements on the impl of `std::ops::CoerceUnsized<&dyn Bar>` for `&T`
+   = note: required by cast to type `&dyn Bar`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0038`.
diff --git a/src/test/ui/object-safety/object-safety-sized-2.rs b/src/test/ui/object-safety/object-safety-sized-2.rs
index 7235b22404e..1e79b8cd917 100644
--- a/src/test/ui/object-safety/object-safety-sized-2.rs
+++ b/src/test/ui/object-safety/object-safety-sized-2.rs
@@ -1,5 +1,9 @@
 // Check that we correctly prevent users from making trait objects
 // from traits where `Self : Sized`.
+//
+// revisions: curr object_safe_for_dispatch
+
+#![cfg_attr(object_safe_for_dispatch, feature(object_safe_for_dispatch))]
 
 trait Bar
     where Self : Sized
@@ -8,8 +12,9 @@ trait Bar
 }
 
 fn make_bar<T:Bar>(t: &T) -> &dyn Bar {
-        //~^ ERROR E0038
-    loop { }
+    //[curr]~^ ERROR E0038
+    t
+    //[object_safe_for_dispatch]~^ ERROR E0038
 }
 
 fn main() {
diff --git a/src/test/ui/object-safety/object-safety-sized.stderr b/src/test/ui/object-safety/object-safety-sized.curr.stderr
index 98bc73e38d4..1a67e79e83d 100644
--- a/src/test/ui/object-safety/object-safety-sized.stderr
+++ b/src/test/ui/object-safety/object-safety-sized.curr.stderr
@@ -1,5 +1,5 @@
 error[E0038]: the trait `Bar` cannot be made into an object
-  --> $DIR/object-safety-sized.rs:8:1
+  --> $DIR/object-safety-sized.rs:12:1
    |
 LL | fn make_bar<T:Bar>(t: &T) -> &dyn Bar {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Bar` cannot be made into an object
diff --git a/src/test/ui/object-safety/object-safety-sized.object_safe_for_dispatch.stderr b/src/test/ui/object-safety/object-safety-sized.object_safe_for_dispatch.stderr
new file mode 100644
index 00000000000..3d88dfc40ed
--- /dev/null
+++ b/src/test/ui/object-safety/object-safety-sized.object_safe_for_dispatch.stderr
@@ -0,0 +1,13 @@
+error[E0038]: the trait `Bar` cannot be made into an object
+  --> $DIR/object-safety-sized.rs:14:5
+   |
+LL |     t
+   |     ^ the trait `Bar` cannot be made into an object
+   |
+   = note: the trait cannot require that `Self : Sized`
+   = note: required because of the requirements on the impl of `std::ops::CoerceUnsized<&dyn Bar>` for `&T`
+   = note: required by cast to type `&dyn Bar`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0038`.
diff --git a/src/test/ui/object-safety/object-safety-sized.rs b/src/test/ui/object-safety/object-safety-sized.rs
index 1312bb34717..b424b892d3b 100644
--- a/src/test/ui/object-safety/object-safety-sized.rs
+++ b/src/test/ui/object-safety/object-safety-sized.rs
@@ -1,13 +1,18 @@
 // Check that we correctly prevent users from making trait objects
 // from traits where `Self : Sized`.
+//
+// revisions: curr object_safe_for_dispatch
+
+#![cfg_attr(object_safe_for_dispatch, feature(object_safe_for_dispatch))]
 
 trait Bar : Sized {
     fn bar<T>(&self, t: T);
 }
 
 fn make_bar<T:Bar>(t: &T) -> &dyn Bar {
-        //~^ ERROR E0038
+    //[curr]~^ ERROR E0038
     t
+    //[object_safe_for_dispatch]~^ ERROR E0038
 }
 
 fn main() {
diff --git a/src/test/ui/rfc-2027-object-safe-for-dispatch/downcast-unsafe-trait-objects.rs b/src/test/ui/rfc-2027-object-safe-for-dispatch/downcast-unsafe-trait-objects.rs
new file mode 100644
index 00000000000..fa04f4b12d5
--- /dev/null
+++ b/src/test/ui/rfc-2027-object-safe-for-dispatch/downcast-unsafe-trait-objects.rs
@@ -0,0 +1,23 @@
+// Check that we if we get ahold of an object unsafe trait
+// object with auto traits and lifetimes, we can downcast it
+//
+// check-pass
+
+#![feature(object_safe_for_dispatch)]
+
+trait Trait: Sized {}
+
+fn downcast_auto(t: &(dyn Trait + Send)) -> &dyn Trait {
+    t
+}
+
+fn downcast_lifetime<'a, 'b, 't>(t: &'a (dyn Trait + 't))
+                                 -> &'b (dyn Trait + 't)
+where
+    'a: 'b,
+    't: 'a + 'b,
+{
+    t
+}
+
+fn main() {}
diff --git a/src/test/ui/rfc-2027-object-safe-for-dispatch/manual-self-impl-for-unsafe-obj.rs b/src/test/ui/rfc-2027-object-safe-for-dispatch/manual-self-impl-for-unsafe-obj.rs
new file mode 100644
index 00000000000..1dea4012265
--- /dev/null
+++ b/src/test/ui/rfc-2027-object-safe-for-dispatch/manual-self-impl-for-unsafe-obj.rs
@@ -0,0 +1,69 @@
+// Check that we can manually implement an object
+// unsafe trait for its trait object
+//
+// run-pass
+
+#![feature(object_safe_for_dispatch)]
+
+trait Bad {
+    fn stat() -> char {
+        'A'
+    }
+    fn virt(&self) -> char {
+        'B'
+    }
+    fn indirect(&self) -> char {
+        Self::stat()
+    }
+}
+
+trait Good {
+    fn good_virt(&self) -> char {
+        panic!()
+    }
+    fn good_indirect(&self) -> char {
+        panic!()
+    }
+}
+
+impl<'a> Bad for dyn Bad + 'a {
+    fn stat() -> char {
+        'C'
+    }
+    fn virt(&self) -> char {
+        'D'
+    }
+}
+
+struct Struct {}
+
+impl Bad for Struct {}
+
+impl Good for Struct {}
+
+fn main() {
+    let s = Struct {};
+
+    let mut res = String::new();
+
+    // Directly call static
+    res.push(Struct::stat()); // "A"
+    res.push(<dyn Bad>::stat()); // "AC"
+
+    let good: &dyn Good = &s;
+
+    // These look similar enough...
+    let bad = unsafe { std::mem::transmute::<&dyn Good, &dyn Bad>(good) };
+
+    // Call virtual
+    res.push(s.virt()); // "ACB"
+    res.push(bad.virt()); // "ACBD"
+
+    // Indirectly call static
+    res.push(s.indirect()); // "ACBDA"
+    res.push(bad.indirect()); // "ACBDAC"
+
+    if &res != "ACBDAC" {
+        panic!();
+    }
+}
diff --git a/src/test/ui/rfc-2027-object-safe-for-dispatch/static-dispatch-unsafe-object.rs b/src/test/ui/rfc-2027-object-safe-for-dispatch/static-dispatch-unsafe-object.rs
new file mode 100644
index 00000000000..df97d2c1327
--- /dev/null
+++ b/src/test/ui/rfc-2027-object-safe-for-dispatch/static-dispatch-unsafe-object.rs
@@ -0,0 +1,37 @@
+// Check that we can statically dispatch methods for object
+// unsafe trait objects, directly and indirectly
+//
+// check-pass
+
+#![feature(object_safe_for_dispatch)]
+
+trait Statics {
+    fn plain() {}
+    fn generic<T>() {}
+}
+
+trait Trait: Sized {}
+
+impl<'a> Statics for dyn Trait + 'a {}
+
+fn static_poly<T: Statics + ?Sized>() {
+    T::plain();
+    T::generic::<usize>();
+}
+
+fn inferred_poly<T: Statics + ?Sized>(t: &T) {
+    static_poly::<T>();
+    T::plain();
+    T::generic::<usize>();
+}
+
+fn call(t: &dyn Trait) {
+    static_poly::<dyn Trait>();
+    inferred_poly(t);
+}
+
+fn main() {
+    static_poly::<dyn Trait>();
+    <dyn Trait>::plain();
+    <dyn Trait>::generic::<usize>()
+}
diff --git a/src/test/ui/self/arbitrary-self-types-not-object-safe.curr.stderr b/src/test/ui/self/arbitrary-self-types-not-object-safe.curr.stderr
new file mode 100644
index 00000000000..cdffc1d86ed
--- /dev/null
+++ b/src/test/ui/self/arbitrary-self-types-not-object-safe.curr.stderr
@@ -0,0 +1,24 @@
+error[E0038]: the trait `Foo` cannot be made into an object
+  --> $DIR/arbitrary-self-types-not-object-safe.rs:34:32
+   |
+LL |     fn foo(self: &Rc<Self>) -> usize;
+   |        --- method `foo`'s `self` parameter cannot be dispatched on
+...
+LL |     let x = Rc::new(5usize) as Rc<dyn Foo>;
+   |                                ^^^^^^^^^^^ the trait `Foo` cannot be made into an object
+
+error[E0038]: the trait `Foo` cannot be made into an object
+  --> $DIR/arbitrary-self-types-not-object-safe.rs:34:13
+   |
+LL |     fn foo(self: &Rc<Self>) -> usize;
+   |        --- method `foo`'s `self` parameter cannot be dispatched on
+...
+LL |     let x = Rc::new(5usize) as Rc<dyn Foo>;
+   |             ^^^^^^^^^^^^^^^ the trait `Foo` cannot be made into an object
+   |
+   = note: required because of the requirements on the impl of `std::ops::CoerceUnsized<std::rc::Rc<dyn Foo>>` for `std::rc::Rc<usize>`
+   = note: required by cast to type `std::rc::Rc<dyn Foo>`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0038`.
diff --git a/src/test/ui/self/arbitrary-self-types-not-object-safe.object_safe_for_dispatch.stderr b/src/test/ui/self/arbitrary-self-types-not-object-safe.object_safe_for_dispatch.stderr
new file mode 100644
index 00000000000..725632a1212
--- /dev/null
+++ b/src/test/ui/self/arbitrary-self-types-not-object-safe.object_safe_for_dispatch.stderr
@@ -0,0 +1,15 @@
+error[E0038]: the trait `Foo` cannot be made into an object
+  --> $DIR/arbitrary-self-types-not-object-safe.rs:34:13
+   |
+LL |     fn foo(self: &Rc<Self>) -> usize;
+   |        --- method `foo`'s `self` parameter cannot be dispatched on
+...
+LL |     let x = Rc::new(5usize) as Rc<dyn Foo>;
+   |             ^^^^^^^^^^^^^^^ the trait `Foo` cannot be made into an object
+   |
+   = note: required because of the requirements on the impl of `std::ops::CoerceUnsized<std::rc::Rc<dyn Foo>>` for `std::rc::Rc<usize>`
+   = note: required by cast to type `std::rc::Rc<dyn Foo>`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0038`.
diff --git a/src/test/ui/self/arbitrary-self-types-not-object-safe.rs b/src/test/ui/self/arbitrary-self-types-not-object-safe.rs
index 7443d888c9e..2eeabad28db 100644
--- a/src/test/ui/self/arbitrary-self-types-not-object-safe.rs
+++ b/src/test/ui/self/arbitrary-self-types-not-object-safe.rs
@@ -1,3 +1,6 @@
+// revisions: curr object_safe_for_dispatch
+
+#![cfg_attr(object_safe_for_dispatch, feature(object_safe_for_dispatch))]
 #![feature(arbitrary_self_types)]
 
 use std::rc::Rc;
@@ -29,8 +32,9 @@ impl Bar for usize {
 
 fn make_foo() {
     let x = Rc::new(5usize) as Rc<dyn Foo>;
-    //~^ ERROR E0038
-    //~| ERROR E0038
+    //[curr]~^ ERROR E0038
+    //[curr]~| ERROR E0038
+    //[object_safe_for_dispatch]~^^^ ERROR E0038
 }
 
 fn make_bar() {
diff --git a/src/test/ui/traits/trait-object-safety.stderr b/src/test/ui/traits/trait-object-safety.stderr
index 3ac1e96b30c..028e9eedd64 100644
--- a/src/test/ui/traits/trait-object-safety.stderr
+++ b/src/test/ui/traits/trait-object-safety.stderr
@@ -8,6 +8,7 @@ LL |     let _: &dyn Tr = &St;
    |                      ^^^ the trait `Tr` cannot be made into an object
    |
    = note: required because of the requirements on the impl of `std::ops::CoerceUnsized<&dyn Tr>` for `&St`
+   = note: required by cast to type `&dyn Tr`
 
 error[E0038]: the trait `Tr` cannot be made into an object
   --> $DIR/trait-object-safety.rs:15:12
diff --git a/src/test/ui/traits/trait-test-2.stderr b/src/test/ui/traits/trait-test-2.stderr
index 83c2c065274..9b750d382ec 100644
--- a/src/test/ui/traits/trait-test-2.stderr
+++ b/src/test/ui/traits/trait-test-2.stderr
@@ -33,6 +33,7 @@ LL |     (box 10 as Box<dyn bar>).dup();
    |      ^^^^^^ the trait `bar` cannot be made into an object
    |
    = note: required because of the requirements on the impl of `std::ops::CoerceUnsized<std::boxed::Box<dyn bar>>` for `std::boxed::Box<{integer}>`
+   = note: required by cast to type `std::boxed::Box<dyn bar>`
 
 error: aborting due to 4 previous errors
 
diff --git a/src/test/ui/wf/wf-convert-unsafe-trait-obj-box.rs b/src/test/ui/wf/wf-convert-unsafe-trait-obj-box.rs
new file mode 100644
index 00000000000..ffdb49a3be5
--- /dev/null
+++ b/src/test/ui/wf/wf-convert-unsafe-trait-obj-box.rs
@@ -0,0 +1,18 @@
+// Check that we do not allow casts or coercions
+// to object unsafe trait objects inside a Box
+
+#![feature(object_safe_for_dispatch)]
+
+trait Trait: Sized {}
+
+struct S;
+
+impl Trait for S {}
+
+fn takes_box(t: Box<dyn Trait>) {}
+
+fn main() {
+    Box::new(S) as Box<dyn Trait>; //~ ERROR E0038
+    let t_box: Box<dyn Trait> = Box::new(S); //~ ERROR E0038
+    takes_box(Box::new(S)); //~ ERROR E0038
+}
diff --git a/src/test/ui/wf/wf-convert-unsafe-trait-obj-box.stderr b/src/test/ui/wf/wf-convert-unsafe-trait-obj-box.stderr
new file mode 100644
index 00000000000..0b63aef2bce
--- /dev/null
+++ b/src/test/ui/wf/wf-convert-unsafe-trait-obj-box.stderr
@@ -0,0 +1,33 @@
+error[E0038]: the trait `Trait` cannot be made into an object
+  --> $DIR/wf-convert-unsafe-trait-obj-box.rs:16:33
+   |
+LL |     let t_box: Box<dyn Trait> = Box::new(S);
+   |                                 ^^^^^^^^^^^ the trait `Trait` cannot be made into an object
+   |
+   = note: the trait cannot require that `Self : Sized`
+   = note: required because of the requirements on the impl of `std::ops::CoerceUnsized<std::boxed::Box<dyn Trait>>` for `std::boxed::Box<S>`
+   = note: required by cast to type `std::boxed::Box<dyn Trait>`
+
+error[E0038]: the trait `Trait` cannot be made into an object
+  --> $DIR/wf-convert-unsafe-trait-obj-box.rs:17:15
+   |
+LL |     takes_box(Box::new(S));
+   |               ^^^^^^^^^^^ the trait `Trait` cannot be made into an object
+   |
+   = note: the trait cannot require that `Self : Sized`
+   = note: required because of the requirements on the impl of `std::ops::CoerceUnsized<std::boxed::Box<dyn Trait>>` for `std::boxed::Box<S>`
+   = note: required by cast to type `std::boxed::Box<(dyn Trait + 'static)>`
+
+error[E0038]: the trait `Trait` cannot be made into an object
+  --> $DIR/wf-convert-unsafe-trait-obj-box.rs:15:5
+   |
+LL |     Box::new(S) as Box<dyn Trait>;
+   |     ^^^^^^^^^^^ the trait `Trait` cannot be made into an object
+   |
+   = note: the trait cannot require that `Self : Sized`
+   = note: required because of the requirements on the impl of `std::ops::CoerceUnsized<std::boxed::Box<dyn Trait>>` for `std::boxed::Box<S>`
+   = note: required by cast to type `std::boxed::Box<dyn Trait>`
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0038`.
diff --git a/src/test/ui/wf/wf-convert-unsafe-trait-obj.rs b/src/test/ui/wf/wf-convert-unsafe-trait-obj.rs
new file mode 100644
index 00000000000..143b854ed6b
--- /dev/null
+++ b/src/test/ui/wf/wf-convert-unsafe-trait-obj.rs
@@ -0,0 +1,18 @@
+// Check that we do not allow casts or coercions
+// to object unsafe trait objects by ref
+
+#![feature(object_safe_for_dispatch)]
+
+trait Trait: Sized {}
+
+struct S;
+
+impl Trait for S {}
+
+fn takes_trait(t: &dyn Trait) {}
+
+fn main() {
+    &S as &dyn Trait; //~ ERROR E0038
+    let t: &dyn Trait = &S; //~ ERROR E0038
+    takes_trait(&S); //~ ERROR E0038
+}
diff --git a/src/test/ui/wf/wf-convert-unsafe-trait-obj.stderr b/src/test/ui/wf/wf-convert-unsafe-trait-obj.stderr
new file mode 100644
index 00000000000..7aeefd731fb
--- /dev/null
+++ b/src/test/ui/wf/wf-convert-unsafe-trait-obj.stderr
@@ -0,0 +1,33 @@
+error[E0038]: the trait `Trait` cannot be made into an object
+  --> $DIR/wf-convert-unsafe-trait-obj.rs:16:25
+   |
+LL |     let t: &dyn Trait = &S;
+   |                         ^^ the trait `Trait` cannot be made into an object
+   |
+   = note: the trait cannot require that `Self : Sized`
+   = note: required because of the requirements on the impl of `std::ops::CoerceUnsized<&dyn Trait>` for `&S`
+   = note: required by cast to type `&dyn Trait`
+
+error[E0038]: the trait `Trait` cannot be made into an object
+  --> $DIR/wf-convert-unsafe-trait-obj.rs:17:17
+   |
+LL |     takes_trait(&S);
+   |                 ^^ the trait `Trait` cannot be made into an object
+   |
+   = note: the trait cannot require that `Self : Sized`
+   = note: required because of the requirements on the impl of `std::ops::CoerceUnsized<&dyn Trait>` for `&S`
+   = note: required by cast to type `&dyn Trait`
+
+error[E0038]: the trait `Trait` cannot be made into an object
+  --> $DIR/wf-convert-unsafe-trait-obj.rs:15:5
+   |
+LL |     &S as &dyn Trait;
+   |     ^^ the trait `Trait` cannot be made into an object
+   |
+   = note: the trait cannot require that `Self : Sized`
+   = note: required because of the requirements on the impl of `std::ops::CoerceUnsized<&dyn Trait>` for `&S`
+   = note: required by cast to type `&dyn Trait`
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0038`.
diff --git a/src/test/ui/wf/wf-unsafe-trait-obj-match.rs b/src/test/ui/wf/wf-unsafe-trait-obj-match.rs
new file mode 100644
index 00000000000..c8731a8ecaf
--- /dev/null
+++ b/src/test/ui/wf/wf-unsafe-trait-obj-match.rs
@@ -0,0 +1,29 @@
+// Check that we do not allow coercions to object
+// unsafe trait objects in match arms
+
+#![feature(object_safe_for_dispatch)]
+
+trait Trait: Sized {}
+
+struct S;
+
+impl Trait for S {}
+
+struct R;
+
+impl Trait for R {}
+
+fn opt() -> Option<()> {
+    Some(())
+}
+
+fn main() {
+    match opt() {
+        Some(()) => &S,
+        None => &R,  //~ ERROR E0308
+    }
+    let t: &dyn Trait = match opt() { //~ ERROR E0038
+        Some(()) => &S, //~ ERROR E0038
+        None => &R,
+    };
+}
diff --git a/src/test/ui/wf/wf-unsafe-trait-obj-match.stderr b/src/test/ui/wf/wf-unsafe-trait-obj-match.stderr
new file mode 100644
index 00000000000..185b1e6c36b
--- /dev/null
+++ b/src/test/ui/wf/wf-unsafe-trait-obj-match.stderr
@@ -0,0 +1,38 @@
+error[E0308]: match arms have incompatible types
+  --> $DIR/wf-unsafe-trait-obj-match.rs:23:17
+   |
+LL | /     match opt() {
+LL | |         Some(()) => &S,
+   | |                     -- this is found to be of type `&S`
+LL | |         None => &R,
+   | |                 ^^ expected struct `S`, found struct `R`
+LL | |     }
+   | |_____- `match` arms have incompatible types
+   |
+   = note: expected type `&S`
+              found type `&R`
+
+error[E0038]: the trait `Trait` cannot be made into an object
+  --> $DIR/wf-unsafe-trait-obj-match.rs:26:21
+   |
+LL |         Some(()) => &S,
+   |                     ^^ the trait `Trait` cannot be made into an object
+   |
+   = note: the trait cannot require that `Self : Sized`
+   = note: required because of the requirements on the impl of `std::ops::CoerceUnsized<&dyn Trait>` for `&S`
+   = note: required by cast to type `&dyn Trait`
+
+error[E0038]: the trait `Trait` cannot be made into an object
+  --> $DIR/wf-unsafe-trait-obj-match.rs:25:25
+   |
+LL |     let t: &dyn Trait = match opt() {
+   |                         ^^^^^^^^^^^ the trait `Trait` cannot be made into an object
+   |
+   = note: the trait cannot require that `Self : Sized`
+   = note: required because of the requirements on the impl of `std::ops::CoerceUnsized<&dyn Trait>` for `&R`
+   = note: required by cast to type `&dyn Trait`
+
+error: aborting due to 3 previous errors
+
+Some errors have detailed explanations: E0038, E0308.
+For more information about an error, try `rustc --explain E0038`.