diff --git a/src/librustc/hir/def.rs b/src/librustc/hir/def.rs
index 3ef0633e7f400..19a37b693db6f 100644
--- a/src/librustc/hir/def.rs
+++ b/src/librustc/hir/def.rs
@@ -37,6 +37,7 @@ pub enum Def {
     Trait(DefId),
     TyAlias(DefId),
     TyForeign(DefId),
+    TraitAlias(DefId),
     AssociatedTy(DefId),
     PrimTy(hir::PrimTy),
     TyParam(DefId),
@@ -155,7 +156,8 @@ impl Def {
     pub fn def_id(&self) -> DefId {
         match *self {
             Def::Fn(id) | Def::Mod(id) | Def::Static(id, _) |
-            Def::Variant(id) | Def::VariantCtor(id, ..) | Def::Enum(id) | Def::TyAlias(id) |
+            Def::Variant(id) | Def::VariantCtor(id, ..) | Def::Enum(id) |
+            Def::TyAlias(id) | Def::TraitAlias(id) |
             Def::AssociatedTy(id) | Def::TyParam(id) | Def::Struct(id) | Def::StructCtor(id, ..) |
             Def::Union(id) | Def::Trait(id) | Def::Method(id) | Def::Const(id) |
             Def::AssociatedConst(id) | Def::Macro(id, ..) |
@@ -186,6 +188,7 @@ impl Def {
             Def::VariantCtor(.., CtorKind::Fictive) => "struct variant",
             Def::Enum(..) => "enum",
             Def::TyAlias(..) => "type alias",
+            Def::TraitAlias(..) => "trait alias",
             Def::AssociatedTy(..) => "associated type",
             Def::Struct(..) => "struct",
             Def::StructCtor(.., CtorKind::Fn) => "tuple struct",
diff --git a/src/librustc/hir/intravisit.rs b/src/librustc/hir/intravisit.rs
index c9d35158ed002..eacad100f10be 100644
--- a/src/librustc/hir/intravisit.rs
+++ b/src/librustc/hir/intravisit.rs
@@ -526,6 +526,11 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item) {
             walk_list!(visitor, visit_ty_param_bound, bounds);
             walk_list!(visitor, visit_trait_item_ref, trait_item_refs);
         }
+        ItemTraitAlias(ref generics, ref bounds) => {
+            visitor.visit_id(item.id);
+            visitor.visit_generics(generics);
+            walk_list!(visitor, visit_ty_param_bound, bounds);
+        }
     }
     walk_list!(visitor, visit_attribute, &item.attrs);
 }
diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs
index e3a5e835bb9f6..b544ea820c0f7 100644
--- a/src/librustc/hir/lowering.rs
+++ b/src/librustc/hir/lowering.rs
@@ -1924,9 +1924,11 @@ impl<'a> LoweringContext<'a> {
                                bounds,
                                items)
             }
-            ItemKind::MacroDef(..) | ItemKind::Mac(..) => {
-                panic!("Shouldn't still be around")
+            ItemKind::TraitAlias(ref generics, ref bounds) => {
+                hir::ItemTraitAlias(self.lower_generics(generics),
+                                    self.lower_bounds(bounds, ImplTraitContext::Disallowed))
             }
+            ItemKind::MacroDef(..) | ItemKind::Mac(..) => panic!("Shouldn't still be around"),
         }
 
         // [1] `defaultness.has_value()` is never called for an `impl`, always `true` in order to
diff --git a/src/librustc/hir/map/def_collector.rs b/src/librustc/hir/map/def_collector.rs
index 17a4c66edb9c9..2978f1eb409d8 100644
--- a/src/librustc/hir/map/def_collector.rs
+++ b/src/librustc/hir/map/def_collector.rs
@@ -106,7 +106,8 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> {
         let def_data = match i.node {
             ItemKind::AutoImpl(..) | ItemKind::Impl(..) =>
                 DefPathData::Impl,
-            ItemKind::Enum(..) | ItemKind::Struct(..) | ItemKind::Union(..) | ItemKind::Trait(..) |
+            ItemKind::Enum(..) | ItemKind::Struct(..) | ItemKind::Union(..) |
+            ItemKind::Trait(..) | ItemKind::TraitAlias(..) |
             ItemKind::ExternCrate(..) | ItemKind::ForeignMod(..) | ItemKind::Ty(..) =>
                 DefPathData::TypeNs(i.ident.name.as_str()),
             ItemKind::Mod(..) if i.ident == keywords::Invalid.ident() => {
diff --git a/src/librustc/hir/map/mod.rs b/src/librustc/hir/map/mod.rs
index 8969528dd1949..014e57716562c 100644
--- a/src/librustc/hir/map/mod.rs
+++ b/src/librustc/hir/map/mod.rs
@@ -1185,6 +1185,7 @@ fn node_id_to_string(map: &Map, id: NodeId, include_id: bool) -> String {
                 ItemStruct(..) => "struct",
                 ItemUnion(..) => "union",
                 ItemTrait(..) => "trait",
+                ItemTraitAlias(..) => "trait alias",
                 ItemImpl(..) => "impl",
                 ItemAutoImpl(..) => "default impl",
             };
diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs
index d6107a8f55197..dc44a943e4cf8 100644
--- a/src/librustc/hir/mod.rs
+++ b/src/librustc/hir/mod.rs
@@ -1888,6 +1888,8 @@ pub enum Item_ {
     ItemUnion(VariantData, Generics),
     /// Represents a Trait Declaration
     ItemTrait(IsAuto, Unsafety, Generics, TyParamBounds, HirVec<TraitItemRef>),
+    /// Represents a Trait Alias Declaration
+    ItemTraitAlias(Generics, TyParamBounds),
 
     /// Auto trait implementations
     ///
@@ -1919,6 +1921,7 @@ impl Item_ {
             ItemStruct(..) => "struct",
             ItemUnion(..) => "union",
             ItemTrait(..) => "trait",
+            ItemTraitAlias(..) => "trait alias",
             ItemImpl(..) |
             ItemAutoImpl(..) => "item",
         }
diff --git a/src/librustc/hir/print.rs b/src/librustc/hir/print.rs
index fb502ecb996ae..c7bb121e90105 100644
--- a/src/librustc/hir/print.rs
+++ b/src/librustc/hir/print.rs
@@ -747,6 +747,27 @@ impl<'a> State<'a> {
                 }
                 self.bclose(item.span)?;
             }
+            hir::ItemTraitAlias(ref generics, ref bounds) => {
+                self.head("")?;
+                self.print_visibility(&item.vis)?;
+                self.word_nbsp("trait")?;
+                self.print_name(item.name)?;
+                self.print_generics(generics)?;
+                let mut real_bounds = Vec::with_capacity(bounds.len());
+                // FIXME(durka) this seems to be some quite outdated syntax
+                for b in bounds.iter() {
+                    if let TraitTyParamBound(ref ptr, hir::TraitBoundModifier::Maybe) = *b {
+                        self.s.space()?;
+                        self.word_space("for ?")?;
+                        self.print_trait_ref(&ptr.trait_ref)?;
+                    } else {
+                        real_bounds.push(b.clone());
+                    }
+                }
+                self.print_bounds(" = ", &real_bounds[..])?;
+                self.print_where_clause(&generics.where_clause)?;
+                self.s.word(";")?;
+            }
         }
         self.ann.post(self, NodeItem(item))
     }
diff --git a/src/librustc/ich/impls_hir.rs b/src/librustc/ich/impls_hir.rs
index 6fc49e5189d55..ff5327ced8b79 100644
--- a/src/librustc/ich/impls_hir.rs
+++ b/src/librustc/ich/impls_hir.rs
@@ -848,6 +848,7 @@ impl_stable_hash_for!(enum hir::Item_ {
     ItemStruct(variant_data, generics),
     ItemUnion(variant_data, generics),
     ItemTrait(is_auto, unsafety, generics, bounds, item_refs),
+    ItemTraitAlias(generics, bounds),
     ItemAutoImpl(unsafety, trait_ref),
     ItemImpl(unsafety, impl_polarity, impl_defaultness, generics, trait_ref, ty, impl_item_refs)
 });
@@ -1004,6 +1005,7 @@ impl_stable_hash_for!(enum hir::def::Def {
     Variant(def_id),
     Trait(def_id),
     TyAlias(def_id),
+    TraitAlias(def_id),
     AssociatedTy(def_id),
     PrimTy(prim_ty),
     TyParam(def_id),
diff --git a/src/librustc/middle/reachable.rs b/src/librustc/middle/reachable.rs
index d5f26d1117c5b..27f12c2c1587e 100644
--- a/src/librustc/middle/reachable.rs
+++ b/src/librustc/middle/reachable.rs
@@ -268,7 +268,7 @@ impl<'a, 'tcx> ReachableContext<'a, 'tcx> {
                     hir::ItemExternCrate(_) | hir::ItemUse(..) |
                     hir::ItemTy(..) | hir::ItemStatic(..) |
                     hir::ItemMod(..) | hir::ItemForeignMod(..) |
-                    hir::ItemImpl(..) | hir::ItemTrait(..) |
+                    hir::ItemImpl(..) | hir::ItemTrait(..) | hir::ItemTraitAlias(..) |
                     hir::ItemStruct(..) | hir::ItemEnum(..) |
                     hir::ItemUnion(..) | hir::ItemAutoImpl(..) |
                     hir::ItemGlobalAsm(..) => {}
diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs
index d9b2bf62841f1..e75762cbacb42 100644
--- a/src/librustc/middle/resolve_lifetime.rs
+++ b/src/librustc/middle/resolve_lifetime.rs
@@ -469,6 +469,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
             | hir::ItemStruct(_, ref generics)
             | hir::ItemUnion(_, ref generics)
             | hir::ItemTrait(_, _, ref generics, ..)
+            | hir::ItemTraitAlias(ref generics, ..)
             | hir::ItemImpl(_, _, _, ref generics, ..) => {
                 // These kinds of items have only early bound lifetime parameters.
                 let mut index = if let hir::ItemTrait(..) = item.node {
diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs
index 93ef29855ce1d..4e1a79d4613e7 100644
--- a/src/librustc/ty/mod.rs
+++ b/src/librustc/ty/mod.rs
@@ -2577,6 +2577,7 @@ fn associated_item_def_ids<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                           .map(|id| tcx.hir.local_def_id(id.node_id))
                           .collect()
         }
+        hir::ItemTraitAlias(..) => vec![],
         _ => span_bug!(item.span, "associated_item_def_ids: not impl or trait")
     };
     Rc::new(vec)
diff --git a/src/librustc_driver/test.rs b/src/librustc_driver/test.rs
index f04e01f3f961d..ded2fa01e5977 100644
--- a/src/librustc_driver/test.rs
+++ b/src/librustc_driver/test.rs
@@ -248,6 +248,7 @@ impl<'a, 'gcx, 'tcx> Env<'a, 'gcx, 'tcx> {
                 hir::ItemStruct(..) |
                 hir::ItemUnion(..) |
                 hir::ItemTrait(..) |
+                hir::ItemTraitAlias(..) |
                 hir::ItemImpl(..) |
                 hir::ItemAutoImpl(..) => None,
 
diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs
index caeee989283fc..5e8bbabee4a9a 100644
--- a/src/librustc_metadata/encoder.rs
+++ b/src/librustc_metadata/encoder.rs
@@ -979,6 +979,7 @@ impl<'a, 'b: 'a, 'tcx: 'b> IsolatedEncoder<'a, 'b, 'tcx> {
                 EntryKind::Trait(self.lazy(&data))
             }
             hir::ItemExternCrate(_) |
+            hir::ItemTraitAlias(..) |
             hir::ItemUse(..) => bug!("cannot encode info for item {:?}", item),
         };
 
@@ -1526,7 +1527,8 @@ impl<'a, 'b, 'tcx> IndexBuilder<'a, 'b, 'tcx> {
             hir::ItemExternCrate(..) |
             hir::ItemUse(..) |
             hir::ItemAutoImpl(..) |
-            hir::ItemTy(..) => {
+            hir::ItemTy(..) |
+            hir::ItemTraitAlias(..) => {
                 // no sub-item recording needed in these cases
             }
             hir::ItemEnum(..) => {
diff --git a/src/librustc_passes/ast_validation.rs b/src/librustc_passes/ast_validation.rs
index 05ad164361905..96c9323e7dc73 100644
--- a/src/librustc_passes/ast_validation.rs
+++ b/src/librustc_passes/ast_validation.rs
@@ -283,6 +283,20 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
                     }
                 }
             }
+            ItemKind::TraitAlias(Generics { ref ty_params, .. }, ..) => {
+                for &TyParam { ref bounds, ref default, span, .. } in ty_params {
+                    if !bounds.is_empty() {
+                        self.err_handler().span_err(span,
+                                                    "type parameters on the left side of a \
+                                                     trait alias cannot be bounded");
+                    }
+                    if !default.is_none() {
+                        self.err_handler().span_err(span,
+                                                    "type parameters on the left side of a \
+                                                     trait alias cannot have defaults");
+                    }
+                }
+            }
             ItemKind::Mod(_) => {
                 // Ensure that `path` attributes on modules are recorded as used (c.f. #35584).
                 attr::first_attr_value_str_by_name(&item.attrs, "path");
diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs
index 27898b5dd64bc..d41881218129f 100644
--- a/src/librustc_privacy/lib.rs
+++ b/src/librustc_privacy/lib.rs
@@ -158,7 +158,8 @@ impl<'a, 'tcx> Visitor<'tcx> for EmbargoVisitor<'a, 'tcx> {
             // Other `pub` items inherit levels from parents
             hir::ItemConst(..) | hir::ItemEnum(..) | hir::ItemExternCrate(..) |
             hir::ItemGlobalAsm(..) | hir::ItemFn(..) | hir::ItemMod(..) |
-            hir::ItemStatic(..) | hir::ItemStruct(..) | hir::ItemTrait(..) |
+            hir::ItemStatic(..) | hir::ItemStruct(..) |
+            hir::ItemTrait(..) | hir::ItemTraitAlias(..) |
             hir::ItemTy(..) | hir::ItemUnion(..) | hir::ItemUse(..) => {
                 if item.vis == hir::Public { self.prev_level } else { None }
             }
@@ -212,7 +213,7 @@ impl<'a, 'tcx> Visitor<'tcx> for EmbargoVisitor<'a, 'tcx> {
                 }
             }
             hir::ItemUse(..) | hir::ItemStatic(..) | hir::ItemConst(..) |
-            hir::ItemGlobalAsm(..) | hir::ItemTy(..) | hir::ItemMod(..) |
+            hir::ItemGlobalAsm(..) | hir::ItemTy(..) | hir::ItemMod(..) | hir::ItemTraitAlias(..) |
             hir::ItemFn(..) | hir::ItemExternCrate(..) | hir::ItemAutoImpl(..) => {}
         }
 
@@ -252,6 +253,11 @@ impl<'a, 'tcx> Visitor<'tcx> for EmbargoVisitor<'a, 'tcx> {
                     }
                 }
             }
