Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

__arg variables from async fn desugaring are accessible to the user #60438

Closed
nikomatsakis opened this issue May 1, 2019 · 1 comment · Fixed by #60437
Closed

__arg variables from async fn desugaring are accessible to the user #60438

nikomatsakis opened this issue May 1, 2019 · 1 comment · Fixed by #60437
Assignees
Labels
A-async-await Area: Async & Await T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.

Comments

@nikomatsakis
Copy link
Contributor

The fixes for #54716 and #60236 introduced __arg variables that, presently, are accessible to the user (playground):

#![feature(async_await)]

async fn foo(_: usize) {
    println!("{}", __arg0);
}

fn main() { }

This code compiles, but it should error.

@nikomatsakis nikomatsakis added T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. A-async-await Area: Async & Await labels May 1, 2019
@davidtwco
Copy link
Member

A complete test case:

// aux-build:arc_wake.rs
// edition:2018

#![allow(unused_variables)]
#![feature(async_await, await_macro)]

extern crate arc_wake;

use arc_wake::ArcWake;
use std::future::Future;
use std::sync::Arc;
use std::task::Context;

struct EmptyWaker;

impl ArcWake for EmptyWaker {
    fn wake(self: Arc<Self>) {}
}

async fn foobar_async(x: u32, (a, _, _c): (u32, u32, u32), _: u32, _y: u32) {
    assert_eq!(__arg1, (1, 2, 3)); // this doesn't compile error, but should
    assert_eq!(__arg2, 4);
}

fn main() {
    let empty = Arc::new(EmptyWaker);
    let waker = ArcWake::into_waker(empty);
    let mut cx = Context::from_waker(&waker);

    let mut fut = Box::pin(foobar_async(0, (1, 2, 3), 4, 0));
    let _ = fut.as_mut().poll(&mut cx);
}

@davidtwco davidtwco self-assigned this May 1, 2019
Centril added a commit to Centril/rust that referenced this issue May 1, 2019
Ensure that drop order of `async fn` matches `fn` and that users cannot refer to generated arguments.

Fixes rust-lang#60236 and fixes rust-lang#60438.

This PR modifies the lowering of `async fn` arguments so that the
drop order matches the equivalent `fn`.

Previously, async function arguments were lowered as shown below:

    async fn foo(<pattern>: <ty>) {
      async move {
      }
    } // <-- dropped as you "exit" the fn

    // ...becomes...
    fn foo(__arg0: <ty>) {
      async move {
        let <pattern> = __arg0;
      } // <-- dropped as you "exit" the async block
    }

After this PR, async function arguments will be lowered as:

    async fn foo(<pattern>: <ty>, <pattern>: <ty>, <pattern>: <ty>) {
      async move {
      }
    } // <-- dropped as you "exit" the fn

    // ...becomes...
    fn foo(__arg0: <ty>, __arg1: <ty>, __arg2: <ty>) {
      async move {
        let __arg2 = __arg2;
        let <pattern> = __arg2;
        let __arg1 = __arg1;
        let <pattern> = __arg1;
        let __arg0 = __arg0;
        let <pattern> = __arg0;
      } // <-- dropped as you "exit" the async block
    }

If `<pattern>` is a simple ident, then it is lowered to a single
`let <pattern> = <pattern>;` statement as an optimization.

This PR also stops users from referring to the generated `__argN`
identifiers.

r? @nikomatsakis
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-async-await Area: Async & Await T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.
Projects
None yet
2 participants