about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/librustc/hir/intravisit.rs6
-rw-r--r--src/librustc/hir/lowering.rs661
-rw-r--r--src/librustc/hir/mod.rs12
-rw-r--r--src/librustc/infer/opaque_types/mod.rs80
-rw-r--r--src/librustc/middle/resolve_lifetime.rs2
-rw-r--r--src/librustc_typeck/collect.rs1
-rw-r--r--src/test/run-pass/async-await.rs20
-rw-r--r--src/test/ui/async-fn-multiple-lifetimes.rs5
-rw-r--r--src/test/ui/async-fn-multiple-lifetimes.stderr34
-rw-r--r--src/test/ui/issues/issue-54974.rs16
-rw-r--r--src/test/ui/issues/issue-55324.rs14
-rw-r--r--src/test/ui/issues/issue-58885.rs21
-rw-r--r--src/test/ui/issues/issue-59001.rs17
13 files changed, 553 insertions, 336 deletions
diff --git a/src/librustc/hir/intravisit.rs b/src/librustc/hir/intravisit.rs
index 6689b0c26fb..c2265eeb30d 100644
--- a/src/librustc/hir/intravisit.rs
+++ b/src/librustc/hir/intravisit.rs
@@ -490,7 +490,11 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item) {
             visitor.visit_ty(ty);
             visitor.visit_generics(generics)
         }
