about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2019-05-22 08:22:17 +0000
committerbors <bors@rust-lang.org>2019-05-22 08:22:17 +0000
commit37ff5d388f8c004ca248adb635f1cc84d347eda0 (patch)
tree460137db1b121095313303ae6c78f2698bd15159 /src
parent1cc822c261f5c94a41eb725755fdda7ca6efbda2 (diff)
parentce2ee305f9165c037ecddddb5792588a15ff6c37 (diff)
Auto merge of #59445 - alexreg:ban-multi-trait-objects-via-aliases, r=oli-obk
Ban multi-trait objects via trait aliases

Obviously, multi-trait objects are not normally supported, so they should not be supported via trait aliases.

This has been factored out from the previous PR https://github.com/rust-lang/rust/pull/55994 (see point 1).

r? @Centril

CC @nikomatsakis

------------------

### RELNOTES:

We now allow `dyn Send + fmt::Debug` with equivalent semantics to `dyn fmt::Debug + Send`.
That is, the order of the mentioned traits does not matter wrt. principal/not-principal traits.
This is a small change that might deserve a mention in the blog post because it is a language change but most likely not.

See https://github.com/rust-lang/rust/blob/ce2ee305f9165c037ecddddb5792588a15ff6c37/src/test/ui/traits/wf-trait-object-reverse-order.rs.

// @Centril
Diffstat (limited to 'src')
-rw-r--r--src/liballoc/slice.rs8
-rw-r--r--src/librustc/hir/map/mod.rs2
-rw-r--r--src/librustc/hir/mod.rs8
-rw-r--r--src/librustc/query/mod.rs42
-rw-r--r--src/librustc/traits/mod.rs8
-rw-r--r--src/librustc/traits/select.rs3
-rw-r--r--src/librustc/traits/util.rs308
-rw-r--r--src/librustc/ty/mod.rs14
-rw-r--r--src/librustc/ty/query/mod.rs3
-rw-r--r--src/librustc_mir/borrow_check/error_reporting.rs1
-rw-r--r--src/librustc_save_analysis/dump_visitor.rs6
-rw-r--r--src/librustc_typeck/astconv.rs211
-rw-r--r--src/librustc_typeck/check/method/probe.rs2
-rw-r--r--src/librustc_typeck/check/wfcheck.rs2
-rw-r--r--src/librustc_typeck/collect.rs14
-rw-r--r--src/libsyntax/ast.rs4
-rw-r--r--src/test/ui/associated-types/associated-types-overridden-binding-2.stderr2
-rw-r--r--src/test/ui/bad/bad-sized.stderr7
-rw-r--r--src/test/ui/error-codes/E0225.rs8
-rw-r--r--src/test/ui/error-codes/E0225.stderr27
-rw-r--r--src/test/ui/issues/issue-22560.stderr28
-rw-r--r--src/test/ui/issues/issue-32963.stderr7
-rw-r--r--src/test/ui/maybe-bounds.rs9
-rw-r--r--src/test/ui/maybe-bounds.stderr12
-rw-r--r--src/test/ui/parser/trait-object-trait-parens.rs4
-rw-r--r--src/test/ui/traits/trait-alias-object.rs9
-rw-r--r--src/test/ui/traits/trait-alias/auxiliary/trait_alias.rs (renamed from src/test/ui/traits/auxiliary/trait_alias.rs)0
-rw-r--r--src/test/ui/traits/trait-alias/trait-alias-bounds.rs (renamed from src/test/run-pass/traits/trait-alias-bounds.rs)2
-rw-r--r--src/test/ui/traits/trait-alias/trait-alias-cross-crate.rs (renamed from src/test/ui/traits/trait-alias-cross-crate.rs)0
-rw-r--r--src/test/ui/traits/trait-alias/trait-alias-cross-crate.stderr (renamed from src/test/ui/traits/trait-alias-cross-crate.stderr)0
-rw-r--r--src/test/ui/traits/trait-alias/trait-alias-impl.rs (renamed from src/test/ui/traits/trait-alias-impl.rs)0
-rw-r--r--src/test/ui/traits/trait-alias/trait-alias-impl.stderr (renamed from src/test/ui/traits/trait-alias-impl.stderr)0
-rw-r--r--src/test/ui/traits/trait-alias/trait-alias-maybe-bound.rs29
-rw-r--r--src/test/ui/traits/trait-alias/trait-alias-no-duplicates.rs126
-rw-r--r--src/test/ui/traits/trait-alias/trait-alias-no-duplicates.stderr458
-rw-r--r--src/test/ui/traits/trait-alias/trait-alias-no-extra-traits.rs121
-rw-r--r--src/test/ui/traits/trait-alias/trait-alias-no-extra-traits.stderr513
-rw-r--r--src/test/ui/traits/trait-alias/trait-alias-object-fail.rs11
-rw-r--r--src/test/ui/traits/trait-alias/trait-alias-object-fail.stderr (renamed from src/test/ui/traits/trait-alias-object.stderr)8
-rw-r--r--src/test/ui/traits/trait-alias/trait-alias-object-wf.rs85
-rw-r--r--src/test/ui/traits/trait-alias/trait-alias-object.rs (renamed from src/test/run-pass/traits/trait-alias-object.rs)2
-rw-r--r--src/test/ui/traits/trait-alias/trait-alias-only-maybe-bound.rs22
-rw-r--r--src/test/ui/traits/trait-alias/trait-alias-only-maybe-bound.stderr14
-rw-r--r--src/test/ui/traits/trait-alias/trait-alias-syntax-fail.rs (renamed from src/test/ui/traits/trait-alias-syntax.rs)0
-rw-r--r--src/test/ui/traits/trait-alias/trait-alias-syntax-fail.stderr (renamed from src/test/ui/traits/trait-alias-syntax.stderr)4
-rw-r--r--src/test/ui/traits/trait-alias/trait-alias-syntax.rs (renamed from src/test/run-pass/traits/trait-alias-syntax.rs)2
-rw-r--r--src/test/ui/traits/trait-alias/trait-alias-wf.rs (renamed from src/test/ui/traits/trait-alias-wf.rs)0
-rw-r--r--src/test/ui/traits/trait-alias/trait-alias-wf.stderr (renamed from src/test/ui/traits/trait-alias-wf.stderr)0
-rw-r--r--src/test/ui/traits/trait-alias/trait-alias.rs (renamed from src/test/ui/run-pass/traits/trait-alias.rs)1
-rw-r--r--src/test/ui/traits/traits-static-outlives-a-where-clause.rs (renamed from src/test/ui/run-pass/traits/traits-static-outlives-a-where-clause.rs)0
-rw-r--r--src/test/ui/traits/wf-trait-object-maybe-bound.rs20
-rw-r--r--src/test/ui/traits/wf-trait-object-maybe-bound.stderr32
-rw-r--r--src/test/ui/traits/wf-trait-object-no-duplicates.rs33
-rw-r--r--src/test/ui/traits/wf-trait-object-no-duplicates.stderr58
-rw-r--r--src/test/ui/traits/wf-trait-object-only-maybe-bound.rs7
-rw-r--r--src/test/ui/traits/wf-trait-object-only-maybe-bound.stderr14
-rw-r--r--src/test/ui/traits/wf-trait-object-reverse-order.rs15
57 files changed, 2032 insertions, 294 deletions
diff --git a/src/liballoc/slice.rs b/src/liballoc/slice.rs
index 6eac8487401..8768f1ff081 100644
--- a/src/liballoc/slice.rs
+++ b/src/liballoc/slice.rs
@@ -123,12 +123,12 @@ pub use core::slice::{RChunks, RChunksMut, RChunksExact, RChunksExactMut};
 ////////////////////////////////////////////////////////////////////////////////
 
 // HACK(japaric) needed for the implementation of `vec!` macro during testing
-// NB see the hack module in this file for more details
+// N.B., see the `hack` module in this file for more details.
 #[cfg(test)]
 pub use hack::into_vec;
 
 // HACK(japaric) needed for the implementation of `Vec::clone` during testing
-// NB see the hack module in this file for more details
+// N.B., see the `hack` module in this file for more details.
 #[cfg(test)]
 pub use hack::to_vec;
 
