From d5fbefe069a5babd1d3a91a8e1fb2b65aae951b2 Mon Sep 17 00:00:00 2001 From: Pavel Grigorenko Date: Tue, 21 Apr 2026 18:13:30 +0300 Subject: [PATCH 1/5] VariantIdx::ONE --- compiler/rustc_abi/src/layout.rs | 7 +++++++ compiler/rustc_const_eval/src/interpret/call.rs | 10 ++++------ compiler/rustc_middle/src/ty/layout.rs | 4 ++-- compiler/rustc_mir_transform/src/coroutine.rs | 4 ++-- 4 files changed, 15 insertions(+), 10 deletions(-) diff --git a/compiler/rustc_abi/src/layout.rs b/compiler/rustc_abi/src/layout.rs index 2a2765a436bb5..b9dd0907b9586 100644 --- a/compiler/rustc_abi/src/layout.rs +++ b/compiler/rustc_abi/src/layout.rs @@ -80,6 +80,13 @@ rustc_index::newtype_index! { } } +impl VariantIdx { + /// The second variant, at index 1. + /// + /// For use alongside [`VariantIdx::ZERO`]. + pub const ONE: VariantIdx = VariantIdx::from_u32(1); +} + // A variant is absent if it's uninhabited and only has ZST fields. // Present uninhabited variants only require space for their fields, // but *not* an encoding of the discriminant (e.g., a tag value). diff --git a/compiler/rustc_const_eval/src/interpret/call.rs b/compiler/rustc_const_eval/src/interpret/call.rs index edbb668024455..6eba4cfbcd507 100644 --- a/compiler/rustc_const_eval/src/interpret/call.rs +++ b/compiler/rustc_const_eval/src/interpret/call.rs @@ -120,12 +120,10 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { // If one variant consists entirely of 1-ZST, then the other variant // is the only "relevant" one for this check. - let var0 = VariantIdx::from_u32(0); - let var1 = VariantIdx::from_u32(1); - let relevant_variant = if all_fields_1zst(def.variant(var0))? { - def.variant(var1) - } else if all_fields_1zst(def.variant(var1))? { - def.variant(var0) + let relevant_variant = if all_fields_1zst(def.variant(VariantIdx::ZERO))? { + def.variant(VariantIdx::ONE) + } else if all_fields_1zst(def.variant(VariantIdx::ONE))? { + def.variant(VariantIdx::ZERO) } else { // No variant is all-1-ZST, so no NPO. return interp_ok(layout); diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs index 7155df08ec59d..183018ecc5663 100644 --- a/compiler/rustc_middle/src/ty/layout.rs +++ b/compiler/rustc_middle/src/ty/layout.rs @@ -1066,9 +1066,9 @@ where && this.fields.offset(tag_field.as_usize()) == offset => { let tagged_variant = if *untagged_variant == VariantIdx::ZERO { - VariantIdx::from_u32(1) + VariantIdx::ONE } else { - VariantIdx::from_u32(0) + VariantIdx::ZERO }; assert_eq!(tagged_variant, *niche_variants.start()); if *niche_start == 0 { diff --git a/compiler/rustc_mir_transform/src/coroutine.rs b/compiler/rustc_mir_transform/src/coroutine.rs index a71d8266d8374..a3c3aead84bd9 100644 --- a/compiler/rustc_mir_transform/src/coroutine.rs +++ b/compiler/rustc_mir_transform/src/coroutine.rs @@ -282,7 +282,7 @@ impl<'tcx> TransformVisitor<'tcx> { statements: &mut Vec>, ) { const ZERO: VariantIdx = VariantIdx::ZERO; - const ONE: VariantIdx = VariantIdx::from_usize(1); + const ONE: VariantIdx = VariantIdx::ONE; let rvalue = match self.coroutine_kind { CoroutineKind::Desugared(CoroutineDesugaring::Async, _) => { let poll_def_id = self.tcx.require_lang_item(LangItem::Poll, source_info.span); @@ -1121,7 +1121,7 @@ fn return_poll_ready_assign<'tcx>(tcx: TyCtxt<'tcx>, source_info: SourceInfo) -> const_: Const::zero_sized(tcx.types.unit), })); let ready_val = Rvalue::Aggregate( - Box::new(AggregateKind::Adt(poll_def_id, VariantIdx::from_usize(0), args, None, None)), + Box::new(AggregateKind::Adt(poll_def_id, VariantIdx::ZERO, args, None, None)), indexvec![val], ); Statement::new(source_info, StatementKind::Assign(Box::new((Place::return_place(), ready_val)))) From c68002acd5895c157a85244198697b3273703162 Mon Sep 17 00:00:00 2001 From: Pavel Grigorenko Date: Tue, 21 Apr 2026 18:13:30 +0300 Subject: [PATCH 2/5] mir_tranform/coroutine: small tweak --- compiler/rustc_mir_transform/src/coroutine.rs | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_mir_transform/src/coroutine.rs b/compiler/rustc_mir_transform/src/coroutine.rs index a3c3aead84bd9..0f4627e29a8bb 100644 --- a/compiler/rustc_mir_transform/src/coroutine.rs +++ b/compiler/rustc_mir_transform/src/coroutine.rs @@ -1277,14 +1277,15 @@ fn create_coroutine_resume_function<'tcx>( if can_return { let block = match transform.coroutine_kind { CoroutineKind::Desugared(CoroutineDesugaring::Async, _) - | CoroutineKind::Coroutine(_) => { + if tcx.is_async_drop_in_place_coroutine(body.source.def_id()) => + { // For `async_drop_in_place::{closure}` we just keep return Poll::Ready, // because async drop of such coroutine keeps polling original coroutine - if tcx.is_async_drop_in_place_coroutine(body.source.def_id()) { - insert_poll_ready_block(tcx, body) - } else { - insert_panic_block(tcx, body, ResumedAfterReturn(transform.coroutine_kind)) - } + insert_poll_ready_block(tcx, body) + } + CoroutineKind::Desugared(CoroutineDesugaring::Async, _) + | CoroutineKind::Coroutine(_) => { + insert_panic_block(tcx, body, ResumedAfterReturn(transform.coroutine_kind)) } CoroutineKind::Desugared(CoroutineDesugaring::AsyncGen, _) | CoroutineKind::Desugared(CoroutineDesugaring::Gen, _) => { From c417ae69712f46e3b942e50cd2a7e65dcea7f14f Mon Sep 17 00:00:00 2001 From: Pavel Grigorenko Date: Tue, 21 Apr 2026 17:28:30 +0300 Subject: [PATCH 3/5] hir::CoroutineDesugaring::Async: add `fused: bool` field --- compiler/rustc_ast_lowering/src/expr.rs | 18 ++++--- compiler/rustc_ast_lowering/src/item.rs | 2 +- .../src/diagnostics/conflict_errors.rs | 4 +- .../src/diagnostics/region_errors.rs | 2 +- .../src/diagnostics/region_name.rs | 12 ++--- .../src/type_check/input_output.rs | 2 +- .../src/debuginfo/type_names.rs | 6 +-- .../rustc_const_eval/src/check_consts/ops.rs | 2 +- compiler/rustc_hir/src/hir.rs | 6 +-- compiler/rustc_hir_typeck/src/callee.rs | 2 +- compiler/rustc_hir_typeck/src/closure.rs | 19 +++---- compiler/rustc_hir_typeck/src/expr.rs | 5 +- .../src/fn_ctxt/suggestions.rs | 2 +- compiler/rustc_hir_typeck/src/loops.rs | 2 +- compiler/rustc_lint/src/async_closures.rs | 2 +- compiler/rustc_metadata/src/rmeta/table.rs | 9 ++-- compiler/rustc_middle/src/mir/terminator.rs | 51 +++++++++++++------ compiler/rustc_middle/src/ty/context.rs | 2 +- compiler/rustc_middle/src/ty/instance.rs | 2 +- compiler/rustc_middle/src/ty/print/pretty.rs | 2 +- compiler/rustc_middle/src/ty/util.rs | 11 ++-- compiler/rustc_mir_transform/src/coroutine.rs | 29 +++++++---- .../src/shim/async_destructor_ctor.rs | 2 +- compiler/rustc_passes/src/check_attr.rs | 2 +- .../src/unstable/convert/stable/mod.rs | 2 +- .../src/handle_cycle_error.rs | 2 +- .../cfi/typeid/itanium_cxx_abi/transform.rs | 2 +- .../src/error_reporting/infer/suggest.rs | 2 +- .../traits/fulfillment_errors.rs | 8 +-- .../src/error_reporting/traits/suggestions.rs | 26 ++++++---- .../src/traits/select/candidate_assembly.rs | 2 +- compiler/rustc_ty_utils/src/abi.rs | 4 +- 32 files changed, 148 insertions(+), 96 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index eaa22e071af4b..1cba009dccdd3 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -250,7 +250,7 @@ impl<'hir> LoweringContext<'_, 'hir> { }, ExprKind::Gen(capture_clause, block, genblock_kind, decl_span) => { let desugaring_kind = match genblock_kind { - GenBlockKind::Async => hir::CoroutineDesugaring::Async, + GenBlockKind::Async => hir::CoroutineDesugaring::Async { fused: false }, GenBlockKind::Gen => hir::CoroutineDesugaring::Gen, GenBlockKind::AsyncGen => hir::CoroutineDesugaring::AsyncGen, }; @@ -714,7 +714,7 @@ impl<'hir> LoweringContext<'_, 'hir> { // The `async` desugaring takes a resume argument and maintains a `task_context`, // whereas a generator does not. let (inputs, params, task_context): (&[_], &[_], _) = match desugaring_kind { - hir::CoroutineDesugaring::Async | hir::CoroutineDesugaring::AsyncGen => { + hir::CoroutineDesugaring::Async { fused: _ } | hir::CoroutineDesugaring::AsyncGen => { // Resume argument type: `ResumeTy` let unstable_span = self.mark_span_with_reason( DesugaringKind::Async, @@ -850,7 +850,10 @@ impl<'hir> LoweringContext<'_, 'hir> { let full_span = expr.span.to(await_kw_span); let is_async_gen = match self.coroutine_kind { - Some(hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Async, _)) => false, + Some(hir::CoroutineKind::Desugared( + hir::CoroutineDesugaring::Async { fused: _ }, + _, + )) => false, Some(hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::AsyncGen, _)) => true, Some(hir::CoroutineKind::Coroutine(_)) | Some(hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Gen, _)) @@ -1114,7 +1117,7 @@ impl<'hir> LoweringContext<'_, 'hir> { } Some( hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Gen, _) - | hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Async, _) + | hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Async { fused: _ }, _) | hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::AsyncGen, _), ) => { panic!("non-`async`/`gen` closure body turned `async`/`gen` during lowering"); @@ -1160,7 +1163,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let (binder_clause, generic_params) = self.lower_closure_binder(binder); let coroutine_desugaring = match coroutine_kind { - CoroutineKind::Async { .. } => hir::CoroutineDesugaring::Async, + CoroutineKind::Async { .. } => hir::CoroutineDesugaring::Async { fused: false }, CoroutineKind::Gen { .. } => hir::CoroutineDesugaring::Gen, CoroutineKind::AsyncGen { span, .. } => { span_bug!(span, "only async closures and `iter!` closures are supported currently") @@ -1706,7 +1709,10 @@ impl<'hir> LoweringContext<'_, 'hir> { let is_async_gen = match self.coroutine_kind { Some(hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Gen, _)) => false, Some(hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::AsyncGen, _)) => true, - Some(hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Async, _)) => { + Some(hir::CoroutineKind::Desugared( + hir::CoroutineDesugaring::Async { fused: _ }, + _, + )) => { // Lower to a block `{ EXPR; }` so that the awaited expr // is not accidentally orphaned. let stmt_id = self.next_id(); diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index 249f8e579eee9..69df4cd2387a1 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -1665,7 +1665,7 @@ impl<'hir> LoweringContext<'_, 'hir> { this.expr_block(body) }; let desugaring_kind = match coroutine_kind { - CoroutineKind::Async { .. } => hir::CoroutineDesugaring::Async, + CoroutineKind::Async { .. } => hir::CoroutineDesugaring::Async { fused: false }, CoroutineKind::Gen { .. } => hir::CoroutineDesugaring::Gen, CoroutineKind::AsyncGen { .. } => hir::CoroutineDesugaring::AsyncGen, }; diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index c4fbe1b9e5d61..f275567830a6b 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -3614,7 +3614,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { bug!("gen block/closure expected, but gen function found.") } }, - CoroutineKind::Desugared(CoroutineDesugaring::Async, async_kind) => { + CoroutineKind::Desugared(CoroutineDesugaring::Async { fused: _ }, async_kind) => { match async_kind { CoroutineSource::Block => "async block", CoroutineSource::Closure => "async closure", @@ -3654,7 +3654,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { fr_name.highlight_region_name(&mut err); if matches!( use_span.coroutine_kind(), - Some(CoroutineKind::Desugared(CoroutineDesugaring::Async, _)) + Some(CoroutineKind::Desugared(CoroutineDesugaring::Async { fused: _ }, _)) ) { err.note( "async blocks are not executed immediately and must either take a \ diff --git a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs index f9c91c3371516..b0361cd65f8c8 100644 --- a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs @@ -1197,7 +1197,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { if !matches!( kind, hir::ClosureKind::Coroutine(hir::CoroutineKind::Desugared( - hir::CoroutineDesugaring::Async, + hir::CoroutineDesugaring::Async { fused: _ }, _ ),) ) { diff --git a/compiler/rustc_borrowck/src/diagnostics/region_name.rs b/compiler/rustc_borrowck/src/diagnostics/region_name.rs index 963f902b71fcb..756d511adb1d0 100644 --- a/compiler/rustc_borrowck/src/diagnostics/region_name.rs +++ b/compiler/rustc_borrowck/src/diagnostics/region_name.rs @@ -807,20 +807,20 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, 'tcx> { }; let mir_description = match kind { hir::ClosureKind::Coroutine(hir::CoroutineKind::Desugared( - hir::CoroutineDesugaring::Async, + hir::CoroutineDesugaring::Async { fused: _ }, hir::CoroutineSource::Block, )) => " of async block", hir::ClosureKind::Coroutine(hir::CoroutineKind::Desugared( - hir::CoroutineDesugaring::Async, + hir::CoroutineDesugaring::Async { fused: _ }, hir::CoroutineSource::Closure, )) - | hir::ClosureKind::CoroutineClosure(hir::CoroutineDesugaring::Async) => { - " of async closure" - } + | hir::ClosureKind::CoroutineClosure(hir::CoroutineDesugaring::Async { + fused: _, + }) => " of async closure", hir::ClosureKind::Coroutine(hir::CoroutineKind::Desugared( - hir::CoroutineDesugaring::Async, + hir::CoroutineDesugaring::Async { fused: _ }, hir::CoroutineSource::Fn, )) => { let parent_item = diff --git a/compiler/rustc_borrowck/src/type_check/input_output.rs b/compiler/rustc_borrowck/src/type_check/input_output.rs index 64c5f5f0c560b..6c90e2f22562b 100644 --- a/compiler/rustc_borrowck/src/type_check/input_output.rs +++ b/compiler/rustc_borrowck/src/type_check/input_output.rs @@ -61,7 +61,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { assert_matches!( self.tcx().coroutine_kind(self.tcx().coroutine_for_closure(mir_def_id)), Some(hir::CoroutineKind::Desugared( - hir::CoroutineDesugaring::Async | hir::CoroutineDesugaring::Gen, + hir::CoroutineDesugaring::Async { fused: _ } | hir::CoroutineDesugaring::Gen, hir::CoroutineSource::Closure )), "this needs to be modified if we're lowering non-async closures" diff --git a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs index 730272d2be94d..2d9c26fc4c420 100644 --- a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs +++ b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs @@ -586,9 +586,9 @@ fn coroutine_kind_label(coroutine_kind: Option) -> &'static str { Some(Desugared(Gen, Block)) => "gen_block", Some(Desugared(Gen, Closure)) => "gen_closure", Some(Desugared(Gen, Fn)) => "gen_fn", - Some(Desugared(Async, Block)) => "async_block", - Some(Desugared(Async, Closure)) => "async_closure", - Some(Desugared(Async, Fn)) => "async_fn", + Some(Desugared(Async { fused: _ }, Block)) => "async_block", + Some(Desugared(Async { fused: _ }, Closure)) => "async_closure", + Some(Desugared(Async { fused: _ }, Fn)) => "async_fn", Some(Desugared(AsyncGen, Block)) => "async_gen_block", Some(Desugared(AsyncGen, Closure)) => "async_gen_closure", Some(Desugared(AsyncGen, Fn)) => "async_gen_fn", diff --git a/compiler/rustc_const_eval/src/check_consts/ops.rs b/compiler/rustc_const_eval/src/check_consts/ops.rs index c776fa69ba5c1..7515c0f8d1ea7 100644 --- a/compiler/rustc_const_eval/src/check_consts/ops.rs +++ b/compiler/rustc_const_eval/src/check_consts/ops.rs @@ -537,7 +537,7 @@ impl<'tcx> NonConstOp<'tcx> for Coroutine { fn status_in_item(&self, _: &ConstCx<'_, 'tcx>) -> Status { match self.0 { hir::CoroutineKind::Desugared( - hir::CoroutineDesugaring::Async, + hir::CoroutineDesugaring::Async { fused: _ }, hir::CoroutineSource::Block, ) // FIXME(coroutines): eventually we want to gate const coroutine coroutines behind a diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 2f18b09cf1ae8..03d5b499ccd8a 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -2207,7 +2207,7 @@ pub enum CoroutineKind { impl CoroutineKind { pub fn movability(self) -> Movability { match self { - CoroutineKind::Desugared(CoroutineDesugaring::Async, _) + CoroutineKind::Desugared(CoroutineDesugaring::Async { fused: _ }, _) | CoroutineKind::Desugared(CoroutineDesugaring::AsyncGen, _) => Movability::Static, CoroutineKind::Desugared(CoroutineDesugaring::Gen, _) => Movability::Movable, CoroutineKind::Coroutine(mov) => mov, @@ -2271,7 +2271,7 @@ impl fmt::Display for CoroutineSource { #[derive(Clone, PartialEq, Eq, Debug, Copy, Hash, StableHash, Encodable, Decodable)] pub enum CoroutineDesugaring { /// An explicit `async` block or the body of an `async` function. - Async, + Async { fused: bool }, /// An explicit `gen` block or the body of a `gen` function. Gen, @@ -2284,7 +2284,7 @@ pub enum CoroutineDesugaring { impl fmt::Display for CoroutineDesugaring { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { - CoroutineDesugaring::Async => { + CoroutineDesugaring::Async { fused: _ } => { if f.alternate() { f.write_str("`async` ")?; } else { diff --git a/compiler/rustc_hir_typeck/src/callee.rs b/compiler/rustc_hir_typeck/src/callee.rs index 9730e08c90c37..01f878ad81a33 100644 --- a/compiler/rustc_hir_typeck/src/callee.rs +++ b/compiler/rustc_hir_typeck/src/callee.rs @@ -467,7 +467,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { hir::ExprKind::Closure(&hir::Closure { kind: hir::ClosureKind::Coroutine(hir::CoroutineKind::Desugared( - hir::CoroutineDesugaring::Async, + hir::CoroutineDesugaring::Async { fused: _ }, hir::CoroutineSource::Closure, )), .. diff --git a/compiler/rustc_hir_typeck/src/closure.rs b/compiler/rustc_hir_typeck/src/closure.rs index 763d2a27e6cc0..3214353284790 100644 --- a/compiler/rustc_hir_typeck/src/closure.rs +++ b/compiler/rustc_hir_typeck/src/closure.rs @@ -146,9 +146,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .into()]), ) } - hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Async, _) => { - tcx.types.unit - } + hir::CoroutineKind::Desugared( + hir::CoroutineDesugaring::Async { fused: _ }, + _, + ) => tcx.types.unit, }; // Resume type defaults to `()` if the coroutine has no argument. @@ -189,7 +190,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // that we have to infer. (tcx.types.unit, self.infcx.next_ty_var(expr_span)) } - hir::CoroutineDesugaring::Async => { + hir::CoroutineDesugaring::Async { fused: _ } => { // async closures always return the type ascribed after the `->` (if present), // and yield `()`. (bound_sig.skip_binder().output(), tcx.types.unit) @@ -450,7 +451,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { | hir::ClosureKind::CoroutineClosure(hir::CoroutineDesugaring::Gen) => { self.tcx.fn_trait_kind_from_def_id(trait_def_id) } - hir::ClosureKind::CoroutineClosure(hir::CoroutineDesugaring::Async) => self + hir::ClosureKind::CoroutineClosure(hir::CoroutineDesugaring::Async { fused: _ }) => self .tcx .async_fn_trait_kind_from_def_id(trait_def_id) .or_else(|| self.tcx.fn_trait_kind_from_def_id(trait_def_id)), @@ -497,7 +498,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { hir::ClosureKind::Closure if self.tcx.is_lang_item(def_id, LangItem::FnOnceOutput) => { self.extract_sig_from_projection(cause_span, projection) } - hir::ClosureKind::CoroutineClosure(hir::CoroutineDesugaring::Async) + hir::ClosureKind::CoroutineClosure(hir::CoroutineDesugaring::Async { fused: _ }) if self.tcx.is_lang_item(def_id, LangItem::AsyncFnOnceOutput) => { self.extract_sig_from_projection(cause_span, projection) @@ -505,7 +506,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // It's possible we've passed the closure to a (somewhat out-of-fashion) // `F: FnOnce() -> Fut, Fut: Future` style bound. Let's still // guide inference here, since it's beneficial for the user. - hir::ClosureKind::CoroutineClosure(hir::CoroutineDesugaring::Async) + hir::ClosureKind::CoroutineClosure(hir::CoroutineDesugaring::Async { fused: _ }) if self.tcx.is_lang_item(def_id, LangItem::FnOnceOutput) => { self.extract_sig_from_projection_and_future_bound(cause_span, projection) @@ -896,7 +897,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // we expect the return type of the block to match that of the enclosing // function. hir::ClosureKind::Coroutine(hir::CoroutineKind::Desugared( - hir::CoroutineDesugaring::Async, + hir::CoroutineDesugaring::Async { fused: _ }, hir::CoroutineSource::Fn, )) => { debug!("closure is async fn body"); @@ -921,7 +922,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // For closures/coroutines, we know nothing about the return // type unless it was supplied. hir::ClosureKind::Coroutine(hir::CoroutineKind::Desugared( - hir::CoroutineDesugaring::Async, + hir::CoroutineDesugaring::Async { fused: _ }, _, )) | hir::ClosureKind::Coroutine(hir::CoroutineKind::Coroutine(_)) diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index fd9c1bc8780ee..6ddc0d068b0ad 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -2937,7 +2937,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { "field not available in `impl Future`, but it is available in its `Output`", ); match self.tcx.coroutine_kind(self.body_id) { - Some(hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Async, _)) => { + Some(hir::CoroutineKind::Desugared( + hir::CoroutineDesugaring::Async { fused: _ }, + _, + )) => { err.span_suggestion_verbose( base.span.shrink_to_hi(), "consider `await`ing on the `Future` to access the field", diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs index 7e2f3e62589ff..a0bb494759336 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs @@ -576,7 +576,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if matches!( self.tcx.coroutine_kind(def_id), Some(CoroutineKind::Desugared( - CoroutineDesugaring::Async, + CoroutineDesugaring::Async { fused: _ }, CoroutineSource::Closure )) ) => diff --git a/compiler/rustc_hir_typeck/src/loops.rs b/compiler/rustc_hir_typeck/src/loops.rs index 21b408064fac5..5e02118b0b8ed 100644 --- a/compiler/rustc_hir_typeck/src/loops.rs +++ b/compiler/rustc_hir_typeck/src/loops.rs @@ -342,7 +342,7 @@ impl<'hir> CheckLoopVisitor<'hir> { } Coroutine { coroutine_span, kind, source } => { let kind = match kind { - hir::CoroutineDesugaring::Async => "async", + hir::CoroutineDesugaring::Async { fused: _ } => "async", hir::CoroutineDesugaring::Gen => "gen", hir::CoroutineDesugaring::AsyncGen => "async gen", }; diff --git a/compiler/rustc_lint/src/async_closures.rs b/compiler/rustc_lint/src/async_closures.rs index 0bc245c742b2e..fcd1d7478d8ca 100644 --- a/compiler/rustc_lint/src/async_closures.rs +++ b/compiler/rustc_lint/src/async_closures.rs @@ -80,7 +80,7 @@ impl<'tcx> LateLintPass<'tcx> for AsyncClosureUsage { let hir::ExprKind::Closure(&hir::Closure { kind: hir::ClosureKind::Coroutine(hir::CoroutineKind::Desugared( - hir::CoroutineDesugaring::Async, + hir::CoroutineDesugaring::Async { fused: _ }, hir::CoroutineSource::Block, )), fn_decl_span: async_decl_span, diff --git a/compiler/rustc_metadata/src/rmeta/table.rs b/compiler/rustc_metadata/src/rmeta/table.rs index 26c5908563777..029baa86ceb61 100644 --- a/compiler/rustc_metadata/src/rmeta/table.rs +++ b/compiler/rustc_metadata/src/rmeta/table.rs @@ -244,9 +244,12 @@ fixed_size_enum! { ( Desugared(hir::CoroutineDesugaring::Gen, hir::CoroutineSource::Block) ) ( Desugared(hir::CoroutineDesugaring::Gen, hir::CoroutineSource::Fn) ) ( Desugared(hir::CoroutineDesugaring::Gen, hir::CoroutineSource::Closure) ) - ( Desugared(hir::CoroutineDesugaring::Async, hir::CoroutineSource::Block) ) - ( Desugared(hir::CoroutineDesugaring::Async, hir::CoroutineSource::Fn) ) - ( Desugared(hir::CoroutineDesugaring::Async, hir::CoroutineSource::Closure) ) + ( Desugared(hir::CoroutineDesugaring::Async { fused: false }, hir::CoroutineSource::Block) ) + ( Desugared(hir::CoroutineDesugaring::Async { fused: true }, hir::CoroutineSource::Block) ) + ( Desugared(hir::CoroutineDesugaring::Async { fused: false }, hir::CoroutineSource::Fn) ) + ( Desugared(hir::CoroutineDesugaring::Async { fused: true }, hir::CoroutineSource::Fn) ) + ( Desugared(hir::CoroutineDesugaring::Async { fused: false }, hir::CoroutineSource::Closure) ) + ( Desugared(hir::CoroutineDesugaring::Async { fused: true }, hir::CoroutineSource::Closure) ) ( Desugared(hir::CoroutineDesugaring::AsyncGen, hir::CoroutineSource::Block) ) ( Desugared(hir::CoroutineDesugaring::AsyncGen, hir::CoroutineSource::Fn) ) ( Desugared(hir::CoroutineDesugaring::AsyncGen, hir::CoroutineSource::Closure) ) diff --git a/compiler/rustc_middle/src/mir/terminator.rs b/compiler/rustc_middle/src/mir/terminator.rs index 1cd11bbd9ce4f..f20e73be6fe89 100644 --- a/compiler/rustc_middle/src/mir/terminator.rs +++ b/compiler/rustc_middle/src/mir/terminator.rs @@ -188,9 +188,10 @@ impl AssertKind { DivisionByZero(_) => LangItem::PanicDivZero, RemainderByZero(_) => LangItem::PanicRemZero, ResumedAfterReturn(CoroutineKind::Coroutine(_)) => LangItem::PanicCoroutineResumed, - ResumedAfterReturn(CoroutineKind::Desugared(CoroutineDesugaring::Async, _)) => { - LangItem::PanicAsyncFnResumed - } + ResumedAfterReturn(CoroutineKind::Desugared( + CoroutineDesugaring::Async { fused: _ }, + _, + )) => LangItem::PanicAsyncFnResumed, ResumedAfterReturn(CoroutineKind::Desugared(CoroutineDesugaring::AsyncGen, _)) => { LangItem::PanicAsyncGenFnResumed } @@ -198,9 +199,10 @@ impl AssertKind { LangItem::PanicGenFnNone } ResumedAfterPanic(CoroutineKind::Coroutine(_)) => LangItem::PanicCoroutineResumedPanic, - ResumedAfterPanic(CoroutineKind::Desugared(CoroutineDesugaring::Async, _)) => { - LangItem::PanicAsyncFnResumedPanic - } + ResumedAfterPanic(CoroutineKind::Desugared( + CoroutineDesugaring::Async { fused: _ }, + _, + )) => LangItem::PanicAsyncFnResumedPanic, ResumedAfterPanic(CoroutineKind::Desugared(CoroutineDesugaring::AsyncGen, _)) => { LangItem::PanicAsyncGenFnResumedPanic } @@ -210,9 +212,10 @@ impl AssertKind { NullPointerDereference => LangItem::PanicNullPointerDereference, InvalidEnumConstruction(_) => LangItem::PanicInvalidEnumConstruction, ResumedAfterDrop(CoroutineKind::Coroutine(_)) => LangItem::PanicCoroutineResumedDrop, - ResumedAfterDrop(CoroutineKind::Desugared(CoroutineDesugaring::Async, _)) => { - LangItem::PanicAsyncFnResumedDrop - } + ResumedAfterDrop(CoroutineKind::Desugared( + CoroutineDesugaring::Async { fused: _ }, + _, + )) => LangItem::PanicAsyncFnResumedDrop, ResumedAfterDrop(CoroutineKind::Desugared(CoroutineDesugaring::AsyncGen, _)) => { LangItem::PanicAsyncGenFnResumedDrop } @@ -291,7 +294,10 @@ impl AssertKind { ResumedAfterReturn(CoroutineKind::Coroutine(_)) => { write!(f, "\"coroutine resumed after completion\"") } - ResumedAfterReturn(CoroutineKind::Desugared(CoroutineDesugaring::Async, _)) => { + ResumedAfterReturn(CoroutineKind::Desugared( + CoroutineDesugaring::Async { fused: _ }, + _, + )) => { write!(f, "\"`async fn` resumed after completion\"") } ResumedAfterReturn(CoroutineKind::Desugared(CoroutineDesugaring::AsyncGen, _)) => { @@ -303,7 +309,10 @@ impl AssertKind { ResumedAfterPanic(CoroutineKind::Coroutine(_)) => { write!(f, "\"coroutine resumed after panicking\"") } - ResumedAfterPanic(CoroutineKind::Desugared(CoroutineDesugaring::Async, _)) => { + ResumedAfterPanic(CoroutineKind::Desugared( + CoroutineDesugaring::Async { fused: _ }, + _, + )) => { write!(f, "\"`async fn` resumed after panicking\"") } ResumedAfterPanic(CoroutineKind::Desugared(CoroutineDesugaring::AsyncGen, _)) => { @@ -315,7 +324,10 @@ impl AssertKind { ResumedAfterDrop(CoroutineKind::Coroutine(_)) => { write!(f, "\"coroutine resumed after async drop\"") } - ResumedAfterDrop(CoroutineKind::Desugared(CoroutineDesugaring::Async, _)) => { + ResumedAfterDrop(CoroutineKind::Desugared( + CoroutineDesugaring::Async { fused: _ }, + _, + )) => { write!(f, "\"`async fn` resumed after async drop\"") } ResumedAfterDrop(CoroutineKind::Desugared(CoroutineDesugaring::AsyncGen, _)) => { @@ -360,7 +372,10 @@ impl fmt::Display for AssertKind { RemainderByZero(val) => { write!(f, "attempt to calculate the remainder of `{val:#?}` with a divisor of zero") } - ResumedAfterReturn(CoroutineKind::Desugared(CoroutineDesugaring::Async, _)) => { + ResumedAfterReturn(CoroutineKind::Desugared( + CoroutineDesugaring::Async { fused: _ }, + _, + )) => { write!(f, "`async fn` resumed after completion") } ResumedAfterReturn(CoroutineKind::Desugared(CoroutineDesugaring::AsyncGen, _)) => { @@ -372,7 +387,10 @@ impl fmt::Display for AssertKind { ResumedAfterReturn(CoroutineKind::Coroutine(_)) => { write!(f, "coroutine resumed after completion") } - ResumedAfterPanic(CoroutineKind::Desugared(CoroutineDesugaring::Async, _)) => { + ResumedAfterPanic(CoroutineKind::Desugared( + CoroutineDesugaring::Async { fused: _ }, + _, + )) => { write!(f, "`async fn` resumed after panicking") } ResumedAfterPanic(CoroutineKind::Desugared(CoroutineDesugaring::AsyncGen, _)) => { @@ -388,7 +406,10 @@ impl fmt::Display for AssertKind { InvalidEnumConstruction(source) => { write!(f, "trying to construct an enum from an invalid value `{source:#?}`") } - ResumedAfterDrop(CoroutineKind::Desugared(CoroutineDesugaring::Async, _)) => { + ResumedAfterDrop(CoroutineKind::Desugared( + CoroutineDesugaring::Async { fused: _ }, + _, + )) => { write!(f, "`async fn` resumed after async drop") } ResumedAfterDrop(CoroutineKind::Desugared(CoroutineDesugaring::AsyncGen, _)) => { diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 1c7bba82d3a7b..f26c68056925e 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -1046,7 +1046,7 @@ impl<'tcx> TyCtxt<'tcx> { pub fn coroutine_is_async(self, def_id: DefId) -> bool { matches!( self.coroutine_kind(def_id), - Some(hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Async, _)) + Some(hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Async { fused: _ }, _)) ) } diff --git a/compiler/rustc_middle/src/ty/instance.rs b/compiler/rustc_middle/src/ty/instance.rs index d425ba7a99658..8143eaf775b35 100644 --- a/compiler/rustc_middle/src/ty/instance.rs +++ b/compiler/rustc_middle/src/ty/instance.rs @@ -790,7 +790,7 @@ impl<'tcx> Instance<'tcx> { let coroutine_callable_item = if tcx.is_lang_item(trait_id, LangItem::Future) { assert_matches!( coroutine_kind, - hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Async, _) + hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Async { fused: _ }, _) ); hir::LangItem::FuturePoll } else if tcx.is_lang_item(trait_id, LangItem::Iterator) { diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index daead99b977c1..8ee247e1abe7e 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -1004,7 +1004,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { match self.tcx().coroutine_kind(self.tcx().coroutine_for_closure(did)).unwrap() { hir::CoroutineKind::Desugared( - hir::CoroutineDesugaring::Async, + hir::CoroutineDesugaring::Async { fused: _ }, hir::CoroutineSource::Closure, ) => write!(self, "async closure")?, hir::CoroutineKind::Desugared( diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs index 3cca1404dac6f..afb86fe09dc0e 100644 --- a/compiler/rustc_middle/src/ty/util.rs +++ b/compiler/rustc_middle/src/ty/util.rs @@ -790,15 +790,15 @@ impl<'tcx> TyCtxt<'tcx> { DefKind::Closure if let Some(coroutine_kind) = self.coroutine_kind(def_id) => { match coroutine_kind { hir::CoroutineKind::Desugared( - hir::CoroutineDesugaring::Async, + hir::CoroutineDesugaring::Async { fused: _ }, hir::CoroutineSource::Fn, ) => "async fn", hir::CoroutineKind::Desugared( - hir::CoroutineDesugaring::Async, + hir::CoroutineDesugaring::Async { fused: _ }, hir::CoroutineSource::Block, ) => "async block", hir::CoroutineKind::Desugared( - hir::CoroutineDesugaring::Async, + hir::CoroutineDesugaring::Async { fused: _ }, hir::CoroutineSource::Closure, ) => "async closure", hir::CoroutineKind::Desugared( @@ -843,7 +843,10 @@ impl<'tcx> TyCtxt<'tcx> { DefKind::AssocFn if self.associated_item(def_id).is_method() => "a", DefKind::Closure if let Some(coroutine_kind) = self.coroutine_kind(def_id) => { match coroutine_kind { - hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Async, ..) => "an", + hir::CoroutineKind::Desugared( + hir::CoroutineDesugaring::Async { fused: _ }, + .., + ) => "an", hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::AsyncGen, ..) => "an", hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Gen, ..) => "a", hir::CoroutineKind::Coroutine(_) => "a", diff --git a/compiler/rustc_mir_transform/src/coroutine.rs b/compiler/rustc_mir_transform/src/coroutine.rs index 0f4627e29a8bb..a043c166d0c0f 100644 --- a/compiler/rustc_mir_transform/src/coroutine.rs +++ b/compiler/rustc_mir_transform/src/coroutine.rs @@ -218,7 +218,7 @@ impl<'tcx> TransformVisitor<'tcx> { let source_info = SourceInfo::outermost(body.span); let none_value = match self.coroutine_kind { - CoroutineKind::Desugared(CoroutineDesugaring::Async, _) => { + CoroutineKind::Desugared(CoroutineDesugaring::Async { fused: _ }, _) => { span_bug!(body.span, "`Future`s are not fused inherently") } CoroutineKind::Coroutine(_) => span_bug!(body.span, "`Coroutine`s cannot be fused"), @@ -284,7 +284,7 @@ impl<'tcx> TransformVisitor<'tcx> { const ZERO: VariantIdx = VariantIdx::ZERO; const ONE: VariantIdx = VariantIdx::ONE; let rvalue = match self.coroutine_kind { - CoroutineKind::Desugared(CoroutineDesugaring::Async, _) => { + CoroutineKind::Desugared(CoroutineDesugaring::Async { fused: _ }, _) => { let poll_def_id = self.tcx.require_lang_item(LangItem::Poll, source_info.span); let args = self.tcx.mk_args(&[self.old_ret_ty.into()]); let (variant_idx, operands) = if is_return { @@ -1276,18 +1276,19 @@ fn create_coroutine_resume_function<'tcx>( if can_return { let block = match transform.coroutine_kind { - CoroutineKind::Desugared(CoroutineDesugaring::Async, _) + CoroutineKind::Desugared(CoroutineDesugaring::Async { fused: false }, _) if tcx.is_async_drop_in_place_coroutine(body.source.def_id()) => { // For `async_drop_in_place::{closure}` we just keep return Poll::Ready, // because async drop of such coroutine keeps polling original coroutine insert_poll_ready_block(tcx, body) } - CoroutineKind::Desugared(CoroutineDesugaring::Async, _) + CoroutineKind::Desugared(CoroutineDesugaring::Async { fused: false }, _) | CoroutineKind::Coroutine(_) => { insert_panic_block(tcx, body, ResumedAfterReturn(transform.coroutine_kind)) } - CoroutineKind::Desugared(CoroutineDesugaring::AsyncGen, _) + CoroutineKind::Desugared(CoroutineDesugaring::Async { fused: true }, _) + | CoroutineKind::Desugared(CoroutineDesugaring::AsyncGen, _) | CoroutineKind::Desugared(CoroutineDesugaring::Gen, _) => { transform.insert_none_ret_block(body) } @@ -1300,8 +1301,10 @@ fn create_coroutine_resume_function<'tcx>( match transform.coroutine_kind { CoroutineKind::Coroutine(_) - | CoroutineKind::Desugared(CoroutineDesugaring::Async | CoroutineDesugaring::AsyncGen, _) => - { + | CoroutineKind::Desugared( + CoroutineDesugaring::Async { fused: _ } | CoroutineDesugaring::AsyncGen, + _, + ) => { make_coroutine_state_argument_pinned(tcx, body); } // Iterator::next doesn't accept a pinned argument, @@ -1491,7 +1494,7 @@ impl<'tcx> crate::MirPass<'tcx> for StateTransform { let discr_ty = args.as_coroutine().discr_ty(tcx); let new_ret_ty = match coroutine_kind { - CoroutineKind::Desugared(CoroutineDesugaring::Async, _) => { + CoroutineKind::Desugared(CoroutineDesugaring::Async { fused: _ }, _) => { // Compute Poll let poll_did = tcx.require_lang_item(LangItem::Poll, body.span); let poll_adt_ref = tcx.adt_def(poll_did); @@ -1524,13 +1527,19 @@ impl<'tcx> crate::MirPass<'tcx> for StateTransform { // and corresponding futures kept in layout. let has_async_drops = matches!( coroutine_kind, - CoroutineKind::Desugared(CoroutineDesugaring::Async | CoroutineDesugaring::AsyncGen, _) + CoroutineKind::Desugared( + CoroutineDesugaring::Async { fused: _ } | CoroutineDesugaring::AsyncGen, + _ + ) ) && has_expandable_async_drops(tcx, body, coroutine_ty); // Replace all occurrences of `ResumeTy` with `&mut Context<'_>` within async bodies. if matches!( coroutine_kind, - CoroutineKind::Desugared(CoroutineDesugaring::Async | CoroutineDesugaring::AsyncGen, _) + CoroutineKind::Desugared( + CoroutineDesugaring::Async { fused: _ } | CoroutineDesugaring::AsyncGen, + _ + ) ) { let context_mut_ref = transform_async_context(tcx, body); expand_async_drops(tcx, body, context_mut_ref, coroutine_kind, coroutine_ty); diff --git a/compiler/rustc_mir_transform/src/shim/async_destructor_ctor.rs b/compiler/rustc_mir_transform/src/shim/async_destructor_ctor.rs index b1f35213d85af..6a9b591090423 100644 --- a/compiler/rustc_mir_transform/src/shim/async_destructor_ctor.rs +++ b/compiler/rustc_mir_transform/src/shim/async_destructor_ctor.rs @@ -58,7 +58,7 @@ pub(super) fn build_async_drop_shim<'tcx>( assert!(matches!( coroutine_kind, - CoroutineKind::Desugared(CoroutineDesugaring::Async, CoroutineSource::Fn) + CoroutineKind::Desugared(CoroutineDesugaring::Async { fused: _ }, CoroutineSource::Fn) )); let needs_async_drop = drop_ty.needs_async_drop(tcx, typing_env); diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index a978138e3e1ff..560b1a7b9216a 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -125,7 +125,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { for attr in attrs { let mut style = None; match attr { - Attribute::Parsed(AttributeKind::ProcMacro) => { + Attribute::Parsed(AttributeKind::ProcMacro) => { self.check_proc_macro(hir_id, target, ProcMacroKind::FunctionLike) } Attribute::Parsed(AttributeKind::ProcMacroAttribute) => { diff --git a/compiler/rustc_public/src/unstable/convert/stable/mod.rs b/compiler/rustc_public/src/unstable/convert/stable/mod.rs index ce55e898b2acb..9634062a58976 100644 --- a/compiler/rustc_public/src/unstable/convert/stable/mod.rs +++ b/compiler/rustc_public/src/unstable/convert/stable/mod.rs @@ -69,7 +69,7 @@ impl<'tcx> Stable<'tcx> for rustc_hir::CoroutineKind { ) -> Self::T { use rustc_hir::{CoroutineDesugaring, CoroutineKind}; match *self { - CoroutineKind::Desugared(CoroutineDesugaring::Async, source) => { + CoroutineKind::Desugared(CoroutineDesugaring::Async { fused: _ }, source) => { crate::mir::CoroutineKind::Desugared( crate::mir::CoroutineDesugaring::Async, source.stable(tables, cx), diff --git a/compiler/rustc_query_impl/src/handle_cycle_error.rs b/compiler/rustc_query_impl/src/handle_cycle_error.rs index 79e7788cafe81..cdce66d1d5871 100644 --- a/compiler/rustc_query_impl/src/handle_cycle_error.rs +++ b/compiler/rustc_query_impl/src/handle_cycle_error.rs @@ -196,7 +196,7 @@ pub(crate) fn layout_of<'tcx>( // enough info here... Maybe we can use a hacky HIR walker. if matches!( coroutine_kind, - hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Async, _) + hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Async { fused: _ }, _) ) { diag.note("a recursive `async fn` call must introduce indirection such as `Box::pin` to avoid an infinitely sized future"); } diff --git a/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/transform.rs b/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/transform.rs index 8b7d906a27a16..a937404762a5d 100644 --- a/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/transform.rs +++ b/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/transform.rs @@ -420,7 +420,7 @@ pub(crate) fn transform_instance<'tcx>( ), hir::CoroutineKind::Desugared(desugaring, _) => { let lang_item = match desugaring { - hir::CoroutineDesugaring::Async => LangItem::Future, + hir::CoroutineDesugaring::Async { fused: _ } => LangItem::Future, hir::CoroutineDesugaring::AsyncGen => LangItem::AsyncIterator, hir::CoroutineDesugaring::Gen => LangItem::Iterator, }; diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/suggest.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/suggest.rs index fd51109db5f99..d4cfb558c583b 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/suggest.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/suggest.rs @@ -175,7 +175,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { match self.tcx.coroutine_kind(cause.body_id) { Some(hir::CoroutineKind::Desugared( - hir::CoroutineDesugaring::Async | hir::CoroutineDesugaring::AsyncGen, + hir::CoroutineDesugaring::Async { fused: _ } | hir::CoroutineDesugaring::AsyncGen, _, )) => (), None diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs index 785118bc6d7eb..cfa05129e9129 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs @@ -1910,18 +1910,18 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { hir::ClosureKind::Closure => "a closure", hir::ClosureKind::Coroutine(hir::CoroutineKind::Coroutine(_)) => "a coroutine", hir::ClosureKind::Coroutine(hir::CoroutineKind::Desugared( - hir::CoroutineDesugaring::Async, + hir::CoroutineDesugaring::Async { fused: _ }, hir::CoroutineSource::Block, )) => "an async block", hir::ClosureKind::Coroutine(hir::CoroutineKind::Desugared( - hir::CoroutineDesugaring::Async, + hir::CoroutineDesugaring::Async { fused: _ }, hir::CoroutineSource::Fn, )) => "an async function", hir::ClosureKind::Coroutine(hir::CoroutineKind::Desugared( - hir::CoroutineDesugaring::Async, + hir::CoroutineDesugaring::Async { fused: _ }, hir::CoroutineSource::Closure, )) - | hir::ClosureKind::CoroutineClosure(hir::CoroutineDesugaring::Async) => { + | hir::ClosureKind::CoroutineClosure(hir::CoroutineDesugaring::Async { fused: _ }) => { "an async closure" } hir::ClosureKind::Coroutine(hir::CoroutineKind::Desugared( diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs index b442faad70ef4..94e9e0ac034a4 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs @@ -1049,7 +1049,8 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { && let Some(hir::Node::Expr(hir::Expr { kind: hir::ExprKind::Closure(closure), .. })) = self.tcx.hir_get_if_local(def_id) - && let hir::ClosureKind::CoroutineClosure(CoroutineDesugaring::Async) = closure.kind + && let hir::ClosureKind::CoroutineClosure(CoroutineDesugaring::Async { fused: _ }) = + closure.kind && let Some(arg_span) = closure.fn_arg_span && obligation.cause.span.contains(arg_span) { @@ -1132,8 +1133,9 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { let mut body = self.tcx.hir_body(closure.body).value; // Async closures desugar to a closure returning a coroutine - if let hir::ClosureKind::CoroutineClosure(hir::CoroutineDesugaring::Async) = - closure.kind + if let hir::ClosureKind::CoroutineClosure(hir::CoroutineDesugaring::Async { + fused: _, + }) = closure.kind { let peeled = body.peel_blocks().peel_drop_temps(); if let hir::ExprKind::Closure(inner) = peeled.kind { @@ -3248,7 +3250,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { Some(match self.tcx.coroutine_kind(coroutine_did).unwrap() { CoroutineKind::Coroutine(_) => format!("coroutine is not {trait_name}"), CoroutineKind::Desugared( - CoroutineDesugaring::Async, + CoroutineDesugaring::Async { fused: _ }, CoroutineSource::Fn, ) => self .tcx @@ -3260,13 +3262,13 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { format!("future returned by `{name}` is not {trait_name}") })?, CoroutineKind::Desugared( - CoroutineDesugaring::Async, + CoroutineDesugaring::Async { fused: _ }, CoroutineSource::Block, ) => { format!("future created by async block is not {trait_name}") } CoroutineKind::Desugared( - CoroutineDesugaring::Async, + CoroutineDesugaring::Async { fused: _ }, CoroutineSource::Closure, ) => { format!("future created by async closure is not {trait_name}") @@ -3993,9 +3995,10 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { | Some(hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Gen, _)) => { "yield" } - Some(hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Async, _)) => { - "await" - } + Some(hir::CoroutineKind::Desugared( + hir::CoroutineDesugaring::Async { fused: _ }, + _, + )) => "await", Some(hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::AsyncGen, _)) => { "yield`/`await" } @@ -4555,7 +4558,10 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { && snippet.ends_with('?') { match self.tcx.coroutine_kind(obligation.cause.body_id) { - Some(hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Async, _)) => { + Some(hir::CoroutineKind::Desugared( + hir::CoroutineDesugaring::Async { fused: _ }, + _, + )) => { err.span_suggestion_verbose( span.with_hi(span.hi() - BytePos(1)).shrink_to_hi(), "consider `await`ing on the `Future`", diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs index f7614e7c9730a..771a109ff1004 100644 --- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs +++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs @@ -499,7 +499,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { debug!(?coroutine_kind); match coroutine_kind { - CoroutineKind::Desugared(CoroutineDesugaring::Async, _) => { + CoroutineKind::Desugared(CoroutineDesugaring::Async { fused: _ }, _) => { candidates.vec.push(AsyncClosureCandidate); } _ => (), diff --git a/compiler/rustc_ty_utils/src/abi.rs b/compiler/rustc_ty_utils/src/abi.rs index 0e0ae76b7a439..03ab9f1f51526 100644 --- a/compiler/rustc_ty_utils/src/abi.rs +++ b/compiler/rustc_ty_utils/src/abi.rs @@ -130,7 +130,7 @@ fn fn_sig_for_fn_abi<'tcx>( // unlike for all other coroutine kinds. env_ty } - hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Async, _) + hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Async { fused: _ }, _) | hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::AsyncGen, _) | hir::CoroutineKind::Coroutine(_) => Ty::new_adt(tcx, pin_adt_ref, pin_args), }; @@ -142,7 +142,7 @@ fn fn_sig_for_fn_abi<'tcx>( // or the `Iterator::next(...) -> Option` function in case this is a // special coroutine backing a gen construct. let (resume_ty, ret_ty) = match coroutine_kind { - hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Async, _) => { + hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Async { fused: _ }, _) => { // The signature should be `Future::poll(_, &mut Context<'_>) -> Poll` assert_eq!(sig.yield_ty, tcx.types.unit); From 95a26c5589f7906cbc62e2aea340209525727f81 Mon Sep 17 00:00:00 2001 From: Pavel Grigorenko Date: Tue, 21 Apr 2026 17:28:30 +0300 Subject: [PATCH 4/5] mir: handle fused futures --- compiler/rustc_middle/src/mir/terminator.rs | 24 ++++++++++++++++--- compiler/rustc_mir_transform/src/coroutine.rs | 14 ++++++++--- 2 files changed, 32 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_middle/src/mir/terminator.rs b/compiler/rustc_middle/src/mir/terminator.rs index f20e73be6fe89..4bb0349a917f1 100644 --- a/compiler/rustc_middle/src/mir/terminator.rs +++ b/compiler/rustc_middle/src/mir/terminator.rs @@ -189,9 +189,15 @@ impl AssertKind { RemainderByZero(_) => LangItem::PanicRemZero, ResumedAfterReturn(CoroutineKind::Coroutine(_)) => LangItem::PanicCoroutineResumed, ResumedAfterReturn(CoroutineKind::Desugared( - CoroutineDesugaring::Async { fused: _ }, + CoroutineDesugaring::Async { fused: false }, _, )) => LangItem::PanicAsyncFnResumed, + ResumedAfterReturn(CoroutineKind::Desugared( + CoroutineDesugaring::Async { fused: true }, + _, + )) => { + bug!("fused futures do not panic when resumed after completion") + } ResumedAfterReturn(CoroutineKind::Desugared(CoroutineDesugaring::AsyncGen, _)) => { LangItem::PanicAsyncGenFnResumed } @@ -295,11 +301,17 @@ impl AssertKind { write!(f, "\"coroutine resumed after completion\"") } ResumedAfterReturn(CoroutineKind::Desugared( - CoroutineDesugaring::Async { fused: _ }, + CoroutineDesugaring::Async { fused: false }, _, )) => { write!(f, "\"`async fn` resumed after completion\"") } + ResumedAfterReturn(CoroutineKind::Desugared( + CoroutineDesugaring::Async { fused: true }, + _, + )) => { + bug!("fused futures do not panic when resumed after completion") + } ResumedAfterReturn(CoroutineKind::Desugared(CoroutineDesugaring::AsyncGen, _)) => { write!(f, "\"`async gen fn` resumed after completion\"") } @@ -373,11 +385,17 @@ impl fmt::Display for AssertKind { write!(f, "attempt to calculate the remainder of `{val:#?}` with a divisor of zero") } ResumedAfterReturn(CoroutineKind::Desugared( - CoroutineDesugaring::Async { fused: _ }, + CoroutineDesugaring::Async { fused: false }, _, )) => { write!(f, "`async fn` resumed after completion") } + ResumedAfterReturn(CoroutineKind::Desugared( + CoroutineDesugaring::Async { fused: true }, + _, + )) => { + bug!("fused futures do not panic when resumed after completion") + } ResumedAfterReturn(CoroutineKind::Desugared(CoroutineDesugaring::AsyncGen, _)) => { todo!() } diff --git a/compiler/rustc_mir_transform/src/coroutine.rs b/compiler/rustc_mir_transform/src/coroutine.rs index a043c166d0c0f..e5bff1b3c6edd 100644 --- a/compiler/rustc_mir_transform/src/coroutine.rs +++ b/compiler/rustc_mir_transform/src/coroutine.rs @@ -218,10 +218,18 @@ impl<'tcx> TransformVisitor<'tcx> { let source_info = SourceInfo::outermost(body.span); let none_value = match self.coroutine_kind { - CoroutineKind::Desugared(CoroutineDesugaring::Async { fused: _ }, _) => { - span_bug!(body.span, "`Future`s are not fused inherently") - } CoroutineKind::Coroutine(_) => span_bug!(body.span, "`Coroutine`s cannot be fused"), + // Fused futures continue to return `Poll::Pending`. + CoroutineKind::Desugared(CoroutineDesugaring::Async { fused }, _) => { + debug_assert!(fused); + let poll_def_id = self.tcx.require_lang_item(LangItem::Poll, body.span); + make_aggregate_adt( + poll_def_id, + VariantIdx::ONE, + self.tcx.mk_args(&[self.old_ret_ty.into()]), + IndexVec::new(), + ) + } // `gen` continues return `None` CoroutineKind::Desugared(CoroutineDesugaring::Gen, _) => { let option_def_id = self.tcx.require_lang_item(LangItem::Option, body.span); From 1fa1ee925232b4c2b8e9dd9ce724d2473a56baa1 Mon Sep 17 00:00:00 2001 From: Pavel Grigorenko Date: Tue, 21 Apr 2026 17:28:30 +0300 Subject: [PATCH 5/5] Add `#[fused]` attribute --- TODO.txt | 2 ++ compiler/rustc_ast_lowering/src/expr.rs | 14 ++++++++++--- compiler/rustc_ast_lowering/src/item.rs | 4 +++- .../rustc_attr_parsing/src/attributes/body.rs | 15 +++++++++++++ compiler/rustc_attr_parsing/src/context.rs | 1 + compiler/rustc_feature/src/builtin_attrs.rs | 2 ++ compiler/rustc_feature/src/unstable.rs | 2 ++ .../rustc_hir/src/attrs/data_structures.rs | 3 +++ .../rustc_hir/src/attrs/encode_cross_crate.rs | 1 + compiler/rustc_passes/src/check_attr.rs | 16 ++++++++++++++ compiler/rustc_span/src/symbol.rs | 2 ++ tests/ui/async-await/fused.rs | 21 +++++++++++++++++++ .../feature-gate-fused-attribute.rs | 8 +++++++ .../feature-gate-fused-attribute.stderr | 13 ++++++++++++ 14 files changed, 100 insertions(+), 4 deletions(-) create mode 100644 TODO.txt create mode 100644 tests/ui/async-await/fused.rs create mode 100644 tests/ui/feature-gates/feature-gate-fused-attribute.rs create mode 100644 tests/ui/feature-gates/feature-gate-fused-attribute.stderr diff --git a/TODO.txt b/TODO.txt new file mode 100644 index 0000000000000..d3b2de90c92f1 --- /dev/null +++ b/TODO.txt @@ -0,0 +1,2 @@ +- mir tests +- support `async` blocks and `async` closures diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index 1cba009dccdd3..d07bb5a607aff 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -234,6 +234,7 @@ impl<'hir> LoweringContext<'_, 'hir> { body, *fn_decl_span, *fn_arg_span, + find_attr!(attrs, Fused(_)), ), None => self.lower_expr_closure( attrs, @@ -250,7 +251,9 @@ impl<'hir> LoweringContext<'_, 'hir> { }, ExprKind::Gen(capture_clause, block, genblock_kind, decl_span) => { let desugaring_kind = match genblock_kind { - GenBlockKind::Async => hir::CoroutineDesugaring::Async { fused: false }, + GenBlockKind::Async => { + hir::CoroutineDesugaring::Async { fused: find_attr!(attrs, Fused(_)) } + } GenBlockKind::Gen => hir::CoroutineDesugaring::Gen, GenBlockKind::AsyncGen => hir::CoroutineDesugaring::AsyncGen, }; @@ -1158,13 +1161,17 @@ impl<'hir> LoweringContext<'_, 'hir> { body: &Expr, fn_decl_span: Span, fn_arg_span: Span, + fused: bool, ) -> hir::ExprKind<'hir> { let closure_def_id = self.local_def_id(closure_id); let (binder_clause, generic_params) = self.lower_closure_binder(binder); let coroutine_desugaring = match coroutine_kind { - CoroutineKind::Async { .. } => hir::CoroutineDesugaring::Async { fused: false }, - CoroutineKind::Gen { .. } => hir::CoroutineDesugaring::Gen, + CoroutineKind::Async { .. } => hir::CoroutineDesugaring::Async { fused }, + CoroutineKind::Gen { .. } => { + debug_assert!(!fused, "This should have been rejected by attribute parsing"); + hir::CoroutineDesugaring::Gen + } CoroutineKind::AsyncGen { span, .. } => { span_bug!(span, "only async closures and `iter!` closures are supported currently") } @@ -1184,6 +1191,7 @@ impl<'hir> LoweringContext<'_, 'hir> { body.span, coroutine_kind, hir::CoroutineSource::Closure, + fused, ); this.maybe_forward_track_caller(body.span, closure_hir_id, expr.hir_id); diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index 69df4cd2387a1..47f6980f49161 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -1484,6 +1484,7 @@ impl<'hir> LoweringContext<'_, 'hir> { body.span, coroutine_kind, hir::CoroutineSource::Fn, + find_attr!(attrs, Fused(_)), ); // FIXME(async_fn_track_caller): Can this be moved above? @@ -1506,6 +1507,7 @@ impl<'hir> LoweringContext<'_, 'hir> { body_span: Span, coroutine_kind: CoroutineKind, coroutine_source: hir::CoroutineSource, + fused: bool, ) -> (&'hir [hir::Param<'hir>], hir::Expr<'hir>) { let mut parameters: Vec> = Vec::new(); let mut statements: Vec> = Vec::new(); @@ -1665,7 +1667,7 @@ impl<'hir> LoweringContext<'_, 'hir> { this.expr_block(body) }; let desugaring_kind = match coroutine_kind { - CoroutineKind::Async { .. } => hir::CoroutineDesugaring::Async { fused: false }, + CoroutineKind::Async { .. } => hir::CoroutineDesugaring::Async { fused }, CoroutineKind::Gen { .. } => hir::CoroutineDesugaring::Gen, CoroutineKind::AsyncGen { .. } => hir::CoroutineDesugaring::AsyncGen, }; diff --git a/compiler/rustc_attr_parsing/src/attributes/body.rs b/compiler/rustc_attr_parsing/src/attributes/body.rs index ff1c78bc10881..02f78c69a67be 100644 --- a/compiler/rustc_attr_parsing/src/attributes/body.rs +++ b/compiler/rustc_attr_parsing/src/attributes/body.rs @@ -9,3 +9,18 @@ impl NoArgsAttributeParser for CoroutineParser { const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Closure)]); const CREATE: fn(rustc_span::Span) -> AttributeKind = |_| AttributeKind::Coroutine; } + +pub(crate) struct FusedParser; + +impl NoArgsAttributeParser for FusedParser { + const PATH: &[Symbol] = &[sym::fused]; + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[ + Allow(Target::Fn), + Allow(Target::Method(MethodKind::TraitImpl)), + Allow(Target::Method(MethodKind::Inherent)), + Allow(Target::Method(MethodKind::Trait { body: true })), + Allow(Target::Closure), + Allow(Target::Expression), + ]); + const CREATE: fn(rustc_span::Span) -> AttributeKind = |span| AttributeKind::Fused(span); +} diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index bf4989b83200b..f2b6360fb44d5 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -236,6 +236,7 @@ attribute_parsers!( Single>, Single>, Single>, + Single>, Single>, Single>, Single>, diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs index 58bf12855ad6e..90fd909f198ea 100644 --- a/compiler/rustc_feature/src/builtin_attrs.rs +++ b/compiler/rustc_feature/src/builtin_attrs.rs @@ -375,6 +375,8 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ // `#[coroutine]` attribute to be applied to closures to make them coroutines instead gated!(coroutine, coroutines, experimental!(coroutine)), + gated!(fused, fused_attribute, experimental!(fused)), + // RFC 3543 // `#[patchable_function_entry(prefix_nops = m, entry_nops = n)]` gated!(patchable_function_entry, experimental!(patchable_function_entry)), diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index 5af522486b1f6..fdb74dca26611 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -322,6 +322,8 @@ declare_features! ( (unstable, dropck_eyepatch, "1.10.0", Some(34761)), /// Allows using the `#[fundamental]` attribute. (unstable, fundamental, "1.0.0", Some(29635)), + /// Allows using the `#[fused]` attribute. + (unstable, fused_attribute, "CURRENT_RUSTC_VERSION", Some(147129)), /// Allows using `#[link_name="llvm.*"]`. (internal, link_llvm_intrinsics, "1.0.0", Some(29602)), /// Allows using the `#[linkage = ".."]` attribute. diff --git a/compiler/rustc_hir/src/attrs/data_structures.rs b/compiler/rustc_hir/src/attrs/data_structures.rs index 2cdcf75d00be7..8ba93087255c0 100644 --- a/compiler/rustc_hir/src/attrs/data_structures.rs +++ b/compiler/rustc_hir/src/attrs/data_structures.rs @@ -1047,6 +1047,9 @@ pub enum AttributeKind { /// Represents `#[fundamental]`. Fundamental, + /// Represents `#[fused]`. + Fused(Span), + /// Represents `#[ignore]` Ignore { span: Span, diff --git a/compiler/rustc_hir/src/attrs/encode_cross_crate.rs b/compiler/rustc_hir/src/attrs/encode_cross_crate.rs index f2b528d1dcdc2..b289a3e53849b 100644 --- a/compiler/rustc_hir/src/attrs/encode_cross_crate.rs +++ b/compiler/rustc_hir/src/attrs/encode_cross_crate.rs @@ -47,6 +47,7 @@ impl AttributeKind { FfiConst => No, FfiPure(..) => No, Fundamental { .. } => Yes, + Fused(..) => No, Ignore { .. } => No, Inline(..) => No, InstructionSet(..) => No, diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 560b1a7b9216a..c546a9b89407e 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -144,6 +144,9 @@ impl<'tcx> CheckAttrVisitor<'tcx> { Attribute::Parsed(AttributeKind::ConstContinue(attr_span)) => { self.check_const_continue(hir_id, *attr_span, target) } + Attribute::Parsed(AttributeKind::Fused(attr_span)) => { + self.check_fused(hir_id, *attr_span, target) + } Attribute::Parsed(AttributeKind::AllowInternalUnsafe(attr_span) | AttributeKind::AllowInternalUnstable(.., attr_span)) => { self.check_macro_only_attr(*attr_span, span, target, attrs) } @@ -1734,6 +1737,19 @@ impl<'tcx> CheckAttrVisitor<'tcx> { self.dcx().emit_err(errors::ConstContinueAttr { attr_span, node_span }); }; } + + fn check_fused(&self, hir_id: HirId, attr_span: Span, target: Target) { + // TODO + match target { + Target::Fn => todo!("Check that the fn is async"), + Target::Closure => todo!("Check that the closure is async"), + Target::Expression => todo!("Check that this is an async block"), + Target::Method( + MethodKind::Inherent | MethodKind::TraitImpl | MethodKind::Trait { body: true }, + ) => todo!("Check that this is async"), + _ => bug!("This should not be accepted by rustc_attr_parsing"), + } + } } impl<'tcx> Visitor<'tcx> for CheckAttrVisitor<'tcx> { diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 695103a249b49..002a7b42f3609 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1008,6 +1008,8 @@ symbols! { fsub_fast, full, fundamental, + fused, + fused_attribute, fused_iterator, future_output, future_trait, diff --git a/tests/ui/async-await/fused.rs b/tests/ui/async-await/fused.rs new file mode 100644 index 0000000000000..6933a34b4dee5 --- /dev/null +++ b/tests/ui/async-await/fused.rs @@ -0,0 +1,21 @@ +//@ run-pass +//@ edition: 2024 + +#![feature(fused_attribute)] + +use std::pin::pin; +use std::task::{Context, Poll, Waker}; + +#[fused] +async fn fused() -> &'static str { + "done" +} + +fn main() { + let mut fut = pin!(fused()); + let cx = &mut Context::from_waker(Waker::noop()); + assert_eq!(fut.as_mut().poll(cx), Poll::Ready("done")); + for _ in 0..10 { + assert_eq!(fut.as_mut().poll(cx), Poll::Pending); + } +} diff --git a/tests/ui/feature-gates/feature-gate-fused-attribute.rs b/tests/ui/feature-gates/feature-gate-fused-attribute.rs new file mode 100644 index 0000000000000..9f489fec010ce --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-fused-attribute.rs @@ -0,0 +1,8 @@ +//@ edition: 2024 + +#[fused] //~ ERROR: the `#[fused]` attribute is an experimental feature +async fn foo() -> &'static str { + "hello" +} + +fn main() {} diff --git a/tests/ui/feature-gates/feature-gate-fused-attribute.stderr b/tests/ui/feature-gates/feature-gate-fused-attribute.stderr new file mode 100644 index 0000000000000..8508e9ce83560 --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-fused-attribute.stderr @@ -0,0 +1,13 @@ +error[E0658]: the `#[fused]` attribute is an experimental feature + --> $DIR/feature-gate-fused-attribute.rs:3:1 + | +LL | #[fused] + | ^^^^^^^^ + | + = note: see issue #147129 for more information + = help: add `#![feature(fused_attribute)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0658`.