Skip to content

async/await: Potentially incorrect lifetime handling when structs with lifetimes are referenced #58884

Description

@Matthias247

The following code (playground) produces a compiler error, even if there doesn't seem to be an obvious lifetime issue:

#![feature(futures_api, async_await, await_macro)]

struct Ctx<'a> {
    a: &'a str,
}

async fn read_loop<'a>(
    ctx: &'a mut Ctx<'a>,
) -> Result<(), ()>
{
    loop {
        await!(read_single(ctx))?;
    }
    Ok(())
}

async fn read_single<'a>(
    ctx: &'a mut Ctx<'a>,
) -> Result<(), ()>
{
    let _ = ctx.a;
    Ok(())
}

The error message is:

error[E0499]: cannot borrow `*ctx` as mutable more than once at a time
  --> src/lib.rs:12:28
   |
8  |     ctx: &'a mut Ctx<'a>,
   |     --- lifetime `'1` appears in the type of `ctx`
...
12 |         await!(read_single(ctx))?;
   |                ------------^^^-
   |                |           |
   |                |           mutable borrow starts here in previous iteration of loop
   |                argument requires that `*ctx` is borrowed for `'1`

That seems very confusing (or wrong), given that the function doesn't return anything with a lifetime. It works without the loop. An additional scope doesn't help.

I tried to work around it by introducing another lifetime for ctx, but doesn't work, since async/await doesn't support it yet.

I got another hint to write an explicit impl Future signature, which allows compiling this simplified example: https://play.rust-lang.org/?version=nightly&mode=debug&edition=2018&gist=f006c176dea64435e984cb46bcfef56d
But I feel the more basic variant should work too.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions