about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2018-06-23 09:02:45 +0000
committerbors <bors@rust-lang.org>2018-06-23 09:02:45 +0000
commit56e8f29dbe89f2109cacc8eb5e92ea3de32eefb9 (patch)
tree8630b3d600677d35ce9c956fbfe12923b57e302d /src
parent2ea922a96d676ff84cd78421d314e6aac305b5e9 (diff)
parent30c17ccbffdbb88020e6ed42d89cc214fc3e6e5f (diff)
downloadrust-56e8f29dbe89f2109cacc8eb5e92ea3de32eefb9.tar.gz
rust-56e8f29dbe89f2109cacc8eb5e92ea3de32eefb9.zip
Auto merge of #51580 - cramertj:async-await, r=eddyb
async/await

This PR implements `async`/`await` syntax for `async fn` in Rust 2015 and `async` closures and `async` blocks in Rust 2018 (tracking issue: https://github.com/rust-lang/rust/issues/50547). Limitations: non-`move` async closures with arguments are currently not supported, nor are `async fn` with multiple different input lifetimes. These limitations are not fundamental and will be removed in the future, however I'd like to go ahead and get this PR merged so we can start experimenting with this in combination with futures 0.3.

Based on https://github.com/rust-lang/rust/pull/51414.
cc @petrochenkov for parsing changes.
r? @eddyb
Diffstat (limited to 'src')
-rw-r--r--src/librustc/diagnostics.rs7
-rw-r--r--src/librustc/hir/intravisit.rs11
-rw-r--r--src/librustc/hir/lowering.rs734
-rw-r--r--src/librustc/hir/map/blocks.rs39
-rw-r--r--src/librustc/hir/map/def_collector.rs66
-rw-r--r--src/librustc/hir/map/mod.rs4
-rw-r--r--src/librustc/hir/mod.rs26
-rw-r--r--src/librustc/hir/print.rs52
-rw-r--r--src/librustc/ich/impls_hir.rs17
-rw-r--r--src/librustc/ich/impls_syntax.rs1
-rw-r--r--src/librustc/middle/reachable.rs4
-rw-r--r--src/librustc/middle/resolve_lifetime.rs2
-rw-r--r--src/librustc_allocator/expand.rs12
-rw-r--r--src/librustc_driver/pretty.rs12
-rw-r--r--src/librustc_lint/bad_style.rs4
-rw-r--r--src/librustc_lint/builtin.rs6
-rw-r--r--src/librustc_metadata/encoder.rs15
-rw-r--r--src/librustc_mir/transform/check_unsafety.rs4
-rw-r--r--src/librustc_passes/ast_validation.rs13
-rw-r--r--src/librustc_passes/diagnostics.rs1
-rw-r--r--src/librustc_resolve/lib.rs115
-rw-r--r--src/librustc_save_analysis/dump_visitor.rs2
-rw-r--r--src/librustc_save_analysis/sig.rs24
-rw-r--r--src/librustc_typeck/check/mod.rs2
-rw-r--r--src/librustc_typeck/collect.rs10
-rw-r--r--src/librustdoc/clean/inline.rs9
-rw-r--r--src/librustdoc/clean/mod.rs54
-rw-r--r--src/librustdoc/doctree.rs5
-rw-r--r--src/librustdoc/html/format.rs13
-rw-r--r--src/librustdoc/html/render.rs52
-rw-r--r--src/librustdoc/visit_ast.rs14
-rw-r--r--src/libstd/future.rs116
-rw-r--r--src/libstd/lib.rs33
-rw-r--r--src/libstd/macros.rs19
-rw-r--r--src/libsyntax/ast.rs59
-rw-r--r--src/libsyntax/ext/build.rs11
-rw-r--r--src/libsyntax/feature_gate.rs49
-rw-r--r--src/libsyntax/fold.rs31
-rw-r--r--src/libsyntax/parse/mod.rs13
-rw-r--r--src/libsyntax/parse/parser.rs135
-rw-r--r--src/libsyntax/print/pprust.rs79
-rw-r--r--src/libsyntax/test.rs52
-rw-r--r--src/libsyntax/util/parser.rs2
-rw-r--r--src/libsyntax/visit.rs17
-rw-r--r--src/libsyntax_ext/deriving/generic/mod.rs10
-rw-r--r--src/libsyntax_pos/hygiene.rs2
-rw-r--r--src/test/parse-fail/issue-20711-2.rs2
-rw-r--r--src/test/parse-fail/issue-20711.rs2
-rw-r--r--src/test/parse-fail/removed-syntax-static-fn.rs2
-rw-r--r--src/test/parse-fail/trait-non-item-macros.rs2
-rw-r--r--src/test/parse-fail/trait-pub-assoc-const.rs2
-rw-r--r--src/test/parse-fail/trait-pub-assoc-ty.rs2
-rw-r--r--src/test/parse-fail/trait-pub-method.rs2
-rw-r--r--src/test/run-pass-fulldeps/pprust-expr-roundtrip.rs1
-rw-r--r--src/test/run-pass/async-await.rs152
-rw-r--r--src/test/ui/async-fn-multiple-lifetimes.rs30
-rw-r--r--src/test/ui/async-fn-multiple-lifetimes.stderr32
-rw-r--r--src/test/ui/did_you_mean/issue-40006.stderr4
-rw-r--r--src/test/ui/edition-keywords-2018-2015-parsing.rs2
-rw-r--r--src/test/ui/edition-keywords-2018-2015-parsing.stderr8
-rw-r--r--src/test/ui/edition-keywords-2018-2018-parsing.rs2
-rw-r--r--src/test/ui/edition-keywords-2018-2018-parsing.stderr8
-rw-r--r--src/test/ui/feature-gate-async-await-2015-edition.rs20
-rw-r--r--src/test/ui/feature-gate-async-await-2015-edition.stderr24
-rw-r--r--src/test/ui/feature-gate-async-await.rs19
-rw-r--r--src/test/ui/feature-gate-async-await.stderr27
-rw-r--r--src/test/ui/no-args-non-move-async-closure.rs18
-rw-r--r--src/test/ui/no-args-non-move-async-closure.stderr11
-rw-r--r--src/test/ui/token/issue-41155.stderr4
69 files changed, 1796 insertions, 538 deletions
diff --git a/src/librustc/diagnostics.rs b/src/librustc/diagnostics.rs
index 1435957a5c1..09153c144ae 100644
--- a/src/librustc/diagnostics.rs
+++ b/src/librustc/diagnostics.rs
@@ -2131,5 +2131,10 @@ register_diagnostics! {
     E0657, // `impl Trait` can only capture lifetimes bound at the fn level
     E0687, // in-band lifetimes cannot be used in `fn`/`Fn` syntax
     E0688, // in-band lifetimes cannot be mixed with explicit lifetime binders
-    E0697, // closures cannot be static
+
+    E0906, // closures cannot be static
+
+    E0725, // multiple different lifetimes used in arguments of `async fn`
+    E0726, // multiple elided lifetimes used in arguments of `async fn`
+    E0727, // `async` non-`move` closures with arguments are not currently supported
 }
diff --git a/src/librustc/hir/intravisit.rs b/src/librustc/hir/intravisit.rs
index ed86ef70564..766909f5723 100644
--- a/src/librustc/hir/intravisit.rs
+++ b/src/librustc/hir/intravisit.rs
@@ -41,7 +41,6 @@
 //! This order consistency is required in a few places in rustc, for
 //! example generator inference, and possibly also HIR borrowck.
 
-use rustc_target::spec::abi::Abi;
 use syntax::ast::{NodeId, CRATE_NODE_ID, Ident, Name, Attribute};
 use syntax_pos::Span;
 use hir::*;
@@ -54,8 +53,8 @@ use std::u32;
 
 #[derive(Copy, Clone, PartialEq, Eq)]
 pub enum FnKind<'a> {
-    /// fn foo() or extern "Abi" fn foo()
-    ItemFn(Name, &'a Generics, Unsafety, Constness, Abi, &'a Visibility, &'a [Attribute]),
+    /// #[xxx] pub async/const/extern "Abi" fn foo()
+    ItemFn(Name, &'a Generics, FnHeader, &'a Visibility, &'a [Attribute]),
 
     /// fn foo(&self)
     Method(Name, &'a MethodSig, Option<&'a Visibility>, &'a [Attribute]),
@@ -479,12 +478,10 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item) {
             visitor.visit_ty(typ);
             visitor.visit_nested_body(body);
         }
-        ItemFn(ref declaration, unsafety, constness, abi, ref generics, body_id) => {
+        ItemFn(ref declaration, header, ref generics, body_id) => {
             visitor.visit_fn(FnKind::ItemFn(item.name,
                                             generics,
-                                            unsafety,
-                                            constness,
-                                            abi,
+                                            header,
                                             &item.vis,
                                             &item.attrs),
                              declaration,
diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs
index 6291e0eb113..d6da2fce69a 100644
--- a/src/librustc/hir/lowering.rs
+++ b/src/librustc/hir/lowering.rs
@@ -168,6 +168,7 @@ pub trait Resolver {
         span: Span,
         crate_root: Option<&str>,
         components: &[&str],
+        params: Option<P<hir::GenericArgs>>,
         is_value: bool,
     ) -> hir::Path;
 }
@@ -449,7 +450,7 @@ impl<'a> LoweringContext<'a> {
         }
     }
 
-    fn allocate_hir_id_counter<T: Debug>(&mut self, owner: NodeId, debug: &T) {
+    fn allocate_hir_id_counter<T: Debug>(&mut self, owner: NodeId, debug: &T) -> LoweredNodeId {
         if self.item_local_id_counters.insert(owner, 0).is_some() {
             bug!(
                 "Tried to allocate item_local_id_counter for {:?} twice",
@@ -457,7 +458,7 @@ impl<'a> LoweringContext<'a> {
             );
         }
         // Always allocate the first HirId for the owner itself
-        self.lower_node_id_with_owner(owner, owner);
+        self.lower_node_id_with_owner(owner, owner)
     }
 
     fn lower_node_id_generic<F>(&mut self, ast_node_id: NodeId, alloc_hir_id: F) -> LoweredNodeId
@@ -501,7 +502,7 @@ impl<'a> LoweringContext<'a> {
     {
         let counter = self.item_local_id_counters
             .insert(owner, HIR_ID_COUNTER_LOCKED)
-            .unwrap();
+            .unwrap_or_else(|| panic!("No item_local_id_counters entry for {:?}", owner));
         let def_index = self.resolver.definitions().opt_def_index(owner).unwrap();
         self.current_hir_id_owner.push((def_index, counter));
         let ret = f(self);
@@ -840,6 +841,46 @@ impl<'a> LoweringContext<'a> {
         result
     }
 
+    fn make_async_expr(
+        &mut self,
+        capture_clause: CaptureBy,
+        closure_node_id: NodeId,
+        ret_ty: Option<&Ty>,
+        body: impl FnOnce(&mut LoweringContext) -> hir::Expr,
+    ) -> hir::Expr_ {
+        let prev_is_generator = mem::replace(&mut self.is_generator, true);
+        let body_expr = body(self);
+        let span = body_expr.span;
+        let output = match ret_ty {
+            Some(ty) => FunctionRetTy::Ty(P(ty.clone())),
+            None => FunctionRetTy::Default(span),
+        };
+        let decl = FnDecl {
+            inputs: vec![],
+            output,
+            variadic: false
+        };
+        let body_id = self.record_body(body_expr, Some(&decl));
+        self.is_generator = prev_is_generator;
+
+        let capture_clause = self.lower_capture_clause(capture_clause);
+        let closure_hir_id = self.lower_node_id(closure_node_id).hir_id;
+        let decl = self.lower_fn_decl(&decl, None, /* impl trait allowed */ false, false);
+        let generator = hir::Expr {
+            id: closure_node_id,
+            hir_id: closure_hir_id,
+            node: hir::ExprClosure(capture_clause, decl, body_id, span,
+                Some(hir::GeneratorMovability::Static)),
+            span,
+            attrs: ThinVec::new(),
+        };
+
+        let unstable_span = self.allow_internal_unstable(CompilerDesugaringKind::Async, span);
+        let gen_future = self.expr_std_path(
+            unstable_span, &["future", "from_generator"], None, ThinVec::new());
+        hir::ExprCall(P(gen_future), hir_vec![generator])
+    }
+
     fn lower_body<F>(&mut self, decl: Option<&FnDecl>, f: F) -> hir::BodyId
     where
         F: FnOnce(&mut LoweringContext) -> hir::Expr,
@@ -1067,7 +1108,7 @@ impl<'a> LoweringContext<'a> {
                                 ),
                                 unsafety: this.lower_unsafety(f.unsafety),
                                 abi: f.abi,
-                                decl: this.lower_fn_decl(&f.decl, None, false),
+                                decl: this.lower_fn_decl(&f.decl, None, false, false),
                                 arg_names: this.lower_fn_args_to_names(&f.decl),
                             }))
                         },
@@ -1132,92 +1173,8 @@ impl<'a> LoweringContext<'a> {
                 let span = t.span;
                 match itctx {
                     ImplTraitContext::Existential(fn_def_id) => {
-
-                        // We need to manually repeat the code of `next_id` because the lowering
-                        // needs to happen while the owner_id is pointing to the item itself,
-                        // because items are their own owners
-                        let exist_ty_node_id = self.sess.next_node_id();
-
-                        // Make sure we know that some funky desugaring has been going on here.
-                        // This is a first: there is code in other places like for loop
-                        // desugaring that explicitly states that we don't want to track that.
-                        // Not tracking it makes lints in rustc and clippy very fragile as
-                        // frequently opened issues show.
-                        let exist_ty_span = self.allow_internal_unstable(
-                            CompilerDesugaringKind::ExistentialReturnType,
-                            t.span,
-                        );
-
-                        // Pull a new definition from the ether
-                        let exist_ty_def_index = self
-                            .resolver
-                            .definitions()
-                            .create_def_with_parent(
-                            fn_def_id.index,
-                            exist_ty_node_id,
-                            DefPathData::ExistentialImplTrait,
-                            DefIndexAddressSpace::High,
-                            Mark::root(),
-                            exist_ty_span,
-                        );
-
-                        // the `t` is just for printing debug messages
-                        self.allocate_hir_id_counter(exist_ty_node_id, t);
-
-                        let hir_bounds = self.with_hir_id_owner(exist_ty_node_id, |lctx| {
-                            lctx.lower_param_bounds(bounds, itctx)
-                        });
-
-                        let (lifetimes, lifetime_defs) = self.lifetimes_from_impl_trait_bounds(
-                            exist_ty_node_id,
-                            exist_ty_def_index,
-                            &hir_bounds,
-                        );
-
-                        self.with_hir_id_owner(exist_ty_node_id, |lctx| {
-                            let exist_ty_item_kind = hir::ItemExistential(hir::ExistTy {
-                                generics: hir::Generics {
-                                    params: lifetime_defs,
-                                    where_clause: hir::WhereClause {
-                                        id: lctx.next_id().node_id,
-                                        predicates: Vec::new().into(),
-                                    },
-                                    span,
-                                },
-                                bounds: hir_bounds,
-                                impl_trait_fn: Some(fn_def_id),
-                            });
-                            let exist_ty_id = lctx.lower_node_id(exist_ty_node_id);
-                            // Generate an `existential type Foo: Trait;` declaration
-                            trace!("creating existential type with id {:#?}", exist_ty_id);
-                            // Set the name to `impl Bound1 + Bound2`
-                            let exist_ty_name = Symbol::intern(&pprust::ty_to_string(t));
-
-                            trace!("exist ty def index: {:#?}", exist_ty_def_index);
-                            let exist_ty_item = hir::Item {
-                                id: exist_ty_id.node_id,
-                                hir_id: exist_ty_id.hir_id,
-                                name: exist_ty_name,
-                                attrs: Default::default(),
-                                node: exist_ty_item_kind,
-                                vis: hir::Visibility::Inherited,
-                                span: exist_ty_span,
-                            };
-
-                            // Insert the item into the global list. This usually happens
-                            // automatically for all AST items. But this existential type item
-                            // does not actually exist in the AST.
-                            lctx.items.insert(exist_ty_id.node_id, exist_ty_item);
-
-                            // `impl Trait` now just becomes `Foo<'a, 'b, ..>`
-                            hir::TyImplTraitExistential(
-                                hir::ItemId {
-                                    id: exist_ty_id.node_id
-                                },
-                                DefId::local(exist_ty_def_index),
-                                lifetimes,
-                            )
-                        })
+                        self.lower_existential_impl_trait(
+                            span, fn_def_id, |this| this.lower_param_bounds(bounds, itctx))
                     }
                     ImplTraitContext::Universal(def_id) => {
                         let def_node_id = self.next_id().node_id;
@@ -1281,6 +1238,94 @@ impl<'a> LoweringContext<'a> {
         })
     }
 
+    fn lower_existential_impl_trait(
+        &mut self,
+        span: Span,
+        fn_def_id: DefId,
+        lower_bounds: impl FnOnce(&mut LoweringContext) -> hir::GenericBounds,
+    ) -> hir::Ty_ {
+        // We need to manually repeat the code of `next_id` because the lowering
+        // needs to happen while the owner_id is pointing to the item itself,
+        // because items are their own owners
+        let exist_ty_node_id = self.sess.next_node_id();
+
+        // Make sure we know that some funky desugaring has been going on here.
+        // This is a first: there is code in other places like for loop
+        // desugaring that explicitly states that we don't want to track that.
+        // Not tracking it makes lints in rustc and clippy very fragile as
+        // frequently opened issues show.
+        let exist_ty_span = self.allow_internal_unstable(
+            CompilerDesugaringKind::ExistentialReturnType,
+            span,
+        );
+
+        // Pull a new definition from the ether
+        let exist_ty_def_index = self
+            .resolver
+            .definitions()
+            .create_def_with_parent(
+            fn_def_id.index,
+            exist_ty_node_id,
+            DefPathData::ExistentialImplTrait,
+            DefIndexAddressSpace::High,
+            Mark::root(),
+            exist_ty_span,
+        );
+
+        self.allocate_hir_id_counter(exist_ty_node_id, &"existential impl trait");
+
+        let hir_bounds = self.with_hir_id_owner(exist_ty_node_id, lower_bounds);
+
+        let (lifetimes, lifetime_defs) = self.lifetimes_from_impl_trait_bounds(
+            exist_ty_node_id,
+            exist_ty_def_index,
+            &hir_bounds,
+        );
+
+        self.with_hir_id_owner(exist_ty_node_id, |lctx| {
+            let exist_ty_item_kind = hir::ItemExistential(hir::ExistTy {
+                generics: hir::Generics {
+                    params: lifetime_defs,
+                    where_clause: hir::WhereClause {
+                        id: lctx.next_id().node_id,
+                        predicates: Vec::new().into(),
+                    },
+                    span,
+                },
+                bounds: hir_bounds,
+                impl_trait_fn: Some(fn_def_id),
+            });
+            let exist_ty_id = lctx.lower_node_id(exist_ty_node_id);
+            // Generate an `existential type Foo: Trait;` declaration
+            trace!("creating existential type with id {:#?}", exist_ty_id);
+
+            trace!("exist ty def index: {:#?}", exist_ty_def_index);
+            let exist_ty_item = hir::Item {
+                id: exist_ty_id.node_id,
+                hir_id: exist_ty_id.hir_id,
+                name: keywords::Invalid.name(),
+                attrs: Default::default(),
+                node: exist_ty_item_kind,
+                vis: hir::Visibility::Inherited,
+                span: exist_ty_span,
+            };
+
+            // Insert the item into the global list. This usually happens
+            // automatically for all AST items. But this existential type item
+            // does not actually exist in the AST.
+            lctx.items.insert(exist_ty_id.node_id, exist_ty_item);
+
+            // `impl Trait` now just becomes `Foo<'a, 'b, ..>`
+            hir::TyImplTraitExistential(
+                hir::ItemId {
+                    id: exist_ty_id.node_id
+                },
+                DefId::local(exist_ty_def_index),
+                lifetimes,
+            )
+        })
+    }
+
     fn lifetimes_from_impl_trait_bounds(
         &mut self,
         exist_ty_id: NodeId,
@@ -1829,31 +1874,40 @@ impl<'a> LoweringContext<'a> {
             .collect()
     }
 
+    // Lowers a function declaration.
+    //
+    // decl: the unlowered (ast) function declaration.
+    // fn_def_id: if `Some`, impl Trait arguments are lowered into generic parameters on the
+    //      given DefId, otherwise impl Trait is disallowed. Must be `Some` if
+    //      make_ret_async is true.
+    // impl_trait_return_allow: determines whether impl Trait can be used in return position.
+    //      This guards against trait declarations and implementations where impl Trait is
+    //      disallowed.
+    // make_ret_async: if enabled, converts `-> T` into `-> impl Future<Output = T>` in the
+    //      return type. This is used for `async fn` declarations.
     fn lower_fn_decl(
         &mut self,
         decl: &FnDecl,
         fn_def_id: Option<DefId>,
         impl_trait_return_allow: bool,
+        make_ret_async: bool,
     ) -> P<hir::FnDecl> {
-        // NOTE: The two last parameters here have to do with impl Trait. If fn_def_id is Some,
-        //       then impl Trait arguments are lowered into generic parameters 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| {
-                    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 {
+        let 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::<HirVec<_>>();
+
+        let output = if make_ret_async {
+            self.lower_async_fn_ret_ty(
+                &inputs, &decl.output, fn_def_id.expect("make_ret_async but no fn_def_id"))
+        } else {
+            match decl.output {
                 FunctionRetTy::Ty(ref ty) => match fn_def_id {
                     Some(def_id) if impl_trait_return_allow => {
                         hir::Return(self.lower_ty(ty, ImplTraitContext::Existential(def_id)))
@@ -1861,7 +1915,12 @@ impl<'a> LoweringContext<'a> {
                     _ => hir::Return(self.lower_ty(ty, ImplTraitContext::Disallowed)),
                 },
                 FunctionRetTy::Default(span) => hir::DefaultReturn(span),
-            },
+            }
+        };
+
+        P(hir::FnDecl {
+            inputs,
+            output,
             variadic: decl.variadic,
             has_implicit_self: decl.inputs.get(0).map_or(false, |arg| match arg.ty.node {
                 TyKind::ImplicitSelf => true,
@@ -1871,6 +1930,231 @@ impl<'a> LoweringContext<'a> {
         })
     }
 
+    // Transform `-> T` into `-> impl Future<Output = T>` for `async fn`
+    //
+    // fn_span: the span of the async function declaration. Used for error reporting.
+    // inputs: lowered types of arguments to the function. Used to collect lifetimes.
+    // output: unlowered output type (`T` in `-> T`)
+    // fn_def_id: DefId of the parent function. Used to create child impl trait definition.
+    fn lower_async_fn_ret_ty(
+        &mut self,
+        inputs: &[P<hir::Ty>],
+        output: &FunctionRetTy,
+        fn_def_id: DefId,
+    ) -> hir::FunctionRetTy {
+        // Get lifetimes used in the input arguments to the function. Our output type must also
+        // have the same lifetime. FIXME(cramertj) multiple different lifetimes are not allowed
+        // because `impl Trait + 'a + 'b` doesn't allow for capture `'a` and `'b` where neither
+        // is a subset of the other. We really want some new lifetime that is a subset of all input
+        // lifetimes, but that doesn't exist at the moment.
+
+        struct AsyncFnLifetimeCollector<'r, 'a: 'r> {
+            context: &'r mut LoweringContext<'a>,
+            // Lifetimes bound by HRTB
+            currently_bound_lifetimes: Vec<hir::LifetimeName>,
+            // Whether to count elided lifetimes.
+            // Disabled inside of `Fn` or `fn` syntax.
+            collect_elided_lifetimes: bool,
+            // The lifetime found.
+            // Multiple different or elided lifetimes cannot appear in async fn for now.
+            output_lifetime: Option<(hir::LifetimeName, Span)>,
+        }
+
+        impl<'r, 'a: 'r, 'v> hir::intravisit::Visitor<'v> for AsyncFnLifetimeCollector<'r, 'a> {
+            fn nested_visit_map<'this>(
+                &'this mut self,
+            ) -> hir::intravisit::NestedVisitorMap<'this, 'v> {
+                hir::intravisit::NestedVisitorMap::None
+            }
+
+            fn visit_generic_args(&mut self, span: Span, parameters: &'v hir::GenericArgs) {
+                // Don't collect elided lifetimes used inside of `Fn()` syntax.
+                if parameters.parenthesized {
+                    let old_collect_elided_lifetimes = self.collect_elided_lifetimes;
+                    self.collect_elided_lifetimes = false;
+                    hir::intravisit::walk_generic_args(self, span, parameters);
+                    self.collect_elided_lifetimes = old_collect_elided_lifetimes;
+                } else {
+                    hir::intravisit::walk_generic_args(self, span, parameters);
+                }
+            }
+
+            fn visit_ty(&mut self, t: &'v hir::Ty) {
+                // Don't collect elided lifetimes used inside of `fn()` syntax
+                if let &hir::Ty_::TyBareFn(_) = &t.node {
+                    let old_collect_elided_lifetimes = self.collect_elided_lifetimes;
+                    self.collect_elided_lifetimes = false;
+
+                    // Record the "stack height" of `for<'a>` lifetime bindings
+                    // to be able to later fully undo their introduction.
+                    let old_len = self.currently_bound_lifetimes.len();
+                    hir::intravisit::walk_ty(self, t);
+                    self.currently_bound_lifetimes.truncate(old_len);
+
+                    self.collect_elided_lifetimes = old_collect_elided_lifetimes;
+                } else {
+                    hir::intravisit::walk_ty(self, t);
+                }
+            }
+
+            fn visit_poly_trait_ref(
+                &mut self,
+                trait_ref: &'v hir::PolyTraitRef,
+                modifier: hir::TraitBoundModifier,
+            ) {
+                // Record the "stack height" of `for<'a>` lifetime bindings
+                // to be able to later fully undo their introduction.
+                let old_len = self.currently_bound_lifetimes.len();
+                hir::intravisit::walk_poly_trait_ref(self, trait_ref, modifier);
+                self.currently_bound_lifetimes.truncate(old_len);
+            }
+
+            fn visit_generic_param(&mut self, param: &'v hir::GenericParam) {
+                 // Record the introduction of 'a in `for<'a> ...`
+                if let hir::GenericParamKind::Lifetime { .. } = param.kind {
+                    // Introduce lifetimes one at a time so that we can handle
+                    // cases like `fn foo<'d>() -> impl for<'a, 'b: 'a, 'c: 'b + 'd>`
+                    let lt_name = hir::LifetimeName::Param(param.name);
+                    self.currently_bound_lifetimes.push(lt_name);
+                }
+
+                hir::intravisit::walk_generic_param(self, param);
+            }
+
+            fn visit_lifetime(&mut self, lifetime: &'v hir::Lifetime) {
+                let name = match lifetime.name {
+                    hir::LifetimeName::Implicit | hir::LifetimeName::Underscore => {
+                        if self.collect_elided_lifetimes {
+                            // Use `'_` for both implicit and underscore lifetimes in
+                            // `abstract type Foo<'_>: SomeTrait<'_>;`
+                            hir::LifetimeName::Underscore
+                        } else {
+                            return;
+                        }
+                    }
+                    hir::LifetimeName::Param(_) => lifetime.name,
+                    hir::LifetimeName::Static => return,
+                };
+
+                if !self.currently_bound_lifetimes.contains(&name) {
+                    if let Some((current_lt_name, current_lt_span)) = self.output_lifetime {
+                        // We don't currently have a reliable way to desugar `async fn` with
+                        // multiple potentially unrelated input lifetimes into
+                        // `-> impl Trait + 'lt`, so we report an error in this case.
+                        if current_lt_name != name {
+                            struct_span_err!(
+                                self.context.sess,
+                                current_lt_span.between(lifetime.span),
+                                E0725,
+                                "multiple different lifetimes used in arguments of `async fn`",
+                            )
+                                .span_label(current_lt_span, "first lifetime here")
+                                .span_label(lifetime.span, "different lifetime here")
+                                .help("`async fn` can only accept borrowed values \
+                                      with identical lifetimes")
+                                .emit()
+                        } else if current_lt_name.is_elided() && name.is_elided() {
+                            struct_span_err!(
+                                self.context.sess,
+                                current_lt_span.between(lifetime.span),
+                                E0726,
+                                "multiple elided lifetimes used in arguments of `async fn`",
+                            )
+                                .span_label(current_lt_span, "first lifetime here")
+                                .span_label(lifetime.span, "different lifetime here")
+                                .help("consider giving these arguments named lifetimes")
+                                .emit()
+                        }
+                    } else {
+                        self.output_lifetime = Some((name, lifetime.span));
+                    }
+                }
+            }
+        }
+
+        let bound_lifetime = {
+            let mut lifetime_collector = AsyncFnLifetimeCollector {
+                context: self,
+                currently_bound_lifetimes: Vec::new(),
+                collect_elided_lifetimes: true,
+                output_lifetime: None,
+            };
+
+            for arg in inputs {
+                hir::intravisit::walk_ty(&mut lifetime_collector, arg);
+            }
+            lifetime_collector.output_lifetime
+        };
+
+        let span = match output {
+            FunctionRetTy::Ty(ty) => ty.span,
+            FunctionRetTy::Default(span) => *span,
+        };
+
+        let impl_trait_ty = self.lower_existential_impl_trait(
+            span, fn_def_id, |this| {
+            let output_ty = match output {
+                FunctionRetTy::Ty(ty) =>
+                    this.lower_ty(ty, ImplTraitContext::Existential(fn_def_id)),
+                FunctionRetTy::Default(span) => {
+                    let LoweredNodeId { node_id, hir_id } = this.next_id();
+                    P(hir::Ty {
+                        id: node_id,
+                        hir_id: hir_id,
+                        node: hir::TyTup(hir_vec![]),
+                        span: *span,
+                    })
+                }
+            };
+
+            // "<Output = T>"
+            let future_params = P(hir::GenericArgs {
+                args: hir_vec![],
+                bindings: hir_vec![hir::TypeBinding {
+                    name: Symbol::intern(FN_OUTPUT_NAME),
+                    ty: output_ty,
+                    id: this.next_id().node_id,
+                    span,
+                }],
+                parenthesized: false,
+            });
+
+            let future_path =
+                this.std_path(span, &["future", "Future"], Some(future_params), false);
+
+            let mut bounds = vec![
+                hir::GenericBound::Trait(
+                    hir::PolyTraitRef {
+                        trait_ref: hir::TraitRef {
+                            path: future_path,
+                            ref_id: this.next_id().node_id,
+                        },
+                        bound_generic_params: hir_vec![],
+                        span,
+                    },
+                    hir::TraitBoundModifier::None
+                ),
+            ];
+
+            if let Some((name, span)) = bound_lifetime {
+                bounds.push(hir::GenericBound::Outlives(
+                    hir::Lifetime { id: this.next_id().node_id, name, span }));
+            }
+
+            hir::HirVec::from(bounds)
+        });
+
+        let LoweredNodeId { node_id, hir_id } = self.next_id();
+        let impl_trait_ty = P(hir::Ty {
+            id: node_id,
+            node: impl_trait_ty,
+            span,
+            hir_id,
+        });
+
+        hir::FunctionRetTy::Return(impl_trait_ty)
+    }
+
     fn lower_param_bound(
         &mut self,
         tpb: &GenericBound,
@@ -2284,25 +2568,40 @@ impl<'a> LoweringContext<'a> {
                 let value = self.lower_body(None, |this| this.lower_expr(e));
                 hir::ItemConst(self.lower_ty(t, ImplTraitContext::Disallowed), value)
             }
-            ItemKind::Fn(ref decl, unsafety, constness, abi, ref generics, ref body) => {
+            ItemKind::Fn(ref decl, header, ref generics, ref body) => {
                 let fn_def_id = self.resolver.definitions().local_def_id(id);
+
                 self.with_new_scopes(|this| {
+                    // Note: we don't need to change the return type from `T` to
+                    // `impl Future<Output = T>` here because lower_body
+                    // only cares about the input argument patterns in the function
+                    // declaration (decl), not the return types.
                     let body_id = this.lower_body(Some(decl), |this| {
-                        let body = this.lower_block(body, false);
-                        this.expr_block(body, ThinVec::new())
+                        if let IsAsync::Async(async_node_id) = header.asyncness {
+                            let async_expr = this.make_async_expr(
+                                CaptureBy::Value, async_node_id, None,
+                                |this| {
+                                    let body = this.lower_block(body, false);
+                                    this.expr_block(body, ThinVec::new())
+                                });
+                            this.expr(body.span, async_expr, ThinVec::new())
+                        } else {
+                            let body = this.lower_block(body, false);
+                            this.expr_block(body, ThinVec::new())
+                        }
                     });
+
                     let (generics, fn_decl) = this.add_in_band_defs(
                         generics,
                         fn_def_id,
                         AnonymousLifetimeMode::PassThrough,
-                        |this| this.lower_fn_decl(decl, Some(fn_def_id), true),
+                        |this| this.lower_fn_decl(
+                            decl, Some(fn_def_id), true, header.asyncness.is_async())
                     );
 
                     hir::ItemFn(
                         fn_decl,
-                        this.lower_unsafety(unsafety),
-                        this.lower_constness(constness),
-                        abi,
+                        this.lower_fn_header(header),
                         generics,
                         body_id,
                     )
@@ -2620,7 +2919,7 @@ impl<'a> LoweringContext<'a> {
                     AnonymousLifetimeMode::PassThrough,
                     |this| {
                         hir::TraitItemKind::Method(
-                            this.lower_method_sig(sig, trait_item_def_id, false),
+                            this.lower_method_sig(sig, trait_item_def_id, false, false),
                             hir::TraitMethod::Required(names),
                         )
                     },
@@ -2638,7 +2937,7 @@ impl<'a> LoweringContext<'a> {
                     AnonymousLifetimeMode::PassThrough,
                     |this| {
                         hir::TraitItemKind::Method(
-                            this.lower_method_sig(sig, trait_item_def_id, false),
+                            this.lower_method_sig(sig, trait_item_def_id, false, false),
                             hir::TraitMethod::Provided(body_id),
                         )
                     },
@@ -2709,8 +3008,18 @@ impl<'a> LoweringContext<'a> {
             }
             ImplItemKind::Method(ref sig, ref body) => {
                 let body_id = self.lower_body(Some(&sig.decl), |this| {
-                    let body = this.lower_block(body, false);
-                    this.expr_block(body, ThinVec::new())
+                    if let IsAsync::Async(async_node_id) = sig.header.asyncness {
+                        let async_expr = this.make_async_expr(
+                            CaptureBy::Value, async_node_id, None,
+                            |this| {
+                                let body = this.lower_block(body, false);
+                                this.expr_block(body, ThinVec::new())
+                            });
+                        this.expr(body.span, async_expr, ThinVec::new())
+                    } else {
+                        let body = this.lower_block(body, false);
+                        this.expr_block(body, ThinVec::new())
+                    }
                 });
                 let impl_trait_return_allow = !self.is_in_trait_impl;
 
@@ -2724,6 +3033,7 @@ impl<'a> LoweringContext<'a> {
                                 sig,
                                 impl_item_def_id,
                                 impl_trait_return_allow,
+                                sig.header.asyncness.is_async(),
                             ),
                             body_id,
                         )
@@ -2865,7 +3175,7 @@ impl<'a> LoweringContext<'a> {
                         |this| {
                             (
                                 // Disallow impl Trait in foreign items
-                                this.lower_fn_decl(fdec, None, false),
+                                this.lower_fn_decl(fdec, None, false, false),
                                 this.lower_fn_args_to_names(fdec),
                             )
                         },
@@ -2889,12 +3199,11 @@ impl<'a> LoweringContext<'a> {
         sig: &MethodSig,
         fn_def_id: DefId,
         impl_trait_return_allow: bool,
+        is_async: 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, Some(fn_def_id), impl_trait_return_allow),
+            header: self.lower_fn_header(sig.header),
+            decl: self.lower_fn_decl(&sig.decl, Some(fn_def_id), impl_trait_return_allow, is_async),
         }
     }
 
@@ -2905,6 +3214,15 @@ impl<'a> LoweringContext<'a> {
         }
     }
 
+    fn lower_fn_header(&mut self, h: FnHeader) -> hir::FnHeader {
+        hir::FnHeader {
+            unsafety: self.lower_unsafety(h.unsafety),
+            asyncness: self.lower_asyncness(h.asyncness),
+            constness: self.lower_constness(h.constness),
+            abi: h.abi,
+        }
+    }
+
     fn lower_unsafety(&mut self, u: Unsafety) -> hir::Unsafety {
         match u {
             Unsafety::Unsafe => hir::Unsafety::Unsafe,
@@ -2919,6 +3237,13 @@ impl<'a> LoweringContext<'a> {
         }
     }
 
+    fn lower_asyncness(&mut self, a: IsAsync) -> hir::IsAsync {
+        match a {
+            IsAsync::Async(_) => hir::IsAsync::Async,
+            IsAsync::NotAsync => hir::IsAsync::NotAsync,
+        }
+    }
+
     fn lower_unop(&mut self, u: UnOp) -> hir::UnOp {
         match u {
             UnOp::Deref => hir::UnDeref,
@@ -3206,46 +3531,101 @@ impl<'a> LoweringContext<'a> {
                 arms.iter().map(|x| self.lower_arm(x)).collect(),
                 hir::MatchSource::Normal,
             ),
-            ExprKind::Closure(capture_clause, movability, ref decl, ref body, fn_decl_span) => {
+            ExprKind::Async(capture_clause, closure_node_id, ref block) => {
+                self.make_async_expr(capture_clause, closure_node_id, None, |this| {
+                    this.with_new_scopes(|this| {
+                        let block = this.lower_block(block, false);
+                        this.expr_block(block, ThinVec::new())
+                    })
+                })
+            },
+            ExprKind::Closure(
+                capture_clause, asyncness, movability, ref decl, ref body, fn_decl_span) =>
+            {
                 self.with_new_scopes(|this| {
-                    let mut is_generator = false;
-                    let body_id = this.lower_body(Some(decl), |this| {
-                        let e = this.lower_expr(body);
-                        is_generator = this.is_generator;
-                        e
-                    });
-                    let generator_option = if is_generator {
-                        if !decl.inputs.is_empty() {
-                            span_err!(
+                    if let IsAsync::Async(async_closure_node_id) = asyncness {
+                        // FIXME(cramertj) allow `async` non-`move` closures with
+                        if capture_clause == CaptureBy::Ref &&
+                            !decl.inputs.is_empty()
+                        {
+                            struct_span_err!(
                                 this.sess,
                                 fn_decl_span,
-                                E0628,
-                                "generators cannot have explicit arguments"
-                            );
-                            this.sess.abort_if_errors();
+                                E0727,
+                                "`async` non-`move` closures with arguments \
+                                are not currently supported",
+                            )
+                                .help("consider using `let` statements to manually capture \
+                                        variables by reference before entering an \
+                                        `async move` closure")
+                                .emit();
                         }
-                        Some(match movability {
-                            Movability::Movable => hir::GeneratorMovability::Movable,
-                            Movability::Static => hir::GeneratorMovability::Static,
-                        })
+
+                        // Transform `async |x: u8| -> X { ... }` into
+                        // `|x: u8| future_from_generator(|| -> X { ... })`
+                        let outer_decl = FnDecl {
+                            inputs: decl.inputs.clone(),
+                            output: FunctionRetTy::Default(fn_decl_span),
+                            variadic: false,
+                        };
+                        let body_id = this.lower_body(Some(&outer_decl), |this| {
+                            let async_ret_ty = if let FunctionRetTy::Ty(ty) = &decl.output {
+                                Some(&**ty)
+                            } else { None };
+                            let async_body = this.make_async_expr(
+                                capture_clause, async_closure_node_id, async_ret_ty,
+                                |this| {
+                                    this.with_new_scopes(|this| this.lower_expr(body))
+                                });
+                            this.expr(fn_decl_span, async_body, ThinVec::new())
+                        });
+                        hir::ExprClosure(
+                            this.lower_capture_clause(capture_clause),
+                            this.lower_fn_decl(&outer_decl, None, false, false),
+                            body_id,
+                            fn_decl_span,
+                            None,
+                        )
                     } else {
-                        if movability == Movability::Static {
-                            span_err!(
-                                this.sess,
-                                fn_decl_span,
-                                E0697,
-                                "closures cannot be static"
-                            );
-                        }
-                        None
-                    };
-                    hir::ExprClosure(
-                        this.lower_capture_clause(capture_clause),
-                        this.lower_fn_decl(decl, None, false),
-                        body_id,
-                        fn_decl_span,
-                        generator_option,
-                    )
+                        let mut is_generator = false;
+                        let body_id = this.lower_body(Some(decl), |this| {
+                            let e = this.lower_expr(body);
+                            is_generator = this.is_generator;
+                            e
+                        });
+                        let generator_option = if is_generator {
+                            if !decl.inputs.is_empty() {
+                                span_err!(
+                                    this.sess,
+                                    fn_decl_span,
+                                    E0628,
+                                    "generators cannot have explicit arguments"
+                                );
+                                this.sess.abort_if_errors();
+                            }
+                            Some(match movability {
+                                Movability::Movable => hir::GeneratorMovability::Movable,
+                                Movability::Static => hir::GeneratorMovability::Static,
+                            })
+                        } else {
+                            if movability == Movability::Static {
+                                span_err!(
+                                    this.sess,
+                                    fn_decl_span,
+                                    E0906,
+                                    "closures cannot be static"
+                                );
+                            }
+                            None
+                        };
+                        hir::ExprClosure(
+                            this.lower_capture_clause(capture_clause),
+                            this.lower_fn_decl(decl, None, false, false),
+                            body_id,
+                            fn_decl_span,
+                            generator_option,
+                        )
+                    }
                 })
             }
             ExprKind::Block(ref blk, opt_label) => {
@@ -3272,7 +3652,7 @@ impl<'a> LoweringContext<'a> {
                 let id = self.next_id();
                 let e1 = self.lower_expr(e1);
                 let e2 = self.lower_expr(e2);
-                let ty_path = P(self.std_path(span, &["ops", "RangeInclusive"], false));
+                let ty_path = P(self.std_path(span, &["ops", "RangeInclusive"], None, false));
                 let ty = self.ty_path(id, span, hir::QPath::Resolved(None, ty_path));
                 let new_seg = P(hir::PathSegment::from_name(Symbol::intern("new")));
                 let new_path = hir::QPath::TypeRelative(ty, new_seg);
@@ -3312,7 +3692,7 @@ impl<'a> LoweringContext<'a> {
                 let struct_path = iter::once("ops")
                     .chain(iter::once(path))
                     .collect::<Vec<_>>();
-                let struct_path = self.std_path(unstable_span, &struct_path, is_unit);
+                let struct_path = self.std_path(unstable_span, &struct_path, None, is_unit);
                 let struct_path = hir::QPath::Resolved(None, P(struct_path));
 
                 let LoweredNodeId { node_id, hir_id } = self.lower_node_id(e.id);
@@ -3589,7 +3969,7 @@ impl<'a> LoweringContext<'a> {
                     let iter = P(self.expr_ident(head_sp, iter, iter_pat.id));
                     let ref_mut_iter = self.expr_mut_addr_of(head_sp, iter);
                     let next_path = &["iter", "Iterator", "next"];
-                    let next_path = P(self.expr_std_path(head_sp, next_path, ThinVec::new()));
+                    let next_path = P(self.expr_std_path(head_sp, next_path, None, ThinVec::new()));
                     let next_expr = P(self.expr_call(head_sp, next_path, hir_vec![ref_mut_iter]));
                     let arms = hir_vec![pat_arm, break_arm];
 
@@ -3647,7 +4027,8 @@ impl<'a> LoweringContext<'a> {
                 // `match ::std::iter::IntoIterator::into_iter(<head>) { ... }`
                 let into_iter_expr = {
                     let into_iter_path = &["iter", "IntoIterator", "into_iter"];
-                    let into_iter = P(self.expr_std_path(head_sp, into_iter_path, ThinVec::new()));
+                    let into_iter = P(self.expr_std_path(
+                            head_sp, into_iter_path, None, ThinVec::new()));
                     P(self.expr_call(head_sp, into_iter, hir_vec![head]))
                 };
 
@@ -3693,7 +4074,8 @@ impl<'a> LoweringContext<'a> {
                     let sub_expr = self.lower_expr(sub_expr);
 
                     let path = &["ops", "Try", "into_result"];
-                    let path = P(self.expr_std_path(unstable_span, path, ThinVec::new()));
+                    let path = P(self.expr_std_path(
+                            unstable_span, path, None, ThinVec::new()));
                     P(self.expr_call(e.span, path, hir_vec![sub_expr]))
                 };
 
@@ -3732,7 +4114,8 @@ impl<'a> LoweringContext<'a> {
                     let err_local = self.pat_ident(e.span, err_ident);
                     let from_expr = {
                         let path = &["convert", "From", "from"];
-                        let from = P(self.expr_std_path(e.span, path, ThinVec::new()));
+                        let from = P(self.expr_std_path(
+                                e.span, path, None, ThinVec::new()));
                         let err_expr = self.expr_ident(e.span, err_ident, err_local.id);
 
                         self.expr_call(e.span, from, hir_vec![err_expr])
@@ -3972,9 +4355,10 @@ impl<'a> LoweringContext<'a> {
         &mut self,
         span: Span,
         components: &[&str],
+        params: Option<P<hir::GenericArgs>>,
         attrs: ThinVec<Attribute>,
     ) -> hir::Expr {
-        let path = self.std_path(span, components, true);
+        let path = self.std_path(span, components, params, true);
         self.expr(
             span,
             hir::ExprPath(hir::QPath::Resolved(None, P(path))),
@@ -4099,7 +4483,7 @@ impl<'a> LoweringContext<'a> {
         components: &[&str],
         subpats: hir::HirVec<P<hir::Pat>>,
     ) -> P<hir::Pat> {
-        let path = self.std_path(span, components, true);
+        let path = self.std_path(span, components, None, true);
         let qpath = hir::QPath::Resolved(None, P(path));
         let pt = if subpats.is_empty() {
             hir::PatKind::Path(qpath)
@@ -4146,9 +4530,15 @@ impl<'a> LoweringContext<'a> {
     /// Given suffix ["b","c","d"], returns path `::std::b::c::d` when
     /// `fld.cx.use_std`, and `::core::b::c::d` otherwise.
     /// The path is also resolved according to `is_value`.
-    fn std_path(&mut self, span: Span, components: &[&str], is_value: bool) -> hir::Path {
+    fn std_path(
+        &mut self,
+        span: Span,
+        components: &[&str],
+        params: Option<P<hir::GenericArgs>>,
+        is_value: bool
+    ) -> hir::Path {
         self.resolver
-            .resolve_str_path(span, self.crate_root, components, is_value)
+            .resolve_str_path(span, self.crate_root, components, params, is_value)
     }
 
     fn ty_path(&mut self, id: LoweredNodeId, span: Span, qpath: hir::QPath) -> P<hir::Ty> {
@@ -4280,7 +4670,7 @@ impl<'a> LoweringContext<'a> {
         unstable_span: Span,
     ) -> P<hir::Expr> {
         let path = &["ops", "Try", method];
-        let from_err = P(self.expr_std_path(unstable_span, path,
+        let from_err = P(self.expr_std_path(unstable_span, path, None,
                                             ThinVec::new()));
         P(self.expr_call(e.span, from_err, hir_vec![e]))
     }
diff --git a/src/librustc/hir/map/blocks.rs b/src/librustc/hir/map/blocks.rs
index 362c0bf07f7..f665ced3dbc 100644
--- a/src/librustc/hir/map/blocks.rs
+++ b/src/librustc/hir/map/blocks.rs
@@ -25,7 +25,6 @@ use hir as ast;
 use hir::map::{self, Node};
 use hir::{Expr, FnDecl};
 use hir::intravisit::FnKind;
-use rustc_target::spec::abi;
 use syntax::ast::{Attribute, Name, NodeId};
 use syntax_pos::Span;
 
@@ -105,9 +104,7 @@ impl<'a> Code<'a> {
 struct ItemFnParts<'a> {
     name:     Name,
     decl:     &'a ast::FnDecl,
-    unsafety: ast::Unsafety,
-    constness: ast::Constness,
-    abi:      abi::Abi,
+    header:   ast::FnHeader,
     vis:      &'a ast::Visibility,
     generics: &'a ast::Generics,
     body:     ast::BodyId,
@@ -183,31 +180,31 @@ impl<'a> FnLikeNode<'a> {
 
     pub fn constness(self) -> ast::Constness {
         match self.kind() {
-            FnKind::ItemFn(_, _, _, constness, ..) => {
-                constness
-            }
-            FnKind::Method(_, m, ..) => {
-                m.constness
-            }
+            FnKind::ItemFn(_, _, header, ..) => header.constness,
+            FnKind::Method(_, m, ..) => m.header.constness,
             _ => ast::Constness::NotConst
         }
     }
 
+    pub fn asyncness(self) -> ast::IsAsync {
+        match self.kind() {
+            FnKind::ItemFn(_, _, header, ..) => header.asyncness,
+            FnKind::Method(_, m, ..) => m.header.asyncness,
+            _ => ast::IsAsync::NotAsync
+        }
+    }
+
     pub fn unsafety(self) -> ast::Unsafety {
         match self.kind() {
-            FnKind::ItemFn(_, _, unsafety, ..) => {
-                unsafety
-            }
-            FnKind::Method(_, m, ..) => {
-                m.unsafety
-            }
+            FnKind::ItemFn(_, _, header, ..) => header.unsafety,
+            FnKind::Method(_, m, ..) => m.header.unsafety,
             _ => ast::Unsafety::Normal
         }
     }
 
     pub fn kind(self) -> FnKind<'a> {
         let item = |p: ItemFnParts<'a>| -> FnKind<'a> {
-            FnKind::ItemFn(p.name, p.generics, p.unsafety, p.constness, p.abi, p.vis, p.attrs)
+            FnKind::ItemFn(p.name, p.generics, p.header, p.vis, p.attrs)
         };
         let closure = |c: ClosureParts<'a>| {
             FnKind::Closure(c.attrs)
@@ -232,19 +229,17 @@ impl<'a> FnLikeNode<'a> {
     {
         match self.node {
             map::NodeItem(i) => match i.node {
-                ast::ItemFn(ref decl, unsafety, constness, abi, ref generics, block) =>
+                ast::ItemFn(ref decl, header, ref generics, block) =>
                     item_fn(ItemFnParts {
                         id: i.id,
                         name: i.name,
                         decl: &decl,
-                        unsafety,
                         body: block,
-                        generics,
-                        abi,
                         vis: &i.vis,
-                        constness,
                         span: i.span,
                         attrs: &i.attrs,
+                        header,
+                        generics,
                     }),
                 _ => bug!("item FnLikeNode that is not fn-like"),
             },
diff --git a/src/librustc/hir/map/def_collector.rs b/src/librustc/hir/map/def_collector.rs
index 8aa5dd4ad80..7c71401c8b2 100644
--- a/src/librustc/hir/map/def_collector.rs
+++ b/src/librustc/hir/map/def_collector.rs
@@ -73,6 +73,27 @@ impl<'a> DefCollector<'a> {
         self.parent_def = parent;
     }
 
+    fn visit_async_fn(
+        &mut self,
+        id: NodeId,
+        async_node_id: NodeId,
+        name: Name,
+        span: Span,
+        visit_fn: impl FnOnce(&mut DefCollector<'a>)
+    ) {
+        // For async functions, we need to create their inner defs inside of a
+        // closure to match their desugared representation.
+        let fn_def_data = DefPathData::ValueNs(name.as_interned_str());
+        let fn_def = self.create_def(id, fn_def_data, ITEM_LIKE_SPACE, span);
+        return self.with_parent(fn_def, |this| {
+            let closure_def = this.create_def(async_node_id,
+                                  DefPathData::ClosureExpr,
+                                  REGULAR_SPACE,
+                                  span);
+            this.with_parent(closure_def, visit_fn)
+        })
+    }
+
     fn visit_macro_invoc(&mut self, id: NodeId) {
         if let Some(ref mut visit) = self.visit_macro_invoc {
             visit(MacroInvocationData {
@@ -99,6 +120,15 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> {
             ItemKind::Mod(..) if i.ident == keywords::Invalid.ident() => {
                 return visit::walk_item(self, i);
             }
+            ItemKind::Fn(_, FnHeader { asyncness: IsAsync::Async(async_node_id), .. }, ..) => {
+                return self.visit_async_fn(
+                    i.id,
+                    async_node_id,
+                    i.ident.name,
+                    i.span,
+                    |this| visit::walk_item(this, i)
+                )
+            }
             ItemKind::Mod(..) => DefPathData::Module(i.ident.name.as_interned_str()),
             ItemKind::Static(..) | ItemKind::Const(..) | ItemKind::Fn(..) =>
                 DefPathData::ValueNs(i.ident.name.as_interned_str()),
@@ -197,6 +227,17 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> {
 
     fn visit_impl_item(&mut self, ii: &'a ImplItem) {
         let def_data = match ii.node {
+            ImplItemKind::Method(MethodSig {
+                header: FnHeader { asyncness: IsAsync::Async(async_node_id), .. }, ..
+            }, ..) => {
+                return self.visit_async_fn(
+                    ii.id,
+                    async_node_id,
+                    ii.ident.name,
+                    ii.span,
+                    |this| visit::walk_impl_item(this, ii)
+                )
+            }
             ImplItemKind::Method(..) | ImplItemKind::Const(..) =>
                 DefPathData::ValueNs(ii.ident.name.as_interned_str()),
             ImplItemKind::Type(..) => DefPathData::AssocTypeInImpl(ii.ident.name.as_interned_str()),
@@ -227,15 +268,32 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> {
 
         match expr.node {
             ExprKind::Mac(..) => return self.visit_macro_invoc(expr.id),
-            ExprKind::Closure(..) => {
-                let def = self.create_def(expr.id,
+            ExprKind::Closure(_, asyncness, ..) => {
+                let closure_def = self.create_def(expr.id,
                                           DefPathData::ClosureExpr,
                                           REGULAR_SPACE,
                                           expr.span);
-                self.parent_def = Some(def);
+                self.parent_def = Some(closure_def);
+
+                // Async closures desugar to closures inside of closures, so
+                // we must create two defs.
+                if let IsAsync::Async(async_id) = asyncness {
+                    let async_def = self.create_def(async_id,
+                                                    DefPathData::ClosureExpr,
+                                                    REGULAR_SPACE,
+                                                    expr.span);
+                    self.parent_def = Some(async_def);
+                }
+            }
+            ExprKind::Async(_, async_id, _) => {
+                let async_def = self.create_def(async_id,
+                                                DefPathData::ClosureExpr,
+                                                REGULAR_SPACE,
+                                                expr.span);
+                self.parent_def = Some(async_def);
             }
             _ => {}
-        }
+        };
 
         visit::walk_expr(self, expr);
         self.parent_def = parent_def;
diff --git a/src/librustc/hir/map/mod.rs b/src/librustc/hir/map/mod.rs
index c2c8c7a391b..1e03381861b 100644
--- a/src/librustc/hir/map/mod.rs
+++ b/src/librustc/hir/map/mod.rs
@@ -174,7 +174,7 @@ impl<'hir> MapEntry<'hir> {
         match self {
             EntryItem(_, _, ref item) => {
                 match item.node {
-                    ItemFn(ref fn_decl, _, _, _, _, _) => Some(&fn_decl),
+                    ItemFn(ref fn_decl, _, _, _) => Some(&fn_decl),
                     _ => None,
                 }
             }
@@ -210,7 +210,7 @@ impl<'hir> MapEntry<'hir> {
                 match item.node {
                     ItemConst(_, body) |
                     ItemStatic(.., body) |
-                    ItemFn(_, _, _, _, _, body) => Some(body),
+                    ItemFn(_, _, _, body) => Some(body),
                     _ => None,
                 }
             }
diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs
index f6876113c11..5e41c51abd9 100644
--- a/src/librustc/hir/mod.rs
+++ b/src/librustc/hir/mod.rs
@@ -255,7 +255,7 @@ impl LifetimeName {
         }
     }
 
-    fn is_elided(&self) -> bool {
+    pub fn is_elided(&self) -> bool {
         use self::LifetimeName::*;
         match self {
             Implicit | Underscore => true,
@@ -1506,9 +1506,7 @@ pub struct MutTy {
 /// Represents a method's signature in a trait declaration or implementation.
 #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
 pub struct MethodSig {
-    pub unsafety: Unsafety,
-    pub constness: Constness,
-    pub abi: Abi,
+    pub header: FnHeader,
     pub decl: P<FnDecl>,
 }
 
@@ -1736,7 +1734,13 @@ pub enum IsAuto {
     No
 }
 
-#[derive(Copy, Clone, PartialEq, Eq,PartialOrd, Ord, RustcEncodable, RustcDecodable, Hash, Debug)]
+#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, RustcEncodable, RustcDecodable, Hash, Debug)]
+pub enum IsAsync {
+    Async,
+    NotAsync,
+}
+
+#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, RustcEncodable, RustcDecodable, Hash, Debug)]
 pub enum Unsafety {
     Unsafe,
     Normal,
@@ -2012,6 +2016,14 @@ pub struct Item {
     pub span: Span,
 }
 
+#[derive(Clone, Copy, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
+pub struct FnHeader {
+    pub unsafety: Unsafety,
+    pub constness: Constness,
+    pub asyncness: IsAsync,
+    pub abi: Abi,
+}
+
 #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
 pub enum Item_ {
     /// An `extern crate` item, with optional *original* crate name if the crate was renamed.
@@ -2031,7 +2043,7 @@ pub enum Item_ {
     /// A `const` item
     ItemConst(P<Ty>, BodyId),
     /// A function declaration
-    ItemFn(P<FnDecl>, Unsafety, Constness, Abi, Generics, BodyId),
+    ItemFn(P<FnDecl>, FnHeader, Generics, BodyId),
     /// A module
     ItemMod(Mod),
     /// An external module
@@ -2096,7 +2108,7 @@ impl Item_ {
 
     pub fn generics(&self) -> Option<&Generics> {
         Some(match *self {
-            ItemFn(_, _, _, _, ref generics, _) |
+            ItemFn(_, _, ref generics, _) |
             ItemTy(_, ref generics) |
             ItemEnum(_, ref generics) |
             ItemStruct(_, ref generics) |
diff --git a/src/librustc/hir/print.rs b/src/librustc/hir/print.rs
index 14f780fab7f..51a7504efcf 100644
--- a/src/librustc/hir/print.rs
+++ b/src/librustc/hir/print.rs
@@ -459,9 +459,12 @@ impl<'a> State<'a> {
             hir::ForeignItemFn(ref decl, ref arg_names, ref generics) => {
                 self.head("")?;
                 self.print_fn(decl,
-                              hir::Unsafety::Normal,
-                              hir::Constness::NotConst,
-                              Abi::Rust,
+                              hir::FnHeader {
+                                  unsafety: hir::Unsafety::Normal,
+                                  constness: hir::Constness::NotConst,
+                                  abi: Abi::Rust,
+                                  asyncness: hir::IsAsync::NotAsync,
+                              },
                               Some(item.name),
                               generics,
                               &item.vis,
@@ -598,12 +601,10 @@ impl<'a> State<'a> {
                 self.s.word(";")?;
                 self.end()?; // end the outer cbox
             }
-            hir::ItemFn(ref decl, unsafety, constness, abi, ref typarams, body) => {
+            hir::ItemFn(ref decl, header, ref typarams, body) => {
                 self.head("")?;
                 self.print_fn(decl,
-                              unsafety,
-                              constness,
-                              abi,
+                              header,
                               Some(item.name),
                               typarams,
                               &item.vis,
@@ -935,9 +936,7 @@ impl<'a> State<'a> {
                             body_id: Option<hir::BodyId>)
                             -> io::Result<()> {
         self.print_fn(&m.decl,
-                      m.unsafety,
-                      m.constness,
-                      m.abi,
+                      m.header,
                       Some(name),
                       generics,
                       vis,
@@ -1986,16 +1985,14 @@ impl<'a> State<'a> {
 
     pub fn print_fn(&mut self,
                     decl: &hir::FnDecl,
-                    unsafety: hir::Unsafety,
-                    constness: hir::Constness,
-                    abi: Abi,
+                    header: hir::FnHeader,
                     name: Option<ast::Name>,
                     generics: &hir::Generics,
                     vis: &hir::Visibility,
                     arg_names: &[Spanned<ast::Name>],
                     body_id: Option<hir::BodyId>)
                     -> io::Result<()> {
-        self.print_fn_header_info(unsafety, constness, abi, vis)?;
+        self.print_fn_header_info(header, vis)?;
 
         if let Some(name) = name {
             self.nbsp()?;
@@ -2260,9 +2257,12 @@ impl<'a> State<'a> {
             span: syntax_pos::DUMMY_SP,
         };
         self.print_fn(decl,
-                      unsafety,
-                      hir::Constness::NotConst,
-                      abi,
+                      hir::FnHeader {
+                          unsafety,
+                          abi,
+                          constness: hir::Constness::NotConst,
+                          asyncness: hir::IsAsync::NotAsync,
+                      },
                       name,
                       &generics,
                       &hir::Inherited,
@@ -2333,22 +2333,26 @@ impl<'a> State<'a> {
     }
 
     pub fn print_fn_header_info(&mut self,
-                                unsafety: hir::Unsafety,
-                                constness: hir::Constness,
-                                abi: Abi,
+                                header: hir::FnHeader,
                                 vis: &hir::Visibility)
                                 -> io::Result<()> {
         self.s.word(&visibility_qualified(vis, ""))?;
-        self.print_unsafety(unsafety)?;
 
-        match constness {
+        match header.constness {
             hir::Constness::NotConst => {}
             hir::Constness::Const => self.word_nbsp("const")?,
         }
 
-        if abi != Abi::Rust {
+        match header.asyncness {
+            hir::IsAsync::NotAsync => {}
+            hir::IsAsync::Async => self.word_nbsp("async")?,
+        }
+
+        self.print_unsafety(header.unsafety)?;
+
+        if header.abi != Abi::Rust {
             self.word_nbsp("extern")?;
-            self.word_nbsp(&abi.to_string())?;
+            self.word_nbsp(&header.abi.to_string())?;
         }
 
         self.s.word("fn")
diff --git a/src/librustc/ich/impls_hir.rs b/src/librustc/ich/impls_hir.rs
index 882194ae64e..b1429247ab0 100644
--- a/src/librustc/ich/impls_hir.rs
+++ b/src/librustc/ich/impls_hir.rs
@@ -272,9 +272,7 @@ impl_stable_hash_for!(struct hir::MutTy {
 });
 
 impl_stable_hash_for!(struct hir::MethodSig {
-    unsafety,
-    constness,
-    abi,
+    header,
     decl
 });
 
@@ -285,6 +283,13 @@ impl_stable_hash_for!(struct hir::TypeBinding {
     span
 });
 
+impl_stable_hash_for!(struct hir::FnHeader {
+    unsafety,
+    constness,
+    asyncness,
+    abi
+});
+
 impl<'a> HashStable<StableHashingContext<'a>> for hir::Ty {
     fn hash_stable<W: StableHasherResult>(&self,
                                           hcx: &mut StableHashingContext<'a>,
@@ -897,7 +902,7 @@ impl_stable_hash_for!(enum hir::Item_ {
     ItemUse(path, use_kind),
     ItemStatic(ty, mutability, body_id),
     ItemConst(ty, body_id),
-    ItemFn(fn_decl, unsafety, constness, abi, generics, body_id),
+    ItemFn(fn_decl, header, generics, body_id),
     ItemMod(module),
     ItemForeignMod(foreign_mod),
     ItemGlobalAsm(global_asm),
@@ -1100,6 +1105,10 @@ impl_stable_hash_for!(enum hir::Unsafety {
     Normal
 });
 
+impl_stable_hash_for!(enum hir::IsAsync {
+    Async,
+    NotAsync
+});
 
 impl_stable_hash_for!(enum hir::Constness {
     Const,
diff --git a/src/librustc/ich/impls_syntax.rs b/src/librustc/ich/impls_syntax.rs
index 7b14831cf95..0f4603be39d 100644
--- a/src/librustc/ich/impls_syntax.rs
+++ b/src/librustc/ich/impls_syntax.rs
@@ -409,6 +409,7 @@ impl_stable_hash_for!(enum ::syntax_pos::hygiene::ExpnFormat {
 });
 
 impl_stable_hash_for!(enum ::syntax_pos::hygiene::CompilerDesugaringKind {
+    Async,
     DotFill,
     QuestionMark,
     ExistentialReturnType,
diff --git a/src/librustc/middle/reachable.rs b/src/librustc/middle/reachable.rs
index 7f81af7e46c..95829346ede 100644
--- a/src/librustc/middle/reachable.rs
+++ b/src/librustc/middle/reachable.rs
@@ -238,8 +238,8 @@ impl<'a, 'tcx> ReachableContext<'a, 'tcx> {
             // If we are building an executable, only explicitly extern
             // types need to be exported.
             if let hir_map::NodeItem(item) = *node {
-                let reachable = if let hir::ItemFn(.., abi, _, _) = item.node {
-                    abi != Abi::Rust
+                let reachable = if let hir::ItemFn(_, header, ..) = item.node {
+                    header.abi != Abi::Rust
                 } else {
                     false
                 };
diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs
index 025ee0f3d74..efb3eecd691 100644
--- a/src/librustc/middle/resolve_lifetime.rs
+++ b/src/librustc/middle/resolve_lifetime.rs
@@ -476,7 +476,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
 
     fn visit_item(&mut self, item: &'tcx hir::Item) {
         match item.node {
-            hir::ItemFn(ref decl, _, _, _, ref generics, _) => {
+            hir::ItemFn(ref decl, _, ref generics, _) => {
                 self.visit_early_late(None, decl, generics, |this| {
                     intravisit::walk_item(this, item);
                 });
diff --git a/src/librustc_allocator/expand.rs b/src/librustc_allocator/expand.rs
index ec0676259ef..78406e88c75 100644
--- a/src/librustc_allocator/expand.rs
+++ b/src/librustc_allocator/expand.rs
@@ -10,12 +10,11 @@
 
 use rustc::middle::allocator::AllocatorKind;
 use rustc_errors;
-use rustc_target::spec::abi::Abi;
 use syntax::ast::{Attribute, Crate, LitKind, StrStyle};
-use syntax::ast::{Arg, Constness, Generics, Mac, Mutability, Ty, Unsafety};
+use syntax::ast::{Arg, FnHeader, Generics, Mac, Mutability, Ty, Unsafety};
 use syntax::ast::{self, Expr, Ident, Item, ItemKind, TyKind, VisibilityKind};
 use syntax::attr;
-use syntax::codemap::{dummy_spanned, respan};
+use syntax::codemap::respan;
 use syntax::codemap::{ExpnInfo, MacroAttribute, NameAndSpan};
 use syntax::ext::base::ExtCtxt;
 use syntax::ext::base::Resolver;
@@ -152,9 +151,10 @@ impl<'a> AllocFnFactory<'a> {
         let (output_ty, output_expr) = self.ret_ty(&method.output, result);
         let kind = ItemKind::Fn(
             self.cx.fn_decl(abi_args, ast::FunctionRetTy::Ty(output_ty)),
-            Unsafety::Unsafe,
-            dummy_spanned(Constness::NotConst),
-            Abi::Rust,
+            FnHeader {
+                unsafety: Unsafety::Unsafe,
+                ..FnHeader::default()
+            },
             Generics::default(),
             self.cx.block_expr(output_expr),
         );
diff --git a/src/librustc_driver/pretty.rs b/src/librustc_driver/pretty.rs
index 67720e61e91..38ecbf5ca8a 100644
--- a/src/librustc_driver/pretty.rs
+++ b/src/librustc_driver/pretty.rs
@@ -712,8 +712,8 @@ impl<'a> fold::Folder for ReplaceBodyWithLoop<'a> {
     fn fold_item_kind(&mut self, i: ast::ItemKind) -> ast::ItemKind {
         let is_const = match i {
             ast::ItemKind::Static(..) | ast::ItemKind::Const(..) => true,
-            ast::ItemKind::Fn(ref decl, _, ref constness, _, _, _) =>
-                constness.node == ast::Constness::Const || Self::should_ignore_fn(decl),
+            ast::ItemKind::Fn(ref decl, ref header, _, _) =>
+                header.constness.node == ast::Constness::Const || Self::should_ignore_fn(decl),
             _ => false,
         };
         self.run(is_const, |s| fold::noop_fold_item_kind(i, s))
@@ -722,8 +722,8 @@ impl<'a> fold::Folder for ReplaceBodyWithLoop<'a> {
     fn fold_trait_item(&mut self, i: ast::TraitItem) -> SmallVector<ast::TraitItem> {
         let is_const = match i.node {
             ast::TraitItemKind::Const(..) => true,
-            ast::TraitItemKind::Method(ast::MethodSig { ref decl, ref constness, .. }, _) =>
-                constness.node == ast::Constness::Const || Self::should_ignore_fn(decl),
+            ast::TraitItemKind::Method(ast::MethodSig { ref decl, ref header, .. }, _) =>
+                header.constness.node == ast::Constness::Const || Self::should_ignore_fn(decl),
             _ => false,
         };
         self.run(is_const, |s| fold::noop_fold_trait_item(i, s))
@@ -732,8 +732,8 @@ impl<'a> fold::Folder for ReplaceBodyWithLoop<'a> {
     fn fold_impl_item(&mut self, i: ast::ImplItem) -> SmallVector<ast::ImplItem> {
         let is_const = match i.node {
             ast::ImplItemKind::Const(..) => true,
-            ast::ImplItemKind::Method(ast::MethodSig { ref decl, ref constness, .. }, _) =>
-                constness.node == ast::Constness::Const || Self::should_ignore_fn(decl),
+            ast::ImplItemKind::Method(ast::MethodSig { ref decl, ref header, .. }, _) =>
+                header.constness.node == ast::Constness::Const || Self::should_ignore_fn(decl),
             _ => false,
         };
         self.run(is_const, |s| fold::noop_fold_impl_item(i, s))
diff --git a/src/librustc_lint/bad_style.rs b/src/librustc_lint/bad_style.rs
index 8f8fe04fd8e..1b5361187f3 100644
--- a/src/librustc_lint/bad_style.rs
+++ b/src/librustc_lint/bad_style.rs
@@ -284,9 +284,9 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NonSnakeCase {
                     _ => (),
                 }
             }
-            FnKind::ItemFn(name, _, _, _, abi, _, attrs) => {
+            FnKind::ItemFn(name, _, header, _, attrs) => {
                 // Skip foreign-ABI #[no_mangle] functions (Issue #31924)
-                if abi != Abi::Rust && attr::find_by_name(attrs, "no_mangle").is_some() {
+                if header.abi != Abi::Rust && attr::find_by_name(attrs, "no_mangle").is_some() {
                     return;
                 }
                 self.check_snake_case(cx, "function", &name.as_str(), Some(span))
diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs
index 941fabe26a6..d6120ab2079 100644
--- a/src/librustc_lint/builtin.rs
+++ b/src/librustc_lint/builtin.rs
@@ -259,12 +259,12 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnsafeCode {
                 span: Span,
                 _: ast::NodeId) {
         match fk {
-            FnKind::ItemFn(_, _, hir::Unsafety::Unsafe, ..) => {
+            FnKind::ItemFn(_, _, hir::FnHeader { unsafety: hir::Unsafety::Unsafe, .. }, ..) => {
                 self.report_unsafe(cx, span, "declaration of an `unsafe` function")
             }
 
             FnKind::Method(_, sig, ..) => {
-                if sig.unsafety == hir::Unsafety::Unsafe {
+                if sig.header.unsafety == hir::Unsafety::Unsafe {
                     self.report_unsafe(cx, span, "implementation of an `unsafe` method")
                 }
             }
@@ -275,7 +275,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnsafeCode {
 
     fn check_trait_item(&mut self, cx: &LateContext, item: &hir::TraitItem) {
         if let hir::TraitItemKind::Method(ref sig, hir::TraitMethod::Required(_)) = item.node {
-            if sig.unsafety == hir::Unsafety::Unsafe {
+            if sig.header.unsafety == hir::Unsafety::Unsafe {
                 self.report_unsafe(cx, item.span, "declaration of an `unsafe` method")
             }
         }
diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs
index cbe9615c693..ce270006a9d 100644
--- a/src/librustc_metadata/encoder.rs
+++ b/src/librustc_metadata/encoder.rs
@@ -917,7 +917,7 @@ impl<'a, 'b: 'a, 'tcx: 'b> IsolatedEncoder<'a, 'b, 'tcx> {
             ty::AssociatedKind::Method => {
                 let fn_data = if let hir::ImplItemKind::Method(ref sig, body) = ast_item.node {
                     FnData {
-                        constness: sig.constness,
+                        constness: sig.header.constness,
                         arg_names: self.encode_fn_arg_names_for_body(body),
                         sig: self.lazy(&tcx.fn_sig(def_id)),
                     }
@@ -941,7 +941,7 @@ impl<'a, 'b: 'a, 'tcx: 'b> IsolatedEncoder<'a, 'b, 'tcx> {
                     let needs_inline = (generics.requires_monomorphization(self.tcx) ||
                                         tcx.codegen_fn_attrs(def_id).requests_inline()) &&
                                         !self.metadata_output_only();
-                    let is_const_fn = sig.constness == hir::Constness::Const;
+                    let is_const_fn = sig.header.constness == hir::Constness::Const;
                     let always_encode_mir = self.tcx.sess.opts.debugging_opts.always_encode_mir;
                     needs_inline || is_const_fn || always_encode_mir
                 },
@@ -1045,9 +1045,9 @@ impl<'a, 'b: 'a, 'tcx: 'b> IsolatedEncoder<'a, 'b, 'tcx> {
                     self.encode_rendered_const_for_body(body_id)
                 )
             }
-            hir::ItemFn(_, _, constness, .., body) => {
+            hir::ItemFn(_, header, .., body) => {
                 let data = FnData {
-                    constness,
+                    constness: header.constness,
                     arg_names: self.encode_fn_arg_names_for_body(body),
                     sig: self.lazy(&tcx.fn_sig(def_id)),
                 };
@@ -1235,7 +1235,7 @@ impl<'a, 'b: 'a, 'tcx: 'b> IsolatedEncoder<'a, 'b, 'tcx> {
                     self.encode_optimized_mir(def_id)
                 }
                 hir::ItemConst(..) => self.encode_optimized_mir(def_id),
-                hir::ItemFn(_, _, constness, ..) => {
+                hir::ItemFn(_, header, ..) => {
                     let generics = tcx.generics_of(def_id);
                     let has_types = generics.params.iter().any(|param| match param.kind {
                         ty::GenericParamDefKind::Type { .. } => true,
@@ -1245,7 +1245,10 @@ impl<'a, 'b: 'a, 'tcx: 'b> IsolatedEncoder<'a, 'b, 'tcx> {
                         (has_types || tcx.codegen_fn_attrs(def_id).requests_inline()) &&
                             !self.metadata_output_only();
                     let always_encode_mir = self.tcx.sess.opts.debugging_opts.always_encode_mir;
-                    if needs_inline || constness == hir::Constness::Const || always_encode_mir {
+                    if needs_inline
+                        || header.constness == hir::Constness::Const
+                        || always_encode_mir
+                    {
                         self.encode_optimized_mir(def_id)
                     } else {
                         None
diff --git a/src/librustc_mir/transform/check_unsafety.rs b/src/librustc_mir/transform/check_unsafety.rs
index 5f8f9acae83..00e064fbb47 100644
--- a/src/librustc_mir/transform/check_unsafety.rs
+++ b/src/librustc_mir/transform/check_unsafety.rs
@@ -380,10 +380,10 @@ fn is_enclosed(tcx: TyCtxt,
         if used_unsafe.contains(&parent_id) {
             Some(("block".to_string(), parent_id))
         } else if let Some(hir::map::NodeItem(&hir::Item {
-            node: hir::ItemFn(_, fn_unsafety, _, _, _, _),
+            node: hir::ItemFn(_, header, _, _),
             ..
         })) = tcx.hir.find(parent_id) {
-            match fn_unsafety {
+            match header.unsafety {
                 hir::Unsafety::Unsafe => Some(("fn".to_string(), parent_id)),
                 hir::Unsafety::Normal => None,
             }
diff --git a/src/librustc_passes/ast_validation.rs b/src/librustc_passes/ast_validation.rs
index fc54d323b0f..25187032fb4 100644
--- a/src/librustc_passes/ast_validation.rs
+++ b/src/librustc_passes/ast_validation.rs
@@ -87,6 +87,13 @@ impl<'a> AstValidator<'a> {
         }
     }
 
+    fn check_trait_fn_not_async(&self, span: Span, asyncness: IsAsync) {
+        if asyncness.is_async() {
+            struct_span_err!(self.session, span, E0706,
+                             "trait fns cannot be declared `async`").emit()
+        }
+    }
+
     fn check_trait_fn_not_const(&self, constness: Spanned<Constness>) {
         match constness.node {
             Constness::Const => {
@@ -257,7 +264,8 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
                 for impl_item in impl_items {
                     self.invalid_visibility(&impl_item.vis, None);
                     if let ImplItemKind::Method(ref sig, _) = impl_item.node {
-                        self.check_trait_fn_not_const(sig.constness);
+                        self.check_trait_fn_not_const(sig.header.constness);
+                        self.check_trait_fn_not_async(impl_item.span, sig.header.asyncness);
                     }
                 }
             }
@@ -309,7 +317,8 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
                 self.no_questions_in_bounds(bounds, "supertraits", true);
                 for trait_item in trait_items {
                     if let TraitItemKind::Method(ref sig, ref block) = trait_item.node {
-                        self.check_trait_fn_not_const(sig.constness);
+                        self.check_trait_fn_not_async(trait_item.span, sig.header.asyncness);
+                        self.check_trait_fn_not_const(sig.header.constness);
                         if block.is_none() {
                             self.check_decl_no_pat(&sig.decl, |span, mut_ident| {
                                 if mut_ident {
diff --git a/src/librustc_passes/diagnostics.rs b/src/librustc_passes/diagnostics.rs
index d031694d853..f1ec3371c3b 100644
--- a/src/librustc_passes/diagnostics.rs
+++ b/src/librustc_passes/diagnostics.rs
@@ -310,4 +310,5 @@ register_diagnostics! {
     E0666, // nested `impl Trait` is illegal
     E0667, // `impl Trait` in projections
     E0696, // `continue` pointing to a labeled block
+    E0706, // `async fn` in trait
 }
diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs
index e311701ac05..792edf4d12b 100644
--- a/src/librustc_resolve/lib.rs
+++ b/src/librustc_resolve/lib.rs
@@ -55,7 +55,7 @@ use syntax::util::lev_distance::find_best_match_for_name;
 
 use syntax::visit::{self, FnKind, Visitor};
 use syntax::attr;
-use syntax::ast::{Arm, BindingMode, Block, Crate, Expr, ExprKind};
+use syntax::ast::{Arm, IsAsync, BindingMode, Block, Crate, Expr, ExprKind};
 use syntax::ast::{FnDecl, ForeignItem, ForeignItemKind, GenericParamKind, Generics};
 use syntax::ast::{Item, ItemKind, ImplItem, ImplItemKind};
 use syntax::ast::{Label, Local, Mutability, Pat, PatKind, Path};
@@ -746,15 +746,17 @@ impl<'a, 'tcx> Visitor<'tcx> for Resolver<'a> {
                 function_kind: FnKind<'tcx>,
                 declaration: &'tcx FnDecl,
                 _: Span,
-                node_id: NodeId) {
-        let rib_kind = match function_kind {
-            FnKind::ItemFn(..) => {
-                ItemRibKind
-            }
-            FnKind::Method(_, _, _, _) => {
-                TraitOrImplItemRibKind
-            }
-            FnKind::Closure(_) => ClosureRibKind(node_id),
+                node_id: NodeId)
+    {
+        let (rib_kind, asyncness) = match function_kind {
+            FnKind::ItemFn(_, ref header, ..) =>
+                (ItemRibKind, header.asyncness),
+            FnKind::Method(_, ref sig, _, _) =>
+                (TraitOrImplItemRibKind, sig.header.asyncness),
+            FnKind::Closure(_) =>
+                // Async closures aren't resolved through `visit_fn`-- they're
+                // processed separately
+                (ClosureRibKind(node_id), IsAsync::NotAsync),
         };
 
         // Create a value rib for the function.
@@ -774,7 +776,13 @@ impl<'a, 'tcx> Visitor<'tcx> for Resolver<'a> {
         }
         visit::walk_fn_ret_ty(self, &declaration.output);
 
-        // Resolve the function body.
+        // Resolve the function body, potentially inside the body of an async closure
+        if let IsAsync::Async(async_closure_id) = asyncness {
+            let rib_kind = ClosureRibKind(async_closure_id);
+            self.ribs[ValueNS].push(Rib::new(rib_kind));
+            self.label_ribs.push(Rib::new(rib_kind));
+        }
+
         match function_kind {
             FnKind::ItemFn(.., body) |
             FnKind::Method(.., body) => {
@@ -785,6 +793,12 @@ impl<'a, 'tcx> Visitor<'tcx> for Resolver<'a> {
             }
         };
 
+        // Leave the body of the async closure
+        if asyncness.is_async() {
+            self.label_ribs.pop();
+            self.ribs[ValueNS].pop();
+        }
+
         debug!("(resolving function) leaving function");
 
         self.label_ribs.pop();
@@ -1475,14 +1489,34 @@ impl<'a> hir::lowering::Resolver for Resolver<'a> {
                                  |resolver, span, error| resolve_error(resolver, span, error))
     }
 
-    fn resolve_str_path(&mut self, span: Span, crate_root: Option<&str>,
-                        components: &[&str], is_value: bool) -> hir::Path {
+    fn resolve_str_path(
+        &mut self,
+        span: Span,
+        crate_root: Option<&str>,
+        components: &[&str],
+        args: Option<P<hir::GenericArgs>>,
+        is_value: bool
+    ) -> hir::Path {
+        let mut segments = iter::once(keywords::CrateRoot.name())
+            .chain(
+                crate_root.into_iter()
+                    .chain(components.iter().cloned())
+                    .map(Symbol::intern)
+            ).map(hir::PathSegment::from_name).collect::<Vec<_>>();
+
+        if let Some(args) = args {
+            let name = segments.last().unwrap().name;
+            *segments.last_mut().unwrap() = hir::PathSegment {
+                name,
+                args: Some(args),
+                infer_types: true,
+            };
+        }
+
         let mut path = hir::Path {
             span,
             def: Def::Err,
-            segments: iter::once(keywords::CrateRoot.name()).chain({
-                crate_root.into_iter().chain(components.iter().cloned()).map(Symbol::intern)
-            }).map(hir::PathSegment::from_name).collect(),
+            segments: segments.into(),
         };
 
         self.resolve_hir_path(&mut path, is_value);
@@ -2058,9 +2092,9 @@ impl<'a> Resolver<'a> {
             ItemKind::Ty(_, ref generics) |
             ItemKind::Struct(_, ref generics) |
             ItemKind::Union(_, ref generics) |
-            ItemKind::Fn(.., ref generics, _) => {
+            ItemKind::Fn(_, _, ref generics, _) => {
                 self.with_type_parameter_rib(HasTypeParameters(generics, ItemRibKind),
-                                             |this| visit::walk_item(this, item));
+                                         |this| visit::walk_item(this, item));
             }
 
             ItemKind::Impl(.., ref generics, ref opt_trait_ref, ref self_type, ref impl_items) =>
@@ -2374,7 +2408,7 @@ impl<'a> Resolver<'a> {
                                                 visit::walk_impl_item(this, impl_item)
                                             );
                                         }
-                                        ImplItemKind::Method(_, _) => {
+                                        ImplItemKind::Method(..) => {
                                             // If this is a trait impl, ensure the method
                                             // exists in trait
                                             this.check_trait_item(impl_item.ident,
@@ -3888,6 +3922,49 @@ impl<'a> Resolver<'a> {
                 visit::walk_expr(self, expr);
                 self.current_type_ascription.pop();
             }
+            // Resolve the body of async exprs inside the async closure to which they desugar
+            ExprKind::Async(_, async_closure_id, ref block) => {
+                let rib_kind = ClosureRibKind(async_closure_id);
+                self.ribs[ValueNS].push(Rib::new(rib_kind));
+                self.label_ribs.push(Rib::new(rib_kind));
+                self.visit_block(&block);
+                self.label_ribs.pop();
+                self.ribs[ValueNS].pop();
+            }
+            // `async |x| ...` gets desugared to `|x| future_from_generator(|| ...)`, so we need to
+            // resolve the arguments within the proper scopes so that usages of them inside the
+            // closure are detected as upvars rather than normal closure arg usages.
+            ExprKind::Closure(
+                _, IsAsync::Async(inner_closure_id), _, ref fn_decl, ref body, _span) =>
+            {
+                let rib_kind = ClosureRibKind(expr.id);
+                self.ribs[ValueNS].push(Rib::new(rib_kind));
+                self.label_ribs.push(Rib::new(rib_kind));
+                // Resolve arguments:
+                let mut bindings_list = FxHashMap();
+                for argument in &fn_decl.inputs {
+                    self.resolve_pattern(&argument.pat, PatternSource::FnParam, &mut bindings_list);
+                    self.visit_ty(&argument.ty);
+                }
+                // No need to resolve return type-- the outer closure return type is
+                // FunctionRetTy::Default
+
+                // Now resolve the inner closure
+                {
+                    let rib_kind = ClosureRibKind(inner_closure_id);
+                    self.ribs[ValueNS].push(Rib::new(rib_kind));
+                    self.label_ribs.push(Rib::new(rib_kind));
+                    // No need to resolve arguments: the inner closure has none.
+                    // Resolve the return type:
+                    visit::walk_fn_ret_ty(self, &fn_decl.output);
+                    // Resolve the body
+                    self.visit_expr(body);
+                    self.label_ribs.pop();
+                    self.ribs[ValueNS].pop();
+                }
+                self.label_ribs.pop();
+                self.ribs[ValueNS].pop();
+            }
             _ => {
                 visit::walk_expr(self, expr);
             }
diff --git a/src/librustc_save_analysis/dump_visitor.rs b/src/librustc_save_analysis/dump_visitor.rs
index 7da5b1668b3..262c0e40abc 100644
--- a/src/librustc_save_analysis/dump_visitor.rs
+++ b/src/librustc_save_analysis/dump_visitor.rs
@@ -1555,7 +1555,7 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> Visitor<'l> for DumpVisitor<'l, 'tc
                     }
                 }
             }
-            ast::ExprKind::Closure(_, _, ref decl, ref body, _fn_decl_span) => {
+            ast::ExprKind::Closure(_, _, _, ref decl, ref body, _fn_decl_span) => {
                 let mut id = String::from("$");
                 id.push_str(&ex.id.to_string());
 
diff --git a/src/librustc_save_analysis/sig.rs b/src/librustc_save_analysis/sig.rs
index 7f2f0b0c837..9f2ca20276c 100644
--- a/src/librustc_save_analysis/sig.rs
+++ b/src/librustc_save_analysis/sig.rs
@@ -380,17 +380,20 @@ impl Sig for ast::Item {
 
                 Ok(extend_sig(ty, text, defs, vec![]))
             }
-            ast::ItemKind::Fn(ref decl, unsafety, constness, abi, ref generics, _) => {
+            ast::ItemKind::Fn(ref decl, header, ref generics, _) => {
                 let mut text = String::new();
-                if constness.node == ast::Constness::Const {
+                if header.constness.node == ast::Constness::Const {
                     text.push_str("const ");
                 }
-                if unsafety == ast::Unsafety::Unsafe {
+                if header.asyncness.is_async() {
+                    text.push_str("async ");
+                }
+                if header.unsafety == ast::Unsafety::Unsafe {
                     text.push_str("unsafe ");
                 }
-                if abi != ::rustc_target::spec::abi::Abi::Rust {
+                if header.abi != ::rustc_target::spec::abi::Abi::Rust {
                     text.push_str("extern");
-                    text.push_str(&abi.to_string());
+                    text.push_str(&header.abi.to_string());
                     text.push(' ');
                 }
                 text.push_str("fn ");
@@ -914,15 +917,18 @@ fn make_method_signature(
 ) -> Result {
     // FIXME code dup with function signature
     let mut text = String::new();
-    if m.constness.node == ast::Constness::Const {
+    if m.header.constness.node == ast::Constness::Const {
         text.push_str("const ");
     }
-    if m.unsafety == ast::Unsafety::Unsafe {
+    if m.header.asyncness.is_async() {
+        text.push_str("async ");
+    }
+    if m.header.unsafety == ast::Unsafety::Unsafe {
         text.push_str("unsafe ");
     }
-    if m.abi != ::rustc_target::spec::abi::Abi::Rust {
+    if m.header.abi != ::rustc_target::spec::abi::Abi::Rust {
         text.push_str("extern");
-        text.push_str(&m.abi.to_string());
+        text.push_str(&m.header.abi.to_string());
         text.push(' ');
     }
     text.push_str("fn ");
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index 366420cfcab..f149a9fe571 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -1164,7 +1164,7 @@ fn check_fn<'a, 'gcx, 'tcx>(inherited: &'a Inherited<'a, 'gcx, 'tcx>,
                     }
 
                     if let Node::NodeItem(item) = fcx.tcx.hir.get(fn_id) {
-                        if let Item_::ItemFn(_, _, _, _, ref generics, _) = item.node {
+                        if let Item_::ItemFn(_, _, ref generics, _) = item.node {
                             if !generics.params.is_empty() {
                                 fcx.tcx.sess.span_err(
                                     span,
diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs
index 4c849cad187..824346dab94 100644
--- a/src/librustc_typeck/collect.rs
+++ b/src/librustc_typeck/collect.rs
@@ -1181,13 +1181,13 @@ fn fn_sig<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     let icx = ItemCtxt::new(tcx, def_id);
 
     match tcx.hir.get(node_id) {
-        NodeTraitItem(&hir::TraitItem { node: TraitItemKind::Method(ref sig, _), .. }) |
-        NodeImplItem(&hir::ImplItem { node: ImplItemKind::Method(ref sig, _), .. }) => {
-            AstConv::ty_of_fn(&icx, sig.unsafety, sig.abi, &sig.decl)
+        NodeTraitItem(hir::TraitItem { node: TraitItemKind::Method(sig, _), .. }) |
+        NodeImplItem(hir::ImplItem { node: ImplItemKind::Method(sig, _), .. }) => {
+            AstConv::ty_of_fn(&icx, sig.header.unsafety, sig.header.abi, &sig.decl)
         }
 
-        NodeItem(&hir::Item { node: ItemFn(ref decl, unsafety, _, abi, _, _), .. }) => {
-            AstConv::ty_of_fn(&icx, unsafety, abi, decl)
+        NodeItem(hir::Item { node: ItemFn(decl, header, _, _), .. }) => {
+            AstConv::ty_of_fn(&icx, header.unsafety, header.abi, decl)
         }
 
         NodeForeignItem(&hir::ForeignItem { node: ForeignItemFn(ref fn_decl, _, _), .. }) => {
diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs
index 114cb0e455d..ad7389db729 100644
--- a/src/librustdoc/clean/inline.rs
+++ b/src/librustdoc/clean/inline.rs
@@ -198,9 +198,12 @@ fn build_external_function(cx: &DocContext, did: DefId) -> clean::Function {
     clean::Function {
         decl: (did, sig).clean(cx),
         generics: (cx.tcx.generics_of(did), &predicates).clean(cx),
-        unsafety: sig.unsafety(),
-        constness,
-        abi: sig.abi(),
+        header: hir::FnHeader {
+            unsafety: sig.unsafety(),
+            abi: sig.abi(),
+            constness,
+            asyncness: hir::IsAsync::NotAsync,
+        }
     }
 }
 
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index 0979c3d8558..057e7f3ab84 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -18,8 +18,8 @@ pub use self::SelfTy::*;
 pub use self::FunctionRetTy::*;
 pub use self::Visibility::{Public, Inherited};
 
-use syntax;
 use rustc_target::spec::abi::Abi;
+use syntax;
 use syntax::ast::{self, AttrStyle, NodeId, Ident};
 use syntax::attr;
 use syntax::codemap::{dummy_spanned, Spanned};
@@ -2074,10 +2074,8 @@ impl<'a, 'tcx> Clean<Generics> for (&'a ty::Generics,
 #[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
 pub struct Method {
     pub generics: Generics,
-    pub unsafety: hir::Unsafety,
-    pub constness: hir::Constness,
     pub decl: FnDecl,
-    pub abi: Abi,
+    pub header: hir::FnHeader,
 }
 
 impl<'a> Clean<Method> for (&'a hir::MethodSig, &'a hir::Generics, hir::BodyId) {
@@ -2088,28 +2086,23 @@ impl<'a> Clean<Method> for (&'a hir::MethodSig, &'a hir::Generics, hir::BodyId)
         Method {
             decl,
             generics,
-            unsafety: self.0.unsafety,
-            constness: self.0.constness,
-            abi: self.0.abi
+            header: self.0.header,
         }
     }
 }
 
 #[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
 pub struct TyMethod {
-    pub unsafety: hir::Unsafety,
+    pub header: hir::FnHeader,
     pub decl: FnDecl,
     pub generics: Generics,
-    pub abi: Abi,
 }
 
 #[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
 pub struct Function {
     pub decl: FnDecl,
     pub generics: Generics,
-    pub unsafety: hir::Unsafety,
-    pub constness: hir::Constness,
-    pub abi: Abi,
+    pub header: hir::FnHeader,
 }
 
 impl Clean<Item> for doctree::Function {
@@ -2128,9 +2121,7 @@ impl Clean<Item> for doctree::Function {
             inner: FunctionItem(Function {
                 decl,
                 generics,
-                unsafety: self.unsafety,
-                constness: self.constness,
-                abi: self.abi,
+                header: self.header,
             }),
         }
     }
@@ -2359,10 +2350,9 @@ impl Clean<Item> for hir::TraitItem {
                     (self.generics.clean(cx), (&*sig.decl, &names[..]).clean(cx))
                 });
                 TyMethodItem(TyMethod {
-                    unsafety: sig.unsafety.clone(),
+                    header: sig.header,
                     decl,
                     generics,
-                    abi: sig.abi
                 })
             }
             hir::TraitItemKind::Type(ref bounds, ref default) => {
@@ -2461,18 +2451,25 @@ impl<'tcx> Clean<Item> for ty::AssociatedItem {
                         hir::Constness::NotConst
                     };
                     MethodItem(Method {
-                        unsafety: sig.unsafety(),
                         generics,
                         decl,
-                        abi: sig.abi(),
-                        constness,
+                        header: hir::FnHeader {
+                            unsafety: sig.unsafety(),
+                            abi: sig.abi(),
+                            constness,
+                            asyncness: hir::IsAsync::NotAsync,
+                        }
                     })
                 } else {
                     TyMethodItem(TyMethod {
-                        unsafety: sig.unsafety(),
                         generics,
                         decl,
-                        abi: sig.abi(),
+                        header: hir::FnHeader {
+                            unsafety: sig.unsafety(),
+                            abi: sig.abi(),
+                            constness: hir::Constness::NotConst,
+                            asyncness: hir::IsAsync::NotAsync,
+                        }
                     })
                 }
             }
@@ -3697,9 +3694,9 @@ impl Clean<BareFunctionDecl> for hir::BareFnTy {
         });
         BareFunctionDecl {
             unsafety: self.unsafety,
+            abi: self.abi,
             decl,
             generic_params,
-            abi: self.abi,
         }
     }
 }
@@ -3994,7 +3991,7 @@ impl Clean<Vec<Item>> for hir::ForeignMod {
         let mut items = self.items.clean(cx);
         for item in &mut items {
             if let ForeignFunctionItem(ref mut f) = item.inner {
-                f.abi = self.abi;
+                f.header.abi = self.abi;
             }
         }
         items
@@ -4011,9 +4008,12 @@ impl Clean<Item> for hir::ForeignItem {
                 ForeignFunctionItem(Function {
                     decl,
                     generics,
-                    unsafety: hir::Unsafety::Unsafe,
-                    abi: Abi::Rust,
-                    constness: hir::Constness::NotConst,
+                    header: hir::FnHeader {
+                        unsafety: hir::Unsafety::Unsafe,
+                        abi: Abi::Rust,
+                        constness: hir::Constness::NotConst,
+                        asyncness: hir::IsAsync::NotAsync,
+                    },
                 })
             }
             hir::ForeignItemStatic(ref ty, mutbl) => {
diff --git a/src/librustdoc/doctree.rs b/src/librustdoc/doctree.rs
index 16d14bc56d6..0807db29976 100644
--- a/src/librustdoc/doctree.rs
+++ b/src/librustdoc/doctree.rs
@@ -13,7 +13,6 @@
 pub use self::StructType::*;
 pub use self::TypeBound::*;
 
-use rustc_target::spec::abi;
 use syntax::ast;
 use syntax::ast::{Name, NodeId};
 use syntax::attr;
@@ -149,11 +148,9 @@ pub struct Function {
     pub vis: hir::Visibility,
     pub stab: Option<attr::Stability>,
     pub depr: Option<attr::Deprecation>,
-    pub unsafety: hir::Unsafety,
-    pub constness: hir::Constness,
+    pub header: hir::FnHeader,
     pub whence: Span,
     pub generics: hir::Generics,
-    pub abi: abi::Abi,
     pub body: hir::BodyId,
 }
 
diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs
index 3d360f2f344..2377354b85f 100644
--- a/src/librustdoc/html/format.rs
+++ b/src/librustdoc/html/format.rs
@@ -39,6 +39,10 @@ pub struct UnsafetySpace(pub hir::Unsafety);
 /// with a space after it.
 #[derive(Copy, Clone)]
 pub struct ConstnessSpace(pub hir::Constness);
+/// Similarly to VisSpace, this structure is used to render a function asyncness
+/// with a space after it.
+#[derive(Copy, Clone)]
+pub struct AsyncSpace(pub hir::IsAsync);
 /// Similar to VisSpace, but used for mutability
 #[derive(Copy, Clone)]
 pub struct MutableSpace(pub clean::Mutability);
@@ -962,6 +966,15 @@ impl fmt::Display for ConstnessSpace {
     }
 }
 
+impl fmt::Display for AsyncSpace {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        match self.0 {
+            hir::IsAsync::Async => write!(f, "async "),
+            hir::IsAsync::NotAsync => Ok(()),
+        }
+    }
+}
+
 impl fmt::Display for clean::Import {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         match *self {
diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs
index 180591b3532..f7be4f58dfb 100644
--- a/src/librustdoc/html/render.rs
+++ b/src/librustdoc/html/render.rs
@@ -62,13 +62,12 @@ use rustc::middle::stability;
 use rustc::hir;
 use rustc::util::nodemap::{FxHashMap, FxHashSet};
 use rustc_data_structures::flock;
-use rustc_target::spec::abi;
 
 use clean::{self, AttributesExt, GetDefId, SelfTy, Mutability};
 use doctree;
 use fold::DocFolder;
 use html::escape::Escape;
-use html::format::{ConstnessSpace};
+use html::format::{AsyncSpace, ConstnessSpace};
 use html::format::{GenericBounds, WhereClause, href, AbiSpace};
 use html::format::{VisSpace, Method, UnsafetySpace, MutableSpace};
 use html::format::fmt_impl_for_trait_page;
@@ -2405,7 +2404,7 @@ fn item_module(w: &mut fmt::Formatter, cx: &Context,
 
                 let unsafety_flag = match myitem.inner {
                     clean::FunctionItem(ref func) | clean::ForeignFunctionItem(ref func)
-                    if func.unsafety == hir::Unsafety::Unsafe => {
+                    if func.header.unsafety == hir::Unsafety::Unsafe => {
                         "<a title='unsafe function' href='#'><sup>âš </sup></a>"
                     }
                     _ => "",
@@ -2575,21 +2574,24 @@ fn item_static(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item,
 
 fn item_function(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item,
                  f: &clean::Function) -> fmt::Result {
-    let name_len = format!("{}{}{}{:#}fn {}{:#}",
+    let name_len = format!("{}{}{}{}{:#}fn {}{:#}",
                            VisSpace(&it.visibility),
-                           ConstnessSpace(f.constness),
-                           UnsafetySpace(f.unsafety),
-                           AbiSpace(f.abi),
+                           ConstnessSpace(f.header.constness),
+                           UnsafetySpace(f.header.unsafety),
+                           AsyncSpace(f.header.asyncness),
+                           AbiSpace(f.header.abi),
                            it.name.as_ref().unwrap(),
                            f.generics).len();
     write!(w, "{}<pre class='rust fn'>", render_spotlight_traits(it)?)?;
     render_attributes(w, it)?;
     write!(w,
-           "{vis}{constness}{unsafety}{abi}fn {name}{generics}{decl}{where_clause}</pre>",
+           "{vis}{constness}{unsafety}{asyncness}{abi}fn \
+           {name}{generics}{decl}{where_clause}</pre>",
            vis = VisSpace(&it.visibility),
-           constness = ConstnessSpace(f.constness),
-           unsafety = UnsafetySpace(f.unsafety),
-           abi = AbiSpace(f.abi),
+           constness = ConstnessSpace(f.header.constness),
+           unsafety = UnsafetySpace(f.header.unsafety),
+           asyncness = AsyncSpace(f.header.asyncness),
+           abi = AbiSpace(f.header.abi),
            name = it.name.as_ref().unwrap(),
            generics = f.generics,
            where_clause = WhereClause { gens: &f.generics, indent: 0, end_newline: true },
@@ -2999,9 +3001,7 @@ fn render_assoc_item(w: &mut fmt::Formatter,
                      parent: ItemType) -> fmt::Result {
     fn method(w: &mut fmt::Formatter,
               meth: &clean::Item,
-              unsafety: hir::Unsafety,
-              constness: hir::Constness,
-              abi: abi::Abi,
+              header: hir::FnHeader,
               g: &clean::Generics,
               d: &clean::FnDecl,
               link: AssocItemLink,
@@ -3024,11 +3024,12 @@ fn render_assoc_item(w: &mut fmt::Formatter,
                 href(did).map(|p| format!("{}#{}.{}", p.0, ty, name)).unwrap_or(anchor)
             }
         };
-        let mut head_len = format!("{}{}{}{:#}fn {}{:#}",
+        let mut head_len = format!("{}{}{}{}{:#}fn {}{:#}",
                                    VisSpace(&meth.visibility),
-                                   ConstnessSpace(constness),
-                                   UnsafetySpace(unsafety),
-                                   AbiSpace(abi),
+                                   ConstnessSpace(header.constness),
+                                   UnsafetySpace(header.unsafety),
+                                   AsyncSpace(header.asyncness),
+                                   AbiSpace(header.abi),
                                    name,
                                    *g).len();
         let (indent, end_newline) = if parent == ItemType::Trait {
@@ -3038,12 +3039,13 @@ fn render_assoc_item(w: &mut fmt::Formatter,
             (0, true)
         };
         render_attributes(w, meth)?;
-        write!(w, "{}{}{}{}fn <a href='{href}' class='fnname'>{name}</a>\
+        write!(w, "{}{}{}{}{}fn <a href='{href}' class='fnname'>{name}</a>\
                    {generics}{decl}{where_clause}",
                VisSpace(&meth.visibility),
-               ConstnessSpace(constness),
-               UnsafetySpace(unsafety),
-               AbiSpace(abi),
+               ConstnessSpace(header.constness),
+               UnsafetySpace(header.unsafety),
+               AsyncSpace(header.asyncness),
+               AbiSpace(header.abi),
                href = href,
                name = name,
                generics = *g,
@@ -3061,12 +3063,10 @@ fn render_assoc_item(w: &mut fmt::Formatter,
     match item.inner {
         clean::StrippedItem(..) => Ok(()),
         clean::TyMethodItem(ref m) => {
-            method(w, item, m.unsafety, hir::Constness::NotConst,
-                   m.abi, &m.generics, &m.decl, link, parent)
+            method(w, item, m.header, &m.generics, &m.decl, link, parent)
         }
         clean::MethodItem(ref m) => {
-            method(w, item, m.unsafety, m.constness,
-                   m.abi, &m.generics, &m.decl, link, parent)
+            method(w, item, m.header, &m.generics, &m.decl, link, parent)
         }
         clean::AssociatedConstItem(ref ty, ref default) => {
             assoc_const(w, item, ty, default.as_ref(), link)
diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs
index 10b1a2e1e0b..6bf1931e468 100644
--- a/src/librustdoc/visit_ast.rs
+++ b/src/librustdoc/visit_ast.rs
@@ -13,7 +13,6 @@
 
 use std::mem;
 
-use rustc_target::spec::abi;
 use syntax::ast;
 use syntax::attr;
 use syntax_pos::Span;
@@ -172,9 +171,7 @@ impl<'a, 'tcx, 'rcx> RustdocVisitor<'a, 'tcx, 'rcx> {
 
     pub fn visit_fn(&mut self, item: &hir::Item,
                     name: ast::Name, fd: &hir::FnDecl,
-                    unsafety: &hir::Unsafety,
-                    constness: hir::Constness,
-                    abi: &abi::Abi,
+                    header: hir::FnHeader,
                     gen: &hir::Generics,
                     body: hir::BodyId) -> Function {
         debug!("Visiting fn");
@@ -188,9 +185,7 @@ impl<'a, 'tcx, 'rcx> RustdocVisitor<'a, 'tcx, 'rcx> {
             name,
             whence: item.span,
             generics: gen.clone(),
-            unsafety: *unsafety,
-            constness,
-            abi: *abi,
+            header,
             body,
         }
     }
@@ -463,9 +458,8 @@ impl<'a, 'tcx, 'rcx> RustdocVisitor<'a, 'tcx, 'rcx> {
                 om.structs.push(self.visit_variant_data(item, name, sd, gen)),
             hir::ItemUnion(ref sd, ref gen) =>
                 om.unions.push(self.visit_union_data(item, name, sd, gen)),
-            hir::ItemFn(ref fd, ref unsafety, constness, ref abi, ref gen, body) =>
-                om.fns.push(self.visit_fn(item, name, &**fd, unsafety,
-                                          constness, abi, gen, body)),
+            hir::ItemFn(ref fd, header, ref gen, body) =>
+                om.fns.push(self.visit_fn(item, name, &**fd, header, gen, body)),
             hir::ItemTy(ref ty, ref gen) => {
                 let t = Typedef {
                     ty: ty.clone(),
diff --git a/src/libstd/future.rs b/src/libstd/future.rs
new file mode 100644
index 00000000000..2da775fdc94
--- /dev/null
+++ b/src/libstd/future.rs
@@ -0,0 +1,116 @@
+// Copyright 2018 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.
+
+//! Asynchronous values.
+
+use core::cell::Cell;
+use core::marker::Unpin;
+use core::mem::PinMut;
+use core::option::Option;
+use core::ptr::NonNull;
+use core::task::{self, Poll};
+use core::ops::{Drop, Generator, GeneratorState};
+
+#[doc(inline)]
+pub use core::future::*;
+
+/// Wrap a future in a generator.
+///
+/// This function returns a `GenFuture` underneath, but hides it in `impl Trait` to give
+/// better error messages (`impl Future` rather than `GenFuture<[closure.....]>`).
+#[unstable(feature = "gen_future", issue = "50547")]
+pub fn from_generator<T: Generator<Yield = ()>>(x: T) -> impl Future<Output = T::Return> {
+    GenFuture(x)
+}
+
+/// A wrapper around generators used to implement `Future` for `async`/`await` code.
+#[unstable(feature = "gen_future", issue = "50547")]
+#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
+struct GenFuture<T: Generator<Yield = ()>>(T);
+
+// We rely on the fact that async/await futures are immovable in order to create
+// self-referential borrows in the underlying generator.
+impl<T: Generator<Yield = ()>> !Unpin for GenFuture<T> {}
+
+#[unstable(feature = "gen_future", issue = "50547")]
+impl<T: Generator<Yield = ()>> Future for GenFuture<T> {
+    type Output = T::Return;
+    fn poll(self: PinMut<Self>, cx: &mut task::Context) -> Poll<Self::Output> {
+        set_task_cx(cx, || match unsafe { PinMut::get_mut(self).0.resume() } {
+            GeneratorState::Yielded(()) => Poll::Pending,
+            GeneratorState::Complete(x) => Poll::Ready(x),
+        })
+    }
+}
+
+thread_local! {
+    static TLS_CX: Cell<Option<NonNull<task::Context<'static>>>> = Cell::new(None);
+}
+
+struct SetOnDrop(Option<NonNull<task::Context<'static>>>);
+
+impl Drop for SetOnDrop {
+    fn drop(&mut self) {
+        TLS_CX.with(|tls_cx| {
+            tls_cx.set(self.0.take());
+        });
+    }
+}
+
+#[unstable(feature = "gen_future", issue = "50547")]
+/// Sets the thread-local task context used by async/await futures.
+pub fn set_task_cx<F, R>(cx: &mut task::Context, f: F) -> R
+where
+    F: FnOnce() -> R
+{
+    let old_cx = TLS_CX.with(|tls_cx| {
+        tls_cx.replace(NonNull::new(
+            cx
+                as *mut task::Context
+                as *mut ()
+                as *mut task::Context<'static>
+        ))
+    });
+    let _reset_cx = SetOnDrop(old_cx);
+    f()
+}
+
+#[unstable(feature = "gen_future", issue = "50547")]
+/// Retrieves the thread-local task context used by async/await futures.
+///
+/// This function acquires exclusive access to the task context.
+///
+/// Panics if no task has been set or if the task context has already been
+/// retrived by a surrounding call to get_task_cx.
+pub fn get_task_cx<F, R>(f: F) -> R
+where
+    F: FnOnce(&mut task::Context) -> R
+{
+    let cx_ptr = TLS_CX.with(|tls_cx| {
+        // Clear the entry so that nested `with_get_cx` calls
+        // will fail or set their own value.
+        tls_cx.replace(None)
+    });
+    let _reset_cx = SetOnDrop(cx_ptr);
+
+    let mut cx_ptr = cx_ptr.expect(
+        "TLS task::Context not set. This is a rustc bug. \
+        Please file an issue on https://github.com/rust-lang/rust.");
+    unsafe { f(cx_ptr.as_mut()) }
+}
+
+#[unstable(feature = "gen_future", issue = "50547")]
+/// Polls a future in the current thread-local task context.
+pub fn poll_in_task_cx<F>(f: &mut PinMut<F>) -> Poll<F::Output>
+where
+    F: Future
+{
+    get_task_cx(|cx| f.reborrow().poll(cx))
+}
diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs
index a6061e96ae5..caad924ea5b 100644
--- a/src/libstd/lib.rs
+++ b/src/libstd/lib.rs
@@ -263,6 +263,7 @@
 #![feature(fn_traits)]
 #![feature(fnbox)]
 #![feature(futures_api)]
+#![feature(generator_trait)]
 #![feature(hashmap_internals)]
 #![feature(int_error_internals)]
 #![feature(integer_atomics)]
@@ -462,22 +463,6 @@ pub use core::u128;
 #[stable(feature = "core_hint", since = "1.27.0")]
 pub use core::hint;
 
-#[unstable(feature = "futures_api",
-           reason = "futures in libcore are unstable",
-           issue = "50547")]
-pub mod task {
-    //! Types and Traits for working with asynchronous tasks.
-    #[doc(inline)]
-    pub use core::task::*;
-    #[doc(inline)]
-    pub use alloc_crate::task::*;
-}
-
-#[unstable(feature = "futures_api",
-           reason = "futures in libcore are unstable",
-           issue = "50547")]
-pub use core::future;
-
 pub mod f32;
 pub mod f64;
 
@@ -499,6 +484,22 @@ pub mod process;
 pub mod sync;
 pub mod time;
 
+#[unstable(feature = "futures_api",
+           reason = "futures in libcore are unstable",
+           issue = "50547")]
+pub mod task {
+    //! Types and Traits for working with asynchronous tasks.
+    #[doc(inline)]
+    pub use core::task::*;
+    #[doc(inline)]
+    pub use alloc_crate::task::*;
+}
+
+#[unstable(feature = "futures_api",
+           reason = "futures in libcore are unstable",
+           issue = "50547")]
+pub mod future;
+
 // Platform-abstraction modules
 #[macro_use]
 mod sys_common;
diff --git a/src/libstd/macros.rs b/src/libstd/macros.rs
index 8da70f5717e..a856e7736fb 100644
--- a/src/libstd/macros.rs
+++ b/src/libstd/macros.rs
@@ -213,6 +213,25 @@ macro_rules! eprintln {
     ($fmt:expr, $($arg:tt)*) => (eprint!(concat!($fmt, "\n"), $($arg)*));
 }
 
+#[macro_export]
+#[unstable(feature = "await_macro", issue = "50547")]
+#[allow_internal_unstable]
+#[allow_internal_unsafe]
+macro_rules! await {
+    ($e:expr) => { {
+        let mut pinned = $e;
+        let mut pinned = unsafe { $crate::mem::PinMut::new_unchecked(&mut pinned) };
+        loop {
+            match $crate::future::poll_in_task_cx(&mut pinned) {
+                // FIXME(cramertj) prior to stabilizing await, we have to ensure that this
+                // can't be used to create a generator on stable via `|| await!()`.
+                $crate::task::Poll::Pending => yield,
+                $crate::task::Poll::Ready(x) => break x,
+            }
+        }
+    } }
+}
+
 /// A macro to select an event from a number of receivers.
 ///
 /// This macro is used to wait for the first event to occur on a number of
diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs
index c6de2c4da39..a57a9b95e5f 100644
--- a/src/libsyntax/ast.rs
+++ b/src/libsyntax/ast.rs
@@ -17,7 +17,7 @@ pub use util::ThinVec;
 pub use util::parser::ExprPrecedence;
 
 use syntax_pos::{Span, DUMMY_SP};
-use codemap::{respan, Spanned};
+use codemap::{dummy_spanned, respan, Spanned};
 use rustc_target::spec::abi::Abi;
 use ext::hygiene::{Mark, SyntaxContext};
 use print::pprust;
@@ -987,6 +987,7 @@ impl Expr {
             ExprKind::Closure(..) => ExprPrecedence::Closure,
             ExprKind::Block(..) => ExprPrecedence::Block,
             ExprKind::Catch(..) => ExprPrecedence::Catch,
+            ExprKind::Async(..) => ExprPrecedence::Async,
             ExprKind::Assign(..) => ExprPrecedence::Assign,
             ExprKind::AssignOp(..) => ExprPrecedence::AssignOp,
             ExprKind::Field(..) => ExprPrecedence::Field,
@@ -1094,9 +1095,18 @@ pub enum ExprKind {
     /// A closure (for example, `move |a, b, c| a + b + c`)
     ///
     /// The final span is the span of the argument block `|...|`
-    Closure(CaptureBy, Movability, P<FnDecl>, P<Expr>, Span),
+    Closure(CaptureBy, IsAsync, Movability, P<FnDecl>, P<Expr>, Span),
     /// A block (`'label: { ... }`)
     Block(P<Block>, Option<Label>),
+    /// An async block (`async move { ... }`)
+    ///
+    /// The `NodeId` is the `NodeId` for the closure that results from
+    /// desugaring an async block, just like the NodeId field in the
+    /// `IsAsync` enum. This is necessary in order to create a def for the
+    /// closure which can be used as a parent of any child defs. Defs
+    /// created during lowering cannot be made the parent of any other
+    /// preexisting defs.
+    Async(CaptureBy, NodeId, P<Block>),
     /// A catch block (`catch { ... }`)
     Catch(P<Block>),
 
@@ -1325,9 +1335,7 @@ pub struct MutTy {
 /// or in an implementation.
 #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
 pub struct MethodSig {
-    pub unsafety: Unsafety,
-    pub constness: Spanned<Constness>,
-    pub abi: Abi,
+    pub header: FnHeader,
     pub decl: P<FnDecl>,
 }
 
@@ -1709,6 +1717,22 @@ pub enum Unsafety {
 }
 
 #[derive(Copy, Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
+pub enum IsAsync {
+    Async(NodeId),
+    NotAsync,
+}
+
+impl IsAsync {
+    pub fn is_async(self) -> bool {
+        if let IsAsync::Async(_) = self {
+            true
+        } else {
+            false
+        }
+    }
+}
+
+#[derive(Copy, Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
 pub enum Constness {
     Const,
     NotConst,
@@ -2009,6 +2033,29 @@ pub struct Item {
     pub tokens: Option<TokenStream>,
 }
 
+/// A function header
+///
+/// All the information between the visibility & the name of the function is
+/// included in this struct (e.g. `async unsafe fn` or `const extern "C" fn`)
+#[derive(Clone, Copy, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
+pub struct FnHeader {
+    pub unsafety: Unsafety,
+    pub asyncness: IsAsync,
+    pub constness: Spanned<Constness>,
+    pub abi: Abi,
+}
+
+impl Default for FnHeader {
+    fn default() -> FnHeader {
+        FnHeader {
+            unsafety: Unsafety::Normal,
+            asyncness: IsAsync::NotAsync,
+            constness: dummy_spanned(Constness::NotConst),
+            abi: Abi::Rust,
+        }
+    }
+}
+
 #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
 pub enum ItemKind {
     /// An `extern crate` item, with optional *original* crate name if the crate was renamed.
@@ -2030,7 +2077,7 @@ pub enum ItemKind {
     /// A function declaration (`fn` or `pub fn`).
     ///
     /// E.g. `fn foo(bar: usize) -> usize { .. }`
-    Fn(P<FnDecl>, Unsafety, Spanned<Constness>, Abi, Generics, P<Block>),
+    Fn(P<FnDecl>, FnHeader, Generics, P<Block>),
     /// A module declaration (`mod` or `pub mod`).
     ///
     /// E.g. `mod foo;` or `mod foo { .. }`
diff --git a/src/libsyntax/ext/build.rs b/src/libsyntax/ext/build.rs
index 9044cab05d6..61356507665 100644
--- a/src/libsyntax/ext/build.rs
+++ b/src/libsyntax/ext/build.rs
@@ -915,6 +915,7 @@ impl<'a> AstBuilder for ExtCtxt<'a> {
                       fn_decl_span: Span) // span of the `|...|` part
                       -> P<ast::Expr> {
         self.expr(span, ast::ExprKind::Closure(ast::CaptureBy::Ref,
+                                               ast::IsAsync::NotAsync,
                                                ast::Movability::Movable,
                                                fn_decl,
                                                body,
@@ -935,6 +936,7 @@ impl<'a> AstBuilder for ExtCtxt<'a> {
         // the entire lambda body. Probably we should extend the API
         // here, but that's not entirely clear.
         self.expr(span, ast::ExprKind::Closure(ast::CaptureBy::Ref,
+                                               ast::IsAsync::NotAsync,
                                                ast::Movability::Movable,
                                                fn_decl,
                                                body,
@@ -1008,9 +1010,12 @@ impl<'a> AstBuilder for ExtCtxt<'a> {
                   name,
                   Vec::new(),
                   ast::ItemKind::Fn(self.fn_decl(inputs, ast::FunctionRetTy::Ty(output)),
-                              ast::Unsafety::Normal,
-                              dummy_spanned(ast::Constness::NotConst),
-                              Abi::Rust,
+                              ast::FnHeader {
+                                  unsafety: ast::Unsafety::Normal,
+                                  asyncness: ast::IsAsync::NotAsync,
+                                  constness: dummy_spanned(ast::Constness::NotConst),
+                                  abi: Abi::Rust,
+                              },
                               generics,
                               body))
     }
diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs
index be4cf197be4..ccb2f51f964 100644
--- a/src/libsyntax/feature_gate.rs
+++ b/src/libsyntax/feature_gate.rs
@@ -29,7 +29,6 @@ use rustc_target::spec::abi::Abi;
 use ast::{self, NodeId, PatKind, RangeEnd};
 use attr;
 use edition::{ALL_EDITIONS, Edition};
-use codemap::Spanned;
 use syntax_pos::{Span, DUMMY_SP};
 use errors::{DiagnosticBuilder, Handler, FatalError};
 use visit::{self, FnKind, Visitor};
@@ -309,7 +308,7 @@ declare_features! (
     // Declarative macros 2.0 (`macro`).
     (active, decl_macro, "1.17.0", Some(39412), None),
 
-    // Allows #[link(kind="static-nobundle"...]
+    // Allows #[link(kind="static-nobundle"...)]
     (active, static_nobundle, "1.16.0", Some(37403), None),
 
     // `extern "msp430-interrupt" fn()`
@@ -468,12 +467,14 @@ declare_features! (
     // 'a: { break 'a; }
     (active, label_break_value, "1.28.0", Some(48594), None),
 
-
     // #[panic_implementation]
     (active, panic_implementation, "1.28.0", Some(44489), None),
 
     // #[doc(keyword = "...")]
     (active, doc_keyword, "1.28.0", Some(51315), None),
+
+    // Allows async and await syntax
+    (active, async_await, "1.28.0", Some(50547), None),
 );
 
 declare_features! (
@@ -1721,6 +1722,12 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
                                     "labels on blocks are unstable");
                 }
             }
+            ast::ExprKind::Closure(_, ast::IsAsync::Async(_), ..) => {
+                gate_feature_post!(&self, async_await, e.span, "async closures are unstable");
+            }
+            ast::ExprKind::Async(..) => {
+                gate_feature_post!(&self, async_await, e.span, "async blocks are unstable");
+            }
             _ => {}
         }
         visit::walk_expr(self, e);
@@ -1760,20 +1767,24 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
                 fn_decl: &'a ast::FnDecl,
                 span: Span,
                 _node_id: NodeId) {
-        // check for const fn declarations
-        if let FnKind::ItemFn(_, _, Spanned { node: ast::Constness::Const, .. }, _, _, _) =
-            fn_kind {
-            gate_feature_post!(&self, const_fn, span, "const fn is unstable");
-        }
-        // stability of const fn methods are covered in
-        // visit_trait_item and visit_impl_item below; this is
-        // because default methods don't pass through this
-        // point.
-
         match fn_kind {
-            FnKind::ItemFn(_, _, _, abi, _, _) |
-            FnKind::Method(_, &ast::MethodSig { abi, .. }, _, _) => {
-                self.check_abi(abi, span);
+            FnKind::ItemFn(_, header, _, _) => {
+                // check for const fn and async fn declarations
+                if header.asyncness.is_async() {
+                    gate_feature_post!(&self, async_await, span, "async fn is unstable");
+                }
+                if header.constness.node == ast::Constness::Const {
+                    gate_feature_post!(&self, const_fn, span, "const fn is unstable");
+                }
+                // stability of const fn methods are covered in
+                // visit_trait_item and visit_impl_item below; this is
+                // because default methods don't pass through this
+                // point.
+
+                self.check_abi(header.abi, span);
+            }
+            FnKind::Method(_, sig, _, _) => {
+                self.check_abi(sig.header.abi, span);
             }
             _ => {}
         }
@@ -1784,9 +1795,9 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
         match ti.node {
             ast::TraitItemKind::Method(ref sig, ref block) => {
                 if block.is_none() {
-                    self.check_abi(sig.abi, ti.span);
+                    self.check_abi(sig.header.abi, ti.span);
                 }
-                if sig.constness.node == ast::Constness::Const {
+                if sig.header.constness.node == ast::Constness::Const {
                     gate_feature_post!(&self, const_fn, ti.span, "const fn is unstable");
                 }
             }
@@ -1820,7 +1831,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
 
         match ii.node {
             ast::ImplItemKind::Method(ref sig, _) => {
-                if sig.constness.node == ast::Constness::Const {
+                if sig.header.constness.node == ast::Constness::Const {
                     gate_feature_post!(&self, const_fn, ii.span, "const fn is unstable");
                 }
             }
diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs
index 93248fe3bfa..ffea713f4ec 100644
--- a/src/libsyntax/fold.rs
+++ b/src/libsyntax/fold.rs
@@ -76,6 +76,10 @@ pub trait Folder : Sized {
         noop_fold_item_simple(i, self)
     }
 
+    fn fold_fn_header(&mut self, header: FnHeader) -> FnHeader {
+        noop_fold_fn_header(header, self)
+    }
+
     fn fold_struct_field(&mut self, sf: StructField) -> StructField {
         noop_fold_struct_field(sf, self)
     }
@@ -881,11 +885,12 @@ pub fn noop_fold_item_kind<T: Folder>(i: ItemKind, folder: &mut T) -> ItemKind {
         ItemKind::Const(t, e) => {
             ItemKind::Const(folder.fold_ty(t), folder.fold_expr(e))
         }
-        ItemKind::Fn(decl, unsafety, constness, abi, generics, body) => {
+        ItemKind::Fn(decl, header, generics, body) => {
             let generics = folder.fold_generics(generics);
+            let header = folder.fold_fn_header(header);
             let decl = folder.fold_fn_decl(decl);
             let body = folder.fold_block(body);
-            ItemKind::Fn(decl, unsafety, constness, abi, generics, body)
+            ItemKind::Fn(decl, header, generics, body)
         }
         ItemKind::Mod(m) => ItemKind::Mod(folder.fold_mod(m)),
         ItemKind::ForeignMod(nm) => ItemKind::ForeignMod(folder.fold_foreign_mod(nm)),
@@ -990,6 +995,14 @@ pub fn noop_fold_impl_item<T: Folder>(i: ImplItem, folder: &mut T)
     })
 }
 
+pub fn noop_fold_fn_header<T: Folder>(mut header: FnHeader, folder: &mut T) -> FnHeader {
+    header.asyncness = match header.asyncness {
+        IsAsync::Async(node_id) => IsAsync::Async(folder.new_id(node_id)),
+        IsAsync::NotAsync => IsAsync::NotAsync,
+    };
+    header
+}
+
 pub fn noop_fold_mod<T: Folder>(Mod {inner, items}: Mod, folder: &mut T) -> Mod {
     Mod {
         inner: folder.new_span(inner),
@@ -1082,9 +1095,7 @@ pub fn noop_fold_foreign_item_simple<T: Folder>(ni: ForeignItem, folder: &mut T)
 
 pub fn noop_fold_method_sig<T: Folder>(sig: MethodSig, folder: &mut T) -> MethodSig {
     MethodSig {
-        abi: sig.abi,
-        unsafety: sig.unsafety,
-        constness: sig.constness,
+        header: folder.fold_fn_header(sig.header),
         decl: folder.fold_fn_decl(sig.decl)
     }
 }
@@ -1237,8 +1248,13 @@ pub fn noop_fold_expr<T: Folder>(Expr {id, node, span, attrs}: Expr, folder: &mu
                 ExprKind::Match(folder.fold_expr(expr),
                           arms.move_map(|x| folder.fold_arm(x)))
             }
-            ExprKind::Closure(capture_clause, movability, decl, body, span) => {
+            ExprKind::Closure(capture_clause, asyncness, movability, decl, body, span) => {
+                let asyncness = match asyncness {
+                    IsAsync::Async(node_id) => IsAsync::Async(folder.new_id(node_id)),
+                    IsAsync::NotAsync => IsAsync::NotAsync,
+                };
                 ExprKind::Closure(capture_clause,
+                                  asyncness,
                                   movability,
                                   folder.fold_fn_decl(decl),
                                   folder.fold_expr(body),
@@ -1248,6 +1264,9 @@ pub fn noop_fold_expr<T: Folder>(Expr {id, node, span, attrs}: Expr, folder: &mu
                 ExprKind::Block(folder.fold_block(blk),
                                 opt_label.map(|label| folder.fold_label(label)))
             }
+            ExprKind::Async(capture_clause, node_id, body) => {
+                ExprKind::Async(capture_clause, folder.new_id(node_id), folder.fold_block(body))
+            }
             ExprKind::Assign(el, er) => {
                 ExprKind::Assign(folder.fold_expr(el), folder.fold_expr(er))
             }
diff --git a/src/libsyntax/parse/mod.rs b/src/libsyntax/parse/mod.rs
index 1cb127bdcc9..cce8da1dcbd 100644
--- a/src/libsyntax/parse/mod.rs
+++ b/src/libsyntax/parse/mod.rs
@@ -928,12 +928,15 @@ mod tests {
                                     output: ast::FunctionRetTy::Default(sp(15, 15)),
                                     variadic: false
                                 }),
-                                        ast::Unsafety::Normal,
-                                        Spanned {
-                                            span: sp(0,2),
-                                            node: ast::Constness::NotConst,
+                                        ast::FnHeader {
+                                            unsafety: ast::Unsafety::Normal,
+                                            asyncness: ast::IsAsync::NotAsync,
+                                            constness: Spanned {
+                                                span: sp(0,2),
+                                                node: ast::Constness::NotConst,
+                                            },
+                                            abi: Abi::Rust,
                                         },
-                                        Abi::Rust,
                                         ast::Generics{
                                             params: Vec::new(),
                                             where_clause: ast::WhereClause {
diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs
index 69521c17a25..5970f94b97d 100644
--- a/src/libsyntax/parse/parser.rs
+++ b/src/libsyntax/parse/parser.rs
@@ -19,11 +19,11 @@ use ast::{Constness, Crate};
 use ast::Defaultness;
 use ast::EnumDef;
 use ast::{Expr, ExprKind, RangeLimits};
-use ast::{Field, FnDecl};
+use ast::{Field, FnDecl, FnHeader};
 use ast::{ForeignItem, ForeignItemKind, FunctionRetTy};
 use ast::{GenericParam, GenericParamKind};
 use ast::GenericArg;
-use ast::{Ident, ImplItem, IsAuto, Item, ItemKind};
+use ast::{Ident, ImplItem, IsAsync, IsAuto, Item, ItemKind};
 use ast::{Label, Lifetime, Lit, LitKind};
 use ast::Local;
 use ast::MacStmtStyle;
@@ -43,7 +43,7 @@ use ast::{BinOpKind, UnOp};
 use ast::{RangeEnd, RangeSyntax};
 use {ast, attr};
 use codemap::{self, CodeMap, Spanned, respan};
-use syntax_pos::{self, Span, MultiSpan, BytePos, FileName, DUMMY_SP};
+use syntax_pos::{self, Span, MultiSpan, BytePos, FileName, DUMMY_SP, edition::Edition};
 use errors::{self, Applicability, DiagnosticBuilder};
 use parse::{self, SeqSep, classify, token};
 use parse::lexer::TokenAndSpan;
@@ -1296,6 +1296,15 @@ impl<'a> Parser<'a> {
         })))
     }
 
+    /// Parse asyncness: `async` or nothing
+    fn parse_asyncness(&mut self) -> IsAsync {
+        if self.eat_keyword(keywords::Async) {
+            IsAsync::Async(ast::DUMMY_NODE_ID)
+        } else {
+            IsAsync::NotAsync
+        }
+    }
+
     /// Parse unsafety: `unsafe` or nothing.
     fn parse_unsafety(&mut self) -> Unsafety {
         if self.eat_keyword(keywords::Unsafe) {
@@ -1345,7 +1354,7 @@ impl<'a> Parser<'a> {
             // trait item macro.
             (keywords::Invalid.ident(), ast::TraitItemKind::Macro(mac), ast::Generics::default())
         } else {
-            let (constness, unsafety, abi) = self.parse_fn_front_matter()?;
+            let (constness, unsafety, asyncness, abi) = self.parse_fn_front_matter()?;
 
             let ident = self.parse_ident()?;
             let mut generics = self.parse_generics()?;
@@ -1359,10 +1368,13 @@ impl<'a> Parser<'a> {
             generics.where_clause = self.parse_where_clause()?;
 
             let sig = ast::MethodSig {
-                unsafety,
-                constness,
+                header: FnHeader {
+                    unsafety,
+                    constness,
+                    abi,
+                    asyncness,
+                },
                 decl: d,
-                abi,
             };
 
             let body = match self.token {
@@ -2258,6 +2270,15 @@ impl<'a> Parser<'a> {
                     hi = path.span;
                     return Ok(self.mk_expr(lo.to(hi), ExprKind::Path(Some(qself), path), attrs));
                 }
+                if self.span.edition() >= Edition::Edition2018 &&
+                    self.check_keyword(keywords::Async)
+                {
+                    if self.is_async_block() { // check for `async {` and `async move {`
+                        return self.parse_async_block(attrs);
+                    } else {
+                        return self.parse_lambda_expr(attrs);
+                    }
+                }
                 if self.check_keyword(keywords::Move) || self.check_keyword(keywords::Static) {
                     return self.parse_lambda_expr(attrs);
                 }
@@ -3258,6 +3279,13 @@ impl<'a> Parser<'a> {
         } else {
             Movability::Movable
         };
+        let asyncness = if self.span.edition() >= Edition::Edition2018
+            && self.eat_keyword(keywords::Async)
+        {
+            IsAsync::Async(ast::DUMMY_NODE_ID)
+        } else {
+            IsAsync::NotAsync
+        };
         let capture_clause = if self.eat_keyword(keywords::Move) {
             CaptureBy::Value
         } else {
@@ -3280,7 +3308,7 @@ impl<'a> Parser<'a> {
 
         Ok(self.mk_expr(
             lo.to(body.span),
-            ExprKind::Closure(capture_clause, movability, decl, body, lo.to(decl_hi)),
+            ExprKind::Closure(capture_clause, asyncness, movability, decl, body, lo.to(decl_hi)),
             attrs))
     }
 
@@ -3358,6 +3386,24 @@ impl<'a> Parser<'a> {
         Ok(self.mk_expr(span, ExprKind::Loop(body, opt_label), attrs))
     }
 
+    /// Parse an `async move {...}` expression
+    pub fn parse_async_block(&mut self, mut attrs: ThinVec<Attribute>)
+        -> PResult<'a, P<Expr>>
+    {
+        let span_lo = self.span;
+        self.expect_keyword(keywords::Async)?;
+        let capture_clause = if self.eat_keyword(keywords::Move) {
+            CaptureBy::Value
+        } else {
+            CaptureBy::Ref
+        };
+        let (iattrs, body) = self.parse_inner_attrs_and_block()?;
+        attrs.extend(iattrs);
+        Ok(self.mk_expr(
+            span_lo.to(body.span),
+            ExprKind::Async(capture_clause, ast::DUMMY_NODE_ID, body), attrs))
+    }
+
     /// Parse a `do catch {...}` expression (`do catch` token already eaten)
     fn parse_catch_expr(&mut self, span_lo: Span, mut attrs: ThinVec<Attribute>)
         -> PResult<'a, P<Expr>>
@@ -4292,6 +4338,18 @@ impl<'a> Parser<'a> {
         })
     }
 
+    fn is_async_block(&mut self) -> bool {
+        self.token.is_keyword(keywords::Async) &&
+        (
+            ( // `async move {`
+                self.look_ahead(1, |t| t.is_keyword(keywords::Move)) &&
+                self.look_ahead(2, |t| *t == token::OpenDelim(token::Brace))
+            ) || ( // `async {`
+                self.look_ahead(1, |t| *t == token::OpenDelim(token::Brace))
+            )
+        )
+    }
+
     fn is_catch_expr(&mut self) -> bool {
         self.token.is_keyword(keywords::Do) &&
         self.look_ahead(1, |t| t.is_keyword(keywords::Catch)) &&
@@ -5358,6 +5416,7 @@ impl<'a> Parser<'a> {
     /// Parse an item-position function declaration.
     fn parse_item_fn(&mut self,
                      unsafety: Unsafety,
+                     asyncness: IsAsync,
                      constness: Spanned<Constness>,
                      abi: Abi)
                      -> PResult<'a, ItemInfo> {
@@ -5365,7 +5424,8 @@ impl<'a> Parser<'a> {
         let decl = self.parse_fn_decl(false)?;
         generics.where_clause = self.parse_where_clause()?;
         let (inner_attrs, body) = self.parse_inner_attrs_and_block()?;
-        Ok((ident, ItemKind::Fn(decl, unsafety, constness, abi, generics, body), Some(inner_attrs)))
+        let header = FnHeader { unsafety, asyncness, constness, abi };
+        Ok((ident, ItemKind::Fn(decl, header, generics, body), Some(inner_attrs)))
     }
 
     /// true if we are looking at `const ID`, false for things like `const fn` etc
@@ -5383,10 +5443,18 @@ impl<'a> Parser<'a> {
     /// - `const unsafe fn`
     /// - `extern fn`
     /// - etc
-    fn parse_fn_front_matter(&mut self) -> PResult<'a, (Spanned<Constness>, Unsafety, Abi)> {
+    fn parse_fn_front_matter(&mut self)
+        -> PResult<'a, (
+            Spanned<Constness>,
+            Unsafety,
+            IsAsync,
+            Abi
+        )>
+    {
         let is_const_fn = self.eat_keyword(keywords::Const);
         let const_span = self.prev_span;
         let unsafety = self.parse_unsafety();
+        let asyncness = self.parse_asyncness();
         let (constness, unsafety, abi) = if is_const_fn {
             (respan(const_span, Constness::Const), unsafety, Abi::Rust)
         } else {
@@ -5398,7 +5466,7 @@ impl<'a> Parser<'a> {
             (respan(self.prev_span, Constness::NotConst), unsafety, abi)
         };
         self.expect_keyword(keywords::Fn)?;
-        Ok((constness, unsafety, abi))
+        Ok((constness, unsafety, asyncness, abi))
     }
 
     /// Parse an impl item.
@@ -5533,19 +5601,18 @@ impl<'a> Parser<'a> {
             Ok((keywords::Invalid.ident(), vec![], ast::Generics::default(),
                 ast::ImplItemKind::Macro(mac)))
         } else {
-            let (constness, unsafety, abi) = self.parse_fn_front_matter()?;
+            let (constness, unsafety, asyncness, abi) = self.parse_fn_front_matter()?;
             let ident = self.parse_ident()?;
             let mut generics = self.parse_generics()?;
             let decl = self.parse_fn_decl_with_self(|p| p.parse_arg())?;
             generics.where_clause = self.parse_where_clause()?;
             *at_end = true;
             let (inner_attrs, body) = self.parse_inner_attrs_and_block()?;
-            Ok((ident, inner_attrs, generics, ast::ImplItemKind::Method(ast::MethodSig {
-                abi,
-                unsafety,
-                constness,
-                decl,
-             }, body)))
+            let header = ast::FnHeader { abi, unsafety, constness, asyncness };
+            Ok((ident, inner_attrs, generics, ast::ImplItemKind::Method(
+                ast::MethodSig { header, decl },
+                body
+            )))
         }
     }
 
@@ -6631,6 +6698,7 @@ impl<'a> Parser<'a> {
                 let abi = opt_abi.unwrap_or(Abi::C);
                 let (ident, item_, extra_attrs) =
                     self.parse_item_fn(Unsafety::Normal,
+                                       IsAsync::NotAsync,
                                        respan(fn_span, Constness::NotConst),
                                        abi)?;
                 let prev_span = self.prev_span;
@@ -6674,6 +6742,7 @@ impl<'a> Parser<'a> {
                 self.bump();
                 let (ident, item_, extra_attrs) =
                     self.parse_item_fn(unsafety,
+                                       IsAsync::NotAsync,
                                        respan(const_span, Constness::Const),
                                        Abi::Rust)?;
                 let prev_span = self.prev_span;
@@ -6701,6 +6770,34 @@ impl<'a> Parser<'a> {
                                     maybe_append(attrs, extra_attrs));
             return Ok(Some(item));
         }
+
+        // `unsafe async fn` or `async fn`
+        if (
+            self.check_keyword(keywords::Unsafe) &&
+            self.look_ahead(1, |t| t.is_keyword(keywords::Async))
+        ) || (
+            self.check_keyword(keywords::Async) &&
+            self.look_ahead(1, |t| t.is_keyword(keywords::Fn))
+        )
+        {
+            // ASYNC FUNCTION ITEM
+            let unsafety = self.parse_unsafety();
+            self.expect_keyword(keywords::Async)?;
+            self.expect_keyword(keywords::Fn)?;
+            let fn_span = self.prev_span;
+            let (ident, item_, extra_attrs) =
+                self.parse_item_fn(unsafety,
+                                   IsAsync::Async(ast::DUMMY_NODE_ID),
+                                   respan(fn_span, Constness::NotConst),
+                                   Abi::Rust)?;
+            let prev_span = self.prev_span;
+            let item = self.mk_item(lo.to(prev_span),
+                                    ident,
+                                    item_,
+                                    visibility,
+                                    maybe_append(attrs, extra_attrs));
+            return Ok(Some(item));
+        }
         if self.check_keyword(keywords::Unsafe) &&
             (self.look_ahead(1, |t| t.is_keyword(keywords::Trait)) ||
             self.look_ahead(1, |t| t.is_keyword(keywords::Auto)))
@@ -6746,6 +6843,7 @@ impl<'a> Parser<'a> {
             let fn_span = self.prev_span;
             let (ident, item_, extra_attrs) =
                 self.parse_item_fn(Unsafety::Normal,
+                                   IsAsync::NotAsync,
                                    respan(fn_span, Constness::NotConst),
                                    Abi::Rust)?;
             let prev_span = self.prev_span;
@@ -6771,6 +6869,7 @@ impl<'a> Parser<'a> {
             let fn_span = self.prev_span;
             let (ident, item_, extra_attrs) =
                 self.parse_item_fn(Unsafety::Unsafe,
+                                   IsAsync::NotAsync,
                                    respan(fn_span, Constness::NotConst),
                                    abi)?;
             let prev_span = self.prev_span;
diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs
index 7a55919f422..ac8088507dd 100644
--- a/src/libsyntax/print/pprust.rs
+++ b/src/libsyntax/print/pprust.rs
@@ -373,14 +373,13 @@ pub fn vis_to_string(v: &ast::Visibility) -> String {
 }
 
 pub fn fun_to_string(decl: &ast::FnDecl,
-                     unsafety: ast::Unsafety,
-                     constness: ast::Constness,
+                     header: ast::FnHeader,
                      name: ast::Ident,
                      generics: &ast::Generics)
                      -> String {
     to_string(|s| {
         s.head("")?;
-        s.print_fn(decl, unsafety, constness, Abi::Rust, Some(name),
+        s.print_fn(decl, header, Some(name),
                    generics, &codemap::dummy_spanned(ast::VisibilityKind::Inherited))?;
         s.end()?; // Close the head box
         s.end() // Close the outer box
@@ -1118,9 +1117,8 @@ impl<'a> State<'a> {
         match item.node {
             ast::ForeignItemKind::Fn(ref decl, ref generics) => {
                 self.head("")?;
-                self.print_fn(decl, ast::Unsafety::Normal,
-                              ast::Constness::NotConst,
-                              Abi::Rust, Some(item.ident),
+                self.print_fn(decl, ast::FnHeader::default(),
+                              Some(item.ident),
                               generics, &item.vis)?;
                 self.end()?; // end head-ibox
                 self.s.word(";")?;
@@ -1249,13 +1247,11 @@ impl<'a> State<'a> {
                 self.s.word(";")?;
                 self.end()?; // end the outer cbox
             }
-            ast::ItemKind::Fn(ref decl, unsafety, constness, abi, ref typarams, ref body) => {
+            ast::ItemKind::Fn(ref decl, header, ref typarams, ref body) => {
                 self.head("")?;
                 self.print_fn(
                     decl,
-                    unsafety,
-                    constness.node,
-                    abi,
+                    header,
                     Some(item.ident),
                     typarams,
                     &item.vis
@@ -1582,9 +1578,7 @@ impl<'a> State<'a> {
                             vis: &ast::Visibility)
                             -> io::Result<()> {
         self.print_fn(&m.decl,
-                      m.unsafety,
-                      m.constness.node,
-                      m.abi,
+                      m.header,
                       Some(ident),
                       &generics,
                       vis)
@@ -2177,8 +2171,10 @@ impl<'a> State<'a> {
                 }
                 self.bclose_(expr.span, INDENT_UNIT)?;
             }
-            ast::ExprKind::Closure(capture_clause, movability, ref decl, ref body, _) => {
+            ast::ExprKind::Closure(
+                capture_clause, asyncness, movability, ref decl, ref body, _) => {
                 self.print_movability(movability)?;
+                self.print_asyncness(asyncness)?;
                 self.print_capture_clause(capture_clause)?;
 
                 self.print_fn_block_args(decl)?;
@@ -2202,6 +2198,12 @@ impl<'a> State<'a> {
                 self.ibox(0)?;
                 self.print_block_with_attrs(blk, attrs)?;
             }
+            ast::ExprKind::Async(capture_clause, _, ref blk) => {
+                self.word_nbsp("async")?;
+                self.print_capture_clause(capture_clause)?;
+                self.s.space()?;
+                self.print_block_with_attrs(blk, attrs)?;
+            }
             ast::ExprKind::Assign(ref lhs, ref rhs) => {
                 let prec = AssocOp::Assign.precedence() as i8;
                 self.print_expr_maybe_paren(lhs, prec + 1)?;
@@ -2740,13 +2742,11 @@ impl<'a> State<'a> {
 
     pub fn print_fn(&mut self,
                     decl: &ast::FnDecl,
-                    unsafety: ast::Unsafety,
-                    constness: ast::Constness,
-                    abi: abi::Abi,
+                    header: ast::FnHeader,
                     name: Option<ast::Ident>,
                     generics: &ast::Generics,
                     vis: &ast::Visibility) -> io::Result<()> {
-        self.print_fn_header_info(unsafety, constness, abi, vis)?;
+        self.print_fn_header_info(header, vis)?;
 
         if let Some(name) = name {
             self.nbsp()?;
@@ -2800,6 +2800,14 @@ impl<'a> State<'a> {
         }
     }
 
+    pub fn print_asyncness(&mut self, asyncness: ast::IsAsync)
+                                -> io::Result<()> {
+        if asyncness.is_async() {
+            self.word_nbsp("async")?;
+        }
+        Ok(())
+    }
+
     pub fn print_capture_clause(&mut self, capture_clause: ast::CaptureBy)
                                 -> io::Result<()> {
         match capture_clause {
@@ -3058,9 +3066,7 @@ impl<'a> State<'a> {
             span: syntax_pos::DUMMY_SP,
         };
         self.print_fn(decl,
-                      unsafety,
-                      ast::Constness::NotConst,
-                      abi,
+                      ast::FnHeader { unsafety, abi, ..ast::FnHeader::default() },
                       name,
                       &generics,
                       &codemap::dummy_spanned(ast::VisibilityKind::Inherited))?;
@@ -3123,22 +3129,21 @@ impl<'a> State<'a> {
     }
 
     pub fn print_fn_header_info(&mut self,
-                                unsafety: ast::Unsafety,
-                                constness: ast::Constness,
-                                abi: Abi,
+                                header: ast::FnHeader,
                                 vis: &ast::Visibility) -> io::Result<()> {
         self.s.word(&visibility_qualified(vis, ""))?;
 
-        match constness {
+        match header.constness.node {
             ast::Constness::NotConst => {}
             ast::Constness::Const => self.word_nbsp("const")?
         }
 
-        self.print_unsafety(unsafety)?;
+        self.print_asyncness(header.asyncness)?;
+        self.print_unsafety(header.unsafety)?;
 
-        if abi != Abi::Rust {
+        if header.abi != Abi::Rust {
             self.word_nbsp("extern")?;
-            self.word_nbsp(&abi.to_string())?;
+            self.word_nbsp(&header.abi.to_string())?;
         }
 
         self.s.word("fn")
@@ -3181,10 +3186,20 @@ mod tests {
                 variadic: false
             };
             let generics = ast::Generics::default();
-            assert_eq!(fun_to_string(&decl, ast::Unsafety::Normal,
-                                    ast::Constness::NotConst,
-                                    abba_ident, &generics),
-                    "fn abba()");
+            assert_eq!(
+                fun_to_string(
+                    &decl,
+                    ast::FnHeader {
+                        unsafety: ast::Unsafety::Normal,
+                        constness: codemap::dummy_spanned(ast::Constness::NotConst),
+                        asyncness: ast::IsAsync::NotAsync,
+                        abi: Abi::Rust,
+                    },
+                    abba_ident,
+                    &generics
+                ),
+                "fn abba()"
+            );
         })
     }
 
diff --git a/src/libsyntax/test.rs b/src/libsyntax/test.rs
index f896fa351b0..77225585141 100644
--- a/src/libsyntax/test.rs
+++ b/src/libsyntax/test.rs
@@ -124,24 +124,36 @@ impl<'a> fold::Folder for TestHarnessGenerator<'a> {
 
         if is_test_fn(&self.cx, &i) || is_bench_fn(&self.cx, &i) {
             match i.node {
-                ast::ItemKind::Fn(_, ast::Unsafety::Unsafe, _, _, _, _) => {
-                    let diag = self.cx.span_diagnostic;
-                    diag.span_fatal(i.span, "unsafe functions cannot be used for tests").raise();
-                }
-                _ => {
-                    debug!("this is a test function");
-                    let test = Test {
-                        span: i.span,
-                        path: self.cx.path.clone(),
-                        bench: is_bench_fn(&self.cx, &i),
-                        ignore: is_ignored(&i),
-                        should_panic: should_panic(&i, &self.cx),
-                        allow_fail: is_allowed_fail(&i),
-                    };
-                    self.cx.testfns.push(test);
-                    self.tests.push(i.ident);
+                ast::ItemKind::Fn(_, header, _, _) => {
+                    if header.unsafety == ast::Unsafety::Unsafe {
+                        let diag = self.cx.span_diagnostic;
+                        diag.span_fatal(
+                            i.span,
+                            "unsafe functions cannot be used for tests"
+                        ).raise();
+                    }
+                    if header.asyncness.is_async() {
+                        let diag = self.cx.span_diagnostic;
+                        diag.span_fatal(
+                            i.span,
+                            "async functions cannot be used for tests"
+                        ).raise();
+                    }
                 }
+                _ => {},
             }
+
+            debug!("this is a test function");
+            let test = Test {
+                span: i.span,
+                path: self.cx.path.clone(),
+                bench: is_bench_fn(&self.cx, &i),
+                ignore: is_ignored(&i),
+                should_panic: should_panic(&i, &self.cx),
+                allow_fail: is_allowed_fail(&i),
+            };
+            self.cx.testfns.push(test);
+            self.tests.push(i.ident);
         }
 
         let mut item = i.into_inner();
@@ -338,7 +350,7 @@ fn is_test_fn(cx: &TestCtxt, i: &ast::Item) -> bool {
     fn has_test_signature(_cx: &TestCtxt, i: &ast::Item) -> HasTestSignature {
         let has_should_panic_attr = attr::contains_name(&i.attrs, "should_panic");
         match i.node {
-            ast::ItemKind::Fn(ref decl, _, _, _, ref generics, _) => {
+            ast::ItemKind::Fn(ref decl, _, ref generics, _) => {
                 // If the termination trait is active, the compiler will check that the output
                 // type implements the `Termination` trait as `libtest` enforces that.
                 let has_output = match decl.output {
@@ -396,7 +408,7 @@ fn is_bench_fn(cx: &TestCtxt, i: &ast::Item) -> bool {
 
     fn has_bench_signature(_cx: &TestCtxt, i: &ast::Item) -> bool {
         match i.node {
-            ast::ItemKind::Fn(ref decl, _, _, _, _, _) => {
+            ast::ItemKind::Fn(ref decl, _, _, _) => {
                 // NB: inadequate check, but we're running
                 // well before resolve, can't get too deep.
                 decl.inputs.len() == 1
@@ -537,9 +549,7 @@ fn mk_main(cx: &mut TestCtxt) -> P<ast::Item> {
     let main_ret_ty = ecx.ty(sp, ast::TyKind::Tup(vec![]));
     let main_body = ecx.block(sp, vec![call_test_main]);
     let main = ast::ItemKind::Fn(ecx.fn_decl(vec![], ast::FunctionRetTy::Ty(main_ret_ty)),
-                           ast::Unsafety::Normal,
-                           dummy_spanned(ast::Constness::NotConst),
-                           ::rustc_target::spec::abi::Abi::Rust,
+                           ast::FnHeader::default(),
                            ast::Generics::default(),
                            main_body);
     P(ast::Item {
diff --git a/src/libsyntax/util/parser.rs b/src/libsyntax/util/parser.rs
index 51b535275d6..15d910b33b0 100644
--- a/src/libsyntax/util/parser.rs
+++ b/src/libsyntax/util/parser.rs
@@ -277,6 +277,7 @@ pub enum ExprPrecedence {
     Block,
     Catch,
     Struct,
+    Async,
 }
 
 impl PartialOrd for ExprPrecedence {
@@ -346,6 +347,7 @@ impl ExprPrecedence {
             ExprPrecedence::Match |
             ExprPrecedence::Block |
             ExprPrecedence::Catch |
+            ExprPrecedence::Async |
             ExprPrecedence::Struct => PREC_PAREN,
         }
     }
diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs
index 613f1a4f113..41e3ad9d4f4 100644
--- a/src/libsyntax/visit.rs
+++ b/src/libsyntax/visit.rs
@@ -23,17 +23,15 @@
 //! instance, a walker looking for item names in a module will miss all of
 //! those that are created by the expansion of a macro.
 
-use rustc_target::spec::abi::Abi;
 use ast::*;
 use syntax_pos::Span;
-use codemap::Spanned;
 use parse::token::Token;
 use tokenstream::{TokenTree, TokenStream};
 
 #[derive(Copy, Clone, PartialEq, Eq)]
 pub enum FnKind<'a> {
     /// fn foo() or extern "Abi" fn foo()
-    ItemFn(Ident, Unsafety, Spanned<Constness>, Abi, &'a Visibility, &'a Block),
+    ItemFn(Ident, FnHeader, &'a Visibility, &'a Block),
 
     /// fn foo(&self)
     Method(Ident, &'a MethodSig, Option<&'a Visibility>, &'a Block),
@@ -235,10 +233,10 @@ pub fn walk_item<'a, V: Visitor<'a>>(visitor: &mut V, item: &'a Item) {
             visitor.visit_ty(typ);
             visitor.visit_expr(expr);
         }
-        ItemKind::Fn(ref declaration, unsafety, constness, abi, ref generics, ref body) => {
+        ItemKind::Fn(ref declaration, header, ref generics, ref body) => {
             visitor.visit_generics(generics);
-            visitor.visit_fn(FnKind::ItemFn(item.ident, unsafety,
-                                            constness, abi, &item.vis, body),
+            visitor.visit_fn(FnKind::ItemFn(item.ident, header,
+                                            &item.vis, body),
                              declaration,
                              item.span,
                              item.id)
@@ -544,7 +542,7 @@ pub fn walk_fn<'a, V>(visitor: &mut V, kind: FnKind<'a>, declaration: &'a FnDecl
     where V: Visitor<'a>,
 {
     match kind {
-        FnKind::ItemFn(_, _, _, _, _, body) => {
+        FnKind::ItemFn(_, _, _, body) => {
             walk_fn_decl(visitor, declaration);
             visitor.visit_block(body);
         }
@@ -737,7 +735,7 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) {
             visitor.visit_expr(subexpression);
             walk_list!(visitor, visit_arm, arms);
         }
-        ExprKind::Closure(_, _, ref function_declaration, ref body, _decl_span) => {
+        ExprKind::Closure(_, _, _, ref function_declaration, ref body, _decl_span) => {
             visitor.visit_fn(FnKind::Closure(body),
                              function_declaration,
                              expression.span,
@@ -747,6 +745,9 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) {
             walk_list!(visitor, visit_label, opt_label);
             visitor.visit_block(block);
         }
+        ExprKind::Async(_, _, ref body) => {
+            visitor.visit_block(body);
+        }
         ExprKind::Assign(ref left_hand_expression, ref right_hand_expression) => {
             visitor.visit_expr(left_hand_expression);
             visitor.visit_expr(right_hand_expression);
diff --git a/src/libsyntax_ext/deriving/generic/mod.rs b/src/libsyntax_ext/deriving/generic/mod.rs
index 672726d1475..3ea0eb8bbd8 100644
--- a/src/libsyntax_ext/deriving/generic/mod.rs
+++ b/src/libsyntax_ext/deriving/generic/mod.rs
@@ -197,7 +197,7 @@ use syntax::ast::{VariantData, GenericParamKind, GenericArg};
 use syntax::attr;
 use syntax::ext::base::{Annotatable, ExtCtxt};
 use syntax::ext::build::AstBuilder;
-use syntax::codemap::{self, dummy_spanned, respan};
+use syntax::codemap::{self, respan};
 use syntax::util::move_map::MoveMap;
 use syntax::ptr::P;
 use syntax::symbol::{Symbol, keywords};
@@ -971,10 +971,10 @@ impl<'a> MethodDef<'a> {
             defaultness: ast::Defaultness::Final,
             ident: method_ident,
             node: ast::ImplItemKind::Method(ast::MethodSig {
-                                                abi,
-                                                unsafety,
-                                                constness:
-                                                    dummy_spanned(ast::Constness::NotConst),
+                                                header: ast::FnHeader {
+                                                    unsafety, abi,
+                                                    ..ast::FnHeader::default()
+                                                },
                                                 decl: fn_decl,
                                             },
                                             body_block),
diff --git a/src/libsyntax_pos/hygiene.rs b/src/libsyntax_pos/hygiene.rs
index 6dd910fba82..0ca42169b8e 100644
--- a/src/libsyntax_pos/hygiene.rs
+++ b/src/libsyntax_pos/hygiene.rs
@@ -493,12 +493,14 @@ pub enum CompilerDesugaringKind {
     /// to an `existential type Foo: Trait;` + replacing the
     /// `impl Trait` with `Foo`.
     ExistentialReturnType,
+    Async,
 }
 
 impl CompilerDesugaringKind {
     pub fn as_symbol(&self) -> Symbol {
         use CompilerDesugaringKind::*;
         let s = match *self {
+            Async => "async",
             DotFill => "...",
             QuestionMark => "?",
             Catch => "do catch",
diff --git a/src/test/parse-fail/issue-20711-2.rs b/src/test/parse-fail/issue-20711-2.rs
index 3a330d8bee2..05df16d21d8 100644
--- a/src/test/parse-fail/issue-20711-2.rs
+++ b/src/test/parse-fail/issue-20711-2.rs
@@ -16,6 +16,6 @@ impl Foo {
     fn foo() {}
 
     #[stable(feature = "rust1", since = "1.0.0")]
-} //~ ERROR expected one of `const`, `crate`, `default`, `extern`, `fn`, `pub`, `type`, or `unsafe`
+} //~ ERROR expected one of `async`, `const`, `crate`, `default`, `extern`, `fn`, `pub`, `type`, or
 
 fn main() {}
diff --git a/src/test/parse-fail/issue-20711.rs b/src/test/parse-fail/issue-20711.rs
index cd79fa8be7c..f30e20ad7db 100644
--- a/src/test/parse-fail/issue-20711.rs
+++ b/src/test/parse-fail/issue-20711.rs
@@ -14,6 +14,6 @@ struct Foo;
 
 impl Foo {
     #[stable(feature = "rust1", since = "1.0.0")]
-} //~ ERROR expected one of `const`, `crate`, `default`, `extern`, `fn`, `pub`, `type`, or `unsafe`
+} //~ ERROR expected one of `async`, `const`, `crate`, `default`, `extern`, `fn`, `pub`, `type`, or
 
 fn main() {}
diff --git a/src/test/parse-fail/removed-syntax-static-fn.rs b/src/test/parse-fail/removed-syntax-static-fn.rs
index 3b783aa79e2..fbc6848f372 100644
--- a/src/test/parse-fail/removed-syntax-static-fn.rs
+++ b/src/test/parse-fail/removed-syntax-static-fn.rs
@@ -15,4 +15,4 @@ struct S;
 impl S {
     static fn f() {}
 }
-//~^^ ERROR expected one of `const`, `crate`, `default`, `extern`, `fn`, `pub`, `type`, `unsafe`
+//~^^ ERROR expected one of `async`, `const`, `crate`, `default`, `extern`, `fn`, `pub`, `type`,
diff --git a/src/test/parse-fail/trait-non-item-macros.rs b/src/test/parse-fail/trait-non-item-macros.rs
index fd356f4a817..9f94d5d41fd 100644
--- a/src/test/parse-fail/trait-non-item-macros.rs
+++ b/src/test/parse-fail/trait-non-item-macros.rs
@@ -10,7 +10,7 @@
 
 macro_rules! bah {
     ($a:expr) => ($a)
-    //~^ ERROR expected one of `const`, `extern`, `fn`, `type`, or `unsafe`, found `2`
+    //~^ ERROR expected one of `async`, `const`, `extern`, `fn`, `type`, or `unsafe`, found `2`
 }
 
 trait bar {
diff --git a/src/test/parse-fail/trait-pub-assoc-const.rs b/src/test/parse-fail/trait-pub-assoc-const.rs
index 6bc24e2081d..cce6b5c4cbf 100644
--- a/src/test/parse-fail/trait-pub-assoc-const.rs
+++ b/src/test/parse-fail/trait-pub-assoc-const.rs
@@ -10,7 +10,7 @@
 
 trait Foo {
     pub const Foo: u32;
-    //~^ ERROR expected one of `const`, `extern`, `fn`, `type`, `unsafe`, or `}`, found `pub`
+    //~^ ERROR expected one of `async`, `const`, `extern`, `fn`, `type`, `unsafe`, or `}`, found
 }
 
 fn main() {}
diff --git a/src/test/parse-fail/trait-pub-assoc-ty.rs b/src/test/parse-fail/trait-pub-assoc-ty.rs
index 493ff087eaf..d6a4e5e021d 100644
--- a/src/test/parse-fail/trait-pub-assoc-ty.rs
+++ b/src/test/parse-fail/trait-pub-assoc-ty.rs
@@ -10,7 +10,7 @@
 
 trait Foo {
     pub type Foo;
-    //~^ ERROR expected one of `const`, `extern`, `fn`, `type`, `unsafe`, or `}`, found `pub`
+    //~^ ERROR expected one of `async`, `const`, `extern`, `fn`, `type`, `unsafe`, or `}`, found
 }
 
 fn main() {}
diff --git a/src/test/parse-fail/trait-pub-method.rs b/src/test/parse-fail/trait-pub-method.rs
index c2ee3c31d88..286cb4dbff7 100644
--- a/src/test/parse-fail/trait-pub-method.rs
+++ b/src/test/parse-fail/trait-pub-method.rs
@@ -10,7 +10,7 @@
 
 trait Foo {
     pub fn foo();
-    //~^ ERROR expected one of `const`, `extern`, `fn`, `type`, `unsafe`, or `}`, found `pub`
+    //~^ ERROR expected one of `async`, `const`, `extern`, `fn`, `type`, `unsafe`, or `}`, found
 }
 
 fn main() {}
diff --git a/src/test/run-pass-fulldeps/pprust-expr-roundtrip.rs b/src/test/run-pass-fulldeps/pprust-expr-roundtrip.rs
index 3a848a31c4d..bbd81e790b8 100644
--- a/src/test/run-pass-fulldeps/pprust-expr-roundtrip.rs
+++ b/src/test/run-pass-fulldeps/pprust-expr-roundtrip.rs
@@ -124,6 +124,7 @@ fn iter_exprs(depth: usize, f: &mut FnMut(P<Expr>)) {
                 });
                 iter_exprs(depth - 1, &mut |e| g(
                         ExprKind::Closure(CaptureBy::Value,
+                                          IsAsync::NotAsync,
                                           Movability::Movable,
                                           decl.clone(),
                                           e,
diff --git a/src/test/run-pass/async-await.rs b/src/test/run-pass/async-await.rs
new file mode 100644
index 00000000000..817db4bb79e
--- /dev/null
+++ b/src/test/run-pass/async-await.rs
@@ -0,0 +1,152 @@
+// Copyright 2018 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.
+
+// compile-flags: --edition=2018
+
+#![feature(arbitrary_self_types, async_await, await_macro, futures_api, pin)]
+
+use std::boxed::PinBox;
+use std::mem::PinMut;
+use std::future::Future;
+use std::sync::{
+    Arc,
+    atomic::{self, AtomicUsize},
+};
+use std::task::{
+    Context, Poll, Wake,
+    Executor, TaskObj, SpawnObjError,
+    local_waker_from_nonlocal,
+};
+
+struct Counter {
+    wakes: AtomicUsize,
+}
+
+impl Wake for Counter {
+    fn wake(this: &Arc<Self>) {
+        this.wakes.fetch_add(1, atomic::Ordering::SeqCst);
+    }
+}
+
+struct NoopExecutor;
+impl Executor for NoopExecutor {
+    fn spawn_obj(&mut self, _: TaskObj) -> Result<(), SpawnObjError> {
+        Ok(())
+    }
+}
+
+struct WakeOnceThenComplete(bool);
+
+fn wake_and_yield_once() -> WakeOnceThenComplete { WakeOnceThenComplete(false) }
+
+impl Future for WakeOnceThenComplete {
+    type Output = ();
+    fn poll(mut self: PinMut<Self>, cx: &mut Context) -> Poll<()> {
+        if self.0 {
+            Poll::Ready(())
+        } else {
+            cx.waker().wake();
+            self.0 = true;
+            Poll::Pending
+        }
+    }
+}
+
+fn async_block(x: u8) -> impl Future<Output = u8> {
+    async move {
+        await!(wake_and_yield_once());
+        x
+    }
+}
+
+fn async_nonmove_block(x: u8) -> impl Future<Output = u8> {
+    async move {
+        let future = async {
+            await!(wake_and_yield_once());
+            x
+        };
+        await!(future)
+    }
+}
+
+fn async_closure(x: u8) -> impl Future<Output = u8> {
+    (async move |x: u8| -> u8 {
+        await!(wake_and_yield_once());
+        x
+    })(x)
+}
+
+async fn async_fn(x: u8) -> u8 {
+    await!(wake_and_yield_once());
+    x
+}
+
+async fn async_fn_with_borrow(x: &u8) -> u8 {
+    await!(wake_and_yield_once());
+    *x
+}
+
+fn async_fn_with_internal_borrow(y: u8) -> impl Future<Output = u8> {
+    async move {
+        await!(async_fn_with_borrow(&y))
+    }
+}
+
+unsafe async fn unsafe_async_fn(x: u8) -> u8 {
+    await!(wake_and_yield_once());
+    x
+}
+
+struct Foo;
+
+trait Bar {
+    fn foo() {}
+}
+
+impl Foo {
+    async fn async_method(x: u8) -> u8 {
+        unsafe {
+            await!(unsafe_async_fn(x))
+        }
+    }
+}
+
+fn test_future_yields_once_then_returns<F, Fut>(f: F)
+where
+    F: FnOnce(u8) -> Fut,
+    Fut: Future<Output = u8>,
+{
+    let mut fut = PinBox::new(f(9));
+    let counter = Arc::new(Counter { wakes: AtomicUsize::new(0) });
+    let waker = local_waker_from_nonlocal(counter.clone());
+    let executor = &mut NoopExecutor;
+    let cx = &mut Context::new(&waker, executor);
+
+    assert_eq!(0, counter.wakes.load(atomic::Ordering::SeqCst));
+    assert_eq!(Poll::Pending, fut.as_pin_mut().poll(cx));
+    assert_eq!(1, counter.wakes.load(atomic::Ordering::SeqCst));
+    assert_eq!(Poll::Ready(9), fut.as_pin_mut().poll(cx));
+}
+
+fn main() {
+    macro_rules! test {
+        ($($fn_name:ident,)*) => { $(
+            test_future_yields_once_then_returns($fn_name);
+        )* }
+    }
+
+    test! {
+        async_block,
+        async_nonmove_block,
+        async_closure,
+        async_fn,
+        async_fn_with_internal_borrow,
+    }
+}
diff --git a/src/test/ui/async-fn-multiple-lifetimes.rs b/src/test/ui/async-fn-multiple-lifetimes.rs
new file mode 100644
index 00000000000..ce062ded7f7
--- /dev/null
+++ b/src/test/ui/async-fn-multiple-lifetimes.rs
@@ -0,0 +1,30 @@
+// Copyright 2018 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.
+
+// compile-flags: --edition=2018
+
+#![feature(arbitrary_self_types, async_await, await_macro, futures_api, pin)]
+
+use std::ops::Add;
+
+async fn multiple_named_lifetimes<'a, 'b>(_: &'a u8, _: &'b u8) {}
+//~^ ERROR multiple different lifetimes used in arguments of `async fn`
+
+async fn multiple_hrtb_and_single_named_lifetime_ok<'c>(
+    _: impl for<'a> Add<&'a u8>,
+    _: impl for<'b> Add<&'b u8>,
+    _: &'c u8,
+) {}
+
+async fn multiple_elided_lifetimes(_: &u8, _: &u8) {}
+//~^ ERROR multiple elided lifetimes used
+//~^^ ERROR missing lifetime specifier
+
+fn main() {}
diff --git a/src/test/ui/async-fn-multiple-lifetimes.stderr b/src/test/ui/async-fn-multiple-lifetimes.stderr
new file mode 100644
index 00000000000..d76bfc5d0e1
--- /dev/null
+++ b/src/test/ui/async-fn-multiple-lifetimes.stderr
@@ -0,0 +1,32 @@
+error[E0725]: multiple different lifetimes used in arguments of `async fn`
+  --> $DIR/async-fn-multiple-lifetimes.rs:17:49
+   |
+LL | async fn multiple_named_lifetimes<'a, 'b>(_: &'a u8, _: &'b u8) {}
+   |                                               --^^^^^^^^^-- different lifetime here
+   |                                               |
+   |                                               first lifetime here
+   |
+   = help: `async fn` can only accept borrowed values with identical lifetimes
+
+error[E0726]: multiple elided lifetimes used in arguments of `async fn`
+  --> $DIR/async-fn-multiple-lifetimes.rs:26:39
+   |
+LL | async fn multiple_elided_lifetimes(_: &u8, _: &u8) {}
+   |                                       -^^^^^^^- different lifetime here
+   |                                       |
+   |                                       first lifetime here
+   |
+   = help: consider giving these arguments named lifetimes
+
+error[E0106]: missing lifetime specifier
+  --> $DIR/async-fn-multiple-lifetimes.rs:26:39
+   |
+LL | async fn multiple_elided_lifetimes(_: &u8, _: &u8) {}
+   |                                       ^ expected lifetime parameter
+   |
+   = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from `_` or `_`
+
+error: aborting due to 3 previous errors
+
+Some errors occurred: E0106, E0725, E0726.
+For more information about an error, try `rustc --explain E0106`.
diff --git a/src/test/ui/did_you_mean/issue-40006.stderr b/src/test/ui/did_you_mean/issue-40006.stderr
index a3433939573..d3ce2cf12f2 100644
--- a/src/test/ui/did_you_mean/issue-40006.stderr
+++ b/src/test/ui/did_you_mean/issue-40006.stderr
@@ -38,11 +38,11 @@ LL |       L = M; //~ ERROR missing
 LL | |     Z = { 2 + 3 }; //~ ERROR expected one of
    | |____^ missing `fn`, `type`, or `const`
 
-error: expected one of `const`, `extern`, `fn`, `type`, `unsafe`, or `}`, found `;`
+error: expected one of `async`, `const`, `extern`, `fn`, `type`, `unsafe`, or `}`, found `;`
   --> $DIR/issue-40006.rs:23:18
    |
 LL |     Z = { 2 + 3 }; //~ ERROR expected one of
-   |                  ^ expected one of `const`, `extern`, `fn`, `type`, `unsafe`, or `}` here
+   |                  ^ expected one of 7 possible tokens here
 
 error: expected one of `!` or `::`, found `(`
   --> $DIR/issue-40006.rs:24:9
diff --git a/src/test/ui/edition-keywords-2018-2015-parsing.rs b/src/test/ui/edition-keywords-2018-2015-parsing.rs
index 29c5ea41f1f..02dc8c87956 100644
--- a/src/test/ui/edition-keywords-2018-2015-parsing.rs
+++ b/src/test/ui/edition-keywords-2018-2015-parsing.rs
@@ -25,7 +25,7 @@ pub fn check_async() {
     r#async = consumes_async_raw!(async); //~ ERROR no rules expected the token `async`
     r#async = consumes_async_raw!(r#async); // OK
 
-    if passes_ident!(async) == 1 {} //~ ERROR expected expression, found reserved keyword `async`
+    if passes_ident!(async) == 1 {}
     if passes_ident!(r#async) == 1 {} // OK
     module::async(); //~ ERROR expected identifier, found reserved keyword `async`
     module::r#async(); // OK
diff --git a/src/test/ui/edition-keywords-2018-2015-parsing.stderr b/src/test/ui/edition-keywords-2018-2015-parsing.stderr
index 0b3ca57bfab..ceab5ea730e 100644
--- a/src/test/ui/edition-keywords-2018-2015-parsing.stderr
+++ b/src/test/ui/edition-keywords-2018-2015-parsing.stderr
@@ -22,11 +22,11 @@ error: no rules expected the token `async`
 LL |     r#async = consumes_async_raw!(async); //~ ERROR no rules expected the token `async`
    |                                   ^^^^^
 
-error: expected expression, found reserved keyword `async`
-  --> $DIR/edition-keywords-2018-2015-parsing.rs:28:22
+error: expected one of `move`, `|`, or `||`, found `<eof>`
+  --> <passes_ident macros>:1:22
    |
-LL |     if passes_ident!(async) == 1 {} //~ ERROR expected expression, found reserved keyword `async`
-   |                      ^^^^^ expected expression
+LL | ( $ i : ident ) => ( $ i )
+   |                      ^^^ expected one of `move`, `|`, or `||` here
 
 error: aborting due to 5 previous errors
 
diff --git a/src/test/ui/edition-keywords-2018-2018-parsing.rs b/src/test/ui/edition-keywords-2018-2018-parsing.rs
index a94808eb224..f9b4d0e18c1 100644
--- a/src/test/ui/edition-keywords-2018-2018-parsing.rs
+++ b/src/test/ui/edition-keywords-2018-2018-parsing.rs
@@ -25,7 +25,7 @@ pub fn check_async() {
     r#async = consumes_async_raw!(async); //~ ERROR no rules expected the token `async`
     r#async = consumes_async_raw!(r#async); // OK
 
-    if passes_ident!(async) == 1 {} //~ ERROR expected expression, found reserved keyword `async`
+    if passes_ident!(async) == 1 {}
     if passes_ident!(r#async) == 1 {} // OK
     module::async(); //~ ERROR expected identifier, found reserved keyword `async`
     module::r#async(); // OK
diff --git a/src/test/ui/edition-keywords-2018-2018-parsing.stderr b/src/test/ui/edition-keywords-2018-2018-parsing.stderr
index 1b18d8a39be..e48aac0a2bb 100644
--- a/src/test/ui/edition-keywords-2018-2018-parsing.stderr
+++ b/src/test/ui/edition-keywords-2018-2018-parsing.stderr
@@ -22,11 +22,11 @@ error: no rules expected the token `async`
 LL |     r#async = consumes_async_raw!(async); //~ ERROR no rules expected the token `async`
    |                                   ^^^^^
 
-error: expected expression, found reserved keyword `async`
-  --> $DIR/edition-keywords-2018-2018-parsing.rs:28:22
+error: expected one of `move`, `|`, or `||`, found `<eof>`
+  --> <passes_ident macros>:1:22
    |
-LL |     if passes_ident!(async) == 1 {} //~ ERROR expected expression, found reserved keyword `async`
-   |                      ^^^^^ expected expression
+LL | ( $ i : ident ) => ( $ i )
+   |                      ^^^ expected one of `move`, `|`, or `||` here
 
 error: aborting due to 5 previous errors
 
diff --git a/src/test/ui/feature-gate-async-await-2015-edition.rs b/src/test/ui/feature-gate-async-await-2015-edition.rs
new file mode 100644
index 00000000000..b1dd6a77e97
--- /dev/null
+++ b/src/test/ui/feature-gate-async-await-2015-edition.rs
@@ -0,0 +1,20 @@
+// Copyright 2018 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.
+
+// compile-flags: --edition=2015
+
+#![feature(futures_api)]
+
+async fn foo() {} //~ ERROR async fn is unstable
+
+fn main() {
+    let _ = async {}; //~ ERROR cannot find struct, variant or union type `async`
+    let _ = async || {}; //~ ERROR cannot find value `async` in this scope
+}
diff --git a/src/test/ui/feature-gate-async-await-2015-edition.stderr b/src/test/ui/feature-gate-async-await-2015-edition.stderr
new file mode 100644
index 00000000000..3db90a48e90
--- /dev/null
+++ b/src/test/ui/feature-gate-async-await-2015-edition.stderr
@@ -0,0 +1,24 @@
+error[E0422]: cannot find struct, variant or union type `async` in this scope
+  --> $DIR/feature-gate-async-await-2015-edition.rs:18:13
+   |
+LL |     let _ = async {}; //~ ERROR cannot find struct, variant or union type `async`
+   |             ^^^^^ not found in this scope
+
+error[E0425]: cannot find value `async` in this scope
+  --> $DIR/feature-gate-async-await-2015-edition.rs:19:13
+   |
+LL |     let _ = async || {}; //~ ERROR cannot find value `async` in this scope
+   |             ^^^^^ not found in this scope
+
+error[E0658]: async fn is unstable (see issue #50547)
+  --> $DIR/feature-gate-async-await-2015-edition.rs:15:1
+   |
+LL | async fn foo() {} //~ ERROR async fn is unstable
+   | ^^^^^^^^^^^^^^^^^
+   |
+   = help: add #![feature(async_await)] to the crate attributes to enable
+
+error: aborting due to 3 previous errors
+
+Some errors occurred: E0422, E0425, E0658.
+For more information about an error, try `rustc --explain E0422`.
diff --git a/src/test/ui/feature-gate-async-await.rs b/src/test/ui/feature-gate-async-await.rs
new file mode 100644
index 00000000000..971b75c6dd0
--- /dev/null
+++ b/src/test/ui/feature-gate-async-await.rs
@@ -0,0 +1,19 @@
+// Copyright 2018 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.
+
+// compile-flags: --edition=2018
+#![feature(futures_api)]
+
+async fn foo() {} //~ ERROR async fn is unstable
+
+fn main() {
+    let _ = async {}; //~ ERROR async blocks are unstable
+    let _ = async || {}; //~ ERROR async closures are unstable
+}
diff --git a/src/test/ui/feature-gate-async-await.stderr b/src/test/ui/feature-gate-async-await.stderr
new file mode 100644
index 00000000000..fdee6e20575
--- /dev/null
+++ b/src/test/ui/feature-gate-async-await.stderr
@@ -0,0 +1,27 @@
+error[E0658]: async fn is unstable (see issue #50547)
+  --> $DIR/feature-gate-async-await.rs:14:1
+   |
+LL | async fn foo() {} //~ ERROR async fn is unstable
+   | ^^^^^^^^^^^^^^^^^
+   |
+   = help: add #![feature(async_await)] to the crate attributes to enable
+
+error[E0658]: async blocks are unstable (see issue #50547)
+  --> $DIR/feature-gate-async-await.rs:17:13
+   |
+LL |     let _ = async {}; //~ ERROR async blocks are unstable
+   |             ^^^^^^^^
+   |
+   = help: add #![feature(async_await)] to the crate attributes to enable
+
+error[E0658]: async closures are unstable (see issue #50547)
+  --> $DIR/feature-gate-async-await.rs:18:13
+   |
+LL |     let _ = async || {}; //~ ERROR async closures are unstable
+   |             ^^^^^^^^^^^
+   |
+   = help: add #![feature(async_await)] to the crate attributes to enable
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/no-args-non-move-async-closure.rs b/src/test/ui/no-args-non-move-async-closure.rs
new file mode 100644
index 00000000000..f2ecc447718
--- /dev/null
+++ b/src/test/ui/no-args-non-move-async-closure.rs
@@ -0,0 +1,18 @@
+// Copyright 2018 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.
+
+// compile-flags: --edition=2018
+
+#![feature(arbitrary_self_types, async_await, await_macro, futures_api, pin)]
+
+fn main() {
+    let _ = async |x: u8| {};
+    //~^ ERROR `async` non-`move` closures with arguments are not currently supported
+}
diff --git a/src/test/ui/no-args-non-move-async-closure.stderr b/src/test/ui/no-args-non-move-async-closure.stderr
new file mode 100644
index 00000000000..34cd0069c04
--- /dev/null
+++ b/src/test/ui/no-args-non-move-async-closure.stderr
@@ -0,0 +1,11 @@
+error[E0727]: `async` non-`move` closures with arguments are not currently supported
+  --> $DIR/no-args-non-move-async-closure.rs:16:13
+   |
+LL |     let _ = async |x: u8| {};
+   |             ^^^^^^^^^^^^^
+   |
+   = help: consider using `let` statements to manually capture variables by reference before entering an `async move` closure
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0727`.
diff --git a/src/test/ui/token/issue-41155.stderr b/src/test/ui/token/issue-41155.stderr
index b56b95a8aaf..84dbc7ffc2f 100644
--- a/src/test/ui/token/issue-41155.stderr
+++ b/src/test/ui/token/issue-41155.stderr
@@ -1,8 +1,8 @@
-error: expected one of `(`, `const`, `default`, `extern`, `fn`, `type`, or `unsafe`, found `}`
+error: expected one of `(`, `async`, `const`, `default`, `extern`, `fn`, `type`, or `unsafe`, found `}`
   --> $DIR/issue-41155.rs:13:1
    |
 LL |     pub
-   |        - expected one of 7 possible tokens here
+   |        - expected one of 8 possible tokens here
 LL | } //~ ERROR expected one of
    | ^ unexpected token