Lowering field access for anonymous adts
This commit is contained in:
parent
36d7e7fd3f
commit
0c0df4efe0
18 changed files with 391 additions and 71 deletions
|
@ -1299,33 +1299,28 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||||
// // ^_____________________|
|
// // ^_____________________|
|
||||||
// }
|
// }
|
||||||
// ```
|
// ```
|
||||||
TyKind::AnonStruct(def_node_id, fields) | TyKind::AnonUnion(def_node_id, fields) => {
|
TyKind::AnonStruct(node_id, fields) | TyKind::AnonUnion(node_id, fields) => {
|
||||||
let (def_kind, item_kind): (DefKind, fn(_, _) -> _) = match t.kind {
|
// Here its `def_id` is created in `build_reduced_graph`.
|
||||||
TyKind::AnonStruct(..) => (DefKind::Struct, hir::ItemKind::Struct),
|
let def_id = self.local_def_id(*node_id);
|
||||||
TyKind::AnonUnion(..) => (DefKind::Union, hir::ItemKind::Union),
|
|
||||||
_ => unreachable!(),
|
|
||||||
};
|
|
||||||
let def_id = self.create_def(
|
|
||||||
self.current_hir_id_owner.def_id,
|
|
||||||
*def_node_id,
|
|
||||||
kw::Empty,
|
|
||||||
def_kind,
|
|
||||||
t.span,
|
|
||||||
);
|
|
||||||
debug!(?def_id);
|
debug!(?def_id);
|
||||||
let owner_id = hir::OwnerId { def_id };
|
let owner_id = hir::OwnerId { def_id };
|
||||||
self.with_hir_id_owner(*def_node_id, |this| {
|
self.with_hir_id_owner(*node_id, |this| {
|
||||||
let fields = this.arena.alloc_from_iter(
|
let fields = this.arena.alloc_from_iter(
|
||||||
fields.iter().enumerate().map(|f| this.lower_field_def(f)),
|
fields.iter().enumerate().map(|f| this.lower_field_def(f)),
|
||||||
);
|
);
|
||||||
let span = t.span;
|
let span = t.span;
|
||||||
let variant_data = hir::VariantData::Struct(fields, false);
|
let variant_data = hir::VariantData::Struct { fields, recovered: false };
|
||||||
// FIXME: capture the generics from the outer adt.
|
// FIXME: capture the generics from the outer adt.
|
||||||
let generics = hir::Generics::empty();
|
let generics = hir::Generics::empty();
|
||||||
|
let kind = match t.kind {
|
||||||
|
TyKind::AnonStruct(..) => hir::ItemKind::Struct(variant_data, generics),
|
||||||
|
TyKind::AnonUnion(..) => hir::ItemKind::Union(variant_data, generics),
|
||||||
|
_ => unreachable!(),
|
||||||
|
};
|
||||||
hir::OwnerNode::Item(this.arena.alloc(hir::Item {
|
hir::OwnerNode::Item(this.arena.alloc(hir::Item {
|
||||||
ident: Ident::new(kw::Empty, span),
|
ident: Ident::new(kw::Empty, span),
|
||||||
owner_id,
|
owner_id,
|
||||||
kind: item_kind(variant_data, generics),
|
kind,
|
||||||
span: this.lower_span(span),
|
span: this.lower_span(span),
|
||||||
vis_span: this.lower_span(span.shrink_to_lo()),
|
vis_span: this.lower_span(span.shrink_to_lo()),
|
||||||
}))
|
}))
|
||||||
|
|
|
@ -31,6 +31,7 @@ use rustc_middle::ty::util::{Discr, IntTypeExt};
|
||||||
use rustc_middle::ty::{self, AdtKind, Const, IsSuggestable, ToPredicate, Ty, TyCtxt};
|
use rustc_middle::ty::{self, AdtKind, Const, IsSuggestable, ToPredicate, Ty, TyCtxt};
|
||||||
use rustc_span::symbol::{kw, sym, Ident, Symbol};
|
use rustc_span::symbol::{kw, sym, Ident, Symbol};
|
||||||
use rustc_span::Span;
|
use rustc_span::Span;
|
||||||
|
use rustc_target::abi::FieldIdx;
|
||||||
use rustc_target::spec::abi;
|
use rustc_target::spec::abi;
|
||||||
use rustc_trait_selection::infer::InferCtxtExt;
|
use rustc_trait_selection::infer::InferCtxtExt;
|
||||||
use rustc_trait_selection::traits::error_reporting::suggestions::NextTypeParamName;
|
use rustc_trait_selection::traits::error_reporting::suggestions::NextTypeParamName;
|
||||||
|
@ -84,6 +85,7 @@ pub fn provide(providers: &mut Providers) {
|
||||||
coroutine_for_closure,
|
coroutine_for_closure,
|
||||||
collect_mod_item_types,
|
collect_mod_item_types,
|
||||||
is_type_alias_impl_trait,
|
is_type_alias_impl_trait,
|
||||||
|
find_field,
|
||||||
..*providers
|
..*providers
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -875,8 +877,8 @@ fn check_field_uniqueness(
|
||||||
// Abort due to errors (there must be an error if an unnamed field
|
// Abort due to errors (there must be an error if an unnamed field
|
||||||
// has any type kind other than an anonymous adt or a named adt)
|
// has any type kind other than an anonymous adt or a named adt)
|
||||||
_ => {
|
_ => {
|
||||||
debug_assert!(tcx.sess.has_errors().is_some());
|
debug_assert!(tcx.dcx().has_errors().is_some());
|
||||||
tcx.sess.abort_if_errors()
|
tcx.dcx().abort_if_errors()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
|
@ -884,6 +886,18 @@ fn check_field_uniqueness(
|
||||||
check(field.ident, field.span.into());
|
check(field.ident, field.span.into());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn find_field(tcx: TyCtxt<'_>, (def_id, ident): (DefId, Ident)) -> Option<FieldIdx> {
|
||||||
|
tcx.adt_def(def_id).non_enum_variant().fields.iter_enumerated().find_map(|(idx, field)| {
|
||||||
|
if field.is_unnamed() {
|
||||||
|
let field_ty = tcx.type_of(field.did).instantiate_identity();
|
||||||
|
let adt_def = field_ty.ty_adt_def().expect("expect Adt for unnamed field");
|
||||||
|
tcx.find_field((adt_def.did(), ident)).map(|_| idx)
|
||||||
|
} else {
|
||||||
|
(field.ident(tcx).normalize_to_macros_2_0() == ident).then_some(idx)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
fn convert_variant(
|
fn convert_variant(
|
||||||
tcx: TyCtxt<'_>,
|
tcx: TyCtxt<'_>,
|
||||||
variant_did: Option<LocalDefId>,
|
variant_did: Option<LocalDefId>,
|
||||||
|
@ -908,14 +922,14 @@ fn convert_variant(
|
||||||
let ident = ident.normalize_to_macros_2_0();
|
let ident = ident.normalize_to_macros_2_0();
|
||||||
match (field_decl, seen_fields.get(&ident).copied()) {
|
match (field_decl, seen_fields.get(&ident).copied()) {
|
||||||
(NotNested(span), Some(NotNested(prev_span))) => {
|
(NotNested(span), Some(NotNested(prev_span))) => {
|
||||||
tcx.sess.emit_err(errors::FieldAlreadyDeclared::NotNested {
|
tcx.dcx().emit_err(errors::FieldAlreadyDeclared::NotNested {
|
||||||
field_name,
|
field_name,
|
||||||
span,
|
span,
|
||||||
prev_span,
|
prev_span,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
(NotNested(span), Some(Nested(prev))) => {
|
(NotNested(span), Some(Nested(prev))) => {
|
||||||
tcx.sess.emit_err(errors::FieldAlreadyDeclared::PreviousNested {
|
tcx.dcx().emit_err(errors::FieldAlreadyDeclared::PreviousNested {
|
||||||
field_name,
|
field_name,
|
||||||
span,
|
span,
|
||||||
prev_span: prev.span,
|
prev_span: prev.span,
|
||||||
|
@ -926,7 +940,7 @@ fn convert_variant(
|
||||||
Nested(NestedSpan { span, nested_field_span }),
|
Nested(NestedSpan { span, nested_field_span }),
|
||||||
Some(NotNested(prev_span)),
|
Some(NotNested(prev_span)),
|
||||||
) => {
|
) => {
|
||||||
tcx.sess.emit_err(errors::FieldAlreadyDeclared::CurrentNested {
|
tcx.dcx().emit_err(errors::FieldAlreadyDeclared::CurrentNested {
|
||||||
field_name,
|
field_name,
|
||||||
span,
|
span,
|
||||||
nested_field_span,
|
nested_field_span,
|
||||||
|
@ -934,7 +948,7 @@ fn convert_variant(
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
(Nested(NestedSpan { span, nested_field_span }), Some(Nested(prev))) => {
|
(Nested(NestedSpan { span, nested_field_span }), Some(Nested(prev))) => {
|
||||||
tcx.sess.emit_err(errors::FieldAlreadyDeclared::BothNested {
|
tcx.dcx().emit_err(errors::FieldAlreadyDeclared::BothNested {
|
||||||
field_name,
|
field_name,
|
||||||
span,
|
span,
|
||||||
nested_field_span,
|
nested_field_span,
|
||||||
|
|
|
@ -1721,7 +1721,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
let ident = tcx.adjust_ident(field.ident, variant.def_id);
|
let ident = tcx.adjust_ident(field.ident, variant.def_id);
|
||||||
let field_type = if let Some((i, v_field)) = remaining_fields.remove(&ident) {
|
let field_type = if let Some((i, v_field)) = remaining_fields.remove(&ident) {
|
||||||
seen_fields.insert(ident, field.span);
|
seen_fields.insert(ident, field.span);
|
||||||
self.write_field_index(field.hir_id, i);
|
// FIXME: handle nested fields
|
||||||
|
self.write_field_index(field.hir_id, i, Vec::new());
|
||||||
|
|
||||||
// We don't look at stability attributes on
|
// We don't look at stability attributes on
|
||||||
// struct-like enums (yet...), but it's definitely not
|
// struct-like enums (yet...), but it's definitely not
|
||||||
|
@ -2367,24 +2368,39 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
let body_hir_id = self.tcx.local_def_id_to_hir_id(self.body_id);
|
let body_hir_id = self.tcx.local_def_id_to_hir_id(self.body_id);
|
||||||
let (ident, def_scope) =
|
let (ident, def_scope) =
|
||||||
self.tcx.adjust_ident_and_get_scope(field, base_def.did(), body_hir_id);
|
self.tcx.adjust_ident_and_get_scope(field, base_def.did(), body_hir_id);
|
||||||
let fields = &base_def.non_enum_variant().fields;
|
let mut adt_def = *base_def;
|
||||||
if let Some((index, field)) = fields
|
let mut last_ty = None;
|
||||||
.iter_enumerated()
|
let mut nested_fields = Vec::new();
|
||||||
.find(|(_, f)| f.ident(self.tcx).normalize_to_macros_2_0() == ident)
|
let mut index = None;
|
||||||
{
|
while let Some(idx) = self.tcx.find_field((adt_def.did(), ident)) {
|
||||||
|
let &mut first_idx = index.get_or_insert(idx);
|
||||||
|
let field = &adt_def.non_enum_variant().fields[idx];
|
||||||
let field_ty = self.field_ty(expr.span, field, args);
|
let field_ty = self.field_ty(expr.span, field, args);
|
||||||
// Save the index of all fields regardless of their visibility in case
|
if let Some(ty) = last_ty {
|
||||||
// of error recovery.
|
nested_fields.push((ty, idx));
|
||||||
self.write_field_index(expr.hir_id, index);
|
|
||||||
let adjustments = self.adjust_steps(&autoderef);
|
|
||||||
if field.vis.is_accessible_from(def_scope, self.tcx) {
|
|
||||||
self.apply_adjustments(base, adjustments);
|
|
||||||
self.register_predicates(autoderef.into_obligations());
|
|
||||||
|
|
||||||
self.tcx.check_stability(field.did, Some(expr.hir_id), expr.span, None);
|
|
||||||
return field_ty;
|
|
||||||
}
|
}
|
||||||
private_candidate = Some((adjustments, base_def.did()));
|
if field.ident(self.tcx).normalize_to_macros_2_0() == ident {
|
||||||
|
// Save the index of all fields regardless of their visibility in case
|
||||||
|
// of error recovery.
|
||||||
|
self.write_field_index(expr.hir_id, first_idx, nested_fields);
|
||||||
|
let adjustments = self.adjust_steps(&autoderef);
|
||||||
|
if field.vis.is_accessible_from(def_scope, self.tcx) {
|
||||||
|
self.apply_adjustments(base, adjustments);
|
||||||
|
self.register_predicates(autoderef.into_obligations());
|
||||||
|
|
||||||
|
self.tcx.check_stability(
|
||||||
|
field.did,
|
||||||
|
Some(expr.hir_id),
|
||||||
|
expr.span,
|
||||||
|
None,
|
||||||
|
);
|
||||||
|
return field_ty;
|
||||||
|
}
|
||||||
|
private_candidate = Some((adjustments, base_def.did()));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
last_ty = Some(field_ty);
|
||||||
|
adt_def = field_ty.ty_adt_def().expect("expect Adt for unnamed field");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ty::Tuple(tys) => {
|
ty::Tuple(tys) => {
|
||||||
|
@ -2395,7 +2411,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
self.apply_adjustments(base, adjustments);
|
self.apply_adjustments(base, adjustments);
|
||||||
self.register_predicates(autoderef.into_obligations());
|
self.register_predicates(autoderef.into_obligations());
|
||||||
|
|
||||||
self.write_field_index(expr.hir_id, FieldIdx::from_usize(index));
|
self.write_field_index(
|
||||||
|
expr.hir_id,
|
||||||
|
FieldIdx::from_usize(index),
|
||||||
|
Vec::new(),
|
||||||
|
);
|
||||||
return field_ty;
|
return field_ty;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -145,8 +145,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn write_field_index(&self, hir_id: hir::HirId, index: FieldIdx) {
|
pub fn write_field_index(
|
||||||
|
&self,
|
||||||
|
hir_id: hir::HirId,
|
||||||
|
index: FieldIdx,
|
||||||
|
nested_fields: Vec<(Ty<'tcx>, FieldIdx)>,
|
||||||
|
) {
|
||||||
self.typeck_results.borrow_mut().field_indices_mut().insert(hir_id, index);
|
self.typeck_results.borrow_mut().field_indices_mut().insert(hir_id, index);
|
||||||
|
if !nested_fields.is_empty() {
|
||||||
|
self.typeck_results.borrow_mut().nested_fields_mut().insert(hir_id, nested_fields);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[instrument(level = "debug", skip(self))]
|
#[instrument(level = "debug", skip(self))]
|
||||||
|
|
|
@ -1389,7 +1389,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
field_map
|
field_map
|
||||||
.get(&ident)
|
.get(&ident)
|
||||||
.map(|(i, f)| {
|
.map(|(i, f)| {
|
||||||
self.write_field_index(field.hir_id, *i);
|
// FIXME: handle nested fields
|
||||||
|
self.write_field_index(field.hir_id, *i, Vec::new());
|
||||||
self.tcx.check_stability(f.did, Some(pat.hir_id), span, None);
|
self.tcx.check_stability(f.did, Some(pat.hir_id), span, None);
|
||||||
self.field_ty(span, f, args)
|
self.field_ty(span, f, args)
|
||||||
})
|
})
|
||||||
|
|
|
@ -596,6 +596,11 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
|
||||||
{
|
{
|
||||||
self.typeck_results.field_indices_mut().insert(hir_id, index);
|
self.typeck_results.field_indices_mut().insert(hir_id, index);
|
||||||
}
|
}
|
||||||
|
if let Some(nested_fields) =
|
||||||
|
self.fcx.typeck_results.borrow_mut().nested_fields_mut().remove(hir_id)
|
||||||
|
{
|
||||||
|
self.typeck_results.nested_fields_mut().insert(hir_id, nested_fields);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[instrument(skip(self, span), level = "debug")]
|
#[instrument(skip(self, span), level = "debug")]
|
||||||
|
|
|
@ -238,6 +238,7 @@ trivial! {
|
||||||
Option<rustc_span::def_id::DefId>,
|
Option<rustc_span::def_id::DefId>,
|
||||||
Option<rustc_span::def_id::LocalDefId>,
|
Option<rustc_span::def_id::LocalDefId>,
|
||||||
Option<rustc_span::Span>,
|
Option<rustc_span::Span>,
|
||||||
|
Option<rustc_target::abi::FieldIdx>,
|
||||||
Option<rustc_target::spec::PanicStrategy>,
|
Option<rustc_target::spec::PanicStrategy>,
|
||||||
Option<usize>,
|
Option<usize>,
|
||||||
Result<(), rustc_errors::ErrorGuaranteed>,
|
Result<(), rustc_errors::ErrorGuaranteed>,
|
||||||
|
|
|
@ -2217,6 +2217,10 @@ rustc_queries! {
|
||||||
desc { "whether the item should be made inlinable across crates" }
|
desc { "whether the item should be made inlinable across crates" }
|
||||||
separate_provide_extern
|
separate_provide_extern
|
||||||
}
|
}
|
||||||
|
|
||||||
|
query find_field((def_id, ident): (DefId, rustc_span::symbol::Ident)) -> Option<rustc_target::abi::FieldIdx> {
|
||||||
|
desc { |tcx| "find the index of maybe nested field `{ident}` in `{}`", tcx.def_path_str(def_id) }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
rustc_query_append! { define_callbacks! }
|
rustc_query_append! { define_callbacks! }
|
||||||
|
|
|
@ -44,6 +44,12 @@ pub struct TypeckResults<'tcx> {
|
||||||
/// belongs, but it may not exist if it's a tuple field (`tuple.0`).
|
/// belongs, but it may not exist if it's a tuple field (`tuple.0`).
|
||||||
field_indices: ItemLocalMap<FieldIdx>,
|
field_indices: ItemLocalMap<FieldIdx>,
|
||||||
|
|
||||||
|
/// Resolved types and indices for the nested fields' accesses of `obj.field` (expanded
|
||||||
|
/// to `obj._(1)._(2).field` in THIR). This map only stores the intermediate type
|
||||||
|
/// of `obj._(1)` and index of `_(1)._(2)`, and the type of `_(1)._(2)`, and the index of
|
||||||
|
/// `_(2).field`.
|
||||||
|
nested_fields: ItemLocalMap<Vec<(Ty<'tcx>, FieldIdx)>>,
|
||||||
|
|
||||||
/// Stores the types for various nodes in the AST. Note that this table
|
/// Stores the types for various nodes in the AST. Note that this table
|
||||||
/// is not guaranteed to be populated outside inference. See
|
/// is not guaranteed to be populated outside inference. See
|
||||||
/// typeck::check::fn_ctxt for details.
|
/// typeck::check::fn_ctxt for details.
|
||||||
|
@ -214,6 +220,7 @@ impl<'tcx> TypeckResults<'tcx> {
|
||||||
hir_owner,
|
hir_owner,
|
||||||
type_dependent_defs: Default::default(),
|
type_dependent_defs: Default::default(),
|
||||||
field_indices: Default::default(),
|
field_indices: Default::default(),
|
||||||
|
nested_fields: Default::default(),
|
||||||
user_provided_types: Default::default(),
|
user_provided_types: Default::default(),
|
||||||
user_provided_sigs: Default::default(),
|
user_provided_sigs: Default::default(),
|
||||||
node_types: Default::default(),
|
node_types: Default::default(),
|
||||||
|
@ -285,6 +292,18 @@ impl<'tcx> TypeckResults<'tcx> {
|
||||||
self.field_indices().get(id).cloned()
|
self.field_indices().get(id).cloned()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn nested_fields(&self) -> LocalTableInContext<'_, Vec<(Ty<'tcx>, FieldIdx)>> {
|
||||||
|
LocalTableInContext { hir_owner: self.hir_owner, data: &self.nested_fields }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn nested_fields_mut(&mut self) -> LocalTableInContextMut<'_, Vec<(Ty<'tcx>, FieldIdx)>> {
|
||||||
|
LocalTableInContextMut { hir_owner: self.hir_owner, data: &mut self.nested_fields }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn nested_field_tys_and_indices(&self, id: hir::HirId) -> &[(Ty<'tcx>, FieldIdx)] {
|
||||||
|
self.nested_fields().get(id).map_or(&[], Vec::as_slice)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn user_provided_types(&self) -> LocalTableInContext<'_, CanonicalUserType<'tcx>> {
|
pub fn user_provided_types(&self) -> LocalTableInContext<'_, CanonicalUserType<'tcx>> {
|
||||||
LocalTableInContext { hir_owner: self.hir_owner, data: &self.user_provided_types }
|
LocalTableInContext { hir_owner: self.hir_owner, data: &self.user_provided_types }
|
||||||
}
|
}
|
||||||
|
|
|
@ -734,11 +734,21 @@ impl<'tcx> Cx<'tcx> {
|
||||||
});
|
});
|
||||||
ExprKind::Loop { body }
|
ExprKind::Loop { body }
|
||||||
}
|
}
|
||||||
hir::ExprKind::Field(source, ..) => ExprKind::Field {
|
hir::ExprKind::Field(source, ..) => {
|
||||||
lhs: self.mirror_expr(source),
|
let mut kind = ExprKind::Field {
|
||||||
variant_index: FIRST_VARIANT,
|
lhs: self.mirror_expr(source),
|
||||||
name: self.typeck_results.field_index(expr.hir_id),
|
variant_index: FIRST_VARIANT,
|
||||||
},
|
name: self.typeck_results.field_index(expr.hir_id),
|
||||||
|
};
|
||||||
|
let nested_field_tys_and_indices =
|
||||||
|
self.typeck_results.nested_field_tys_and_indices(expr.hir_id);
|
||||||
|
for &(ty, idx) in nested_field_tys_and_indices {
|
||||||
|
let expr = Expr { temp_lifetime, ty, span: source.span, kind };
|
||||||
|
let lhs = self.thir.exprs.push(expr);
|
||||||
|
kind = ExprKind::Field { lhs, variant_index: FIRST_VARIANT, name: idx };
|
||||||
|
}
|
||||||
|
kind
|
||||||
|
}
|
||||||
hir::ExprKind::Cast(source, cast_ty) => {
|
hir::ExprKind::Cast(source, cast_ty) => {
|
||||||
// Check for a user-given type annotation on this `cast`
|
// Check for a user-given type annotation on this `cast`
|
||||||
let user_provided_types = self.typeck_results.user_provided_types();
|
let user_provided_types = self.typeck_results.user_provided_types();
|
||||||
|
|
|
@ -313,18 +313,17 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn insert_field_def_ids(&mut self, def_id: LocalDefId, vdata: &ast::VariantData) {
|
fn insert_field_def_ids(&mut self, def_id: LocalDefId, fields: &[ast::FieldDef]) {
|
||||||
if vdata.fields().iter().any(|field| field.is_placeholder) {
|
if fields.iter().any(|field| field.is_placeholder) {
|
||||||
// The fields are not expanded yet.
|
// The fields are not expanded yet.
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let def_ids = vdata.fields().iter().map(|field| self.r.local_def_id(field.id).to_def_id());
|
let def_ids = fields.iter().map(|field| self.r.local_def_id(field.id).to_def_id());
|
||||||
self.r.field_def_ids.insert(def_id, self.r.tcx.arena.alloc_from_iter(def_ids));
|
self.r.field_def_ids.insert(def_id, self.r.tcx.arena.alloc_from_iter(def_ids));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn insert_field_visibilities_local(&mut self, def_id: DefId, vdata: &ast::VariantData) {
|
fn insert_field_visibilities_local(&mut self, def_id: DefId, fields: &[ast::FieldDef]) {
|
||||||
let field_vis = vdata
|
let field_vis = fields
|
||||||
.fields()
|
|
||||||
.iter()
|
.iter()
|
||||||
.map(|field| field.vis.span.until(field.ident.map_or(field.ty.span, |i| i.span)))
|
.map(|field| field.vis.span.until(field.ident.map_or(field.ty.span, |i| i.span)))
|
||||||
.collect();
|
.collect();
|
||||||
|
@ -629,6 +628,50 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn build_reduced_graph_for_fields(
|
||||||
|
&mut self,
|
||||||
|
fields: &[ast::FieldDef],
|
||||||
|
ident: Ident,
|
||||||
|
def_id: LocalDefId,
|
||||||
|
adt_res: Res,
|
||||||
|
adt_vis: ty::Visibility,
|
||||||
|
adt_span: Span,
|
||||||
|
) {
|
||||||
|
let parent_scope = &self.parent_scope;
|
||||||
|
let parent = parent_scope.module;
|
||||||
|
let expansion = parent_scope.expansion;
|
||||||
|
|
||||||
|
// Define a name in the type namespace if it is not anonymous.
|
||||||
|
self.r.define(parent, ident, TypeNS, (adt_res, adt_vis, adt_span, expansion));
|
||||||
|
self.r.feed_visibility(def_id, adt_vis);
|
||||||
|
|
||||||
|
// Record field names for error reporting.
|
||||||
|
self.insert_field_def_ids(def_id, fields);
|
||||||
|
self.insert_field_visibilities_local(def_id.to_def_id(), fields);
|
||||||
|
|
||||||
|
for field in fields {
|
||||||
|
match &field.ty.kind {
|
||||||
|
ast::TyKind::AnonStruct(id, nested_fields)
|
||||||
|
| ast::TyKind::AnonUnion(id, nested_fields) => {
|
||||||
|
let local_def_id = self.r.local_def_id(*id);
|
||||||
|
let def_id = local_def_id.to_def_id();
|
||||||
|
let def_kind = self.r.tcx.def_kind(local_def_id);
|
||||||
|
let res = Res::Def(def_kind, def_id);
|
||||||
|
self.build_reduced_graph_for_fields(
|
||||||
|
&nested_fields,
|
||||||
|
Ident::empty(),
|
||||||
|
local_def_id,
|
||||||
|
res,
|
||||||
|
// Anonymous adts inherit visibility from their parent adts.
|
||||||
|
adt_vis,
|
||||||
|
field.span,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Constructs the reduced graph for one item.
|
/// Constructs the reduced graph for one item.
|
||||||
fn build_reduced_graph_for_item(&mut self, item: &'b Item) {
|
fn build_reduced_graph_for_item(&mut self, item: &'b Item) {
|
||||||
let parent_scope = &self.parent_scope;
|
let parent_scope = &self.parent_scope;
|
||||||
|
@ -716,12 +759,14 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> {
|
||||||
|
|
||||||
// These items live in both the type and value namespaces.
|
// These items live in both the type and value namespaces.
|
||||||
ItemKind::Struct(ref vdata, _) => {
|
ItemKind::Struct(ref vdata, _) => {
|
||||||
// Define a name in the type namespace.
|
self.build_reduced_graph_for_fields(
|
||||||
self.r.define(parent, ident, TypeNS, (res, vis, sp, expansion));
|
vdata.fields(),
|
||||||
|
ident,
|
||||||
// Record field names for error reporting.
|
local_def_id,
|
||||||
self.insert_field_def_ids(local_def_id, vdata);
|
res,
|
||||||
self.insert_field_visibilities_local(def_id, vdata);
|
vis,
|
||||||
|
sp,
|
||||||
|
);
|
||||||
|
|
||||||
// If this is a tuple or unit struct, define a name
|
// If this is a tuple or unit struct, define a name
|
||||||
// in the value namespace as well.
|
// in the value namespace as well.
|
||||||
|
@ -755,7 +800,7 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> {
|
||||||
self.r.define(parent, ident, ValueNS, (ctor_res, ctor_vis, sp, expansion));
|
self.r.define(parent, ident, ValueNS, (ctor_res, ctor_vis, sp, expansion));
|
||||||
self.r.feed_visibility(ctor_def_id, ctor_vis);
|
self.r.feed_visibility(ctor_def_id, ctor_vis);
|
||||||
// We need the field visibility spans also for the constructor for E0603.
|
// We need the field visibility spans also for the constructor for E0603.
|
||||||
self.insert_field_visibilities_local(ctor_def_id.to_def_id(), vdata);
|
self.insert_field_visibilities_local(ctor_def_id.to_def_id(), vdata.fields());
|
||||||
|
|
||||||
self.r
|
self.r
|
||||||
.struct_constructors
|
.struct_constructors
|
||||||
|
@ -764,11 +809,14 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
ItemKind::Union(ref vdata, _) => {
|
ItemKind::Union(ref vdata, _) => {
|
||||||
self.r.define(parent, ident, TypeNS, (res, vis, sp, expansion));
|
self.build_reduced_graph_for_fields(
|
||||||
|
vdata.fields(),
|
||||||
// Record field names for error reporting.
|
ident,
|
||||||
self.insert_field_def_ids(local_def_id, vdata);
|
local_def_id,
|
||||||
self.insert_field_visibilities_local(def_id, vdata);
|
res,
|
||||||
|
vis,
|
||||||
|
sp,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// These items do not add names to modules.
|
// These items do not add names to modules.
|
||||||
|
@ -1461,8 +1509,8 @@ impl<'a, 'b, 'tcx> Visitor<'b> for BuildReducedGraphVisitor<'a, 'b, 'tcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Record field names for error reporting.
|
// Record field names for error reporting.
|
||||||
self.insert_field_def_ids(def_id, &variant.data);
|
self.insert_field_def_ids(def_id, variant.data.fields());
|
||||||
self.insert_field_visibilities_local(def_id.to_def_id(), &variant.data);
|
self.insert_field_visibilities_local(def_id.to_def_id(), variant.data.fields());
|
||||||
|
|
||||||
visit::walk_variant(self, variant);
|
visit::walk_variant(self, variant);
|
||||||
}
|
}
|
||||||
|
|
|
@ -324,8 +324,21 @@ impl<'a, 'b, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'b, 'tcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_ty(&mut self, ty: &'a Ty) {
|
fn visit_ty(&mut self, ty: &'a Ty) {
|
||||||
match ty.kind {
|
match &ty.kind {
|
||||||
TyKind::MacCall(..) => self.visit_macro_invoc(ty.id),
|
TyKind::MacCall(..) => self.visit_macro_invoc(ty.id),
|
||||||
|
TyKind::AnonStruct(node_id, fields) | TyKind::AnonUnion(node_id, fields) => {
|
||||||
|
let def_kind = match &ty.kind {
|
||||||
|
TyKind::AnonStruct(..) => DefKind::Struct,
|
||||||
|
TyKind::AnonUnion(..) => DefKind::Union,
|
||||||
|
_ => unreachable!(),
|
||||||
|
};
|
||||||
|
let def_id = self.create_def(*node_id, kw::Empty, def_kind, ty.span);
|
||||||
|
self.with_parent(def_id, |this| {
|
||||||
|
for f in fields {
|
||||||
|
this.visit_field_def(f);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
_ => visit::walk_ty(self, ty),
|
_ => visit::walk_ty(self, ty),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1016,6 +1016,8 @@ pub struct Resolver<'a, 'tcx> {
|
||||||
binding_parent_modules: FxHashMap<NameBinding<'a>, Module<'a>>,
|
binding_parent_modules: FxHashMap<NameBinding<'a>, Module<'a>>,
|
||||||
|
|
||||||
underscore_disambiguator: u32,
|
underscore_disambiguator: u32,
|
||||||
|
/// Disambiguator for anonymous adts.
|
||||||
|
empty_disambiguator: u32,
|
||||||
|
|
||||||
/// Maps glob imports to the names of items actually imported.
|
/// Maps glob imports to the names of items actually imported.
|
||||||
glob_map: FxHashMap<LocalDefId, FxHashSet<Symbol>>,
|
glob_map: FxHashMap<LocalDefId, FxHashSet<Symbol>>,
|
||||||
|
@ -1367,6 +1369,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
||||||
module_children: Default::default(),
|
module_children: Default::default(),
|
||||||
trait_map: NodeMap::default(),
|
trait_map: NodeMap::default(),
|
||||||
underscore_disambiguator: 0,
|
underscore_disambiguator: 0,
|
||||||
|
empty_disambiguator: 0,
|
||||||
empty_module,
|
empty_module,
|
||||||
module_map,
|
module_map,
|
||||||
block_map: Default::default(),
|
block_map: Default::default(),
|
||||||
|
@ -1734,6 +1737,9 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
||||||
let disambiguator = if ident.name == kw::Underscore {
|
let disambiguator = if ident.name == kw::Underscore {
|
||||||
self.underscore_disambiguator += 1;
|
self.underscore_disambiguator += 1;
|
||||||
self.underscore_disambiguator
|
self.underscore_disambiguator
|
||||||
|
} else if ident.name == kw::Empty {
|
||||||
|
self.empty_disambiguator += 1;
|
||||||
|
self.empty_disambiguator
|
||||||
} else {
|
} else {
|
||||||
0
|
0
|
||||||
};
|
};
|
||||||
|
|
|
@ -183,7 +183,7 @@ pub(in crate::solve) fn instantiate_constituent_tys_for_copy_clone_trait<'tcx>(
|
||||||
|
|
||||||
// Check for anonymous adts.
|
// Check for anonymous adts.
|
||||||
ty::Adt(adt, generics) if adt.is_anonymous() => {
|
ty::Adt(adt, generics) if adt.is_anonymous() => {
|
||||||
Ok(adt.all_fields().map(|f| f.ty(ecx.tcx(), generics)).collect())
|
Ok(adt.non_enum_variant().fields.iter().map(|f| f.ty(ecx.tcx(), generics)).collect())
|
||||||
}
|
}
|
||||||
|
|
||||||
ty::Dynamic(..)
|
ty::Dynamic(..)
|
||||||
|
|
|
@ -2212,14 +2212,14 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
|
||||||
|
|
||||||
// FIXME(async_closures): These are never clone, for now.
|
// FIXME(async_closures): These are never clone, for now.
|
||||||
ty::CoroutineClosure(_, _) => None,
|
ty::CoroutineClosure(_, _) => None,
|
||||||
// `Copy` and `Clone` are automatically impelemented for an anonymous adt
|
// `Copy` and `Clone` are automatically implemented for an anonymous adt
|
||||||
// if all of its fields are `Copy` and `Clone`
|
// if all of its fields are `Copy` and `Clone`
|
||||||
ty::Adt(adt, args) if adt.is_anonymous() => {
|
ty::Adt(adt, args) if adt.is_anonymous() => {
|
||||||
// (*) binder moved here
|
// (*) binder moved here
|
||||||
Where(
|
Where(
|
||||||
obligation
|
obligation
|
||||||
.predicate
|
.predicate
|
||||||
.rebind(adt.all_fields().map(|f| f.ty(self.tcx(), args)).collect()),
|
.rebind(adt.non_enum_variant().fields.iter().map(|f| f.ty(self.tcx(), args)).collect()),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,61 @@
|
||||||
|
// MIR for `bar` after SimplifyCfg-initial
|
||||||
|
|
||||||
|
fn bar(_1: Bar) -> () {
|
||||||
|
debug bar => _1;
|
||||||
|
let mut _0: ();
|
||||||
|
let _2: ();
|
||||||
|
let mut _3: u8;
|
||||||
|
let _4: ();
|
||||||
|
let mut _5: i8;
|
||||||
|
let _6: ();
|
||||||
|
let mut _7: bool;
|
||||||
|
let _8: ();
|
||||||
|
let mut _9: [u8; 1];
|
||||||
|
scope 1 {
|
||||||
|
}
|
||||||
|
|
||||||
|
bb0: {
|
||||||
|
StorageLive(_2);
|
||||||
|
StorageLive(_3);
|
||||||
|
_3 = (_1.0: u8);
|
||||||
|
_2 = access::<u8>(move _3) -> [return: bb1, unwind: bb5];
|
||||||
|
}
|
||||||
|
|
||||||
|
bb1: {
|
||||||
|
StorageDead(_3);
|
||||||
|
StorageDead(_2);
|
||||||
|
StorageLive(_4);
|
||||||
|
StorageLive(_5);
|
||||||
|
_5 = ((_1.1: Bar::_::{anon_adt#0}).0: i8);
|
||||||
|
_4 = access::<i8>(move _5) -> [return: bb2, unwind: bb5];
|
||||||
|
}
|
||||||
|
|
||||||
|
bb2: {
|
||||||
|
StorageDead(_5);
|
||||||
|
StorageDead(_4);
|
||||||
|
StorageLive(_6);
|
||||||
|
StorageLive(_7);
|
||||||
|
_7 = ((_1.1: Bar::_::{anon_adt#0}).1: bool);
|
||||||
|
_6 = access::<bool>(move _7) -> [return: bb3, unwind: bb5];
|
||||||
|
}
|
||||||
|
|
||||||
|
bb3: {
|
||||||
|
StorageDead(_7);
|
||||||
|
StorageDead(_6);
|
||||||
|
StorageLive(_8);
|
||||||
|
StorageLive(_9);
|
||||||
|
_9 = (((_1.2: Bar::_::{anon_adt#0}).0: Bar::_::{anon_adt#0}::_::{anon_adt#0}).0: [u8; 1]);
|
||||||
|
_8 = access::<[u8; 1]>(move _9) -> [return: bb4, unwind: bb5];
|
||||||
|
}
|
||||||
|
|
||||||
|
bb4: {
|
||||||
|
StorageDead(_9);
|
||||||
|
StorageDead(_8);
|
||||||
|
_0 = const ();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
bb5 (cleanup): {
|
||||||
|
resume;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,59 @@
|
||||||
|
// MIR for `foo` after SimplifyCfg-initial
|
||||||
|
|
||||||
|
fn foo(_1: Foo) -> () {
|
||||||
|
debug foo => _1;
|
||||||
|
let mut _0: ();
|
||||||
|
let _2: ();
|
||||||
|
let mut _3: u8;
|
||||||
|
let _4: ();
|
||||||
|
let mut _5: i8;
|
||||||
|
let _6: ();
|
||||||
|
let mut _7: bool;
|
||||||
|
let _8: ();
|
||||||
|
let mut _9: [u8; 1];
|
||||||
|
|
||||||
|
bb0: {
|
||||||
|
StorageLive(_2);
|
||||||
|
StorageLive(_3);
|
||||||
|
_3 = (_1.0: u8);
|
||||||
|
_2 = access::<u8>(move _3) -> [return: bb1, unwind: bb5];
|
||||||
|
}
|
||||||
|
|
||||||
|
bb1: {
|
||||||
|
StorageDead(_3);
|
||||||
|
StorageDead(_2);
|
||||||
|
StorageLive(_4);
|
||||||
|
StorageLive(_5);
|
||||||
|
_5 = ((_1.1: Foo::_::{anon_adt#0}).0: i8);
|
||||||
|
_4 = access::<i8>(move _5) -> [return: bb2, unwind: bb5];
|
||||||
|
}
|
||||||
|
|
||||||
|
bb2: {
|
||||||
|
StorageDead(_5);
|
||||||
|
StorageDead(_4);
|
||||||
|
StorageLive(_6);
|
||||||
|
StorageLive(_7);
|
||||||
|
_7 = ((_1.1: Foo::_::{anon_adt#0}).1: bool);
|
||||||
|
_6 = access::<bool>(move _7) -> [return: bb3, unwind: bb5];
|
||||||
|
}
|
||||||
|
|
||||||
|
bb3: {
|
||||||
|
StorageDead(_7);
|
||||||
|
StorageDead(_6);
|
||||||
|
StorageLive(_8);
|
||||||
|
StorageLive(_9);
|
||||||
|
_9 = (((_1.2: Foo::_::{anon_adt#0}).0: Foo::_::{anon_adt#0}::_::{anon_adt#0}).0: [u8; 1]);
|
||||||
|
_8 = access::<[u8; 1]>(move _9) -> [return: bb4, unwind: bb5];
|
||||||
|
}
|
||||||
|
|
||||||
|
bb4: {
|
||||||
|
StorageDead(_9);
|
||||||
|
StorageDead(_8);
|
||||||
|
_0 = const ();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
bb5 (cleanup): {
|
||||||
|
resume;
|
||||||
|
}
|
||||||
|
}
|
56
tests/mir-opt/unnamed-fields/field_access.rs
Normal file
56
tests/mir-opt/unnamed-fields/field_access.rs
Normal file
|
@ -0,0 +1,56 @@
|
||||||
|
// skip-filecheck
|
||||||
|
// EMIT_MIR field_access.foo.SimplifyCfg-initial.after.mir
|
||||||
|
// EMIT_MIR field_access.bar.SimplifyCfg-initial.after.mir
|
||||||
|
|
||||||
|
#![allow(incomplete_features)]
|
||||||
|
#![feature(unnamed_fields)]
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
struct Foo {
|
||||||
|
a: u8,
|
||||||
|
_: struct {
|
||||||
|
b: i8,
|
||||||
|
c: bool,
|
||||||
|
},
|
||||||
|
_: struct {
|
||||||
|
_: struct {
|
||||||
|
d: [u8; 1],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
union Bar {
|
||||||
|
a: u8,
|
||||||
|
_: union {
|
||||||
|
b: i8,
|
||||||
|
c: bool,
|
||||||
|
},
|
||||||
|
_: union {
|
||||||
|
_: union {
|
||||||
|
d: [u8; 1],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fn access<T>(_: T) {}
|
||||||
|
|
||||||
|
fn foo(foo: Foo) {
|
||||||
|
access(foo.a);
|
||||||
|
access(foo.b);
|
||||||
|
access(foo.c);
|
||||||
|
access(foo.d);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn bar(bar: Bar) {
|
||||||
|
unsafe {
|
||||||
|
access(bar.a);
|
||||||
|
access(bar.b);
|
||||||
|
access(bar.c);
|
||||||
|
access(bar.d);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fn main() {}
|
Loading…
Add table
Add a link
Reference in a new issue