+            hir::ItemTraitAlias(..) => {
+                if item_level.is_some() {
+                    self.reach(item.id).generics().predicates();
+                }
+            }
             // Visit everything except for private impl items
             hir::ItemImpl(.., ref trait_ref, _, ref impl_item_refs) => {
                 if item_level.is_some() {
@@ -1498,6 +1504,9 @@ impl<'a, 'tcx> Visitor<'tcx> for PrivateItemsInPublicInterfacesVisitor<'a, 'tcx>
                     }
                 }
             }
+            hir::ItemTraitAlias(..) => {
+                self.check(item.id, item_visibility).generics().predicates();
+            }
             hir::ItemEnum(ref def, _) => {
                 self.check(item.id, item_visibility).generics().predicates();
 
diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs
index 8df6458b72e18..3b20c1e74cd39 100644
--- a/src/librustc_resolve/build_reduced_graph.rs
+++ b/src/librustc_resolve/build_reduced_graph.rs
@@ -344,6 +344,11 @@ impl<'a> Resolver<'a> {
                 }
             }
 
+            ItemKind::TraitAlias(..) => {
+                let def = Def::TraitAlias(self.definitions.local_def_id(item.id));
+                self.define(parent, ident, TypeNS, (def, vis, sp, expansion));
+            }
+
             // These items live in both the type and value namespaces.
             ItemKind::Struct(ref struct_def, _) => {
                 // Define a name in the type namespace.
@@ -411,6 +416,7 @@ impl<'a> Resolver<'a> {
                 self.define(parent, ident, TypeNS, (module, vis, sp, expansion));
                 self.current_module = module;
             }
+
             ItemKind::MacroDef(..) | ItemKind::Mac(_) => unreachable!(),
         }
     }
diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs
index 33e57b2d180d6..c42ac7aaa937c 100644
--- a/src/librustc_resolve/lib.rs
+++ b/src/librustc_resolve/lib.rs
@@ -390,12 +390,18 @@ impl PatternSource {
     }
 }
 
+#[derive(Copy, Clone, PartialEq, Eq, Debug)]
+enum AliasPossibility {
+    No,
+    Maybe,
+}
+
 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
 enum PathSource<'a> {
     // Type paths `Path`.
     Type,
     // Trait paths in bounds or impls.
-    Trait,
+    Trait(AliasPossibility),
     // Expression paths `path`, with optional parent context.
     Expr(Option<&'a Expr>),
     // Paths in path patterns `Path`.
@@ -415,7 +421,7 @@ enum PathSource<'a> {
 impl<'a> PathSource<'a> {
     fn namespace(self) -> Namespace {
         match self {
-            PathSource::Type | PathSource::Trait | PathSource::Struct |
+            PathSource::Type | PathSource::Trait(_) | PathSource::Struct |
             PathSource::Visibility | PathSource::ImportPrefix => TypeNS,
             PathSource::Expr(..) | PathSource::Pat | PathSource::TupleStruct => ValueNS,
             PathSource::TraitItem(ns) => ns,
@@ -427,7 +433,7 @@ impl<'a> PathSource<'a> {
             PathSource::Visibility | PathSource::ImportPrefix => true,
             PathSource::Type | PathSource::Expr(..) | PathSource::Pat |
             PathSource::Struct | PathSource::TupleStruct |
-            PathSource::Trait | PathSource::TraitItem(..) => false,
+            PathSource::Trait(_) | PathSource::TraitItem(..) => false,
         }
     }
 
@@ -435,7 +441,7 @@ impl<'a> PathSource<'a> {
         match self {
             PathSource::Type | PathSource::Expr(..) | PathSource::Pat |
             PathSource::Struct | PathSource::TupleStruct => true,
-            PathSource::Trait | PathSource::TraitItem(..) |
+            PathSource::Trait(_) | PathSource::TraitItem(..) |
             PathSource::Visibility | PathSource::ImportPrefix => false,
         }
     }
@@ -443,7 +449,7 @@ impl<'a> PathSource<'a> {
     fn descr_expected(self) -> &'static str {
         match self {
             PathSource::Type => "type",
-            PathSource::Trait => "trait",
+            PathSource::Trait(_) => "trait",
             PathSource::Pat => "unit struct/variant or constant",
             PathSource::Struct => "struct, variant or union type",
             PathSource::TupleStruct => "tuple struct/variant",
@@ -472,10 +478,15 @@ impl<'a> PathSource<'a> {
                 Def::TyForeign(..) => true,
                 _ => false,
             },
-            PathSource::Trait => match def {
+            PathSource::Trait(AliasPossibility::No) => match def {
                 Def::Trait(..) => true,
                 _ => false,
             },
+            PathSource::Trait(AliasPossibility::Maybe) => match def {
+                Def::Trait(..) => true,
+                Def::TraitAlias(..) => true,
+                _ => false,
+            },
             PathSource::Expr(..) => match def {
                 Def::StructCtor(_, CtorKind::Const) | Def::StructCtor(_, CtorKind::Fn) |
                 Def::VariantCtor(_, CtorKind::Const) | Def::VariantCtor(_, CtorKind::Fn) |
@@ -530,8 +541,8 @@ impl<'a> PathSource<'a> {
         __diagnostic_used!(E0577);
         __diagnostic_used!(E0578);
         match (self, has_unexpected_resolution) {
-            (PathSource::Trait, true) => "E0404",
-            (PathSource::Trait, false) => "E0405",
+            (PathSource::Trait(_), true) => "E0404",
+            (PathSource::Trait(_), false) => "E0405",
             (PathSource::Type, true) => "E0573",
             (PathSource::Type, false) => "E0412",
             (PathSource::Struct, true) => "E0574",
@@ -693,7 +704,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Resolver<'a> {
                             tref: &'tcx ast::PolyTraitRef,
                             m: &'tcx ast::TraitBoundModifier) {
         self.smart_resolve_path(tref.trait_ref.ref_id, None,
-                                &tref.trait_ref.path, PathSource::Trait);
+                                &tref.trait_ref.path, PathSource::Trait(AliasPossibility::Maybe));
         visit::walk_poly_trait_ref(self, tref, m);
     }
     fn visit_variant(&mut self,
@@ -1935,6 +1946,17 @@ impl<'a> Resolver<'a> {
                 });
             }
 
+            ItemKind::TraitAlias(ref generics, ref bounds) => {
+                // Create a new rib for the trait-wide type parameters.
+                self.with_type_parameter_rib(HasTypeParameters(generics, ItemRibKind), |this| {
+                    let local_def_id = this.definitions.local_def_id(item.id);
+                    this.with_self_rib(Def::SelfTy(Some(local_def_id), None), |this| {
+                        this.visit_generics(generics);
+                        walk_list!(this, visit_ty_param_bound, bounds);
+                    });
+                });
+            }
+
             ItemKind::Mod(_) | ItemKind::ForeignMod(_) => {
                 self.with_scope(item.id, |this| {
                     visit::walk_item(this, item);
@@ -2083,7 +2105,7 @@ impl<'a> Resolver<'a> {
                                                        &path,
                                                        trait_ref.path.span,
                                                        trait_ref.path.segments.last().unwrap().span,
-                                                       PathSource::Trait)
+                                                       PathSource::Trait(AliasPossibility::No))
                 .base_def();
             if def != Def::Err {
                 new_id = Some(def.def_id());
@@ -2635,7 +2657,7 @@ impl<'a> Resolver<'a> {
                         err.span_label(span, format!("did you mean `{}!(...)`?", path_str));
                         return (err, candidates);
                     }
-                    (Def::TyAlias(..), PathSource::Trait) => {
+                    (Def::TyAlias(..), PathSource::Trait(_)) => {
                         err.span_label(span, "type aliases cannot be used for traits");
                         return (err, candidates);
                     }
diff --git a/src/librustc_save_analysis/dump_visitor.rs b/src/librustc_save_analysis/dump_visitor.rs
index 7989dba11f7b8..fe6ad92ad00b2 100644
--- a/src/librustc_save_analysis/dump_visitor.rs
+++ b/src/librustc_save_analysis/dump_visitor.rs
@@ -285,6 +285,7 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> DumpVisitor<'l, 'tcx, 'll, O> {
             HirDef::Enum(..) |
             HirDef::TyAlias(..) |
             HirDef::TyForeign(..) |
+            HirDef::TraitAlias(..) |
             HirDef::Trait(_) => {
                 let span = self.span_from_span(sub_span.expect("No span found for type ref"));
                 self.dumper.dump_ref(Ref {
diff --git a/src/librustc_save_analysis/lib.rs b/src/librustc_save_analysis/lib.rs
index a815c81a6fe0b..97f77b20f8114 100644
--- a/src/librustc_save_analysis/lib.rs
+++ b/src/librustc_save_analysis/lib.rs
@@ -721,6 +721,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
             HirDef::Enum(def_id) |
             HirDef::TyAlias(def_id) |
             HirDef::TyForeign(def_id) |
+            HirDef::TraitAlias(def_id) |
             HirDef::AssociatedTy(def_id) |
             HirDef::Trait(def_id) |
             HirDef::TyParam(def_id) => {
diff --git a/src/librustc_save_analysis/sig.rs b/src/librustc_save_analysis/sig.rs
index b244876226c48..11d17e0227fdf 100644
--- a/src/librustc_save_analysis/sig.rs
+++ b/src/librustc_save_analysis/sig.rs
@@ -487,6 +487,25 @@ impl Sig for ast::Item {
 
                 Ok(sig)
             }
+            ast::ItemKind::TraitAlias(ref generics, ref bounds) => {
+                let mut text = String::new();
+                text.push_str("trait ");
+                let mut sig = name_and_generics(text,
+                                                offset,
+                                                generics,
+                                                self.id,
+                                                self.ident,
+                                                scx)?;
+
+                if !bounds.is_empty() {
+                    sig.text.push_str(" = ");
+                    sig.text.push_str(&pprust::bounds_to_string(bounds));
+                }
+                // FIXME where clause
+                sig.text.push_str(";");
+
+                Ok(sig)
+            }
             ast::ItemKind::AutoImpl(unsafety, ref trait_ref) => {
                 let mut text = String::new();
                 if unsafety == ast::Unsafety::Unsafe {
diff --git a/src/librustc_trans_utils/collector.rs b/src/librustc_trans_utils/collector.rs
index e5a97966723d2..56b1a0238a1a6 100644
--- a/src/librustc_trans_utils/collector.rs
+++ b/src/librustc_trans_utils/collector.rs
@@ -894,6 +894,7 @@ impl<'b, 'a, 'v> ItemLikeVisitor<'v> for RootCollector<'b, 'a, 'v> {
             hir::ItemTy(..)          |
             hir::ItemAutoImpl(..) |
             hir::ItemTrait(..)       |
+            hir::ItemTraitAlias(..)  |
             hir::ItemMod(..)         => {
                 // Nothing to do, just keep recursing...
             }
diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs
index 83aec27c15315..6b37a30cb82d8 100644
--- a/src/librustc_typeck/astconv.rs
+++ b/src/librustc_typeck/astconv.rs
@@ -336,6 +336,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
         let path = &trait_ref.path;
         match path.def {
             Def::Trait(trait_def_id) => trait_def_id,
+            Def::TraitAlias(alias_def_id) => alias_def_id,
             Def::Err => {
                 self.tcx().sess.fatal("cannot continue compilation due to previous error");
             }
diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs
index 85b926a707db3..3d4d8e65f699d 100644
--- a/src/librustc_typeck/collect.rs
+++ b/src/librustc_typeck/collect.rs
@@ -441,6 +441,10 @@ fn convert_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, item_id: ast::NodeId) {
             tcx.at(it.span).super_predicates_of(def_id);
             tcx.predicates_of(def_id);
         },
+        hir::ItemTraitAlias(..) => {
+            span_err!(tcx.sess, it.span, E0645,
+                      "trait aliases are not yet implemented (see issue #41517)");
+        },
         hir::ItemStruct(ref struct_def, _) |
         hir::ItemUnion(ref struct_def, _) => {
             tcx.generics_of(def_id);
@@ -672,6 +676,7 @@ fn super_predicates_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
 
     let (generics, bounds) = match item.node {
         hir::ItemTrait(.., ref generics, ref supertraits, _) => (generics, supertraits),
+        hir::ItemTraitAlias(ref generics, ref supertraits) => (generics, supertraits),
         _ => span_bug!(item.span,
                        "super_predicates invoked on non-trait"),
     };
@@ -715,6 +720,7 @@ fn trait_def<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
 
     let unsafety = match item.node {
         hir::ItemTrait(_, unsafety, ..) => unsafety,
+        hir::ItemTraitAlias(..) => hir::Unsafety::Normal,
         _ => span_bug!(item.span, "trait_def_of_item invoked on non-trait"),
     };
 
@@ -902,7 +908,7 @@ fn generics_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                     (generics, None)
                 }
 
-                ItemTrait(_, _, ref generics, ..) => {
+                ItemTrait(_, _, ref generics, ..) | ItemTraitAlias(ref generics, ..) => {
                     // Add in the self type parameter.
                     //
                     // Something of a hack: use the node id for the trait, also as
@@ -1132,7 +1138,7 @@ fn type_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                     tcx.mk_adt(def, substs)
                 }
                 ItemAutoImpl(..) |
-                ItemTrait(..) |
+                ItemTrait(..) | ItemTraitAlias(..) |
                 ItemMod(..) |
                 ItemForeignMod(..) |
                 ItemGlobalAsm(..) |
diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs
index 328b7f9fdefca..770d0cd4f1fc4 100644
--- a/src/librustc_typeck/diagnostics.rs
+++ b/src/librustc_typeck/diagnostics.rs
@@ -4721,4 +4721,5 @@ register_diagnostics! {
     E0632, // cannot provide explicit type parameters when `impl Trait` is used in
            // argument position.
     E0641, // cannot cast to/from a pointer with an unknown kind
+    E0645, // trait aliases not finished
 }
diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs
index fe1dac36be1f9..be78935cadfbb 100644
--- a/src/librustdoc/visit_ast.rs
+++ b/src/librustdoc/visit_ast.rs
@@ -512,6 +512,9 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
                 };
                 om.traits.push(t);
             },
+            hir::ItemTraitAlias(..) => {
+                unimplemented!("trait objects are not yet implemented")
+            },
 
             hir::ItemImpl(unsafety,
                           polarity,
diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs
index 3c1d6ea18f7c2..0d289dbd46b5b 100644
--- a/src/libsyntax/ast.rs
+++ b/src/libsyntax/ast.rs
@@ -1929,6 +1929,10 @@ pub enum ItemKind {
     ///
     /// E.g. `trait Foo { .. }`, `trait Foo<T> { .. }` or `auto trait Foo {}`
     Trait(IsAuto, Unsafety, Generics, TyParamBounds, Vec<TraitItem>),
+    /// Trait alias
+    ///
+    /// E.g. `trait Foo = Bar + Quux;`
+    TraitAlias(Generics, TyParamBounds),
     /// Auto trait implementation.
     ///
     /// E.g. `impl Trait for .. {}` or `impl<T> Trait<T> for .. {}`
@@ -1968,6 +1972,7 @@ impl ItemKind {
             ItemKind::Struct(..) => "struct",
             ItemKind::Union(..) => "union",
             ItemKind::Trait(..) => "trait",
+            ItemKind::TraitAlias(..) => "trait alias",
             ItemKind::Mac(..) |
             ItemKind::MacroDef(..) |
             ItemKind::Impl(..) |
diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs
index c7bfb121f801e..ba534676324a9 100644
--- a/src/libsyntax/feature_gate.rs
+++ b/src/libsyntax/feature_gate.rs
@@ -368,6 +368,8 @@ declare_features! (
     // Generators
     (active, generators, "1.21.0", None),
 
+    // Trait aliases
+    (active, trait_alias, "1.24.0", Some(41517)),
 
     // global allocators and their internals
     (active, global_allocator, "1.20.0", None),
@@ -1406,6 +1408,12 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
                 }
             }
 
+            ast::ItemKind::TraitAlias(..) => {
+                gate_feature_post!(&self, trait_alias,
+                                   i.span,
+                                   "trait aliases are not yet fully implemented");
+            }
+
             ast::ItemKind::AutoImpl(..) => {
                 gate_feature_post!(&self, optin_builtin_traits,
                                    i.span,
diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs
index 1a92f057e5e87..6f973e2bcfaef 100644
--- a/src/libsyntax/fold.rs
+++ b/src/libsyntax/fold.rs
@@ -921,6 +921,9 @@ pub fn noop_fold_item_kind<T: Folder>(i: ItemKind, folder: &mut T) -> ItemKind {
             folder.fold_bounds(bounds),
             items.move_flat_map(|item| folder.fold_trait_item(item)),
         ),
+        ItemKind::TraitAlias(generics, bounds) => ItemKind::TraitAlias(
+            folder.fold_generics(generics),
+            folder.fold_bounds(bounds)),
         ItemKind::Mac(m) => ItemKind::Mac(folder.fold_mac(m)),
         ItemKind::MacroDef(def) => ItemKind::MacroDef(folder.fold_macro_def(def)),
     }
diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs
index b3ef70fd18eb9..ec77d85f030eb 100644
--- a/src/libsyntax/parse/parser.rs
+++ b/src/libsyntax/parse/parser.rs
@@ -5182,7 +5182,7 @@ impl<'a> Parser<'a> {
         }
     }
 
-    /// Parse trait Foo { ... }
+    /// Parse `trait Foo { ... }` or `trait Foo = Bar;`
     fn parse_item_trait(&mut self, is_auto: IsAuto, unsafety: Unsafety) -> PResult<'a, ItemInfo> {
         let ident = self.parse_ident()?;
         let mut tps = self.parse_generics()?;
@@ -5194,23 +5194,34 @@ impl<'a> Parser<'a> {
             Vec::new()
         };
 
-        tps.where_clause = self.parse_where_clause()?;
-
-        self.expect(&token::OpenDelim(token::Brace))?;
-        let mut trait_items = vec![];
-        while !self.eat(&token::CloseDelim(token::Brace)) {
-            let mut at_end = false;
-            match self.parse_trait_item(&mut at_end) {
-                Ok(item) => trait_items.push(item),
-                Err(mut e) => {
-                    e.emit();
-                    if !at_end {
-                        self.recover_stmt_(SemiColonMode::Break, BlockMode::Break);
+        if self.eat(&token::Eq) {
+            // it's a trait alias
+            let bounds = self.parse_ty_param_bounds()?;
+            tps.where_clause = self.parse_where_clause()?;
+            self.expect(&token::Semi)?;
+            if unsafety != Unsafety::Normal {
+                self.span_err(self.prev_span, "trait aliases cannot be unsafe");
+            }
+            Ok((ident, ItemKind::TraitAlias(tps, bounds), None))
+        } else {
+            // it's a normal trait
+            tps.where_clause = self.parse_where_clause()?;
+            self.expect(&token::OpenDelim(token::Brace))?;
+            let mut trait_items = vec![];
+            while !self.eat(&token::CloseDelim(token::Brace)) {
+                let mut at_end = false;
+                match self.parse_trait_item(&mut at_end) {
+                    Ok(item) => trait_items.push(item),
+                    Err(mut e) => {
+                        e.emit();
+                        if !at_end {
+                            self.recover_stmt_(SemiColonMode::Break, BlockMode::Break);
+                        }
                     }
                 }
             }
+            Ok((ident, ItemKind::Trait(is_auto, unsafety, tps, bounds, trait_items), None))
         }
-        Ok((ident, ItemKind::Trait(is_auto, unsafety, tps, bounds, trait_items), None))
     }
 
     /// Parses items implementations variants
diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs
index e4b7dc26d3261..e9386e5187ff0 100644
--- a/src/libsyntax/print/pprust.rs
+++ b/src/libsyntax/print/pprust.rs
@@ -1381,6 +1381,27 @@ impl<'a> State<'a> {
                 }
                 self.bclose(item.span)?;
             }
+            ast::ItemKind::TraitAlias(ref generics, ref bounds) => {
+                self.head("")?;
+                self.print_visibility(&item.vis)?;
+                self.word_nbsp("trait")?;
+                self.print_ident(item.ident)?;
+                self.print_generics(generics)?;
+                let mut real_bounds = Vec::with_capacity(bounds.len());
+                // FIXME(durka) this seems to be some quite outdated syntax
+                for b in bounds.iter() {
+                    if let TraitTyParamBound(ref ptr, ast::TraitBoundModifier::Maybe) = *b {
+                        self.s.space()?;
+                        self.word_space("for ?")?;
+                        self.print_trait_ref(&ptr.trait_ref)?;
+                    } else {
+                        real_bounds.push(b.clone());
+                    }
+                }
+                self.print_bounds(" = ", &real_bounds[..])?;
+                self.print_where_clause(&generics.where_clause)?;
+                self.s.word(";")?;
+            }
             ast::ItemKind::Mac(codemap::Spanned { ref node, .. }) => {
                 self.print_path(&node.path, false, 0, false)?;
                 self.s.word("! ")?;
diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs
index 9a06ed0ba0297..9266cc280974d 100644
--- a/src/libsyntax/visit.rs
+++ b/src/libsyntax/visit.rs
@@ -291,6 +291,10 @@ pub fn walk_item<'a, V: Visitor<'a>>(visitor: &mut V, item: &'a Item) {
             walk_list!(visitor, visit_ty_param_bound, bounds);
             walk_list!(visitor, visit_trait_item, methods);
         }
+        ItemKind::TraitAlias(ref generics, ref bounds) => {
+            visitor.visit_generics(generics);
+            walk_list!(visitor, visit_ty_param_bound, bounds);
+        }
         ItemKind::Mac(ref mac) => visitor.visit_mac(mac),
         ItemKind::MacroDef(ref ts) => visitor.visit_mac_def(ts, item.id),
     }
diff --git a/src/test/compile-fail/trait-alias.rs b/src/test/compile-fail/trait-alias.rs
new file mode 100644
index 0000000000000..7aca227a76c48
--- /dev/null
+++ b/src/test/compile-fail/trait-alias.rs
@@ -0,0 +1,27 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// gate-test-trait_alias
+
+trait Alias1<T> = Default where T: Clone; // ok
+    //~^ERROR trait aliases are not yet fully implemented
+trait Alias2<T: Clone = ()> = Default;
+    //~^ERROR type parameters on the left side of a trait alias cannot be bounded
+    //~^^ERROR type parameters on the left side of a trait alias cannot have defaults
+    //~^^^ERROR trait aliases are not yet fully implemented
+
+impl Alias1 { //~ERROR expected type, found trait alias
+}
+
+impl Alias1 for () { //~ERROR expected trait, found trait alias
+}
+
+fn main() {}
+
diff --git a/src/test/ui/trait-alias.rs b/src/test/ui/trait-alias.rs
new file mode 100644
index 0000000000000..9ea211b4d7d69
--- /dev/null
+++ b/src/test/ui/trait-alias.rs
@@ -0,0 +1,43 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(trait_alias)]
+
+trait SimpleAlias = Default; //~ERROR E0645
+trait GenericAlias<T> = Iterator<Item=T>; //~ERROR E0645
+trait Partial<T> = IntoIterator<Item=T>; //~ERROR E0645
+
+trait Things<T> {}
+trait Romeo {}
+struct The<T>(T);
+struct Fore<T>(T);
+impl<T, U> Things<T> for The<U> {}
+impl<T> Romeo for Fore<T> {}
+
+trait WithWhere<Art, Thou> = Romeo + Romeo where Fore<(Art, Thou)>: Romeo; //~ERROR E0645
+trait BareWhere<Wild, Are> = where The<Wild>: Things<Are>; //~ERROR E0645
+
+trait CD = Clone + Default; //~ERROR E0645
+
+fn foo<T: CD>() -> (T, T) {
+    let one = T::default();
+    let two = one.clone();
+    (one, two)
+}
+
+fn main() {
+    let both = foo();
+    assert_eq!(both.0, 0);
+    assert_eq!(both.1, 0);
+    let both: (i32, i32) = foo();
+    assert_eq!(both.0, 0);
+    assert_eq!(both.1, 0);
+}
+
diff --git a/src/test/ui/trait-alias.stderr b/src/test/ui/trait-alias.stderr
new file mode 100644
index 0000000000000..ad299dc84145c
--- /dev/null
+++ b/src/test/ui/trait-alias.stderr
@@ -0,0 +1,38 @@
+error[E0645]: trait aliases are not yet implemented (see issue #41517)
+  --> $DIR/trait-alias.rs:13:1
+   |
+13 | trait SimpleAlias = Default; //~ERROR E0645
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0645]: trait aliases are not yet implemented (see issue #41517)
+  --> $DIR/trait-alias.rs:14:1
+   |
+14 | trait GenericAlias<T> = Iterator<Item=T>; //~ERROR E0645
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0645]: trait aliases are not yet implemented (see issue #41517)
+  --> $DIR/trait-alias.rs:15:1
+   |
+15 | trait Partial<T> = IntoIterator<Item=T>; //~ERROR E0645
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0645]: trait aliases are not yet implemented (see issue #41517)
+  --> $DIR/trait-alias.rs:24:1
+   |
+24 | trait WithWhere<Art, Thou> = Romeo + Romeo where Fore<(Art, Thou)>: Romeo; //~ERROR E0645
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0645]: trait aliases are not yet implemented (see issue #41517)
+  --> $DIR/trait-alias.rs:25:1
+   |
+25 | trait BareWhere<Wild, Are> = where The<Wild>: Things<Are>; //~ERROR E0645
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0645]: trait aliases are not yet implemented (see issue #41517)
+  --> $DIR/trait-alias.rs:27:1
+   |
+27 | trait CD = Clone + Default; //~ERROR E0645
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 6 previous errors
+
diff --git a/src/tools/toolstate.toml b/src/tools/toolstate.toml
index 3f0d13b585c40..b29e505c3b09e 100644
--- a/src/tools/toolstate.toml
+++ b/src/tools/toolstate.toml
@@ -32,4 +32,5 @@ clippy = "Testing"
 rls = "Broken"
 
 # ping @nrc
+# when breaking rustfmt, always break rls as well
 rustfmt = "Broken"