Identify anonymous lifetimes by their DefId in HIR.
This commit is contained in:
parent
012720ffb0
commit
d3b7ea6c9e
3 changed files with 104 additions and 69 deletions
|
@ -95,6 +95,7 @@ impl<'a> Visitor<'a> for ItemLowerer<'a, '_, '_> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_assoc_item(&mut self, item: &'a AssocItem, ctxt: AssocCtxt) {
|
fn visit_assoc_item(&mut self, item: &'a AssocItem, ctxt: AssocCtxt) {
|
||||||
|
debug!(in_scope_lifetimes = ?self.lctx.in_scope_lifetimes);
|
||||||
self.lctx.with_hir_id_owner(item.id, |lctx| match ctxt {
|
self.lctx.with_hir_id_owner(item.id, |lctx| match ctxt {
|
||||||
AssocCtxt::Trait => hir::OwnerNode::TraitItem(lctx.lower_trait_item(item)),
|
AssocCtxt::Trait => hir::OwnerNode::TraitItem(lctx.lower_trait_item(item)),
|
||||||
AssocCtxt::Impl => hir::OwnerNode::ImplItem(lctx.lower_impl_item(item)),
|
AssocCtxt::Impl => hir::OwnerNode::ImplItem(lctx.lower_impl_item(item)),
|
||||||
|
@ -118,35 +119,42 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||||
// This should only be used with generics that have already had their
|
// This should only be used with generics that have already had their
|
||||||
// in-band lifetimes added. In practice, this means that this function is
|
// in-band lifetimes added. In practice, this means that this function is
|
||||||
// only used when lowering a child item of a trait or impl.
|
// only used when lowering a child item of a trait or impl.
|
||||||
|
#[tracing::instrument(level = "debug", skip(self, f))]
|
||||||
fn with_parent_item_lifetime_defs<T>(
|
fn with_parent_item_lifetime_defs<T>(
|
||||||
&mut self,
|
&mut self,
|
||||||
parent_hir_id: LocalDefId,
|
parent_hir_id: LocalDefId,
|
||||||
f: impl FnOnce(&mut Self) -> T,
|
f: impl FnOnce(&mut Self) -> T,
|
||||||
) -> T {
|
) -> T {
|
||||||
let old_len = self.in_scope_lifetimes.len();
|
|
||||||
|
|
||||||
let parent_generics = match self.owners[parent_hir_id].unwrap().node().expect_item().kind {
|
let parent_generics = match self.owners[parent_hir_id].unwrap().node().expect_item().kind {
|
||||||
hir::ItemKind::Impl(hir::Impl { ref generics, .. })
|
hir::ItemKind::Impl(hir::Impl { ref generics, .. })
|
||||||
| hir::ItemKind::Trait(_, _, ref generics, ..) => generics.params,
|
| hir::ItemKind::Trait(_, _, ref generics, ..) => generics.params,
|
||||||
_ => &[],
|
_ => &[],
|
||||||
};
|
};
|
||||||
let lt_def_names = parent_generics.iter().filter_map(|param| match param.kind {
|
let lt_def_names = parent_generics
|
||||||
hir::GenericParamKind::Lifetime { .. } => Some(param.name.normalize_to_macros_2_0()),
|
.iter()
|
||||||
|
.filter_map(|param| match param.kind {
|
||||||
|
hir::GenericParamKind::Lifetime { .. } => {
|
||||||
|
Some(param.name.normalize_to_macros_2_0())
|
||||||
|
}
|
||||||
_ => None,
|
_ => None,
|
||||||
});
|
})
|
||||||
self.in_scope_lifetimes.extend(lt_def_names);
|
.collect();
|
||||||
|
let old_in_scope_lifetimes = mem::replace(&mut self.in_scope_lifetimes, lt_def_names);
|
||||||
|
debug!(in_scope_lifetimes = ?self.in_scope_lifetimes);
|
||||||
|
|
||||||
let res = f(self);
|
let res = f(self);
|
||||||
|
|
||||||
self.in_scope_lifetimes.truncate(old_len);
|
self.in_scope_lifetimes = old_in_scope_lifetimes;
|
||||||
res
|
res
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clears (and restores) the `in_scope_lifetimes` field. Used when
|
// Clears (and restores) the `in_scope_lifetimes` field. Used when
|
||||||
// visiting nested items, which never inherit in-scope lifetimes
|
// visiting nested items, which never inherit in-scope lifetimes
|
||||||
// from their surrounding environment.
|
// from their surrounding environment.
|
||||||
|
#[tracing::instrument(level = "debug", skip(self, f))]
|
||||||
fn without_in_scope_lifetime_defs<T>(&mut self, f: impl FnOnce(&mut Self) -> T) -> T {
|
fn without_in_scope_lifetime_defs<T>(&mut self, f: impl FnOnce(&mut Self) -> T) -> T {
|
||||||
let old_in_scope_lifetimes = mem::replace(&mut self.in_scope_lifetimes, vec![]);
|
let old_in_scope_lifetimes = mem::replace(&mut self.in_scope_lifetimes, vec![]);
|
||||||
|
debug!(?old_in_scope_lifetimes);
|
||||||
|
|
||||||
// this vector is only used when walking over impl headers,
|
// this vector is only used when walking over impl headers,
|
||||||
// input types, and the like, and should not be non-empty in
|
// input types, and the like, and should not be non-empty in
|
||||||
|
|
|
@ -136,13 +136,13 @@ struct LoweringContext<'a, 'hir: 'a> {
|
||||||
/// (i.e., it doesn't appear in the in_scope_lifetimes list), it is added
|
/// (i.e., it doesn't appear in the in_scope_lifetimes list), it is added
|
||||||
/// to this list. The results of this list are then added to the list of
|
/// to this list. The results of this list are then added to the list of
|
||||||
/// lifetime definitions in the corresponding impl or function generics.
|
/// lifetime definitions in the corresponding impl or function generics.
|
||||||
lifetimes_to_define: Vec<(Span, ParamName)>,
|
lifetimes_to_define: Vec<(Span, NodeId)>,
|
||||||
|
|
||||||
/// `true` if in-band lifetimes are being collected. This is used to
|
/// `true` if in-band lifetimes are being collected. This is used to
|
||||||
/// indicate whether or not we're in a place where new lifetimes will result
|
/// indicate whether or not we're in a place where new lifetimes will result
|
||||||
/// in in-band lifetime definitions, such a function or an impl header,
|
/// in in-band lifetime definitions, such a function or an impl header,
|
||||||
/// including implicit lifetimes from `impl_header_lifetime_elision`.
|
/// including implicit lifetimes from `impl_header_lifetime_elision`.
|
||||||
is_collecting_anonymous_lifetimes: bool,
|
is_collecting_anonymous_lifetimes: Option<LocalDefId>,
|
||||||
|
|
||||||
/// Currently in-scope lifetimes defined in impl headers, fn headers, or HRTB.
|
/// Currently in-scope lifetimes defined in impl headers, fn headers, or HRTB.
|
||||||
/// We always store a `normalize_to_macros_2_0()` version of the param-name in this
|
/// We always store a `normalize_to_macros_2_0()` version of the param-name in this
|
||||||
|
@ -375,7 +375,7 @@ pub fn lower_crate<'a, 'hir>(
|
||||||
task_context: None,
|
task_context: None,
|
||||||
current_item: None,
|
current_item: None,
|
||||||
lifetimes_to_define: Vec::new(),
|
lifetimes_to_define: Vec::new(),
|
||||||
is_collecting_anonymous_lifetimes: false,
|
is_collecting_anonymous_lifetimes: None,
|
||||||
in_scope_lifetimes: Vec::new(),
|
in_scope_lifetimes: Vec::new(),
|
||||||
allow_try_trait: Some([sym::try_trait_v2][..].into()),
|
allow_try_trait: Some([sym::try_trait_v2][..].into()),
|
||||||
allow_gen_future: Some([sym::gen_future][..].into()),
|
allow_gen_future: Some([sym::gen_future][..].into()),
|
||||||
|
@ -720,9 +720,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||||
/// parameter while `f` is running (and restored afterwards).
|
/// parameter while `f` is running (and restored afterwards).
|
||||||
fn collect_in_band_defs<T>(
|
fn collect_in_band_defs<T>(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
parent_def_id: LocalDefId,
|
||||||
f: impl FnOnce(&mut Self) -> T,
|
f: impl FnOnce(&mut Self) -> T,
|
||||||
) -> (Vec<(Span, ParamName)>, T) {
|
) -> (Vec<(Span, NodeId)>, T) {
|
||||||
let was_collecting = std::mem::replace(&mut self.is_collecting_anonymous_lifetimes, true);
|
let was_collecting =
|
||||||
|
std::mem::replace(&mut self.is_collecting_anonymous_lifetimes, Some(parent_def_id));
|
||||||
let len = self.lifetimes_to_define.len();
|
let len = self.lifetimes_to_define.len();
|
||||||
|
|
||||||
let res = f(self);
|
let res = f(self);
|
||||||
|
@ -733,49 +735,41 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Converts a lifetime into a new generic parameter.
|
/// Converts a lifetime into a new generic parameter.
|
||||||
fn lifetime_to_generic_param(
|
fn fresh_lifetime_to_generic_param(
|
||||||
&mut self,
|
&mut self,
|
||||||
span: Span,
|
span: Span,
|
||||||
hir_name: ParamName,
|
node_id: NodeId,
|
||||||
parent_def_id: LocalDefId,
|
|
||||||
) -> hir::GenericParam<'hir> {
|
) -> hir::GenericParam<'hir> {
|
||||||
let node_id = self.resolver.next_node_id();
|
let hir_id = self.lower_node_id(node_id);
|
||||||
|
let def_id = self.resolver.local_def_id(node_id);
|
||||||
// Get the name we'll use to make the def-path. Note
|
|
||||||
// that collisions are ok here and this shouldn't
|
|
||||||
// really show up for end-user.
|
|
||||||
let (str_name, kind) = match hir_name {
|
|
||||||
ParamName::Plain(ident) => (ident.name, hir::LifetimeParamKind::Explicit),
|
|
||||||
ParamName::Fresh(_) => (kw::UnderscoreLifetime, hir::LifetimeParamKind::Elided),
|
|
||||||
ParamName::Error => (kw::UnderscoreLifetime, hir::LifetimeParamKind::Error),
|
|
||||||
};
|
|
||||||
|
|
||||||
// Add a definition for the in-band lifetime def.
|
|
||||||
self.resolver.create_def(
|
|
||||||
parent_def_id,
|
|
||||||
node_id,
|
|
||||||
DefPathData::LifetimeNs(str_name),
|
|
||||||
ExpnId::root(),
|
|
||||||
span.with_parent(None),
|
|
||||||
);
|
|
||||||
|
|
||||||
hir::GenericParam {
|
hir::GenericParam {
|
||||||
hir_id: self.lower_node_id(node_id),
|
hir_id,
|
||||||
name: hir_name,
|
name: hir::ParamName::Fresh(def_id),
|
||||||
bounds: &[],
|
bounds: &[],
|
||||||
span: self.lower_span(span),
|
span: self.lower_span(span),
|
||||||
pure_wrt_drop: false,
|
pure_wrt_drop: false,
|
||||||
kind: hir::GenericParamKind::Lifetime { kind },
|
kind: hir::GenericParamKind::Lifetime { kind: hir::LifetimeParamKind::Elided },
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// When we have either an elided or `'_` lifetime in an impl
|
/// When we have either an elided or `'_` lifetime in an impl
|
||||||
/// header, we convert it to an in-band lifetime.
|
/// header, we convert it to an in-band lifetime.
|
||||||
fn collect_fresh_anonymous_lifetime(&mut self, span: Span) -> ParamName {
|
fn collect_fresh_anonymous_lifetime(&mut self, span: Span) -> ParamName {
|
||||||
assert!(self.is_collecting_anonymous_lifetimes);
|
let Some(parent_def_id) = self.is_collecting_anonymous_lifetimes else { panic!() };
|
||||||
let index = self.lifetimes_to_define.len() + self.in_scope_lifetimes.len();
|
|
||||||
let hir_name = ParamName::Fresh(index);
|
let node_id = self.resolver.next_node_id();
|
||||||
self.lifetimes_to_define.push((span, hir_name));
|
|
||||||
|
// Add a definition for the in-band lifetime def.
|
||||||
|
let param_def_id = self.resolver.create_def(
|
||||||
|
parent_def_id,
|
||||||
|
node_id,
|
||||||
|
DefPathData::LifetimeNs(kw::UnderscoreLifetime),
|
||||||
|
ExpnId::root(),
|
||||||
|
span.with_parent(None),
|
||||||
|
);
|
||||||
|
|
||||||
|
let hir_name = ParamName::Fresh(param_def_id);
|
||||||
|
self.lifetimes_to_define.push((span, node_id));
|
||||||
hir_name
|
hir_name
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -817,7 +811,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||||
f: impl FnOnce(&mut Self, &mut Vec<hir::GenericParam<'hir>>) -> T,
|
f: impl FnOnce(&mut Self, &mut Vec<hir::GenericParam<'hir>>) -> T,
|
||||||
) -> (hir::Generics<'hir>, T) {
|
) -> (hir::Generics<'hir>, T) {
|
||||||
let (lifetimes_to_define, (mut lowered_generics, impl_trait_defs, res)) = self
|
let (lifetimes_to_define, (mut lowered_generics, impl_trait_defs, res)) = self
|
||||||
.collect_in_band_defs(|this| {
|
.collect_in_band_defs(parent_def_id, |this| {
|
||||||
this.with_anonymous_lifetime_mode(anonymous_lifetime_mode, |this| {
|
this.with_anonymous_lifetime_mode(anonymous_lifetime_mode, |this| {
|
||||||
this.with_in_scope_lifetime_defs(&generics.params, |this| {
|
this.with_in_scope_lifetime_defs(&generics.params, |this| {
|
||||||
let mut impl_trait_defs = Vec::new();
|
let mut impl_trait_defs = Vec::new();
|
||||||
|
@ -844,9 +838,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||||
lowered_generics.params.extend(
|
lowered_generics.params.extend(
|
||||||
lifetimes_to_define
|
lifetimes_to_define
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|(span, hir_name)| {
|
.map(|(span, node_id)| self.fresh_lifetime_to_generic_param(span, node_id))
|
||||||
self.lifetime_to_generic_param(span, hir_name, parent_def_id)
|
|
||||||
})
|
|
||||||
.chain(impl_trait_defs),
|
.chain(impl_trait_defs),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -1763,15 +1755,53 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||||
.in_scope_lifetimes
|
.in_scope_lifetimes
|
||||||
.iter()
|
.iter()
|
||||||
.cloned()
|
.cloned()
|
||||||
.map(|name| (name.ident().span, name, hir::LifetimeName::Param(name)))
|
.map(|name| (name.ident().span, hir::LifetimeName::Param(name)))
|
||||||
.chain(
|
.chain(self.lifetimes_to_define.iter().map(|&(span, node_id)| {
|
||||||
self.lifetimes_to_define
|
let def_id = self.resolver.local_def_id(node_id);
|
||||||
.iter()
|
let name = hir::ParamName::Fresh(def_id);
|
||||||
.map(|&(span, name)| (span, name, hir::LifetimeName::Param(name))),
|
(span, hir::LifetimeName::Param(name))
|
||||||
)
|
}))
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
self.with_hir_id_owner(opaque_ty_node_id, |this| {
|
self.with_hir_id_owner(opaque_ty_node_id, |this| {
|
||||||
|
let mut generic_params: Vec<_> = lifetime_params
|
||||||
|
.iter()
|
||||||
|
.map(|&(span, name)| {
|
||||||
|
// We can only get lifetime names from the outside.
|
||||||
|
let hir::LifetimeName::Param(hir_name) = name else { panic!() };
|
||||||
|
|
||||||
|
let node_id = this.resolver.next_node_id();
|
||||||
|
|
||||||
|
// Add a definition for the in-band lifetime def.
|
||||||
|
let def_id = this.resolver.create_def(
|
||||||
|
opaque_ty_def_id,
|
||||||
|
node_id,
|
||||||
|
DefPathData::LifetimeNs(hir_name.ident().name),
|
||||||
|
ExpnId::root(),
|
||||||
|
span.with_parent(None),
|
||||||
|
);
|
||||||
|
|
||||||
|
let (kind, name) = match hir_name {
|
||||||
|
ParamName::Plain(ident) => {
|
||||||
|
(hir::LifetimeParamKind::Explicit, hir::ParamName::Plain(ident))
|
||||||
|
}
|
||||||
|
ParamName::Fresh(_) => {
|
||||||
|
(hir::LifetimeParamKind::Elided, hir::ParamName::Fresh(def_id))
|
||||||
|
}
|
||||||
|
ParamName::Error => (hir::LifetimeParamKind::Error, hir::ParamName::Error),
|
||||||
|
};
|
||||||
|
|
||||||
|
hir::GenericParam {
|
||||||
|
hir_id: this.lower_node_id(node_id),
|
||||||
|
name,
|
||||||
|
bounds: &[],
|
||||||
|
span: this.lower_span(span),
|
||||||
|
pure_wrt_drop: false,
|
||||||
|
kind: hir::GenericParamKind::Lifetime { kind },
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
|
||||||
// We have to be careful to get elision right here. The
|
// We have to be careful to get elision right here. The
|
||||||
// idea is that we create a lifetime parameter for each
|
// idea is that we create a lifetime parameter for each
|
||||||
// lifetime in the return type. So, given a return type
|
// lifetime in the return type. So, given a return type
|
||||||
|
@ -1782,25 +1812,22 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||||
// hence the elision takes place at the fn site.
|
// hence the elision takes place at the fn site.
|
||||||
let (lifetimes_to_define, future_bound) =
|
let (lifetimes_to_define, future_bound) =
|
||||||
this.with_anonymous_lifetime_mode(AnonymousLifetimeMode::CreateParameter, |this| {
|
this.with_anonymous_lifetime_mode(AnonymousLifetimeMode::CreateParameter, |this| {
|
||||||
this.collect_in_band_defs(|this| {
|
this.collect_in_band_defs(opaque_ty_def_id, |this| {
|
||||||
this.lower_async_fn_output_type_to_future_bound(output, fn_def_id, span)
|
this.lower_async_fn_output_type_to_future_bound(output, fn_def_id, span)
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
debug!("lower_async_fn_ret_ty: future_bound={:#?}", future_bound);
|
debug!("lower_async_fn_ret_ty: future_bound={:#?}", future_bound);
|
||||||
debug!("lower_async_fn_ret_ty: lifetimes_to_define={:#?}", lifetimes_to_define);
|
debug!("lower_async_fn_ret_ty: lifetimes_to_define={:#?}", lifetimes_to_define);
|
||||||
|
|
||||||
lifetime_params.extend(
|
|
||||||
// Output lifetime like `'_`:
|
// Output lifetime like `'_`:
|
||||||
lifetimes_to_define
|
for (span, node_id) in lifetimes_to_define {
|
||||||
.into_iter()
|
let param = this.fresh_lifetime_to_generic_param(span, node_id);
|
||||||
.map(|(span, name)| (span, name, hir::LifetimeName::Implicit(false))),
|
lifetime_params.push((span, hir::LifetimeName::Implicit(false)));
|
||||||
);
|
generic_params.push(param);
|
||||||
|
}
|
||||||
|
let generic_params = this.arena.alloc_from_iter(generic_params);
|
||||||
debug!("lower_async_fn_ret_ty: lifetime_params={:#?}", lifetime_params);
|
debug!("lower_async_fn_ret_ty: lifetime_params={:#?}", lifetime_params);
|
||||||
|
debug!("lower_async_fn_ret_ty: generic_params={:#?}", generic_params);
|
||||||
let generic_params =
|
|
||||||
this.arena.alloc_from_iter(lifetime_params.iter().map(|&(span, hir_name, _)| {
|
|
||||||
this.lifetime_to_generic_param(span, hir_name, opaque_ty_def_id)
|
|
||||||
}));
|
|
||||||
|
|
||||||
let opaque_ty_item = hir::OpaqueTy {
|
let opaque_ty_item = hir::OpaqueTy {
|
||||||
generics: hir::Generics {
|
generics: hir::Generics {
|
||||||
|
@ -1833,7 +1860,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||||
// For the "output" lifetime parameters, we just want to
|
// For the "output" lifetime parameters, we just want to
|
||||||
// generate `'_`.
|
// generate `'_`.
|
||||||
let generic_args =
|
let generic_args =
|
||||||
self.arena.alloc_from_iter(lifetime_params.into_iter().map(|(span, _, name)| {
|
self.arena.alloc_from_iter(lifetime_params.into_iter().map(|(span, name)| {
|
||||||
GenericArg::Lifetime(hir::Lifetime {
|
GenericArg::Lifetime(hir::Lifetime {
|
||||||
hir_id: self.next_id(),
|
hir_id: self.next_id(),
|
||||||
span: self.lower_span(span),
|
span: self.lower_span(span),
|
||||||
|
@ -1969,7 +1996,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||||
let (name, kind) = match param.kind {
|
let (name, kind) = match param.kind {
|
||||||
GenericParamKind::Lifetime => {
|
GenericParamKind::Lifetime => {
|
||||||
let was_collecting_in_band = self.is_collecting_anonymous_lifetimes;
|
let was_collecting_in_band = self.is_collecting_anonymous_lifetimes;
|
||||||
self.is_collecting_anonymous_lifetimes = false;
|
self.is_collecting_anonymous_lifetimes = None;
|
||||||
|
|
||||||
let lt = self
|
let lt = self
|
||||||
.with_anonymous_lifetime_mode(AnonymousLifetimeMode::ReportError, |this| {
|
.with_anonymous_lifetime_mode(AnonymousLifetimeMode::ReportError, |this| {
|
||||||
|
|
|
@ -59,7 +59,7 @@ pub enum ParamName {
|
||||||
///
|
///
|
||||||
/// where `'f` is something like `Fresh(0)`. The indices are
|
/// where `'f` is something like `Fresh(0)`. The indices are
|
||||||
/// unique per impl, but not necessarily continuous.
|
/// unique per impl, but not necessarily continuous.
|
||||||
Fresh(usize),
|
Fresh(LocalDefId),
|
||||||
|
|
||||||
/// Indicates an illegal name was given and an error has been
|
/// Indicates an illegal name was given and an error has been
|
||||||
/// reported (so we should squelch other derived errors). Occurs
|
/// reported (so we should squelch other derived errors). Occurs
|
||||||
|
@ -3303,7 +3303,7 @@ mod size_asserts {
|
||||||
rustc_data_structures::static_assert_size!(super::Expr<'static>, 56);
|
rustc_data_structures::static_assert_size!(super::Expr<'static>, 56);
|
||||||
rustc_data_structures::static_assert_size!(super::Pat<'static>, 88);
|
rustc_data_structures::static_assert_size!(super::Pat<'static>, 88);
|
||||||
rustc_data_structures::static_assert_size!(super::QPath<'static>, 24);
|
rustc_data_structures::static_assert_size!(super::QPath<'static>, 24);
|
||||||
rustc_data_structures::static_assert_size!(super::Ty<'static>, 80);
|
rustc_data_structures::static_assert_size!(super::Ty<'static>, 72);
|
||||||
|
|
||||||
rustc_data_structures::static_assert_size!(super::Item<'static>, 184);
|
rustc_data_structures::static_assert_size!(super::Item<'static>, 184);
|
||||||
rustc_data_structures::static_assert_size!(super::TraitItem<'static>, 128);
|
rustc_data_structures::static_assert_size!(super::TraitItem<'static>, 128);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue