about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2019-01-05 03:36:31 +0000
committerbors <bors@rust-lang.org>2019-01-05 03:36:31 +0000
commit2fba17fc972f89fe9165fbed77d2f0ad6d3e2174 (patch)
tree4d53cc7f637ccfb8c21ea5c1c113907d96694749 /src
parent244b05db12e47efef4695036974bc25fde13b828 (diff)
parentc213b0db2e8e344c419095450dbbdae71afa8c61 (diff)
downloadrust-2fba17fc972f89fe9165fbed77d2f0ad6d3e2174.tar.gz
rust-2fba17fc972f89fe9165fbed77d2f0ad6d3e2174.zip
Auto merge of #56837 - arielb1:nonprincipal-trait-objects, r=nikomatsakis
Add support for trait-objects without a principal

The hard-error version of #56481 - should be merged after we do something about the `traitobject` crate.

Fixes #33140.
Fixes #57057.

r? @nikomatsakis
Diffstat (limited to 'src')
-rw-r--r--src/librustc/dep_graph/dep_node.rs1
-rw-r--r--src/librustc/infer/combine.rs4
-rw-r--r--src/librustc/infer/equate.rs4
-rw-r--r--src/librustc/infer/glb.rs6
-rw-r--r--src/librustc/infer/lub.rs6
-rw-r--r--src/librustc/infer/mod.rs19
-rw-r--r--src/librustc/infer/nll_relate/mod.rs14
-rw-r--r--src/librustc/infer/sub.rs6
-rw-r--r--src/librustc/traits/coherence.rs20
-rw-r--r--src/librustc/traits/error_reporting.rs2
-rw-r--r--src/librustc/traits/select.rs36
-rw-r--r--src/librustc/traits/specialize/mod.rs3
-rw-r--r--src/librustc/traits/specialize/specialization_graph.rs40
-rw-r--r--src/librustc/ty/_match.rs13
-rw-r--r--src/librustc/ty/error.rs6
-rw-r--r--src/librustc/ty/fast_reject.rs12
-rw-r--r--src/librustc/ty/item_path.rs2
-rw-r--r--src/librustc/ty/mod.rs122
-rw-r--r--src/librustc/ty/query/mod.rs2
-rw-r--r--src/librustc/ty/query/plumbing.rs1
-rw-r--r--src/librustc/ty/relate.rs49
-rw-r--r--src/librustc/ty/sty.rs47
-rw-r--r--src/librustc/ty/wf.rs2
-rw-r--r--src/librustc/util/ppaux.rs48
-rw-r--r--src/librustc_codegen_llvm/context.rs5
-rw-r--r--src/librustc_codegen_llvm/debuginfo/metadata.rs3
-rw-r--r--src/librustc_codegen_llvm/debuginfo/type_names.rs16
-rw-r--r--src/librustc_codegen_ssa/meth.rs13
-rw-r--r--src/librustc_codegen_ssa/traits/misc.rs2
-rw-r--r--src/librustc_mir/interpret/eval_context.rs2
-rw-r--r--src/librustc_mir/interpret/traits.rs13
-rw-r--r--src/librustc_mir/monomorphize/collector.rs23
-rw-r--r--src/librustc_mir/monomorphize/item.rs17
-rw-r--r--src/librustc_traits/chalk_context/resolvent_ops.rs6
-rw-r--r--src/librustc_typeck/astconv.rs8
-rw-r--r--src/librustc_typeck/check/cast.rs4
-rw-r--r--src/librustc_typeck/check/closure.rs4
-rw-r--r--src/librustc_typeck/check/method/confirm.rs6
-rw-r--r--src/librustc_typeck/check/method/probe.rs33
-rw-r--r--src/librustc_typeck/check/method/suggest.rs3
-rw-r--r--src/librustc_typeck/coherence/inherent_impls.rs4
-rw-r--r--src/librustc_typeck/coherence/inherent_impls_overlap.rs105
-rw-r--r--src/librustc_typeck/coherence/mod.rs39
-rw-r--r--src/librustc_typeck/collect.rs8
-rw-r--r--src/librustc_typeck/outlives/implicit_infer.rs43
-rw-r--r--src/librustc_typeck/variance/constraints.rs11
-rw-r--r--src/librustdoc/clean/mod.rs19
-rw-r--r--src/test/run-pass/issues/issue-33140.rs47
-rw-r--r--src/test/run-pass/traits/principal-less-trait-objects.rs41
-rw-r--r--src/test/ui/issues/issue-33140-hack-boundaries.rs80
-rw-r--r--src/test/ui/issues/issue-33140-hack-boundaries.stderr67
-rw-r--r--src/test/ui/issues/issue-33140-traitobject-crate.rs101
-rw-r--r--src/test/ui/issues/issue-33140-traitobject-crate.stderr39
-rw-r--r--src/test/ui/issues/issue-33140.rs5
-rw-r--r--src/test/ui/issues/issue-33140.stderr29
-rw-r--r--src/test/ui/issues/issue-57162.rs7
56 files changed, 815 insertions, 453 deletions
diff --git a/src/librustc/dep_graph/dep_node.rs b/src/librustc/dep_graph/dep_node.rs
index 070551c0b7b..3156f17e0c4 100644
--- a/src/librustc/dep_graph/dep_node.rs
+++ b/src/librustc/dep_graph/dep_node.rs
@@ -492,6 +492,7 @@ define_dep_nodes!( <'tcx>
     [] AdtDefOfItem(DefId),
     [] ImplTraitRef(DefId),
     [] ImplPolarity(DefId),
+    [] Issue33140SelfTy(DefId),
     [] FnSignature(DefId),
     [] CoerceUnsizedInfo(DefId),
 
diff --git a/src/librustc/infer/combine.rs b/src/librustc/infer/combine.rs
index ed251d81e62..40c11695d51 100644
--- a/src/librustc/infer/combine.rs
+++ b/src/librustc/infer/combine.rs
@@ -337,10 +337,6 @@ impl<'cx, 'gcx, 'tcx> TypeRelation<'cx, 'gcx, 'tcx> for Generalizer<'cx, 'gcx, '
         self.infcx.tcx
     }
 
-    fn trait_object_mode(&self) -> relate::TraitObjectMode {
-        self.infcx.trait_object_mode()
-    }
-
     fn tag(&self) -> &'static str {
         "Generalizer"
     }
diff --git a/src/librustc/infer/equate.rs b/src/librustc/infer/equate.rs
index 38d3258d140..60a7eb0d54f 100644
--- a/src/librustc/infer/equate.rs
+++ b/src/librustc/infer/equate.rs
@@ -29,10 +29,6 @@ impl<'combine, 'infcx, 'gcx, 'tcx> TypeRelation<'infcx, 'gcx, 'tcx>
 
     fn tcx(&self) -> TyCtxt<'infcx, 'gcx, 'tcx> { self.fields.tcx() }
 
