Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Include coroutine desugaring in DefPathData
... and, make that available via `get_opt_name()` so that it shows up in
symbol mangling.
  • Loading branch information
sharnoff committed Jun 30, 2025
commit de62955e5168cda408567c71ac29198434f092fb
4 changes: 2 additions & 2 deletions compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs
Original file line number Diff line number Diff line change
Expand Up @@ -605,7 +605,7 @@ fn push_unqualified_item_name(
DefPathData::CrateRoot => {
output.push_str(tcx.crate_name(def_id.krate).as_str());
}
DefPathData::Closure => {
DefPathData::Closure { .. } => {
let label = coroutine_kind_label(tcx.coroutine_kind(def_id));

push_disambiguated_special_name(
Expand All @@ -619,7 +619,7 @@ fn push_unqualified_item_name(
DefPathDataName::Named(name) => {
output.push_str(name.as_str());
}
DefPathDataName::Anon { namespace } => {
DefPathDataName::Anon { namespace, kind: _ } => {
push_disambiguated_special_name(
namespace.as_str(),
disambiguated_data.disambiguator,
Expand Down
10 changes: 8 additions & 2 deletions compiler/rustc_const_eval/src/interpret/stack.rs
Original file line number Diff line number Diff line change
Expand Up @@ -217,7 +217,10 @@ pub struct FrameInfo<'tcx> {
impl<'tcx> fmt::Display for FrameInfo<'tcx> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
ty::tls::with(|tcx| {
if tcx.def_key(self.instance.def_id()).disambiguated_data.data == DefPathData::Closure {
if matches!(
tcx.def_key(self.instance.def_id()).disambiguated_data.data,
DefPathData::Closure { .. }
) {
write!(f, "inside closure")
} else {
// Note: this triggers a `must_produce_diag` state, which means that if we ever
Expand All @@ -232,7 +235,10 @@ impl<'tcx> fmt::Display for FrameInfo<'tcx> {
impl<'tcx> FrameInfo<'tcx> {
pub fn as_note(&self, tcx: TyCtxt<'tcx>) -> errors::FrameNote {
let span = self.span;
if tcx.def_key(self.instance.def_id()).disambiguated_data.data == DefPathData::Closure {
if matches!(
tcx.def_key(self.instance.def_id()).disambiguated_data.data,
DefPathData::Closure { .. }
) {
errors::FrameNote {
where_: "closure",
span,
Expand Down
18 changes: 16 additions & 2 deletions compiler/rustc_hir/src/def.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@ use rustc_ast::NodeId;
use rustc_data_structures::stable_hasher::ToStableHashKey;
use rustc_data_structures::unord::UnordMap;
use rustc_macros::{Decodable, Encodable, HashStable_Generic};
use rustc_span::Symbol;
use rustc_span::def_id::{DefId, LocalDefId};
use rustc_span::hygiene::MacroKind;
use rustc_span::{Symbol, kw, sym};

use crate::definitions::DefPathData;
use crate::hir;
Expand Down Expand Up @@ -319,7 +319,21 @@ impl DefKind {
DefKind::OpaqueTy => DefPathData::OpaqueTy,
DefKind::GlobalAsm => DefPathData::GlobalAsm,
DefKind::Impl { .. } => DefPathData::Impl,
DefKind::Closure { .. } => DefPathData::Closure,
DefKind::Closure { coroutine_kind } => match coroutine_kind {
None => DefPathData::Closure { coroutine_kind: None },
Some(CoroutineDefKind::Desugared(hir::CoroutineDesugaring::Async)) => {
DefPathData::Closure { coroutine_kind: Some(kw::Async) }
}
Some(CoroutineDefKind::Desugared(hir::CoroutineDesugaring::Gen)) => {
DefPathData::Closure { coroutine_kind: Some(kw::Gen) }
}
Some(CoroutineDefKind::Desugared(hir::CoroutineDesugaring::AsyncGen)) => {
DefPathData::Closure { coroutine_kind: Some(sym::async_gen) }
}
Some(CoroutineDefKind::Coroutine) => {
DefPathData::Closure { coroutine_kind: Some(sym::coroutine) }
}
},
DefKind::SyntheticCoroutineBody => DefPathData::SyntheticCoroutineBody,
}
}
Expand Down
58 changes: 37 additions & 21 deletions compiler/rustc_hir/src/definitions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -190,13 +190,20 @@ impl DisambiguatedDefPathData {
writer.write_str(name.as_str())
}
}
DefPathDataName::Anon { namespace } => {
if let DefPathData::AnonAssocTy(method) = self.data {
DefPathDataName::Anon { namespace, kind } => match (self.data, kind) {
(DefPathData::AnonAssocTy(method), None) => {
write!(writer, "{}::{{{}#{}}}", method, namespace, self.disambiguator)
} else {
}
(DefPathData::AnonAssocTy(method), Some(kind)) => {
write!(writer, "{}::{{{}:{}#{}}}", method, namespace, kind, self.disambiguator)
}
(_, None) => {
write!(writer, "{{{}#{}}}", namespace, self.disambiguator)
}
}
(_, Some(kind)) => {
write!(writer, "{{{}:{}#{}}}", namespace, kind, self.disambiguator)
}
},
}
}
}
Expand Down Expand Up @@ -299,7 +306,7 @@ pub enum DefPathData {
/// Something in the lifetime namespace.
LifetimeNs(Symbol),
/// A closure expression.
Closure,
Closure { coroutine_kind: Option<Symbol> },

// Subportions of items:
/// Implicit constructor for a unit or tuple-like struct or enum variant.
Expand Down Expand Up @@ -440,7 +447,7 @@ impl Definitions {
#[derive(Copy, Clone, PartialEq, Debug)]
pub enum DefPathDataName {
Named(Symbol),
Anon { namespace: Symbol },
Anon { namespace: Symbol, kind: Option<Symbol> },
}

impl DefPathData {
Expand All @@ -450,12 +457,13 @@ impl DefPathData {
TypeNs(name) | ValueNs(name) | MacroNs(name) | LifetimeNs(name)
| OpaqueLifetime(name) => Some(name),

Closure { coroutine_kind } => coroutine_kind,

Impl
| ForeignMod
| CrateRoot
| Use
| GlobalAsm
| Closure
| Ctor
| AnonConst
| OpaqueTy
Expand All @@ -471,12 +479,13 @@ impl DefPathData {
TypeNs(name) | ValueNs(name) | MacroNs(name) | LifetimeNs(name) | AnonAssocTy(name)
| OpaqueLifetime(name) => Some(name),

Closure { coroutine_kind } => coroutine_kind,

Impl
| ForeignMod
| CrateRoot
| Use
| GlobalAsm
| Closure
| Ctor
| AnonConst
| OpaqueTy
Expand All @@ -491,18 +500,22 @@ impl DefPathData {
TypeNs(name) | ValueNs(name) | MacroNs(name) | LifetimeNs(name)
| OpaqueLifetime(name) => DefPathDataName::Named(name),
// Note that this does not show up in user print-outs.
CrateRoot => DefPathDataName::Anon { namespace: kw::Crate },
Impl => DefPathDataName::Anon { namespace: kw::Impl },
ForeignMod => DefPathDataName::Anon { namespace: kw::Extern },
Use => DefPathDataName::Anon { namespace: kw::Use },
GlobalAsm => DefPathDataName::Anon { namespace: sym::global_asm },
Closure => DefPathDataName::Anon { namespace: sym::closure },
Ctor => DefPathDataName::Anon { namespace: sym::constructor },
AnonConst => DefPathDataName::Anon { namespace: sym::constant },
OpaqueTy => DefPathDataName::Anon { namespace: sym::opaque },
AnonAssocTy(..) => DefPathDataName::Anon { namespace: sym::anon_assoc },
SyntheticCoroutineBody => DefPathDataName::Anon { namespace: sym::synthetic },
NestedStatic => DefPathDataName::Anon { namespace: sym::nested },
CrateRoot => DefPathDataName::Anon { namespace: kw::Crate, kind: None },
Impl => DefPathDataName::Anon { namespace: kw::Impl, kind: None },
ForeignMod => DefPathDataName::Anon { namespace: kw::Extern, kind: None },
Use => DefPathDataName::Anon { namespace: kw::Use, kind: None },
GlobalAsm => DefPathDataName::Anon { namespace: sym::global_asm, kind: None },
Closure { coroutine_kind } => {
DefPathDataName::Anon { namespace: sym::closure, kind: coroutine_kind }
}
Ctor => DefPathDataName::Anon { namespace: sym::constructor, kind: None },
AnonConst => DefPathDataName::Anon { namespace: sym::constant, kind: None },
OpaqueTy => DefPathDataName::Anon { namespace: sym::opaque, kind: None },
AnonAssocTy(..) => DefPathDataName::Anon { namespace: sym::anon_assoc, kind: None },
SyntheticCoroutineBody => {
DefPathDataName::Anon { namespace: sym::synthetic, kind: None }
}
NestedStatic => DefPathDataName::Anon { namespace: sym::nested, kind: None },
}
}
}
Expand All @@ -512,7 +525,10 @@ impl fmt::Display for DefPathData {
match self.name() {
DefPathDataName::Named(name) => f.write_str(name.as_str()),
// FIXME(#70334): this will generate legacy {{closure}}, {{impl}}, etc
DefPathDataName::Anon { namespace } => write!(f, "{{{{{namespace}}}}}"),
DefPathDataName::Anon { namespace, kind: None } => write!(f, "{{{{{namespace}}}}}"),
DefPathDataName::Anon { namespace, kind: Some(n) } => {
write!(f, "{{{{{namespace}:{n}}}}}")
}
}
}
}
2 changes: 1 addition & 1 deletion compiler/rustc_middle/src/ty/instance.rs
Original file line number Diff line number Diff line change
Expand Up @@ -314,7 +314,7 @@ impl<'tcx> InstanceKind<'tcx> {
};
matches!(
tcx.def_key(def_id).disambiguated_data.data,
DefPathData::Ctor | DefPathData::Closure
DefPathData::Ctor | DefPathData::Closure { .. }
)
}

Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_middle/src/ty/print/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ pub trait Printer<'tcx>: Sized {
parent_args = &args[..generics.parent_count.min(args.len())];

match key.disambiguated_data.data {
DefPathData::Closure => {
DefPathData::Closure { .. } => {
// We need to additionally print the `kind` field of a coroutine if
// it is desugared from a coroutine-closure.
if let Some(hir::CoroutineKind::Desugared(
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_middle/src/ty/print/pretty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2193,7 +2193,7 @@ fn guess_def_namespace(tcx: TyCtxt<'_>, def_id: DefId) -> Namespace {

DefPathData::ValueNs(..)
| DefPathData::AnonConst
| DefPathData::Closure
| DefPathData::Closure { .. }
| DefPathData::Ctor => Namespace::ValueNS,

DefPathData::MacroNs(..) => Namespace::MacroNS,
Expand Down
12 changes: 10 additions & 2 deletions compiler/rustc_resolve/src/def_collector.rs
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,8 @@ impl<'a, 'ra, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'ra, 'tcx> {

// Async closures desugar to closures inside of closures, so
// we must create two defs.
// This is the inner coroutine-ish closure, so we should include
// the coroutine info.
let def_kind =
DefKind::Closure { coroutine_kind: Some(coroutine_def_kind(coroutine_kind)) };
let coroutine_def =
Expand Down Expand Up @@ -368,9 +370,15 @@ impl<'a, 'ra, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'ra, 'tcx> {
ExprKind::MacCall(..) => return self.visit_macro_invoc(expr.id),
ExprKind::Closure(ref closure) => {
let coroutine_kind = match closure.coroutine_kind {
Some(kind) => Some(coroutine_def_kind(&kind)),
// A closure may actually be a coroutine if it has the `#[coroutine]` attr.
// This is more like an `async {}` or `gen {}` block in that it's actually the
// coroutine (instead of async/gen closures, where the desugared inner closure
// is the real coroutine). So we should include the coroutine kind here.
None if has_coroutine_attr(&expr.attrs) => Some(CoroutineDefKind::Coroutine),
None => None,
// For async/gen closures (`async || ...` / `gen || ...`), the desugared inner
// closure will have `coroutine_kind = Some(_)`. This is the outer closure, so
// we should not include it.
_ => None,
};

self.create_def(expr.id, None, DefKind::Closure { coroutine_kind }, expr.span)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -712,7 +712,7 @@ fn encode_ty_name(tcx: TyCtxt<'_>, def_id: DefId) -> String {
hir::definitions::DefPathData::ForeignMod => "F", // Not specified in v0's <namespace>
hir::definitions::DefPathData::TypeNs(..) => "t",
hir::definitions::DefPathData::ValueNs(..) => "v",
hir::definitions::DefPathData::Closure => "C",
hir::definitions::DefPathData::Closure { .. } => "C",
hir::definitions::DefPathData::Ctor => "c",
hir::definitions::DefPathData::AnonConst => "k",
hir::definitions::DefPathData::OpaqueTy => "i",
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_span/src/symbol.rs
Original file line number Diff line number Diff line change
Expand Up @@ -510,6 +510,7 @@ symbols! {
async_fn_track_caller,
async_fn_traits,
async_for_loop,
async_gen,
async_iterator,
async_iterator_poll_next,
async_trait_bounds,
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_symbol_mangling/src/legacy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ pub(super) fn mangle<'tcx>(
match key.disambiguated_data.data {
DefPathData::TypeNs(_)
| DefPathData::ValueNs(_)
| DefPathData::Closure
| DefPathData::Closure { .. }
| DefPathData::SyntheticCoroutineBody => {
instance_ty = tcx.type_of(ty_def_id).instantiate_identity();
debug!(?instance_ty);
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_symbol_mangling/src/v0.rs
Original file line number Diff line number Diff line change
Expand Up @@ -872,7 +872,7 @@ impl<'tcx> Printer<'tcx> for SymbolMangler<'tcx> {
// Uppercase categories are more stable than lowercase ones.
DefPathData::TypeNs(_) => 't',
DefPathData::ValueNs(_) => 'v',
DefPathData::Closure => 'C',
DefPathData::Closure { .. } => 'C',
DefPathData::Ctor => 'c',
DefPathData::AnonConst => 'k',
DefPathData::OpaqueTy => 'i',
Expand Down
2 changes: 1 addition & 1 deletion tests/codegen-units/item-collection/closures.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
//@ compile-flags: -Clink-dead-code --crate-type=lib

//~ MONO_ITEM fn async_fn @@
//~ MONO_ITEM fn async_fn::{closure#0} @@
//~ MONO_ITEM fn async_fn::{closure:async#0} @@
pub async fn async_fn() {}

//~ MONO_ITEM fn closure @@
Expand Down
4 changes: 2 additions & 2 deletions tests/codegen/issues/issue-98678-closure-coroutine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ pub fn foo() {
let closure = |x| x;
closure(0);

// NONMSVC-DAG: !DICompositeType({{.*"[{]}}coroutine_env#1{{[}]".*}}file: ![[#FILE]]{{.*}}line: [[# @LINE + 3]],
// MSVC-DAG: !DICompositeType({{.*".*foo::}}coroutine_env$1>{{".*}}file: ![[#FILE]]{{.*}}line: [[# @LINE + 2]],
// NONMSVC-DAG: !DICompositeType({{.*"[{]}}coroutine_env#0{{[}]".*}}file: ![[#FILE]]{{.*}}line: [[# @LINE + 3]],
// MSVC-DAG: !DICompositeType({{.*".*foo::}}coroutine_env$0>{{".*}}file: ![[#FILE]]{{.*}}line: [[# @LINE + 2]],
let _coroutine = #[coroutine]
|| yield 1;
}
18 changes: 9 additions & 9 deletions tests/coverage/async.cov-map
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ Number of file 0 mappings: 1
- Code(Counter(0)) at (prev + 11, 1) to (start + 0, 24)
Highest counter ID seen: c0

Function name: async::c::{closure#0}
Function name: async::c::{closure:async#0}
Raw bytes (31): 0x[01, 01, 01, 01, 05, 05, 01, 0b, 19, 00, 1a, 01, 01, 08, 00, 0e, 05, 01, 09, 00, 0a, 02, 02, 09, 00, 0a, 01, 02, 01, 00, 02]
Number of files: 1
- file 0 => $DIR/async.rs
Expand All @@ -31,7 +31,7 @@ Number of file 0 mappings: 1
- Code(Counter(0)) at (prev + 19, 1) to (start + 0, 19)
Highest counter ID seen: c0

Function name: async::d::{closure#0}
Function name: async::d::{closure:async#0}
Raw bytes (19): 0x[01, 01, 00, 03, 01, 13, 14, 00, 15, 01, 00, 16, 00, 17, 01, 00, 18, 00, 19]
Number of files: 1
- file 0 => $DIR/async.rs
Expand All @@ -51,7 +51,7 @@ Number of file 0 mappings: 1
- Code(Zero) at (prev + 21, 1) to (start + 0, 19)
Highest counter ID seen: (none)

Function name: async::e::{closure#0} (unused)
Function name: async::e::{closure:async#0} (unused)
Raw bytes (19): 0x[01, 01, 00, 03, 00, 15, 14, 00, 15, 00, 00, 16, 00, 17, 00, 00, 18, 00, 19]
Number of files: 1
- file 0 => $DIR/async.rs
Expand All @@ -71,7 +71,7 @@ Number of file 0 mappings: 1
- Code(Counter(0)) at (prev + 23, 1) to (start + 0, 19)
Highest counter ID seen: c0

Function name: async::f::{closure#0}
Function name: async::f::{closure:async#0}
Raw bytes (19): 0x[01, 01, 00, 03, 01, 17, 14, 00, 15, 01, 00, 16, 00, 17, 01, 00, 18, 00, 19]
Number of files: 1
- file 0 => $DIR/async.rs
Expand All @@ -91,7 +91,7 @@ Number of file 0 mappings: 1
- Code(Zero) at (prev + 25, 1) to (start + 0, 29)
Highest counter ID seen: (none)

Function name: async::foo::{closure#0} (unused)
Function name: async::foo::{closure:async#0} (unused)
Raw bytes (19): 0x[01, 01, 00, 03, 00, 19, 1e, 00, 1f, 00, 00, 20, 00, 2b, 00, 00, 2c, 00, 2d]
Number of files: 1
- file 0 => $DIR/async.rs
Expand All @@ -111,7 +111,7 @@ Number of file 0 mappings: 1
- Code(Counter(0)) at (prev + 27, 1) to (start + 0, 22)
Highest counter ID seen: c0

Function name: async::g::{closure#0} (unused)
Function name: async::g::{closure:async#0} (unused)
Raw bytes (64): 0x[01, 01, 00, 0c, 00, 1b, 17, 00, 18, 00, 01, 0b, 00, 0c, 00, 01, 09, 00, 0a, 00, 00, 0e, 00, 17, 00, 00, 1b, 00, 1c, 00, 00, 20, 00, 22, 00, 01, 09, 00, 0a, 00, 00, 0e, 00, 17, 00, 00, 1b, 00, 1c, 00, 00, 20, 00, 22, 00, 01, 0e, 00, 10, 00, 02, 01, 00, 02]
Number of files: 1
- file 0 => $DIR/async.rs
Expand Down Expand Up @@ -140,7 +140,7 @@ Number of file 0 mappings: 1
- Code(Counter(0)) at (prev + 35, 1) to (start + 0, 21)
Highest counter ID seen: c0

Function name: async::h::{closure#0} (unused)
Function name: async::h::{closure:async#0} (unused)
Raw bytes (44): 0x[01, 01, 00, 08, 00, 23, 16, 00, 17, 00, 03, 0b, 00, 0c, 00, 01, 09, 00, 0a, 00, 00, 0e, 00, 19, 00, 00, 1a, 00, 1b, 00, 00, 20, 00, 22, 00, 01, 0e, 00, 10, 00, 02, 01, 00, 02]
Number of files: 1
- file 0 => $DIR/async.rs
Expand All @@ -165,7 +165,7 @@ Number of file 0 mappings: 1
- Code(Counter(0)) at (prev + 44, 1) to (start + 0, 18)
Highest counter ID seen: c0

Function name: async::i::{closure#0}
Function name: async::i::{closure:async#0}
Raw bytes (75): 0x[01, 01, 03, 05, 09, 11, 15, 0d, 11, 0d, 01, 2c, 13, 00, 14, 01, 04, 0b, 00, 0c, 09, 01, 09, 00, 0a, 01, 00, 0e, 00, 0f, 01, 00, 0e, 00, 18, 05, 00, 1c, 00, 21, 09, 00, 27, 00, 30, 15, 01, 09, 00, 0a, 02, 00, 0e, 00, 17, 11, 00, 1b, 00, 20, 15, 00, 24, 00, 26, 06, 01, 0e, 00, 10, 0b, 02, 01, 00, 02]
Number of files: 1
- file 0 => $DIR/async.rs
Expand Down Expand Up @@ -293,7 +293,7 @@ Number of file 0 mappings: 1
- Code(Counter(0)) at (prev + 89, 1) to (start + 0, 24)
Highest counter ID seen: c0

Function name: async::m::{closure#0} (unused)
Function name: async::m::{closure:async#0} (unused)
Raw bytes (19): 0x[01, 01, 00, 03, 00, 59, 19, 00, 1a, 00, 00, 1b, 00, 20, 00, 00, 21, 00, 22]
Number of files: 1
- file 0 => $DIR/async.rs
Expand Down
Loading
Loading