-        ItemKind::Existential(ExistTy { ref generics, ref bounds, impl_trait_fn: _ }) => {
+        ItemKind::Existential(ExistTy {
+            ref generics,
+            ref bounds,
+            ..
+        }) => {
             visitor.visit_id(item.hir_id);
             walk_generics(visitor, generics);
             walk_list!(visitor, visit_param_bound, bounds);
diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs
index 7dfb16602a3..2a255523676 100644
--- a/src/librustc/hir/lowering.rs
+++ b/src/librustc/hir/lowering.rs
@@ -66,7 +66,7 @@ use syntax::symbol::{keywords, Symbol};
 use syntax::tokenstream::{TokenStream, TokenTree};
 use syntax::parse::token::Token;
 use syntax::visit::{self, Visitor};
-use syntax_pos::{Span, MultiSpan};
+use syntax_pos::Span;
 
 const HIR_ID_COUNTER_LOCKED: u32 = 0xFFFFFFFF;
 
@@ -318,6 +318,49 @@ enum AnonymousLifetimeMode {
 
     /// Pass responsibility to `resolve_lifetime` code for all cases.
     PassThrough,
+
+    /// Used in the return types of `async fn` where there exists
+    /// exactly one argument-position elided lifetime.
+    ///
+    /// In `async fn`, we lower the arguments types using the `CreateParameter`
+    /// mode, meaning that non-`dyn` elided lifetimes are assigned a fresh name.
+    /// If any corresponding elided lifetimes appear in the output, we need to
+    /// replace them with references to the fresh name assigned to the corresponding
+    /// elided lifetime in the arguments.
+    ///
+    /// For **Modern cases**, replace the anonymous parameter with a
+    /// reference to a specific freshly-named lifetime that was
+    /// introduced in argument
+    ///
+    /// For **Dyn Bound** cases, pass responsibility to
+    /// `resole_lifetime` code.
+    Replace(LtReplacement),
+}
+
+/// The type of elided lifetime replacement to perform on `async fn` return types.
+#[derive(Copy, Clone)]
+enum LtReplacement {
+    /// Fresh name introduced by the single non-dyn elided lifetime
+    /// in the arguments of the async fn.
+    Some(ParamName),
+
+    /// There is no single non-dyn elided lifetime because no lifetimes
+    /// appeared in the arguments.
+    NoLifetimes,
+
+    /// There is no single non-dyn elided lifetime because multiple
+    /// lifetimes appeared in the arguments.
+    MultipleLifetimes,
+}
+
+/// Calculates the `LtReplacement` to use for elided lifetimes in the return
+/// type based on the fresh elided lifetimes introduced in argument position.
+fn get_elided_lt_replacement(arg_position_lifetimes: &[(Span, ParamName)]) -> LtReplacement {
+    match arg_position_lifetimes {
+        [] => LtReplacement::NoLifetimes,
+        [(_span, param)] => LtReplacement::Some(*param),
+        _ => LtReplacement::MultipleLifetimes,
+    }
 }
 
 struct ImplTraitTypeIdVisitor<'a> { ids: &'a mut SmallVec<[NodeId; 1]> }
@@ -778,53 +821,63 @@ impl<'a> LoweringContext<'a> {
 
         let params = lifetimes_to_define
             .into_iter()
-            .map(|(span, hir_name)| {
-                let LoweredNodeId { node_id, hir_id } = self.next_id();
-
-                // Get the name we'll use to make the def-path. Note
-                // that collisions are ok here and this shouldn't
-                // really show up for end-user.
-                let (str_name, kind) = match hir_name {
-                    ParamName::Plain(ident) => (
-                        ident.as_interned_str(),
-                        hir::LifetimeParamKind::InBand,
-                    ),
-                    ParamName::Fresh(_) => (
-                        keywords::UnderscoreLifetime.name().as_interned_str(),
-                        hir::LifetimeParamKind::Elided,
-                    ),
-                    ParamName::Error => (
-                        keywords::UnderscoreLifetime.name().as_interned_str(),
-                        hir::LifetimeParamKind::Error,
-                    ),
-                };
-
-                // Add a definition for the in-band lifetime def.
-                self.resolver.definitions().create_def_with_parent(
-                    parent_id.index,
-                    node_id,
-                    DefPathData::LifetimeParam(str_name),
-                    DefIndexAddressSpace::High,
-                    Mark::root(),
-                    span,
-                );
-
-                hir::GenericParam {
-                    hir_id,
-                    name: hir_name,
-                    attrs: hir_vec![],
-                    bounds: hir_vec![],
-                    span,
-                    pure_wrt_drop: false,
-                    kind: hir::GenericParamKind::Lifetime { kind }
-                }
-            })
+            .map(|(span, hir_name)| self.lifetime_to_generic_param(
+                span, hir_name, parent_id.index,
+            ))
             .chain(in_band_ty_params.into_iter())
             .collect();
 
         (params, res)
     }
 
+    /// Converts a lifetime into a new generic parameter.
+    fn lifetime_to_generic_param(
+        &mut self,
+        span: Span,
+        hir_name: ParamName,
+        parent_index: DefIndex,
+    ) -> hir::GenericParam {
+        let LoweredNodeId { node_id, hir_id } = self.next_id();
+
+        // Get the name we'll use to make the def-path. Note
+        // that collisions are ok here and this shouldn't
+        // really show up for end-user.
+        let (str_name, kind) = match hir_name {
+            ParamName::Plain(ident) => (
+                ident.as_interned_str(),
+                hir::LifetimeParamKind::InBand,
+            ),
+            ParamName::Fresh(_) => (
+                keywords::UnderscoreLifetime.name().as_interned_str(),
+                hir::LifetimeParamKind::Elided,
+            ),
+            ParamName::Error => (
+                keywords::UnderscoreLifetime.name().as_interned_str(),
+                hir::LifetimeParamKind::Error,
+            ),
+        };
+
+        // Add a definition for the in-band lifetime def.
+        self.resolver.definitions().create_def_with_parent(
+            parent_index,
+            node_id,
+            DefPathData::LifetimeParam(str_name),
+            DefIndexAddressSpace::High,
+            Mark::root(),
+            span,
+        );
+
+        hir::GenericParam {
+            hir_id,
+            name: hir_name,
+            attrs: hir_vec![],
+            bounds: hir_vec![],
+            span,
+            pure_wrt_drop: false,
+            kind: hir::GenericParamKind::Lifetime { kind }
+        }
+    }
+
     /// When there is a reference to some lifetime `'a`, and in-band
     /// lifetimes are enabled, then we want to push that lifetime into
     /// the vector of names to define later. In that case, it will get
@@ -928,6 +981,13 @@ impl<'a> LoweringContext<'a> {
             |this| {
                 this.collect_in_band_defs(parent_id, anonymous_lifetime_mode, |this| {
                     let mut params = Vec::new();
+                    // Note: it is necessary to lower generics *before* calling `f`.
+                    // When lowering `async fn`, there's a final step when lowering
+                    // the return type that assumes that all in-scope lifetimes have
+                    // already been added to either `in_scope_lifetimes` or
+                    // `lifetimes_to_define`. If we swapped the order of these two,
+                    // in-band-lifetimes introduced by generics or where-clauses
+                    // wouldn't have been added yet.
                     let generics = this.lower_generics(
                         generics,
                         ImplTraitContext::Universal(&mut params),
@@ -1426,42 +1486,62 @@ impl<'a> LoweringContext<'a> {
 
         self.with_hir_id_owner(exist_ty_node_id, |lctx| {
             let LoweredNodeId { node_id: _, hir_id } = lctx.next_id();
-            let exist_ty_item_kind = hir::ItemKind::Existential(hir::ExistTy {
+            let exist_ty_item = hir::ExistTy {
                 generics: hir::Generics {
                     params: lifetime_defs,
                     where_clause: hir::WhereClause {
                         hir_id,
-                        predicates: Vec::new().into(),
+                        predicates: hir_vec![],
                     },
                     span,
                 },
                 bounds: hir_bounds,
                 impl_trait_fn: 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 {
-                hir_id: exist_ty_id.hir_id,
-                ident: keywords::Invalid.ident(),
-                attrs: Default::default(),
-                node: exist_ty_item_kind,
-                vis: respan(span.shrink_to_lo(), hir::VisibilityKind::Inherited),
-                span: exist_ty_span,
+                origin: hir::ExistTyOrigin::ReturnImplTrait,
             };
 
-            // 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.insert_item(exist_ty_item);
+            trace!("exist ty from impl trait def index: {:#?}", exist_ty_def_index);
+            let exist_ty_id = lctx.generate_existential_type(
+                exist_ty_node_id,
+                exist_ty_item,
+                span,
+                exist_ty_span,
+            );
 
             // `impl Trait` now just becomes `Foo<'a, 'b, ..>`.
             hir::TyKind::Def(hir::ItemId { id: exist_ty_id.hir_id }, lifetimes)
         })
     }
 
+    /// Registers a new existential type with the proper NodeIds and
+    /// returns the lowered node ID for the existential type.
+    fn generate_existential_type(
+        &mut self,
+        exist_ty_node_id: NodeId,
+        exist_ty_item: hir::ExistTy,
+        span: Span,
+        exist_ty_span: Span,
+    ) -> LoweredNodeId {
+        let exist_ty_item_kind = hir::ItemKind::Existential(exist_ty_item);
+        let exist_ty_id = self.lower_node_id(exist_ty_node_id);
+        // Generate an `existential type Foo: Trait;` declaration.
+        trace!("registering existential type with id {:#?}", exist_ty_id);
+        let exist_ty_item = hir::Item {
+            hir_id: exist_ty_id.hir_id,
+            ident: keywords::Invalid.ident(),
+            attrs: Default::default(),
+            node: exist_ty_item_kind,
+            vis: respan(span.shrink_to_lo(), hir::VisibilityKind::Inherited),
+            span: exist_ty_span,
+        };
+
+        // Insert the item into the global item list. This usually happens
+        // automatically for all AST items. But this existential type item
+        // does not actually exist in the AST.
+        self.insert_item(exist_ty_item);
+        exist_ty_id
+    }
+
     fn lifetimes_from_impl_trait_bounds(
         &mut self,
         exist_ty_id: NodeId,
@@ -1569,9 +1649,6 @@ impl<'a> LoweringContext<'a> {
                         name,
                     }));
 
-                    // We need to manually create the ids here, because the
-                    // definitions will go into the explicit `existential type`
-                    // declaration and thus need to have their owner set to that item
                     let def_node_id = self.context.sess.next_node_id();
                     let LoweredNodeId { node_id: _, hir_id } =
                         self.context.lower_node_id_with_owner(def_node_id, self.exist_ty_id);
@@ -2108,23 +2185,42 @@ impl<'a> LoweringContext<'a> {
         impl_trait_return_allow: bool,
         make_ret_async: Option<NodeId>,
     ) -> P<hir::FnDecl> {
-        let inputs = decl.inputs
-            .iter()
-            .map(|arg| {
-                if let Some((_, ref mut ibty)) = in_band_ty_params {
-                    self.lower_ty_direct(&arg.ty, ImplTraitContext::Universal(ibty))
-                } else {
-                    self.lower_ty_direct(&arg.ty, ImplTraitContext::disallowed())
-                }
-            })
-            .collect::<HirVec<_>>();
+        let lt_mode = if make_ret_async.is_some() {
+            // In `async fn`, argument-position elided lifetimes
+            // must be transformed into fresh generic parameters so that
+            // they can be applied to the existential return type.
+            AnonymousLifetimeMode::CreateParameter
+        } else {
+            self.anonymous_lifetime_mode
+        };
+
+        // Remember how many lifetimes were already around so that we can
+        // only look at the lifetime parameters introduced by the arguments.
+        let lifetime_count_before_args = self.lifetimes_to_define.len();
+        let inputs = self.with_anonymous_lifetime_mode(lt_mode, |this| {
+            decl.inputs
+                .iter()
+                .map(|arg| {
+                    if let Some((_, ibty)) = &mut in_band_ty_params {
+                        this.lower_ty_direct(&arg.ty, ImplTraitContext::Universal(ibty))
+                    } else {
+                        this.lower_ty_direct(&arg.ty, ImplTraitContext::disallowed())
+                    }
+                })
+                .collect::<HirVec<_>>()
+        });
 
         let output = if let Some(ret_id) = make_ret_async {
+            // Calculate the `LtReplacement` to use for any return-position elided
+            // lifetimes based on the elided lifetime parameters introduced in the args.
+            let lt_replacement = get_elided_lt_replacement(
+                &self.lifetimes_to_define[lifetime_count_before_args..]
+            );
             self.lower_async_fn_ret_ty(
-                &inputs,
                 &decl.output,
                 in_band_ty_params.expect("make_ret_async but no fn_def_id").0,
                 ret_id,
+                lt_replacement,
             )
         } else {
             match decl.output {
@@ -2173,233 +2269,171 @@ impl<'a> LoweringContext<'a> {
         })
     }
 
-    // Transform `-> T` into `-> impl Future<Output = T>` for `async fn`
+    // Transform `-> T` for `async fn` into -> ExistTy { .. }
+    // combined with the following definition of `ExistTy`:
+    //
+    // existential type ExistTy<generics_from_parent_fn>: Future<Output = T>;
     //
-    // 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.
+    // exist_ty_node_id: NodeId of the existential type that should be created.
+    // elided_lt_replacement: replacement for elided lifetimes in the return type
     fn lower_async_fn_ret_ty(
         &mut self,
-        inputs: &[hir::Ty],
         output: &FunctionRetTy,
         fn_def_id: DefId,
-        return_impl_trait_id: NodeId,
+        exist_ty_node_id: NodeId,
+        elided_lt_replacement: LtReplacement,
     ) -> 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
-            }
+        let span = output.span();
 
-            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::TyKind::BareFn(_) = &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);
-                }
-            }
+        let exist_ty_span = self.mark_span_with_reason(
+            CompilerDesugaringKind::Async,
+            span,
+            None,
+        );
 
-            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);
-            }
+        let exist_ty_def_index = self
+            .resolver
+            .definitions()
+            .opt_def_index(exist_ty_node_id)
+            .unwrap();
 
-            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);
-                }
+        self.allocate_hir_id_counter(exist_ty_node_id);
 
-                hir::intravisit::walk_generic_param(self, param);
-            }
+        let (exist_ty_node_id, lifetime_params) = self.with_hir_id_owner(exist_ty_node_id, |this| {
+            let future_bound = this.with_anonymous_lifetime_mode(
+                AnonymousLifetimeMode::Replace(elided_lt_replacement),
+                |this| this.lower_async_fn_output_type_to_future_bound(
+                    output,
+                    fn_def_id,
+                    span,
+                ),
+            );
 
-            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::Error | hir::LifetimeName::Static => return,
-                };
+            // Calculate all the lifetimes that should be captured
+            // by the existential type. This should include all in-scope
+            // lifetime parameters, including those defined in-band.
+            //
+            // Note: this must be done after lowering the output type,
+            // as the output type may introduce new in-band lifetimes.
+            let lifetime_params: Vec<(Span, ParamName)> =
+                this.in_scope_lifetimes
+                    .iter().cloned()
+                    .map(|ident| (ident.span, ParamName::Plain(ident)))
+                    .chain(this.lifetimes_to_define.iter().cloned())
+                    .collect();
 
-                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,
-                                MultiSpan::from_spans(vec![current_lt_span, lifetime.span]),
-                                E0709,
-                                "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,
-                                MultiSpan::from_spans(vec![current_lt_span, lifetime.span]),
-                                E0707,
-                                "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 generic_params =
+                lifetime_params
+                    .iter().cloned()
+                    .map(|(span, hir_name)| {
+                        this.lifetime_to_generic_param(span, hir_name, exist_ty_def_index)
+                    })
+                    .collect();
 
-        let bound_lifetime = {
-            let mut lifetime_collector = AsyncFnLifetimeCollector {
-                context: self,
-                currently_bound_lifetimes: Vec::new(),
-                collect_elided_lifetimes: true,
-                output_lifetime: None,
+            let LoweredNodeId { node_id: _, hir_id } = this.next_id();
+            let exist_ty_item = hir::ExistTy {
+                generics: hir::Generics {
+                    params: generic_params,
+                    where_clause: hir::WhereClause {
+                        hir_id,
+                        predicates: hir_vec![],
+                    },
+                    span,
+                },
+                bounds: hir_vec![future_bound],
+                impl_trait_fn: Some(fn_def_id),
+                origin: hir::ExistTyOrigin::AsyncFn,
             };
 
-            for arg in inputs {
-                hir::intravisit::walk_ty(&mut lifetime_collector, arg);
-            }
-            lifetime_collector.output_lifetime
-        };
+            trace!("exist ty from async fn def index: {:#?}", exist_ty_def_index);
+            let exist_ty_id = this.generate_existential_type(
+                exist_ty_node_id,
+                exist_ty_item,
+                span,
+                exist_ty_span,
+            );
 
-        let span = match output {
-            FunctionRetTy::Ty(ty) => ty.span,
-            FunctionRetTy::Default(span) => *span,
-        };
+            (exist_ty_id.node_id, lifetime_params)
+        });
 