-    fn trait_object_mode(&self) -> relate::TraitObjectMode {
-        self.fields.infcx.trait_object_mode()
-    }
-
     fn a_is_expected(&self) -> bool { self.a_is_expected }
 
     fn relate_item_substs(&mut self,
diff --git a/src/librustc/infer/glb.rs b/src/librustc/infer/glb.rs
index aebacd28f45..635a6d00270 100644
--- a/src/librustc/infer/glb.rs
+++ b/src/librustc/infer/glb.rs
@@ -5,7 +5,7 @@ use super::Subtype;
 
 use traits::ObligationCause;
 use ty::{self, Ty, TyCtxt};
-use ty::relate::{self, Relate, RelateResult, TypeRelation};
+use ty::relate::{Relate, RelateResult, TypeRelation};
 
 /// "Greatest lower bound" (common subtype)
 pub struct Glb<'combine, 'infcx: 'combine, 'gcx: 'infcx+'tcx, 'tcx: 'infcx> {
@@ -26,10 +26,6 @@ impl<'combine, 'infcx, 'gcx, 'tcx> TypeRelation<'infcx, 'gcx, 'tcx>
 {
     fn tag(&self) -> &'static str { "Glb" }
 
-    fn trait_object_mode(&self) -> relate::TraitObjectMode {
-        self.fields.infcx.trait_object_mode()
-    }
-
     fn tcx(&self) -> TyCtxt<'infcx, 'gcx, 'tcx> { self.fields.tcx() }
 
     fn a_is_expected(&self) -> bool { self.a_is_expected }
diff --git a/src/librustc/infer/lub.rs b/src/librustc/infer/lub.rs
index c6af8e49671..0b9839f69fa 100644
--- a/src/librustc/infer/lub.rs
+++ b/src/librustc/infer/lub.rs
@@ -5,7 +5,7 @@ use super::Subtype;
 
 use traits::ObligationCause;
 use ty::{self, Ty, TyCtxt};
-use ty::relate::{self, Relate, RelateResult, TypeRelation};
+use ty::relate::{Relate, RelateResult, TypeRelation};
 
 /// "Least upper bound" (common supertype)
 pub struct Lub<'combine, 'infcx: 'combine, 'gcx: 'infcx+'tcx, 'tcx: 'infcx> {
@@ -26,10 +26,6 @@ impl<'combine, 'infcx, 'gcx, 'tcx> TypeRelation<'infcx, 'gcx, 'tcx>
 {
     fn tag(&self) -> &'static str { "Lub" }
 
-    fn trait_object_mode(&self) -> relate::TraitObjectMode {
-        self.fields.infcx.trait_object_mode()
-    }
-
     fn tcx(&self) -> TyCtxt<'infcx, 'gcx, 'tcx> { self.fields.tcx() }
 
     fn a_is_expected(&self) -> bool { self.a_is_expected }
diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs
index 2d3fb137faf..95898254575 100644
--- a/src/librustc/infer/mod.rs
+++ b/src/librustc/infer/mod.rs
@@ -25,7 +25,7 @@ use syntax_pos::{self, Span};
 use traits::{self, ObligationCause, PredicateObligations, TraitEngine};
 use ty::error::{ExpectedFound, TypeError, UnconstrainedNumeric};
 use ty::fold::TypeFoldable;
-use ty::relate::{RelateResult, TraitObjectMode};
+use ty::relate::RelateResult;
 use ty::subst::{Kind, Substs};
 use ty::{self, GenericParamDefKind, Ty, TyCtxt, CtxtInterners};
 use ty::{FloatVid, IntVid, TyVid};
@@ -171,9 +171,6 @@ pub struct InferCtxt<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> {
     // This flag is true while there is an active snapshot.
     in_snapshot: Cell<bool>,
 
-    // The TraitObjectMode used here,
-    trait_object_mode: TraitObjectMode,
-
     // A set of constraints that regionck must validate. Each
     // constraint has the form `T:'a`, meaning "some type `T` must
     // outlive the lifetime 'a". These constraints derive from
@@ -465,7 +462,6 @@ pub struct InferCtxtBuilder<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> {
     arena: SyncDroplessArena,
     interners: Option<CtxtInterners<'tcx>>,
     fresh_tables: Option<RefCell<ty::TypeckTables<'tcx>>>,
-    trait_object_mode: TraitObjectMode,
 }
 
 impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'gcx> {
@@ -475,7 +471,6 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'gcx> {
             arena: SyncDroplessArena::default(),
             interners: None,
             fresh_tables: None,
-            trait_object_mode: TraitObjectMode::NoSquash,
         }
     }
 }
@@ -488,12 +483,6 @@ impl<'a, 'gcx, 'tcx> InferCtxtBuilder<'a, 'gcx, 'tcx> {
         self
     }
 
-    pub fn with_trait_object_mode(mut self, mode: TraitObjectMode) -> Self {
-        debug!("with_trait_object_mode: setting mode to {:?}", mode);
-        self.trait_object_mode = mode;
-        self
-    }
-
     /// Given a canonical value `C` as a starting point, create an
     /// inference context that contains each of the bound values
     /// within instantiated as a fresh variable. The `f` closure is
@@ -520,7 +509,6 @@ impl<'a, 'gcx, 'tcx> InferCtxtBuilder<'a, 'gcx, 'tcx> {
     pub fn enter<R>(&'tcx mut self, f: impl for<'b> FnOnce(InferCtxt<'b, 'gcx, 'tcx>) -> R) -> R {
         let InferCtxtBuilder {
             global_tcx,
-            trait_object_mode,
             ref arena,
             ref mut interners,
             ref fresh_tables,
@@ -532,7 +520,6 @@ impl<'a, 'gcx, 'tcx> InferCtxtBuilder<'a, 'gcx, 'tcx> {
             f(InferCtxt {
                 tcx,
                 in_progress_tables,
-                trait_object_mode,
                 projection_cache: Default::default(),
                 type_variables: RefCell::new(type_variable::TypeVariableTable::new()),
                 int_unification_table: RefCell::new(ut::UnificationTable::new()),
@@ -614,10 +601,6 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
         self.in_snapshot.get()
     }
 
-    pub fn trait_object_mode(&self) -> TraitObjectMode {
-        self.trait_object_mode
-    }
-
     pub fn freshen<T: TypeFoldable<'tcx>>(&self, t: T) -> T {
         t.fold_with(&mut self.freshener())
     }
diff --git a/src/librustc/infer/nll_relate/mod.rs b/src/librustc/infer/nll_relate/mod.rs
index db5ec3c1c0c..7671a471357 100644
--- a/src/librustc/infer/nll_relate/mod.rs
+++ b/src/librustc/infer/nll_relate/mod.rs
@@ -372,13 +372,6 @@ where
         self.infcx.tcx
     }
 
-    fn trait_object_mode(&self) -> relate::TraitObjectMode {
-        // squashing should only be done in coherence, not NLL
-        assert_eq!(self.infcx.trait_object_mode(),
-                   relate::TraitObjectMode::NoSquash);
-        relate::TraitObjectMode::NoSquash
-    }
-
     fn tag(&self) -> &'static str {
         "nll::subtype"
     }
@@ -693,13 +686,6 @@ where
         self.infcx.tcx
     }
 
-    fn trait_object_mode(&self) -> relate::TraitObjectMode {
-        // squashing should only be done in coherence, not NLL
-        assert_eq!(self.infcx.trait_object_mode(),
-                   relate::TraitObjectMode::NoSquash);
-        relate::TraitObjectMode::NoSquash
-    }
-
     fn tag(&self) -> &'static str {
         "nll::generalizer"
     }
diff --git a/src/librustc/infer/sub.rs b/src/librustc/infer/sub.rs
index 1d4842a6d56..df76d1d3afb 100644
--- a/src/librustc/infer/sub.rs
+++ b/src/librustc/infer/sub.rs
@@ -5,7 +5,7 @@ use traits::Obligation;
 use ty::{self, Ty, TyCtxt};
 use ty::TyVar;
 use ty::fold::TypeFoldable;
-use ty::relate::{self, Cause, Relate, RelateResult, TypeRelation};
+use ty::relate::{Cause, Relate, RelateResult, TypeRelation};
 use std::mem;
 
 /// Ensures `a` is made a subtype of `b`. Returns `a` on success.
@@ -33,10 +33,6 @@ impl<'combine, 'infcx, 'gcx, 'tcx> TypeRelation<'infcx, 'gcx, 'tcx>
     for Sub<'combine, 'infcx, 'gcx, 'tcx>
 {
     fn tag(&self) -> &'static str { "Sub" }
-    fn trait_object_mode(&self) -> relate::TraitObjectMode {
-        self.fields.infcx.trait_object_mode()
-    }
-
     fn tcx(&self) -> TyCtxt<'infcx, 'gcx, 'tcx> { self.fields.infcx.tcx }
     fn a_is_expected(&self) -> bool { self.a_is_expected }
 
diff --git a/src/librustc/traits/coherence.rs b/src/librustc/traits/coherence.rs
index c9cb823ebb3..4c7049c3662 100644
--- a/src/librustc/traits/coherence.rs
+++ b/src/librustc/traits/coherence.rs
@@ -11,7 +11,6 @@ use traits::{self, Normalized, SelectionContext, Obligation, ObligationCause};
 use traits::IntercrateMode;
 use traits::select::IntercrateAmbiguityCause;
 use ty::{self, Ty, TyCtxt};
-use ty::relate::TraitObjectMode;
 use ty::fold::TypeFoldable;
 use ty::subst::Subst;
 
@@ -55,7 +54,6 @@ pub fn overlapping_impls<'gcx, F1, F2, R>(
     impl1_def_id: DefId,
     impl2_def_id: DefId,
     intercrate_mode: IntercrateMode,
-    trait_object_mode: TraitObjectMode,
     on_overlap: F1,
     no_overlap: F2,
 ) -> R
@@ -66,14 +64,12 @@ where
     debug!("overlapping_impls(\
            impl1_def_id={:?}, \
            impl2_def_id={:?},
-           intercrate_mode={:?},
-           trait_object_mode={:?})",
+           intercrate_mode={:?})",
            impl1_def_id,
            impl2_def_id,
-           intercrate_mode,
-           trait_object_mode);
+           intercrate_mode);
 
-    let overlaps = tcx.infer_ctxt().with_trait_object_mode(trait_object_mode).enter(|infcx| {
+    let overlaps = tcx.infer_ctxt().enter(|infcx| {
         let selcx = &mut SelectionContext::intercrate(&infcx, intercrate_mode);
         overlap(selcx, impl1_def_id, impl2_def_id).is_some()
     });
@@ -85,7 +81,7 @@ where
     // In the case where we detect an error, run the check again, but
     // this time tracking intercrate ambuiguity causes for better
     // diagnostics. (These take time and can lead to false errors.)
-    tcx.infer_ctxt().with_trait_object_mode(trait_object_mode).enter(|infcx| {
+    tcx.infer_ctxt().enter(|infcx| {
         let selcx = &mut SelectionContext::intercrate(&infcx, intercrate_mode);
         selcx.enable_tracking_intercrate_ambiguity_causes();
         on_overlap(overlap(selcx, impl1_def_id, impl2_def_id).unwrap())
@@ -510,7 +506,13 @@ fn ty_is_local_constructor(ty: Ty<'_>, in_crate: InCrate) -> bool {
         ty::Adt(def, _) => def_id_is_local(def.did, in_crate),
         ty::Foreign(did) => def_id_is_local(did, in_crate),
 
-        ty::Dynamic(ref tt, ..) => def_id_is_local(tt.principal().def_id(), in_crate),
+        ty::Dynamic(ref tt, ..) => {
+            if let Some(principal) = tt.principal() {
+                def_id_is_local(principal.def_id(), in_crate)
+            } else {
+                false
+            }
+        }
 
         ty::Error => true,
 
diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs
index c0f50ecd288..7ce5960b9b3 100644
--- a/src/librustc/traits/error_reporting.rs
+++ b/src/librustc/traits/error_reporting.rs
@@ -447,7 +447,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
     {
         let simp = fast_reject::simplify_type(self.tcx,
                                               trait_ref.skip_binder().self_ty(),
-                                              true,);
+                                              true);
         let all_impls = self.tcx.all_impls(trait_ref.def_id());
 
         match simp {
diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs
index 373ec2d5e49..6db6fe31fba 100644
--- a/src/librustc/traits/select.rs
+++ b/src/librustc/traits/select.rs
@@ -33,7 +33,7 @@ use infer::{InferCtxt, InferOk, TypeFreshener};
 use middle::lang_items;
 use mir::interpret::GlobalId;
 use ty::fast_reject;
-use ty::relate::{TypeRelation, TraitObjectMode};
+use ty::relate::TypeRelation;
 use ty::subst::{Subst, Substs};
 use ty::{self, ToPolyTraitRef, ToPredicate, Ty, TyCtxt, TypeFoldable};
 
@@ -1416,13 +1416,6 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
             return false;
         }
 
-        // Same idea as the above, but for alt trait object modes. These
-        // should only be used in intercrate mode - better safe than sorry.
-        if self.infcx.trait_object_mode() != TraitObjectMode::NoSquash {
-            bug!("using squashing TraitObjectMode outside of intercrate mode? param_env={:?}",
-                 param_env);
-        }
-
         // Otherwise, we can use the global cache.
         true
     }
@@ -2016,7 +2009,12 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
                         return;
                     }
 
-                    data.principal().with_self_ty(self.tcx(), self_ty)
+                    if let Some(principal) = data.principal() {
+                        principal.with_self_ty(self.tcx(), self_ty)
+                    } else {
+                        // Only auto-trait bounds exist.
+                        return;
+                    }
                 }
                 ty::Infer(ty::TyVar(_)) => {
                     debug!("assemble_candidates_from_object_ty: ambiguous");
@@ -2108,7 +2106,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
                 //
                 // We always upcast when we can because of reason
                 // #2 (region bounds).
-                data_a.principal().def_id() == data_b.principal().def_id()
+                data_a.principal_def_id() == data_b.principal_def_id()
                     && data_b.auto_traits()
                     // All of a's auto traits need to be in b's auto traits.
                     .all(|b| data_a.auto_traits().any(|a| a == b))
@@ -2262,7 +2260,8 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
                         ImplCandidate(victim_def) => {
                             let tcx = self.tcx().global_tcx();
                             return tcx.specializes((other_def, victim_def))
-                                || tcx.impls_are_allowed_to_overlap(other_def, victim_def);
+                                || tcx.impls_are_allowed_to_overlap(
+                                    other_def, victim_def).is_some();
                         }
                         ParamCandidate(ref cand) => {
                             // Prefer the impl to a global where clause candidate.
@@ -2919,7 +2918,10 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
         let self_ty = self.infcx
             .shallow_resolve(*obligation.self_ty().skip_binder());
         let poly_trait_ref = match self_ty.sty {
-            ty::Dynamic(ref data, ..) => data.principal().with_self_ty(self.tcx(), self_ty),
+            ty::Dynamic(ref data, ..) =>
+                data.principal().unwrap_or_else(|| {
+                    span_bug!(obligation.cause.span, "object candidate with no principal")
+                }).with_self_ty(self.tcx(), self_ty),
             _ => span_bug!(obligation.cause.span, "object candidate with non-object"),
         };
 
@@ -3222,8 +3224,9 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
             (&ty::Dynamic(ref data_a, r_a), &ty::Dynamic(ref data_b, r_b)) => {
                 // See assemble_candidates_for_unsizing for more info.
                 let existential_predicates = data_a.map_bound(|data_a| {
-                    let iter = iter::once(ty::ExistentialPredicate::Trait(data_a.principal()))
-                        .chain(
+                    let iter =
+                        data_a.principal().map(|x| ty::ExistentialPredicate::Trait(x))
+                        .into_iter().chain(
                             data_a
                                 .projection_bounds()
                                 .map(|x| ty::ExistentialPredicate::Projection(x)),
@@ -3260,7 +3263,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
             // T -> Trait.
             (_, &ty::Dynamic(ref data, r)) => {
                 let mut object_dids = data.auto_traits()
-                    .chain(iter::once(data.principal().def_id()));
+                    .chain(data.principal_def_id());
                 if let Some(did) = object_dids.find(|did| !tcx.is_object_safe(*did)) {
                     return Err(TraitNotObjectSafe(did));
                 }
@@ -3571,8 +3574,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
         previous: &ty::PolyTraitRef<'tcx>,
         current: &ty::PolyTraitRef<'tcx>,
     ) -> bool {
-        let mut matcher = ty::_match::Match::new(
-            self.tcx(), self.infcx.trait_object_mode());
+        let mut matcher = ty::_match::Match::new(self.tcx());
         matcher.relate(previous, current).is_ok()
     }
 
diff --git a/src/librustc/traits/specialize/mod.rs b/src/librustc/traits/specialize/mod.rs
index 63f52a34dfa..e5ed16e7558 100644
--- a/src/librustc/traits/specialize/mod.rs
+++ b/src/librustc/traits/specialize/mod.rs
@@ -14,8 +14,7 @@ pub mod specialization_graph;
 use hir::def_id::DefId;
 use infer::{InferCtxt, InferOk};
 use lint;
-use traits::{self, FutureCompatOverlapErrorKind, ObligationCause, TraitEngine};
-use traits::coherence;
+use traits::{self, coherence, FutureCompatOverlapErrorKind, ObligationCause, TraitEngine};
 use rustc_data_structures::fx::FxHashSet;
 use rustc_data_structures::sync::Lrc;
 use syntax_pos::DUMMY_SP;
diff --git a/src/librustc/traits/specialize/specialization_graph.rs b/src/librustc/traits/specialize/specialization_graph.rs
index db3547b2b74..e5780a26a19 100644
--- a/src/librustc/traits/specialize/specialization_graph.rs
+++ b/src/librustc/traits/specialize/specialization_graph.rs
@@ -7,7 +7,6 @@ use rustc_data_structures::stable_hasher::{HashStable, StableHasher,
 use traits;
 use ty::{self, TyCtxt, TypeFoldable};
 use ty::fast_reject::{self, SimplifiedType};
-use ty::relate::TraitObjectMode;
 use rustc_data_structures::sync::Lrc;
 use syntax::ast::Ident;
 use util::captures::Captures;
@@ -174,9 +173,20 @@ impl<'a, 'gcx, 'tcx> Children {
                 possible_sibling,
                 impl_def_id,
                 traits::IntercrateMode::Issue43355,
-                TraitObjectMode::NoSquash,
                 |overlap| {
-                    if tcx.impls_are_allowed_to_overlap(impl_def_id, possible_sibling) {
+                    if let Some(overlap_kind) =
+                        tcx.impls_are_allowed_to_overlap(impl_def_id, possible_sibling)
+                    {
+                        match overlap_kind {
+                            ty::ImplOverlapKind::Permitted => {}
+                            ty::ImplOverlapKind::Issue33140 => {
+                                last_lint = Some(FutureCompatOverlapError {
+                                    error: overlap_error(overlap),
+                                    kind: FutureCompatOverlapErrorKind::Issue33140
+                                });
+                            }
+                        }
+
                         return Ok((false, false));
                     }
 
@@ -204,31 +214,17 @@ impl<'a, 'gcx, 'tcx> Children {
 
                 replace_children.push(possible_sibling);
             } else {
-                if !tcx.impls_are_allowed_to_overlap(impl_def_id, possible_sibling) {
-                    // do future-compat checks for overlap. Have issue #43355
-                    // errors overwrite issue #33140 errors when both are present.
-
-                    traits::overlapping_impls(
-                        tcx,
-                        possible_sibling,
-                        impl_def_id,
-                        traits::IntercrateMode::Fixed,
-                        TraitObjectMode::SquashAutoTraitsIssue33140,
-                        |overlap| {
-                            last_lint = Some(FutureCompatOverlapError {
-                                error: overlap_error(overlap),
-                                kind: FutureCompatOverlapErrorKind::Issue33140
-                            });
-                        },
-                        || (),
-                    );
+                if let None = tcx.impls_are_allowed_to_overlap(
+                    impl_def_id, possible_sibling)
+                {
+                    // do future-compat checks for overlap. Have issue #33140
+                    // errors overwrite issue #43355 errors when both are present.
 
                     traits::overlapping_impls(
                         tcx,
                         possible_sibling,
                         impl_def_id,
                         traits::IntercrateMode::Fixed,
-                        TraitObjectMode::NoSquash,
                         |overlap| {
                             last_lint = Some(FutureCompatOverlapError {
                                 error: overlap_error(overlap),
diff --git a/src/librustc/ty/_match.rs b/src/librustc/ty/_match.rs
index 3657a880804..34b94d4217d 100644
--- a/src/librustc/ty/_match.rs
+++ b/src/librustc/ty/_match.rs
@@ -19,24 +19,17 @@ use ty::relate::{self, Relate, TypeRelation, RelateResult};
 /// important thing about the result is Ok/Err. Also, matching never
 /// affects any type variables or unification state.
 pub struct Match<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
-    tcx: TyCtxt<'a, 'gcx, 'tcx>,
-    trait_object_mode: relate::TraitObjectMode
+    tcx: TyCtxt<'a, 'gcx, 'tcx>
 }
 
 impl<'a, 'gcx, 'tcx> Match<'a, 'gcx, 'tcx> {
-    pub fn new(tcx: TyCtxt<'a, 'gcx, 'tcx>,
-               trait_object_mode: relate::TraitObjectMode)
-               -> Match<'a, 'gcx, 'tcx> {
-        Match { tcx, trait_object_mode }
+    pub fn new(tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Match<'a, 'gcx, 'tcx> {
+        Match { tcx }
     }
 }
 
 impl<'a, 'gcx, 'tcx> TypeRelation<'a, 'gcx, 'tcx> for Match<'a, 'gcx, 'tcx> {
     fn tag(&self) -> &'static str { "Match" }
-    fn trait_object_mode(&self) -> relate::TraitObjectMode {
-        self.trait_object_mode
-    }
-
     fn tcx(&self) -> TyCtxt<'a, 'gcx, 'tcx> { self.tcx }
     fn a_is_expected(&self) -> bool { true } // irrelevant
 
diff --git a/src/librustc/ty/error.rs b/src/librustc/ty/error.rs
index 0d6d9f91eb4..834b541d4c0 100644
--- a/src/librustc/ty/error.rs
+++ b/src/librustc/ty/error.rs
@@ -184,7 +184,11 @@ impl<'a, 'gcx, 'lcx, 'tcx> ty::TyS<'tcx> {
             ty::FnDef(..) => "fn item".into(),
             ty::FnPtr(_) => "fn pointer".into(),
             ty::Dynamic(ref inner, ..) => {
-                format!("trait {}", tcx.item_path_str(inner.principal().def_id())).into()
+                if let Some(principal) = inner.principal() {
+                    format!("trait {}", tcx.item_path_str(principal.def_id())).into()
+                } else {
+                    "trait".into()
+                }
             }
             ty::Closure(..) => "closure".into(),
             ty::Generator(..) => "generator".into(),
diff --git a/src/librustc/ty/fast_reject.rs b/src/librustc/ty/fast_reject.rs
index 7fbbfb337ea..2b41fc4fe34 100644
--- a/src/librustc/ty/fast_reject.rs
+++ b/src/librustc/ty/fast_reject.rs
@@ -71,11 +71,11 @@ pub fn simplify_type<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
         ty::Array(..) | ty::Slice(_) => Some(ArraySimplifiedType),
         ty::RawPtr(_) => Some(PtrSimplifiedType),
         ty::Dynamic(ref trait_info, ..) => {
-            let principal_def_id = trait_info.principal().def_id();
-            if tcx.trait_is_auto(principal_def_id) {
-                Some(MarkerTraitObjectSimplifiedType)
-            } else {
-                Some(TraitSimplifiedType(principal_def_id))
+            match trait_info.principal_def_id() {
+                Some(principal_def_id) if !tcx.trait_is_auto(principal_def_id) => {
+                    Some(TraitSimplifiedType(principal_def_id))
+                }
+                _ => Some(MarkerTraitObjectSimplifiedType)
             }
         }
         ty::Ref(_, ty, _) => {
@@ -140,9 +140,9 @@ impl<D: Copy + Debug + Ord + Eq + Hash> SimplifiedTypeGen<D> {
             ArraySimplifiedType => ArraySimplifiedType,
             PtrSimplifiedType => PtrSimplifiedType,
             NeverSimplifiedType => NeverSimplifiedType,
+            MarkerTraitObjectSimplifiedType => MarkerTraitObjectSimplifiedType,
             TupleSimplifiedType(n) => TupleSimplifiedType(n),
             TraitSimplifiedType(d) => TraitSimplifiedType(map(d)),
-            MarkerTraitObjectSimplifiedType => MarkerTraitObjectSimplifiedType,
             ClosureSimplifiedType(d) => ClosureSimplifiedType(map(d)),
             GeneratorSimplifiedType(d) => GeneratorSimplifiedType(map(d)),
             GeneratorWitnessSimplifiedType(n) => GeneratorWitnessSimplifiedType(n),
diff --git a/src/librustc/ty/item_path.rs b/src/librustc/ty/item_path.rs
index da467f57d25..417e14054d2 100644
--- a/src/librustc/ty/item_path.rs
+++ b/src/librustc/ty/item_path.rs
@@ -479,7 +479,7 @@ pub fn characteristic_def_id_of_type(ty: Ty<'_>) -> Option<DefId> {
     match ty.sty {
         ty::Adt(adt_def, _) => Some(adt_def.did),
 
-        ty::Dynamic(data, ..) => Some(data.principal().def_id()),
+        ty::Dynamic(data, ..) => data.principal_def_id(),
 
         ty::Array(subty, _) |
         ty::Slice(subty) => characteristic_def_id_of_type(subty),
diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs
index 20167bd41fb..f11a3688b39 100644
--- a/src/librustc/ty/mod.rs
+++ b/src/librustc/ty/mod.rs
@@ -2637,6 +2637,45 @@ impl<'gcx> ::std::ops::Deref for Attributes<'gcx> {
     }
 }
 
+#[derive(Debug, PartialEq, Eq)]
+pub enum ImplOverlapKind {
+    /// These impls are always allowed to overlap.
+    Permitted,
+    /// These impls are allowed to overlap, but that raises
+    /// an issue #33140 future-compatibility warning.
+    ///
+    /// Some background: in Rust 1.0, the trait-object types `Send + Sync` (today's
+    /// `dyn Send + Sync`) and `Sync + Send` (now `dyn Sync + Send`) were different.
+    ///
+    /// The widely-used version 0.1.0 of the crate `traitobject` had accidentally relied
+    /// that difference, making what reduces to the following set of impls:
+    ///
+    /// ```
+    /// trait Trait {}
+    /// impl Trait for dyn Send + Sync {}
+    /// impl Trait for dyn Sync + Send {}
+    /// ```
+    ///
+    /// Obviously, once we made these types be identical, that code causes a coherence
+    /// error and a fairly big headache for us. However, luckily for us, the trait
+    /// `Trait` used in this case is basically a marker trait, and therefore having
+    /// overlapping impls for it is sound.
+    ///
+    /// To handle this, we basically regard the trait as a marker trait, with an additional
+    /// future-compatibility warning. To avoid accidentally "stabilizing" this feature,
+    /// it has the following restrictions:
+    ///
+    /// 1. The trait must indeed be a marker-like trait (i.e., no items), and must be
+    /// positive impls.
+    /// 2. The trait-ref of both impls must be equal.
+    /// 3. The trait-ref of both impls must be a trait object type consisting only of
+    /// marker traits.
+    /// 4. Neither of the impls can have any where-clauses.
+    ///
+    /// Once `traitobject` 0.1.0 is no longer an active concern, this hack can be removed.
+    Issue33140
+}
+
 impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
     pub fn body_tables(self, body: hir::BodyId) -> &'gcx TypeckTables<'gcx> {
         self.typeck_tables_of(self.hir().body_owner_def_id(body))
@@ -2788,8 +2827,10 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
 
     /// Returns `true` if the impls are the same polarity and the trait either
     /// has no items or is annotated #[marker] and prevents item overrides.
-    pub fn impls_are_allowed_to_overlap(self, def_id1: DefId, def_id2: DefId) -> bool {
-        if self.features().overlapping_marker_traits {
+    pub fn impls_are_allowed_to_overlap(self, def_id1: DefId, def_id2: DefId)
+                                        -> Option<ImplOverlapKind>
+    {
+        let is_legit = if self.features().overlapping_marker_traits {
             let trait1_is_empty = self.impl_trait_ref(def_id1)
                 .map_or(false, |trait_ref| {
                     self.associated_item_def_ids(trait_ref.def_id).is_empty()
@@ -2811,6 +2852,29 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
                 && is_marker_impl(def_id2)
         } else {
             false
+        };
+
+        if is_legit {
+            debug!("impls_are_allowed_to_overlap({:?}, {:?}) = Some(Permitted)",
+                  def_id1, def_id2);
+            Some(ImplOverlapKind::Permitted)
+        } else {
+            if let Some(self_ty1) = self.issue33140_self_ty(def_id1) {
+                if let Some(self_ty2) = self.issue33140_self_ty(def_id2) {
+                    if self_ty1 == self_ty2 {
+                        debug!("impls_are_allowed_to_overlap({:?}, {:?}) - issue #33140 HACK",
+                               def_id1, def_id2);
+                        return Some(ImplOverlapKind::Issue33140);
+                    } else {
+                        debug!("impls_are_allowed_to_overlap({:?}, {:?}) - found {:?} != {:?}",
+                              def_id1, def_id2, self_ty1, self_ty2);
+                    }
+                }
+            }
+
+            debug!("impls_are_allowed_to_overlap({:?}, {:?}) = None",
+                  def_id1, def_id2);
+            None
         }
     }
 
@@ -3203,6 +3267,59 @@ fn instance_def_size_estimate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     }
 }
 
+/// If `def_id` is an issue 33140 hack impl, return its self type. Otherwise
+/// return None.
+///
+/// See ImplOverlapKind::Issue33140 for more details.
+fn issue33140_self_ty<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+                                def_id: DefId)
+                                -> Option<Ty<'tcx>>
+{
+    debug!("issue33140_self_ty({:?})", def_id);
+
+    let trait_ref = tcx.impl_trait_ref(def_id).unwrap_or_else(|| {
+        bug!("issue33140_self_ty called on inherent impl {:?}", def_id)
+    });
+
+    debug!("issue33140_self_ty({:?}), trait-ref={:?}", def_id, trait_ref);
+
+    let is_marker_like =
+        tcx.impl_polarity(def_id) == hir::ImplPolarity::Positive &&
+        tcx.associated_item_def_ids(trait_ref.def_id).is_empty();
+
+    // Check whether these impls would be ok for a marker trait.
+    if !is_marker_like {
+        debug!("issue33140_self_ty - not marker-like!");
+        return None;
+    }
+
+    // impl must be `impl Trait for dyn Marker1 + Marker2 + ...`
+    if trait_ref.substs.len() != 1 {
+        debug!("issue33140_self_ty - impl has substs!");
+        return None;
+    }
+
+    let predicates = tcx.predicates_of(def_id);
+    if predicates.parent.is_some() || !predicates.predicates.is_empty() {
+        debug!("issue33140_self_ty - impl has predicates {:?}!", predicates);
+        return None;
+    }
+
+    let self_ty = trait_ref.self_ty();
+    let self_ty_matches = match self_ty.sty {
+        ty::Dynamic(ref data, ty::ReStatic) => data.principal().is_none(),
+        _ => false
+    };
+
+    if self_ty_matches {
+        debug!("issue33140_self_ty - MATCHES!");
+        Some(self_ty)
+    } else {
+        debug!("issue33140_self_ty - non-matching self type");
+        None
+    }
+}
+
 pub fn provide(providers: &mut ty::query::Providers<'_>) {
     context::provide(providers);
     erase_regions::provide(providers);
@@ -3221,6 +3338,7 @@ pub fn provide(providers: &mut ty::query::Providers<'_>) {
         crate_hash,
         trait_impls_of: trait_def::trait_impls_of_provider,
         instance_def_size_estimate,
+        issue33140_self_ty,
         ..*providers
     };
 }
diff --git a/src/librustc/ty/query/mod.rs b/src/librustc/ty/query/mod.rs
index 4d026b97233..99dd3569491 100644
--- a/src/librustc/ty/query/mod.rs
+++ b/src/librustc/ty/query/mod.rs
@@ -202,6 +202,8 @@ define_queries! { <'tcx>
 
         [] fn impl_trait_ref: ImplTraitRef(DefId) -> Option<ty::TraitRef<'tcx>>,
         [] fn impl_polarity: ImplPolarity(DefId) -> hir::ImplPolarity,
+
+        [] fn issue33140_self_ty: Issue33140SelfTy(DefId) -> Option<ty::Ty<'tcx>>,
     },
 
     TypeChecking {
diff --git a/src/librustc/ty/query/plumbing.rs b/src/librustc/ty/query/plumbing.rs
index 6887f480f72..9a1ab559688 100644
--- a/src/librustc/ty/query/plumbing.rs
+++ b/src/librustc/ty/query/plumbing.rs
@@ -1275,6 +1275,7 @@ pub fn force_from_dep_node<'a, 'gcx, 'lcx>(tcx: TyCtxt<'a, 'gcx, 'lcx>,
         DepKind::AdtDefOfItem => { force!(adt_def, def_id!()); }
         DepKind::ImplTraitRef => { force!(impl_trait_ref, def_id!()); }
         DepKind::ImplPolarity => { force!(impl_polarity, def_id!()); }
+        DepKind::Issue33140SelfTy => { force!(issue33140_self_ty, def_id!()); }
         DepKind::FnSignature => { force!(fn_sig, def_id!()); }
         DepKind::CoerceUnsizedInfo => { force!(coerce_unsized_info, def_id!()); }
         DepKind::ItemVariances => { force!(variances_of, def_id!()); }
diff --git a/src/librustc/ty/relate.rs b/src/librustc/ty/relate.rs
index 6d310a9500a..a16d6fea74c 100644
--- a/src/librustc/ty/relate.rs
+++ b/src/librustc/ty/relate.rs
@@ -24,20 +24,9 @@ pub enum Cause {
     ExistentialRegionBound, // relating an existential region bound
 }
 
-#[derive(Copy, Clone, Debug, PartialEq, Eq)]
-pub enum TraitObjectMode {
-    NoSquash,
-    /// A temporary mode to treat `Send + Sync = Sync + Send`, should be
-    /// used only in coherence.
-    SquashAutoTraitsIssue33140
-}
-
 pub trait TypeRelation<'a, 'gcx: 'a+'tcx, 'tcx: 'a> : Sized {
     fn tcx(&self) -> TyCtxt<'a, 'gcx, 'tcx>;
 
-    /// Return the trait object mode to be used.
-    fn trait_object_mode(&self) -> TraitObjectMode;
-
     /// Returns a static string we can use for printouts.
     fn tag(&self) -> &'static str;
 
@@ -591,44 +580,14 @@ impl<'tcx> Relate<'tcx> for &'tcx ty::List<ty::ExistentialPredicate<'tcx>> {
                            a: &Self,
                            b: &Self)
         -> RelateResult<'tcx, Self>
-        where R: TypeRelation<'a, 'gcx, 'tcx>, 'gcx: 'a+'tcx, 'tcx: 'a {
-        use ty::ExistentialPredicate::*;
+            where R: TypeRelation<'a, 'gcx, 'tcx>, 'gcx: 'a+'tcx, 'tcx: 'a {
 
-        let tcx = relation.tcx();
-        let (a_buf, b_buf);
-        let (a_norm, b_norm): (&[_], &[_]) = match relation.trait_object_mode() {
-            TraitObjectMode::NoSquash => {
-                (a, b)
-            }
-            TraitObjectMode::SquashAutoTraitsIssue33140 => {
-                // Treat auto-trait "principal" components as equal
-                // to the non-principal components, to make
-                // `dyn Send+Sync = dyn Sync+Send`.
-                let normalize = |d: &[ty::ExistentialPredicate<'tcx>]| {
-                    let mut result: Vec<_> = d.iter().map(|pi| match pi {
-                        Trait(ref a) if tcx.trait_is_auto(a.def_id) => {
-                            AutoTrait(a.def_id)
-                        },
-                        other => *other
-                    }).collect();
-
-                    result.sort_by(|a, b| a.stable_cmp(tcx, b));
-                    result.dedup();
-                    result
-                };
-
-                a_buf = normalize(a);
-                b_buf = normalize(b);
-
-                (&a_buf, &b_buf)
-            }
-        };
-
-        if a_norm.len() != b_norm.len() {
+        if a.len() != b.len() {
             return Err(TypeError::ExistentialMismatch(expected_found(relation, a, b)));
         }
 
-        let v = a_norm.iter().zip(b_norm.iter()).map(|(ep_a, ep_b)| {
+        let tcx = relation.tcx();
+        let v = a.iter().zip(b.iter()).map(|(ep_a, ep_b)| {
             use ty::ExistentialPredicate::*;
             match (*ep_a, *ep_b) {
                 (Trait(ref a), Trait(ref b)) => Ok(Trait(relation.relate(a, b)?)),
diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs
index ebaf6a73e34..b98369b62ea 100644
--- a/src/librustc/ty/sty.rs
+++ b/src/librustc/ty/sty.rs
@@ -569,13 +569,42 @@ impl<'a, 'gcx, 'tcx> Binder<ExistentialPredicate<'tcx>> {
 impl<'tcx> serialize::UseSpecializedDecodable for &'tcx List<ExistentialPredicate<'tcx>> {}
 
 impl<'tcx> List<ExistentialPredicate<'tcx>> {
-    pub fn principal(&self) -> ExistentialTraitRef<'tcx> {
+    /// Returns the "principal def id" of this set of existential predicates.
+    ///
+    /// A Rust trait object type consists (in addition to a lifetime bound)
+    /// of a set of trait bounds, which are separated into any number
+    /// of auto-trait bounds, and at most 1 non-auto-trait bound. The
+    /// non-auto-trait bound is called the "principal" of the trait
+    /// object.
+    ///
+    /// Only the principal can have methods or type parameters (because
+    /// auto traits can have neither of them). This is important, because
+    /// it means the auto traits can be treated as an unordered set (methods
+    /// would force an order for the vtable, while relating traits with
+    /// type parameters without knowing the order to relate them in is
+    /// a rather non-trivial task).
+    ///
+    /// For example, in the trait object `dyn fmt::Debug + Sync`, the
+    /// principal bound is `Some(fmt::Debug)`, while the auto-trait bounds
+    /// are the set `{Sync}`.
+    ///
+    /// It is also possible to have a "trivial" trait object that
+    /// consists only of auto traits, with no principal - for example,
+    /// `dyn Send + Sync`. In that case, the set of auto-trait bounds
+    /// is `{Send, Sync}`, while there is no principal. These trait objects
+    /// have a "trivial" vtable consisting of just the size, alignment,
+    /// and destructor.
+    pub fn principal(&self) -> Option<ExistentialTraitRef<'tcx>> {
         match self[0] {
-            ExistentialPredicate::Trait(tr) => tr,
-            other => bug!("first predicate is {:?}", other),
+            ExistentialPredicate::Trait(tr) => Some(tr),
+            _ => None
         }
     }
 
+    pub fn principal_def_id(&self) -> Option<DefId> {
+        self.principal().map(|d| d.def_id)
+    }
+
     #[inline]
     pub fn projection_bounds<'a>(&'a self) ->
         impl Iterator<Item=ExistentialProjection<'tcx>> + 'a {
@@ -599,8 +628,12 @@ impl<'tcx> List<ExistentialPredicate<'tcx>> {
 }
 
 impl<'tcx> Binder<&'tcx List<ExistentialPredicate<'tcx>>> {
-    pub fn principal(&self) -> PolyExistentialTraitRef<'tcx> {
-        Binder::bind(self.skip_binder().principal())
+    pub fn principal(&self) -> Option<ty::Binder<ExistentialTraitRef<'tcx>>> {
+        self.skip_binder().principal().map(Binder::bind)
+    }
+
+    pub fn principal_def_id(&self) -> Option<DefId> {
+        self.skip_binder().principal_def_id()
     }
 
     #[inline]
@@ -1917,7 +1950,9 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> {
             }
             Dynamic(ref obj, region) => {
                 out.push(region);
-                out.extend(obj.principal().skip_binder().substs.regions());
+                if let Some(principal) = obj.principal() {
+                    out.extend(principal.skip_binder().substs.regions());
+                }
             }
             Adt(_, substs) | Opaque(_, substs) => {
                 out.extend(substs.regions())
diff --git a/src/librustc/ty/wf.rs b/src/librustc/ty/wf.rs
index 517cfd9edfa..ef683940296 100644
--- a/src/librustc/ty/wf.rs
+++ b/src/librustc/ty/wf.rs
@@ -381,7 +381,7 @@ impl<'a, 'gcx, 'tcx> WfPredicates<'a, 'gcx, 'tcx> {
 
                     let cause = self.cause(traits::MiscObligation);
                     let component_traits =
-                        data.auto_traits().chain(once(data.principal().def_id()));
+                        data.auto_traits().chain(data.principal_def_id());
                     self.out.extend(
                         component_traits.map(|did| traits::Obligation::new(
                             cause.clone(),
diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs
index 37bc9397d90..04e571863d4 100644
--- a/src/librustc/util/ppaux.rs
+++ b/src/librustc/util/ppaux.rs
@@ -711,21 +711,43 @@ define_print! {
             ty::tls::with(|tcx| {
                 // Use a type that can't appear in defaults of type parameters.
                 let dummy_self = tcx.mk_infer(ty::FreshTy(0));
-
-                let principal = tcx
-                    .lift(&self.principal())
-                    .expect("could not lift TraitRef for printing")
-                    .with_self_ty(tcx, dummy_self);
-                let projections = self.projection_bounds().map(|p| {
-                    tcx.lift(&p)
-                        .expect("could not lift projection for printing")
-                        .with_self_ty(tcx, dummy_self)
-                }).collect::<Vec<_>>();
-                cx.parameterized(f, principal.substs, principal.def_id, &projections)?;
+                let mut first = true;
+
+                if let Some(principal) = self.principal() {
+                    let principal = tcx
+                        .lift(&principal)
+                        .expect("could not lift TraitRef for printing")
+                        .with_self_ty(tcx, dummy_self);
+                    let projections = self.projection_bounds().map(|p| {
+                        tcx.lift(&p)
+                            .expect("could not lift projection for printing")
+                            .with_self_ty(tcx, dummy_self)
+                    }).collect::<Vec<_>>();
+                    cx.parameterized(f, principal.substs, principal.def_id, &projections)?;
+                    first = false;
+                }
 
                 // Builtin bounds.
-                for did in self.auto_traits() {
-                    write!(f, " + {}", tcx.item_path_str(did))?;
+                let mut auto_traits: Vec<_> = self.auto_traits().map(|did| {
+                    tcx.item_path_str(did)
+                }).collect();
+
+                // The auto traits come ordered by `DefPathHash`. While
+                // `DefPathHash` is *stable* in the sense that it depends on
+                // neither the host nor the phase of the moon, it depends
+                // "pseudorandomly" on the compiler version and the target.
+                //
+                // To avoid that causing instabilities in compiletest
+                // output, sort the auto-traits alphabetically.
+                auto_traits.sort();
+
+                for auto_trait in auto_traits {
+                    if !first {
+                        write!(f, " + ")?;
+                    }
+                    first = false;
+
+                    write!(f, "{}", auto_trait)?;
                 }
 
                 Ok(())
diff --git a/src/librustc_codegen_llvm/context.rs b/src/librustc_codegen_llvm/context.rs
index 3a5da29c681..2b03e99161d 100644
--- a/src/librustc_codegen_llvm/context.rs
+++ b/src/librustc_codegen_llvm/context.rs
@@ -50,7 +50,8 @@ pub struct CodegenCx<'ll, 'tcx: 'll> {
     /// Cache instances of monomorphic and polymorphic items
     pub instances: RefCell<FxHashMap<Instance<'tcx>, &'ll Value>>,
     /// Cache generated vtables
-    pub vtables: RefCell<FxHashMap<(Ty<'tcx>, ty::PolyExistentialTraitRef<'tcx>), &'ll Value>>,
+    pub vtables: RefCell<FxHashMap<
+            (Ty<'tcx>, Option<ty::PolyExistentialTraitRef<'tcx>>), &'ll Value>>,
     /// Cache of constant strings,
     pub const_cstr_cache: RefCell<FxHashMap<LocalInternedString, &'ll Value>>,
 
@@ -311,7 +312,7 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> {
 
 impl MiscMethods<'tcx> for CodegenCx<'ll, 'tcx> {
     fn vtables(&self) -> &RefCell<FxHashMap<(Ty<'tcx>,
-                                ty::PolyExistentialTraitRef<'tcx>), &'ll Value>>
+                                Option<ty::PolyExistentialTraitRef<'tcx>>), &'ll Value>>
     {
         &self.vtables
     }
diff --git a/src/librustc_codegen_llvm/debuginfo/metadata.rs b/src/librustc_codegen_llvm/debuginfo/metadata.rs
index 0fd04e9d203..72ed55df946 100644
--- a/src/librustc_codegen_llvm/debuginfo/metadata.rs
+++ b/src/librustc_codegen_llvm/debuginfo/metadata.rs
@@ -429,7 +429,8 @@ fn trait_pointer_metadata(
     // But it does not describe the trait's methods.
 
     let containing_scope = match trait_type.sty {
-        ty::Dynamic(ref data, ..) => Some(get_namespace_for_item(cx, data.principal().def_id())),
+        ty::Dynamic(ref data, ..) =>
+            data.principal_def_id().map(|did| get_namespace_for_item(cx, did)),
         _ => {
             bug!("debuginfo: Unexpected trait-object type in \
                   trait_pointer_metadata(): {:?}",
diff --git a/src/librustc_codegen_llvm/debuginfo/type_names.rs b/src/librustc_codegen_llvm/debuginfo/type_names.rs
index c8cbd735e85..32432f7e4ec 100644
--- a/src/librustc_codegen_llvm/debuginfo/type_names.rs
+++ b/src/librustc_codegen_llvm/debuginfo/type_names.rs
@@ -107,12 +107,16 @@ pub fn push_debuginfo_type_name<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>,
             }
         },
         ty::Dynamic(ref trait_data, ..) => {
-            let principal = cx.tcx.normalize_erasing_late_bound_regions(
-                ty::ParamEnv::reveal_all(),
-                &trait_data.principal(),
-            );
-            push_item_name(cx, principal.def_id, false, output);
-            push_type_params(cx, principal.substs, output);
+            if let Some(principal) = trait_data.principal() {
+                let principal = cx.tcx.normalize_erasing_late_bound_regions(
+                    ty::ParamEnv::reveal_all(),
+                    &principal,
+                );
+                push_item_name(cx, principal.def_id, false, output);
+                push_type_params(cx, principal.substs, output);
+            } else {
+                output.push_str("dyn '_");
+            }
         },
         ty::FnDef(..) | ty::FnPtr(_) => {
             let sig = t.fn_sig(cx.tcx);
diff --git a/src/librustc_codegen_ssa/meth.rs b/src/librustc_codegen_ssa/meth.rs
index 31640826262..98ad2616eea 100644
--- a/src/librustc_codegen_ssa/meth.rs
+++ b/src/librustc_codegen_ssa/meth.rs
@@ -69,7 +69,7 @@ impl<'a, 'tcx: 'a> VirtualIndex {
 pub fn get_vtable<'tcx, Cx: CodegenMethods<'tcx>>(
     cx: &Cx,
     ty: Ty<'tcx>,
-    trait_ref: ty::PolyExistentialTraitRef<'tcx>,
+    trait_ref: Option<ty::PolyExistentialTraitRef<'tcx>>,
 ) -> Cx::Value {
     let tcx = cx.tcx();
 
@@ -83,8 +83,15 @@ pub fn get_vtable<'tcx, Cx: CodegenMethods<'tcx>>(
     // Not in the cache. Build it.
     let nullptr = cx.const_null(cx.type_i8p());
 
-    let methods = tcx.vtable_methods(trait_ref.with_self_ty(tcx, ty));
-    let methods = methods.iter().cloned().map(|opt_mth| {
+    let methods_root;
+    let methods = if let Some(trait_ref) = trait_ref {
+        methods_root = tcx.vtable_methods(trait_ref.with_self_ty(tcx, ty));
+        methods_root.iter()
+    } else {
+        (&[]).iter()
+    };
+
+    let methods = methods.cloned().map(|opt_mth| {
         opt_mth.map_or(nullptr, |(def_id, substs)| {
             callee::resolve_and_get_fn_for_vtable(cx, def_id, substs)
         })
diff --git a/src/librustc_codegen_ssa/traits/misc.rs b/src/librustc_codegen_ssa/traits/misc.rs
index c297288b255..b2315556366 100644
--- a/src/librustc_codegen_ssa/traits/misc.rs
+++ b/src/librustc_codegen_ssa/traits/misc.rs
@@ -11,7 +11,7 @@ use std::sync::Arc;
 pub trait MiscMethods<'tcx>: BackendTypes {
     fn vtables(
         &self,
-    ) -> &RefCell<FxHashMap<(Ty<'tcx>, ty::PolyExistentialTraitRef<'tcx>), Self::Value>>;
+    ) -> &RefCell<FxHashMap<(Ty<'tcx>, Option<ty::PolyExistentialTraitRef<'tcx>>), Self::Value>>;
     fn check_overflow(&self) -> bool;
     fn instances(&self) -> &RefCell<FxHashMap<Instance<'tcx>, Self::Value>>;
     fn get_fn(&self, instance: Instance<'tcx>) -> Self::Value;
diff --git a/src/librustc_mir/interpret/eval_context.rs b/src/librustc_mir/interpret/eval_context.rs
index 9a76a36ef22..19362b6cfdb 100644
--- a/src/librustc_mir/interpret/eval_context.rs
+++ b/src/librustc_mir/interpret/eval_context.rs
@@ -42,7 +42,7 @@ pub struct EvalContext<'a, 'mir, 'tcx: 'a + 'mir, M: Machine<'a, 'mir, 'tcx>> {
     pub(crate) stack: Vec<Frame<'mir, 'tcx, M::PointerTag, M::FrameExtra>>,
 
     /// A cache for deduplicating vtables
-    pub(super) vtables: FxHashMap<(Ty<'tcx>, ty::PolyExistentialTraitRef<'tcx>), AllocId>,
+    pub(super) vtables: FxHashMap<(Ty<'tcx>, Option<ty::PolyExistentialTraitRef<'tcx>>), AllocId>,
 }
 
 /// A stack frame.
diff --git a/src/librustc_mir/interpret/traits.rs b/src/librustc_mir/interpret/traits.rs
index 69a52b002ce..642bbc114f5 100644
--- a/src/librustc_mir/interpret/traits.rs
+++ b/src/librustc_mir/interpret/traits.rs
@@ -1,3 +1,4 @@
+use rustc_data_structures::sync::Lrc;
 use rustc::ty::{self, Ty};
 use rustc::ty::layout::{Size, Align, LayoutOf};
 use rustc::mir::interpret::{Scalar, Pointer, EvalResult, PointerArithmetic};
@@ -14,7 +15,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
     pub fn get_vtable(
         &mut self,
         ty: Ty<'tcx>,
-        poly_trait_ref: ty::PolyExistentialTraitRef<'tcx>,
+        poly_trait_ref: Option<ty::PolyExistentialTraitRef<'tcx>>,
     ) -> EvalResult<'tcx, Pointer<M::PointerTag>> {
         trace!("get_vtable(trait_ref={:?})", poly_trait_ref);
 
@@ -24,10 +25,14 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
             return Ok(Pointer::from(vtable).with_default_tag());
         }
 
-        let trait_ref = poly_trait_ref.with_self_ty(*self.tcx, ty);
-        let trait_ref = self.tcx.erase_regions(&trait_ref);
+        let methods = if let Some(poly_trait_ref) = poly_trait_ref {
+            let trait_ref = poly_trait_ref.with_self_ty(*self.tcx, ty);
+            let trait_ref = self.tcx.erase_regions(&trait_ref);
 
-        let methods = self.tcx.vtable_methods(trait_ref);
+            self.tcx.vtable_methods(trait_ref)
+        } else {
+            Lrc::new(Vec::new())
+        };
 
         let layout = self.layout_of(ty)?;
         assert!(!layout.is_unsized(), "can't create a vtable for an unsized type");
diff --git a/src/librustc_mir/monomorphize/collector.rs b/src/librustc_mir/monomorphize/collector.rs
index eabfd47c9fb..a6a8fe5ade5 100644
--- a/src/librustc_mir/monomorphize/collector.rs
+++ b/src/librustc_mir/monomorphize/collector.rs
@@ -894,20 +894,23 @@ fn create_mono_items_for_vtable_methods<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
             !impl_ty.needs_subst() && !impl_ty.has_escaping_bound_vars());
 
     if let ty::Dynamic(ref trait_ty, ..) = trait_ty.sty {
-        let poly_trait_ref = trait_ty.principal().with_self_ty(tcx, impl_ty);
-        assert!(!poly_trait_ref.has_escaping_bound_vars());
-
-        // Walk all methods of the trait, including those of its supertraits
-        let methods = tcx.vtable_methods(poly_trait_ref);
-        let methods = methods.iter().cloned().filter_map(|method| method)
-            .map(|(def_id, substs)| ty::Instance::resolve_for_vtable(
+        if let Some(principal) = trait_ty.principal() {
+            let poly_trait_ref = principal.with_self_ty(tcx, impl_ty);
+            assert!(!poly_trait_ref.has_escaping_bound_vars());
+
+            // Walk all methods of the trait, including those of its supertraits
+            let methods = tcx.vtable_methods(poly_trait_ref);
+            let methods = methods.iter().cloned().filter_map(|method| method)
+                .map(|(def_id, substs)| ty::Instance::resolve_for_vtable(
                     tcx,
                     ty::ParamEnv::reveal_all(),
                     def_id,
                     substs).unwrap())
-            .filter(|&instance| should_monomorphize_locally(tcx, &instance))
-            .map(|instance| create_fn_mono_item(instance));
-        output.extend(methods);
+                .filter(|&instance| should_monomorphize_locally(tcx, &instance))
+                .map(|instance| create_fn_mono_item(instance));
+            output.extend(methods);
+        }
+
         // Also add the destructor
         visit_drop_use(tcx, impl_ty, false, output);
     }
diff --git a/src/librustc_mir/monomorphize/item.rs b/src/librustc_mir/monomorphize/item.rs
index e7f4451fdd7..7014f539d57 100644
--- a/src/librustc_mir/monomorphize/item.rs
+++ b/src/librustc_mir/monomorphize/item.rs
@@ -304,13 +304,16 @@ impl<'a, 'tcx> DefPathBasedNames<'a, 'tcx> {
                 output.push(']');
             },
             ty::Dynamic(ref trait_data, ..) => {
-                let principal = trait_data.principal();
-                self.push_def_path(principal.def_id(), output);
-                self.push_type_params(
-                    principal.skip_binder().substs,
-                    trait_data.projection_bounds(),
-                    output,
-                );
+                if let Some(principal) = trait_data.principal() {
+                    self.push_def_path(principal.def_id(), output);
+                    self.push_type_params(
+                        principal.skip_binder().substs,
+                        trait_data.projection_bounds(),
+                        output,
+                    );
+                } else {
+                    output.push_str("dyn '_");
+                }
             },
             ty::Foreign(did) => self.push_def_path(did, output),
             ty::FnDef(..) |
diff --git a/src/librustc_traits/chalk_context/resolvent_ops.rs b/src/librustc_traits/chalk_context/resolvent_ops.rs
index f7bbf621c09..932501cc04f 100644
--- a/src/librustc_traits/chalk_context/resolvent_ops.rs
+++ b/src/librustc_traits/chalk_context/resolvent_ops.rs
@@ -17,7 +17,7 @@ use rustc::traits::{
 };
 use rustc::ty::{self, Ty};
 use rustc::ty::subst::Kind;
-use rustc::ty::relate::{self, Relate, RelateResult, TypeRelation};
+use rustc::ty::relate::{Relate, RelateResult, TypeRelation};
 use syntax_pos::DUMMY_SP;
 
 use super::{ChalkInferenceContext, ChalkArenas, ChalkExClause, ConstrainedSubst};
@@ -157,10 +157,6 @@ impl TypeRelation<'cx, 'gcx, 'tcx> for AnswerSubstitutor<'cx, 'gcx, 'tcx> {
         self.infcx.tcx
     }
 
-    fn trait_object_mode(&self) -> relate::TraitObjectMode {
-        self.infcx.trait_object_mode()
-    }
-
     fn tag(&self) -> &'static str {
         "chalk_context::answer_substitutor"
     }
diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs
index e018aa3b26d..41ecfaad86a 100644
--- a/src/librustc_typeck/astconv.rs
+++ b/src/librustc_typeck/astconv.rs
@@ -1138,13 +1138,19 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o {
         auto_traits.dedup();
 
         // Calling `skip_binder` is okay, because the predicates are re-bound.
+        let principal = if tcx.trait_is_auto(existential_principal.def_id()) {
+            ty::ExistentialPredicate::AutoTrait(existential_principal.def_id())
+        } else {
+            ty::ExistentialPredicate::Trait(*existential_principal.skip_binder())
+        };
         let mut v =
-            iter::once(ty::ExistentialPredicate::Trait(*existential_principal.skip_binder()))
+            iter::once(principal)
             .chain(auto_traits.into_iter().map(ty::ExistentialPredicate::AutoTrait))
             .chain(existential_projections
                 .map(|x| ty::ExistentialPredicate::Projection(*x.skip_binder())))
             .collect::<SmallVec<[_; 8]>>();
         v.sort_by(|a, b| a.stable_cmp(tcx, b));
+        v.dedup();
         let existential_predicates = ty::Binder::bind(tcx.mk_existential_predicates(v.into_iter()));
 
         // Use explicitly-specified region bound.
diff --git a/src/librustc_typeck/check/cast.rs b/src/librustc_typeck/check/cast.rs
index 9d418704f48..38f9adee0a4 100644
--- a/src/librustc_typeck/check/cast.rs
+++ b/src/librustc_typeck/check/cast.rs
@@ -63,7 +63,7 @@ enum PointerKind<'tcx> {
     /// No metadata attached, ie pointer to sized type or foreign type
     Thin,
     /// A trait object
-    Vtable(DefId),
+    Vtable(Option<DefId>),
     /// Slice
     Length,
     /// The unsize info of this projection
@@ -95,7 +95,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         Ok(match t.sty {
             ty::Slice(_) | ty::Str => Some(PointerKind::Length),
             ty::Dynamic(ref tty, ..) =>
-                Some(PointerKind::Vtable(tty.principal().def_id())),
+                Some(PointerKind::Vtable(tty.principal_def_id())),
             ty::Adt(def, substs) if def.is_struct() => {
                 match def.non_enum_variant().fields.last() {
                     None => Some(PointerKind::Thin),
diff --git a/src/librustc_typeck/check/closure.rs b/src/librustc_typeck/check/closure.rs
index 25b1c0836c2..ff3b22dd1de 100644
--- a/src/librustc_typeck/check/closure.rs
+++ b/src/librustc_typeck/check/closure.rs
@@ -190,7 +190,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                         self.deduce_sig_from_projection(None, &pb)
                     })
                     .next();
-                let kind = self.tcx.lang_items().fn_trait_kind(object_type.principal().def_id());
+                let kind = object_type.principal_def_id().and_then(|did| {
+                    self.tcx.lang_items().fn_trait_kind(did)
+                });
                 (sig, kind)
             }
             ty::Infer(ty::TyVar(vid)) => self.deduce_expectations_from_obligations(vid),
diff --git a/src/librustc_typeck/check/method/confirm.rs b/src/librustc_typeck/check/method/confirm.rs
index 4343f751e6a..2cf2974a45a 100644
--- a/src/librustc_typeck/check/method/confirm.rs
+++ b/src/librustc_typeck/check/method/confirm.rs
@@ -280,7 +280,11 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> {
             .include_raw_pointers()
             .filter_map(|(ty, _)|
                 match ty.sty {
-                    ty::Dynamic(ref data, ..) => Some(closure(self, ty, data.principal())),
+                    ty::Dynamic(ref data, ..) => {
+                        Some(closure(self, ty, data.principal().unwrap_or_else(|| {
+                            span_bug!(self.span, "calling trait method on empty object?")
+                        })))
+                    },
                     _ => None,
                 }
             )
diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs
index 30a868622a5..9a828ce0177 100644
--- a/src/librustc_typeck/check/method/probe.rs
+++ b/src/librustc_typeck/check/method/probe.rs
@@ -505,17 +505,18 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
 
         match self_ty.value.value.sty {
             ty::Dynamic(ref data, ..) => {
-                let p = data.principal();
-                self.fcx.probe(|_| {
-                    let InferOk { value: self_ty, obligations: _ } =
-                        self.fcx.probe_instantiate_query_response(
-                            self.span, &self.orig_steps_var_values, self_ty)
-                        .unwrap_or_else(|_| {
-                            span_bug!(self.span, "{:?} was applicable but now isn't?", self_ty)
-                        });
-                    self.assemble_inherent_candidates_from_object(self_ty);
-                });
-                self.assemble_inherent_impl_candidates_for_type(p.def_id());
+                if let Some(p) = data.principal() {
+                    self.fcx.probe(|_| {
+                        let InferOk { value: self_ty, obligations: _ } =
+                            self.fcx.probe_instantiate_query_response(
+                                self.span, &self.orig_steps_var_values, self_ty)
+                            .unwrap_or_else(|_| {
+                                span_bug!(self.span, "{:?} was applicable but now isn't?", self_ty)
+                            });
+                        self.assemble_inherent_candidates_from_object(self_ty);
+                    });
+                    self.assemble_inherent_impl_candidates_for_type(p.def_id());
+                }
             }
             ty::Adt(def, _) => {
                 self.assemble_inherent_impl_candidates_for_type(def.did);
@@ -680,10 +681,12 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
                self_ty);
 
         let principal = match self_ty.sty {
-            ty::Dynamic(ref data, ..) => data.principal(),
-            _ => span_bug!(self.span, "non-object {:?} in assemble_inherent_candidates_from_object",
-                           self_ty)
-        };
+            ty::Dynamic(ref data, ..) => Some(data),
+            _ => None
+        }.and_then(|data| data.principal()).unwrap_or_else(|| {
+            span_bug!(self.span, "non-object {:?} in assemble_inherent_candidates_from_object",
+                      self_ty)
+        });
 
         // It is illegal to invoke a method on a trait instance that
         // refers to the `Self` type. An error will be reported by
diff --git a/src/librustc_typeck/check/method/suggest.rs b/src/librustc_typeck/check/method/suggest.rs
index 98c425655d2..23bcd88d6af 100644
--- a/src/librustc_typeck/check/method/suggest.rs
+++ b/src/librustc_typeck/check/method/suggest.rs
@@ -651,7 +651,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                 ty::Adt(def, _) => def.did.is_local(),
                 ty::Foreign(did) => did.is_local(),
 
-                ty::Dynamic(ref tr, ..) => tr.principal().def_id().is_local(),
+                ty::Dynamic(ref tr, ..) =>
+                    tr.principal().map(|d| d.def_id().is_local()).unwrap_or(false),
 
                 ty::Param(_) => true,
 
diff --git a/src/librustc_typeck/coherence/inherent_impls.rs b/src/librustc_typeck/coherence/inherent_impls.rs
index b9324a17fcc..93cc86423ac 100644
--- a/src/librustc_typeck/coherence/inherent_impls.rs
+++ b/src/librustc_typeck/coherence/inherent_impls.rs
@@ -95,8 +95,8 @@ impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for InherentCollect<'a, 'tcx> {
             ty::Foreign(did) => {
                 self.check_def_id(item, did);
             }
-            ty::Dynamic(ref data, ..) => {
-                self.check_def_id(item, data.principal().def_id());
+            ty::Dynamic(ref data, ..) if data.principal_def_id().is_some() => {
+                self.check_def_id(item, data.principal_def_id().unwrap());
             }
             ty::Char => {
                 self.check_primitive_impl(def_id,
diff --git a/src/librustc_typeck/coherence/inherent_impls_overlap.rs b/src/librustc_typeck/coherence/inherent_impls_overlap.rs
index 8d27a77b29c..52dee29294c 100644
--- a/src/librustc_typeck/coherence/inherent_impls_overlap.rs
+++ b/src/librustc_typeck/coherence/inherent_impls_overlap.rs
@@ -2,9 +2,8 @@ use namespace::Namespace;
 use rustc::hir::def_id::{CrateNum, DefId, LOCAL_CRATE};
 use rustc::hir;
 use rustc::hir::itemlikevisit::ItemLikeVisitor;
-use rustc::traits::{self, IntercrateMode, FutureCompatOverlapErrorKind};
+use rustc::traits::{self, IntercrateMode};
 use rustc::ty::TyCtxt;
-use rustc::ty::relate::TraitObjectMode;
 
 use lint;
 
@@ -20,11 +19,9 @@ struct InherentOverlapChecker<'a, 'tcx: 'a> {
 }
 
 impl<'a, 'tcx> InherentOverlapChecker<'a, 'tcx> {
-    fn check_for_common_items_in_impls(
-        &self, impl1: DefId, impl2: DefId,
-        overlap: traits::OverlapResult,
-        used_to_be_allowed: Option<FutureCompatOverlapErrorKind>)
-    {
+    fn check_for_common_items_in_impls(&self, impl1: DefId, impl2: DefId,
+                                       overlap: traits::OverlapResult,
+                                       used_to_be_allowed: bool) {
 
         let name_and_namespace = |def_id| {
             let item = self.tcx.associated_item(def_id);
@@ -40,28 +37,19 @@ impl<'a, 'tcx> InherentOverlapChecker<'a, 'tcx> {
             for &item2 in &impl_items2[..] {
                 if (name, namespace) == name_and_namespace(item2) {
                     let node_id = self.tcx.hir().as_local_node_id(impl1);
-                    let mut err = match used_to_be_allowed {
-                        Some(kind) if node_id.is_some() => {
-                            let lint = match kind {
-                                FutureCompatOverlapErrorKind::Issue43355 =>
-                                    lint::builtin::INCOHERENT_FUNDAMENTAL_IMPLS,
-                                FutureCompatOverlapErrorKind::Issue33140 =>
-                                    lint::builtin::ORDER_DEPENDENT_TRAIT_OBJECTS,
-                            };
-                            self.tcx.struct_span_lint_node(
-                                lint,
-                                node_id.unwrap(),
-                                self.tcx.span_of_impl(item1).unwrap(),
-                                &format!("duplicate definitions with name `{}` (E0592)", name)
-                            )
-                        }
-                        _ => {
-                            struct_span_err!(self.tcx.sess,
-                                             self.tcx.span_of_impl(item1).unwrap(),
-                                             E0592,
-                                             "duplicate definitions with name `{}`",
-                                             name)
-                        }
+                    let mut err = if used_to_be_allowed && node_id.is_some() {
+                        self.tcx.struct_span_lint_node(
+                            lint::builtin::INCOHERENT_FUNDAMENTAL_IMPLS,
+                            node_id.unwrap(),
+                            self.tcx.span_of_impl(item1).unwrap(),
+                            &format!("duplicate definitions with name `{}` (E0592)", name)
+                        )
+                    } else {
+                        struct_span_err!(self.tcx.sess,
+                                         self.tcx.span_of_impl(item1).unwrap(),
+                                         E0592,
+                                         "duplicate definitions with name `{}`",
+                                         name)
                     };
 
                     err.span_label(self.tcx.span_of_impl(item1).unwrap(),
@@ -88,73 +76,38 @@ impl<'a, 'tcx> InherentOverlapChecker<'a, 'tcx> {
 
         for (i, &impl1_def_id) in impls.iter().enumerate() {
             for &impl2_def_id in &impls[(i + 1)..] {
-                // First, check if the impl was forbidden under the
-                // old rules. In that case, just have an error.
                 let used_to_be_allowed = traits::overlapping_impls(
                     self.tcx,
                     impl1_def_id,
                     impl2_def_id,
                     IntercrateMode::Issue43355,
-                    TraitObjectMode::NoSquash,
                     |overlap| {
                         self.check_for_common_items_in_impls(
                             impl1_def_id,
                             impl2_def_id,
                             overlap,
-                            None,
+                            false,
                         );
                         false
                     },
                     || true,
                 );
 
-                if !used_to_be_allowed {
-                    continue;
-                }
-
-                // Then, check if the impl was forbidden under only
-                // #43355. In that case, emit an #43355 error.
-                let used_to_be_allowed = traits::overlapping_impls(
-                    self.tcx,
-                    impl1_def_id,
-                    impl2_def_id,
-                    IntercrateMode::Fixed,
-                    TraitObjectMode::NoSquash,
-                    |overlap| {
-                        self.check_for_common_items_in_impls(
+                if used_to_be_allowed {
+                    traits::overlapping_impls(
+                        self.tcx,
+                        impl1_def_id,
+                        impl2_def_id,
+                        IntercrateMode::Fixed,
+                        |overlap| self.check_for_common_items_in_impls(
                             impl1_def_id,
                             impl2_def_id,
                             overlap,
-                            Some(FutureCompatOverlapErrorKind::Issue43355),
-                        );
-                        false
-                    },
-                    || true,
-                );
-
-                if !used_to_be_allowed {
-                    continue;
+                            true,
+                        ),
+                        || (),
+                    );
                 }
-
-                // Then, check if the impl was forbidden under
-                // #33140. In that case, emit a #33140 error.
-                traits::overlapping_impls(
-                    self.tcx,
-                    impl1_def_id,
-                    impl2_def_id,
-                    IntercrateMode::Fixed,
-                    TraitObjectMode::SquashAutoTraitsIssue33140,
-                    |overlap| {
-                        self.check_for_common_items_in_impls(
-                            impl1_def_id,
-                            impl2_def_id,
-                            overlap,
-                            Some(FutureCompatOverlapErrorKind::Issue33140),
-                        );
-                        false
-                    },
-                    || true,
-                );
             }
         }
     }
diff --git a/src/librustc_typeck/coherence/mod.rs b/src/librustc_typeck/coherence/mod.rs
index 060fc4977a7..ce71be07efd 100644
--- a/src/librustc_typeck/coherence/mod.rs
+++ b/src/librustc_typeck/coherence/mod.rs
@@ -171,25 +171,28 @@ fn check_impl_overlap<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, node_id: ast::NodeI
         // This is something like impl Trait1 for Trait2. Illegal
         // if Trait1 is a supertrait of Trait2 or Trait2 is not object safe.
 
-        if !tcx.is_object_safe(data.principal().def_id()) {
-            // This is an error, but it will be reported by wfcheck.  Ignore it here.
-            // This is tested by `coherence-impl-trait-for-trait-object-safe.rs`.
-        } else {
-            let mut supertrait_def_ids =
-                traits::supertrait_def_ids(tcx, data.principal().def_id());
-            if supertrait_def_ids.any(|d| d == trait_def_id) {
-                let sp = tcx.sess.source_map().def_span(tcx.span_of_impl(impl_def_id).unwrap());
-                struct_span_err!(tcx.sess,
-                                 sp,
-                                 E0371,
-                                 "the object type `{}` automatically implements the trait `{}`",
-                                 trait_ref.self_ty(),
-                                 tcx.item_path_str(trait_def_id))
-                    .span_label(sp, format!("`{}` automatically implements trait `{}`",
-                                            trait_ref.self_ty(),
-                                            tcx.item_path_str(trait_def_id)))
-                    .emit();
+        if let Some(principal_def_id) = data.principal_def_id() {
+            if !tcx.is_object_safe(principal_def_id) {
+                // This is an error, but it will be reported by wfcheck.  Ignore it here.
+                // This is tested by `coherence-impl-trait-for-trait-object-safe.rs`.
+            } else {
+                let mut supertrait_def_ids =
+                    traits::supertrait_def_ids(tcx, principal_def_id);
+                if supertrait_def_ids.any(|d| d == trait_def_id) {
+                    let sp = tcx.sess.source_map().def_span(tcx.span_of_impl(impl_def_id).unwrap());
+                    struct_span_err!(tcx.sess,
+                                     sp,
+                                     E0371,
+                                     "the object type `{}` automatically implements the trait `{}`",
+                                     trait_ref.self_ty(),
+                                     tcx.item_path_str(trait_def_id))
+                        .span_label(sp, format!("`{}` automatically implements trait `{}`",
+                                                trait_ref.self_ty(),
+                                                tcx.item_path_str(trait_def_id)))
+                        .emit();
+                }
             }
         }
+        // FIXME: also check auto-trait def-ids? (e.g. `impl Sync for Foo+Sync`)?
     }
 }
diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs
index 9fc2f11b197..e0e173901ef 100644
--- a/src/librustc_typeck/collect.rs
+++ b/src/librustc_typeck/collect.rs
@@ -1618,6 +1618,7 @@ fn predicates_defined_on<'a, 'tcx>(
             .predicates
             .extend(inferred_outlives.iter().map(|&p| (p, span)));
     }
+    debug!("predicates_defined_on({:?}) = {:?}", def_id, result);
     result
 }
 
@@ -1645,6 +1646,7 @@ fn predicates_of<'a, 'tcx>(
             .predicates
             .push((ty::TraitRef::identity(tcx, def_id).to_predicate(), span));
     }
+    debug!("predicates_of(def_id={:?}) = {:?}", def_id, result);
     result
 }
 
@@ -1972,10 +1974,12 @@ fn explicit_predicates_of<'a, 'tcx>(
         );
     }
 
-    Lrc::new(ty::GenericPredicates {
+    let result = Lrc::new(ty::GenericPredicates {
         parent: generics.parent,
         predicates,
-    })
+    });
+    debug!("explicit_predicates_of(def_id={:?}) = {:?}", def_id, result);
+    result
 }
 
 pub enum SizedByDefault {
diff --git a/src/librustc_typeck/outlives/implicit_infer.rs b/src/librustc_typeck/outlives/implicit_infer.rs
index 8929f5e5c6a..e388a3e0d0c 100644
--- a/src/librustc_typeck/outlives/implicit_infer.rs
+++ b/src/librustc_typeck/outlives/implicit_infer.rs
@@ -194,27 +194,28 @@ fn insert_required_predicates_to_be_wf<'tcx>(
                 debug!("Dynamic");
                 debug!("field_ty = {}", &field_ty);
                 debug!("ty in field = {}", &ty);
-                let ex_trait_ref = obj.principal();
-                // Here, we are passing the type `usize` as a
-                // placeholder value with the function
-                // `with_self_ty`, since there is no concrete type
-                // `Self` for a `dyn Trait` at this
-                // stage. Therefore when checking explicit
-                // predicates in `check_explicit_predicates` we
-                // need to ignore checking the explicit_map for
-                // Self type.
-                let substs = ex_trait_ref
-                    .with_self_ty(tcx, tcx.types.usize)
-                    .skip_binder()
-                    .substs;
-                check_explicit_predicates(
-                    tcx,
-                    &ex_trait_ref.skip_binder().def_id,
-                    substs,
-                    required_predicates,
-                    explicit_map,
-                    IgnoreSelfTy(true),
-                );
+                if let Some(ex_trait_ref) = obj.principal() {
+                    // Here, we are passing the type `usize` as a
+                    // placeholder value with the function
+                    // `with_self_ty`, since there is no concrete type
+                    // `Self` for a `dyn Trait` at this
+                    // stage. Therefore when checking explicit
+                    // predicates in `check_explicit_predicates` we
+                    // need to ignore checking the explicit_map for
+                    // Self type.
+                    let substs = ex_trait_ref
+                        .with_self_ty(tcx, tcx.types.usize)
+                        .skip_binder()
+                        .substs;
+                    check_explicit_predicates(
+                        tcx,
+                        &ex_trait_ref.skip_binder().def_id,
+                        substs,
+                        required_predicates,
+                        explicit_map,
+                        IgnoreSelfTy(true),
+                    );
+                }
             }
 
             ty::Projection(obj) => {
diff --git a/src/librustc_typeck/variance/constraints.rs b/src/librustc_typeck/variance/constraints.rs
index 51d89688dc2..868c1132e44 100644
--- a/src/librustc_typeck/variance/constraints.rs
+++ b/src/librustc_typeck/variance/constraints.rs
@@ -301,11 +301,12 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> {
                 let contra = self.contravariant(variance);
                 self.add_constraints_from_region(current, r, contra);
 
-                let poly_trait_ref = data
-                    .principal()
-                    .with_self_ty(self.tcx(), self.tcx().types.err);
-                self.add_constraints_from_trait_ref(
-                    current, *poly_trait_ref.skip_binder(), variance);
+                if let Some(poly_trait_ref) = data.principal() {
+                    let poly_trait_ref =
+                        poly_trait_ref.with_self_ty(self.tcx(), self.tcx().types.err);
+                    self.add_constraints_from_trait_ref(
+                        current, *poly_trait_ref.skip_binder(), variance);
+                }
 
                 for projection in data.projection_bounds() {
                     self.add_constraints_from_ty(
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index 3aa752b35ad..37c6407fbd1 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -2642,13 +2642,24 @@ impl<'tcx> Clean<Type> for Ty<'tcx> {
                 }
             }
             ty::Dynamic(ref obj, ref reg) => {
-                let principal = obj.principal();
-                let did = principal.def_id();
+                // HACK: pick the first `did` as the `did` of the trait object. Someone
+                // might want to implement "native" support for marker-trait-only
+                // trait objects.
+                let mut dids = obj.principal_def_id().into_iter().chain(obj.auto_traits());
+                let did = dids.next().unwrap_or_else(|| {
+                    panic!("found trait object `{:?}` with no traits?", self)
+                });
+                let substs = match obj.principal() {
+                    Some(principal) => principal.skip_binder().substs,
+                    // marker traits have no substs.
+                    _ => cx.tcx.intern_substs(&[])
+                };
+
                 inline::record_extern_fqn(cx, did, TypeKind::Trait);
 
                 let mut typarams = vec![];
                 reg.clean(cx).map(|b| typarams.push(GenericBound::Outlives(b)));
-                for did in obj.auto_traits() {
+                for did in dids {
                     let empty = cx.tcx.intern_substs(&[]);
                     let path = external_path(cx, &cx.tcx.item_name(did).as_str(),
                         Some(did), false, vec![], empty);
@@ -2674,7 +2685,7 @@ impl<'tcx> Clean<Type> for Ty<'tcx> {
                 }
 
                 let path = external_path(cx, &cx.tcx.item_name(did).as_str(), Some(did),
-                    false, bindings, principal.skip_binder().substs);
+                    false, bindings, substs);
                 ResolvedPath {
                     path,
                     typarams: Some(typarams),
diff --git a/src/test/run-pass/issues/issue-33140.rs b/src/test/run-pass/issues/issue-33140.rs
deleted file mode 100644
index 4d91af2fb19..00000000000
--- a/src/test/run-pass/issues/issue-33140.rs
+++ /dev/null
@@ -1,47 +0,0 @@
-#![allow(order_dependent_trait_objects)]
-
-trait Trait {
-    fn xyz() -> bool;
-}
-
-impl Trait for dyn Send + Sync {
-    fn xyz() -> bool { false }
-}
-
-impl Trait for dyn Sync + Send {
-    fn xyz() -> bool { true }
-}
-
-trait Trait2 {
-    fn uvw() -> bool;
-}
-
-impl Trait2 for dyn Send + Sync {
-    fn uvw() -> bool { false }
-}
-
-impl Trait2 for dyn Sync + Send + Sync {
-    fn uvw() -> bool { true }
-}
-
-struct Foo<T: ?Sized>(T);
-impl Foo<dyn Send + Sync> {
-    fn abc() -> bool {
-        false
-    }
-}
-
-impl Foo<dyn Sync + Send> {
-    fn abc() -> bool {
-        true
-    }
-}
-
-fn main() {
-    assert_eq!(<dyn Send+Sync>::xyz(), false);
-    assert_eq!(<dyn Sync+Send>::xyz(), true);
-    assert_eq!(<dyn Send+Sync>::uvw(), false);
-    assert_eq!(<dyn Sync+Send+Sync>::uvw(), true);
-    assert_eq!(<Foo<dyn Send+Sync>>::abc(), false);
-    assert_eq!(<Foo<dyn Sync+Send>>::abc(), true);
-}
diff --git a/src/test/run-pass/traits/principal-less-trait-objects.rs b/src/test/run-pass/traits/principal-less-trait-objects.rs
new file mode 100644
index 00000000000..0984362993c
--- /dev/null
+++ b/src/test/run-pass/traits/principal-less-trait-objects.rs
@@ -0,0 +1,41 @@
+// Check that trait-objects without a principal codegen properly.
+
+use std::sync::atomic::{AtomicUsize, Ordering};
+use std::mem;
+
+// Array is to make sure the size is not exactly pointer-size, so
+// we can be sure we are measuring the right size in the
+// `size_of_val` test.
+struct SetOnDrop<'a>(&'a AtomicUsize, [u8; 64]);
+impl<'a> Drop for SetOnDrop<'a> {
+    fn drop(&mut self) {
+        self.0.store(self.0.load(Ordering::Relaxed)+1, Ordering::Relaxed);
+    }
+}
+
+trait TypeEq<V: ?Sized> {}
+impl<T: ?Sized> TypeEq<T> for T {}
+fn assert_types_eq<U: ?Sized, V: ?Sized>() where U: TypeEq<V> {}
+
+fn main() {
+    // Check that different ways of writing the same type are equal.
+    assert_types_eq::<dyn Sync, dyn Sync + Sync>();
+    assert_types_eq::<dyn Sync + Send, dyn Send + Sync>();
+    assert_types_eq::<dyn Sync + Send + Sync, dyn Send + Sync>();
+
+    // Check that codegen works.
+    //
+    // Using `AtomicUsize` here because `Cell<u32>` is not `Sync`, and
+    // so can't be made into a `Box<dyn Sync>`.
+    let c = AtomicUsize::new(0);
+    {
+        let d: Box<dyn Sync> = Box::new(SetOnDrop(&c, [0; 64]));
+
+        assert_eq!(mem::size_of_val(&*d),
+                   mem::size_of::<SetOnDrop>());
+        assert_eq!(mem::align_of_val(&*d),
+                   mem::align_of::<SetOnDrop>());
+        assert_eq!(c.load(Ordering::Relaxed), 0);
+    }
+    assert_eq!(c.load(Ordering::Relaxed), 1);
+}
diff --git a/src/test/ui/issues/issue-33140-hack-boundaries.rs b/src/test/ui/issues/issue-33140-hack-boundaries.rs
new file mode 100644
index 00000000000..fbdef51c132
--- /dev/null
+++ b/src/test/ui/issues/issue-33140-hack-boundaries.rs
@@ -0,0 +1,80 @@
+#![feature(optin_builtin_traits)]
+#![allow(order_dependent_trait_objects)]
+
+// Check that the issue #33140 hack does not allow unintended things.
+
+// OK
+trait Trait0 {
+}
+
+impl Trait0 for dyn Send {}
+impl Trait0 for dyn Send {}
+
+// Problem 1: associated types
+trait Trait1 {
+    fn my_fn(&self) {}
+}
+
+impl Trait1 for dyn Send {}
+impl Trait1 for dyn Send {}
+//~^ ERROR E0119
+
+// Problem 2: negative impl
+trait Trait2 {
+}
+
+impl Trait2 for dyn Send {}
+impl !Trait2 for dyn Send {}
+//~^ ERROR E0119
+
+
+// Problem 3: type parameter
+trait Trait3<T: ?Sized> {
+}
+
+impl Trait3<dyn Sync> for dyn Send {}
+impl Trait3<dyn Sync> for dyn Send {}
+//~^ ERROR E0119
+
+// Problem 4a: not a trait object - generic
+trait Trait4a {
+}
+
+impl<T: ?Sized> Trait4a for T {}
+impl Trait4a for dyn Send {}
+//~^ ERROR E0119
+
+// Problem 4b: not a trait object - misc
+trait Trait4b {
+}
+
+impl Trait4b for () {}
+impl Trait4b for () {}
+//~^ ERROR E0119
+
+// Problem 4c: not a principal-less trait object
+trait Trait4c {
+}
+
+impl Trait4c for dyn Trait1 + Send {}
+impl Trait4c for dyn Trait1 + Send {}
+//~^ ERROR E0119
+
+// Problem 4d: lifetimes
+trait Trait4d {
+}
+
+impl<'a> Trait4d for dyn Send + 'a {}
+impl<'a> Trait4d for dyn Send + 'a {}
+//~^ ERROR E0119
+
+
+// Problem 5: where-clauses
+trait Trait5 {
+}
+
+impl Trait5 for dyn Send {}
+impl Trait5 for dyn Send where u32: Copy {}
+//~^ ERROR E0119
+
+fn main() {}
diff --git a/src/test/ui/issues/issue-33140-hack-boundaries.stderr b/src/test/ui/issues/issue-33140-hack-boundaries.stderr
new file mode 100644
index 00000000000..95aaa55ba7c
--- /dev/null
+++ b/src/test/ui/issues/issue-33140-hack-boundaries.stderr
@@ -0,0 +1,67 @@
+error[E0119]: conflicting implementations of trait `Trait1` for type `(dyn std::marker::Send + 'static)`:
+  --> $DIR/issue-33140-hack-boundaries.rs:19:1
+   |
+LL | impl Trait1 for dyn Send {}
+   | ------------------------ first implementation here
+LL | impl Trait1 for dyn Send {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `(dyn std::marker::Send + 'static)`
+
+error[E0119]: conflicting implementations of trait `Trait2` for type `(dyn std::marker::Send + 'static)`:
+  --> $DIR/issue-33140-hack-boundaries.rs:27:1
+   |
+LL | impl Trait2 for dyn Send {}
+   | ------------------------ first implementation here
+LL | impl !Trait2 for dyn Send {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `(dyn std::marker::Send + 'static)`
+
+error[E0119]: conflicting implementations of trait `Trait3<(dyn std::marker::Sync + 'static)>` for type `(dyn std::marker::Send + 'static)`:
+  --> $DIR/issue-33140-hack-boundaries.rs:36:1
+   |
+LL | impl Trait3<dyn Sync> for dyn Send {}
+   | ---------------------------------- first implementation here
+LL | impl Trait3<dyn Sync> for dyn Send {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `(dyn std::marker::Send + 'static)`
+
+error[E0119]: conflicting implementations of trait `Trait4a` for type `(dyn std::marker::Send + 'static)`:
+  --> $DIR/issue-33140-hack-boundaries.rs:44:1
+   |
+LL | impl<T: ?Sized> Trait4a for T {}
+   | ----------------------------- first implementation here
+LL | impl Trait4a for dyn Send {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `(dyn std::marker::Send + 'static)`
+
+error[E0119]: conflicting implementations of trait `Trait4b` for type `()`:
+  --> $DIR/issue-33140-hack-boundaries.rs:52:1
+   |
+LL | impl Trait4b for () {}
+   | ------------------- first implementation here
+LL | impl Trait4b for () {}
+   | ^^^^^^^^^^^^^^^^^^^ conflicting implementation for `()`
+
+error[E0119]: conflicting implementations of trait `Trait4c` for type `(dyn Trait1 + std::marker::Send + 'static)`:
+  --> $DIR/issue-33140-hack-boundaries.rs:60:1
+   |
+LL | impl Trait4c for dyn Trait1 + Send {}
+   | ---------------------------------- first implementation here
+LL | impl Trait4c for dyn Trait1 + Send {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `(dyn Trait1 + std::marker::Send + 'static)`
+
+error[E0119]: conflicting implementations of trait `Trait4d` for type `dyn std::marker::Send`:
+  --> $DIR/issue-33140-hack-boundaries.rs:68:1
+   |
+LL | impl<'a> Trait4d for dyn Send + 'a {}
+   | ---------------------------------- first implementation here
+LL | impl<'a> Trait4d for dyn Send + 'a {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `dyn std::marker::Send`
+
+error[E0119]: conflicting implementations of trait `Trait5` for type `(dyn std::marker::Send + 'static)`:
+  --> $DIR/issue-33140-hack-boundaries.rs:77:1
+   |
+LL | impl Trait5 for dyn Send {}
+   | ------------------------ first implementation here
+LL | impl Trait5 for dyn Send where u32: Copy {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `(dyn std::marker::Send + 'static)`
+
+error: aborting due to 8 previous errors
+
+For more information about this error, try `rustc --explain E0119`.
diff --git a/src/test/ui/issues/issue-33140-traitobject-crate.rs b/src/test/ui/issues/issue-33140-traitobject-crate.rs
new file mode 100644
index 00000000000..2b644817df1
--- /dev/null
+++ b/src/test/ui/issues/issue-33140-traitobject-crate.rs
@@ -0,0 +1,101 @@
+// compile-pass
+
+#![warn(order_dependent_trait_objects)]
+
+// Check that traitobject 0.1.0 compiles
+
+//! # traitobject
+//!
+//! Unsafe helpers for working with raw TraitObjects.
+
+/// A trait implemented for all trait objects.
+///
+/// Implementations for all traits in std are provided.
+pub unsafe trait Trait {}
+
+unsafe impl Trait for ::std::any::Any + Send { }
+unsafe impl Trait for ::std::any::Any + Sync { }
+unsafe impl Trait for ::std::any::Any + Send + Sync { }
+unsafe impl<T: ?Sized> Trait for ::std::borrow::Borrow<T> + Send { }
+unsafe impl<T: ?Sized> Trait for ::std::borrow::Borrow<T> + Sync { }
+unsafe impl<T: ?Sized> Trait for ::std::borrow::Borrow<T> + Send + Sync { }
+unsafe impl<T: ?Sized> Trait for ::std::borrow::BorrowMut<T> + Send { }
+unsafe impl<T: ?Sized> Trait for ::std::borrow::BorrowMut<T> + Sync { }
+unsafe impl<T: ?Sized> Trait for ::std::borrow::BorrowMut<T> + Send + Sync { }
+unsafe impl<T: ?Sized> Trait for ::std::convert::AsMut<T> + Send { }
+unsafe impl<T: ?Sized> Trait for ::std::convert::AsMut<T> + Sync { }
+unsafe impl<T: ?Sized> Trait for ::std::convert::AsMut<T> + Send + Sync { }
+unsafe impl<T: ?Sized> Trait for ::std::convert::AsRef<T> + Send { }
+unsafe impl<T: ?Sized> Trait for ::std::convert::AsRef<T> + Sync { }
+unsafe impl<T: ?Sized> Trait for ::std::convert::AsRef<T> + Send + Sync { }
+unsafe impl Trait for ::std::error::Error + Send { }
+unsafe impl Trait for ::std::error::Error + Sync { }
+unsafe impl Trait for ::std::error::Error + Send + Sync { }
+unsafe impl Trait for ::std::fmt::Binary + Send { }
+unsafe impl Trait for ::std::fmt::Binary + Sync { }
+unsafe impl Trait for ::std::fmt::Binary + Send + Sync { }
+unsafe impl Trait for ::std::fmt::Debug + Send { }
+unsafe impl Trait for ::std::fmt::Debug + Sync { }
+unsafe impl Trait for ::std::fmt::Debug + Send + Sync { }
+unsafe impl Trait for ::std::fmt::Display + Send { }
+unsafe impl Trait for ::std::fmt::Display + Sync { }
+unsafe impl Trait for ::std::fmt::Display + Send + Sync { }
+unsafe impl Trait for ::std::fmt::LowerExp + Send { }
+unsafe impl Trait for ::std::fmt::LowerExp + Sync { }
+unsafe impl Trait for ::std::fmt::LowerExp + Send + Sync { }
+unsafe impl Trait for ::std::fmt::LowerHex + Send { }
+unsafe impl Trait for ::std::fmt::LowerHex + Sync { }
+unsafe impl Trait for ::std::fmt::LowerHex + Send + Sync { }
+unsafe impl Trait for ::std::fmt::Octal + Send { }
+unsafe impl Trait for ::std::fmt::Octal + Sync { }
+unsafe impl Trait for ::std::fmt::Octal + Send + Sync { }
+unsafe impl Trait for ::std::fmt::Pointer + Send { }
+unsafe impl Trait for ::std::fmt::Pointer + Sync { }
+unsafe impl Trait for ::std::fmt::Pointer + Send + Sync { }
+unsafe impl Trait for ::std::fmt::UpperExp + Send { }
+unsafe impl Trait for ::std::fmt::UpperExp + Sync { }
+unsafe impl Trait for ::std::fmt::UpperExp + Send + Sync { }
+unsafe impl Trait for ::std::fmt::UpperHex + Send { }
+unsafe impl Trait for ::std::fmt::UpperHex + Sync { }
+unsafe impl Trait for ::std::fmt::UpperHex + Send + Sync { }
+unsafe impl Trait for ::std::fmt::Write + Send { }
+unsafe impl Trait for ::std::fmt::Write + Sync { }
+unsafe impl Trait for ::std::fmt::Write + Send + Sync { }
+unsafe impl Trait for ::std::hash::Hasher + Send { }
+unsafe impl Trait for ::std::hash::Hasher + Sync { }
+unsafe impl Trait for ::std::hash::Hasher + Send + Sync { }
+unsafe impl Trait for ::std::io::BufRead + Send { }
+unsafe impl Trait for ::std::io::BufRead + Sync { }
+unsafe impl Trait for ::std::io::BufRead + Send + Sync { }
+unsafe impl Trait for ::std::io::Read + Send { }
+unsafe impl Trait for ::std::io::Read + Sync { }
+unsafe impl Trait for ::std::io::Read + Send + Sync { }
+unsafe impl Trait for ::std::io::Seek + Send { }
+unsafe impl Trait for ::std::io::Seek + Sync { }
+unsafe impl Trait for ::std::io::Seek + Send + Sync { }
+unsafe impl Trait for ::std::io::Write + Send { }
+unsafe impl Trait for ::std::io::Write + Sync { }
+unsafe impl Trait for ::std::io::Write + Send + Sync { }
+unsafe impl<T, I> Trait for ::std::iter::IntoIterator<IntoIter=I, Item=T> { }
+unsafe impl<T> Trait for ::std::iter::Iterator<Item=T> + Send { }
+unsafe impl<T> Trait for ::std::iter::Iterator<Item=T> + Sync { }
+unsafe impl<T> Trait for ::std::iter::Iterator<Item=T> + Send + Sync { }
+unsafe impl Trait for ::std::marker::Send + Send { }
+unsafe impl Trait for ::std::marker::Send + Sync { }
+unsafe impl Trait for ::std::marker::Send + Send + Sync { }
+unsafe impl Trait for ::std::marker::Sync + Send { }
+unsafe impl Trait for ::std::marker::Sync + Sync { }
+unsafe impl Trait for ::std::marker::Sync + Send + Sync { }
+unsafe impl Trait for ::std::ops::Drop + Send { }
+unsafe impl Trait for ::std::ops::Drop + Sync { }
+unsafe impl Trait for ::std::ops::Drop + Send + Sync { }
+unsafe impl Trait for ::std::string::ToString + Send { }
+unsafe impl Trait for ::std::string::ToString + Sync { }
+unsafe impl Trait for ::std::string::ToString + Send + Sync { }
+fn assert_trait<T: Trait + ?Sized>() {}
+
+fn main() {
+    assert_trait::<dyn Send>();
+    assert_trait::<dyn Sync>();
+    assert_trait::<dyn Send + Sync>();
+}
diff --git a/src/test/ui/issues/issue-33140-traitobject-crate.stderr b/src/test/ui/issues/issue-33140-traitobject-crate.stderr
new file mode 100644
index 00000000000..6f71e79d0ee
--- /dev/null
+++ b/src/test/ui/issues/issue-33140-traitobject-crate.stderr
@@ -0,0 +1,39 @@
+warning: conflicting implementations of trait `Trait` for type `(dyn std::marker::Send + std::marker::Sync + 'static)`: (E0119)
+  --> $DIR/issue-33140-traitobject-crate.rs:85:1
+   |
+LL | unsafe impl Trait for ::std::marker::Send + Sync { }
+   | ------------------------------------------------ first implementation here
+LL | unsafe impl Trait for ::std::marker::Send + Send + Sync { }
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `(dyn std::marker::Send + std::marker::Sync + 'static)`
+   |
+note: lint level defined here
+  --> $DIR/issue-33140-traitobject-crate.rs:3:9
+   |
+LL | #![warn(order_dependent_trait_objects)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   = 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 #56484 <https://github.com/rust-lang/rust/issues/56484>
+
+warning: conflicting implementations of trait `Trait` for type `(dyn std::marker::Send + std::marker::Sync + 'static)`: (E0119)
+  --> $DIR/issue-33140-traitobject-crate.rs:86:1
+   |
+LL | unsafe impl Trait for ::std::marker::Send + Send + Sync { }
+   | ------------------------------------------------------- first implementation here
+LL | unsafe impl Trait for ::std::marker::Sync + Send { }
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `(dyn std::marker::Send + std::marker::Sync + 'static)`
+   |
+   = 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 #56484 <https://github.com/rust-lang/rust/issues/56484>
+
+warning: conflicting implementations of trait `Trait` for type `(dyn std::marker::Send + std::marker::Sync + 'static)`: (E0119)
+  --> $DIR/issue-33140-traitobject-crate.rs:88:1
+   |
+LL | unsafe impl Trait for ::std::marker::Sync + Send { }
+   | ------------------------------------------------ first implementation here
+LL | unsafe impl Trait for ::std::marker::Sync + Sync { }
+LL | unsafe impl Trait for ::std::marker::Sync + Send + Sync { }
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `(dyn std::marker::Send + std::marker::Sync + 'static)`
+   |
+   = 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 #56484 <https://github.com/rust-lang/rust/issues/56484>
+
diff --git a/src/test/ui/issues/issue-33140.rs b/src/test/ui/issues/issue-33140.rs
index 8d19248d5e0..930e24218ac 100644
--- a/src/test/ui/issues/issue-33140.rs
+++ b/src/test/ui/issues/issue-33140.rs
@@ -1,5 +1,3 @@
-#![deny(order_dependent_trait_objects)]
-
 trait Trait {
     fn xyz() -> bool;
 }
@@ -10,7 +8,6 @@ impl Trait for dyn Send + Sync {
 
 impl Trait for dyn Sync + Send {
 //~^ ERROR conflicting implementations
-//~| hard error
     fn xyz() -> bool { true }
 }
 
@@ -24,14 +21,12 @@ impl Trait2 for dyn Send + Sync {
 
 impl Trait2 for dyn Sync + Send + Sync {
 //~^ ERROR conflicting implementations
-//~| hard error
     fn uvw() -> bool { true }
 }
 
 struct Foo<T: ?Sized>(T);
 impl Foo<dyn Send + Sync> {
     fn abc() -> bool { //~ ERROR duplicate definitions with name `abc`
-                       //~| hard error
         false
     }
 }
diff --git a/src/test/ui/issues/issue-33140.stderr b/src/test/ui/issues/issue-33140.stderr
index 520921a7512..e2631e971c5 100644
--- a/src/test/ui/issues/issue-33140.stderr
+++ b/src/test/ui/issues/issue-33140.stderr
@@ -1,37 +1,25 @@
-error: conflicting implementations of trait `Trait` for type `(dyn std::marker::Send + std::marker::Sync + 'static)`: (E0119)
-  --> $DIR/issue-33140.rs:11:1
+error[E0119]: conflicting implementations of trait `Trait` for type `(dyn std::marker::Send + std::marker::Sync + 'static)`:
+  --> $DIR/issue-33140.rs:9:1
    |
 LL | impl Trait for dyn Send + Sync {
    | ------------------------------ first implementation here
 ...
 LL | impl Trait for dyn Sync + Send {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `(dyn std::marker::Send + std::marker::Sync + 'static)`
-   |
-note: lint level defined here
-  --> $DIR/issue-33140.rs:1:9
-   |
-LL | #![deny(order_dependent_trait_objects)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   = 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 #56484 <https://github.com/rust-lang/rust/issues/56484>
 
-error: conflicting implementations of trait `Trait2` for type `(dyn std::marker::Send + std::marker::Sync + 'static)`: (E0119)
-  --> $DIR/issue-33140.rs:25:1
+error[E0119]: conflicting implementations of trait `Trait2` for type `(dyn std::marker::Send + std::marker::Sync + 'static)`:
+  --> $DIR/issue-33140.rs:22:1
    |
 LL | impl Trait2 for dyn Send + Sync {
    | ------------------------------- first implementation here
 ...
 LL | impl Trait2 for dyn Sync + Send + Sync {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `(dyn std::marker::Send + std::marker::Sync + 'static)`
-   |
-   = 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 #56484 <https://github.com/rust-lang/rust/issues/56484>
 
-error: duplicate definitions with name `abc` (E0592)
-  --> $DIR/issue-33140.rs:33:5
+error[E0592]: duplicate definitions with name `abc`
+  --> $DIR/issue-33140.rs:29:5
    |
 LL | /     fn abc() -> bool { //~ ERROR duplicate definitions with name `abc`
-LL | |                        //~| hard error
 LL | |         false
 LL | |     }
    | |_____^ duplicate definitions for `abc`
@@ -40,9 +28,8 @@ LL | /     fn abc() -> bool {
 LL | |         true
 LL | |     }
    | |_____- other definition for `abc`
-   |
-   = 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 #56484 <https://github.com/rust-lang/rust/issues/56484>
 
 error: aborting due to 3 previous errors
 
+Some errors occurred: E0119, E0592.
+For more information about an error, try `rustc --explain E0119`.
diff --git a/src/test/ui/issues/issue-57162.rs b/src/test/ui/issues/issue-57162.rs
new file mode 100644
index 00000000000..abe0887e927
--- /dev/null
+++ b/src/test/ui/issues/issue-57162.rs
@@ -0,0 +1,7 @@
+// compile-pass
+
+trait Foo {}
+impl Foo for dyn Send {}
+
+impl<T: Sync + Sync> Foo for T {}
+fn main() {}