@@ -376,7 +376,7 @@ impl<T> [T] {
     pub fn to_vec(&self) -> Vec<T>
         where T: Clone
     {
-        // NB see hack module in this file
+        // N.B., see the `hack` module in this file for more details.
         hack::to_vec(self)
     }
 
@@ -397,7 +397,7 @@ impl<T> [T] {
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
     pub fn into_vec(self: Box<Self>) -> Vec<T> {
-        // NB see hack module in this file
+        // N.B., see the `hack` module in this file for more details.
         hack::into_vec(self)
     }
 
diff --git a/src/librustc/hir/map/mod.rs b/src/librustc/hir/map/mod.rs
index 4b94f772554..23f4d208571 100644
--- a/src/librustc/hir/map/mod.rs
+++ b/src/librustc/hir/map/mod.rs
@@ -957,7 +957,7 @@ impl<'hir> Map<'hir> {
         }
     }
 
-    /// Returns the name associated with the given NodeId's AST.
+    /// Returns the name associated with the given `NodeId`'s AST.
     pub fn name(&self, id: NodeId) -> Name {
         let hir_id = self.node_to_hir_id(id);
         self.name_by_hir_id(hir_id)
diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs
index 57304c5ed37..d2b926d1886 100644
--- a/src/librustc/hir/mod.rs
+++ b/src/librustc/hir/mod.rs
@@ -2143,11 +2143,11 @@ pub enum UseKind {
     ListStem,
 }
 
-/// TraitRef's appear in impls.
+/// References to traits in impls.
 ///
-/// resolve maps each TraitRef's ref_id to its defining trait; that's all
-/// that the ref_id is for. Note that ref_id's value is not the NodeId of the
-/// trait being referred to but just a unique NodeId that serves as a key
+/// `resolve` maps each `TraitRef`'s `ref_id` to its defining trait; that's all
+/// that the `ref_id` is for. Note that `ref_id`'s value is not the `NodeId` of the
+/// trait being referred to but just a unique `NodeId` that serves as a key
 /// within the resolution map.
 #[derive(Clone, RustcEncodable, RustcDecodable, Debug, HashStable)]
 pub struct TraitRef {
diff --git a/src/librustc/query/mod.rs b/src/librustc/query/mod.rs
index 2fff4c3f109..8825c94cdb8 100644
--- a/src/librustc/query/mod.rs
+++ b/src/librustc/query/mod.rs
@@ -168,7 +168,7 @@ rustc_queries! {
         query predicates_defined_on(_: DefId)
             -> Lrc<ty::GenericPredicates<'tcx>> {}
 
-        /// Returns the predicates written explicit by the user.
+        /// Returns the predicates written explicitly by the user.
         query explicit_predicates_of(_: DefId)
             -> Lrc<ty::GenericPredicates<'tcx>> {}
 
@@ -216,9 +216,9 @@ rustc_queries! {
             _: DefId
         ) -> Result<DtorckConstraint<'tcx>, NoSolution> {}
 
-        /// True if this is a const fn, use the `is_const_fn` to know whether your crate actually
-        /// sees it as const fn (e.g., the const-fn-ness might be unstable and you might not have
-        /// the feature gate active)
+        /// Returns `true` if this is a const fn, use the `is_const_fn` to know whether your crate
+        /// actually sees it as const fn (e.g., the const-fn-ness might be unstable and you might
+        /// not have the feature gate active).
         ///
         /// **Do not call this function manually.** It is only meant to cache the base data for the
         /// `is_const_fn` function.
@@ -226,7 +226,7 @@ rustc_queries! {
             desc { |tcx| "checking if item is const fn: `{}`", tcx.def_path_str(key) }
         }
 
-        /// Returns true if calls to the function may be promoted
+        /// Returns `true` if calls to the function may be promoted.
         ///
         /// This is either because the function is e.g., a tuple-struct or tuple-variant
         /// constructor, or because it has the `#[rustc_promotable]` attribute. The attribute should
@@ -237,25 +237,23 @@ rustc_queries! {
 
         query const_fn_is_allowed_fn_ptr(_: DefId) -> bool {}
 
-        /// True if this is a foreign item (i.e., linked via `extern { ... }`).
+        /// Returns `true` if this is a foreign item (i.e., linked via `extern { ... }`).
         query is_foreign_item(_: DefId) -> bool {}
 
         /// Returns `Some(mutability)` if the node pointed to by `def_id` is a static item.
         query static_mutability(_: DefId) -> Option<hir::Mutability> {}
 
-        /// Get a map with the variance of every item; use `item_variance`
-        /// instead.
+        /// Gets a map with the variance of every item; use `item_variance` instead.
         query crate_variances(_: CrateNum) -> Lrc<ty::CrateVariancesMap<'tcx>> {
             desc { "computing the variances for items in this crate" }
         }
 
-        /// Maps from def-id of a type or region parameter to its
-        /// (inferred) variance.
+        /// Maps from the `DefId` of a type or region parameter to its (inferred) variance.
         query variances_of(_: DefId) -> &'tcx [ty::Variance] {}
     }
 
     TypeChecking {
-        /// Maps from def-id of a type to its (inferred) outlives.
+        /// Maps from thee `DefId` of a type to its (inferred) outlives.
         query inferred_outlives_crate(_: CrateNum)
             -> Lrc<ty::CratePredicatesMap<'tcx>> {
             desc { "computing the inferred outlives predicates for items in this crate" }
@@ -263,10 +261,10 @@ rustc_queries! {
     }
 
     Other {
-        /// Maps from an impl/trait def-id to a list of the def-ids of its items
+        /// Maps from an impl/trait `DefId to a list of the `DefId`s of its items.
         query associated_item_def_ids(_: DefId) -> Lrc<Vec<DefId>> {}
 
-        /// Maps from a trait item to the trait item "descriptor"
+        /// Maps from a trait item to the trait item "descriptor".
         query associated_item(_: DefId) -> ty::AssociatedItem {}
 
         query impl_trait_ref(_: DefId) -> Option<ty::TraitRef<'tcx>> {}
@@ -276,7 +274,7 @@ rustc_queries! {
     }
 
     TypeChecking {
-        /// Maps a DefId of a type to a list of its inherent impls.
+        /// Maps a `DefId` of a type to a list of its inherent impls.
         /// Contains implementations of methods that are inherent to a type.
         /// Methods in these implementations don't need to be exported.
         query inherent_impls(_: DefId) -> Lrc<Vec<DefId>> {
@@ -300,7 +298,7 @@ rustc_queries! {
             desc { |tcx| "linting {}", key.describe_as_module(tcx) }
         }
 
-        /// Checks the attributes in the module
+        /// Checks the attributes in the module.
         query check_mod_attrs(key: DefId) -> () {
             desc { |tcx| "checking attributes in {}", key.describe_as_module(tcx) }
         }
@@ -309,7 +307,7 @@ rustc_queries! {
             desc { |tcx| "checking for unstable API usage in {}", key.describe_as_module(tcx) }
         }
 
-        /// Checks the loops in the module
+        /// Checks the loops in the module.
         query check_mod_loops(key: DefId) -> () {
             desc { |tcx| "checking loops in {}", key.describe_as_module(tcx) }
         }
@@ -338,7 +336,7 @@ rustc_queries! {
             desc { |tcx| "collecting item types in {}", key.describe_as_module(tcx) }
         }
 
-        /// Caches CoerceUnsized kinds for impls on custom types.
+        /// Caches `CoerceUnsized` kinds for impls on custom types.
         query coerce_unsized_info(_: DefId)
             -> ty::adjustment::CoerceUnsizedInfo {}
     }
@@ -375,7 +373,7 @@ rustc_queries! {
     BorrowChecking {
         query borrowck(_: DefId) -> Lrc<BorrowCheckResult> {}
 
-        /// Borrow checks the function body. If this is a closure, returns
+        /// Borrow-checks the function body. If this is a closure, returns
         /// additional requirements that the closure's creator must verify.
         query mir_borrowck(_: DefId) -> mir::BorrowCheckResult<'tcx> {}
     }
@@ -401,11 +399,11 @@ rustc_queries! {
     }
 
     Other {
-        /// Evaluate a constant without running sanity checks
+        /// Evaluates a constant without running sanity checks.
         ///
         /// **Do not use this** outside const eval. Const eval uses this to break query cycles
         /// during validation. Please add a comment to every use site explaining why using
-        /// `const_eval` isn't sufficient
+        /// `const_eval` isn't sufficient.
         query const_eval_raw(key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>)
             -> ConstEvalRawResult<'tcx> {
             no_force
@@ -660,12 +658,12 @@ rustc_queries! {
     }
 
     Linking {
-        // The DefIds of all non-generic functions and statics in the given crate
+        // The `DefId`s of all non-generic functions and statics in the given crate
         // that can be reached from outside the crate.
         //
         // We expect this items to be available for being linked to.
         //
-        // This query can also be called for LOCAL_CRATE. In this case it will
+        // This query can also be called for `LOCAL_CRATE`. In this case it will
         // compute which items will be reachable to other crates, taking into account
         // the kind of crate that is currently compiled. Crates with only a
         // C interface have fewer reachable things.
diff --git a/src/librustc/traits/mod.rs b/src/librustc/traits/mod.rs
index 846924fb591..a4b9ed0a206 100644
--- a/src/librustc/traits/mod.rs
+++ b/src/librustc/traits/mod.rs
@@ -60,8 +60,10 @@ pub use self::specialize::specialization_graph::FutureCompatOverlapError;
 pub use self::specialize::specialization_graph::FutureCompatOverlapErrorKind;
 pub use self::engine::{TraitEngine, TraitEngineExt};
 pub use self::util::{elaborate_predicates, elaborate_trait_ref, elaborate_trait_refs};
-pub use self::util::{supertraits, supertrait_def_ids, transitive_bounds,
-                     Supertraits, SupertraitDefIds};
+pub use self::util::{
+    supertraits, supertrait_def_ids, transitive_bounds, Supertraits, SupertraitDefIds,
+};
+pub use self::util::{expand_trait_aliases, TraitAliasExpander};
 
 pub use self::chalk_fulfill::{
     CanonicalGoal as ChalkCanonicalGoal,
@@ -1043,7 +1045,7 @@ fn vtable_methods<'a, 'tcx>(
     )
 }
 
-impl<'tcx,O> Obligation<'tcx,O> {
+impl<'tcx, O> Obligation<'tcx, O> {
     pub fn new(cause: ObligationCause<'tcx>,
                param_env: ty::ParamEnv<'tcx>,
                predicate: O)
diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs
index c4be85050db..ec5e127a5ec 100644
--- a/src/librustc/traits/select.rs
+++ b/src/librustc/traits/select.rs
@@ -1772,7 +1772,8 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
             bounds
         );
 
-        let matching_bound = util::elaborate_predicates(self.tcx(), bounds.predicates)
+        let elaborated_predicates = util::elaborate_predicates(self.tcx(), bounds.predicates);
+        let matching_bound = elaborated_predicates
             .filter_to_traits()
             .find(|bound| {
                 self.infcx.probe(|_| {
diff --git a/src/librustc/traits/util.rs b/src/librustc/traits/util.rs
index be29ea5701b..5ba23a9c45a 100644
--- a/src/librustc/traits/util.rs
+++ b/src/librustc/traits/util.rs
@@ -1,3 +1,7 @@
+use errors::DiagnosticBuilder;
+use smallvec::SmallVec;
+use syntax_pos::Span;
+
 use crate::hir;
 use crate::hir::def_id::DefId;
 use crate::traits::specialize::specialization_graph::NodeItem;
@@ -41,15 +45,14 @@ fn anonymize_predicate<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
     }
 }
 
-
-struct PredicateSet<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
+struct PredicateSet<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> {
     tcx: TyCtxt<'a, 'gcx, 'tcx>,
     set: FxHashSet<ty::Predicate<'tcx>>,
 }
 
 impl<'a, 'gcx, 'tcx> PredicateSet<'a, 'gcx, 'tcx> {
-    fn new(tcx: TyCtxt<'a, 'gcx, 'tcx>) -> PredicateSet<'a, 'gcx, 'tcx> {
-        PredicateSet { tcx: tcx, set: Default::default() }
+    fn new(tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Self {
+        Self { tcx: tcx, set: Default::default() }
     }
 
     fn insert(&mut self, pred: &ty::Predicate<'tcx>) -> bool {
@@ -67,18 +70,25 @@ impl<'a, 'gcx, 'tcx> PredicateSet<'a, 'gcx, 'tcx> {
     }
 }
 
+impl<'a, 'gcx, 'tcx, T: AsRef<ty::Predicate<'tcx>>> Extend<T> for PredicateSet<'a, 'gcx, 'tcx> {
+    fn extend<I: IntoIterator<Item = T>>(&mut self, iter: I) {
+        for pred in iter {
+            self.insert(pred.as_ref());
+        }
+    }
+}
+
 ///////////////////////////////////////////////////////////////////////////
 // `Elaboration` iterator
 ///////////////////////////////////////////////////////////////////////////
 
 /// "Elaboration" is the process of identifying all the predicates that
 /// are implied by a source predicate. Currently this basically means
-/// walking the "supertraits" and other similar assumptions. For
-/// example, if we know that `T : Ord`, the elaborator would deduce
-/// that `T : PartialOrd` holds as well. Similarly, if we have `trait
-/// Foo : 'static`, and we know that `T : Foo`, then we know that `T :
-/// 'static`.
-pub struct Elaborator<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
+/// walking the "supertraits" and other similar assumptions. For example,
+/// if we know that `T: Ord`, the elaborator would deduce that `T: PartialOrd`
+/// holds as well. Similarly, if we have `trait Foo: 'static`, and we know that
+/// `T: Foo`, then we know that `T: 'static`.
+pub struct Elaborator<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> {
     stack: Vec<ty::Predicate<'tcx>>,
     visited: PredicateSet<'a, 'gcx, 'tcx>,
 }
@@ -96,8 +106,7 @@ pub fn elaborate_trait_refs<'cx, 'gcx, 'tcx>(
     trait_refs: impl Iterator<Item = ty::PolyTraitRef<'tcx>>)
     -> Elaborator<'cx, 'gcx, 'tcx>
 {
-    let predicates = trait_refs.map(|trait_ref| trait_ref.to_predicate())
-                               .collect();
+    let predicates = trait_refs.map(|trait_ref| trait_ref.to_predicate()).collect();
     elaborate_predicates(tcx, predicates)
 }
 
@@ -108,7 +117,7 @@ pub fn elaborate_predicates<'cx, 'gcx, 'tcx>(
 {
     let mut visited = PredicateSet::new(tcx);
     predicates.retain(|pred| visited.insert(pred));
-    Elaborator { stack: predicates, visited: visited }
+    Elaborator { stack: predicates, visited }
 }
 
 impl<'cx, 'gcx, 'tcx> Elaborator<'cx, 'gcx, 'tcx> {
@@ -116,28 +125,25 @@ impl<'cx, 'gcx, 'tcx> Elaborator<'cx, 'gcx, 'tcx> {
         FilterToTraits::new(self)
     }
 
-    fn push(&mut self, predicate: &ty::Predicate<'tcx>) {
+    fn elaborate(&mut self, predicate: &ty::Predicate<'tcx>) {
         let tcx = self.visited.tcx;
         match *predicate {
             ty::Predicate::Trait(ref data) => {
-                // Predicates declared on the trait.
+                // Get predicates declared on the trait.
                 let predicates = tcx.super_predicates_of(data.def_id());
 
-                let mut predicates: Vec<_> =
-                    predicates.predicates
-                              .iter()
-                              .map(|(p, _)| p.subst_supertrait(tcx, &data.to_poly_trait_ref()))
-                              .collect();
-
+                let predicates = predicates.predicates
+                    .iter()
+                    .map(|(pred, _)| pred.subst_supertrait(tcx, &data.to_poly_trait_ref()));
                 debug!("super_predicates: data={:?} predicates={:?}",
-                       data, predicates);
+                       data, predicates.clone());
 
-                // Only keep those bounds that we haven't already
-                // seen.  This is necessary to prevent infinite
-                // recursion in some cases.  One common case is when
-                // people define `trait Sized: Sized { }` rather than `trait
-                // Sized { }`.
-                predicates.retain(|r| self.visited.insert(r));
+                // Only keep those bounds that we haven't already seen.
+                // This is necessary to prevent infinite recursion in some
+                // cases. One common case is when people define
+                // `trait Sized: Sized { }` rather than `trait Sized { }`.
+                let visited = &mut self.visited;
+                let predicates = predicates.filter(|pred| visited.insert(pred));
 
                 self.stack.extend(predicates);
             }
@@ -150,8 +156,8 @@ impl<'cx, 'gcx, 'tcx> Elaborator<'cx, 'gcx, 'tcx> {
                 // predicates.
             }
             ty::Predicate::Subtype(..) => {
-                // Currently, we do not "elaborate" predicates like `X
-                // <: Y`, though conceivably we might.
+                // Currently, we do not "elaborate" predicates like `X <: Y`,
+                // though conceivably we might.
             }
             ty::Predicate::Projection(..) => {
                 // Nothing to elaborate in a projection predicate.
@@ -163,11 +169,9 @@ impl<'cx, 'gcx, 'tcx> Elaborator<'cx, 'gcx, 'tcx> {
                 // Currently, we do not elaborate const-evaluatable
                 // predicates.
             }
-
             ty::Predicate::RegionOutlives(..) => {
                 // Nothing to elaborate from `'a: 'b`.
             }
-
             ty::Predicate::TypeOutlives(ref data) => {
                 // We know that `T: 'a` for some type `T`. We can
                 // often elaborate this. For example, if we know that
@@ -194,34 +198,35 @@ impl<'cx, 'gcx, 'tcx> Elaborator<'cx, 'gcx, 'tcx> {
                 tcx.push_outlives_components(ty_max, &mut components);
                 self.stack.extend(
                     components
-                       .into_iter()
-                       .filter_map(|component| match component {
-                           Component::Region(r) => if r.is_late_bound() {
-                               None
-                           } else {
-                               Some(ty::Predicate::RegionOutlives(
-                                   ty::Binder::dummy(ty::OutlivesPredicate(r, r_min))))
-                           },
-
-                           Component::Param(p) => {
-                               let ty = tcx.mk_ty_param(p.index, p.name);
-                               Some(ty::Predicate::TypeOutlives(
-                                   ty::Binder::dummy(ty::OutlivesPredicate(ty, r_min))))
-                           },
-
-                           Component::UnresolvedInferenceVariable(_) => {
-                               None
-                           },
-
-                           Component::Projection(_) |
-                           Component::EscapingProjection(_) => {
-                               // We can probably do more here. This
-                               // corresponds to a case like `<T as
-                               // Foo<'a>>::U: 'b`.
-                               None
-                           },
-                       })
-                       .filter(|p| visited.insert(p)));
+                        .into_iter()
+                        .filter_map(|component| match component {
+                            Component::Region(r) => if r.is_late_bound() {
+                                None
+                            } else {
+                                Some(ty::Predicate::RegionOutlives(
+                                    ty::Binder::dummy(ty::OutlivesPredicate(r, r_min))))
+                            }
+
+                            Component::Param(p) => {
+                                let ty = tcx.mk_ty_param(p.index, p.name);
+                                Some(ty::Predicate::TypeOutlives(
+                                    ty::Binder::dummy(ty::OutlivesPredicate(ty, r_min))))
+                            }
+
+                            Component::UnresolvedInferenceVariable(_) => {
+                                None
+                            }
+
+                            Component::Projection(_) |
+                            Component::EscapingProjection(_) => {
+                                // We can probably do more here. This
+                                // corresponds to a case like `<T as
+                                // Foo<'a>>::U: 'b`.
+                                None
+                            }
+                        })
+                        .filter(|p| visited.insert(p))
+                );
             }
         }
     }
@@ -236,15 +241,12 @@ impl<'cx, 'gcx, 'tcx> Iterator for Elaborator<'cx, 'gcx, 'tcx> {
 
     fn next(&mut self) -> Option<ty::Predicate<'tcx>> {
         // Extract next item from top-most stack frame, if any.
-        let next_predicate = match self.stack.pop() {
-            Some(predicate) => predicate,
-            None => {
-                // No more stack frames. Done.
-                return None;
-            }
-        };
-        self.push(&next_predicate);
-        return Some(next_predicate);
+        if let Some(pred) = self.stack.pop() {
+            self.elaborate(&pred);
+            Some(pred)
+        } else {
+            None
+        }
     }
 }
 
@@ -256,20 +258,161 @@ pub type Supertraits<'cx, 'gcx, 'tcx> = FilterToTraits<Elaborator<'cx, 'gcx, 'tc
 
 pub fn supertraits<'cx, 'gcx, 'tcx>(tcx: TyCtxt<'cx, 'gcx, 'tcx>,
                                     trait_ref: ty::PolyTraitRef<'tcx>)
-                                    -> Supertraits<'cx, 'gcx, 'tcx>
-{
+                                    -> Supertraits<'cx, 'gcx, 'tcx> {
     elaborate_trait_ref(tcx, trait_ref).filter_to_traits()
 }
 
 pub fn transitive_bounds<'cx, 'gcx, 'tcx>(tcx: TyCtxt<'cx, 'gcx, 'tcx>,
                                           bounds: impl Iterator<Item = ty::PolyTraitRef<'tcx>>)
-                                          -> Supertraits<'cx, 'gcx, 'tcx>
-{
+                                          -> Supertraits<'cx, 'gcx, 'tcx> {
     elaborate_trait_refs(tcx, bounds).filter_to_traits()
 }
 
 ///////////////////////////////////////////////////////////////////////////
-// Iterator over def-ids of supertraits
+// `TraitAliasExpander` iterator
+///////////////////////////////////////////////////////////////////////////
+
+/// "Trait alias expansion" is the process of expanding a sequence of trait
+/// references into another sequence by transitively following all trait
+/// aliases. e.g. If you have bounds like `Foo + Send`, a trait alias
+/// `trait Foo = Bar + Sync;`, and another trait alias
+/// `trait Bar = Read + Write`, then the bounds would expand to
+/// `Read + Write + Sync + Send`.
+/// Expansion is done via a DFS (depth-first search), and the `visited` field
+/// is used to avoid cycles.
+pub struct TraitAliasExpander<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> {
+    tcx: TyCtxt<'a, 'gcx, 'tcx>,
+    stack: Vec<TraitAliasExpansionInfo<'tcx>>,
+}
+
+/// Stores information about the expansion of a trait via a path of zero or more trait aliases.
+#[derive(Debug, Clone)]
+pub struct TraitAliasExpansionInfo<'tcx> {
+    pub path: SmallVec<[(ty::PolyTraitRef<'tcx>, Span); 4]>,
+}
+
+impl<'tcx> TraitAliasExpansionInfo<'tcx> {
+    fn new(trait_ref: ty::PolyTraitRef<'tcx>, span: Span) -> Self {
+        Self {
+            path: smallvec![(trait_ref, span)]
+        }
+    }
+
+    /// Adds diagnostic labels to `diag` for the expansion path of a trait through all intermediate
+    /// trait aliases.
+    pub fn label_with_exp_info(&self,
+        diag: &mut DiagnosticBuilder<'_>,
+        top_label: &str,
+        use_desc: &str
+    ) {
+        diag.span_label(self.top().1, top_label);
+        if self.path.len() > 1 {
+            for (_, sp) in self.path.iter().rev().skip(1).take(self.path.len() - 2) {
+                diag.span_label(*sp, format!("referenced here ({})", use_desc));
+            }
+        }
+        diag.span_label(self.bottom().1,
+            format!("trait alias used in trait object type ({})", use_desc));
+    }
+
+    pub fn trait_ref(&self) -> &ty::PolyTraitRef<'tcx> {
+        &self.top().0
+    }
+
+    pub fn top(&self) -> &(ty::PolyTraitRef<'tcx>, Span) {
+        self.path.last().unwrap()
+    }
+
+    pub fn bottom(&self) -> &(ty::PolyTraitRef<'tcx>, Span) {
+        self.path.first().unwrap()
+    }
+
+    fn clone_and_push(&self, trait_ref: ty::PolyTraitRef<'tcx>, span: Span) -> Self {
+        let mut path = self.path.clone();
+        path.push((trait_ref, span));
+
+        Self {
+            path
+        }
+    }
+}
+
+pub fn expand_trait_aliases<'cx, 'gcx, 'tcx>(
+    tcx: TyCtxt<'cx, 'gcx, 'tcx>,
+    trait_refs: impl IntoIterator<Item = (ty::PolyTraitRef<'tcx>, Span)>
+) -> TraitAliasExpander<'cx, 'gcx, 'tcx> {
+    let items: Vec<_> = trait_refs
+        .into_iter()
+        .map(|(trait_ref, span)| TraitAliasExpansionInfo::new(trait_ref, span))
+        .collect();
+    TraitAliasExpander { tcx, stack: items }
+}
+
+impl<'cx, 'gcx, 'tcx> TraitAliasExpander<'cx, 'gcx, 'tcx> {
+    /// If `item` is a trait alias and its predicate has not yet been visited, then expands `item`
+    /// to the definition, pushes the resulting expansion onto `self.stack`, and returns `false`.
+    /// Otherwise, immediately returns `true` if `item` is a regular trait, or `false` if it is a
+    /// trait alias.
+    /// The return value indicates whether `item` should be yielded to the user.
+    fn expand(&mut self, item: &TraitAliasExpansionInfo<'tcx>) -> bool {
+        let tcx = self.tcx;
+        let trait_ref = item.trait_ref();
+        let pred = trait_ref.to_predicate();
+
+        debug!("expand_trait_aliases: trait_ref={:?}", trait_ref);
+
+        // Don't recurse if this bound is not a trait alias.
+        let is_alias = tcx.is_trait_alias(trait_ref.def_id());
+        if !is_alias {
+            return true;
+        }
+
+        // Don't recurse if this trait alias is already on the stack for the DFS search.
+        let anon_pred = anonymize_predicate(tcx, &pred);
+        if item.path.iter().rev().skip(1)
+                .any(|(tr, _)| anonymize_predicate(tcx, &tr.to_predicate()) == anon_pred) {
+            return false;
+        }
+
+        // Get components of trait alias.
+        let predicates = tcx.super_predicates_of(trait_ref.def_id());
+
+        let items = predicates.predicates
+            .iter()
+            .rev()
+            .filter_map(|(pred, span)| {
+                pred.subst_supertrait(tcx, &trait_ref)
+                    .to_opt_poly_trait_ref()
+                    .map(|trait_ref| item.clone_and_push(trait_ref, *span))
+            });
+        debug!("expand_trait_aliases: items={:?}", items.clone());
+
+        self.stack.extend(items);
+
+        false
+    }
+}
+
+impl<'cx, 'gcx, 'tcx> Iterator for TraitAliasExpander<'cx, 'gcx, 'tcx> {
+    type Item = TraitAliasExpansionInfo<'tcx>;
+
+    fn size_hint(&self) -> (usize, Option<usize>) {
+        (self.stack.len(), None)
+    }
+
+    fn next(&mut self) -> Option<TraitAliasExpansionInfo<'tcx>> {
+        while let Some(item) = self.stack.pop() {
+            if self.expand(&item) {
+                return Some(item);
+            }
+        }
+        None
+    }
+}
+
+///////////////////////////////////////////////////////////////////////////
+// Iterator over def-IDs of supertraits
+///////////////////////////////////////////////////////////////////////////
 
 pub struct SupertraitDefIds<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
     tcx: TyCtxt<'a, 'gcx, 'tcx>,
@@ -298,8 +441,8 @@ impl<'cx, 'gcx, 'tcx> Iterator for SupertraitDefIds<'cx, 'gcx, 'tcx> {
         self.stack.extend(
             predicates.predicates
                       .iter()
-                      .filter_map(|(p, _)| p.to_opt_poly_trait_ref())
-                      .map(|t| t.def_id())
+                      .filter_map(|(pred, _)| pred.to_opt_poly_trait_ref())
+                      .map(|trait_ref| trait_ref.def_id())
                       .filter(|&super_def_id| visited.insert(super_def_id)));
         Some(def_id)
     }
@@ -325,17 +468,12 @@ impl<'tcx, I: Iterator<Item = ty::Predicate<'tcx>>> Iterator for FilterToTraits<
     type Item = ty::PolyTraitRef<'tcx>;
 
     fn next(&mut self) -> Option<ty::PolyTraitRef<'tcx>> {
-        loop {
-            match self.base_iterator.next() {
-                None => {
-                    return None;
-                }
-                Some(ty::Predicate::Trait(data)) => {
-                    return Some(data.to_poly_trait_ref());
-                }
-                Some(_) => {}
+        while let Some(pred) = self.base_iterator.next() {
+            if let ty::Predicate::Trait(data) = pred {
+                return Some(data.to_poly_trait_ref());
             }
         }
+        None
     }
 
     fn size_hint(&self) -> (usize, Option<usize>) {
diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs
index b60ef557cb8..4d242265e61 100644
--- a/src/librustc/ty/mod.rs
+++ b/src/librustc/ty/mod.rs
@@ -1075,25 +1075,25 @@ impl<'a, 'gcx, 'tcx> GenericPredicates<'tcx> {
 
 #[derive(Clone, Copy, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable, HashStable)]
 pub enum Predicate<'tcx> {
-    /// Corresponds to `where Foo: Bar<A,B,C>`. `Foo` here would be
+    /// Corresponds to `where Foo: Bar<A, B, C>`. `Foo` here would be
     /// the `Self` type of the trait reference and `A`, `B`, and `C`
     /// would be the type parameters.
     Trait(PolyTraitPredicate<'tcx>),
 
-    /// where `'a: 'b`
+    /// `where 'a: 'b`
     RegionOutlives(PolyRegionOutlivesPredicate<'tcx>),
 
-    /// where `T: 'a`
+    /// `where T: 'a`
     TypeOutlives(PolyTypeOutlivesPredicate<'tcx>),
 
-    /// where `<T as TraitRef>::Name == X`, approximately.
+    /// `where <T as TraitRef>::Name == X`, approximately.
     /// See the `ProjectionPredicate` struct for details.
     Projection(PolyProjectionPredicate<'tcx>),
 
     /// no syntax: `T` well-formed
     WellFormed(Ty<'tcx>),
 
-    /// trait must be object-safe
+    /// Trait must be object-safe.
     ObjectSafe(DefId),
 
     /// No direct syntax. May be thought of as `where T: FnFoo<...>`
@@ -1234,7 +1234,7 @@ impl<'tcx> TraitPredicate<'tcx> {
         self.trait_ref.def_id
     }
 
-    pub fn input_types<'a>(&'a self) -> impl DoubleEndedIterator<Item=Ty<'tcx>> + 'a {
+    pub fn input_types<'a>(&'a self) -> impl DoubleEndedIterator<Item = Ty<'tcx>> + 'a {
         self.trait_ref.input_types()
     }
 
@@ -2400,7 +2400,7 @@ impl<'a, 'gcx, 'tcx> AdtDef {
     pub fn discriminants(
         &'a self,
         tcx: TyCtxt<'a, 'gcx, 'tcx>,
-    ) -> impl Iterator<Item=(VariantIdx, Discr<'tcx>)> + Captures<'gcx> + 'a {
+    ) -> impl Iterator<Item = (VariantIdx, Discr<'tcx>)> + Captures<'gcx> + 'a {
         let repr_type = self.repr.discr_type();
         let initial = repr_type.initial_discriminant(tcx.global_tcx());
         let mut prev_discr = None::<Discr<'tcx>>;
diff --git a/src/librustc/ty/query/mod.rs b/src/librustc/ty/query/mod.rs
index 18d575f7364..be52b7e6451 100644
--- a/src/librustc/ty/query/mod.rs
+++ b/src/librustc/ty/query/mod.rs
@@ -100,8 +100,7 @@ pub use self::on_disk_cache::OnDiskCache;
 
 rustc_query_append! { [define_queries!][ <'tcx>
     Other {
-        /// Run analysis passes on the crate
+        /// Runs analysis passes on the crate.
         [] fn analysis: Analysis(CrateNum) -> Result<(), ErrorReported>,
-
     },
 ]}
diff --git a/src/librustc_mir/borrow_check/error_reporting.rs b/src/librustc_mir/borrow_check/error_reporting.rs
index 1a1000f0bb4..32d182edfdc 100644
--- a/src/librustc_mir/borrow_check/error_reporting.rs
+++ b/src/librustc_mir/borrow_check/error_reporting.rs
@@ -1502,7 +1502,6 @@ enum StorageDeadOrDrop<'tcx> {
 }
 
 impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
-
     /// Adds a suggestion when a closure is invoked twice with a moved variable or when a closure
     /// is moved after being invoked.
     ///
diff --git a/src/librustc_save_analysis/dump_visitor.rs b/src/librustc_save_analysis/dump_visitor.rs
index 1e65f868eba..1fdfcc84926 100644
--- a/src/librustc_save_analysis/dump_visitor.rs
+++ b/src/librustc_save_analysis/dump_visitor.rs
@@ -1177,13 +1177,13 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> DumpVisitor<'l, 'tcx, 'll, O> {
                 );
             }
             ast::ImplItemKind::Type(ref ty) => {
-                // FIXME uses of the assoc type should ideally point to this
+                // FIXME: uses of the assoc type should ideally point to this
                 // 'def' and the name here should be a ref to the def in the
                 // trait.
                 self.visit_ty(ty)
             }
             ast::ImplItemKind::Existential(ref bounds) => {
-                // FIXME uses of the assoc type should ideally point to this
+                // FIXME: uses of the assoc type should ideally point to this
                 // 'def' and the name here should be a ref to the def in the
                 // trait.
                 for bound in bounds.iter() {
@@ -1216,7 +1216,7 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> DumpVisitor<'l, 'tcx, 'll, O> {
         let hir_id = self.tcx.hir().node_to_hir_id(id);
         let access = access_from!(self.save_ctxt, root_item, hir_id);
 
-        // The parent def id of a given use tree is always the enclosing item.
+        // The parent `DefId` of a given use tree is always the enclosing item.
         let parent = self.save_ctxt.tcx.hir().opt_local_def_id(id)
             .and_then(|id| self.save_ctxt.tcx.parent(id))
             .map(id_from_def_id);
diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs
index 4b052aec5fc..4110a558401 100644
--- a/src/librustc_typeck/astconv.rs
+++ b/src/librustc_typeck/astconv.rs
@@ -648,14 +648,14 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o {
                             // careful!
                             if default_needs_object_self(param) {
                                 struct_span_err!(tcx.sess, span, E0393,
-                                                    "the type parameter `{}` must be explicitly \
-                                                     specified",
-                                                    param.name)
-                                    .span_label(span,
-                                                format!("missing reference to `{}`", param.name))
-                                    .note(&format!("because of the default `Self` reference, \
-                                                    type parameters must be specified on object \
-                                                    types"))
+                                    "the type parameter `{}` must be explicitly specified",
+                                    param.name
+                                )
+                                    .span_label(span, format!(
+                                        "missing reference to `{}`", param.name))
+                                    .note(&format!(
+                                        "because of the default `Self` reference, type parameters \
+                                         must be specified on object types"))
                                     .emit();
                                 tcx.types.err.into()
                             } else {
@@ -702,7 +702,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o {
     }
 
     /// Instantiates the path for the given trait reference, assuming that it's
-    /// bound to a valid trait type. Returns the def_id for the defining trait.
+    /// bound to a valid trait type. Returns the `DefId` of the defining trait.
     /// The type _cannot_ be a type other than a trait type.
     ///
     /// If the `projections` argument is `None`, then assoc type bindings like `Foo<T = X>`
@@ -973,60 +973,81 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o {
     {
         let tcx = self.tcx();
 
-        if trait_bounds.is_empty() {
-            span_err!(tcx.sess, span, E0224,
-                      "at least one non-builtin trait is required for an object type");
-            return tcx.types.err;
-        }
-
         let mut projection_bounds = Vec::new();
+        let mut potential_assoc_types = Vec::new();
         let dummy_self = self.tcx().types.trait_object_dummy_self;
-        let (principal, potential_assoc_types) = self.instantiate_poly_trait_ref(
-            &trait_bounds[0],
-            dummy_self,
-            &mut projection_bounds,
-        );
-        debug!("principal: {:?}", principal);
-
-        for trait_bound in trait_bounds[1..].iter() {
-            // sanity check for non-principal trait bounds
-            self.instantiate_poly_trait_ref(trait_bound,
-                                            dummy_self,
-                                            &mut vec![]);
+        // FIXME: we want to avoid collecting into a `Vec` here, but simply cloning the iterator is
+        // not straightforward due to the borrow checker.
+        let bound_trait_refs: Vec<_> = trait_bounds
+            .iter()
+            .rev()
+            .map(|trait_bound| {
+                let (trait_ref, cur_potential_assoc_types) = self.instantiate_poly_trait_ref(
+                    trait_bound,
+                    dummy_self,
+                    &mut projection_bounds
+                );
+                potential_assoc_types.extend(cur_potential_assoc_types.into_iter().flatten());
+                (trait_ref, trait_bound.span)
+            })
+            .collect();
+
+        // Expand trait aliases recursively and check that only one regular (non-auto) trait
+        // is used and no 'maybe' bounds are used.
+        let expanded_traits = traits::expand_trait_aliases(tcx, bound_trait_refs.iter().cloned());
+        let (mut auto_traits, regular_traits): (Vec<_>, Vec<_>) =
+            expanded_traits.partition(|i| tcx.trait_is_auto(i.trait_ref().def_id()));
+        if regular_traits.len() > 1 {
+            let first_trait = &regular_traits[0];
+            let additional_trait = &regular_traits[1];
+            let mut err = struct_span_err!(tcx.sess, additional_trait.bottom().1, E0225,
+                "only auto traits can be used as additional traits in a trait object"
+            );
+            additional_trait.label_with_exp_info(&mut err,
+                "additional non-auto trait", "additional use");
+            first_trait.label_with_exp_info(&mut err,
+                "first non-auto trait", "first use");
+            err.emit();
         }
 
-        let (mut auto_traits, trait_bounds) = split_auto_traits(tcx, &trait_bounds[1..]);
-
-        if !trait_bounds.is_empty() {
-            let b = &trait_bounds[0];
-            let span = b.trait_ref.path.span;
-            struct_span_err!(self.tcx().sess, span, E0225,
-                "only auto traits can be used as additional traits in a trait object")
-                .span_label(span, "non-auto additional trait")
-                .emit();
+        if regular_traits.is_empty() && auto_traits.is_empty() {
+            span_err!(tcx.sess, span, E0224,
+                "at least one non-builtin trait is required for an object type");
+            return tcx.types.err;
         }
 
         // Check that there are no gross object safety violations;
         // most importantly, that the supertraits don't contain `Self`,
         // to avoid ICEs.
-        let object_safety_violations =
-            tcx.global_tcx().astconv_object_safety_violations(principal.def_id());
-        if !object_safety_violations.is_empty() {
-            tcx.report_object_safety_error(span, principal.def_id(), object_safety_violations)
-                .map(|mut err| err.emit());
-            return tcx.types.err;
+        for item in &regular_traits {
+            let object_safety_violations =
+                tcx.global_tcx().astconv_object_safety_violations(item.trait_ref().def_id());
+            if !object_safety_violations.is_empty() {
+                tcx.report_object_safety_error(
+                    span,
+                    item.trait_ref().def_id(),
+                    object_safety_violations
+                )
+                    .map(|mut err| err.emit());
+                return tcx.types.err;
+            }
         }
 
         // Use a `BTreeSet` to keep output in a more consistent order.
         let mut associated_types = BTreeSet::default();
 
-        for tr in traits::elaborate_trait_ref(tcx, principal) {
-            debug!("conv_object_ty_poly_trait_ref: observing object predicate `{:?}`", tr);
-            match tr {
+        let regular_traits_refs = bound_trait_refs
+            .into_iter()
+            .filter(|(trait_ref, _)| !tcx.trait_is_auto(trait_ref.def_id()))
+            .map(|(trait_ref, _)| trait_ref);
+        for trait_ref in traits::elaborate_trait_refs(tcx, regular_traits_refs) {
+            debug!("conv_object_ty_poly_trait_ref: observing object predicate `{:?}`", trait_ref);
+            match trait_ref {
                 ty::Predicate::Trait(pred) => {
-                    associated_types.extend(tcx.associated_items(pred.def_id())
-                                    .filter(|item| item.kind == ty::AssociatedKind::Type)
-                                    .map(|item| item.def_id));
+                    associated_types
+                        .extend(tcx.associated_items(pred.def_id())
+                        .filter(|item| item.kind == ty::AssociatedKind::Type)
+                        .map(|item| item.def_id));
                 }
                 ty::Predicate::Projection(pred) => {
                     // A `Self` within the original bound will be substituted with a
@@ -1035,7 +1056,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o {
                         pred.skip_binder().ty.walk().any(|t| t == dummy_self);
 
                     // If the projection output contains `Self`, force the user to
-                    // elaborate it explicitly to avoid a bunch of complexity.
+                    // elaborate it explicitly to avoid a lot of complexity.
                     //
                     // The "classicaly useful" case is the following:
                     // ```
@@ -1044,14 +1065,14 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o {
                     //     }
                     // ```
                     //
-                    // Here, the user could theoretically write `dyn MyTrait<Output=X>`,
+                    // Here, the user could theoretically write `dyn MyTrait<Output = X>`,
                     // but actually supporting that would "expand" to an infinitely-long type
-                    // `fix $ τ → dyn MyTrait<MyOutput=X, Output=<τ as MyTrait>::MyOutput`.
+                    // `fix $ τ → dyn MyTrait<MyOutput = X, Output = <τ as MyTrait>::MyOutput`.
                     //
-                    // Instead, we force the user to write `dyn MyTrait<MyOutput=X, Output=X>`,
+                    // Instead, we force the user to write `dyn MyTrait<MyOutput = X, Output = X>`,
                     // which is uglier but works. See the discussion in #56288 for alternatives.
                     if !references_self {
-                        // Include projections defined on supertraits,
+                        // Include projections defined on supertraits.
                         projection_bounds.push((pred, DUMMY_SP))
                     }
                 }
@@ -1081,20 +1102,18 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o {
                 if associated_types.len() == 1 { "" } else { "s" },
                 names,
             );
-            let mut suggest = false;
-            let mut potential_assoc_types_spans = vec![];
-            if let Some(potential_assoc_types) = potential_assoc_types {
+            let (suggest, potential_assoc_types_spans) =
                 if potential_assoc_types.len() == associated_types.len() {
-                    // Only suggest when the amount of missing associated types is equals to the
+                    // Only suggest when the amount of missing associated types equals the number of
                     // extra type arguments present, as that gives us a relatively high confidence
                     // that the user forgot to give the associtated type's name. The canonical
                     // example would be trying to use `Iterator<isize>` instead of
-                    // `Iterator<Item=isize>`.
-                    suggest = true;
-                    potential_assoc_types_spans = potential_assoc_types;
-                }
-            }
-            let mut suggestions = vec![];
+                    // `Iterator<Item = isize>`.
+                    (true, potential_assoc_types)
+                } else {
+                    (false, Vec::new())
+                };
+            let mut suggestions = Vec::new();
             for (i, item_def_id) in associated_types.iter().enumerate() {
                 let assoc_item = tcx.associated_item(*item_def_id);
                 err.span_label(
@@ -1130,9 +1149,16 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o {
             err.emit();
         }
 
+        // De-duplicate auto traits so that, e.g., `dyn Trait + Send + Send` is the same as
+        // `dyn Trait + Send`.
+        auto_traits.sort_by_key(|i| i.trait_ref().def_id());
+        auto_traits.dedup_by_key(|i| i.trait_ref().def_id());
+        debug!("regular_traits: {:?}", regular_traits);
+        debug!("auto_traits: {:?}", auto_traits);
+
         // Erase the `dummy_self` (`trait_object_dummy_self`) used above.
-        let existential_principal = principal.map_bound(|trait_ref| {
-            self.trait_ref_to_existential(trait_ref)
+        let existential_trait_refs = regular_traits.iter().map(|i| {
+            i.trait_ref().map_bound(|trait_ref| self.trait_ref_to_existential(trait_ref))
         });
         let existential_projections = projection_bounds.iter().map(|(bound, _)| {
             bound.map_bound(|b| {
@@ -1145,19 +1171,14 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o {
             })
         });
 
-        // Dedup auto traits so that `dyn Trait + Send + Send` is the same as `dyn Trait + Send`.
-        auto_traits.sort();
-        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())
-        };
+        // Calling `skip_binder` is okay because the predicates are re-bound.
+        let regular_trait_predicates = existential_trait_refs.map(
+            |trait_ref| ty::ExistentialPredicate::Trait(*trait_ref.skip_binder()));
+        let auto_trait_predicates = auto_traits.into_iter().map(
+            |trait_ref| ty::ExistentialPredicate::AutoTrait(trait_ref.trait_ref().def_id()));
         let mut v =
-            iter::once(principal)
-            .chain(auto_traits.into_iter().map(ty::ExistentialPredicate::AutoTrait))
+            regular_trait_predicates
+            .chain(auto_trait_predicates)
             .chain(existential_projections
                 .map(|x| ty::ExistentialPredicate::Projection(*x.skip_binder())))
             .collect::<SmallVec<[_; 8]>>();
@@ -1175,14 +1196,13 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o {
                 } else {
                     self.re_infer(span, None).unwrap_or_else(|| {
                         span_err!(tcx.sess, span, E0228,
-                                  "the lifetime bound for this object type cannot be deduced \
-                                   from context; please supply an explicit bound");
+                            "the lifetime bound for this object type cannot be deduced \
+                             from context; please supply an explicit bound");
                         tcx.lifetimes.re_static
                     })
                 }
             })
         };
-
         debug!("region_bound: {:?}", region_bound);
 
         let ty = tcx.mk_dynamic(existential_predicates, region_bound);
@@ -1220,7 +1240,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o {
     }
 
     // Search for a bound on a type parameter which includes the associated item
-    // given by `assoc_name`. `ty_param_def_id` is the `DefId` for the type parameter
+    // given by `assoc_name`. `ty_param_def_id` is the `DefId` of the type parameter
     // This function will fail if there are no suitable bounds or there is
     // any ambiguity.
     fn find_bound_for_assoc_item(&self,
@@ -2097,33 +2117,6 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o {
     }
 }
 
-/// Divides a list of general trait bounds into two groups: auto traits (e.g., Sync and Send) and
-/// the remaining general trait bounds.
-fn split_auto_traits<'a, 'b, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
-                                         trait_bounds: &'b [hir::PolyTraitRef])
-    -> (Vec<DefId>, Vec<&'b hir::PolyTraitRef>)
-{
-    let (auto_traits, trait_bounds): (Vec<_>, _) = trait_bounds.iter().partition(|bound| {
-        // Checks whether `trait_did` is an auto trait and adds it to `auto_traits` if so.
-        match bound.trait_ref.path.res {
-            Res::Def(DefKind::Trait, trait_did) if tcx.trait_is_auto(trait_did) => {
-                true
-            }
-            _ => false
-        }
-    });
-
-    let auto_traits = auto_traits.into_iter().map(|tr| {
-        if let Res::Def(DefKind::Trait, trait_did) = tr.trait_ref.path.res {
-            trait_did
-        } else {
-            unreachable!()
-        }
-    }).collect::<Vec<_>>();
-
-    (auto_traits, trait_bounds)
-}
-
 // A helper struct for conveniently grouping a set of bounds which we pass to
 // and return from functions in multiple places.
 #[derive(PartialEq, Eq, Clone, Debug)]
@@ -2138,7 +2131,7 @@ impl<'a, 'gcx, 'tcx> Bounds<'tcx> {
     pub fn predicates(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>, param_ty: Ty<'tcx>)
                       -> Vec<(ty::Predicate<'tcx>, Span)>
     {
-        // If it could be sized, and is, add the sized predicate.
+        // If it could be sized, and is, add the `Sized` predicate.
         let sized_predicate = self.implicitly_sized.and_then(|span| {
             tcx.lang_items().sized_trait().map(|sized| {
                 let trait_ref = ty::TraitRef {
diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs
index 251400e65f3..590ae9d46e8 100644
--- a/src/librustc_typeck/check/method/probe.rs
+++ b/src/librustc_typeck/check/method/probe.rs
@@ -758,7 +758,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
     }
 
     fn assemble_inherent_candidates_from_param(&mut self, param_ty: ty::ParamTy) {
-        // FIXME -- Do we want to commit to this behavior for param bounds?
+        // FIXME: do we want to commit to this behavior for param bounds?
 
         let bounds = self.param_env
             .caller_bounds
diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs
index b009c8ea6dc..7e7a8d59266 100644
--- a/src/librustc_typeck/check/wfcheck.rs
+++ b/src/librustc_typeck/check/wfcheck.rs
@@ -1019,7 +1019,7 @@ fn check_false_global_bounds<'a, 'gcx, 'tcx>(
         .iter()
         .map(|(p, _)| *p)
         .collect();
-    // Check elaborated bounds
+    // Check elaborated bounds.
     let implied_obligations = traits::elaborate_predicates(fcx.tcx, predicates);
 
     for pred in implied_obligations {
diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs
index 711d79f95f5..7adf86a99bd 100644
--- a/src/librustc_typeck/collect.rs
+++ b/src/librustc_typeck/collect.rs
@@ -684,9 +684,9 @@ fn adt_def<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> &'tcx ty::Ad
     tcx.alloc_adt_def(def_id, kind, variants, repr)
 }
 
-/// Ensures that the super-predicates of the trait with `DefId`
-/// trait_def_id are converted and stored. This also ensures that
-/// the transitive super-predicates are converted;
+/// Ensures that the super-predicates of the trait with a `DefId`
+/// of `trait_def_id` are converted and stored. This also ensures that
+/// the transitive super-predicates are converted.
 fn super_predicates_of<'a, 'tcx>(
     tcx: TyCtxt<'a, 'tcx, 'tcx>,
     trait_def_id: DefId,
@@ -707,15 +707,15 @@ fn super_predicates_of<'a, 'tcx>(
 
     let icx = ItemCtxt::new(tcx, trait_def_id);
 
-    // Convert the bounds that follow the colon, e.g., `Bar + Zed` in `trait Foo : Bar + Zed`.
+    // Convert the bounds that follow the colon, e.g., `Bar + Zed` in `trait Foo: Bar + Zed`.
     let self_param_ty = tcx.mk_self_type();
     let superbounds1 = compute_bounds(&icx, self_param_ty, bounds, SizedByDefault::No, item.span);
 
     let superbounds1 = superbounds1.predicates(tcx, self_param_ty);
 
-    // Convert any explicit superbounds in the where clause,
-    // e.g., `trait Foo where Self : Bar`.
-    // In the case of trait aliases, however, we include all bounds in the where clause,
+    // Convert any explicit superbounds in the where-clause,
+    // e.g., `trait Foo where Self: Bar`.
+    // In the case of trait aliases, however, we include all bounds in the where-clause,
     // so e.g., `trait Foo = where u32: PartialEq<Self>` would include `u32: PartialEq<Self>`
     // as one of its "superpredicates".
     let is_trait_alias = tcx.is_trait_alias(trait_def_id);
diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs
index a6bb47bef87..da45bc1d9f5 100644
--- a/src/libsyntax/ast.rs
+++ b/src/libsyntax/ast.rs
@@ -2129,10 +2129,10 @@ pub struct TraitRef {
 
 #[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
 pub struct PolyTraitRef {
-    /// The `'a` in `<'a> Foo<&'a T>`
+    /// The `'a` in `<'a> Foo<&'a T>`.
     pub bound_generic_params: Vec<GenericParam>,
 
-    /// The `Foo<&'a T>` in `<'a> Foo<&'a T>`
+    /// The `Foo<&'a T>` in `<'a> Foo<&'a T>`.
     pub trait_ref: TraitRef,
 
     pub span: Span,
diff --git a/src/test/ui/associated-types/associated-types-overridden-binding-2.stderr b/src/test/ui/associated-types/associated-types-overridden-binding-2.stderr
index ad0b6515490..85724cb7c6e 100644
--- a/src/test/ui/associated-types/associated-types-overridden-binding-2.stderr
+++ b/src/test/ui/associated-types/associated-types-overridden-binding-2.stderr
@@ -6,7 +6,7 @@ LL |     let _: &I32Iterator<Item = u32> = &vec![42].into_iter();
    |
    = note: expected type `u32`
               found type `i32`
-   = note: required for the cast to the object type `dyn I32Iterator<Item = u32, Item = i32>`
+   = note: required for the cast to the object type `dyn std::iter::Iterator<Item = u32, Item = i32>`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/bad/bad-sized.stderr b/src/test/ui/bad/bad-sized.stderr
index 321f9754158..6307af5d725 100644
--- a/src/test/ui/bad/bad-sized.stderr
+++ b/src/test/ui/bad/bad-sized.stderr
@@ -2,7 +2,12 @@ error[E0225]: only auto traits can be used as additional traits in a trait objec
   --> $DIR/bad-sized.rs:4:24
    |
 LL |     let x: Vec<Trait + Sized> = Vec::new();
-   |                        ^^^^^ non-auto additional trait
+   |                -----   ^^^^^
+   |                |       |
+   |                |       additional non-auto trait
+   |                |       trait alias used in trait object type (additional use)
+   |                first non-auto trait
+   |                trait alias used in trait object type (first use)
 
 error[E0277]: the size for values of type `dyn Trait` cannot be known at compilation time
   --> $DIR/bad-sized.rs:4:12
diff --git a/src/test/ui/error-codes/E0225.rs b/src/test/ui/error-codes/E0225.rs
index 1789be1559d..b50f68e6451 100644
--- a/src/test/ui/error-codes/E0225.rs
+++ b/src/test/ui/error-codes/E0225.rs
@@ -1,4 +1,10 @@
+#![feature(trait_alias)]
+
+trait Foo = std::io::Read + std::io::Write;
+
 fn main() {
-    let _: Box<std::io::Read + std::io::Write>;
+    let _: Box<dyn std::io::Read + std::io::Write>;
+    //~^ ERROR only auto traits can be used as additional traits in a trait object [E0225]
+    let _: Box<dyn Foo>;
     //~^ ERROR only auto traits can be used as additional traits in a trait object [E0225]
 }
diff --git a/src/test/ui/error-codes/E0225.stderr b/src/test/ui/error-codes/E0225.stderr
index 85a04708cb2..c7a66c327f1 100644
--- a/src/test/ui/error-codes/E0225.stderr
+++ b/src/test/ui/error-codes/E0225.stderr
@@ -1,9 +1,28 @@
 error[E0225]: only auto traits can be used as additional traits in a trait object
-  --> $DIR/E0225.rs:2:32
+  --> $DIR/E0225.rs:6:36
    |
-LL |     let _: Box<std::io::Read + std::io::Write>;
-   |                                ^^^^^^^^^^^^^^ non-auto additional trait
+LL |     let _: Box<dyn std::io::Read + std::io::Write>;
+   |                    -------------   ^^^^^^^^^^^^^^
+   |                    |               |
+   |                    |               additional non-auto trait
+   |                    |               trait alias used in trait object type (additional use)
+   |                    first non-auto trait
+   |                    trait alias used in trait object type (first use)
 
-error: aborting due to previous error
+error[E0225]: only auto traits can be used as additional traits in a trait object
+  --> $DIR/E0225.rs:8:20
+   |
+LL | trait Foo = std::io::Read + std::io::Write;
+   |             -------------   -------------- additional non-auto trait
+   |             |
+   |             first non-auto trait
+...
+LL |     let _: Box<dyn Foo>;
+   |                    ^^^
+   |                    |
+   |                    trait alias used in trait object type (additional use)
+   |                    trait alias used in trait object type (first use)
+
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0225`.
diff --git a/src/test/ui/issues/issue-22560.stderr b/src/test/ui/issues/issue-22560.stderr
index 5a056dff590..322136d35ca 100644
--- a/src/test/ui/issues/issue-22560.stderr
+++ b/src/test/ui/issues/issue-22560.stderr
@@ -1,15 +1,15 @@
 error[E0393]: the type parameter `Rhs` must be explicitly specified
-  --> $DIR/issue-22560.rs:3:13
+  --> $DIR/issue-22560.rs:6:13
    |
-LL | type Test = Add +
+LL |             Sub;
    |             ^^^ missing reference to `Rhs`
    |
    = note: because of the default `Self` reference, type parameters must be specified on object types
 
 error[E0393]: the type parameter `Rhs` must be explicitly specified
-  --> $DIR/issue-22560.rs:6:13
+  --> $DIR/issue-22560.rs:3:13
    |
-LL |             Sub;
+LL | type Test = Add +
    |             ^^^ missing reference to `Rhs`
    |
    = note: because of the default `Self` reference, type parameters must be specified on object types
@@ -17,18 +17,32 @@ LL |             Sub;
 error[E0225]: only auto traits can be used as additional traits in a trait object
   --> $DIR/issue-22560.rs:6:13
    |
+LL | type Test = Add +
+   |             ---
+   |             |
+   |             first non-auto trait
+   |             trait alias used in trait object type (first use)
+...
 LL |             Sub;
-   |             ^^^ non-auto additional trait
+   |             ^^^
+   |             |
+   |             additional non-auto trait
+   |             trait alias used in trait object type (additional use)
 
-error[E0191]: the value of the associated type `Output` (from the trait `std::ops::Add`) must be specified
+error[E0191]: the value of the associated types `Output` (from the trait `std::ops::Add`), `Output` (from the trait `std::ops::Sub`) must be specified
   --> $DIR/issue-22560.rs:3:13
    |
 LL |   type Test = Add +
    |  _____________^
+   | |_____________|
+   | |
 LL | |
 LL | |
 LL | |             Sub;
-   | |_______________^ associated type `Output` must be specified
+   | |               ^
+   | |_______________|
+   | |_______________associated type `Output` must be specified
+   |                 associated type `Output` must be specified
 
 error: aborting due to 4 previous errors
 
diff --git a/src/test/ui/issues/issue-32963.stderr b/src/test/ui/issues/issue-32963.stderr
index 70fda313170..cde4123dc3f 100644
--- a/src/test/ui/issues/issue-32963.stderr
+++ b/src/test/ui/issues/issue-32963.stderr
@@ -2,7 +2,12 @@ error[E0225]: only auto traits can be used as additional traits in a trait objec
   --> $DIR/issue-32963.rs:8:25
    |
 LL |     size_of_copy::<Misc+Copy>();
-   |                         ^^^^ non-auto additional trait
+   |                    ---- ^^^^
+   |                    |    |
+   |                    |    additional non-auto trait
+   |                    |    trait alias used in trait object type (additional use)
+   |                    first non-auto trait
+   |                    trait alias used in trait object type (first use)
 
 error[E0277]: the trait bound `dyn Misc: std::marker::Copy` is not satisfied
   --> $DIR/issue-32963.rs:8:5
diff --git a/src/test/ui/maybe-bounds.rs b/src/test/ui/maybe-bounds.rs
index 3e07026fb7d..02ed45c656f 100644
--- a/src/test/ui/maybe-bounds.rs
+++ b/src/test/ui/maybe-bounds.rs
@@ -1,6 +1,9 @@
-trait Tr: ?Sized {} //~ ERROR `?Trait` is not permitted in supertraits
+trait Tr: ?Sized {}
+//~^ ERROR `?Trait` is not permitted in supertraits
 
-type A1 = Tr + (?Sized); //~ ERROR `?Trait` is not permitted in trait object types
-type A2 = for<'a> Tr + (?Sized); //~ ERROR `?Trait` is not permitted in trait object types
+type A1 = dyn Tr + (?Sized);
+//~^ ERROR `?Trait` is not permitted in trait object types
+type A2 = dyn for<'a> Tr + (?Sized);
+//~^ ERROR `?Trait` is not permitted in trait object types
 
 fn main() {}
diff --git a/src/test/ui/maybe-bounds.stderr b/src/test/ui/maybe-bounds.stderr
index 20446c257df..1d823b6acb2 100644
--- a/src/test/ui/maybe-bounds.stderr
+++ b/src/test/ui/maybe-bounds.stderr
@@ -7,16 +7,16 @@ LL | trait Tr: ?Sized {}
    = note: traits are `?Sized` by default
 
 error: `?Trait` is not permitted in trait object types
-  --> $DIR/maybe-bounds.rs:3:16
+  --> $DIR/maybe-bounds.rs:4:20
    |
-LL | type A1 = Tr + (?Sized);
-   |                ^^^^^^^^
+LL | type A1 = dyn Tr + (?Sized);
+   |                    ^^^^^^^^
 
 error: `?Trait` is not permitted in trait object types
-  --> $DIR/maybe-bounds.rs:4:24
+  --> $DIR/maybe-bounds.rs:6:28
    |
-LL | type A2 = for<'a> Tr + (?Sized);
-   |                        ^^^^^^^^
+LL | type A2 = dyn for<'a> Tr + (?Sized);
+   |                            ^^^^^^^^
 
 error: aborting due to 3 previous errors
 
diff --git a/src/test/ui/parser/trait-object-trait-parens.rs b/src/test/ui/parser/trait-object-trait-parens.rs
index 2bbc5800015..9ac10cd1327 100644
--- a/src/test/ui/parser/trait-object-trait-parens.rs
+++ b/src/test/ui/parser/trait-object-trait-parens.rs
@@ -7,6 +7,6 @@ fn main() {
     //~^ ERROR `?Trait` is not permitted in trait object types
     let _: Box<(?Sized) + (for<'a> Trait<'a>) + (Copy)>;
     let _: Box<(for<'a> Trait<'a>) + (Copy) + (?Sized)>;
-    //~^ ERROR `?Trait` is not permitted in trait object types
-    //~| ERROR use of undeclared lifetime name `'a`
+    //~^ ERROR use of undeclared lifetime name `'a`
+    //~| ERROR `?Trait` is not permitted in trait object types
 }
diff --git a/src/test/ui/traits/trait-alias-object.rs b/src/test/ui/traits/trait-alias-object.rs
deleted file mode 100644
index 37963740117..00000000000
--- a/src/test/ui/traits/trait-alias-object.rs
+++ /dev/null
@@ -1,9 +0,0 @@
-#![feature(trait_alias)]
-
-trait EqAlias = Eq;
-trait IteratorAlias = Iterator;
-
-fn main() {
-    let _: &dyn EqAlias = &123; //~ ERROR `EqAlias` cannot be made into an object
-    let _: &dyn IteratorAlias = &vec![123].into_iter(); //~ ERROR must be specified
-}
diff --git a/src/test/ui/traits/auxiliary/trait_alias.rs b/src/test/ui/traits/trait-alias/auxiliary/trait_alias.rs
index 9e56b87e088..9e56b87e088 100644
--- a/src/test/ui/traits/auxiliary/trait_alias.rs
+++ b/src/test/ui/traits/trait-alias/auxiliary/trait_alias.rs
diff --git a/src/test/run-pass/traits/trait-alias-bounds.rs b/src/test/ui/traits/trait-alias/trait-alias-bounds.rs
index d3dd5cee0c3..428ce5102ba 100644
--- a/src/test/run-pass/traits/trait-alias-bounds.rs
+++ b/src/test/ui/traits/trait-alias/trait-alias-bounds.rs
@@ -1,3 +1,5 @@
+// run-pass
+
 #![feature(trait_alias)]
 
 use std::marker::PhantomData;
diff --git a/src/test/ui/traits/trait-alias-cross-crate.rs b/src/test/ui/traits/trait-alias/trait-alias-cross-crate.rs
index 259fc4fa5d1..259fc4fa5d1 100644
--- a/src/test/ui/traits/trait-alias-cross-crate.rs
+++ b/src/test/ui/traits/trait-alias/trait-alias-cross-crate.rs
diff --git a/src/test/ui/traits/trait-alias-cross-crate.stderr b/src/test/ui/traits/trait-alias/trait-alias-cross-crate.stderr
index 972d213ac8f..972d213ac8f 100644
--- a/src/test/ui/traits/trait-alias-cross-crate.stderr
+++ b/src/test/ui/traits/trait-alias/trait-alias-cross-crate.stderr
diff --git a/src/test/ui/traits/trait-alias-impl.rs b/src/test/ui/traits/trait-alias/trait-alias-impl.rs
index 6e35793a066..6e35793a066 100644
--- a/src/test/ui/traits/trait-alias-impl.rs
+++ b/src/test/ui/traits/trait-alias/trait-alias-impl.rs
diff --git a/src/test/ui/traits/trait-alias-impl.stderr b/src/test/ui/traits/trait-alias/trait-alias-impl.stderr
index 301db4fb71c..301db4fb71c 100644
--- a/src/test/ui/traits/trait-alias-impl.stderr
+++ b/src/test/ui/traits/trait-alias/trait-alias-impl.stderr
diff --git a/src/test/ui/traits/trait-alias/trait-alias-maybe-bound.rs b/src/test/ui/traits/trait-alias/trait-alias-maybe-bound.rs
new file mode 100644
index 00000000000..3dfcf03ce79
--- /dev/null
+++ b/src/test/ui/traits/trait-alias/trait-alias-maybe-bound.rs
@@ -0,0 +1,29 @@
+// compile-pass
+
+// Test that `dyn ... + ?Sized + ...` resulting from the expansion of trait aliases is okay.
+
+#![feature(trait_alias)]
+
+trait Foo {}
+
+trait S = ?Sized;
+
+// Nest a couple of levels deep:
+trait _0 = S;
+trait _1 = _0;
+
+// Straight list expansion:
+type _T0 = dyn _1 + Foo;
+
+// In second position:
+type _T1 = dyn Foo + _1;
+
+// ... and with an auto trait:
+type _T2 = dyn Foo + Send + _1;
+
+// Twice:
+trait _2 = _1 + _1;
+
+type _T3 = dyn _2 + Foo;
+
+fn main() {}
diff --git a/src/test/ui/traits/trait-alias/trait-alias-no-duplicates.rs b/src/test/ui/traits/trait-alias/trait-alias-no-duplicates.rs
new file mode 100644
index 00000000000..afd8400e230
--- /dev/null
+++ b/src/test/ui/traits/trait-alias/trait-alias-no-duplicates.rs
@@ -0,0 +1,126 @@
+// The purpose of this test is to demonstrate that duplicating object safe traits
+// that are not auto traits is rejected with trait aliases even though one could
+// reasonably accept this.
+
+#![feature(trait_alias)]
+
+use std::marker::Unpin;
+
+// Some arbitrary object-safe trait:
+trait Obj {}
+
+// Nest a few levels deep:
+trait _0 = Obj;
+trait _1 = _0;
+
+type _T00 = dyn _0 + _0;
+//~^ ERROR only auto traits can be used as additional traits in a trait object [E0225]
+
+type _T01 = dyn _1 + _0;
+//~^ ERROR only auto traits can be used as additional traits in a trait object [E0225]
+
+type _T02 = dyn _1 + _1;
+//~^ ERROR only auto traits can be used as additional traits in a trait object [E0225]
+
+type _T03 = dyn Obj + _1;
+//~^ ERROR only auto traits can be used as additional traits in a trait object [E0225]
+
+type _T04 = dyn _1 + Obj;
+//~^ ERROR only auto traits can be used as additional traits in a trait object [E0225]
+
+// Nest some more and in weird ways:
+
+trait _2 = _0 + _1;
+trait _3 = Obj;
+trait _4 = _3;
+
+type _T10 = dyn _2 + _3;
+//~^ ERROR only auto traits can be used as additional traits in a trait object [E0225]
+
+type _T11 = dyn _3 + _2;
+//~^ ERROR only auto traits can be used as additional traits in a trait object [E0225]
+
+type _T12 = dyn Obj + _2;
+//~^ ERROR only auto traits can be used as additional traits in a trait object [E0225]
+
+type _T13 = dyn _2 + Obj;
+//~^ ERROR only auto traits can be used as additional traits in a trait object [E0225]
+
+type _T14 = dyn _1 + _3;
+//~^ ERROR only auto traits can be used as additional traits in a trait object [E0225]
+
+type _T15 = dyn _3 + _1;
+//~^ ERROR only auto traits can be used as additional traits in a trait object [E0225]
+
+type _T16 = dyn _1 + _4;
+//~^ ERROR only auto traits can be used as additional traits in a trait object [E0225]
+
+type _T17 = dyn _4 + _1;
+//~^ ERROR only auto traits can be used as additional traits in a trait object [E0225]
+
+// Include auto traits:
+
+trait _5 = Obj + Send;
+
+type _T20 = dyn _5 + _5;
+//~^ ERROR only auto traits can be used as additional traits in a trait object [E0225]
+
+type _T21 = dyn Obj + _5;
+//~^ ERROR only auto traits can be used as additional traits in a trait object [E0225]
+
+type _T22 = dyn _5 + Obj;
+//~^ ERROR only auto traits can be used as additional traits in a trait object [E0225]
+
+type _T23 = dyn _5 + Send + Sync + Obj;
+//~^ ERROR only auto traits can be used as additional traits in a trait object [E0225]
+
+// Also nest:
+
+trait _6 = _5 + _5; // ==> Obj + Send + Obj + Send
+
+type _T30 = dyn _6;
+//~^ ERROR only auto traits can be used as additional traits in a trait object [E0225]
+
+type _T31 = dyn _6 + Send;
+//~^ ERROR only auto traits can be used as additional traits in a trait object [E0225]
+
+type _T32 = dyn Send + _6;
+//~^ ERROR only auto traits can be used as additional traits in a trait object [E0225]
+
+// Nest some more:
+
+trait _7 = _5 + Sync;
+trait _8 = Unpin + _7;
+
+type _T40 = dyn _8 + Obj;
+//~^ ERROR only auto traits can be used as additional traits in a trait object [E0225]
+
+type _T41 = dyn Obj + _8;
+//~^ ERROR only auto traits can be used as additional traits in a trait object [E0225]
+
+type _T42 = dyn _8 + _4;
+//~^ ERROR only auto traits can be used as additional traits in a trait object [E0225]
+
+type _T43 = dyn _4 + _8;
+//~^ ERROR only auto traits can be used as additional traits in a trait object [E0225]
+
+type _T44 = dyn _4 + Send + Sync + _8;
+//~^ ERROR only auto traits can be used as additional traits in a trait object [E0225]
+
+// Take higher ranked types into account.
+
+// Note that `'a` and `'b` are intentionally different to make sure we consider
+// them semantically the same.
+trait ObjL<'l> {}
+trait _9 = for<'a> ObjL<'a>;
+trait _10 = for<'b> ObjL<'b>;
+type _T50 = _9 + _10;
+//~^ ERROR only auto traits can be used as additional traits in a trait object [E0225]
+
+trait ObjT<T> {}
+trait _11 = ObjT<for<'a> fn(&'a u8)>;
+trait _12 = ObjT<for<'b> fn(&'b u8)>;
+type _T60 = _11 + _12;
+//~^ ERROR only auto traits can be used as additional traits in a trait object [E0225]
+
+fn main() {}
diff --git a/src/test/ui/traits/trait-alias/trait-alias-no-duplicates.stderr b/src/test/ui/traits/trait-alias/trait-alias-no-duplicates.stderr
new file mode 100644
index 00000000000..eb667c9522c
--- /dev/null
+++ b/src/test/ui/traits/trait-alias/trait-alias-no-duplicates.stderr
@@ -0,0 +1,458 @@
+error[E0225]: only auto traits can be used as additional traits in a trait object
+  --> $DIR/trait-alias-no-duplicates.rs:16:22
+   |
+LL | trait _0 = Obj;
+   |            ---
+   |            |
+   |            additional non-auto trait
+   |            first non-auto trait
+...
+LL | type _T00 = dyn _0 + _0;
+   |                 --   ^^ trait alias used in trait object type (additional use)
+   |                 |
+   |                 trait alias used in trait object type (first use)
+
+error[E0225]: only auto traits can be used as additional traits in a trait object
+  --> $DIR/trait-alias-no-duplicates.rs:19:22
+   |
+LL | trait _0 = Obj;
+   |            ---
+   |            |
+   |            additional non-auto trait
+   |            first non-auto trait
+LL | trait _1 = _0;
+   |            -- referenced here (first use)
+...
+LL | type _T01 = dyn _1 + _0;
+   |                 --   ^^ trait alias used in trait object type (additional use)
+   |                 |
+   |                 trait alias used in trait object type (first use)
+
+error[E0225]: only auto traits can be used as additional traits in a trait object
+  --> $DIR/trait-alias-no-duplicates.rs:22:22
+   |
+LL | trait _0 = Obj;
+   |            ---
+   |            |
+   |            additional non-auto trait
+   |            first non-auto trait
+LL | trait _1 = _0;
+   |            --
+   |            |
+   |            referenced here (additional use)
+   |            referenced here (first use)
+...
+LL | type _T02 = dyn _1 + _1;
+   |                 --   ^^ trait alias used in trait object type (additional use)
+   |                 |
+   |                 trait alias used in trait object type (first use)
+
+error[E0225]: only auto traits can be used as additional traits in a trait object
+  --> $DIR/trait-alias-no-duplicates.rs:25:23
+   |
+LL | trait _0 = Obj;
+   |            --- additional non-auto trait
+LL | trait _1 = _0;
+   |            -- referenced here (additional use)
+...
+LL | type _T03 = dyn Obj + _1;
+   |                 ---   ^^ trait alias used in trait object type (additional use)
+   |                 |
+   |                 first non-auto trait
+   |                 trait alias used in trait object type (first use)
+
+error[E0225]: only auto traits can be used as additional traits in a trait object
+  --> $DIR/trait-alias-no-duplicates.rs:28:22
+   |
+LL | trait _0 = Obj;
+   |            --- first non-auto trait
+LL | trait _1 = _0;
+   |            -- referenced here (first use)
+...
+LL | type _T04 = dyn _1 + Obj;
+   |                 --   ^^^
+   |                 |    |
+   |                 |    additional non-auto trait
+   |                 |    trait alias used in trait object type (additional use)
+   |                 trait alias used in trait object type (first use)
+
+error[E0225]: only auto traits can be used as additional traits in a trait object
+  --> $DIR/trait-alias-no-duplicates.rs:37:17
+   |
+LL | trait _0 = Obj;
+   |            ---
+   |            |
+   |            additional non-auto trait
+   |            first non-auto trait
+LL | trait _1 = _0;
+   |            -- referenced here (additional use)
+...
+LL | trait _2 = _0 + _1;
+   |            --   -- referenced here (additional use)
+   |            |
+   |            referenced here (first use)
+...
+LL | type _T10 = dyn _2 + _3;
+   |                 ^^
+   |                 |
+   |                 trait alias used in trait object type (additional use)
+   |                 trait alias used in trait object type (first use)
+
+error[E0225]: only auto traits can be used as additional traits in a trait object
+  --> $DIR/trait-alias-no-duplicates.rs:40:22
+   |
+LL | trait _0 = Obj;
+   |            --- additional non-auto trait
+...
+LL | trait _2 = _0 + _1;
+   |            -- referenced here (additional use)
+LL | trait _3 = Obj;
+   |            --- first non-auto trait
+...
+LL | type _T11 = dyn _3 + _2;
+   |                 --   ^^ trait alias used in trait object type (additional use)
+   |                 |
+   |                 trait alias used in trait object type (first use)
+
+error[E0225]: only auto traits can be used as additional traits in a trait object
+  --> $DIR/trait-alias-no-duplicates.rs:43:23
+   |
+LL | trait _0 = Obj;
+   |            --- additional non-auto trait
+...
+LL | trait _2 = _0 + _1;
+   |            -- referenced here (additional use)
+...
+LL | type _T12 = dyn Obj + _2;
+   |                 ---   ^^ trait alias used in trait object type (additional use)
+   |                 |
+   |                 first non-auto trait
+   |                 trait alias used in trait object type (first use)
+
+error[E0225]: only auto traits can be used as additional traits in a trait object
+  --> $DIR/trait-alias-no-duplicates.rs:46:17
+   |
+LL | trait _0 = Obj;
+   |            ---
+   |            |
+   |            additional non-auto trait
+   |            first non-auto trait
+LL | trait _1 = _0;
+   |            -- referenced here (additional use)
+...
+LL | trait _2 = _0 + _1;
+   |            --   -- referenced here (additional use)
+   |            |
+   |            referenced here (first use)
+...
+LL | type _T13 = dyn _2 + Obj;
+   |                 ^^
+   |                 |
+   |                 trait alias used in trait object type (additional use)
+   |                 trait alias used in trait object type (first use)
+
+error[E0225]: only auto traits can be used as additional traits in a trait object
+  --> $DIR/trait-alias-no-duplicates.rs:49:22
+   |
+LL | trait _0 = Obj;
+   |            --- first non-auto trait
+LL | trait _1 = _0;
+   |            -- referenced here (first use)
+...
+LL | trait _3 = Obj;
+   |            --- additional non-auto trait
+...
+LL | type _T14 = dyn _1 + _3;
+   |                 --   ^^ trait alias used in trait object type (additional use)
+   |                 |
+   |                 trait alias used in trait object type (first use)
+
+error[E0225]: only auto traits can be used as additional traits in a trait object
+  --> $DIR/trait-alias-no-duplicates.rs:52:22
+   |
+LL | trait _0 = Obj;
+   |            --- additional non-auto trait
+LL | trait _1 = _0;
+   |            -- referenced here (additional use)
+...
+LL | trait _3 = Obj;
+   |            --- first non-auto trait
+...
+LL | type _T15 = dyn _3 + _1;
+   |                 --   ^^ trait alias used in trait object type (additional use)
+   |                 |
+   |                 trait alias used in trait object type (first use)
+
+error[E0225]: only auto traits can be used as additional traits in a trait object
+  --> $DIR/trait-alias-no-duplicates.rs:55:22
+   |
+LL | trait _0 = Obj;
+   |            --- first non-auto trait
+LL | trait _1 = _0;
+   |            -- referenced here (first use)
+...
+LL | trait _3 = Obj;
+   |            --- additional non-auto trait
+LL | trait _4 = _3;
+   |            -- referenced here (additional use)
+...
+LL | type _T16 = dyn _1 + _4;
+   |                 --   ^^ trait alias used in trait object type (additional use)
+   |                 |
+   |                 trait alias used in trait object type (first use)
+
+error[E0225]: only auto traits can be used as additional traits in a trait object
+  --> $DIR/trait-alias-no-duplicates.rs:58:22
+   |
+LL | trait _0 = Obj;
+   |            --- additional non-auto trait
+LL | trait _1 = _0;
+   |            -- referenced here (additional use)
+...
+LL | trait _3 = Obj;
+   |            --- first non-auto trait
+LL | trait _4 = _3;
+   |            -- referenced here (first use)
+...
+LL | type _T17 = dyn _4 + _1;
+   |                 --   ^^ trait alias used in trait object type (additional use)
+   |                 |
+   |                 trait alias used in trait object type (first use)
+
+error[E0225]: only auto traits can be used as additional traits in a trait object
+  --> $DIR/trait-alias-no-duplicates.rs:65:22
+   |
+LL | trait _5 = Obj + Send;
+   |            ---
+   |            |
+   |            additional non-auto trait
+   |            first non-auto trait
+LL | 
+LL | type _T20 = dyn _5 + _5;
+   |                 --   ^^ trait alias used in trait object type (additional use)
+   |                 |
+   |                 trait alias used in trait object type (first use)
+
+error[E0225]: only auto traits can be used as additional traits in a trait object
+  --> $DIR/trait-alias-no-duplicates.rs:68:23
+   |
+LL | trait _5 = Obj + Send;
+   |            --- additional non-auto trait
+...
+LL | type _T21 = dyn Obj + _5;
+   |                 ---   ^^ trait alias used in trait object type (additional use)
+   |                 |
+   |                 first non-auto trait
+   |                 trait alias used in trait object type (first use)
+
+error[E0225]: only auto traits can be used as additional traits in a trait object
+  --> $DIR/trait-alias-no-duplicates.rs:71:22
+   |
+LL | trait _5 = Obj + Send;
+   |            --- first non-auto trait
+...
+LL | type _T22 = dyn _5 + Obj;
+   |                 --   ^^^
+   |                 |    |
+   |                 |    additional non-auto trait
+   |                 |    trait alias used in trait object type (additional use)
+   |                 trait alias used in trait object type (first use)
+
+error[E0225]: only auto traits can be used as additional traits in a trait object
+  --> $DIR/trait-alias-no-duplicates.rs:74:36
+   |
+LL | trait _5 = Obj + Send;
+   |            --- first non-auto trait
+...
+LL | type _T23 = dyn _5 + Send + Sync + Obj;
+   |                 --                 ^^^
+   |                 |                  |
+   |                 |                  additional non-auto trait
+   |                 |                  trait alias used in trait object type (additional use)
+   |                 trait alias used in trait object type (first use)
+
+error[E0225]: only auto traits can be used as additional traits in a trait object
+  --> $DIR/trait-alias-no-duplicates.rs:81:17
+   |
+LL | trait _5 = Obj + Send;
+   |            ---
+   |            |
+   |            additional non-auto trait
+   |            first non-auto trait
+...
+LL | trait _6 = _5 + _5; // ==> Obj + Send + Obj + Send
+   |            --   -- referenced here (additional use)
+   |            |
+   |            referenced here (first use)
+LL | 
+LL | type _T30 = dyn _6;
+   |                 ^^
+   |                 |
+   |                 trait alias used in trait object type (additional use)
+   |                 trait alias used in trait object type (first use)
+
+error[E0225]: only auto traits can be used as additional traits in a trait object
+  --> $DIR/trait-alias-no-duplicates.rs:84:17
+   |
+LL | trait _5 = Obj + Send;
+   |            ---
+   |            |
+   |            additional non-auto trait
+   |            first non-auto trait
+...
+LL | trait _6 = _5 + _5; // ==> Obj + Send + Obj + Send
+   |            --   -- referenced here (additional use)
+   |            |
+   |            referenced here (first use)
+...
+LL | type _T31 = dyn _6 + Send;
+   |                 ^^
+   |                 |
+   |                 trait alias used in trait object type (additional use)
+   |                 trait alias used in trait object type (first use)
+
+error[E0225]: only auto traits can be used as additional traits in a trait object
+  --> $DIR/trait-alias-no-duplicates.rs:87:24
+   |
+LL | trait _5 = Obj + Send;
+   |            ---
+   |            |
+   |            additional non-auto trait
+   |            first non-auto trait
+...
+LL | trait _6 = _5 + _5; // ==> Obj + Send + Obj + Send
+   |            --   -- referenced here (additional use)
+   |            |
+   |            referenced here (first use)
+...
+LL | type _T32 = dyn Send + _6;
+   |                        ^^
+   |                        |
+   |                        trait alias used in trait object type (additional use)
+   |                        trait alias used in trait object type (first use)
+
+error[E0225]: only auto traits can be used as additional traits in a trait object
+  --> $DIR/trait-alias-no-duplicates.rs:95:22
+   |
+LL | trait _5 = Obj + Send;
+   |            --- first non-auto trait
+...
+LL | trait _7 = _5 + Sync;
+   |            -- referenced here (first use)
+LL | trait _8 = Unpin + _7;
+   |                    -- referenced here (first use)
+LL | 
+LL | type _T40 = dyn _8 + Obj;
+   |                 --   ^^^
+   |                 |    |
+   |                 |    additional non-auto trait
+   |                 |    trait alias used in trait object type (additional use)
+   |                 trait alias used in trait object type (first use)
+
+error[E0225]: only auto traits can be used as additional traits in a trait object
+  --> $DIR/trait-alias-no-duplicates.rs:98:23
+   |
+LL | trait _5 = Obj + Send;
+   |            --- additional non-auto trait
+...
+LL | trait _7 = _5 + Sync;
+   |            -- referenced here (additional use)
+LL | trait _8 = Unpin + _7;
+   |                    -- referenced here (additional use)
+...
+LL | type _T41 = dyn Obj + _8;
+   |                 ---   ^^ trait alias used in trait object type (additional use)
+   |                 |
+   |                 first non-auto trait
+   |                 trait alias used in trait object type (first use)
+
+error[E0225]: only auto traits can be used as additional traits in a trait object
+  --> $DIR/trait-alias-no-duplicates.rs:101:22
+   |
+LL | trait _3 = Obj;
+   |            --- additional non-auto trait
+LL | trait _4 = _3;
+   |            -- referenced here (additional use)
+...
+LL | trait _5 = Obj + Send;
+   |            --- first non-auto trait
+...
+LL | trait _7 = _5 + Sync;
+   |            -- referenced here (first use)
+LL | trait _8 = Unpin + _7;
+   |                    -- referenced here (first use)
+...
+LL | type _T42 = dyn _8 + _4;
+   |                 --   ^^ trait alias used in trait object type (additional use)
+   |                 |
+   |                 trait alias used in trait object type (first use)
+
+error[E0225]: only auto traits can be used as additional traits in a trait object
+  --> $DIR/trait-alias-no-duplicates.rs:104:22
+   |
+LL | trait _3 = Obj;
+   |            --- first non-auto trait
+LL | trait _4 = _3;
+   |            -- referenced here (first use)
+...
+LL | trait _5 = Obj + Send;
+   |            --- additional non-auto trait
+...
+LL | trait _7 = _5 + Sync;
+   |            -- referenced here (additional use)
+LL | trait _8 = Unpin + _7;
+   |                    -- referenced here (additional use)
+...
+LL | type _T43 = dyn _4 + _8;
+   |                 --   ^^ trait alias used in trait object type (additional use)
+   |                 |
+   |                 trait alias used in trait object type (first use)
+
+error[E0225]: only auto traits can be used as additional traits in a trait object
+  --> $DIR/trait-alias-no-duplicates.rs:107:36
+   |
+LL | trait _3 = Obj;
+   |            --- first non-auto trait
+LL | trait _4 = _3;
+   |            -- referenced here (first use)
+...
+LL | trait _5 = Obj + Send;
+   |            --- additional non-auto trait
+...
+LL | trait _7 = _5 + Sync;
+   |            -- referenced here (additional use)
+LL | trait _8 = Unpin + _7;
+   |                    -- referenced here (additional use)
+...
+LL | type _T44 = dyn _4 + Send + Sync + _8;
+   |                 --                 ^^ trait alias used in trait object type (additional use)
+   |                 |
+   |                 trait alias used in trait object type (first use)
+
+error[E0225]: only auto traits can be used as additional traits in a trait object
+  --> $DIR/trait-alias-no-duplicates.rs:117:18
+   |
+LL | trait _9 = for<'a> ObjL<'a>;
+   |            ---------------- first non-auto trait
+LL | trait _10 = for<'b> ObjL<'b>;
+   |             ---------------- additional non-auto trait
+LL | type _T50 = _9 + _10;
+   |             --   ^^^ trait alias used in trait object type (additional use)
+   |             |
+   |             trait alias used in trait object type (first use)
+
+error[E0225]: only auto traits can be used as additional traits in a trait object
+  --> $DIR/trait-alias-no-duplicates.rs:123:19
+   |
+LL | trait _11 = ObjT<for<'a> fn(&'a u8)>;
+   |             ------------------------ first non-auto trait
+LL | trait _12 = ObjT<for<'b> fn(&'b u8)>;
+   |             ------------------------ additional non-auto trait
+LL | type _T60 = _11 + _12;
+   |             ---   ^^^ trait alias used in trait object type (additional use)
+   |             |
+   |             trait alias used in trait object type (first use)
+
+error: aborting due to 27 previous errors
+
+For more information about this error, try `rustc --explain E0225`.
diff --git a/src/test/ui/traits/trait-alias/trait-alias-no-extra-traits.rs b/src/test/ui/traits/trait-alias/trait-alias-no-extra-traits.rs
new file mode 100644
index 00000000000..4dad8c0f873
--- /dev/null
+++ b/src/test/ui/traits/trait-alias/trait-alias-no-extra-traits.rs
@@ -0,0 +1,121 @@
+// The purpose of this test is to demonstrate that trait alias expansion
+// preserves the rule that `dyn Trait` may only reference one non-auto trait.
+
+#![feature(trait_alias)]
+
+use std::marker::Unpin;
+
+// Some arbitrary object-safe traits:
+trait ObjA {}
+trait ObjB {}
+
+// Nest a few levels deep:
+trait _0 = ObjA;
+trait _1 = _0;
+
+type _T00 = dyn _0 + ObjB;
+//~^ ERROR only auto traits can be used as additional traits in a trait object [E0225]
+
+type _T01 = dyn ObjB + _0;
+//~^ ERROR only auto traits can be used as additional traits in a trait object [E0225]
+
+type _T02 = dyn ObjB + _1;
+//~^ ERROR only auto traits can be used as additional traits in a trait object [E0225]
+
+type _T03 = dyn _1 + ObjB;
+//~^ ERROR only auto traits can be used as additional traits in a trait object [E0225]
+
+// Nest some more and in weird ways:
+
+trait _2 = ObjB;
+trait _3 = _2;
+trait _4 = _3;
+
+type _T10 = dyn _2 + _3;
+//~^ ERROR only auto traits can be used as additional traits in a trait object [E0225]
+
+type _T11 = dyn _3 + _2;
+//~^ ERROR only auto traits can be used as additional traits in a trait object [E0225]
+
+type _T12 = dyn _2 + _4;
+//~^ ERROR only auto traits can be used as additional traits in a trait object [E0225]
+
+type _T13 = dyn _4 + _2;
+//~^ ERROR only auto traits can be used as additional traits in a trait object [E0225]
+
+// Include auto traits:
+
+trait _5 = Sync + ObjB + Send;
+
+type _T20 = dyn _5 + _1;
+//~^ ERROR only auto traits can be used as additional traits in a trait object [E0225]
+
+type _T21 = dyn _1 + _5;
+//~^ ERROR only auto traits can be used as additional traits in a trait object [E0225]
+
+type _T22 = dyn _5 + ObjA;
+//~^ ERROR only auto traits can be used as additional traits in a trait object [E0225]
+
+type _T23 = dyn ObjA + _5;
+//~^ ERROR only auto traits can be used as additional traits in a trait object [E0225]
+
+type _T24 = dyn Send + _5 + _1 + Sync;
+//~^ ERROR only auto traits can be used as additional traits in a trait object [E0225]
+
+type _T25 = dyn _1 + Sync + _5 + Send;
+//~^ ERROR only auto traits can be used as additional traits in a trait object [E0225]
+
+type _T26 = dyn Sync + Send + _5 + ObjA;
+//~^ ERROR only auto traits can be used as additional traits in a trait object [E0225]
+
+type _T27 = dyn Send + Sync + ObjA + _5;
+//~^ ERROR only auto traits can be used as additional traits in a trait object [E0225]
+
+// Also nest:
+
+trait _6 = _1 + _5;
+trait _7 = _6;
+trait _8 = _7;
+
+type _T30 = dyn _6;
+//~^ ERROR only auto traits can be used as additional traits in a trait object [E0225]
+
+type _T31 = dyn _6 + Send;
+//~^ ERROR only auto traits can be used as additional traits in a trait object [E0225]
+
+type _T32 = dyn Send + _6;
+//~^ ERROR only auto traits can be used as additional traits in a trait object [E0225]
+
+type _T33 = dyn _8;
+//~^ ERROR only auto traits can be used as additional traits in a trait object [E0225]
+
+type _T34 = dyn _8 + Send;
+//~^ ERROR only auto traits can be used as additional traits in a trait object [E0225]
+
+type _T35 = dyn Send + _8;
+//~^ ERROR only auto traits can be used as additional traits in a trait object [E0225]
+
+// Nest some more:
+
+trait _9 = _5 + Sync;
+trait _10 = Unpin + _9;
+
+type _T40 = dyn _10 + ObjA;
+//~^ ERROR only auto traits can be used as additional traits in a trait object [E0225]
+
+type _T41 = dyn ObjA + _10;
+//~^ ERROR only auto traits can be used as additional traits in a trait object [E0225]
+
+type _T42 = dyn _10 + _1;
+//~^ ERROR only auto traits can be used as additional traits in a trait object [E0225]
+
+type _T43 = dyn Send + _10 + Sync + ObjA;
+//~^ ERROR only auto traits can be used as additional traits in a trait object [E0225]
+
+type _T44 = dyn ObjA + _10 + Send + Sync;
+//~^ ERROR only auto traits can be used as additional traits in a trait object [E0225]
+
+type _T45 = dyn Sync + Send + _10 + _1;
+//~^ ERROR only auto traits can be used as additional traits in a trait object [E0225]
+
+fn main() {}
diff --git a/src/test/ui/traits/trait-alias/trait-alias-no-extra-traits.stderr b/src/test/ui/traits/trait-alias/trait-alias-no-extra-traits.stderr
new file mode 100644
index 00000000000..15685a22883
--- /dev/null
+++ b/src/test/ui/traits/trait-alias/trait-alias-no-extra-traits.stderr
@@ -0,0 +1,513 @@
+error[E0225]: only auto traits can be used as additional traits in a trait object
+  --> $DIR/trait-alias-no-extra-traits.rs:16:22
+   |
+LL | trait _0 = ObjA;
+   |            ---- first non-auto trait
+...
+LL | type _T00 = dyn _0 + ObjB;
+   |                 --   ^^^^
+   |                 |    |
+   |                 |    additional non-auto trait
+   |                 |    trait alias used in trait object type (additional use)
+   |                 trait alias used in trait object type (first use)
+
+error[E0225]: only auto traits can be used as additional traits in a trait object
+  --> $DIR/trait-alias-no-extra-traits.rs:19:24
+   |
+LL | trait _0 = ObjA;
+   |            ---- additional non-auto trait
+...
+LL | type _T01 = dyn ObjB + _0;
+   |                 ----   ^^ trait alias used in trait object type (additional use)
+   |                 |
+   |                 first non-auto trait
+   |                 trait alias used in trait object type (first use)
+
+error[E0225]: only auto traits can be used as additional traits in a trait object
+  --> $DIR/trait-alias-no-extra-traits.rs:22:24
+   |
+LL | trait _0 = ObjA;
+   |            ---- additional non-auto trait
+LL | trait _1 = _0;
+   |            -- referenced here (additional use)
+...
+LL | type _T02 = dyn ObjB + _1;
+   |                 ----   ^^ trait alias used in trait object type (additional use)
+   |                 |
+   |                 first non-auto trait
+   |                 trait alias used in trait object type (first use)
+
+error[E0225]: only auto traits can be used as additional traits in a trait object
+  --> $DIR/trait-alias-no-extra-traits.rs:25:22
+   |
+LL | trait _0 = ObjA;
+   |            ---- first non-auto trait
+LL | trait _1 = _0;
+   |            -- referenced here (first use)
+...
+LL | type _T03 = dyn _1 + ObjB;
+   |                 --   ^^^^
+   |                 |    |
+   |                 |    additional non-auto trait
+   |                 |    trait alias used in trait object type (additional use)
+   |                 trait alias used in trait object type (first use)
+
+error[E0225]: only auto traits can be used as additional traits in a trait object
+  --> $DIR/trait-alias-no-extra-traits.rs:34:22
+   |
+LL | trait _2 = ObjB;
+   |            ----
+   |            |
+   |            additional non-auto trait
+   |            first non-auto trait
+LL | trait _3 = _2;
+   |            -- referenced here (additional use)
+...
+LL | type _T10 = dyn _2 + _3;
+   |                 --   ^^ trait alias used in trait object type (additional use)
+   |                 |
+   |                 trait alias used in trait object type (first use)
+
+error[E0225]: only auto traits can be used as additional traits in a trait object
+  --> $DIR/trait-alias-no-extra-traits.rs:37:22
+   |
+LL | trait _2 = ObjB;
+   |            ----
+   |            |
+   |            additional non-auto trait
+   |            first non-auto trait
+LL | trait _3 = _2;
+   |            -- referenced here (first use)
+...
+LL | type _T11 = dyn _3 + _2;
+   |                 --   ^^ trait alias used in trait object type (additional use)
+   |                 |
+   |                 trait alias used in trait object type (first use)
+
+error[E0225]: only auto traits can be used as additional traits in a trait object
+  --> $DIR/trait-alias-no-extra-traits.rs:40:22
+   |
+LL | trait _2 = ObjB;
+   |            ----
+   |            |
+   |            additional non-auto trait
+   |            first non-auto trait
+LL | trait _3 = _2;
+   |            -- referenced here (additional use)
+LL | trait _4 = _3;
+   |            -- referenced here (additional use)
+...
+LL | type _T12 = dyn _2 + _4;
+   |                 --   ^^ trait alias used in trait object type (additional use)
+   |                 |
+   |                 trait alias used in trait object type (first use)
+
+error[E0225]: only auto traits can be used as additional traits in a trait object
+  --> $DIR/trait-alias-no-extra-traits.rs:43:22
+   |
+LL | trait _2 = ObjB;
+   |            ----
+   |            |
+   |            additional non-auto trait
+   |            first non-auto trait
+LL | trait _3 = _2;
+   |            -- referenced here (first use)
+LL | trait _4 = _3;
+   |            -- referenced here (first use)
+...
+LL | type _T13 = dyn _4 + _2;
+   |                 --   ^^ trait alias used in trait object type (additional use)
+   |                 |
+   |                 trait alias used in trait object type (first use)
+
+error[E0225]: only auto traits can be used as additional traits in a trait object
+  --> $DIR/trait-alias-no-extra-traits.rs:50:22
+   |
+LL | trait _0 = ObjA;
+   |            ---- additional non-auto trait
+LL | trait _1 = _0;
+   |            -- referenced here (additional use)
+...
+LL | trait _5 = Sync + ObjB + Send;
+   |                   ---- first non-auto trait
+LL | 
+LL | type _T20 = dyn _5 + _1;
+   |                 --   ^^ trait alias used in trait object type (additional use)
+   |                 |
+   |                 trait alias used in trait object type (first use)
+
+error[E0225]: only auto traits can be used as additional traits in a trait object
+  --> $DIR/trait-alias-no-extra-traits.rs:53:22
+   |
+LL | trait _0 = ObjA;
+   |            ---- first non-auto trait
+LL | trait _1 = _0;
+   |            -- referenced here (first use)
+...
+LL | trait _5 = Sync + ObjB + Send;
+   |                   ---- additional non-auto trait
+...
+LL | type _T21 = dyn _1 + _5;
+   |                 --   ^^ trait alias used in trait object type (additional use)
+   |                 |
+   |                 trait alias used in trait object type (first use)
+
+error[E0225]: only auto traits can be used as additional traits in a trait object
+  --> $DIR/trait-alias-no-extra-traits.rs:56:22
+   |
+LL | trait _5 = Sync + ObjB + Send;
+   |                   ---- first non-auto trait
+...
+LL | type _T22 = dyn _5 + ObjA;
+   |                 --   ^^^^
+   |                 |    |
+   |                 |    additional non-auto trait
+   |                 |    trait alias used in trait object type (additional use)
+   |                 trait alias used in trait object type (first use)
+
+error[E0225]: only auto traits can be used as additional traits in a trait object
+  --> $DIR/trait-alias-no-extra-traits.rs:59:24
+   |
+LL | trait _5 = Sync + ObjB + Send;
+   |                   ---- additional non-auto trait
+...
+LL | type _T23 = dyn ObjA + _5;
+   |                 ----   ^^ trait alias used in trait object type (additional use)
+   |                 |
+   |                 first non-auto trait
+   |                 trait alias used in trait object type (first use)
+
+error[E0225]: only auto traits can be used as additional traits in a trait object
+  --> $DIR/trait-alias-no-extra-traits.rs:62:29
+   |
+LL | trait _0 = ObjA;
+   |            ---- additional non-auto trait
+LL | trait _1 = _0;
+   |            -- referenced here (additional use)
+...
+LL | trait _5 = Sync + ObjB + Send;
+   |                   ---- first non-auto trait
+...
+LL | type _T24 = dyn Send + _5 + _1 + Sync;
+   |                        --   ^^ trait alias used in trait object type (additional use)
+   |                        |
+   |                        trait alias used in trait object type (first use)
+
+error[E0225]: only auto traits can be used as additional traits in a trait object
+  --> $DIR/trait-alias-no-extra-traits.rs:65:29
+   |
+LL | trait _0 = ObjA;
+   |            ---- first non-auto trait
+LL | trait _1 = _0;
+   |            -- referenced here (first use)
+...
+LL | trait _5 = Sync + ObjB + Send;
+   |                   ---- additional non-auto trait
+...
+LL | type _T25 = dyn _1 + Sync + _5 + Send;
+   |                 --          ^^ trait alias used in trait object type (additional use)
+   |                 |
+   |                 trait alias used in trait object type (first use)
+
+error[E0225]: only auto traits can be used as additional traits in a trait object
+  --> $DIR/trait-alias-no-extra-traits.rs:68:36
+   |
+LL | trait _5 = Sync + ObjB + Send;
+   |                   ---- first non-auto trait
+...
+LL | type _T26 = dyn Sync + Send + _5 + ObjA;
+   |                               --   ^^^^
+   |                               |    |
+   |                               |    additional non-auto trait
+   |                               |    trait alias used in trait object type (additional use)
+   |                               trait alias used in trait object type (first use)
+
+error[E0225]: only auto traits can be used as additional traits in a trait object
+  --> $DIR/trait-alias-no-extra-traits.rs:71:38
+   |
+LL | trait _5 = Sync + ObjB + Send;
+   |                   ---- additional non-auto trait
+...
+LL | type _T27 = dyn Send + Sync + ObjA + _5;
+   |                               ----   ^^ trait alias used in trait object type (additional use)
+   |                               |
+   |                               first non-auto trait
+   |                               trait alias used in trait object type (first use)
+
+error[E0225]: only auto traits can be used as additional traits in a trait object
+  --> $DIR/trait-alias-no-extra-traits.rs:80:17
+   |
+LL | trait _0 = ObjA;
+   |            ---- first non-auto trait
+LL | trait _1 = _0;
+   |            -- referenced here (first use)
+...
+LL | trait _5 = Sync + ObjB + Send;
+   |                   ---- additional non-auto trait
+...
+LL | trait _6 = _1 + _5;
+   |            --   -- referenced here (additional use)
+   |            |
+   |            referenced here (first use)
+...
+LL | type _T30 = dyn _6;
+   |                 ^^
+   |                 |
+   |                 trait alias used in trait object type (additional use)
+   |                 trait alias used in trait object type (first use)
+
+error[E0225]: only auto traits can be used as additional traits in a trait object
+  --> $DIR/trait-alias-no-extra-traits.rs:83:17
+   |
+LL | trait _0 = ObjA;
+   |            ---- first non-auto trait
+LL | trait _1 = _0;
+   |            -- referenced here (first use)
+...
+LL | trait _5 = Sync + ObjB + Send;
+   |                   ---- additional non-auto trait
+...
+LL | trait _6 = _1 + _5;
+   |            --   -- referenced here (additional use)
+   |            |
+   |            referenced here (first use)
+...
+LL | type _T31 = dyn _6 + Send;
+   |                 ^^
+   |                 |
+   |                 trait alias used in trait object type (additional use)
+   |                 trait alias used in trait object type (first use)
+
+error[E0225]: only auto traits can be used as additional traits in a trait object
+  --> $DIR/trait-alias-no-extra-traits.rs:86:24
+   |
+LL | trait _0 = ObjA;
+   |            ---- first non-auto trait
+LL | trait _1 = _0;
+   |            -- referenced here (first use)
+...
+LL | trait _5 = Sync + ObjB + Send;
+   |                   ---- additional non-auto trait
+...
+LL | trait _6 = _1 + _5;
+   |            --   -- referenced here (additional use)
+   |            |
+   |            referenced here (first use)
+...
+LL | type _T32 = dyn Send + _6;
+   |                        ^^
+   |                        |
+   |                        trait alias used in trait object type (additional use)
+   |                        trait alias used in trait object type (first use)
+
+error[E0225]: only auto traits can be used as additional traits in a trait object
+  --> $DIR/trait-alias-no-extra-traits.rs:89:17
+   |
+LL | trait _0 = ObjA;
+   |            ---- first non-auto trait
+LL | trait _1 = _0;
+   |            -- referenced here (first use)
+...
+LL | trait _5 = Sync + ObjB + Send;
+   |                   ---- additional non-auto trait
+...
+LL | trait _6 = _1 + _5;
+   |            --   -- referenced here (additional use)
+   |            |
+   |            referenced here (first use)
+LL | trait _7 = _6;
+   |            --
+   |            |
+   |            referenced here (additional use)
+   |            referenced here (first use)
+LL | trait _8 = _7;
+   |            --
+   |            |
+   |            referenced here (additional use)
+   |            referenced here (first use)
+...
+LL | type _T33 = dyn _8;
+   |                 ^^
+   |                 |
+   |                 trait alias used in trait object type (additional use)
+   |                 trait alias used in trait object type (first use)
+
+error[E0225]: only auto traits can be used as additional traits in a trait object
+  --> $DIR/trait-alias-no-extra-traits.rs:92:17
+   |
+LL | trait _0 = ObjA;
+   |            ---- first non-auto trait
+LL | trait _1 = _0;
+   |            -- referenced here (first use)
+...
+LL | trait _5 = Sync + ObjB + Send;
+   |                   ---- additional non-auto trait
+...
+LL | trait _6 = _1 + _5;
+   |            --   -- referenced here (additional use)
+   |            |
+   |            referenced here (first use)
+LL | trait _7 = _6;
+   |            --
+   |            |
+   |            referenced here (additional use)
+   |            referenced here (first use)
+LL | trait _8 = _7;
+   |            --
+   |            |
+   |            referenced here (additional use)
+   |            referenced here (first use)
+...
+LL | type _T34 = dyn _8 + Send;
+   |                 ^^
+   |                 |
+   |                 trait alias used in trait object type (additional use)
+   |                 trait alias used in trait object type (first use)
+
+error[E0225]: only auto traits can be used as additional traits in a trait object
+  --> $DIR/trait-alias-no-extra-traits.rs:95:24
+   |
+LL | trait _0 = ObjA;
+   |            ---- first non-auto trait
+LL | trait _1 = _0;
+   |            -- referenced here (first use)
+...
+LL | trait _5 = Sync + ObjB + Send;
+   |                   ---- additional non-auto trait
+...
+LL | trait _6 = _1 + _5;
+   |            --   -- referenced here (additional use)
+   |            |
+   |            referenced here (first use)
+LL | trait _7 = _6;
+   |            --
+   |            |
+   |            referenced here (additional use)
+   |            referenced here (first use)
+LL | trait _8 = _7;
+   |            --
+   |            |
+   |            referenced here (additional use)
+   |            referenced here (first use)
+...
+LL | type _T35 = dyn Send + _8;
+   |                        ^^
+   |                        |
+   |                        trait alias used in trait object type (additional use)
+   |                        trait alias used in trait object type (first use)
+
+error[E0225]: only auto traits can be used as additional traits in a trait object
+  --> $DIR/trait-alias-no-extra-traits.rs:103:23
+   |
+LL | trait _5 = Sync + ObjB + Send;
+   |                   ---- first non-auto trait
+...
+LL | trait _9 = _5 + Sync;
+   |            -- referenced here (first use)
+LL | trait _10 = Unpin + _9;
+   |                     -- referenced here (first use)
+LL | 
+LL | type _T40 = dyn _10 + ObjA;
+   |                 ---   ^^^^
+   |                 |     |
+   |                 |     additional non-auto trait
+   |                 |     trait alias used in trait object type (additional use)
+   |                 trait alias used in trait object type (first use)
+
+error[E0225]: only auto traits can be used as additional traits in a trait object
+  --> $DIR/trait-alias-no-extra-traits.rs:106:24
+   |
+LL | trait _5 = Sync + ObjB + Send;
+   |                   ---- additional non-auto trait
+...
+LL | trait _9 = _5 + Sync;
+   |            -- referenced here (additional use)
+LL | trait _10 = Unpin + _9;
+   |                     -- referenced here (additional use)
+...
+LL | type _T41 = dyn ObjA + _10;
+   |                 ----   ^^^ trait alias used in trait object type (additional use)
+   |                 |
+   |                 first non-auto trait
+   |                 trait alias used in trait object type (first use)
+
+error[E0225]: only auto traits can be used as additional traits in a trait object
+  --> $DIR/trait-alias-no-extra-traits.rs:109:23
+   |
+LL | trait _0 = ObjA;
+   |            ---- additional non-auto trait
+LL | trait _1 = _0;
+   |            -- referenced here (additional use)
+...
+LL | trait _5 = Sync + ObjB + Send;
+   |                   ---- first non-auto trait
+...
+LL | trait _9 = _5 + Sync;
+   |            -- referenced here (first use)
+LL | trait _10 = Unpin + _9;
+   |                     -- referenced here (first use)
+...
+LL | type _T42 = dyn _10 + _1;
+   |                 ---   ^^ trait alias used in trait object type (additional use)
+   |                 |
+   |                 trait alias used in trait object type (first use)
+
+error[E0225]: only auto traits can be used as additional traits in a trait object
+  --> $DIR/trait-alias-no-extra-traits.rs:112:37
+   |
+LL | trait _5 = Sync + ObjB + Send;
+   |                   ---- first non-auto trait
+...
+LL | trait _9 = _5 + Sync;
+   |            -- referenced here (first use)
+LL | trait _10 = Unpin + _9;
+   |                     -- referenced here (first use)
+...
+LL | type _T43 = dyn Send + _10 + Sync + ObjA;
+   |                        ---          ^^^^
+   |                        |            |
+   |                        |            additional non-auto trait
+   |                        |            trait alias used in trait object type (additional use)
+   |                        trait alias used in trait object type (first use)
+
+error[E0225]: only auto traits can be used as additional traits in a trait object
+  --> $DIR/trait-alias-no-extra-traits.rs:115:24
+   |
+LL | trait _5 = Sync + ObjB + Send;
+   |                   ---- additional non-auto trait
+...
+LL | trait _9 = _5 + Sync;
+   |            -- referenced here (additional use)
+LL | trait _10 = Unpin + _9;
+   |                     -- referenced here (additional use)
+...
+LL | type _T44 = dyn ObjA + _10 + Send + Sync;
+   |                 ----   ^^^ trait alias used in trait object type (additional use)
+   |                 |
+   |                 first non-auto trait
+   |                 trait alias used in trait object type (first use)
+
+error[E0225]: only auto traits can be used as additional traits in a trait object
+  --> $DIR/trait-alias-no-extra-traits.rs:118:37
+   |
+LL | trait _0 = ObjA;
+   |            ---- additional non-auto trait
+LL | trait _1 = _0;
+   |            -- referenced here (additional use)
+...
+LL | trait _5 = Sync + ObjB + Send;
+   |                   ---- first non-auto trait
+...
+LL | trait _9 = _5 + Sync;
+   |            -- referenced here (first use)
+LL | trait _10 = Unpin + _9;
+   |                     -- referenced here (first use)
+...
+LL | type _T45 = dyn Sync + Send + _10 + _1;
+   |                               ---   ^^ trait alias used in trait object type (additional use)
+   |                               |
+   |                               trait alias used in trait object type (first use)
+
+error: aborting due to 28 previous errors
+
+For more information about this error, try `rustc --explain E0225`.
diff --git a/src/test/ui/traits/trait-alias/trait-alias-object-fail.rs b/src/test/ui/traits/trait-alias/trait-alias-object-fail.rs
new file mode 100644
index 00000000000..d62fd7e59c9
--- /dev/null
+++ b/src/test/ui/traits/trait-alias/trait-alias-object-fail.rs
@@ -0,0 +1,11 @@
+#![feature(trait_alias)]
+
+trait EqAlias = Eq;
+trait IteratorAlias = Iterator;
+
+fn main() {
+    let _: &dyn EqAlias = &123;
+    //~^ ERROR the trait `std::cmp::Eq` cannot be made into an object [E0038]
+    let _: &dyn IteratorAlias = &vec![123].into_iter();
+    //~^ ERROR must be specified
+}
diff --git a/src/test/ui/traits/trait-alias-object.stderr b/src/test/ui/traits/trait-alias/trait-alias-object-fail.stderr
index 353aea311e9..9a9b9177030 100644
--- a/src/test/ui/traits/trait-alias-object.stderr
+++ b/src/test/ui/traits/trait-alias/trait-alias-object-fail.stderr
@@ -1,13 +1,13 @@
-error[E0038]: the trait `EqAlias` cannot be made into an object
-  --> $DIR/trait-alias-object.rs:7:13
+error[E0038]: the trait `std::cmp::Eq` cannot be made into an object
+  --> $DIR/trait-alias-object-fail.rs:7:13
    |
 LL |     let _: &dyn EqAlias = &123;
-   |             ^^^^^^^^^^^ the trait `EqAlias` cannot be made into an object
+   |             ^^^^^^^^^^^ the trait `std::cmp::Eq` cannot be made into an object
    |
    = note: the trait cannot use `Self` as a type parameter in the supertraits or where-clauses
 
 error[E0191]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) must be specified
-  --> $DIR/trait-alias-object.rs:8:13
+  --> $DIR/trait-alias-object-fail.rs:9:13
    |
 LL |     let _: &dyn IteratorAlias = &vec![123].into_iter();
    |             ^^^^^^^^^^^^^^^^^ associated type `Item` must be specified
diff --git a/src/test/ui/traits/trait-alias/trait-alias-object-wf.rs b/src/test/ui/traits/trait-alias/trait-alias-object-wf.rs
new file mode 100644
index 00000000000..fb26b7e2df7
--- /dev/null
+++ b/src/test/ui/traits/trait-alias/trait-alias-object-wf.rs
@@ -0,0 +1,85 @@
+// run-pass
+
+// This test checks that trait objects involving trait aliases are well-formed.
+
+#![feature(trait_alias)]
+
+trait Obj {}
+
+trait _0 = Send + Sync;
+
+// Just auto traits:
+
+trait _1 = _0 + Send + Sync;
+
+use std::marker::Unpin;
+
+fn _f0() {
+    let _: Box<dyn _0>;
+    let _: Box<dyn _1>;
+    let _: Box<dyn Unpin + _1 + Send + Sync>;
+}
+
+// Include object safe traits:
+
+fn _f1() {
+    let _: Box<dyn Obj + _0>;
+    let _: Box<dyn Obj + _1>;
+    let _: Box<dyn Obj + _1 + _0>;
+}
+
+// And when the object safe trait is in a trait alias:
+
+trait _2 = Obj;
+
+fn _f2() {
+    let _: Box<dyn _2 + _0>;
+    let _: Box<dyn _2 + _1>;
+    let _: Box<dyn _2 + _1 + _0>;
+}
+
+// And it should also work when that trait is has auto traits to the right of it.
+
+trait _3 = Obj + Unpin;
+
+fn _f3() {
+    let _: Box<dyn _3 + _0>;
+    let _: Box<dyn _3 + _1>;
+    let _: Box<dyn _3 + _1 + _0>;
+}
+
+// Nest the trait deeply:
+
+trait _4 = _3;
+trait _5 = _4 + Sync + _0 + Send;
+trait _6 = _5 + Send + _1 + Sync;
+
+fn _f4() {
+    let _: Box<dyn _6 + _0>;
+    let _: Box<dyn _6 + _1>;
+    let _: Box<dyn _6 + _1 + _0>;
+}
+
+// Just nest the trait alone:
+
+trait _7 = _2;
+trait _8 = _7;
+trait _9 = _8;
+
+fn _f5() {
+    let _: Box<dyn _9>;
+}
+
+// First bound is auto trait:
+
+trait _10 = Send + Obj;
+trait _11 = Obj + Send;
+trait _12 = Sync + _11;
+trait _13 = Send + _12;
+
+fn f6() {
+    let _: Box<dyn _10>;
+    let _: Box<dyn _13>;
+}
+
+fn main() {}
diff --git a/src/test/run-pass/traits/trait-alias-object.rs b/src/test/ui/traits/trait-alias/trait-alias-object.rs
index 1cf9e34edf3..12177cd827f 100644
--- a/src/test/run-pass/traits/trait-alias-object.rs
+++ b/src/test/ui/traits/trait-alias/trait-alias-object.rs
@@ -1,3 +1,5 @@
+// run-pass
+
 #![feature(trait_alias)]
 
 trait Foo = PartialEq<i32> + Send;
diff --git a/src/test/ui/traits/trait-alias/trait-alias-only-maybe-bound.rs b/src/test/ui/traits/trait-alias/trait-alias-only-maybe-bound.rs
new file mode 100644
index 00000000000..d6c611d2a4d
--- /dev/null
+++ b/src/test/ui/traits/trait-alias/trait-alias-only-maybe-bound.rs
@@ -0,0 +1,22 @@
+// Test that `dyn ?Sized` (i.e., a trait object with only a maybe buond) is not allowed, when just
+// `?Sized` results from trait alias expansion.
+
+#![feature(trait_alias)]
+
+trait S = ?Sized;
+
+// Nest a couple of levels deep:
+trait _0 = S;
+trait _1 = _0;
+
+// Straight list expansion:
+type _T0 = dyn _1;
+//~^ ERROR at least one non-builtin trait is required for an object type [E0224]
+
+// Twice:
+trait _2 = _1 + _1;
+
+type _T1 = dyn _2;
+//~^ ERROR at least one non-builtin trait is required for an object type [E0224]
+
+fn main() {}
diff --git a/src/test/ui/traits/trait-alias/trait-alias-only-maybe-bound.stderr b/src/test/ui/traits/trait-alias/trait-alias-only-maybe-bound.stderr
new file mode 100644
index 00000000000..d4f77200fd5
--- /dev/null
+++ b/src/test/ui/traits/trait-alias/trait-alias-only-maybe-bound.stderr
@@ -0,0 +1,14 @@
+error[E0224]: at least one non-builtin trait is required for an object type
+  --> $DIR/trait-alias-only-maybe-bound.rs:13:12
+   |
+LL | type _T0 = dyn _1;
+   |            ^^^^^^
+
+error[E0224]: at least one non-builtin trait is required for an object type
+  --> $DIR/trait-alias-only-maybe-bound.rs:19:12
+   |
+LL | type _T1 = dyn _2;
+   |            ^^^^^^
+
+error: aborting due to 2 previous errors
+
diff --git a/src/test/ui/traits/trait-alias-syntax.rs b/src/test/ui/traits/trait-alias/trait-alias-syntax-fail.rs
index 5948d45b698..5948d45b698 100644
--- a/src/test/ui/traits/trait-alias-syntax.rs
+++ b/src/test/ui/traits/trait-alias/trait-alias-syntax-fail.rs
diff --git a/src/test/ui/traits/trait-alias-syntax.stderr b/src/test/ui/traits/trait-alias/trait-alias-syntax-fail.stderr
index f99cc45d8ae..f456a2d778c 100644
--- a/src/test/ui/traits/trait-alias-syntax.stderr
+++ b/src/test/ui/traits/trait-alias/trait-alias-syntax-fail.stderr
@@ -1,11 +1,11 @@
 error: trait aliases cannot be `auto`
-  --> $DIR/trait-alias-syntax.rs:4:19
+  --> $DIR/trait-alias-syntax-fail.rs:4:19
    |
 LL | auto trait A = Foo;
    |                   ^ trait aliases cannot be `auto`
 
 error: trait aliases cannot be `unsafe`
-  --> $DIR/trait-alias-syntax.rs:5:21
+  --> $DIR/trait-alias-syntax-fail.rs:5:21
    |
 LL | unsafe trait B = Foo;
    |                     ^ trait aliases cannot be `unsafe`
diff --git a/src/test/run-pass/traits/trait-alias-syntax.rs b/src/test/ui/traits/trait-alias/trait-alias-syntax.rs
index 7cdd9184d3f..17557a51aa7 100644
--- a/src/test/run-pass/traits/trait-alias-syntax.rs
+++ b/src/test/ui/traits/trait-alias/trait-alias-syntax.rs
@@ -1,3 +1,5 @@
+// run-pass
+
 #![feature(trait_alias)]
 
 trait SimpleAlias = Default;
diff --git a/src/test/ui/traits/trait-alias-wf.rs b/src/test/ui/traits/trait-alias/trait-alias-wf.rs
index d10e2abb0e1..d10e2abb0e1 100644
--- a/src/test/ui/traits/trait-alias-wf.rs
+++ b/src/test/ui/traits/trait-alias/trait-alias-wf.rs
diff --git a/src/test/ui/traits/trait-alias-wf.stderr b/src/test/ui/traits/trait-alias/trait-alias-wf.stderr
index ee2dd5b24af..ee2dd5b24af 100644
--- a/src/test/ui/traits/trait-alias-wf.stderr
+++ b/src/test/ui/traits/trait-alias/trait-alias-wf.stderr
diff --git a/src/test/ui/run-pass/traits/trait-alias.rs b/src/test/ui/traits/trait-alias/trait-alias.rs
index 9be5664869e..d8168f2990c 100644
--- a/src/test/ui/run-pass/traits/trait-alias.rs
+++ b/src/test/ui/traits/trait-alias/trait-alias.rs
@@ -1,4 +1,5 @@
 // run-pass
+
 #![feature(trait_alias)]
 
 pub trait Foo {}
diff --git a/src/test/ui/run-pass/traits/traits-static-outlives-a-where-clause.rs b/src/test/ui/traits/traits-static-outlives-a-where-clause.rs
index f0c2c1082b0..f0c2c1082b0 100644
--- a/src/test/ui/run-pass/traits/traits-static-outlives-a-where-clause.rs
+++ b/src/test/ui/traits/traits-static-outlives-a-where-clause.rs
diff --git a/src/test/ui/traits/wf-trait-object-maybe-bound.rs b/src/test/ui/traits/wf-trait-object-maybe-bound.rs
new file mode 100644
index 00000000000..f24c1301c53
--- /dev/null
+++ b/src/test/ui/traits/wf-trait-object-maybe-bound.rs
@@ -0,0 +1,20 @@
+// compile-fail
+
+// Test that `dyn ... + ?Sized + ...` is okay (though `?Sized` has no effect in trait objects).
+
+trait Foo {}
+
+type _0 = dyn ?Sized + Foo;
+//~^ ERROR `?Trait` is not permitted in trait object types
+
+type _1 = dyn Foo + ?Sized;
+//~^ ERROR `?Trait` is not permitted in trait object types
+
+type _2 = dyn Foo + ?Sized + ?Sized;
+//~^ ERROR `?Trait` is not permitted in trait object types
+//~| ERROR `?Trait` is not permitted in trait object types
+
+type _3 = dyn ?Sized + Foo;
+//~^ ERROR `?Trait` is not permitted in trait object types
+
+fn main() {}
diff --git a/src/test/ui/traits/wf-trait-object-maybe-bound.stderr b/src/test/ui/traits/wf-trait-object-maybe-bound.stderr
new file mode 100644
index 00000000000..11187342d59
--- /dev/null
+++ b/src/test/ui/traits/wf-trait-object-maybe-bound.stderr
@@ -0,0 +1,32 @@
+error: `?Trait` is not permitted in trait object types
+  --> $DIR/wf-trait-object-maybe-bound.rs:7:15
+   |
+LL | type _0 = dyn ?Sized + Foo;
+   |               ^^^^^^
+
+error: `?Trait` is not permitted in trait object types
+  --> $DIR/wf-trait-object-maybe-bound.rs:10:21
+   |
+LL | type _1 = dyn Foo + ?Sized;
+   |                     ^^^^^^
+
+error: `?Trait` is not permitted in trait object types
+  --> $DIR/wf-trait-object-maybe-bound.rs:13:21
+   |
+LL | type _2 = dyn Foo + ?Sized + ?Sized;
+   |                     ^^^^^^
+
+error: `?Trait` is not permitted in trait object types
+  --> $DIR/wf-trait-object-maybe-bound.rs:13:30
+   |
+LL | type _2 = dyn Foo + ?Sized + ?Sized;
+   |                              ^^^^^^
+
+error: `?Trait` is not permitted in trait object types
+  --> $DIR/wf-trait-object-maybe-bound.rs:17:15
+   |
+LL | type _3 = dyn ?Sized + Foo;
+   |               ^^^^^^
+
+error: aborting due to 5 previous errors
+
diff --git a/src/test/ui/traits/wf-trait-object-no-duplicates.rs b/src/test/ui/traits/wf-trait-object-no-duplicates.rs
new file mode 100644
index 00000000000..678ede58296
--- /dev/null
+++ b/src/test/ui/traits/wf-trait-object-no-duplicates.rs
@@ -0,0 +1,33 @@
+// The purpose of this test is to demonstrate that duplicating object safe traits
+// that are not auto-traits is rejected even though one could reasonably accept this.
+
+// Some arbitrary object-safe trait:
+trait Obj {}
+
+// Demonstrate that recursive expansion of trait aliases doesn't affect stable behavior:
+type _0 = dyn Obj + Obj;
+//~^ ERROR only auto traits can be used as additional traits in a trait object [E0225]
+
+// Some variations:
+
+type _1 = dyn Send + Obj + Obj;
+//~^ ERROR only auto traits can be used as additional traits in a trait object [E0225]
+
+type _2 = dyn Obj + Send + Obj;
+//~^ ERROR only auto traits can be used as additional traits in a trait object [E0225]
+
+type _3 = dyn Obj + Send + Send; // But it is OK to duplicate auto traits.
+
+// Take higher ranked types into account.
+
+// Note that `'a` and `'b` are intentionally different to make sure we consider
+// them semantically the same.
+trait ObjL<'l> {}
+type _4 = dyn for<'a> ObjL<'a> + for<'b> ObjL<'b>;
+//~^ ERROR only auto traits can be used as additional traits in a trait object [E0225]
+
+trait ObjT<T> {}
+type _5 = dyn ObjT<for<'a> fn(&'a u8)> + ObjT<for<'b> fn(&'b u8)>;
+//~^ ERROR only auto traits can be used as additional traits in a trait object [E0225]
+
+fn main() {}
diff --git a/src/test/ui/traits/wf-trait-object-no-duplicates.stderr b/src/test/ui/traits/wf-trait-object-no-duplicates.stderr
new file mode 100644
index 00000000000..269d92fe43d
--- /dev/null
+++ b/src/test/ui/traits/wf-trait-object-no-duplicates.stderr
@@ -0,0 +1,58 @@
+error[E0225]: only auto traits can be used as additional traits in a trait object
+  --> $DIR/wf-trait-object-no-duplicates.rs:8:21
+   |
+LL | type _0 = dyn Obj + Obj;
+   |               ---   ^^^
+   |               |     |
+   |               |     additional non-auto trait
+   |               |     trait alias used in trait object type (additional use)
+   |               first non-auto trait
+   |               trait alias used in trait object type (first use)
+
+error[E0225]: only auto traits can be used as additional traits in a trait object
+  --> $DIR/wf-trait-object-no-duplicates.rs:13:28
+   |
+LL | type _1 = dyn Send + Obj + Obj;
+   |                      ---   ^^^
+   |                      |     |
+   |                      |     additional non-auto trait
+   |                      |     trait alias used in trait object type (additional use)
+   |                      first non-auto trait
+   |                      trait alias used in trait object type (first use)
+
+error[E0225]: only auto traits can be used as additional traits in a trait object
+  --> $DIR/wf-trait-object-no-duplicates.rs:16:28
+   |
+LL | type _2 = dyn Obj + Send + Obj;
+   |               ---          ^^^
+   |               |            |
+   |               |            additional non-auto trait
+   |               |            trait alias used in trait object type (additional use)
+   |               first non-auto trait
+   |               trait alias used in trait object type (first use)
+
+error[E0225]: only auto traits can be used as additional traits in a trait object
+  --> $DIR/wf-trait-object-no-duplicates.rs:26:34
+   |
+LL | type _4 = dyn for<'a> ObjL<'a> + for<'b> ObjL<'b>;
+   |               ----------------   ^^^^^^^^^^^^^^^^
+   |               |                  |
+   |               |                  additional non-auto trait
+   |               |                  trait alias used in trait object type (additional use)
+   |               first non-auto trait
+   |               trait alias used in trait object type (first use)
+
+error[E0225]: only auto traits can be used as additional traits in a trait object
+  --> $DIR/wf-trait-object-no-duplicates.rs:30:42
+   |
+LL | type _5 = dyn ObjT<for<'a> fn(&'a u8)> + ObjT<for<'b> fn(&'b u8)>;
+   |               ------------------------   ^^^^^^^^^^^^^^^^^^^^^^^^
+   |               |                          |
+   |               |                          additional non-auto trait
+   |               |                          trait alias used in trait object type (additional use)
+   |               first non-auto trait
+   |               trait alias used in trait object type (first use)
+
+error: aborting due to 5 previous errors
+
+For more information about this error, try `rustc --explain E0225`.
diff --git a/src/test/ui/traits/wf-trait-object-only-maybe-bound.rs b/src/test/ui/traits/wf-trait-object-only-maybe-bound.rs
new file mode 100644
index 00000000000..1b83d2487f4
--- /dev/null
+++ b/src/test/ui/traits/wf-trait-object-only-maybe-bound.rs
@@ -0,0 +1,7 @@
+// Test that `dyn ?Sized` (i.e., a trait object with only a maybe buond) is not allowed.
+
+type _0 = dyn ?Sized;
+//~^ ERROR at least one non-builtin trait is required for an object type [E0224]
+//~| ERROR ?Trait` is not permitted in trait object types
+
+fn main() {}
diff --git a/src/test/ui/traits/wf-trait-object-only-maybe-bound.stderr b/src/test/ui/traits/wf-trait-object-only-maybe-bound.stderr
new file mode 100644
index 00000000000..0cfb389fd89
--- /dev/null
+++ b/src/test/ui/traits/wf-trait-object-only-maybe-bound.stderr
@@ -0,0 +1,14 @@
+error: `?Trait` is not permitted in trait object types
+  --> $DIR/wf-trait-object-only-maybe-bound.rs:3:15
+   |
+LL | type _0 = dyn ?Sized;
+   |               ^^^^^^
+
+error[E0224]: at least one non-builtin trait is required for an object type
+  --> $DIR/wf-trait-object-only-maybe-bound.rs:3:11
+   |
+LL | type _0 = dyn ?Sized;
+   |           ^^^^^^^^^^
+
+error: aborting due to 2 previous errors
+
diff --git a/src/test/ui/traits/wf-trait-object-reverse-order.rs b/src/test/ui/traits/wf-trait-object-reverse-order.rs
new file mode 100644
index 00000000000..4f676cbe338
--- /dev/null
+++ b/src/test/ui/traits/wf-trait-object-reverse-order.rs
@@ -0,0 +1,15 @@
+// run-pass
+
+// Ensure that `dyn $($AutoTrait)+ ObjSafe` is well-formed.
+
+use std::marker::Unpin;
+
+// Some arbitrary object-safe trait:
+trait Obj {}
+
+type _0 = dyn Unpin;
+type _1 = dyn Send + Obj;
+type _2 = dyn Send + Unpin + Obj;
+type _3 = dyn Send + Unpin + Sync + Obj;
+
+fn main() {}