about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/doc/unstable-book/src/language-features/universal-impl-trait.md32
-rw-r--r--src/librustc/diagnostics.rs40
-rw-r--r--src/librustc/hir/intravisit.rs5
-rw-r--r--src/librustc/hir/lowering.rs305
-rw-r--r--src/librustc/hir/mod.rs9
-rw-r--r--src/librustc/hir/print.rs5
-rw-r--r--src/librustc/ich/impls_hir.rs3
-rw-r--r--src/librustc/middle/resolve_lifetime.rs13
-rw-r--r--src/librustc_metadata/encoder.rs2
-rw-r--r--src/librustc_privacy/lib.rs4
-rw-r--r--src/librustc_typeck/astconv.rs58
-rw-r--r--src/librustc_typeck/check/compare_method.rs47
-rw-r--r--src/librustc_typeck/check/mod.rs4
-rw-r--r--src/librustc_typeck/collect.rs159
-rw-r--r--src/librustc_typeck/diagnostics.rs56
-rw-r--r--src/librustdoc/clean/mod.rs4
-rw-r--r--src/libsyntax/feature_gate.rs7
-rw-r--r--src/test/compile-fail/impl-trait/disallowed.rs61
-rw-r--r--src/test/compile-fail/impl-trait/feature-gate-universal.rs16
-rw-r--r--src/test/compile-fail/impl-trait/feature-gate.rs2
-rw-r--r--src/test/compile-fail/impl-trait/impl-generic-mismatch-ab.rs23
-rw-r--r--src/test/compile-fail/impl-trait/impl-generic-mismatch.rs32
-rw-r--r--src/test/compile-fail/impl-trait/where-allowed.rs234
-rw-r--r--src/test/run-pass/impl-trait/auxiliary/xcrate.rs7
-rw-r--r--src/test/run-pass/impl-trait/example-calendar.rs31
-rw-r--r--src/test/run-pass/impl-trait/universal_hrtb_anon.rs (renamed from src/test/compile-fail/impl-trait/disallowed-2.rs)14
-rw-r--r--src/test/run-pass/impl-trait/universal_hrtb_named.rs20
-rw-r--r--src/test/run-pass/impl-trait/universal_in_adt_in_parameters.rs31
-rw-r--r--src/test/run-pass/impl-trait/universal_in_impl_trait_in_parameters.rs39
-rw-r--r--src/test/run-pass/impl-trait/universal_in_trait_defn_parameters.rs28
-rw-r--r--src/test/run-pass/impl-trait/universal_multiple_bounds.rs23
-rw-r--r--src/test/run-pass/impl-trait/xcrate.rs3
-rw-r--r--src/test/rustdoc/issue-43869.rs18
-rw-r--r--src/test/ui/impl-trait/universal-mismatched-type.rs19
-rw-r--r--src/test/ui/impl-trait/universal-mismatched-type.stderr13
-rw-r--r--src/test/ui/impl-trait/universal-two-impl-traits.rs21
-rw-r--r--src/test/ui/impl-trait/universal-two-impl-traits.stderr11
-rw-r--r--src/test/ui/impl-trait/universal_wrong_bounds.rs26
-rw-r--r--src/test/ui/impl-trait/universal_wrong_bounds.stderr30
-rw-r--r--src/test/ui/resolve/use_suggestion_placement.stderr14
-rw-r--r--src/tools/toolstate.toml2
41 files changed, 1146 insertions, 325 deletions
diff --git a/src/doc/unstable-book/src/language-features/universal-impl-trait.md b/src/doc/unstable-book/src/language-features/universal-impl-trait.md
new file mode 100644
index 00000000000..6b3c5e92720
--- /dev/null
+++ b/src/doc/unstable-book/src/language-features/universal-impl-trait.md
@@ -0,0 +1,32 @@
+# `universal_impl_trait`
+
+The tracking issue for this feature is: [#34511].
+
+[#34511]: https://github.com/rust-lang/rust/issues/34511
+
+--------------------
+
+The `universal_impl_trait` feature extends the [`conservative_impl_trait`]
+feature allowing the `impl Trait` syntax in arguments (universal
+quantification).
+
+[`conservative_impl_trait`]: ./language-features/conservative-impl-trait.html
+
+## Examples
+
+```rust
+#![feature(universal_impl_trait)]
+use std::ops::Not;
+
+fn any_zero(values: impl IntoIterator<Item = i32>) -> bool {
+    for val in values { if val == 0 { return true; } }
+    false
+}
+
+fn main() {
+    let test1 = -5..;
+    let test2 = vec![1, 8, 42, -87, 60];
+    assert!(any_zero(test1));
+    assert!(bool::not(any_zero(test2)));
+}
+```
diff --git a/src/librustc/diagnostics.rs b/src/librustc/diagnostics.rs
index 2b6e1d85568..bab3bded77b 100644
--- a/src/librustc/diagnostics.rs
+++ b/src/librustc/diagnostics.rs
@@ -1770,6 +1770,46 @@ If you want to get command-line arguments, use `std::env::args`. To exit with a
 specified exit code, use `std::process::exit`.
 "##,
 
+E0562: r##"
+Abstract return types (written `impl Trait` for some trait `Trait`) are only
+allowed as function return types.
+
+Erroneous code example:
+
+```compile_fail,E0562
+#![feature(conservative_impl_trait)]
+
+fn main() {
+    let count_to_ten: impl Iterator<Item=usize> = 0..10;
+    // error: `impl Trait` not allowed outside of function and inherent method
+    //        return types
+    for i in count_to_ten {
+        println!("{}", i);
+    }
+}
+```
+
+Make sure `impl Trait` only appears in return-type position.
+
+```
+#![feature(conservative_impl_trait)]
+
+fn count_to_n(n: usize) -> impl Iterator<Item=usize> {
+    0..n
+}
+
+fn main() {
+    for i in count_to_n(10) {  // ok!
+        println!("{}", i);
+    }
+}
+```
+
+See [RFC 1522] for more details.
+
+[RFC 1522]: https://github.com/rust-lang/rfcs/blob/master/text/1522-conservative-impl-trait.md
+"##,
+
 E0591: r##"
 Per [RFC 401][rfc401], if you have a function declaration `foo`:
 
diff --git a/src/librustc/hir/intravisit.rs b/src/librustc/hir/intravisit.rs
index c23a5fb1f7e..84be68cb197 100644
--- a/src/librustc/hir/intravisit.rs
+++ b/src/librustc/hir/intravisit.rs
@@ -591,7 +591,10 @@ pub fn walk_ty<'v, V: Visitor<'v>>(visitor: &mut V, typ: &'v Ty) {
             }
             visitor.visit_lifetime(lifetime);
         }
-        TyImplTrait(ref bounds) => {
+        TyImplTraitExistential(ref bounds) => {
+            walk_list!(visitor, visit_ty_param_bound, bounds);
+        }
+        TyImplTraitUniversal(_, ref bounds) => {
             walk_list!(visitor, visit_ty_param_bound, bounds);
         }
         TyTypeof(expression) => {
diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs
index ba89961adc6..8c9d1a38e70 100644
--- a/src/librustc/hir/lowering.rs
+++ b/src/librustc/hir/lowering.rs
@@ -103,6 +103,7 @@ pub struct LoweringContext<'a> {
     catch_scopes: Vec<NodeId>,
     loop_scopes: Vec<NodeId>,
     is_in_loop_condition: bool,
+    is_in_trait_impl: bool,
 
     type_def_lifetime_params: DefIdMap<usize>,
 
@@ -123,6 +124,24 @@ pub trait Resolver {
     fn definitions(&mut self) -> &mut Definitions;
 }
 
+#[derive(Clone, Copy, Debug)]
+enum ImplTraitContext {
+    /// Treat `impl Trait` as shorthand for a new universal generic parameter.
+    /// Example: `fn foo(x: impl Debug)`, where `impl Debug` is conceptually
+    /// equivalent to a fresh universal parameter like `fn foo<T: Debug>(x: T)`.
+    ///
+    /// We store a DefId here so we can look up necessary information later
+    Universal(DefId),
+
+    /// Treat `impl Trait` as shorthand for a new universal existential parameter.
+    /// Example: `fn foo() -> impl Debug`, where `impl Debug` is conceptually
+    /// equivalent to a fresh existential parameter like `abstract type T; fn foo() -> T`.
+    Existential,
+
+    /// `impl Trait` is not accepted in this position.
+    Disallowed,
+}
+
 pub fn lower_crate(sess: &Session,
                    cstore: &CrateStore,
                    dep_graph: &DepGraph,
@@ -156,6 +175,7 @@ pub fn lower_crate(sess: &Session,
         item_local_id_counters: NodeMap(),
         node_id_to_hir_id: IndexVec::new(),
         is_generator: false,
+        is_in_trait_impl: false,
     }.lower_crate(krate)
 }
 
@@ -223,6 +243,21 @@ impl<'a> LoweringContext<'a> {
             lctx: &'lcx mut LoweringContext<'interner>,
         }
 
+        impl<'lcx, 'interner> ItemLowerer<'lcx, 'interner> {
+            fn with_trait_impl_ref<F>(&mut self, trait_impl_ref: &Option<TraitRef>, f: F)
+                where F: FnOnce(&mut Self)
+            {
+                let old = self.lctx.is_in_trait_impl;
+                self.lctx.is_in_trait_impl = if let &None = trait_impl_ref {
+                    false
+                } else {
+                    true
+                };
+                f(self);
+                self.lctx.is_in_trait_impl = old;
+            }
+        }
+
         impl<'lcx, 'interner> Visitor<'lcx> for ItemLowerer<'lcx, 'interner> {
             fn visit_item(&mut self, item: &'lcx Item) {
                 let mut item_lowered = true;
@@ -235,7 +270,13 @@ impl<'a> LoweringContext<'a> {
                 });
 
                 if item_lowered {
-                    visit::walk_item(self, item);
+                    if let ItemKind::Impl(_,_,_,_,ref opt_trait_ref,_,_) = item.node {
+                        self.with_trait_impl_ref(opt_trait_ref, |this| {
+                            visit::walk_item(this, item)
+                        });
+                    } else {
+                        visit::walk_item(self, item);
+                    }
                 }
             }
 
@@ -644,48 +685,48 @@ impl<'a> LoweringContext<'a> {
         }
     }
 
-    fn lower_ty_binding(&mut self, b: &TypeBinding) -> hir::TypeBinding {
+    fn lower_ty_binding(&mut self, b: &TypeBinding, itctx: ImplTraitContext) -> hir::TypeBinding {
         hir::TypeBinding {
             id: self.lower_node_id(b.id).node_id,
             name: self.lower_ident(b.ident),
-            ty: self.lower_ty(&b.ty),
+            ty: self.lower_ty(&b.ty, itctx),
             span: b.span,
         }
     }
 
-    fn lower_ty(&mut self, t: &Ty) -> P<hir::Ty> {
+    fn lower_ty(&mut self, t: &Ty, itctx: ImplTraitContext) -> P<hir::Ty> {
         let kind = match t.node {
             TyKind::Infer => hir::TyInfer,
             TyKind::Err => hir::TyErr,
-            TyKind::Slice(ref ty) => hir::TySlice(self.lower_ty(ty)),
-            TyKind::Ptr(ref mt) => hir::TyPtr(self.lower_mt(mt)),
+            TyKind::Slice(ref ty) => hir::TySlice(self.lower_ty(ty, itctx)),
+            TyKind::Ptr(ref mt) => hir::TyPtr(self.lower_mt(mt, itctx)),
             TyKind::Rptr(ref region, ref mt) => {
                 let span = t.span.with_hi(t.span.lo());
                 let lifetime = match *region {
                     Some(ref lt) => self.lower_lifetime(lt),
                     None => self.elided_lifetime(span)
                 };
-                hir::TyRptr(lifetime, self.lower_mt(mt))
+                hir::TyRptr(lifetime, self.lower_mt(mt, itctx))
             }
             TyKind::BareFn(ref f) => {
                 hir::TyBareFn(P(hir::BareFnTy {
                     lifetimes: self.lower_lifetime_defs(&f.lifetimes),
                     unsafety: self.lower_unsafety(f.unsafety),
                     abi: f.abi,
-                    decl: self.lower_fn_decl(&f.decl),
+                    decl: self.lower_fn_decl(&f.decl, None, false),
                     arg_names: self.lower_fn_args_to_names(&f.decl),
                 }))
             }
             TyKind::Never => hir::TyNever,
             TyKind::Tup(ref tys) => {
-                hir::TyTup(tys.iter().map(|ty| self.lower_ty(ty)).collect())
+                hir::TyTup(tys.iter().map(|ty| self.lower_ty(ty, itctx)).collect())
             }
             TyKind::Paren(ref ty) => {
-                return self.lower_ty(ty);
+                return self.lower_ty(ty, itctx);
             }
             TyKind::Path(ref qself, ref path) => {
                 let id = self.lower_node_id(t.id);
-                let qpath = self.lower_qpath(t.id, qself, path, ParamMode::Explicit);
+                let qpath = self.lower_qpath(t.id, qself, path, ParamMode::Explicit, itctx);
                 return self.ty_path(id, t.span, qpath);
             }
             TyKind::ImplicitSelf => {
@@ -699,7 +740,7 @@ impl<'a> LoweringContext<'a> {
             }
             TyKind::Array(ref ty, ref length) => {
                 let length = self.lower_body(None, |this| this.lower_expr(length));
-                hir::TyArray(self.lower_ty(ty), length)
+                hir::TyArray(self.lower_ty(ty, itctx), length)
             }
             TyKind::Typeof(ref expr) => {
                 let expr = self.lower_body(None, |this| this.lower_expr(expr));
@@ -710,7 +751,7 @@ impl<'a> LoweringContext<'a> {
                 let bounds = bounds.iter().filter_map(|bound| {
                     match *bound {
                         TraitTyParamBound(ref ty, TraitBoundModifier::None) => {
-                            Some(self.lower_poly_trait_ref(ty))
+                            Some(self.lower_poly_trait_ref(ty, itctx))
                         }
                         TraitTyParamBound(_, TraitBoundModifier::Maybe) => None,
                         RegionTyParamBound(ref lifetime) => {
@@ -727,7 +768,33 @@ impl<'a> LoweringContext<'a> {
                 hir::TyTraitObject(bounds, lifetime_bound)
             }
             TyKind::ImplTrait(ref bounds) => {
-                hir::TyImplTrait(self.lower_bounds(bounds))
+                use syntax::feature_gate::{emit_feature_err, GateIssue};
+                match itctx {
+                    ImplTraitContext::Existential => {
+                        let has_feature = self.sess.features.borrow().conservative_impl_trait;
+                        if !t.span.allows_unstable() && !has_feature {
+                            emit_feature_err(&self.sess.parse_sess, "conservative_impl_trait",
+                                             t.span, GateIssue::Language,
+                                             "`impl Trait` in return position is experimental");
+                        }
+                        hir::TyImplTraitExistential(self.lower_bounds(bounds, itctx))
+                    },
+                    ImplTraitContext::Universal(def_id) => {
+                        let has_feature = self.sess.features.borrow().universal_impl_trait;
+                        if !t.span.allows_unstable() && !has_feature {
+                            emit_feature_err(&self.sess.parse_sess, "universal_impl_trait",
+                                             t.span, GateIssue::Language,
+                                             "`impl Trait` in argument position is experimental");
+                        }
+                        hir::TyImplTraitUniversal(def_id, self.lower_bounds(bounds, itctx))
+                    },
+                    ImplTraitContext::Disallowed => {
+                        span_err!(self.sess, t.span, E0562,
+                                  "`impl Trait` not allowed outside of function \
+                                  and inherent method return types");
+                        hir::TyErr
+                    }
+                }
             }
             TyKind::Mac(_) => panic!("TyMac should have been expanded by now."),
         };
@@ -773,10 +840,11 @@ impl<'a> LoweringContext<'a> {
                    id: NodeId,
                    qself: &Option<QSelf>,
                    p: &Path,
-                   param_mode: ParamMode)
+                   param_mode: ParamMode,
+                   itctx: ImplTraitContext)
                    -> hir::QPath {
         let qself_position = qself.as_ref().map(|q| q.position);
-        let qself = qself.as_ref().map(|q| self.lower_ty(&q.ty));
+        let qself = qself.as_ref().map(|q| self.lower_ty(&q.ty, itctx));
 
         let resolution = self.resolver.get_resolution(id)
                                       .unwrap_or(PathResolution::new(Def::Err));
@@ -846,7 +914,7 @@ impl<'a> LoweringContext<'a> {
                     n
                 });
                 self.lower_path_segment(p.span, segment, param_mode, num_lifetimes,
-                                        parenthesized_generic_args)
+                                        parenthesized_generic_args, itctx)
             }).collect(),
             span: p.span,
         });
@@ -882,7 +950,8 @@ impl<'a> LoweringContext<'a> {
         // * final path is `<<<std::vec::Vec<T>>::IntoIter>::Item>::clone`
         for (i, segment) in p.segments.iter().enumerate().skip(proj_start) {
             let segment = P(self.lower_path_segment(p.span, segment, param_mode, 0,
-                                                    ParenthesizedGenericArgs::Warn));
+                                                    ParenthesizedGenericArgs::Warn,
+                                                    itctx));
             let qpath = hir::QPath::TypeRelative(ty, segment);
 
             // It's finished, return the extension of the right node type.
@@ -916,7 +985,8 @@ impl<'a> LoweringContext<'a> {
             def: self.expect_full_def(id),
             segments: segments.map(|segment| {
                 self.lower_path_segment(p.span, segment, param_mode, 0,
-                                        ParenthesizedGenericArgs::Err)
+                                        ParenthesizedGenericArgs::Err,
+                                        ImplTraitContext::Disallowed)
             }).chain(name.map(|name| hir::PathSegment::from_name(name)))
               .collect(),
             span: p.span,
@@ -937,16 +1007,18 @@ impl<'a> LoweringContext<'a> {
                           segment: &PathSegment,
                           param_mode: ParamMode,
                           expected_lifetimes: usize,
-                          parenthesized_generic_args: ParenthesizedGenericArgs)
+                          parenthesized_generic_args: ParenthesizedGenericArgs,
+                          itctx: ImplTraitContext)
                           -> hir::PathSegment {
         let (mut parameters, infer_types) = if let Some(ref parameters) = segment.parameters {
             let msg = "parenthesized parameters may only be used with a trait";
             match **parameters {
                 PathParameters::AngleBracketed(ref data) => {
-                    self.lower_angle_bracketed_parameter_data(data, param_mode)
+                    self.lower_angle_bracketed_parameter_data(data, param_mode, itctx)
                 }
                 PathParameters::Parenthesized(ref data) => match parenthesized_generic_args {
-                    ParenthesizedGenericArgs::Ok => self.lower_parenthesized_parameter_data(data),
+                    ParenthesizedGenericArgs::Ok =>
+                        self.lower_parenthesized_parameter_data(data),
                     ParenthesizedGenericArgs::Warn => {
                         self.sess.buffer_lint(PARENTHESIZED_PARAMS_IN_TYPES_AND_MODULES,
                                               CRATE_NODE_ID, data.span, msg.into());
@@ -960,7 +1032,7 @@ impl<'a> LoweringContext<'a> {
                 }
             }
         } else {
-            self.lower_angle_bracketed_parameter_data(&Default::default(), param_mode)
+            self.lower_angle_bracketed_parameter_data(&Default::default(), param_mode, itctx)
         };
 
         if !parameters.parenthesized && parameters.lifetimes.is_empty() {
@@ -978,13 +1050,14 @@ impl<'a> LoweringContext<'a> {
 
     fn lower_angle_bracketed_parameter_data(&mut self,
                                             data: &AngleBracketedParameterData,
-                                            param_mode: ParamMode)
+                                            param_mode: ParamMode,
+                                            itctx: ImplTraitContext)
                                             -> (hir::PathParameters, bool) {
         let &AngleBracketedParameterData { ref lifetimes, ref types, ref bindings, .. } = data;
         (hir::PathParameters {
             lifetimes: self.lower_lifetimes(lifetimes),
-            types: types.iter().map(|ty| self.lower_ty(ty)).collect(),
-            bindings: bindings.iter().map(|b| self.lower_ty_binding(b)).collect(),
+            types: types.iter().map(|ty| self.lower_ty(ty, itctx)).collect(),
+            bindings: bindings.iter().map(|b| self.lower_ty_binding(b, itctx)).collect(),
             parenthesized: false,
         }, types.is_empty() && param_mode == ParamMode::Optional)
     }
@@ -992,8 +1065,9 @@ impl<'a> LoweringContext<'a> {
     fn lower_parenthesized_parameter_data(&mut self,
                                           data: &ParenthesizedParameterData)
                                           -> (hir::PathParameters, bool) {
+        const DISALLOWED: ImplTraitContext = ImplTraitContext::Disallowed;
         let &ParenthesizedParameterData { ref inputs, ref output, span } = data;
-        let inputs = inputs.iter().map(|ty| self.lower_ty(ty)).collect();
+        let inputs = inputs.iter().map(|ty| self.lower_ty(ty, DISALLOWED)).collect();
         let mk_tup = |this: &mut Self, tys, span| {
             let LoweredNodeId { node_id, hir_id } = this.next_id();
             P(hir::Ty { node: hir::TyTup(tys), id: node_id, hir_id, span })
@@ -1005,7 +1079,7 @@ impl<'a> LoweringContext<'a> {
             bindings: hir_vec![hir::TypeBinding {
                 id: self.next_id().node_id,
                 name: Symbol::intern(FN_OUTPUT_NAME),
-                ty: output.as_ref().map(|ty| self.lower_ty(&ty))
+                ty: output.as_ref().map(|ty| self.lower_ty(&ty, DISALLOWED))
                                    .unwrap_or_else(|| mk_tup(self, hir::HirVec::new(), span)),
                 span: output.as_ref().map_or(span, |ty| ty.span),
             }],
@@ -1018,7 +1092,7 @@ impl<'a> LoweringContext<'a> {
         P(hir::Local {
             id: node_id,
             hir_id,
-            ty: l.ty.as_ref().map(|t| self.lower_ty(t)),
+            ty: l.ty.as_ref().map(|t| self.lower_ty(t, ImplTraitContext::Disallowed)),
             pat: self.lower_pat(&l.pat),
             init: l.init.as_ref().map(|e| P(self.lower_expr(e))),
             span: l.span,
@@ -1055,11 +1129,32 @@ impl<'a> LoweringContext<'a> {
         }).collect()
     }
 
-    fn lower_fn_decl(&mut self, decl: &FnDecl) -> P<hir::FnDecl> {
+
+    fn lower_fn_decl(&mut self,
+                     decl: &FnDecl,
+                     fn_def_id: Option<DefId>,
+                     impl_trait_return_allow: bool)
+                     -> P<hir::FnDecl> {
+        // NOTE: The two last paramters here have to do with impl Trait. If fn_def_id is Some,
+        //       then impl Trait arguments are lowered into generic paramters on the given
+        //       fn_def_id, otherwise impl Trait is disallowed. (for now)
+        //
+        //       Furthermore, if impl_trait_return_allow is true, then impl Trait may be used in
+        //       return positions as well. This guards against trait declarations and their impls
+        //       where impl Trait is disallowed. (again for now)
         P(hir::FnDecl {
-            inputs: decl.inputs.iter().map(|arg| self.lower_ty(&arg.ty)).collect(),
+            inputs: decl.inputs.iter()
+                .map(|arg| if let Some(def_id) = fn_def_id {
+                    self.lower_ty(&arg.ty, ImplTraitContext::Universal(def_id))
+                } else {
+                    self.lower_ty(&arg.ty, ImplTraitContext::Disallowed)
+                }).collect(),
             output: match decl.output {
-                FunctionRetTy::Ty(ref ty) => hir::Return(self.lower_ty(ty)),
+                FunctionRetTy::Ty(ref ty) => match fn_def_id {
+                    Some(_) if impl_trait_return_allow =>
+                        hir::Return(self.lower_ty(ty, ImplTraitContext::Existential)),
+                    _ => hir::Return(self.lower_ty(ty, ImplTraitContext::Disallowed)),
+                },
                 FunctionRetTy::Default(span) => hir::DefaultReturn(span),
             },
             variadic: decl.variadic,
@@ -1073,10 +1168,11 @@ impl<'a> LoweringContext<'a> {
         })
     }
 
-    fn lower_ty_param_bound(&mut self, tpb: &TyParamBound) -> hir::TyParamBound {
+    fn lower_ty_param_bound(&mut self, tpb: &TyParamBound, itctx: ImplTraitContext)
+                            -> hir::TyParamBound {
         match *tpb {
             TraitTyParamBound(ref ty, modifier) => {
-                hir::TraitTyParamBound(self.lower_poly_trait_ref(ty),
+                hir::TraitTyParamBound(self.lower_poly_trait_ref(ty, itctx),
                                        self.lower_trait_bound_modifier(modifier))
             }
             RegionTyParamBound(ref lifetime) => {
@@ -1095,16 +1191,19 @@ impl<'a> LoweringContext<'a> {
             name = Symbol::gensym("Self");
         }
 
-        let mut bounds = self.lower_bounds(&tp.bounds);
+        let itctx = ImplTraitContext::Universal(self.resolver.definitions().local_def_id(tp.id));
+        let mut bounds = self.lower_bounds(&tp.bounds, itctx);
         if !add_bounds.is_empty() {
-            bounds = bounds.into_iter().chain(self.lower_bounds(add_bounds).into_iter()).collect();
+            bounds = bounds.into_iter().chain(
+                self.lower_bounds(add_bounds, itctx).into_iter()
+            ).collect();
         }
 
         hir::TyParam {
             id: self.lower_node_id(tp.id).node_id,
             name,
             bounds,
-            default: tp.default.as_ref().map(|x| self.lower_ty(x)),
+            default: tp.default.as_ref().map(|x| self.lower_ty(x, ImplTraitContext::Disallowed)),
             span: tp.span,
             pure_wrt_drop: tp.attrs.iter().any(|attr| attr.check_name("may_dangle")),
             synthetic: tp.attrs.iter()
@@ -1215,11 +1314,11 @@ impl<'a> LoweringContext<'a> {
                                                                 span}) => {
                 hir::WherePredicate::BoundPredicate(hir::WhereBoundPredicate {
                     bound_lifetimes: self.lower_lifetime_defs(bound_lifetimes),
-                    bounded_ty: self.lower_ty(bounded_ty),
+                    bounded_ty: self.lower_ty(bounded_ty, ImplTraitContext::Disallowed),
                     bounds: bounds.iter().filter_map(|bound| match *bound {
                         // Ignore `?Trait` bounds, they were copied into type parameters already.
                         TraitTyParamBound(_, TraitBoundModifier::Maybe) => None,
-                        _ => Some(self.lower_ty_param_bound(bound))
+                        _ => Some(self.lower_ty_param_bound(bound, ImplTraitContext::Disallowed))
                     }).collect(),
                     span,
                 })
@@ -1239,8 +1338,8 @@ impl<'a> LoweringContext<'a> {
                                                           span}) => {
                 hir::WherePredicate::EqPredicate(hir::WhereEqPredicate {
                     id: self.lower_node_id(id).node_id,
-                    lhs_ty: self.lower_ty(lhs_ty),
-                    rhs_ty: self.lower_ty(rhs_ty),
+                    lhs_ty: self.lower_ty(lhs_ty, ImplTraitContext::Disallowed),
+                    rhs_ty: self.lower_ty(rhs_ty, ImplTraitContext::Disallowed),
                     span,
                 })
             }
@@ -1267,8 +1366,8 @@ impl<'a> LoweringContext<'a> {
         }
     }
 
-    fn lower_trait_ref(&mut self, p: &TraitRef) -> hir::TraitRef {
-        let path = match self.lower_qpath(p.ref_id, &None, &p.path, ParamMode::Explicit) {
+    fn lower_trait_ref(&mut self, p: &TraitRef, itctx: ImplTraitContext) -> hir::TraitRef {
+        let path = match self.lower_qpath(p.ref_id, &None, &p.path, ParamMode::Explicit, itctx) {
             hir::QPath::Resolved(None, path) => path.and_then(|path| path),
             qpath => bug!("lower_trait_ref: unexpected QPath `{:?}`", qpath)
         };
@@ -1278,10 +1377,13 @@ impl<'a> LoweringContext<'a> {
         }
     }
 
-    fn lower_poly_trait_ref(&mut self, p: &PolyTraitRef) -> hir::PolyTraitRef {
+    fn lower_poly_trait_ref(&mut self,
+                            p: &PolyTraitRef,
+                            itctx: ImplTraitContext)
+                            -> hir::PolyTraitRef {
         hir::PolyTraitRef {
             bound_lifetimes: self.lower_lifetime_defs(&p.bound_lifetimes),
-            trait_ref: self.lower_trait_ref(&p.trait_ref),
+            trait_ref: self.lower_trait_ref(&p.trait_ref, itctx),
             span: p.span,
         }
     }
@@ -1296,7 +1398,7 @@ impl<'a> LoweringContext<'a> {
                 None => Ident { name: Symbol::intern(&index.to_string()), ctxt: f.span.ctxt() },
             }),
             vis: self.lower_visibility(&f.vis, None),
-            ty: self.lower_ty(&f.ty),
+            ty: self.lower_ty(&f.ty, ImplTraitContext::Disallowed),
             attrs: self.lower_attrs(&f.attrs),
         }
     }
@@ -1310,15 +1412,16 @@ impl<'a> LoweringContext<'a> {
         }
     }
 
-    fn lower_mt(&mut self, mt: &MutTy) -> hir::MutTy {
+    fn lower_mt(&mut self, mt: &MutTy, itctx: ImplTraitContext) -> hir::MutTy {
         hir::MutTy {
-            ty: self.lower_ty(&mt.ty),
+            ty: self.lower_ty(&mt.ty, itctx),
             mutbl: self.lower_mutability(mt.mutbl),
         }
     }
 
-    fn lower_bounds(&mut self, bounds: &[TyParamBound]) -> hir::TyParamBounds {
-        bounds.iter().map(|bound| self.lower_ty_param_bound(bound)).collect()
+    fn lower_bounds(&mut self, bounds: &[TyParamBound], itctx: ImplTraitContext)
+                    -> hir::TyParamBounds {
+        bounds.iter().map(|bound| self.lower_ty_param_bound(bound, itctx)).collect()
     }
 
     fn lower_block(&mut self, b: &Block, targeted_by_break: bool) -> P<hir::Block> {
@@ -1437,33 +1540,35 @@ impl<'a> LoweringContext<'a> {
             }
             ItemKind::Static(ref t, m, ref e) => {
                 let value = self.lower_body(None, |this| this.lower_expr(e));
-                hir::ItemStatic(self.lower_ty(t),
+                hir::ItemStatic(self.lower_ty(t, ImplTraitContext::Disallowed),
                                 self.lower_mutability(m),
                                 value)
             }
             ItemKind::Const(ref t, ref e) => {
                 let value = self.lower_body(None, |this| this.lower_expr(e));
-                hir::ItemConst(self.lower_ty(t), value)
+                hir::ItemConst(self.lower_ty(t, ImplTraitContext::Disallowed), value)
             }
             ItemKind::Fn(ref decl, unsafety, constness, abi, ref generics, ref body) => {
+                let fn_def_id = self.resolver.definitions().opt_local_def_id(id);
                 self.with_new_scopes(|this| {
                     let body_id = this.lower_body(Some(decl), |this| {
                         let body = this.lower_block(body, false);
                         this.expr_block(body, ThinVec::new())
                     });
-                    hir::ItemFn(this.lower_fn_decl(decl),
-                                              this.lower_unsafety(unsafety),
-                                              this.lower_constness(constness),
-                                              abi,
-                                              this.lower_generics(generics),
-                                              body_id)
+                    hir::ItemFn(this.lower_fn_decl(decl, fn_def_id, true),
+                                this.lower_unsafety(unsafety),
+                                this.lower_constness(constness),
+                                abi,
+                                this.lower_generics(generics),
+                                body_id)
                 })
             }
             ItemKind::Mod(ref m) => hir::ItemMod(self.lower_mod(m)),
             ItemKind::ForeignMod(ref nm) => hir::ItemForeignMod(self.lower_foreign_mod(nm)),
             ItemKind::GlobalAsm(ref ga) => hir::ItemGlobalAsm(self.lower_global_asm(ga)),
             ItemKind::Ty(ref t, ref generics) => {
-                hir::ItemTy(self.lower_ty(t), self.lower_generics(generics))
+                hir::ItemTy(self.lower_ty(t, ImplTraitContext::Disallowed),
+                            self.lower_generics(generics))
             }
             ItemKind::Enum(ref enum_definition, ref generics) => {
                 hir::ItemEnum(hir::EnumDef {
@@ -1483,7 +1588,7 @@ impl<'a> LoweringContext<'a> {
                 hir::ItemUnion(vdata, self.lower_generics(generics))
             }
             ItemKind::AutoImpl(unsafety, ref trait_ref) => {
-                let trait_ref = self.lower_trait_ref(trait_ref);
+                let trait_ref = self.lower_trait_ref(trait_ref, ImplTraitContext::Disallowed);
 
                 if let Def::Trait(def_id) = trait_ref.path.def {
                     self.trait_auto_impl.insert(def_id, id);
@@ -1502,7 +1607,9 @@ impl<'a> LoweringContext<'a> {
                 let new_impl_items = impl_items.iter()
                                                .map(|item| self.lower_impl_item_ref(item))
                                                .collect();
-                let ifce = ifce.as_ref().map(|trait_ref| self.lower_trait_ref(trait_ref));
+                let ifce = ifce.as_ref().map(|trait_ref| {
+                    self.lower_trait_ref(trait_ref, ImplTraitContext::Disallowed)
+                });
 
                 if let Some(ref trait_ref) = ifce {
                     if let Def::Trait(def_id) = trait_ref.path.def {
@@ -1515,11 +1622,11 @@ impl<'a> LoweringContext<'a> {
                               self.lower_defaultness(defaultness, true /* [1] */),
                               self.lower_generics(generics),
                               ifce,
-                              self.lower_ty(ty),
+                              self.lower_ty(ty, ImplTraitContext::Disallowed),
                               new_impl_items)
             }
             ItemKind::Trait(is_auto, unsafety, ref generics, ref bounds, ref items) => {
-                let bounds = self.lower_bounds(bounds);
+                let bounds = self.lower_bounds(bounds, ImplTraitContext::Disallowed);
                 let items = items.iter().map(|item| self.lower_trait_item_ref(item)).collect();
                 hir::ItemTrait(self.lower_is_auto(is_auto),
                                self.lower_unsafety(unsafety),
@@ -1537,6 +1644,7 @@ impl<'a> LoweringContext<'a> {
     fn lower_trait_item(&mut self, i: &TraitItem) -> hir::TraitItem {
         self.with_parent_def(i.id, |this| {
             let LoweredNodeId { node_id, hir_id } = this.lower_node_id(i.id);
+            let fn_def_id = this.resolver.definitions().opt_local_def_id(node_id);
 
             hir::TraitItem {
                 id: node_id,
@@ -1546,14 +1654,14 @@ impl<'a> LoweringContext<'a> {
                 generics: this.lower_generics(&i.generics),
                 node: match i.node {
                     TraitItemKind::Const(ref ty, ref default) => {
-                        hir::TraitItemKind::Const(this.lower_ty(ty),
+                        hir::TraitItemKind::Const(this.lower_ty(ty, ImplTraitContext::Disallowed),
                                                   default.as_ref().map(|x| {
                             this.lower_body(None, |this| this.lower_expr(x))
                         }))
                     }
                     TraitItemKind::Method(ref sig, None) => {
                         let names = this.lower_fn_args_to_names(&sig.decl);
-                        hir::TraitItemKind::Method(this.lower_method_sig(sig),
+                        hir::TraitItemKind::Method(this.lower_method_sig(sig, fn_def_id, false),
                                                    hir::TraitMethod::Required(names))
                     }
                     TraitItemKind::Method(ref sig, Some(ref body)) => {
@@ -1561,12 +1669,15 @@ impl<'a> LoweringContext<'a> {
                             let body = this.lower_block(body, false);
                             this.expr_block(body, ThinVec::new())
                         });
-                        hir::TraitItemKind::Method(this.lower_method_sig(sig),
+                        hir::TraitItemKind::Method(this.lower_method_sig(sig, fn_def_id, false),
                                                    hir::TraitMethod::Provided(body_id))
                     }
                     TraitItemKind::Type(ref bounds, ref default) => {
-                        hir::TraitItemKind::Type(this.lower_bounds(bounds),
-                                                 default.as_ref().map(|x| this.lower_ty(x)))
+                        hir::TraitItemKind::Type(this.lower_bounds(bounds,
+                                                                   ImplTraitContext::Disallowed),
+                                                 default.as_ref().map(|x| {
+                                                     this.lower_ty(x, ImplTraitContext::Disallowed)
+                                                 }))
                     }
                     TraitItemKind::Macro(..) => panic!("Shouldn't exist any more"),
                 },
@@ -1602,6 +1713,7 @@ impl<'a> LoweringContext<'a> {
     fn lower_impl_item(&mut self, i: &ImplItem) -> hir::ImplItem {
         self.with_parent_def(i.id, |this| {
             let LoweredNodeId { node_id, hir_id } = this.lower_node_id(i.id);
+            let fn_def_id = this.resolver.definitions().opt_local_def_id(node_id);
 
             hir::ImplItem {
                 id: node_id,
@@ -1614,16 +1726,24 @@ impl<'a> LoweringContext<'a> {
                 node: match i.node {
                     ImplItemKind::Const(ref ty, ref expr) => {
                         let body_id = this.lower_body(None, |this| this.lower_expr(expr));
-                        hir::ImplItemKind::Const(this.lower_ty(ty), body_id)
+                        hir::ImplItemKind::Const(
+                            this.lower_ty(ty, ImplTraitContext::Disallowed),
+                            body_id
+                        )
                     }
                     ImplItemKind::Method(ref sig, ref body) => {
                         let body_id = this.lower_body(Some(&sig.decl), |this| {
                             let body = this.lower_block(body, false);
                             this.expr_block(body, ThinVec::new())
                         });
-                        hir::ImplItemKind::Method(this.lower_method_sig(sig), body_id)
+                        let impl_trait_return_allow = !this.is_in_trait_impl;
+                        hir::ImplItemKind::Method(this.lower_method_sig(sig,
+                                                                        fn_def_id,
+                                                                        impl_trait_return_allow),
+                                                  body_id)
                     }
-                    ImplItemKind::Type(ref ty) => hir::ImplItemKind::Type(this.lower_ty(ty)),
+                    ImplItemKind::Type(ref ty) =>
+                        hir::ImplItemKind::Type(this.lower_ty(ty, ImplTraitContext::Disallowed)),
                     ImplItemKind::Macro(..) => panic!("Shouldn't exist any more"),
                 },
                 span: i.span,
@@ -1643,8 +1763,10 @@ impl<'a> LoweringContext<'a> {
             kind: match i.node {
                 ImplItemKind::Const(..) => hir::AssociatedItemKind::Const,
                 ImplItemKind::Type(..) => hir::AssociatedItemKind::Type,
-                ImplItemKind::Method(ref sig, _) => hir::AssociatedItemKind::Method {
-                    has_self: sig.decl.has_self(),
+                ImplItemKind::Method(ref sig, _) => {
+                    hir::AssociatedItemKind::Method {
+                        has_self: sig.decl.has_self(),
+                    }
                 },
                 ImplItemKind::Macro(..) => unimplemented!(),
             },
@@ -1719,12 +1841,13 @@ impl<'a> LoweringContext<'a> {
                 attrs: this.lower_attrs(&i.attrs),
                 node: match i.node {
                     ForeignItemKind::Fn(ref fdec, ref generics) => {
-                        hir::ForeignItemFn(this.lower_fn_decl(fdec),
+                        // Disallow impl Trait in foreign items
+                        hir::ForeignItemFn(this.lower_fn_decl(fdec, None, false),
                                            this.lower_fn_args_to_names(fdec),
                                            this.lower_generics(generics))
                     }
                     ForeignItemKind::Static(ref t, m) => {
-                        hir::ForeignItemStatic(this.lower_ty(t), m)
+                        hir::ForeignItemStatic(this.lower_ty(t, ImplTraitContext::Disallowed), m)
                     }
                     ForeignItemKind::Ty => {
                         hir::ForeignItemType
@@ -1736,12 +1859,16 @@ impl<'a> LoweringContext<'a> {
         })
     }
 
-    fn lower_method_sig(&mut self, sig: &MethodSig) -> hir::MethodSig {
+    fn lower_method_sig(&mut self,
+                        sig: &MethodSig,
+                        fn_def_id: Option<DefId>,
+                        impl_trait_return_allow: bool)
+                        -> hir::MethodSig {
         hir::MethodSig {
             abi: sig.abi,
             unsafety: self.lower_unsafety(sig.unsafety),
             constness: self.lower_constness(sig.constness),
-            decl: self.lower_fn_decl(&sig.decl),
+            decl: self.lower_fn_decl(&sig.decl, fn_def_id, impl_trait_return_allow),
         }
     }
 
@@ -1834,16 +1961,19 @@ impl<'a> LoweringContext<'a> {
                 }
                 PatKind::Lit(ref e) => hir::PatKind::Lit(P(self.lower_expr(e))),
                 PatKind::TupleStruct(ref path, ref pats, ddpos) => {
-                    let qpath = self.lower_qpath(p.id, &None, path, ParamMode::Optional);
+                    let qpath = self.lower_qpath(p.id, &None, path, ParamMode::Optional,
+                                                 ImplTraitContext::Disallowed);
                     hir::PatKind::TupleStruct(qpath,
                                               pats.iter().map(|x| self.lower_pat(x)).collect(),
                                               ddpos)
                 }
                 PatKind::Path(ref qself, ref path) => {
-                    hir::PatKind::Path(self.lower_qpath(p.id, qself, path, ParamMode::Optional))
+                    hir::PatKind::Path(self.lower_qpath(p.id, qself, path, ParamMode::Optional,
+                                                        ImplTraitContext::Disallowed))
                 }
                 PatKind::Struct(ref path, ref fields, etc) => {
-                    let qpath = self.lower_qpath(p.id, &None, path, ParamMode::Optional);
+                    let qpath = self.lower_qpath(p.id, &None, path, ParamMode::Optional,
+                                                 ImplTraitContext::Disallowed);
 
                     let fs = fields.iter()
                                    .map(|f| {
@@ -2020,7 +2150,8 @@ impl<'a> LoweringContext<'a> {
             }
             ExprKind::MethodCall(ref seg, ref args) => {
                 let hir_seg = self.lower_path_segment(e.span, seg, ParamMode::Optional, 0,
-                                                      ParenthesizedGenericArgs::Err);
+                                                      ParenthesizedGenericArgs::Err,
+                                                      ImplTraitContext::Disallowed);
                 let args = args.iter().map(|x| self.lower_expr(x)).collect();
                 hir::ExprMethodCall(hir_seg, seg.span, args)
             }
@@ -2038,11 +2169,11 @@ impl<'a> LoweringContext<'a> {
             ExprKind::Lit(ref l) => hir::ExprLit(P((**l).clone())),
             ExprKind::Cast(ref expr, ref ty) => {
                 let expr = P(self.lower_expr(expr));
-                hir::ExprCast(expr, self.lower_ty(ty))
+                hir::ExprCast(expr, self.lower_ty(ty, ImplTraitContext::Disallowed))
             }
             ExprKind::Type(ref expr, ref ty) => {
                 let expr = P(self.lower_expr(expr));
-                hir::ExprType(expr, self.lower_ty(ty))
+                hir::ExprType(expr, self.lower_ty(ty, ImplTraitContext::Disallowed))
             }
             ExprKind::AddrOf(m, ref ohs) => {
                 let m = self.lower_mutability(m);
@@ -2119,7 +2250,7 @@ impl<'a> LoweringContext<'a> {
                             this.sess.abort_if_errors();
                         }
                         hir::ExprClosure(this.lower_capture_clause(capture_clause),
-                                         this.lower_fn_decl(decl),
+                                         this.lower_fn_decl(decl, None, false),
                                          body_id,
                                          fn_decl_span,
                                          is_generator)
@@ -2193,7 +2324,8 @@ impl<'a> LoweringContext<'a> {
                 };
             }
             ExprKind::Path(ref qself, ref path) => {
-                hir::ExprPath(self.lower_qpath(e.id, qself, path, ParamMode::Optional))
+                hir::ExprPath(self.lower_qpath(e.id, qself, path, ParamMode::Optional,
+                                               ImplTraitContext::Disallowed))
             }
             ExprKind::Break(opt_ident, ref opt_expr) => {
                 let label_result = if self.is_in_loop_condition && opt_ident.is_none() {
@@ -2246,7 +2378,8 @@ impl<'a> LoweringContext<'a> {
                 hir::ExprInlineAsm(P(hir_asm), outputs, inputs)
             }
             ExprKind::Struct(ref path, ref fields, ref maybe_expr) => {
-                hir::ExprStruct(self.lower_qpath(e.id, &None, path, ParamMode::Optional),
+                hir::ExprStruct(self.lower_qpath(e.id, &None, path, ParamMode::Optional,
+                                                 ImplTraitContext::Disallowed),
                                 fields.iter().map(|x| self.lower_field(x)).collect(),
                                 maybe_expr.as_ref().map(|x| P(self.lower_expr(x))))
             }
diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs
index a7206f5d420..ee83000c440 100644
--- a/src/librustc/hir/mod.rs
+++ b/src/librustc/hir/mod.rs
@@ -1461,9 +1461,12 @@ pub enum Ty_ {
     /// A trait object type `Bound1 + Bound2 + Bound3`
     /// where `Bound` is a trait or a lifetime.
     TyTraitObject(HirVec<PolyTraitRef>, Lifetime),
-    /// An `impl Bound1 + Bound2 + Bound3` type
-    /// where `Bound` is a trait or a lifetime.
-    TyImplTrait(TyParamBounds),
+    /// An exsitentially quantified (there exists a type satisfying) `impl
+    /// Bound1 + Bound2 + Bound3` type where `Bound` is a trait or a lifetime.
+    TyImplTraitExistential(TyParamBounds),
+    /// An universally quantified (for all types satisfying) `impl
+    /// Bound1 + Bound2 + Bound3` type where `Bound` is a trait or a lifetime.
+    TyImplTraitUniversal(DefId, TyParamBounds),
     /// Unused for now
     TyTypeof(BodyId),
     /// TyInfer means the type should be inferred instead of it having been
diff --git a/src/librustc/hir/print.rs b/src/librustc/hir/print.rs
index 7d0f26ba34d..451e870f500 100644
--- a/src/librustc/hir/print.rs
+++ b/src/librustc/hir/print.rs
@@ -421,8 +421,9 @@ impl<'a> State<'a> {
                     self.print_lifetime(lifetime)?;
                 }
             }
-            hir::TyImplTrait(ref bounds) => {
-                self.print_bounds("impl ", &bounds[..])?;
+            hir::TyImplTraitExistential(ref bounds) |
+                hir::TyImplTraitUniversal(_, ref bounds) => {
+                self.print_bounds("impl", &bounds[..])?;
             }
             hir::TyArray(ref ty, v) => {
                 self.s.word("[")?;
diff --git a/src/librustc/ich/impls_hir.rs b/src/librustc/ich/impls_hir.rs
index 6b78cd473be..a04683e1b22 100644
--- a/src/librustc/ich/impls_hir.rs
+++ b/src/librustc/ich/impls_hir.rs
@@ -287,7 +287,8 @@ impl_stable_hash_for!(enum hir::Ty_ {
     TyTup(ts),
     TyPath(qpath),
     TyTraitObject(trait_refs, lifetime),
-    TyImplTrait(bounds),
+    TyImplTraitExistential(bounds),
+    TyImplTraitUniversal(def_id, bounds),
     TyTypeof(body_id),
     TyErr,
     TyInfer
diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs
index ffd06ee8a2e..8c299612064 100644
--- a/src/librustc/middle/resolve_lifetime.rs
+++ b/src/librustc/middle/resolve_lifetime.rs
@@ -1604,6 +1604,17 @@ fn insert_late_bound_lifetimes(map: &mut NamedRegionMap,
     walk_list!(&mut appears_in_where_clause,
                visit_where_predicate,
                &generics.where_clause.predicates);
+    // We need to collect argument impl Trait lifetimes as well,
+    // we do so here.
+    walk_list!(&mut appears_in_where_clause,
+               visit_ty,
+               decl.inputs.iter().filter(|ty| {
+                   if let hir::TyImplTraitUniversal(..) = ty.node {
+                       true
+                   } else {
+                       false
+                   }
+               }));
     for lifetime_def in &generics.lifetimes {
         if !lifetime_def.bounds.is_empty() {
             // `'a: 'b` means both `'a` and `'b` are referenced
@@ -1698,7 +1709,7 @@ fn insert_late_bound_lifetimes(map: &mut NamedRegionMap,
         }
 
         fn visit_ty(&mut self, ty: &hir::Ty) {
-            if let hir::TyImplTrait(_) = ty.node {
+            if let hir::TyImplTraitExistential(_) = ty.node {
                 self.impl_trait = true;
             }
             intravisit::walk_ty(self, ty);
diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs
index d5eee14bf50..8c40f303b93 100644
--- a/src/librustc_metadata/encoder.rs
+++ b/src/librustc_metadata/encoder.rs
@@ -1487,7 +1487,7 @@ impl<'a, 'b, 'tcx> IndexBuilder<'a, 'b, 'tcx> {
 
     fn encode_info_for_ty(&mut self, ty: &hir::Ty) {
         match ty.node {
-            hir::TyImplTrait(_) => {
+            hir::TyImplTraitExistential(_) => {
                 let def_id = self.tcx.hir.local_def_id(ty.id);
                 self.record(def_id, IsolatedEncoder::encode_info_for_anon_ty, def_id);
             }
diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs
index 630260feed7..74d92ce1c3e 100644
--- a/src/librustc_privacy/lib.rs
+++ b/src/librustc_privacy/lib.rs
@@ -373,7 +373,7 @@ impl<'a, 'tcx> Visitor<'tcx> for EmbargoVisitor<'a, 'tcx> {
     }
 
     fn visit_ty(&mut self, ty: &'tcx hir::Ty) {
-        if let hir::TyImplTrait(..) = ty.node {
+        if let hir::TyImplTraitExistential(..) = ty.node {
             if self.get(ty.id).is_some() {
                 // Reach the (potentially private) type and the API being exposed.
                 self.reach(ty.id).ty().predicates();
@@ -1557,7 +1557,7 @@ impl<'a, 'tcx> Visitor<'tcx> for PrivateItemsInPublicInterfacesVisitor<'a, 'tcx>
     }
 
     fn visit_ty(&mut self, ty: &'tcx hir::Ty) {
-        if let hir::TyImplTrait(..) = ty.node {
+        if let hir::TyImplTraitExistential(..) = ty.node {
             // Check the traits being exposed, as they're separate,
             // e.g. `impl Iterator<Item=T>` has two predicates,
             // `X: Iterator` and `<X as Iterator>::Item == T`,
diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs
index 95b19616e5e..7aaf65e1fd0 100644
--- a/src/librustc_typeck/astconv.rs
+++ b/src/librustc_typeck/astconv.rs
@@ -30,6 +30,7 @@ use util::nodemap::FxHashSet;
 
 use std::iter;
 use syntax::{abi, ast};
+use syntax::symbol::Symbol;
 use syntax::feature_gate::{GateIssue, emit_feature_err};
 use syntax_pos::Span;
 
@@ -1033,53 +1034,16 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
             hir::TyTraitObject(ref bounds, ref lifetime) => {
                 self.conv_object_ty_poly_trait_ref(ast_ty.span, bounds, lifetime)
             }
-            hir::TyImplTrait(_) => {
-                // Figure out if we can allow an `impl Trait` here, by walking up
-                // to a `fn` or inherent `impl` method, going only through `Ty`
-                // or `TraitRef` nodes (as nothing else should be in types) and
-                // ensuring that we reach the `fn`/method signature's return type.
-                let mut node_id = ast_ty.id;
-                let fn_decl = loop {
-                    let parent = tcx.hir.get_parent_node(node_id);
-                    match tcx.hir.get(parent) {
-                        hir::map::NodeItem(&hir::Item {
-                            node: hir::ItemFn(ref fn_decl, ..), ..
-                        }) => break Some(fn_decl),
-
-                        hir::map::NodeImplItem(&hir::ImplItem {
-                            node: hir::ImplItemKind::Method(ref sig, _), ..
-                        }) => {
-                            match tcx.hir.expect_item(tcx.hir.get_parent(parent)).node {
-                                hir::ItemImpl(.., None, _, _) => {
-                                    break Some(&sig.decl)
-                                }
-                                _ => break None
-                            }
-                        }
-
-                        hir::map::NodeTy(_) | hir::map::NodeTraitRef(_) => {}
-
-                        _ => break None
-                    }
-                    node_id = parent;
-                };
-                let allow = fn_decl.map_or(false, |fd| {
-                    match fd.output {
-                        hir::DefaultReturn(_) => false,
-                        hir::Return(ref ty) => ty.id == node_id
-                    }
-                });
-
-                // Create the anonymized type.
-                if allow {
-                    let def_id = tcx.hir.local_def_id(ast_ty.id);
-                    tcx.mk_anon(def_id, Substs::identity_for_item(tcx, def_id))
-                } else {
-                    span_err!(tcx.sess, ast_ty.span, E0562,
-                              "`impl Trait` not allowed outside of function \
-                               and inherent method return types");
-                    tcx.types.err
-                }
+            hir::TyImplTraitExistential(_) => {
+                let def_id = tcx.hir.local_def_id(ast_ty.id);
+                tcx.mk_anon(def_id, Substs::identity_for_item(tcx, def_id))
+            }
+            hir::TyImplTraitUniversal(fn_def_id, _) => {
+                let impl_trait_def_id = tcx.hir.local_def_id(ast_ty.id);
+                let generics = tcx.generics_of(fn_def_id);
+                let index = generics.type_param_to_index[&impl_trait_def_id.index];
+                tcx.mk_param(index,
+                             Symbol::intern(&tcx.hir.node_to_pretty_string(ast_ty.id)))
             }
             hir::TyPath(hir::QPath::Resolved(ref maybe_qself, ref path)) => {
                 debug!("ast_ty_to_ty: maybe_qself={:?} path={:?}", maybe_qself, path);
diff --git a/src/librustc_typeck/check/compare_method.rs b/src/librustc_typeck/check/compare_method.rs
index 2c44c40d83d..139449e5ab0 100644
--- a/src/librustc_typeck/check/compare_method.rs
+++ b/src/librustc_typeck/check/compare_method.rs
@@ -67,6 +67,14 @@ pub fn compare_impl_method<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
         return;
     }
 
+    if let Err(ErrorReported) = compare_synthetic_generics(tcx,
+                                                           impl_m,
+                                                           impl_m_span,
+                                                           trait_m,
+                                                           trait_item_span) {
+        return;
+    }
+
     if let Err(ErrorReported) = compare_predicate_entailment(tcx,
                                                              impl_m,
                                                              impl_m_span,
@@ -708,6 +716,45 @@ fn compare_number_of_method_arguments<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     Ok(())
 }
 
+fn compare_synthetic_generics<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+                                        impl_m: &ty::AssociatedItem,
+                                        _impl_m_span: Span, // FIXME necessary?
+                                        trait_m: &ty::AssociatedItem,
+                                        _trait_item_span: Option<Span>) // FIXME necessary?
+                                        -> Result<(), ErrorReported> {
+    // FIXME(chrisvittal) Clean up this function, list of FIXME items:
+    //     1. Better messages for the span lables
+    //     2. Explanation as to what is going on
+    //     3. Correct the function signature for what we actually use
+    // If we get here, we already have the same number of generics, so the zip will
+    // be okay.
+    let mut error_found = false;
+    let impl_m_generics = tcx.generics_of(impl_m.def_id);
+    let trait_m_generics = tcx.generics_of(trait_m.def_id);
+    for (impl_ty, trait_ty) in impl_m_generics.types.iter().zip(trait_m_generics.types.iter()) {
+        if impl_ty.synthetic != trait_ty.synthetic {
+            let impl_node_id = tcx.hir.as_local_node_id(impl_ty.def_id).unwrap();
+            let impl_span = tcx.hir.span(impl_node_id);
+            let trait_node_id = tcx.hir.as_local_node_id(trait_ty.def_id).unwrap();
+            let trait_span = tcx.hir.span(trait_node_id);
+            let mut err = struct_span_err!(tcx.sess,
+                                           impl_span,
+                                           E0643,
+                                           "method `{}` has incompatible signature for trait",
+                                           trait_m.name);
+            err.span_label(trait_span, "annotation in trait");
+            err.span_label(impl_span, "annotation in impl");
+            err.emit();
+            error_found = true;
+        }
+    }
+    if error_found {
+        Err(ErrorReported)
+    } else {
+        Ok(())
+    }
+}
+
 pub fn compare_const_impl<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                     impl_c: &ty::AssociatedItem,
                                     impl_c_span: Span,
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index 82d59ecfc92..4cc1e83d6e3 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -5035,6 +5035,10 @@ pub fn check_bounds_are_used<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
         if let ty::TyParam(ParamTy {idx, ..}) = leaf_ty.sty {
             debug!("Found use of ty param num {}", idx);
             tps_used[idx as usize - generics.lifetimes.len()] = true;
+        } else if let ty::TyError = leaf_ty.sty {
+            // If there already another error, do not emit an error for not using a type Parameter
+            assert!(tcx.sess.err_count() > 0);
+            return;
         }
     }
 
diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs
index 81447097428..b5fbbeb1692 100644
--- a/src/librustc_typeck/collect.rs
+++ b/src/librustc_typeck/collect.rs
@@ -43,6 +43,7 @@ use rustc_const_math::ConstInt;
 use std::collections::BTreeMap;
 
 use syntax::{abi, ast};
+use syntax::ptr::P;
 use syntax::codemap::Spanned;
 use syntax::symbol::{Symbol, keywords};
 use syntax_pos::{Span, DUMMY_SP};
@@ -130,7 +131,7 @@ impl<'a, 'tcx> Visitor<'tcx> for CollectItemTypesVisitor<'a, 'tcx> {
     }
 
     fn visit_ty(&mut self, ty: &'tcx hir::Ty) {
-        if let hir::TyImplTrait(..) = ty.node {
+        if let hir::TyImplTraitExistential(..) = ty.node {
             let def_id = self.tcx.hir.local_def_id(ty.id);
             self.tcx.generics_of(def_id);
             self.tcx.predicates_of(def_id);
@@ -854,7 +855,7 @@ fn generics_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
         NodeExpr(&hir::Expr { node: hir::ExprClosure(..), .. }) => {
             Some(tcx.closure_base_def_id(def_id))
         }
-        NodeTy(&hir::Ty { node: hir::TyImplTrait(..), .. }) => {
+        NodeTy(&hir::Ty { node: hir::TyImplTraitExistential(..), .. }) => {
             let mut parent_id = node_id;
             loop {
                 match tcx.hir.get(parent_id) {
@@ -873,22 +874,32 @@ fn generics_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     let mut allow_defaults = false;
 
     let no_generics = hir::Generics::empty();
-    let ast_generics = match node {
-        NodeTraitItem(item) => &item.generics,
+    let (ast_generics, opt_inputs) = match node {
+        NodeTraitItem(item) => {
+            match item.node {
+                TraitItemKind::Method(ref sig, _) => (&item.generics, Some(&sig.decl.inputs)),
+                _ => (&item.generics, None)
+            }
+        }
 
-        NodeImplItem(item) => &item.generics,
+        NodeImplItem(item) => {
+            match item.node {
+                ImplItemKind::Method(ref sig, _) => (&item.generics, Some(&sig.decl.inputs)),
+                _ => (&item.generics, None)
+            }
+        }
 
         NodeItem(item) => {
             match item.node {
-                ItemFn(.., ref generics, _) |
-                ItemImpl(_, _, _, ref generics, ..) => generics,
+                ItemFn(ref decl, .., ref generics, _) => (generics, Some(&decl.inputs)),
+                ItemImpl(_, _, _, ref generics, ..) => (generics, None),
 
                 ItemTy(_, ref generics) |
                 ItemEnum(_, ref generics) |
                 ItemStruct(_, ref generics) |
                 ItemUnion(_, ref generics) => {
                     allow_defaults = true;
-                    generics
+                    (generics, None)
                 }
 
                 ItemTrait(_, _, ref generics, ..) => {
@@ -909,22 +920,22 @@ fn generics_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                     });
 
                     allow_defaults = true;
-                    generics
+                    (generics, None)
                 }
 
-                _ => &no_generics
+                _ => (&no_generics, None)
             }
         }
 
         NodeForeignItem(item) => {
             match item.node {
-                ForeignItemStatic(..) => &no_generics,
-                ForeignItemFn(_, _, ref generics) => generics,
-                ForeignItemType => &no_generics,
+                ForeignItemStatic(..) => (&no_generics, None),
+                ForeignItemFn(ref decl, _, ref generics) => (generics, Some(&decl.inputs)),
+                ForeignItemType => (&no_generics, None)
             }
         }
 
-        _ => &no_generics
+        _ => (&no_generics, None)
     };
 
     let has_self = opt_self.is_some();
@@ -981,7 +992,24 @@ fn generics_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
             synthetic: p.synthetic,
         }
     });
-    let mut types: Vec<_> = opt_self.into_iter().chain(types).collect();
+
+    let fn_ins = opt_inputs.map(|tys| &tys[..]);
+    let univ_impl_trait_info = extract_universal_impl_trait_info(tcx, fn_ins);
+    let other_type_start = type_start + ast_generics.ty_params.len() as u32;
+    let mut types: Vec<_> = opt_self.into_iter()
+        .chain(types)
+        .chain(univ_impl_trait_info.iter().enumerate().map(|(i, info)| {
+            ty::TypeParameterDef {
+                index: other_type_start + i as u32,
+                name: Symbol::intern(&tcx.hir.node_to_pretty_string(info.id)),
+                def_id: info.def_id,
+                has_default: false,
+                object_lifetime_default: rl::Set1::Empty,
+                pure_wrt_drop: false,
+                synthetic: Some(SyntheticTyParamKind::ImplTrait),
+            }
+        }))
+        .collect();
 
     // provide junk type parameter defs - the only place that
     // cares about anything but the length is instantiation,
@@ -1155,7 +1183,7 @@ fn type_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
             icx.to_ty(ty)
         }
 
-        NodeTy(&hir::Ty { node: TyImplTrait(..), .. }) => {
+        NodeTy(&hir::Ty { node: TyImplTraitExistential(..), .. }) => {
             let owner = tcx.hir.get_parent_did(node_id);
             let hir_id = tcx.hir.node_to_hir_id(node_id);
             tcx.typeck_tables_of(owner).node_id_to_type(hir_id)
@@ -1337,20 +1365,31 @@ fn explicit_predicates_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
 
     let icx = ItemCtxt::new(tcx, def_id);
     let no_generics = hir::Generics::empty();
-    let ast_generics = match node {
-        NodeTraitItem(item) => &item.generics,
+    let (ast_generics, opt_inputs) = match node {
+        NodeTraitItem(item) => {
+            match item.node {
+                TraitItemKind::Method(ref sig, _) => (&item.generics, Some(&sig.decl.inputs)),
+                _ => (&item.generics, None)
+            }
+        }
 
-        NodeImplItem(item) => &item.generics,
+        NodeImplItem(item) => {
+            match item.node {
+                ImplItemKind::Method(ref sig, _) => (&item.generics, Some(&sig.decl.inputs)),
+                _ => (&item.generics, None)
+            }
+        }
 
         NodeItem(item) => {
             match item.node {
-                ItemFn(.., ref generics, _) |
+                ItemFn(ref decl, .., ref generics, _) => (generics, Some(&decl.inputs)),
+
                 ItemImpl(_, _, _, ref generics, ..) |
                 ItemTy(_, ref generics) |
                 ItemEnum(_, ref generics) |
                 ItemStruct(_, ref generics) |
                 ItemUnion(_, ref generics) => {
-                    generics
+                    (generics, None)
                 }
 
                 ItemTrait(_, _, ref generics, .., ref items) => {
@@ -1358,22 +1397,22 @@ fn explicit_predicates_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                         def_id,
                         substs: Substs::identity_for_item(tcx, def_id)
                     }, items));
-                    generics
+                    (generics, None)
                 }
 
-                _ => &no_generics
+                _ => (&no_generics, None)
             }
         }
 
         NodeForeignItem(item) => {
             match item.node {
-                ForeignItemStatic(..) => &no_generics,
-                ForeignItemFn(_, _, ref generics) => generics,
-                ForeignItemType => &no_generics,
+                ForeignItemStatic(..) => (&no_generics, None),
+                ForeignItemFn(ref decl, _, ref generics) => (generics, Some(&decl.inputs)),
+                ForeignItemType => (&no_generics, None),
             }
         }
 
-        NodeTy(&Ty { node: TyImplTrait(ref bounds), span, .. }) => {
+        NodeTy(&Ty { node: TyImplTraitExistential(ref bounds), span, .. }) => {
             let substs = Substs::identity_for_item(tcx, def_id);
             let anon_ty = tcx.mk_anon(def_id, substs);
 
@@ -1387,7 +1426,7 @@ fn explicit_predicates_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
             };
         }
 
-        _ => &no_generics
+        _ => (&no_generics, None)
     };
 
     let generics = tcx.generics_of(def_id);
@@ -1518,6 +1557,19 @@ fn explicit_predicates_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
         }))
     }
 
+    // Add predicates from impl Trait arguments
+    let fn_ins = opt_inputs.map(|tys| &tys[..]);
+    let univ_impl_trait_info = extract_universal_impl_trait_info(tcx, fn_ins);
+    for info in univ_impl_trait_info.iter() {
+        let name = keywords::Invalid.name();
+        let param_ty = ty::ParamTy::new(index, name).to_ty(tcx);
+        index += 1;
+        let bounds = compute_bounds(&icx, param_ty, info.bounds,
+                                    SizedByDefault::Yes,
+                                    info.span);
+        predicates.extend(bounds.predicates(tcx, param_ty));
+    }
+
     // Subtle: before we store the predicates into the tcx, we
     // sort them so that predicates like `T: Foo<Item=U>` come
     // before uses of `U`.  This avoids false ambiguity errors
@@ -1678,3 +1730,54 @@ fn is_auto_impl<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
         _ => bug!("is_auto_impl applied to non-local def-id {:?}", def_id)
     }
 }
+
+struct ImplTraitUniversalInfo<'hir> {
+    id: ast::NodeId,
+    def_id: DefId,
+    span: Span,
+    bounds: &'hir [hir::TyParamBound],
+}
+
+/// Take some possible list of arguments and return the DefIds of the ImplTraitUniversal
+/// arguments
+fn extract_universal_impl_trait_info<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+                                               opt_inputs: Option<&'tcx [P<hir::Ty>]>)
+                                               -> Vec<ImplTraitUniversalInfo<'tcx>>
+{
+    // A visitor for simply collecting Universally quantified impl Trait arguments
+    struct ImplTraitUniversalVisitor<'tcx> {
+        items: Vec<&'tcx hir::Ty>
+    }
+
+    impl<'tcx> Visitor<'tcx> for ImplTraitUniversalVisitor<'tcx> {
+        fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
+            NestedVisitorMap::None
+        }
+
+        fn visit_ty(&mut self, ty: &'tcx hir::Ty) {
+            if let hir::TyImplTraitUniversal(..) = ty.node {
+                self.items.push(ty);
+            }
+            intravisit::walk_ty(self, ty);
+        }
+    }
+
+    let mut visitor = ImplTraitUniversalVisitor { items: Vec::new() };
+
+    if let Some(inputs) = opt_inputs {
+        for t in inputs.iter() {
+            visitor.visit_ty(t);
+        }
+    }
+
+    visitor.items.into_iter().map(|ty| if let hir::TyImplTraitUniversal(_, ref bounds) = ty.node {
+        ImplTraitUniversalInfo {
+            id: ty.id,
+            def_id: tcx.hir.local_def_id(ty.id),
+            span: ty.span,
+            bounds: bounds
+        }
+    } else {
+        span_bug!(ty.span, "this type should be a universally quantified impl trait. this is a bug")
+    }).collect()
+}
diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs
index 73bec697d49..328b7f9fdef 100644
--- a/src/librustc_typeck/diagnostics.rs
+++ b/src/librustc_typeck/diagnostics.rs
@@ -3818,46 +3818,6 @@ let s = Simba { mother: 1, father: 0 }; // ok!
 ```
 "##,
 
-E0562: r##"
-Abstract return types (written `impl Trait` for some trait `Trait`) are only
-allowed as function return types.
-
-Erroneous code example:
-
-```compile_fail,E0562
-#![feature(conservative_impl_trait)]
-
-fn main() {
-    let count_to_ten: impl Iterator<Item=usize> = 0..10;
-    // error: `impl Trait` not allowed outside of function and inherent method
-    //        return types
-    for i in count_to_ten {
-        println!("{}", i);
-    }
-}
-```
-
-Make sure `impl Trait` only appears in return-type position.
-
-```
-#![feature(conservative_impl_trait)]
-
-fn count_to_n(n: usize) -> impl Iterator<Item=usize> {
-    0..n
-}
-
-fn main() {
-    for i in count_to_n(10) {  // ok!
-        println!("{}", i);
-    }
-}
-```
-
-See [RFC 1522] for more details.
-
-[RFC 1522]: https://github.com/rust-lang/rfcs/blob/master/text/1522-conservative-impl-trait.md
-"##,
-
 E0569: r##"
 If an impl has a generic parameter with the `#[may_dangle]` attribute, then
 that impl must be declared as an `unsafe impl.
@@ -4665,6 +4625,22 @@ It is recommended that you look for a `new` function or equivalent in the
 crate's documentation.
 "##,
 
+E0643: r##"
+This error indicates that there is a mismatch between generic parameters and
+impl Trait parameters in a trait declaration versus its impl.
+
+```compile_fail,E0643
+#![feature(universal_impl_trait)]
+trait Foo {
+    fn foo(&self, _: &impl Iterator);
+}
+impl Foo for () {
+    fn foo<U: Iterator>(&self, _: &U) { } // error method `foo` has incompatible
+                                          // signature for trait
+}
+```
+"##,
+
 }
 
 register_diagnostics! {
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index 4b60536e1d1..1d107c169b0 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -1960,7 +1960,9 @@ impl Clean<Type> for hir::Ty {
                 }
             }
             TyBareFn(ref barefn) => BareFunction(box barefn.clean(cx)),
-            TyImplTrait(ref bounds) => ImplTrait(bounds.clean(cx)),
+            TyImplTraitExistential(ref bounds) |
+                TyImplTraitUniversal(_, ref bounds) =>
+                    ImplTrait(bounds.clean(cx)),
             TyInfer | TyErr => Infer,
             TyTypeof(..) => panic!("Unimplemented type {:?}", self.node),
         }
diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs
index b6cb3ac1308..97eec3a21e9 100644
--- a/src/libsyntax/feature_gate.rs
+++ b/src/libsyntax/feature_gate.rs
@@ -275,6 +275,9 @@ declare_features! (
     // Allows `impl Trait` in function return types.
     (active, conservative_impl_trait, "1.12.0", Some(34511)),
 
+    // Allows `impl Trait` in function arguments.
+    (active, universal_impl_trait, "1.23.0", Some(34511)),
+
     // The `!` type
     (active, never_type, "1.13.0", Some(35121)),
 
@@ -1451,10 +1454,6 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
             ast::TyKind::BareFn(ref bare_fn_ty) => {
                 self.check_abi(bare_fn_ty.abi, ty.span);
             }
-            ast::TyKind::ImplTrait(..) => {
-                gate_feature_post!(&self, conservative_impl_trait, ty.span,
-                                   "`impl Trait` is experimental");
-            }
             ast::TyKind::Never => {
                 gate_feature_post!(&self, never_type, ty.span,
                                    "The `!` type is experimental");
diff --git a/src/test/compile-fail/impl-trait/disallowed.rs b/src/test/compile-fail/impl-trait/disallowed.rs
deleted file mode 100644
index 0467c49b031..00000000000
--- a/src/test/compile-fail/impl-trait/disallowed.rs
+++ /dev/null
@@ -1,61 +0,0 @@
-// Copyright 2016 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(conservative_impl_trait)]
-
-fn arguments(_: impl Fn(),
-//~^ ERROR `impl Trait` not allowed outside of function and inherent method return types
-             _: Vec<impl Clone>) {}
-//~^ ERROR `impl Trait` not allowed outside of function and inherent method return types
-
-type Factory<R> = impl Fn() -> R;
-//~^ ERROR `impl Trait` not allowed outside of function and inherent method return types
-
-type GlobalFactory<R> = fn() -> impl FnOnce() -> R;
-//~^ ERROR `impl Trait` not allowed outside of function and inherent method return types
-
-trait LazyToString {
-    fn lazy_to_string<'a>(&'a self) -> impl Fn() -> String;
-    //~^ ERROR `impl Trait` not allowed outside of function and inherent method return types
-}
-
-impl LazyToString for String {
-    fn lazy_to_string<'a>(&'a self) -> impl Fn() -> String {
-    //~^ ERROR `impl Trait` not allowed outside of function and inherent method return types
-        || self.clone()
-    }
-}
-
-#[derive(Copy, Clone)]
-struct Lazy<T>(T);
-
-impl std::ops::Add<Lazy<i32>> for Lazy<i32> {
-    type Output = impl Fn() -> Lazy<i32>;
-    //~^ ERROR `impl Trait` not allowed outside of function and inherent method return types
-
-    fn add(self, other: Lazy<i32>) -> Self::Output {
-        move || Lazy(self.0 + other.0)
-    }
-}
-
-impl<F> std::ops::Add<F>
-for impl Fn() -> Lazy<i32>
-//~^ ERROR `impl Trait` not allowed outside of function and inherent method return types
-where F: Fn() -> impl FnOnce() -> i32
-//~^ ERROR `impl Trait` not allowed outside of function and inherent method return types
-{
-    type Output = Self;
-
-    fn add(self, other: F) -> Self::Output {
-        move || Lazy(self().0 + other()())
-    }
-}
-
-fn main() {}
diff --git a/src/test/compile-fail/impl-trait/feature-gate-universal.rs b/src/test/compile-fail/impl-trait/feature-gate-universal.rs
new file mode 100644
index 00000000000..e5bdf3a42eb
--- /dev/null
+++ b/src/test/compile-fail/impl-trait/feature-gate-universal.rs
@@ -0,0 +1,16 @@
+// 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-universal_impl_trait
+
+fn foo(x: impl std::fmt::Debug) { print!("{:?}", x); }
+//~^ ERROR `impl Trait` in argument position is experimental
+
+fn main() {}
diff --git a/src/test/compile-fail/impl-trait/feature-gate.rs b/src/test/compile-fail/impl-trait/feature-gate.rs
index f171b6becc4..d46a16450db 100644
--- a/src/test/compile-fail/impl-trait/feature-gate.rs
+++ b/src/test/compile-fail/impl-trait/feature-gate.rs
@@ -11,6 +11,6 @@
 // gate-test-conservative_impl_trait
 
 fn foo() -> impl Fn() { || {} }
-//~^ ERROR `impl Trait` is experimental
+//~^ ERROR `impl Trait` in return position is experimental
 
 fn main() {}
diff --git a/src/test/compile-fail/impl-trait/impl-generic-mismatch-ab.rs b/src/test/compile-fail/impl-trait/impl-generic-mismatch-ab.rs
new file mode 100644
index 00000000000..43b47e9e915
--- /dev/null
+++ b/src/test/compile-fail/impl-trait/impl-generic-mismatch-ab.rs
@@ -0,0 +1,23 @@
+// 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(universal_impl_trait)]
+use std::fmt::Debug;
+
+trait Foo {
+    fn foo<A: Debug>(&self, a: &A, b: &impl Debug);
+}
+
+impl Foo for () {
+    fn foo<B: Debug>(&self, a: &impl Debug, b: &B) { }
+    //~^ ERROR method `foo` has an incompatible type for trait
+}
+
+fn main() {}
diff --git a/src/test/compile-fail/impl-trait/impl-generic-mismatch.rs b/src/test/compile-fail/impl-trait/impl-generic-mismatch.rs
new file mode 100644
index 00000000000..a95da61aa4c
--- /dev/null
+++ b/src/test/compile-fail/impl-trait/impl-generic-mismatch.rs
@@ -0,0 +1,32 @@
+// 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(universal_impl_trait)]
+use std::fmt::Debug;
+
+trait Foo {
+    fn foo(&self, _: &impl Debug);
+}
+
+impl Foo for () {
+    fn foo<U: Debug>(&self, _: &U) { }
+    //~^ Error method `foo` has incompatible signature for trait
+}
+
+trait Bar {
+    fn bar<U: Debug>(&self, _: &U);
+}
+
+impl Bar for () {
+    fn bar(&self, _: &impl Debug) { }
+    //~^ Error method `bar` has incompatible signature for trait
+}
+
+fn main() {}
diff --git a/src/test/compile-fail/impl-trait/where-allowed.rs b/src/test/compile-fail/impl-trait/where-allowed.rs
new file mode 100644
index 00000000000..af83a2d0a23
--- /dev/null
+++ b/src/test/compile-fail/impl-trait/where-allowed.rs
@@ -0,0 +1,234 @@
+// 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.
+
+//! A simple test for testing many permutations of allowedness of
+//! impl Trait
+#![feature(conservative_impl_trait, universal_impl_trait, dyn_trait)]
+use std::fmt::Debug;
+
+// Allowed
+fn in_parameters(_: impl Debug) { panic!() }
+
+// Allowed
+fn in_return() -> impl Debug { panic!() }
+
+// Allowed
+fn in_adt_in_parameters(_: Vec<impl Debug>) { panic!() }
+
+// Allowed
+fn in_adt_in_return() -> Vec<impl Debug> { panic!() }
+
+// Disallowed
+fn in_fn_parameter_in_parameters(_: fn(impl Debug)) { panic!() }
+//~^ ERROR `impl Trait` not allowed outside of function and inherent method return types
+
+// Disallowed
+fn in_fn_return_in_parameters(_: fn() -> impl Debug) { panic!() }
+//~^ ERROR `impl Trait` not allowed outside of function and inherent method return types
+
+// Disallowed
+fn in_fn_parameter_in_return() -> fn(impl Debug) { panic!() }
+//~^ ERROR `impl Trait` not allowed outside of function and inherent method return types
+
+// Disallowed
+fn in_fn_return_in_return() -> fn() -> impl Debug { panic!() }
+//~^ ERROR `impl Trait` not allowed outside of function and inherent method return types
+
+// Disallowed
+fn in_dyn_Fn_parameter_in_parameters(_: &dyn Fn(impl Debug)) { panic!() }
+//~^ ERROR `impl Trait` not allowed outside of function and inherent method return types
+
+// Disallowed
+fn in_dyn_Fn_return_in_parameters(_: &dyn Fn() -> impl Debug) { panic!() }
+//~^ ERROR `impl Trait` not allowed outside of function and inherent method return types
+
+// Disallowed
+fn in_dyn_Fn_parameter_in_return() -> &'static dyn Fn(impl Debug) { panic!() }
+//~^ ERROR `impl Trait` not allowed outside of function and inherent method return types
+
+// Disallowed
+fn in_dyn_Fn_return_in_return() -> &'static dyn Fn() -> impl Debug { panic!() }
+//~^ ERROR `impl Trait` not allowed outside of function and inherent method return types
+
+// Disallowed
+fn in_impl_Fn_parameter_in_parameters(_: &impl Fn(impl Debug)) { panic!() }
+//~^ ERROR `impl Trait` not allowed outside of function and inherent method return types
+
+// Disallowed
+fn in_impl_Fn_return_in_parameters(_: &impl Fn() -> impl Debug) { panic!() }
+//~^ ERROR `impl Trait` not allowed outside of function and inherent method return types
+
+// Disallowed
+fn in_impl_Fn_parameter_in_return() -> &'static impl Fn(impl Debug) { panic!() }
+//~^ ERROR `impl Trait` not allowed outside of function and inherent method return types
+
+// Disallowed
+fn in_impl_Fn_return_in_return() -> &'static impl Fn() -> impl Debug { panic!() }
+//~^ ERROR `impl Trait` not allowed outside of function and inherent method return types
+
+// Disallowed
+fn in_Fn_parameter_in_generics<F: Fn(impl Debug)> (_: F) { panic!() }
+//~^ ERROR `impl Trait` not allowed outside of function and inherent method return types
+
+// Disallowed
+fn in_Fn_return_in_generics<F: Fn() -> impl Debug> (_: F) { panic!() }
+//~^ ERROR `impl Trait` not allowed outside of function and inherent method return types
+
+
+// Allowed
+fn in_impl_Trait_in_parameters(_: impl Iterator<Item = impl Iterator>) { panic!() }
+
+// Allowed
+fn in_impl_Trait_in_return() -> impl IntoIterator<Item = impl IntoIterator> {
+    vec![vec![0; 10], vec![12; 7], vec![8; 3]]
+}
+
+// Disallowed
+struct InBraceStructField { x: impl Debug }
+//~^ ERROR `impl Trait` not allowed outside of function and inherent method return types
+
+// Disallowed
+struct InAdtInBraceStructField { x: Vec<impl Debug> }
+//~^ ERROR `impl Trait` not allowed outside of function and inherent method return types
+
+// Disallowed
+struct InTupleStructField(impl Debug);
+//~^ ERROR `impl Trait` not allowed outside of function and inherent method return types
+
+// Disallowed
+enum InEnum {
+    InBraceVariant { x: impl Debug },
+    //~^ ERROR `impl Trait` not allowed outside of function and inherent method return types
+    InTupleVariant(impl Debug),
+    //~^ ERROR `impl Trait` not allowed outside of function and inherent method return types
+}
+
+// Allowed
+trait InTraitDefnParameters {
+    fn in_parameters(_: impl Debug);
+}
+
+// Disallowed
+trait InTraitDefnReturn {
+    fn in_return() -> impl Debug;
+    //~^ ERROR `impl Trait` not allowed outside of function and inherent method return types
+}
+
+// Allowed and disallowed in trait impls
+trait DummyTrait {
+    type Out;
+    fn in_trait_impl_parameter(impl Debug);
+    fn in_trait_impl_return() -> Self::Out;
+}
+impl DummyTrait for () {
+    type Out = impl Debug;
+    //~^ ERROR `impl Trait` not allowed outside of function and inherent method return types
+
+    fn in_trait_impl_parameter(_: impl Debug) { }
+    // Allowed
+
+    fn in_trait_impl_return() -> impl Debug { () }
+    //~^ ERROR `impl Trait` not allowed outside of function and inherent method return types
+}
+
+// Allowed
+struct DummyType;
+impl DummyType {
+    fn in_inherent_impl_parameters(_: impl Debug) { }
+    fn in_inherent_impl_return() -> impl Debug { () }
+}
+
+// Disallowed
+extern "C" {
+    fn in_foreign_parameters(_: impl Debug);
+    //~^ ERROR `impl Trait` not allowed outside of function and inherent method return types
+
+    fn in_foreign_return() -> impl Debug;
+    //~^ ERROR `impl Trait` not allowed outside of function and inherent method return types
+}
+
+// Allowed
+extern "C" fn in_extern_fn_parameters(_: impl Debug) {
+}
+
+// Allowed
+extern "C" fn in_extern_fn_return() -> impl Debug {
+    22
+}
+
+type InTypeAlias<R> = impl Debug;
+//~^ ERROR `impl Trait` not allowed outside of function and inherent method return types
+
+type InReturnInTypeAlias<R> = fn() -> impl Debug;
+//~^ ERROR `impl Trait` not allowed outside of function and inherent method return types
+
+// Disallowed in impl headers
+impl PartialEq<impl Debug> for () {
+    //~^ ERROR `impl Trait` not allowed outside of function and inherent method return types
+}
+
+// Disallowed in impl headers
+impl PartialEq<()> for impl Debug {
+    //~^ ERROR `impl Trait` not allowed outside of function and inherent method return types
+}
+
+// Disallowed in inherent impls
+impl impl Debug {
+    //~^ ERROR `impl Trait` not allowed outside of function and inherent method return types
+}
+
+// Disallowed in inherent impls
+struct InInherentImplAdt<T> { t: T }
+impl InInherentImplAdt<impl Debug> {
+    //~^ ERROR `impl Trait` not allowed outside of function and inherent method return types
+}
+
+// Disallowed in where clauses
+fn in_fn_where_clause()
+    where impl Debug: Debug
+//~^ ERROR `impl Trait` not allowed outside of function and inherent method return types
+{
+}
+
+// Disallowed in where clauses
+fn in_adt_in_fn_where_clause()
+    where Vec<impl Debug>: Debug
+//~^ ERROR `impl Trait` not allowed outside of function and inherent method return types
+{
+}
+
+// Disallowed
+fn in_trait_parameter_in_fn_where_clause<T>()
+    where T: PartialEq<impl Debug>
+//~^ ERROR `impl Trait` not allowed outside of function and inherent method return types
+{
+}
+
+// Disallowed
+fn in_Fn_parameter_in_fn_where_clause<T>()
+    where T: Fn(impl Debug)
+//~^ ERROR `impl Trait` not allowed outside of function and inherent method return types
+{
+}
+
+// Disallowed
+fn in_Fn_return_in_fn_where_clause<T>()
+    where T: Fn() -> impl Debug
+//~^ ERROR `impl Trait` not allowed outside of function and inherent method return types
+{
+}
+
+fn main() {
+    let _in_local_variable: impl Fn() = || {};
+    //~^ ERROR `impl Trait` not allowed outside of function and inherent method return types
+    let _in_return_in_local_variable = || -> impl Fn() { || {} };
+    //~^ ERROR `impl Trait` not allowed outside of function and inherent method return types
+}
+
diff --git a/src/test/run-pass/impl-trait/auxiliary/xcrate.rs b/src/test/run-pass/impl-trait/auxiliary/xcrate.rs
index e9074f8c230..e4f525a9826 100644
--- a/src/test/run-pass/impl-trait/auxiliary/xcrate.rs
+++ b/src/test/run-pass/impl-trait/auxiliary/xcrate.rs
@@ -10,9 +10,10 @@
 
 #![feature(conservative_impl_trait)]
 
-pub fn fourway_add(a: i32) -> impl Fn(i32) -> impl Fn(i32) -> impl Fn(i32) -> i32 {
-    move |b| move |c| move |d| a + b + c + d
-}
+// NOTE commented out due to issue #45994
+//pub fn fourway_add(a: i32) -> impl Fn(i32) -> impl Fn(i32) -> impl Fn(i32) -> i32 {
+//    move |b| move |c| move |d| a + b + c + d
+//}
 
 fn some_internal_fn() -> u32 {
     1
diff --git a/src/test/run-pass/impl-trait/example-calendar.rs b/src/test/run-pass/impl-trait/example-calendar.rs
index 84d86cfdf65..0b612c2d3ff 100644
--- a/src/test/run-pass/impl-trait/example-calendar.rs
+++ b/src/test/run-pass/impl-trait/example-calendar.rs
@@ -1,4 +1,4 @@
-// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// Copyright 2016-2017 The Rust Project Developers. See the COPYRIGHT
 // file at the top-level directory of this distribution and at
 // http://rust-lang.org/COPYRIGHT.
 //
@@ -8,7 +8,12 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#![feature(conservative_impl_trait, fn_traits, step_trait, unboxed_closures)]
+#![feature(conservative_impl_trait,
+           universal_impl_trait,
+           fn_traits,
+           step_trait,
+           unboxed_closures
+)]
 
 //! Derived from: <https://raw.githubusercontent.com/quickfur/dcal/master/dcal.d>.
 //!
@@ -457,9 +462,9 @@ fn test_group_by() {
 ///
 /// Groups an iterator of dates by month.
 ///
-fn by_month<It>(it: It)
-                ->  impl Iterator<Item=(u32, impl Iterator<Item=NaiveDate> + Clone)> + Clone
-where It: Iterator<Item=NaiveDate> + Clone {
+fn by_month(it: impl Iterator<Item=NaiveDate> + Clone)
+           ->  impl Iterator<Item=(u32, impl Iterator<Item=NaiveDate> + Clone)> + Clone
+{
     it.group_by(|d| d.month())
 }
 
@@ -474,9 +479,9 @@ fn test_by_month() {
 ///
 /// Groups an iterator of dates by week.
 ///
-fn by_week<It>(it: It)
-               -> impl Iterator<Item=(u32, impl DateIterator)> + Clone
-where It: DateIterator {
+fn by_week(it: impl DateIterator)
+          -> impl Iterator<Item=(u32, impl DateIterator)> + Clone
+{
     // We go forward one day because `isoweekdate` considers the week to start on a Monday.
     it.group_by(|d| d.succ().isoweekdate().1)
 }
@@ -548,8 +553,7 @@ const COLS_PER_WEEK: u32 = 7 * COLS_PER_DAY;
 ///
 /// Formats an iterator of weeks into an iterator of strings.
 ///
-fn format_weeks<It>(it: It) -> impl Iterator<Item=String>
-where It: Iterator, It::Item: DateIterator {
+fn format_weeks(it: impl Iterator<Item = impl DateIterator>) -> impl Iterator<Item=String> {
     it.map(|week| {
         let mut buf = String::with_capacity((COLS_PER_DAY * COLS_PER_WEEK + 2) as usize);
 
@@ -627,7 +631,7 @@ fn test_month_title() {
 ///
 /// Formats a month.
 ///
-fn format_month<It: DateIterator>(it: It) -> impl Iterator<Item=String> {
+fn format_month(it: impl DateIterator) -> impl Iterator<Item=String> {
     let mut month_days = it.peekable();
     let title = month_title(month_days.peek().unwrap().month());
 
@@ -659,8 +663,9 @@ fn test_format_month() {
 ///
 /// Formats an iterator of months.
 ///
-fn format_months<It>(it: It) -> impl Iterator<Item=impl Iterator<Item=String>>
-where It: Iterator, It::Item: DateIterator {
+fn format_months(it: impl Iterator<Item = impl DateIterator>)
+                -> impl Iterator<Item=impl Iterator<Item=String>>
+{
     it.map(format_month)
 }
 
diff --git a/src/test/compile-fail/impl-trait/disallowed-2.rs b/src/test/run-pass/impl-trait/universal_hrtb_anon.rs
index 46b3106ab8d..48874ef41de 100644
--- a/src/test/compile-fail/impl-trait/disallowed-2.rs
+++ b/src/test/run-pass/impl-trait/universal_hrtb_anon.rs
@@ -1,4 +1,4 @@
-// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// 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.
 //
@@ -8,11 +8,13 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#![feature(conservative_impl_trait)]
+#![feature(universal_impl_trait)]
+
+fn hrtb(f: impl Fn(&u32) -> u32) -> u32 {
+    f(&22) + f(&44)
+}
 
 fn main() {
-    let _: impl Fn() = || {};
-    //~^ ERROR `impl Trait` not allowed outside of function and inherent method return types
-    let _ = || -> impl Fn() { || {} };
-    //~^ ERROR `impl Trait` not allowed outside of function and inherent method return types
+    let sum = hrtb(|x| x * 2);
+    assert_eq!(sum, 22*2 + 44*2);
 }
diff --git a/src/test/run-pass/impl-trait/universal_hrtb_named.rs b/src/test/run-pass/impl-trait/universal_hrtb_named.rs
new file mode 100644
index 00000000000..95147a54200
--- /dev/null
+++ b/src/test/run-pass/impl-trait/universal_hrtb_named.rs
@@ -0,0 +1,20 @@
+// 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(universal_impl_trait)]
+
+fn hrtb(f: impl for<'a> Fn(&'a u32) -> &'a u32) -> u32 {
+    f(&22) + f(&44)
+}
+
+fn main() {
+    let sum = hrtb(|x| x);
+    assert_eq!(sum, 22 + 44);
+}
diff --git a/src/test/run-pass/impl-trait/universal_in_adt_in_parameters.rs b/src/test/run-pass/impl-trait/universal_in_adt_in_parameters.rs
new file mode 100644
index 00000000000..d0f18575297
--- /dev/null
+++ b/src/test/run-pass/impl-trait/universal_in_adt_in_parameters.rs
@@ -0,0 +1,31 @@
+// 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(universal_impl_trait)]
+use std::fmt::Display;
+
+fn check_display_eq(iter: &Vec<impl Display>) {
+    let mut collected = String::new();
+    for it in iter {
+        let disp = format!("{} ", it);
+        collected.push_str(&disp);
+    }
+    assert_eq!("0 3 27 823 4891 1 0", collected.trim());
+}
+
+fn main() {
+    let i32_list_vec = vec![0i32, 3, 27, 823, 4891, 1, 0];
+    let u32_list_vec = vec![0u32, 3, 27, 823, 4891, 1, 0];
+    let str_list_vec = vec!["0", "3", "27", "823", "4891", "1", "0"];
+
+    check_display_eq(&i32_list_vec);
+    check_display_eq(&u32_list_vec);
+    check_display_eq(&str_list_vec);
+}
diff --git a/src/test/run-pass/impl-trait/universal_in_impl_trait_in_parameters.rs b/src/test/run-pass/impl-trait/universal_in_impl_trait_in_parameters.rs
new file mode 100644
index 00000000000..ccf24b77a6b
--- /dev/null
+++ b/src/test/run-pass/impl-trait/universal_in_impl_trait_in_parameters.rs
@@ -0,0 +1,39 @@
+// 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(universal_impl_trait)]
+use std::fmt::Display;
+
+fn check_display_eq(iter: impl IntoIterator<Item = impl Display>) {
+    let mut collected = String::new();
+    for it in iter {
+        let disp = format!("{} ", it);
+        collected.push_str(&disp);
+    }
+    assert_eq!("0 3 27 823 4891 1 0", collected.trim());
+}
+
+fn main() {
+    let i32_list = [0i32, 3, 27, 823, 4891, 1, 0];
+    let i32_list_vec = vec![0i32, 3, 27, 823, 4891, 1, 0];
+    let u32_list = [0u32, 3, 27, 823, 4891, 1, 0];
+    let u32_list_vec = vec![0u32, 3, 27, 823, 4891, 1, 0];
+    let u16_list = [0u16, 3, 27, 823, 4891, 1, 0];
+    let str_list = ["0", "3", "27", "823", "4891", "1", "0"];
+    let str_list_vec = vec!["0", "3", "27", "823", "4891", "1", "0"];
+
+    check_display_eq(&i32_list);
+    check_display_eq(i32_list_vec);
+    check_display_eq(&u32_list);
+    check_display_eq(u32_list_vec);
+    check_display_eq(&u16_list);
+    check_display_eq(&str_list);
+    check_display_eq(str_list_vec);
+}
diff --git a/src/test/run-pass/impl-trait/universal_in_trait_defn_parameters.rs b/src/test/run-pass/impl-trait/universal_in_trait_defn_parameters.rs
new file mode 100644
index 00000000000..af0201b5f87
--- /dev/null
+++ b/src/test/run-pass/impl-trait/universal_in_trait_defn_parameters.rs
@@ -0,0 +1,28 @@
+// 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(universal_impl_trait)]
+
+use std::fmt::Debug;
+
+trait InTraitDefnParameters {
+    fn in_parameters(_: impl Debug) -> String;
+}
+
+impl InTraitDefnParameters for () {
+    fn in_parameters(v: impl Debug) -> String {
+        format!("() + {:?}", v)
+    }
+}
+
+fn main() {
+    let s = <() as InTraitDefnParameters>::in_parameters(22);
+    assert_eq!(s, "() + 22");
+}
diff --git a/src/test/run-pass/impl-trait/universal_multiple_bounds.rs b/src/test/run-pass/impl-trait/universal_multiple_bounds.rs
new file mode 100644
index 00000000000..bb332c0c96c
--- /dev/null
+++ b/src/test/run-pass/impl-trait/universal_multiple_bounds.rs
@@ -0,0 +1,23 @@
+// 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(universal_impl_trait)]
+
+use std::fmt::Display;
+
+fn foo(f: impl Display + Clone) -> String {
+    let g = f.clone();
+    format!("{} + {}", f, g)
+}
+
+fn main() {
+    let sum = foo(format!("22"));
+    assert_eq!(sum, r"22 + 22");
+}
diff --git a/src/test/run-pass/impl-trait/xcrate.rs b/src/test/run-pass/impl-trait/xcrate.rs
index 6d00c46fa35..35ae185b3e1 100644
--- a/src/test/run-pass/impl-trait/xcrate.rs
+++ b/src/test/run-pass/impl-trait/xcrate.rs
@@ -13,6 +13,7 @@
 extern crate xcrate;
 
 fn main() {
-    assert_eq!(xcrate::fourway_add(1)(2)(3)(4), 10);
+//  NOTE line below commeted out due to issue #45994
+//  assert_eq!(xcrate::fourway_add(1)(2)(3)(4), 10);
     xcrate::return_closure_accessing_internal_fn()();
 }
diff --git a/src/test/rustdoc/issue-43869.rs b/src/test/rustdoc/issue-43869.rs
index 4670c5386c8..554c71500cc 100644
--- a/src/test/rustdoc/issue-43869.rs
+++ b/src/test/rustdoc/issue-43869.rs
@@ -55,13 +55,15 @@ pub fn test_44731_1() -> Result<Box<impl Clone>, ()> {
     Ok(Box::new(j()))
 }
 
-pub fn test_44731_2() -> Box<Fn(impl Clone)> {
-    Box::new(|_: u32| {})
-}
-
-pub fn test_44731_3() -> Box<Fn() -> impl Clone> {
-    Box::new(|| 0u32)
-}
+// NOTE these involve Fn sugar, where impl Trait is disallowed for now, see issue #45994
+//
+//pub fn test_44731_2() -> Box<Fn(impl Clone)> {
+//    Box::new(|_: u32| {})
+//}
+//
+//pub fn test_44731_3() -> Box<Fn() -> impl Clone> {
+//    Box::new(|| 0u32)
+//}
 
 pub fn test_44731_4() -> Box<Iterator<Item=impl Clone>> {
     Box::new(g())
@@ -78,6 +80,4 @@ pub fn test_44731_4() -> Box<Iterator<Item=impl Clone>> {
 // @has issue_43869/fn.o.html
 // @has issue_43869/fn.test_44731_0.html
 // @has issue_43869/fn.test_44731_1.html
-// @has issue_43869/fn.test_44731_2.html
-// @has issue_43869/fn.test_44731_3.html
 // @has issue_43869/fn.test_44731_4.html
diff --git a/src/test/ui/impl-trait/universal-mismatched-type.rs b/src/test/ui/impl-trait/universal-mismatched-type.rs
new file mode 100644
index 00000000000..af7adc4c657
--- /dev/null
+++ b/src/test/ui/impl-trait/universal-mismatched-type.rs
@@ -0,0 +1,19 @@
+// 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(universal_impl_trait)]
+
+use std::fmt::Debug;
+
+fn foo(x: impl Debug) -> String {
+    x
+}
+
+fn main() { }
diff --git a/src/test/ui/impl-trait/universal-mismatched-type.stderr b/src/test/ui/impl-trait/universal-mismatched-type.stderr
new file mode 100644
index 00000000000..2be24584497
--- /dev/null
+++ b/src/test/ui/impl-trait/universal-mismatched-type.stderr
@@ -0,0 +1,13 @@
+error[E0308]: mismatched types
+  --> $DIR/universal-mismatched-type.rs:16:5
+   |
+15 | fn foo(x: impl Debug) -> String {
+   |                          ------ expected `std::string::String` because of return type
+16 |     x
+   |     ^ expected struct `std::string::String`, found type parameter
+   |
+   = note: expected type `std::string::String`
+              found type `impl Debug`
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/impl-trait/universal-two-impl-traits.rs b/src/test/ui/impl-trait/universal-two-impl-traits.rs
new file mode 100644
index 00000000000..f8855a79755
--- /dev/null
+++ b/src/test/ui/impl-trait/universal-two-impl-traits.rs
@@ -0,0 +1,21 @@
+// 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(universal_impl_trait)]
+
+use std::fmt::Debug;
+
+fn foo(x: impl Debug, y: impl Debug) -> String {
+    let mut a = x;
+    a = y;
+    format!("{:?}", a)
+}
+
+fn main() { }
diff --git a/src/test/ui/impl-trait/universal-two-impl-traits.stderr b/src/test/ui/impl-trait/universal-two-impl-traits.stderr
new file mode 100644
index 00000000000..c663d38ca8a
--- /dev/null
+++ b/src/test/ui/impl-trait/universal-two-impl-traits.stderr
@@ -0,0 +1,11 @@
+error[E0308]: mismatched types
+  --> $DIR/universal-two-impl-traits.rs:17:9
+   |
+17 |     a = y;
+   |         ^ expected type parameter, found a different type parameter
+   |
+   = note: expected type `impl Debug` (type parameter)
+              found type `impl Debug` (type parameter)
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/impl-trait/universal_wrong_bounds.rs b/src/test/ui/impl-trait/universal_wrong_bounds.rs
new file mode 100644
index 00000000000..fd35d04b258
--- /dev/null
+++ b/src/test/ui/impl-trait/universal_wrong_bounds.rs
@@ -0,0 +1,26 @@
+// 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(universal_impl_trait)]
+
+use std::fmt::Display;
+
+fn foo(f: impl Display + Clone) -> String {
+    wants_debug(f);
+    wants_display(f);
+    wants_clone(f);
+}
+
+fn wants_debug(g: impl Debug) { }
+fn wants_display(g: impl Debug) { }
+fn wants_cone(g: impl Clone) { }
+
+fn main() {
+}
diff --git a/src/test/ui/impl-trait/universal_wrong_bounds.stderr b/src/test/ui/impl-trait/universal_wrong_bounds.stderr
new file mode 100644
index 00000000000..5e7788812e6
--- /dev/null
+++ b/src/test/ui/impl-trait/universal_wrong_bounds.stderr
@@ -0,0 +1,30 @@
+error[E0425]: cannot find function `wants_clone` in this scope
+  --> $DIR/universal_wrong_bounds.rs:18:5
+   |
+18 |     wants_clone(f);
+   |     ^^^^^^^^^^^ did you mean `wants_cone`?
+
+error[E0405]: cannot find trait `Debug` in this scope
+  --> $DIR/universal_wrong_bounds.rs:21:24
+   |
+21 | fn wants_debug(g: impl Debug) { }
+   |                        ^^^^^ not found in this scope
+   |
+help: possible candidate is found in another module, you can import it into scope
+   |
+13 | use std::fmt::Debug;
+   |
+
+error[E0405]: cannot find trait `Debug` in this scope
+  --> $DIR/universal_wrong_bounds.rs:22:26
+   |
+22 | fn wants_display(g: impl Debug) { }
+   |                          ^^^^^ not found in this scope
+   |
+help: possible candidate is found in another module, you can import it into scope
+   |
+13 | use std::fmt::Debug;
+   |
+
+error: cannot continue compilation due to previous error
+
diff --git a/src/test/ui/resolve/use_suggestion_placement.stderr b/src/test/ui/resolve/use_suggestion_placement.stderr
index 8a4dfdc8027..08640b292ea 100644
--- a/src/test/ui/resolve/use_suggestion_placement.stderr
+++ b/src/test/ui/resolve/use_suggestion_placement.stderr
@@ -33,17 +33,5 @@ help: possible candidates are found in other modules, you can import them into s
 11 | use std::collections::hash_map::HashMap;
    |
 
-error[E0091]: type parameter `K` is unused
-  --> $DIR/use_suggestion_placement.rs:35:15
-   |
-35 |     type Dict<K, V> = HashMap<K, V>;
-   |               ^ unused type parameter
-
-error[E0091]: type parameter `V` is unused
-  --> $DIR/use_suggestion_placement.rs:35:18
-   |
-35 |     type Dict<K, V> = HashMap<K, V>;
-   |                  ^ unused type parameter
-
-error: aborting due to 5 previous errors
+error: aborting due to 3 previous errors
 
diff --git a/src/tools/toolstate.toml b/src/tools/toolstate.toml
index 744a0f96ad7..f1684f4c5ac 100644
--- a/src/tools/toolstate.toml
+++ b/src/tools/toolstate.toml
@@ -26,7 +26,7 @@
 miri = "Broken"
 
 # ping @Manishearth @llogiq @mcarton @oli-obk
-clippy = "Testing"
+clippy = "Broken"
 
 # ping @nrc
 rls = "Testing"