-        let impl_trait_ty = self.lower_existential_impl_trait(
-            span, Some(fn_def_id), return_impl_trait_id, |this| {
-            let output_ty = match output {
-                FunctionRetTy::Ty(ty) => {
-                    this.lower_ty(ty, ImplTraitContext::Existential(Some(fn_def_id)))
-                }
-                FunctionRetTy::Default(span) => {
-                    let LoweredNodeId { node_id: _, hir_id } = this.next_id();
-                    P(hir::Ty {
+        let generic_args =
+            lifetime_params
+                .iter().cloned()
+                .map(|(span, hir_name)| {
+                    let LoweredNodeId { node_id: _, hir_id  } = self.next_id();
+                    GenericArg::Lifetime(hir::Lifetime {
                         hir_id,
-                        node: hir::TyKind::Tup(hir_vec![]),
-                        span: *span,
+                        span,
+                        name: hir::LifetimeName::Param(hir_name),
                     })
-                }
-            };
-
-            // "<Output = T>"
-            let LoweredNodeId { node_id: _, hir_id } = this.next_id();
-            let future_params = P(hir::GenericArgs {
-                args: hir_vec![],
-                bindings: hir_vec![hir::TypeBinding {
-                    ident: Ident::from_str(FN_OUTPUT_NAME),
-                    ty: output_ty,
-                    hir_id,
-                    span,
-                }],
-                parenthesized: false,
-            });
+                })
+                .collect();
 
-            let future_path =
-                this.std_path(span, &["future", "Future"], Some(future_params), false);
+        let exist_ty_hir_id = self.lower_node_id(exist_ty_node_id).hir_id;
+        let exist_ty_ref = hir::TyKind::Def(hir::ItemId { id: exist_ty_hir_id }, generic_args);
 
-            let LoweredNodeId { node_id: _, hir_id } = this.next_id();
-            let mut bounds = vec![
-                hir::GenericBound::Trait(
-                    hir::PolyTraitRef {
-                        trait_ref: hir::TraitRef {
-                            path: future_path,
-                            hir_ref_id: hir_id,
-                        },
-                        bound_generic_params: hir_vec![],
-                        span,
-                    },
-                    hir::TraitBoundModifier::None
-                ),
-            ];
+        let LoweredNodeId { node_id: _, hir_id } = self.next_id();
+        hir::FunctionRetTy::Return(P(hir::Ty {
+            node: exist_ty_ref,
+            span,
+            hir_id,
+        }))
+    }
 
-            if let Some((name, span)) = bound_lifetime {
-                let LoweredNodeId { node_id: _, hir_id } = this.next_id();
-                bounds.push(hir::GenericBound::Outlives(
-                    hir::Lifetime { hir_id, name, span }));
+    /// Turns `-> T` into `Future<Output = T>`
+    fn lower_async_fn_output_type_to_future_bound(
+        &mut self,
+        output: &FunctionRetTy,
+        fn_def_id: DefId,
+        span: Span,
+    ) -> hir::GenericBound {
+        // Compute the `T` in `Future<Output = T>` from the return type.
+        let output_ty = match output {
+            FunctionRetTy::Ty(ty) => {
+                self.lower_ty(ty, ImplTraitContext::Existential(Some(fn_def_id)))
             }
+            FunctionRetTy::Default(ret_ty_span) => {
+                let LoweredNodeId { node_id: _, hir_id } = self.next_id();
+                P(hir::Ty {
+                    hir_id,
+                    node: hir::TyKind::Tup(hir_vec![]),
+                    span: *ret_ty_span,
+                })
+            }
+        };
 
-            hir::HirVec::from(bounds)
-        });
-
+        // "<Output = T>"
         let LoweredNodeId { node_id: _, hir_id } = self.next_id();
-        let impl_trait_ty = P(hir::Ty {
-            node: impl_trait_ty,
-            span,
-            hir_id,
+        let future_params = P(hir::GenericArgs {
+            args: hir_vec![],
+            bindings: hir_vec![hir::TypeBinding {
+                ident: Ident::from_str(FN_OUTPUT_NAME),
+                ty: output_ty,
+                hir_id,
+                span,
+            }],
+            parenthesized: false,
         });
 
-        hir::FunctionRetTy::Return(impl_trait_ty)
+        // ::std::future::Future<future_params>
+        let future_path =
+            self.std_path(span, &["future", "Future"], Some(future_params), false);
+
+        let LoweredNodeId { node_id: _, hir_id } = self.next_id();
+        hir::GenericBound::Trait(
+            hir::PolyTraitRef {
+                trait_ref: hir::TraitRef {
+                    path: future_path,
+                    hir_ref_id: hir_id,
+                },
+                bound_generic_params: hir_vec![],
+                span,
+            },
+            hir::TraitBoundModifier::None,
+        )
     }
 
     fn lower_param_bound(
@@ -2437,6 +2471,11 @@ impl<'a> LoweringContext<'a> {
                     }
 
                     AnonymousLifetimeMode::ReportError => self.new_error_lifetime(Some(l.id), span),
+
+                    AnonymousLifetimeMode::Replace(replacement) => {
+                        let LoweredNodeId { node_id: _, hir_id  } = self.lower_node_id(l.id);
+                        self.replace_elided_lifetime(hir_id, span, replacement)
+                    }
                 },
             ident => {
                 self.maybe_collect_in_band_lifetime(ident);
@@ -2461,6 +2500,39 @@ impl<'a> LoweringContext<'a> {
         }
     }
 
+    /// Replace a return-position elided lifetime with the elided lifetime
+    /// from the arguments.
+    fn replace_elided_lifetime(
+        &mut self,
+        hir_id: hir::HirId,
+        span: Span,
+        replacement: LtReplacement,
+    ) -> hir::Lifetime {
+        let multiple_or_none = match replacement {
+            LtReplacement::Some(name) => {
+                return hir::Lifetime {
+                    hir_id,
+                    span,
+                    name: hir::LifetimeName::Param(name),
+                };
+            }
+            LtReplacement::MultipleLifetimes => "multiple",
+            LtReplacement::NoLifetimes => "none",
+        };
+
+        let mut err = crate::middle::resolve_lifetime::report_missing_lifetime_specifiers(
+            self.sess,
+            span,
+            1,
+        );
+        err.note(&format!(
+            "return-position elided lifetimes require exactly one \
+             input-position elided lifetime, found {}.", multiple_or_none));
+        err.emit();
+
+        hir::Lifetime { hir_id, span, name: hir::LifetimeName::Error }
+    }
+
     fn lower_generic_params(
         &mut self,
         params: &[GenericParam],
@@ -2941,6 +3013,7 @@ impl<'a> LoweringContext<'a> {
                 generics: self.lower_generics(generics, ImplTraitContext::disallowed()),
                 bounds: self.lower_param_bounds(b, ImplTraitContext::disallowed()),
                 impl_trait_fn: None,
+                origin: hir::ExistTyOrigin::ExistentialType,
             }),
             ItemKind::Enum(ref enum_definition, ref generics) => hir::ItemKind::Enum(
                 hir::EnumDef {
@@ -5083,7 +5156,8 @@ impl<'a> LoweringContext<'a> {
     /// with no explicit lifetime.
     fn elided_ref_lifetime(&mut self, span: Span) -> hir::Lifetime {
         match self.anonymous_lifetime_mode {
-            // Intercept when we are in an impl header and introduce an in-band lifetime.
+            // Intercept when we are in an impl header or async fn and introduce an in-band
+            // lifetime.
             // Hence `impl Foo for &u32` becomes `impl<'f> Foo for &'f u32` for some fresh
             // `'f`.
             AnonymousLifetimeMode::CreateParameter => {
@@ -5099,6 +5173,10 @@ impl<'a> LoweringContext<'a> {
             AnonymousLifetimeMode::ReportError => self.new_error_lifetime(None, span),
 
             AnonymousLifetimeMode::PassThrough => self.new_implicit_lifetime(span),
+
+            AnonymousLifetimeMode::Replace(replacement) => {
+                self.new_replacement_lifetime(replacement, span)
+            }
         }
     }
 
@@ -5133,6 +5211,12 @@ impl<'a> LoweringContext<'a> {
     /// sorts of cases are deprecated. This may therefore report a warning or an
     /// error, depending on the mode.
     fn elided_path_lifetimes(&mut self, span: Span, count: usize) -> P<[hir::Lifetime]> {
+        (0..count)
+            .map(|_| self.elided_path_lifetime(span))
+            .collect()
+    }
+
+    fn elided_path_lifetime(&mut self, span: Span) -> hir::Lifetime {
         match self.anonymous_lifetime_mode {
             // N.B., We intentionally ignore the create-parameter mode here
             // and instead "pass through" to resolve-lifetimes, which will then
@@ -5140,21 +5224,16 @@ impl<'a> LoweringContext<'a> {
             // impl elision for deprecated forms like
             //
             //     impl Foo for std::cell::Ref<u32> // note lack of '_
-            AnonymousLifetimeMode::CreateParameter => {}
+            AnonymousLifetimeMode::CreateParameter |
+            // This is the normal case.
+            AnonymousLifetimeMode::PassThrough => self.new_implicit_lifetime(span),
 
-            AnonymousLifetimeMode::ReportError => {
-                return (0..count)
-                    .map(|_| self.new_error_lifetime(None, span))
-                    .collect();
+            AnonymousLifetimeMode::Replace(replacement) => {
+                self.new_replacement_lifetime(replacement, span)
             }
 
-            // This is the normal case.
-            AnonymousLifetimeMode::PassThrough => {}
+            AnonymousLifetimeMode::ReportError => self.new_error_lifetime(None, span),
         }
-
-        (0..count)
-            .map(|_| self.new_implicit_lifetime(span))
-            .collect()
     }
 
     /// Invoked to create the lifetime argument(s) for an elided trait object
@@ -5184,11 +5263,25 @@ impl<'a> LoweringContext<'a> {
 
             // This is the normal case.
             AnonymousLifetimeMode::PassThrough => {}
+
+            // We don't need to do any replacement here as this lifetime
+            // doesn't refer to an elided lifetime elsewhere in the function
+            // signature.
+            AnonymousLifetimeMode::Replace(_) => {}
         }
 
         self.new_implicit_lifetime(span)
     }
 
+    fn new_replacement_lifetime(
+        &mut self,
+        replacement: LtReplacement,
+        span: Span,
+    ) -> hir::Lifetime {
+        let LoweredNodeId { node_id: _, hir_id } = self.next_id();
+        self.replace_elided_lifetime(hir_id, span, replacement)
+    }
+
     fn new_implicit_lifetime(&mut self, span: Span) -> hir::Lifetime {
         let LoweredNodeId { node_id: _, hir_id } = self.next_id();
 
diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs
index 8509ddaccf7..58a27d3f78e 100644
--- a/src/librustc/hir/mod.rs
+++ b/src/librustc/hir/mod.rs
@@ -1799,6 +1799,18 @@ pub struct ExistTy {
     pub generics: Generics,
     pub bounds: GenericBounds,
     pub impl_trait_fn: Option<DefId>,
+    pub origin: ExistTyOrigin,
+}
+
+/// Where the existential type came from
+#[derive(Copy, Clone, RustcEncodable, RustcDecodable, Debug, HashStable)]
+pub enum ExistTyOrigin {
+    /// `existential type Foo: Trait;`
+    ExistentialType,
+    /// `-> impl Trait`
+    ReturnImplTrait,
+    /// `async fn`
+    AsyncFn,
 }
 
 /// The various kinds of types recognized by the compiler.
diff --git a/src/librustc/infer/opaque_types/mod.rs b/src/librustc/infer/opaque_types/mod.rs
index 8bd20843163..be9460ad86f 100644
--- a/src/librustc/infer/opaque_types/mod.rs
+++ b/src/librustc/infer/opaque_types/mod.rs
@@ -67,6 +67,9 @@ pub struct OpaqueTypeDecl<'tcx> {
     /// the fn body). (Ultimately, writeback is responsible for this
     /// check.)
     pub has_required_region_bounds: bool,
+
+    /// The origin of the existential type
+    pub origin: hir::ExistTyOrigin,
 }
 
 impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
@@ -326,14 +329,39 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
                         // There are two regions (`lr` and
                         // `subst_arg`) which are not relatable. We can't
                         // find a best choice.
-                        self.tcx
+                        let context_name = match opaque_defn.origin {
+                            hir::ExistTyOrigin::ExistentialType => "existential type",
+                            hir::ExistTyOrigin::ReturnImplTrait => "impl Trait",
+                            hir::ExistTyOrigin::AsyncFn => "async fn",
+                        };
+                        let msg = format!("ambiguous lifetime bound in `{}`", context_name);
+                        let mut err = self.tcx
                             .sess
-                            .struct_span_err(span, "ambiguous lifetime bound in `impl Trait`")
-                            .span_label(
-                                span,
-                                format!("neither `{}` nor `{}` outlives the other", lr, subst_arg),
-                            )
-                            .emit();
+                            .struct_span_err(span, &msg);
+
+                        let lr_name = lr.to_string();
+                        let subst_arg_name = subst_arg.to_string();
+                        let label_owned;
+                        let label = match (&*lr_name, &*subst_arg_name) {
+                            ("'_", "'_") => "the elided lifetimes here do not outlive one another",
+                            _ => {
+                                label_owned = format!(
+                                    "neither `{}` nor `{}` outlives the other",
+                                    lr_name,
+                                    subst_arg_name,
+                                );
+                                &label_owned
+                            }
+                        };
+                        err.span_label(span, label);
+
+                        if let hir::ExistTyOrigin::AsyncFn = opaque_defn.origin {
+                            err.note("multiple unrelated lifetimes are not allowed in \
+                                     `async fn`.");
+                            err.note("if you're using argument-position elided lifetimes, consider \
+                                switching to a single named lifetime.");
+                        }
+                        err.emit();
 
                         least_region = Some(self.tcx.mk_region(ty::ReEmpty));
                         break;
@@ -692,31 +720,41 @@ impl<'a, 'gcx, 'tcx> Instantiator<'a, 'gcx, 'tcx> {
                             parent_def_id == tcx.hir()
                                                 .local_def_id_from_hir_id(opaque_parent_hir_id)
                         };
-                        let in_definition_scope = match tcx.hir().find_by_hir_id(opaque_hir_id) {
+                        let (in_definition_scope, origin) =
+                            match tcx.hir().find_by_hir_id(opaque_hir_id)
+                        {
                             Some(Node::Item(item)) => match item.node {
                                 // impl trait
                                 hir::ItemKind::Existential(hir::ExistTy {
                                     impl_trait_fn: Some(parent),
+                                    origin,
                                     ..
-                                }) => parent == self.parent_def_id,
+                                }) => (parent == self.parent_def_id, origin),
                                 // named existential types
                                 hir::ItemKind::Existential(hir::ExistTy {
                                     impl_trait_fn: None,
+                                    origin,
                                     ..
-                                }) => may_define_existential_type(
-                                    tcx,
-                                    self.parent_def_id,
-                                    opaque_hir_id,
+                                }) => (
+                                    may_define_existential_type(
+                                        tcx,
+                                        self.parent_def_id,
+                                        opaque_hir_id,
+                                    ),
+                                    origin,
                                 ),
-                                _ => def_scope_default(),
+                                _ => (def_scope_default(), hir::ExistTyOrigin::ExistentialType),
                             },
                             Some(Node::ImplItem(item)) => match item.node {
-                                hir::ImplItemKind::Existential(_) => may_define_existential_type(
-                                    tcx,
-                                    self.parent_def_id,
-                                    opaque_hir_id,
+                                hir::ImplItemKind::Existential(_) => (
+                                    may_define_existential_type(
+                                        tcx,
+                                        self.parent_def_id,
+                                        opaque_hir_id,
+                                    ),
+                                    hir::ExistTyOrigin::ExistentialType,
                                 ),
-                                _ => def_scope_default(),
+                                _ => (def_scope_default(), hir::ExistTyOrigin::ExistentialType),
                             },
                             _ => bug!(
                                 "expected (impl) item, found {}",
@@ -724,7 +762,7 @@ impl<'a, 'gcx, 'tcx> Instantiator<'a, 'gcx, 'tcx> {
                             ),
                         };
                         if in_definition_scope {
-                            return self.fold_opaque_ty(ty, def_id, substs);
+                            return self.fold_opaque_ty(ty, def_id, substs, origin);
                         }
 
                         debug!(
@@ -746,6 +784,7 @@ impl<'a, 'gcx, 'tcx> Instantiator<'a, 'gcx, 'tcx> {
         ty: Ty<'tcx>,
         def_id: DefId,
         substs: SubstsRef<'tcx>,
+        origin: hir::ExistTyOrigin,
     ) -> Ty<'tcx> {
         let infcx = self.infcx;
         let tcx = infcx.tcx;
@@ -795,6 +834,7 @@ impl<'a, 'gcx, 'tcx> Instantiator<'a, 'gcx, 'tcx> {
                 substs,
                 concrete_ty: ty_var,
                 has_required_region_bounds: !required_region_bounds.is_empty(),
+                origin,
             },
         );
         debug!("instantiate_opaque_types: ty_var={:?}", ty_var);
diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs
index 73e232a6a4f..3306bcae212 100644
--- a/src/librustc/middle/resolve_lifetime.rs
+++ b/src/librustc/middle/resolve_lifetime.rs
@@ -2891,7 +2891,7 @@ fn insert_late_bound_lifetimes(
     }
 }
 
-fn report_missing_lifetime_specifiers(
+pub fn report_missing_lifetime_specifiers(
     sess: &Session,
     span: Span,
     count: usize,
diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs
index 5edb8c92a3b..f92fa2e9799 100644
--- a/src/librustc_typeck/collect.rs
+++ b/src/librustc_typeck/collect.rs
@@ -1979,6 +1979,7 @@ fn explicit_predicates_of<'a, 'tcx>(
                     ref bounds,
                     impl_trait_fn,
                     ref generics,
+                    origin: _,
                 }) => {
                     let substs = InternalSubsts::identity_for_item(tcx, def_id);
                     let opaque_ty = tcx.mk_opaque(def_id, substs);
diff --git a/src/test/run-pass/async-await.rs b/src/test/run-pass/async-await.rs
index 1843feed927..72af5162992 100644
--- a/src/test/run-pass/async-await.rs
+++ b/src/test/run-pass/async-await.rs
@@ -79,6 +79,11 @@ async fn async_fn(x: u8) -> u8 {
     x
 }
 
+async fn generic_async_fn<T>(x: T) -> T {
+    await!(wake_and_yield_once());
+    x
+}
+
 async fn async_fn_with_borrow(x: &u8) -> u8 {
     await!(wake_and_yield_once());
     *x
@@ -96,14 +101,21 @@ fn async_fn_with_impl_future_named_lifetime<'a>(x: &'a u8) -> impl Future<Output
     }
 }
 
-async fn async_fn_with_named_lifetime_multiple_args<'a>(x: &'a u8, _y: &'a u8) -> u8 {
+/* FIXME(cramertj) support when `existential type T<'a, 'b>:;` works
+async fn async_fn_multiple_args(x: &u8, _y: &u8) -> u8 {
+    await!(wake_and_yield_once());
+    *x
+}
+*/
+
+async fn async_fn_multiple_args_named_lifetime<'a>(x: &'a u8, _y: &'a 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))
+        await!(async_fn_with_borrow_named_lifetime(&y))
     }
 }
 
@@ -162,6 +174,7 @@ fn main() {
         async_nonmove_block,
         async_closure,
         async_fn,
+        generic_async_fn,
         async_fn_with_internal_borrow,
         Foo::async_method,
         |x| {
@@ -170,7 +183,6 @@ fn main() {
             }
         },
     }
-
     test_with_borrow! {
         async_block_with_borrow_named_lifetime,
         async_fn_with_borrow,
@@ -178,7 +190,7 @@ fn main() {
         async_fn_with_impl_future_named_lifetime,
         |x| {
             async move {
-                await!(async_fn_with_named_lifetime_multiple_args(x, x))
+                await!(async_fn_multiple_args_named_lifetime(x, x))
             }
         },
     }
diff --git a/src/test/ui/async-fn-multiple-lifetimes.rs b/src/test/ui/async-fn-multiple-lifetimes.rs
index 6156617c4da..fccc4fdb917 100644
--- a/src/test/ui/async-fn-multiple-lifetimes.rs
+++ b/src/test/ui/async-fn-multiple-lifetimes.rs
@@ -5,7 +5,7 @@
 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`
+//~^ ERROR ambiguous lifetime bound in `async fn`
 
 async fn multiple_hrtb_and_single_named_lifetime_ok<'c>(
     _: impl for<'a> Add<&'a u8>,
@@ -14,7 +14,6 @@ async fn multiple_hrtb_and_single_named_lifetime_ok<'c>(
 ) {}
 
 async fn multiple_elided_lifetimes(_: &u8, _: &u8) {}
-//~^ ERROR multiple elided lifetimes used
-//~^^ ERROR missing lifetime specifier
+//~^ ambiguous lifetime bound in `async fn`
 
 fn main() {}
diff --git a/src/test/ui/async-fn-multiple-lifetimes.stderr b/src/test/ui/async-fn-multiple-lifetimes.stderr
index 071349b23fa..8c3ee2bed83 100644
--- a/src/test/ui/async-fn-multiple-lifetimes.stderr
+++ b/src/test/ui/async-fn-multiple-lifetimes.stderr
@@ -1,32 +1,20 @@
-error[E0709]: multiple different lifetimes used in arguments of `async fn`
-  --> $DIR/async-fn-multiple-lifetimes.rs:7:47
+error: ambiguous lifetime bound in `async fn`
+  --> $DIR/async-fn-multiple-lifetimes.rs:7:65
    |
 LL | async fn multiple_named_lifetimes<'a, 'b>(_: &'a u8, _: &'b u8) {}
-   |                                               ^^         ^^ different lifetime here
-   |                                               |
-   |                                               first lifetime here
+   |                                                                 ^ neither `'a` nor `'b` outlives the other
    |
-   = help: `async fn` can only accept borrowed values with identical lifetimes
+   = note: multiple unrelated lifetimes are not allowed in `async fn`.
+   = note: if you're using argument-position elided lifetimes, consider switching to a single named lifetime.
 
-error[E0707]: multiple elided lifetimes used in arguments of `async fn`
-  --> $DIR/async-fn-multiple-lifetimes.rs:16:39
+error: ambiguous lifetime bound in `async fn`
+  --> $DIR/async-fn-multiple-lifetimes.rs:16:52
    |
 LL | async fn multiple_elided_lifetimes(_: &u8, _: &u8) {}
-   |                                       ^       ^ different lifetime here
-   |                                       |
-   |                                       first lifetime here
+   |                                                    ^ the elided lifetimes here do not outlive one another
    |
-   = help: consider giving these arguments named lifetimes
+   = note: multiple unrelated lifetimes are not allowed in `async fn`.
+   = note: if you're using argument-position elided lifetimes, consider switching to a single named lifetime.
 
-error[E0106]: missing lifetime specifier
-  --> $DIR/async-fn-multiple-lifetimes.rs:16: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
+error: aborting due to 2 previous errors
 
-Some errors occurred: E0106, E0707, E0709.
-For more information about an error, try `rustc --explain E0106`.
diff --git a/src/test/ui/issues/issue-54974.rs b/src/test/ui/issues/issue-54974.rs
new file mode 100644
index 00000000000..b2624ec92a1
--- /dev/null
+++ b/src/test/ui/issues/issue-54974.rs
@@ -0,0 +1,16 @@
+// compile-pass
+// edition:2018
+
+#![feature(async_await, await_macro, futures_api)]
+
+use std::sync::Arc;
+
+trait SomeTrait: Send + Sync + 'static {
+    fn do_something(&self);
+}
+
+async fn my_task(obj: Arc<SomeTrait>) {
+    unimplemented!()
+}
+
+fn main() {}
diff --git a/src/test/ui/issues/issue-55324.rs b/src/test/ui/issues/issue-55324.rs
new file mode 100644
index 00000000000..6160fbabd96
--- /dev/null
+++ b/src/test/ui/issues/issue-55324.rs
@@ -0,0 +1,14 @@
+// compile-pass
+// edition:2018
+
+#![feature(async_await, await_macro, futures_api)]
+
+use std::future::Future;
+
+#[allow(unused)]
+async fn foo<F: Future<Output = i32>>(x: &i32, future: F) -> i32 {
+    let y = await!(future);
+    *x + y
+}
+
+fn main() {}
diff --git a/src/test/ui/issues/issue-58885.rs b/src/test/ui/issues/issue-58885.rs
new file mode 100644
index 00000000000..559899194fb
--- /dev/null
+++ b/src/test/ui/issues/issue-58885.rs
@@ -0,0 +1,21 @@
+// compile-pass
+// edition:2018
+
+#![feature(async_await, await_macro, futures_api)]
+
+struct Xyz {
+    a: u64,
+}
+
+trait Foo {}
+
+impl Xyz {
+    async fn do_sth<'a>(
+        &'a self, foo: &'a dyn Foo
+    ) -> bool
+    {
+        true
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/issues/issue-59001.rs b/src/test/ui/issues/issue-59001.rs
new file mode 100644
index 00000000000..a310653fbce
--- /dev/null
+++ b/src/test/ui/issues/issue-59001.rs
@@ -0,0 +1,17 @@
+// compile-pass
+// edition:2018
+
+#![feature(async_await, await_macro, futures_api)]
+
+use std::future::Future;
+
+#[allow(unused)]
+async fn enter<'a, F, R>(mut callback: F)
+where
+    F: FnMut(&'a mut i32) -> R,
+    R: Future<Output = ()> + 'a,
+{
+    unimplemented!()
+}
+
+fn main() {}