Skip to content

rustfmt removes "async" keyword in experimental feature, changing the meaning of the code #6070

Closed
@RalfJung

Description

@RalfJung

When formatting this file

#![feature(async_closure, noop_waker, async_fn_traits)]
//@compile-flags: --edition 2018

use std::future::Future;
use std::pin::pin;
use std::task::*;

pub fn block_on<T>(fut: impl Future<Output = T>) -> T {
    let mut fut = pin!(fut);
    let ctx = &mut Context::from_waker(Waker::noop());

    loop {
        match fut.as_mut().poll(ctx) {
            Poll::Pending => {}
            Poll::Ready(t) => break t,
        }
    }
}

async fn call_once(f: impl async FnOnce(DropMe)) { // <--- this line is changed
    f(DropMe("world")).await;
}

#[derive(Debug)]
struct DropMe(&'static str);

impl Drop for DropMe {
    fn drop(&mut self) {
        println!("{}", self.0);
    }
}

pub fn main() {
    block_on(async {
        let b = DropMe("hello");
        let async_closure = async move |a: DropMe| {
            println!("{a:?} {b:?}");
        };
        call_once(async_closure).await;
    });
}

rustfmt removes the 2nd async in the marked line, changing impl async FnOnce to impl FnOnce. The code then fails to compile.

Of course rustfmt can't be expected to properly format experimental syntax, but it'd be better if rustfmt could at least not entirely remove experimental syntax, and rather leave it unchanged. :) This caused a ton of confusion in rust-lang/miri#3298 while I was trying to figure out why the test worked on rustc CI but failed on Miri CI... until Oli realized the automatically applied formatting broke the code.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugPanic, non-idempotency, invalid code, etc.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions