Change:
This has already tripped up some people which seem to get quite confused with this error message, so I'd rather we not regress here: I tried this code: I expected to see this happen: Code compiles fine: the type of is . Instead, this happened: The type of is not send, since the backing state-machine generator produced for it now captures part of the internals involving a reference to the , which is not . It most recently worked on: beta : modify labels: +regression-from-stable-to-nightly -regression-untriaged
Might be related to / ?
I was also suspecting one of those, although I have to admit not having looked into it any further
Does it work with btw ? That should completely disable drop range tracking. (I've launched a try build there so that we have artifacts ready for that soon). There were also recent changes in the formatting macros/machinery last week IIRC. That could be related as well. This should be easy enough to bisect, and make sure where the regression is coming from.
Answering my own questions: doesn't change this, my guess is that it's actually unrelated to initially landed as part of and that rollup's commit doesn't reproduce the issue the change I mentioned was and its commit does reproduce the issue. This PR seems to have caused it indeed.
Nice investigation
Assigning priority as discussed in the of the Prioritization Working Group. label -I-prioritize +P-high

Discussion:
use rustc_ast as ast; use rustc_ast::ptr::P; use rustc_ast::tokenstream::TokenStream; <ins> use rustc_ast::visit::{self, Visitor}; </ins> use rustc_ast::{token, BlockCheckMode, UnsafeSource}; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_errors::{pluralize, Applicability, DiagnosticBuilder};

// the order provided to fmt::Arguments. When arguments are repeated, we // want the expression evaluated only once. // <del> // Thus in the not nicely ordered case we emit the following instead: </del> <ins> // Further, if any arg _after the first one_ contains a yield point such // as `await` or `yield`, the above short form is inconvenient for the // caller because it would keep a temporary of type ArgumentV1 alive // across the yield point. ArgumentV1 can't implement Send since it // holds a type-erased arbitrary type. // // Thus in the not nicely ordered case, and in the yielding case, we // emit the following instead: </ins> // //     match (&$arg0, &$arg1, …) { //         args => [ArgumentV1::new(args.$i, …), ArgumentV1::new(args.$j, …), …] //     } // // for the sequence of indices $i, $j, … governed by fmt_arg_index_and_ty. <ins> // This more verbose representation ensures that all arguments are // evaluated a single time each, in the order written by the programmer, // and that the surrounding future/generator (if any) is Send whenever // possible. let no_need_for_match = nicely_ordered && !original_args.iter().skip(1).any(|e| may_contain_yield_point(e)); </ins> for (arg_index, arg_ty) in fmt_arg_index_and_ty { let e = &mut original_args[arg_index]; let span = e.span; <del> let arg = if nicely_ordered { </del> <ins> let arg = if no_need_for_match { </ins> let expansion_span = e.span.with_ctxt(self.macsp.ctxt()); // The indices are strictly ordered so e has not been taken yet. self.ecx.expr_addr_of(expansion_span, P(e.take()))

let args_array = self.ecx.expr_vec(self.macsp, fmt_args); let args_slice = self.ecx.expr_addr_of( self.macsp, <del> if nicely_ordered { </del> <ins> if no_need_for_match { </ins> args_array } else { <del> // In the !nicely_ordered case, none of the exprs were moved </del> <ins> // In the !no_need_for_match case, none of the exprs were moved </ins> // away in the previous loop. // // This uses the arg span for `&arg` so that borrowck errors

cx.into_expr() } <ins> fn may_contain_yield_point(e: &ast::Expr) -> bool { struct MayContainYieldPoint(bool); impl Visitor<'_> for MayContainYieldPoint { fn visit_expr(&mut self, e: &ast::Expr) { if let ast::ExprKind::Await(_) | ast::ExprKind::Yield(_) = e.kind { self.0 = true; } else { visit::walk_expr(self, e); } } fn visit_mac_call(&mut self, _: &ast::MacCall) { self.0 = true; } fn visit_attribute(&mut self, _: &ast::Attribute) { // Conservatively assume this may be a proc macro attribute in // expression position. self.0 = true; } fn visit_item(&mut self, _: &ast::Item) { // Do not recurse into nested items. } } let mut visitor = MayContainYieldPoint(false); visitor.visit_expr(e); visitor.0 } </ins>

<ins> // check-pass // edition:2021 macro_rules! m { () => { async {}.await }; } async fn with_await() { println!("{} {:?}", "", async {}.await); } async fn with_macro_call_expr() { println!("{} {:?}", "", m!()); } async fn with_macro_call_stmt_semi() { println!("{} {:?}", "", { m!(); }); } async fn with_macro_call_stmt_braced() { println!("{} {:?}", "", { m!{} }); } fn assert_send(_: impl Send) {} fn main() { assert_send(with_await()); assert_send(with_macro_call_expr()); assert_send(with_macro_call_stmt_semi()); assert_send(with_macro_call_stmt_braced()); } </ins>