Auto merge of #115367 - frank-king:feature/unnamed-fields-hir, r=davidtwco
Lowering unnamed fields and anonymous adt This implements #49804. Goals: - [x] lowering anonymous ADTs from AST to HIR - [x] generating definitions of anonymous ADTs - [x] uniqueness check of the unnamed fields - [x] field projection of anonymous ADTs - [x] `#[repr(C)]` check of the anonymous ADTs Non-Goals (will be in the next PRs) - capturing generic params for the anonymous ADTs from the parent ADT - pattern matching of anonymous ADTs - structural expressions of anonymous ADTs - rustdoc support of anonymous ADTs
This commit is contained in:
commit
bdc15928c8
60 changed files with 3274 additions and 260 deletions
|
@ -2107,9 +2107,9 @@ pub enum TyKind {
|
||||||
/// A tuple (`(A, B, C, D,...)`).
|
/// A tuple (`(A, B, C, D,...)`).
|
||||||
Tup(ThinVec<P<Ty>>),
|
Tup(ThinVec<P<Ty>>),
|
||||||
/// An anonymous struct type i.e. `struct { foo: Type }`
|
/// An anonymous struct type i.e. `struct { foo: Type }`
|
||||||
AnonStruct(ThinVec<FieldDef>),
|
AnonStruct(NodeId, ThinVec<FieldDef>),
|
||||||
/// An anonymous union type i.e. `union { bar: Type }`
|
/// An anonymous union type i.e. `union { bar: Type }`
|
||||||
AnonUnion(ThinVec<FieldDef>),
|
AnonUnion(NodeId, ThinVec<FieldDef>),
|
||||||
/// A path (`module::module::...::Type`), optionally
|
/// A path (`module::module::...::Type`), optionally
|
||||||
/// "qualified", e.g., `<Vec<T> as SomeTrait>::SomeType`.
|
/// "qualified", e.g., `<Vec<T> as SomeTrait>::SomeType`.
|
||||||
///
|
///
|
||||||
|
@ -2161,6 +2161,10 @@ impl TyKind {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn is_anon_adt(&self) -> bool {
|
||||||
|
matches!(self, TyKind::AnonStruct(..) | TyKind::AnonUnion(..))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Syntax used to declare a trait object.
|
/// Syntax used to declare a trait object.
|
||||||
|
|
|
@ -514,7 +514,8 @@ pub fn noop_visit_ty<T: MutVisitor>(ty: &mut P<Ty>, vis: &mut T) {
|
||||||
visit_vec(bounds, |bound| vis.visit_param_bound(bound));
|
visit_vec(bounds, |bound| vis.visit_param_bound(bound));
|
||||||
}
|
}
|
||||||
TyKind::MacCall(mac) => vis.visit_mac_call(mac),
|
TyKind::MacCall(mac) => vis.visit_mac_call(mac),
|
||||||
TyKind::AnonStruct(fields) | TyKind::AnonUnion(fields) => {
|
TyKind::AnonStruct(id, fields) | TyKind::AnonUnion(id, fields) => {
|
||||||
|
vis.visit_id(id);
|
||||||
fields.flat_map_in_place(|field| vis.flat_map_field_def(field));
|
fields.flat_map_in_place(|field| vis.flat_map_field_def(field));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -450,7 +450,7 @@ pub fn walk_ty<'a, V: Visitor<'a>>(visitor: &mut V, typ: &'a Ty) {
|
||||||
TyKind::Infer | TyKind::ImplicitSelf | TyKind::Err => {}
|
TyKind::Infer | TyKind::ImplicitSelf | TyKind::Err => {}
|
||||||
TyKind::MacCall(mac) => visitor.visit_mac_call(mac),
|
TyKind::MacCall(mac) => visitor.visit_mac_call(mac),
|
||||||
TyKind::Never | TyKind::CVarArgs => {}
|
TyKind::Never | TyKind::CVarArgs => {}
|
||||||
TyKind::AnonStruct(ref fields, ..) | TyKind::AnonUnion(ref fields, ..) => {
|
TyKind::AnonStruct(_, ref fields) | TyKind::AnonUnion(_, ref fields) => {
|
||||||
walk_list!(visitor, visit_field_def, fields)
|
walk_list!(visitor, visit_field_def, fields)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -720,7 +720,10 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn lower_field_def(&mut self, (index, f): (usize, &FieldDef)) -> hir::FieldDef<'hir> {
|
pub(super) fn lower_field_def(
|
||||||
|
&mut self,
|
||||||
|
(index, f): (usize, &FieldDef),
|
||||||
|
) -> hir::FieldDef<'hir> {
|
||||||
let ty = if let TyKind::Path(qself, path) = &f.ty.kind {
|
let ty = if let TyKind::Path(qself, path) = &f.ty.kind {
|
||||||
let t = self.lower_path_ty(
|
let t = self.lower_path_ty(
|
||||||
&f.ty,
|
&f.ty,
|
||||||
|
|
|
@ -1288,17 +1288,44 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||||
TyKind::Err => {
|
TyKind::Err => {
|
||||||
hir::TyKind::Err(self.dcx().span_delayed_bug(t.span, "TyKind::Err lowered"))
|
hir::TyKind::Err(self.dcx().span_delayed_bug(t.span, "TyKind::Err lowered"))
|
||||||
}
|
}
|
||||||
// FIXME(unnamed_fields): IMPLEMENTATION IN PROGRESS
|
// Lower the anonymous structs or unions in a nested lowering context.
|
||||||
#[allow(rustc::untranslatable_diagnostic)]
|
//
|
||||||
#[allow(rustc::diagnostic_outside_of_impl)]
|
// ```
|
||||||
TyKind::AnonStruct(ref _fields) => {
|
// struct Foo {
|
||||||
hir::TyKind::Err(self.dcx().span_err(t.span, "anonymous structs are unimplemented"))
|
// _: union {
|
||||||
}
|
// // ^__________________ <-- within the nested lowering context,
|
||||||
// FIXME(unnamed_fields): IMPLEMENTATION IN PROGRESS
|
// /* fields */ // | we lower all fields defined into an
|
||||||
#[allow(rustc::untranslatable_diagnostic)]
|
// } // | owner node of struct or union item
|
||||||
#[allow(rustc::diagnostic_outside_of_impl)]
|
// // ^_____________________|
|
||||||
TyKind::AnonUnion(ref _fields) => {
|
// }
|
||||||
hir::TyKind::Err(self.dcx().span_err(t.span, "anonymous unions are unimplemented"))
|
// ```
|
||||||
|
TyKind::AnonStruct(node_id, fields) | TyKind::AnonUnion(node_id, fields) => {
|
||||||
|
// Here its `def_id` is created in `build_reduced_graph`.
|
||||||
|
let def_id = self.local_def_id(*node_id);
|
||||||
|
debug!(?def_id);
|
||||||
|
let owner_id = hir::OwnerId { def_id };
|
||||||
|
self.with_hir_id_owner(*node_id, |this| {
|
||||||
|
let fields = this.arena.alloc_from_iter(
|
||||||
|
fields.iter().enumerate().map(|f| this.lower_field_def(f)),
|
||||||
|
);
|
||||||
|
let span = t.span;
|
||||||
|
let variant_data = hir::VariantData::Struct { fields, recovered: false };
|
||||||
|
// FIXME: capture the generics from the outer adt.
|
||||||
|
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 {
|
||||||
|
ident: Ident::new(kw::Empty, span),
|
||||||
|
owner_id,
|
||||||
|
kind,
|
||||||
|
span: this.lower_span(span),
|
||||||
|
vis_span: this.lower_span(span.shrink_to_lo()),
|
||||||
|
}))
|
||||||
|
});
|
||||||
|
hir::TyKind::AnonAdt(hir::ItemId { owner_id })
|
||||||
}
|
}
|
||||||
TyKind::Slice(ty) => hir::TyKind::Slice(self.lower_ty(ty, itctx)),
|
TyKind::Slice(ty) => hir::TyKind::Slice(self.lower_ty(ty, itctx)),
|
||||||
TyKind::Ptr(mt) => hir::TyKind::Ptr(self.lower_mt(mt, itctx)),
|
TyKind::Ptr(mt) => hir::TyKind::Ptr(self.lower_mt(mt, itctx)),
|
||||||
|
|
|
@ -219,8 +219,8 @@ impl<'a> AstValidator<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
TyKind::AnonStruct(ref fields, ..) | TyKind::AnonUnion(ref fields, ..) => {
|
TyKind::AnonStruct(_, ref fields) | TyKind::AnonUnion(_, ref fields) => {
|
||||||
walk_list!(self, visit_field_def, fields)
|
walk_list!(self, visit_struct_field_def, fields)
|
||||||
}
|
}
|
||||||
_ => visit::walk_ty(self, t),
|
_ => visit::walk_ty(self, t),
|
||||||
}
|
}
|
||||||
|
|
|
@ -1003,11 +1003,11 @@ impl<'a> State<'a> {
|
||||||
}
|
}
|
||||||
self.pclose();
|
self.pclose();
|
||||||
}
|
}
|
||||||
ast::TyKind::AnonStruct(fields) => {
|
ast::TyKind::AnonStruct(_, fields) => {
|
||||||
self.head("struct");
|
self.head("struct");
|
||||||
self.print_record_struct_body(fields, ty.span);
|
self.print_record_struct_body(fields, ty.span);
|
||||||
}
|
}
|
||||||
ast::TyKind::AnonUnion(fields) => {
|
ast::TyKind::AnonUnion(_, fields) => {
|
||||||
self.head("union");
|
self.head("union");
|
||||||
self.print_record_struct_body(fields, ty.span);
|
self.print_record_struct_body(fields, ty.span);
|
||||||
}
|
}
|
||||||
|
|
|
@ -110,7 +110,9 @@ fn cs_clone_simple(
|
||||||
&& !seen_type_names.insert(name)
|
&& !seen_type_names.insert(name)
|
||||||
{
|
{
|
||||||
// Already produced an assertion for this type.
|
// Already produced an assertion for this type.
|
||||||
} else {
|
// Anonymous structs or unions must be eliminated as they cannot be
|
||||||
|
// type parameters.
|
||||||
|
} else if !field.ty.kind.is_anon_adt() {
|
||||||
// let _: AssertParamIsClone<FieldTy>;
|
// let _: AssertParamIsClone<FieldTy>;
|
||||||
super::assert_ty_bounds(
|
super::assert_ty_bounds(
|
||||||
cx,
|
cx,
|
||||||
|
|
|
@ -123,6 +123,8 @@ fn assert_ty_bounds(
|
||||||
span: Span,
|
span: Span,
|
||||||
assert_path: &[Symbol],
|
assert_path: &[Symbol],
|
||||||
) {
|
) {
|
||||||
|
// Deny anonymous structs or unions to avoid wierd errors.
|
||||||
|
assert!(!ty.kind.is_anon_adt(), "Anonymous structs or unions cannot be type parameters");
|
||||||
// Generate statement `let _: assert_path<ty>;`.
|
// Generate statement `let _: assert_path<ty>;`.
|
||||||
let span = cx.with_def_site_ctxt(span);
|
let span = cx.with_def_site_ctxt(span);
|
||||||
let assert_path = cx.path_all(span, true, cx.std_path(assert_path), vec![GenericArg::Type(ty)]);
|
let assert_path = cx.path_all(span, true, cx.std_path(assert_path), vec![GenericArg::Type(ty)]);
|
||||||
|
|
|
@ -8,6 +8,7 @@ use rustc_data_structures::unord::UnordMap;
|
||||||
use rustc_macros::HashStable_Generic;
|
use rustc_macros::HashStable_Generic;
|
||||||
use rustc_span::def_id::{DefId, LocalDefId};
|
use rustc_span::def_id::{DefId, LocalDefId};
|
||||||
use rustc_span::hygiene::MacroKind;
|
use rustc_span::hygiene::MacroKind;
|
||||||
|
use rustc_span::symbol::kw;
|
||||||
use rustc_span::Symbol;
|
use rustc_span::Symbol;
|
||||||
|
|
||||||
use std::array::IntoIter;
|
use std::array::IntoIter;
|
||||||
|
@ -225,6 +226,7 @@ impl DefKind {
|
||||||
|
|
||||||
pub fn def_path_data(self, name: Symbol) -> DefPathData {
|
pub fn def_path_data(self, name: Symbol) -> DefPathData {
|
||||||
match self {
|
match self {
|
||||||
|
DefKind::Struct | DefKind::Union if name == kw::Empty => DefPathData::AnonAdt,
|
||||||
DefKind::Mod
|
DefKind::Mod
|
||||||
| DefKind::Struct
|
| DefKind::Struct
|
||||||
| DefKind::Union
|
| DefKind::Union
|
||||||
|
|
|
@ -287,6 +287,8 @@ pub enum DefPathData {
|
||||||
/// An existential `impl Trait` type node.
|
/// An existential `impl Trait` type node.
|
||||||
/// Argument position `impl Trait` have a `TypeNs` with their pretty-printed name.
|
/// Argument position `impl Trait` have a `TypeNs` with their pretty-printed name.
|
||||||
OpaqueTy,
|
OpaqueTy,
|
||||||
|
/// An anonymous struct or union type i.e. `struct { foo: Type }` or `union { bar: Type }`
|
||||||
|
AnonAdt,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Definitions {
|
impl Definitions {
|
||||||
|
@ -409,8 +411,9 @@ impl DefPathData {
|
||||||
match *self {
|
match *self {
|
||||||
TypeNs(name) if name == kw::Empty => None,
|
TypeNs(name) if name == kw::Empty => None,
|
||||||
TypeNs(name) | ValueNs(name) | MacroNs(name) | LifetimeNs(name) => Some(name),
|
TypeNs(name) | ValueNs(name) | MacroNs(name) | LifetimeNs(name) => Some(name),
|
||||||
|
|
||||||
Impl | ForeignMod | CrateRoot | Use | GlobalAsm | Closure | Ctor | AnonConst
|
Impl | ForeignMod | CrateRoot | Use | GlobalAsm | Closure | Ctor | AnonConst
|
||||||
| OpaqueTy => None,
|
| OpaqueTy | AnonAdt => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -431,6 +434,7 @@ impl DefPathData {
|
||||||
Ctor => DefPathDataName::Anon { namespace: sym::constructor },
|
Ctor => DefPathDataName::Anon { namespace: sym::constructor },
|
||||||
AnonConst => DefPathDataName::Anon { namespace: sym::constant },
|
AnonConst => DefPathDataName::Anon { namespace: sym::constant },
|
||||||
OpaqueTy => DefPathDataName::Anon { namespace: sym::opaque },
|
OpaqueTy => DefPathDataName::Anon { namespace: sym::opaque },
|
||||||
|
AnonAdt => DefPathDataName::Anon { namespace: sym::anon_adt },
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2587,6 +2587,8 @@ pub enum TyKind<'hir> {
|
||||||
Never,
|
Never,
|
||||||
/// A tuple (`(A, B, C, D, ...)`).
|
/// A tuple (`(A, B, C, D, ...)`).
|
||||||
Tup(&'hir [Ty<'hir>]),
|
Tup(&'hir [Ty<'hir>]),
|
||||||
|
/// An anonymous struct or union type i.e. `struct { foo: Type }` or `union { foo: Type }`
|
||||||
|
AnonAdt(ItemId),
|
||||||
/// A path to a type definition (`module::module::...::Type`), or an
|
/// A path to a type definition (`module::module::...::Type`), or an
|
||||||
/// associated type (e.g., `<Vec<T> as Trait>::Type` or `<T>::Target`).
|
/// associated type (e.g., `<Vec<T> as Trait>::Type` or `<T>::Target`).
|
||||||
///
|
///
|
||||||
|
|
|
@ -852,6 +852,9 @@ pub fn walk_ty<'v, V: Visitor<'v>>(visitor: &mut V, typ: &'v Ty<'v>) {
|
||||||
}
|
}
|
||||||
TyKind::Typeof(ref expression) => visitor.visit_anon_const(expression),
|
TyKind::Typeof(ref expression) => visitor.visit_anon_const(expression),
|
||||||
TyKind::Infer | TyKind::InferDelegation(..) | TyKind::Err(_) => {}
|
TyKind::Infer | TyKind::InferDelegation(..) | TyKind::Err(_) => {}
|
||||||
|
TyKind::AnonAdt(item_id) => {
|
||||||
|
visitor.visit_nested_item(item_id);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -123,6 +123,28 @@ hir_analysis_field_already_declared =
|
||||||
.label = field already declared
|
.label = field already declared
|
||||||
.previous_decl_label = `{$field_name}` first declared here
|
.previous_decl_label = `{$field_name}` first declared here
|
||||||
|
|
||||||
|
hir_analysis_field_already_declared_both_nested =
|
||||||
|
field `{$field_name}` is already declared
|
||||||
|
.label = field `{$field_name}` declared in this unnamed field
|
||||||
|
.nested_field_decl_note = field `{$field_name}` declared here
|
||||||
|
.previous_decl_label = `{$field_name}` first declared here in this unnamed field
|
||||||
|
.previous_nested_field_decl_note = field `{$field_name}` first declared here
|
||||||
|
|
||||||
|
hir_analysis_field_already_declared_current_nested =
|
||||||
|
field `{$field_name}` is already declared
|
||||||
|
.label = field `{$field_name}` declared in this unnamed field
|
||||||
|
.nested_field_decl_note = field `{$field_name}` declared here
|
||||||
|
.previous_decl_label = `{$field_name}` first declared here
|
||||||
|
|
||||||
|
hir_analysis_field_already_declared_nested_help =
|
||||||
|
fields from the type of this unnamed field are considered fields of the outer type
|
||||||
|
|
||||||
|
hir_analysis_field_already_declared_previous_nested =
|
||||||
|
field `{$field_name}` is already declared
|
||||||
|
.label = field already declared
|
||||||
|
.previous_decl_label = `{$field_name}` first declared here in this unnamed field
|
||||||
|
.previous_nested_field_decl_note = field `{$field_name}` first declared here
|
||||||
|
|
||||||
hir_analysis_function_not_found_in_trait = function not found in this trait
|
hir_analysis_function_not_found_in_trait = function not found in this trait
|
||||||
|
|
||||||
hir_analysis_function_not_have_default_implementation = function doesn't have a default implementation
|
hir_analysis_function_not_have_default_implementation = function doesn't have a default implementation
|
||||||
|
@ -420,6 +442,19 @@ hir_analysis_typeof_reserved_keyword_used =
|
||||||
hir_analysis_unconstrained_opaque_type = unconstrained opaque type
|
hir_analysis_unconstrained_opaque_type = unconstrained opaque type
|
||||||
.note = `{$name}` must be used in combination with a concrete type within the same {$what}
|
.note = `{$name}` must be used in combination with a concrete type within the same {$what}
|
||||||
|
|
||||||
|
hir_analysis_unnamed_fields_repr_field_defined = unnamed field defined here
|
||||||
|
|
||||||
|
hir_analysis_unnamed_fields_repr_field_missing_repr_c =
|
||||||
|
named type of unnamed field must have `#[repr(C)]` representation
|
||||||
|
.label = unnamed field defined here
|
||||||
|
.field_ty_label = `{$field_ty}` defined here
|
||||||
|
.suggestion = add `#[repr(C)]` to this {$field_adt_kind}
|
||||||
|
|
||||||
|
hir_analysis_unnamed_fields_repr_missing_repr_c =
|
||||||
|
{$adt_kind} with unnamed fields must have `#[repr(C)]` representation
|
||||||
|
.label = {$adt_kind} `{$adt_name}` defined here
|
||||||
|
.suggestion = add `#[repr(C)]` to this {$adt_kind}
|
||||||
|
|
||||||
hir_analysis_unrecognized_atomic_operation =
|
hir_analysis_unrecognized_atomic_operation =
|
||||||
unrecognized atomic operation function: `{$op}`
|
unrecognized atomic operation function: `{$op}`
|
||||||
.label = unrecognized atomic operation
|
.label = unrecognized atomic operation
|
||||||
|
|
|
@ -2457,6 +2457,19 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
||||||
hir::TyKind::Tup(fields) => {
|
hir::TyKind::Tup(fields) => {
|
||||||
Ty::new_tup_from_iter(tcx, fields.iter().map(|t| self.ast_ty_to_ty(t)))
|
Ty::new_tup_from_iter(tcx, fields.iter().map(|t| self.ast_ty_to_ty(t)))
|
||||||
}
|
}
|
||||||
|
hir::TyKind::AnonAdt(item_id) => {
|
||||||
|
let did = item_id.owner_id.def_id;
|
||||||
|
let adt_def = tcx.adt_def(did);
|
||||||
|
let generics = tcx.generics_of(did);
|
||||||
|
|
||||||
|
debug!("ast_ty_to_ty_inner(AnonAdt): generics={:?}", generics);
|
||||||
|
let args = ty::GenericArgs::for_item(tcx, did.to_def_id(), |param, _| {
|
||||||
|
tcx.mk_param_from_def(param)
|
||||||
|
});
|
||||||
|
debug!("ast_ty_to_ty_inner(AnonAdt): args={:?}", args);
|
||||||
|
|
||||||
|
Ty::new_adt(tcx, adt_def, tcx.mk_args(args))
|
||||||
|
}
|
||||||
hir::TyKind::BareFn(bf) => {
|
hir::TyKind::BareFn(bf) => {
|
||||||
require_c_abi_if_c_variadic(tcx, bf.decl, bf.abi, ast_ty.span);
|
require_c_abi_if_c_variadic(tcx, bf.decl, bf.abi, ast_ty.span);
|
||||||
|
|
||||||
|
|
|
@ -80,6 +80,7 @@ fn check_struct(tcx: TyCtxt<'_>, def_id: LocalDefId) {
|
||||||
|
|
||||||
check_transparent(tcx, def);
|
check_transparent(tcx, def);
|
||||||
check_packed(tcx, span, def);
|
check_packed(tcx, span, def);
|
||||||
|
check_unnamed_fields(tcx, def);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_union(tcx: TyCtxt<'_>, def_id: LocalDefId) {
|
fn check_union(tcx: TyCtxt<'_>, def_id: LocalDefId) {
|
||||||
|
@ -89,6 +90,58 @@ fn check_union(tcx: TyCtxt<'_>, def_id: LocalDefId) {
|
||||||
check_transparent(tcx, def);
|
check_transparent(tcx, def);
|
||||||
check_union_fields(tcx, span, def_id);
|
check_union_fields(tcx, span, def_id);
|
||||||
check_packed(tcx, span, def);
|
check_packed(tcx, span, def);
|
||||||
|
check_unnamed_fields(tcx, def);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Check the representation of adts with unnamed fields.
|
||||||
|
fn check_unnamed_fields(tcx: TyCtxt<'_>, def: ty::AdtDef<'_>) {
|
||||||
|
if def.is_enum() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let variant = def.non_enum_variant();
|
||||||
|
if !variant.has_unnamed_fields() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if !def.is_anonymous() {
|
||||||
|
let adt_kind = def.descr();
|
||||||
|
let span = tcx.def_span(def.did());
|
||||||
|
let unnamed_fields = variant
|
||||||
|
.fields
|
||||||
|
.iter()
|
||||||
|
.filter(|f| f.is_unnamed())
|
||||||
|
.map(|f| {
|
||||||
|
let span = tcx.def_span(f.did);
|
||||||
|
errors::UnnamedFieldsReprFieldDefined { span }
|
||||||
|
})
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
debug_assert_ne!(unnamed_fields.len(), 0, "expect unnamed fields in this adt");
|
||||||
|
let adt_name = tcx.item_name(def.did());
|
||||||
|
if !def.repr().c() {
|
||||||
|
tcx.dcx().emit_err(errors::UnnamedFieldsRepr::MissingReprC {
|
||||||
|
span,
|
||||||
|
adt_kind,
|
||||||
|
adt_name,
|
||||||
|
unnamed_fields,
|
||||||
|
sugg_span: span.shrink_to_lo(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for field in variant.fields.iter().filter(|f| f.is_unnamed()) {
|
||||||
|
let field_ty = tcx.type_of(field.did).instantiate_identity();
|
||||||
|
if let Some(adt) = field_ty.ty_adt_def()
|
||||||
|
&& !adt.is_anonymous()
|
||||||
|
&& !adt.repr().c()
|
||||||
|
{
|
||||||
|
let field_ty_span = tcx.def_span(adt.did());
|
||||||
|
tcx.dcx().emit_err(errors::UnnamedFieldsRepr::FieldMissingReprC {
|
||||||
|
span: tcx.def_span(field.did),
|
||||||
|
field_ty_span,
|
||||||
|
field_ty,
|
||||||
|
field_adt_kind: adt.descr(),
|
||||||
|
sugg_span: field_ty_span.shrink_to_lo(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Check that the fields of the `union` do not need dropping.
|
/// Check that the fields of the `union` do not need dropping.
|
||||||
|
|
|
@ -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
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -789,6 +791,175 @@ fn convert_enum_variant_types(tcx: TyCtxt<'_>, def_id: DefId) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
|
struct NestedSpan {
|
||||||
|
span: Span,
|
||||||
|
nested_field_span: Span,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl NestedSpan {
|
||||||
|
fn to_field_already_declared_nested_help(&self) -> errors::FieldAlreadyDeclaredNestedHelp {
|
||||||
|
errors::FieldAlreadyDeclaredNestedHelp { span: self.span }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
|
enum FieldDeclSpan {
|
||||||
|
NotNested(Span),
|
||||||
|
Nested(NestedSpan),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Span> for FieldDeclSpan {
|
||||||
|
fn from(span: Span) -> Self {
|
||||||
|
Self::NotNested(span)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<NestedSpan> for FieldDeclSpan {
|
||||||
|
fn from(span: NestedSpan) -> Self {
|
||||||
|
Self::Nested(span)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct FieldUniquenessCheckContext<'tcx> {
|
||||||
|
tcx: TyCtxt<'tcx>,
|
||||||
|
seen_fields: FxHashMap<Ident, FieldDeclSpan>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'tcx> FieldUniquenessCheckContext<'tcx> {
|
||||||
|
fn new(tcx: TyCtxt<'tcx>) -> Self {
|
||||||
|
Self { tcx, seen_fields: FxHashMap::default() }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Check if a given field `ident` declared at `field_decl` has been declared elsewhere before.
|
||||||
|
fn check_field_decl(&mut self, ident: Ident, field_decl: FieldDeclSpan) {
|
||||||
|
use FieldDeclSpan::*;
|
||||||
|
let field_name = ident.name;
|
||||||
|
let ident = ident.normalize_to_macros_2_0();
|
||||||
|
match (field_decl, self.seen_fields.get(&ident).copied()) {
|
||||||
|
(NotNested(span), Some(NotNested(prev_span))) => {
|
||||||
|
self.tcx.dcx().emit_err(errors::FieldAlreadyDeclared::NotNested {
|
||||||
|
field_name,
|
||||||
|
span,
|
||||||
|
prev_span,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
(NotNested(span), Some(Nested(prev))) => {
|
||||||
|
self.tcx.dcx().emit_err(errors::FieldAlreadyDeclared::PreviousNested {
|
||||||
|
field_name,
|
||||||
|
span,
|
||||||
|
prev_span: prev.span,
|
||||||
|
prev_nested_field_span: prev.nested_field_span,
|
||||||
|
prev_help: prev.to_field_already_declared_nested_help(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
(
|
||||||
|
Nested(current @ NestedSpan { span, nested_field_span, .. }),
|
||||||
|
Some(NotNested(prev_span)),
|
||||||
|
) => {
|
||||||
|
self.tcx.dcx().emit_err(errors::FieldAlreadyDeclared::CurrentNested {
|
||||||
|
field_name,
|
||||||
|
span,
|
||||||
|
nested_field_span,
|
||||||
|
help: current.to_field_already_declared_nested_help(),
|
||||||
|
prev_span,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
(Nested(current @ NestedSpan { span, nested_field_span }), Some(Nested(prev))) => {
|
||||||
|
self.tcx.dcx().emit_err(errors::FieldAlreadyDeclared::BothNested {
|
||||||
|
field_name,
|
||||||
|
span,
|
||||||
|
nested_field_span,
|
||||||
|
help: current.to_field_already_declared_nested_help(),
|
||||||
|
prev_span: prev.span,
|
||||||
|
prev_nested_field_span: prev.nested_field_span,
|
||||||
|
prev_help: prev.to_field_already_declared_nested_help(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
(field_decl, None) => {
|
||||||
|
self.seen_fields.insert(ident, field_decl);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Check the uniqueness of fields across adt where there are
|
||||||
|
/// nested fields imported from an unnamed field.
|
||||||
|
fn check_field_in_nested_adt(&mut self, adt_def: ty::AdtDef<'_>, unnamed_field_span: Span) {
|
||||||
|
for field in adt_def.all_fields() {
|
||||||
|
if field.is_unnamed() {
|
||||||
|
// Here we don't care about the generic parameters, so `instantiate_identity` is enough.
|
||||||
|
match self.tcx.type_of(field.did).instantiate_identity().kind() {
|
||||||
|
ty::Adt(adt_def, _) => {
|
||||||
|
self.check_field_in_nested_adt(*adt_def, unnamed_field_span);
|
||||||
|
}
|
||||||
|
ty_kind => span_bug!(
|
||||||
|
self.tcx.def_span(field.did),
|
||||||
|
"Unexpected TyKind in FieldUniquenessCheckContext::check_field_in_nested_adt(): {ty_kind:?}"
|
||||||
|
),
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
self.check_field_decl(
|
||||||
|
field.ident(self.tcx),
|
||||||
|
NestedSpan {
|
||||||
|
span: unnamed_field_span,
|
||||||
|
nested_field_span: self.tcx.def_span(field.did),
|
||||||
|
}
|
||||||
|
.into(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Check the uniqueness of fields in a struct variant, and recursively
|
||||||
|
/// check the nested fields if it is an unnamed field with type of an
|
||||||
|
/// annoymous adt.
|
||||||
|
fn check_field(&mut self, field: &hir::FieldDef<'_>) {
|
||||||
|
if field.ident.name != kw::Underscore {
|
||||||
|
self.check_field_decl(field.ident, field.span.into());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
match &field.ty.kind {
|
||||||
|
hir::TyKind::AnonAdt(item_id) => {
|
||||||
|
match &self.tcx.hir_node(item_id.hir_id()).expect_item().kind {
|
||||||
|
hir::ItemKind::Struct(variant_data, ..)
|
||||||
|
| hir::ItemKind::Union(variant_data, ..) => {
|
||||||
|
variant_data.fields().iter().for_each(|f| self.check_field(f));
|
||||||
|
}
|
||||||
|
item_kind => span_bug!(
|
||||||
|
field.ty.span,
|
||||||
|
"Unexpected ItemKind in FieldUniquenessCheckContext::check_field(): {item_kind:?}"
|
||||||
|
),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
hir::TyKind::Path(hir::QPath::Resolved(_, hir::Path { res, .. })) => {
|
||||||
|
self.check_field_in_nested_adt(self.tcx.adt_def(res.def_id()), field.span);
|
||||||
|
}
|
||||||
|
// 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)
|
||||||
|
ty_kind => {
|
||||||
|
self.tcx.dcx().span_delayed_bug(
|
||||||
|
field.ty.span,
|
||||||
|
format!("Unexpected TyKind in FieldUniquenessCheckContext::check_field(): {ty_kind:?}"),
|
||||||
|
);
|
||||||
|
// FIXME: errors during AST validation should abort the compilation before reaching here.
|
||||||
|
self.tcx.dcx().abort_if_errors();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn convert_variant(
|
fn convert_variant(
|
||||||
tcx: TyCtxt<'_>,
|
tcx: TyCtxt<'_>,
|
||||||
variant_did: Option<LocalDefId>,
|
variant_did: Option<LocalDefId>,
|
||||||
|
@ -797,28 +968,25 @@ fn convert_variant(
|
||||||
def: &hir::VariantData<'_>,
|
def: &hir::VariantData<'_>,
|
||||||
adt_kind: ty::AdtKind,
|
adt_kind: ty::AdtKind,
|
||||||
parent_did: LocalDefId,
|
parent_did: LocalDefId,
|
||||||
|
is_anonymous: bool,
|
||||||
) -> ty::VariantDef {
|
) -> ty::VariantDef {
|
||||||
let mut seen_fields: FxHashMap<Ident, Span> = Default::default();
|
let mut has_unnamed_fields = false;
|
||||||
|
let mut field_uniqueness_check_ctx = FieldUniquenessCheckContext::new(tcx);
|
||||||
let fields = def
|
let fields = def
|
||||||
.fields()
|
.fields()
|
||||||
.iter()
|
.iter()
|
||||||
.map(|f| {
|
.inspect(|f| {
|
||||||
let dup_span = seen_fields.get(&f.ident.normalize_to_macros_2_0()).cloned();
|
has_unnamed_fields |= f.ident.name == kw::Underscore;
|
||||||
if let Some(prev_span) = dup_span {
|
// We only check named ADT here because anonymous ADTs are checked inside
|
||||||
tcx.dcx().emit_err(errors::FieldAlreadyDeclared {
|
// the nammed ADT in which they are defined.
|
||||||
field_name: f.ident,
|
if !is_anonymous {
|
||||||
span: f.span,
|
field_uniqueness_check_ctx.check_field(f);
|
||||||
prev_span,
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
seen_fields.insert(f.ident.normalize_to_macros_2_0(), f.span);
|
|
||||||
}
|
}
|
||||||
|
})
|
||||||
ty::FieldDef {
|
.map(|f| ty::FieldDef {
|
||||||
did: f.def_id.to_def_id(),
|
did: f.def_id.to_def_id(),
|
||||||
name: f.ident.name,
|
name: f.ident.name,
|
||||||
vis: tcx.visibility(f.def_id),
|
vis: tcx.visibility(f.def_id),
|
||||||
}
|
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
let recovered = match def {
|
let recovered = match def {
|
||||||
|
@ -837,6 +1005,7 @@ fn convert_variant(
|
||||||
adt_kind == AdtKind::Struct && tcx.has_attr(parent_did, sym::non_exhaustive)
|
adt_kind == AdtKind::Struct && tcx.has_attr(parent_did, sym::non_exhaustive)
|
||||||
|| variant_did
|
|| variant_did
|
||||||
.is_some_and(|variant_did| tcx.has_attr(variant_did, sym::non_exhaustive)),
|
.is_some_and(|variant_did| tcx.has_attr(variant_did, sym::non_exhaustive)),
|
||||||
|
has_unnamed_fields,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -847,7 +1016,12 @@ fn adt_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::AdtDef<'_> {
|
||||||
bug!("expected ADT to be an item");
|
bug!("expected ADT to be an item");
|
||||||
};
|
};
|
||||||
|
|
||||||
let repr = tcx.repr_options_of_def(def_id.to_def_id());
|
let is_anonymous = item.ident.name == kw::Empty;
|
||||||
|
let repr = if is_anonymous {
|
||||||
|
tcx.adt_def(tcx.local_parent(def_id)).repr()
|
||||||
|
} else {
|
||||||
|
tcx.repr_options_of_def(def_id.to_def_id())
|
||||||
|
};
|
||||||
let (kind, variants) = match &item.kind {
|
let (kind, variants) = match &item.kind {
|
||||||
ItemKind::Enum(def, _) => {
|
ItemKind::Enum(def, _) => {
|
||||||
let mut distance_from_explicit = 0;
|
let mut distance_from_explicit = 0;
|
||||||
|
@ -871,6 +1045,7 @@ fn adt_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::AdtDef<'_> {
|
||||||
&v.data,
|
&v.data,
|
||||||
AdtKind::Enum,
|
AdtKind::Enum,
|
||||||
def_id,
|
def_id,
|
||||||
|
is_anonymous,
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
@ -890,6 +1065,7 @@ fn adt_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::AdtDef<'_> {
|
||||||
def,
|
def,
|
||||||
adt_kind,
|
adt_kind,
|
||||||
def_id,
|
def_id,
|
||||||
|
is_anonymous,
|
||||||
))
|
))
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
|
@ -897,7 +1073,7 @@ fn adt_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::AdtDef<'_> {
|
||||||
}
|
}
|
||||||
_ => bug!("{:?} is not an ADT", item.owner_id.def_id),
|
_ => bug!("{:?} is not an ADT", item.owner_id.def_id),
|
||||||
};
|
};
|
||||||
tcx.mk_adt_def(def_id.to_def_id(), kind, variants, repr)
|
tcx.mk_adt_def(def_id.to_def_id(), kind, variants, repr, is_anonymous)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn trait_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::TraitDef {
|
fn trait_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::TraitDef {
|
||||||
|
|
|
@ -175,14 +175,66 @@ pub struct DropImplOnWrongItem {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
#[diag(hir_analysis_field_already_declared, code = E0124)]
|
pub enum FieldAlreadyDeclared {
|
||||||
pub struct FieldAlreadyDeclared {
|
#[diag(hir_analysis_field_already_declared, code = E0124)]
|
||||||
pub field_name: Ident,
|
NotNested {
|
||||||
|
field_name: Symbol,
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
#[label]
|
#[label]
|
||||||
pub span: Span,
|
span: Span,
|
||||||
#[label(hir_analysis_previous_decl_label)]
|
#[label(hir_analysis_previous_decl_label)]
|
||||||
pub prev_span: Span,
|
prev_span: Span,
|
||||||
|
},
|
||||||
|
#[diag(hir_analysis_field_already_declared_current_nested)]
|
||||||
|
CurrentNested {
|
||||||
|
field_name: Symbol,
|
||||||
|
#[primary_span]
|
||||||
|
#[label]
|
||||||
|
span: Span,
|
||||||
|
#[note(hir_analysis_nested_field_decl_note)]
|
||||||
|
nested_field_span: Span,
|
||||||
|
#[subdiagnostic]
|
||||||
|
help: FieldAlreadyDeclaredNestedHelp,
|
||||||
|
#[label(hir_analysis_previous_decl_label)]
|
||||||
|
prev_span: Span,
|
||||||
|
},
|
||||||
|
#[diag(hir_analysis_field_already_declared_previous_nested)]
|
||||||
|
PreviousNested {
|
||||||
|
field_name: Symbol,
|
||||||
|
#[primary_span]
|
||||||
|
#[label]
|
||||||
|
span: Span,
|
||||||
|
#[label(hir_analysis_previous_decl_label)]
|
||||||
|
prev_span: Span,
|
||||||
|
#[note(hir_analysis_previous_nested_field_decl_note)]
|
||||||
|
prev_nested_field_span: Span,
|
||||||
|
#[subdiagnostic]
|
||||||
|
prev_help: FieldAlreadyDeclaredNestedHelp,
|
||||||
|
},
|
||||||
|
#[diag(hir_analysis_field_already_declared_both_nested)]
|
||||||
|
BothNested {
|
||||||
|
field_name: Symbol,
|
||||||
|
#[primary_span]
|
||||||
|
#[label]
|
||||||
|
span: Span,
|
||||||
|
#[note(hir_analysis_nested_field_decl_note)]
|
||||||
|
nested_field_span: Span,
|
||||||
|
#[subdiagnostic]
|
||||||
|
help: FieldAlreadyDeclaredNestedHelp,
|
||||||
|
#[label(hir_analysis_previous_decl_label)]
|
||||||
|
prev_span: Span,
|
||||||
|
#[note(hir_analysis_previous_nested_field_decl_note)]
|
||||||
|
prev_nested_field_span: Span,
|
||||||
|
#[subdiagnostic]
|
||||||
|
prev_help: FieldAlreadyDeclaredNestedHelp,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Subdiagnostic)]
|
||||||
|
#[help(hir_analysis_field_already_declared_nested_help)]
|
||||||
|
pub struct FieldAlreadyDeclaredNestedHelp {
|
||||||
|
#[primary_span]
|
||||||
|
pub span: Span,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
|
@ -1534,3 +1586,38 @@ pub(crate) enum UnusedGenericParameterHelp {
|
||||||
#[help(hir_analysis_unused_generic_parameter_ty_alias_help)]
|
#[help(hir_analysis_unused_generic_parameter_ty_alias_help)]
|
||||||
TyAlias { param_name: Ident },
|
TyAlias { param_name: Ident },
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Diagnostic)]
|
||||||
|
pub enum UnnamedFieldsRepr<'a> {
|
||||||
|
#[diag(hir_analysis_unnamed_fields_repr_missing_repr_c)]
|
||||||
|
MissingReprC {
|
||||||
|
#[primary_span]
|
||||||
|
#[label]
|
||||||
|
span: Span,
|
||||||
|
adt_kind: &'static str,
|
||||||
|
adt_name: Symbol,
|
||||||
|
#[subdiagnostic]
|
||||||
|
unnamed_fields: Vec<UnnamedFieldsReprFieldDefined>,
|
||||||
|
#[suggestion(code = "#[repr(C)]\n")]
|
||||||
|
sugg_span: Span,
|
||||||
|
},
|
||||||
|
#[diag(hir_analysis_unnamed_fields_repr_field_missing_repr_c)]
|
||||||
|
FieldMissingReprC {
|
||||||
|
#[primary_span]
|
||||||
|
#[label]
|
||||||
|
span: Span,
|
||||||
|
#[label(hir_analysis_field_ty_label)]
|
||||||
|
field_ty_span: Span,
|
||||||
|
field_ty: Ty<'a>,
|
||||||
|
field_adt_kind: &'static str,
|
||||||
|
#[suggestion(code = "#[repr(C)]\n")]
|
||||||
|
sugg_span: Span,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Subdiagnostic)]
|
||||||
|
#[note(hir_analysis_unnamed_fields_repr_field_defined)]
|
||||||
|
pub struct UnnamedFieldsReprFieldDefined {
|
||||||
|
#[primary_span]
|
||||||
|
pub span: Span,
|
||||||
|
}
|
||||||
|
|
|
@ -328,6 +328,7 @@ impl<'a> State<'a> {
|
||||||
hir::TyKind::Infer | hir::TyKind::InferDelegation(..) => {
|
hir::TyKind::Infer | hir::TyKind::InferDelegation(..) => {
|
||||||
self.word("_");
|
self.word("_");
|
||||||
}
|
}
|
||||||
|
hir::TyKind::AnonAdt(..) => self.word("/* anonymous adt */"),
|
||||||
}
|
}
|
||||||
self.end()
|
self.end()
|
||||||
}
|
}
|
||||||
|
@ -728,11 +729,17 @@ impl<'a> State<'a> {
|
||||||
}
|
}
|
||||||
hir::VariantData::Struct { .. } => {
|
hir::VariantData::Struct { .. } => {
|
||||||
self.print_where_clause(generics);
|
self.print_where_clause(generics);
|
||||||
|
self.print_variant_struct(span, struct_def.fields())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn print_variant_struct(&mut self, span: rustc_span::Span, fields: &[hir::FieldDef<'_>]) {
|
||||||
self.nbsp();
|
self.nbsp();
|
||||||
self.bopen();
|
self.bopen();
|
||||||
self.hardbreak_if_not_bol();
|
self.hardbreak_if_not_bol();
|
||||||
|
|
||||||
for field in struct_def.fields() {
|
for field in fields {
|
||||||
self.hardbreak_if_not_bol();
|
self.hardbreak_if_not_bol();
|
||||||
self.maybe_print_comment(field.span.lo());
|
self.maybe_print_comment(field.span.lo());
|
||||||
self.print_outer_attributes(self.attrs(field.hir_id));
|
self.print_outer_attributes(self.attrs(field.hir_id));
|
||||||
|
@ -744,10 +751,8 @@ impl<'a> State<'a> {
|
||||||
|
|
||||||
self.bclose(span)
|
self.bclose(span)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn print_variant(&mut self, v: &hir::Variant<'_>) {
|
pub fn print_variant(&mut self, v: &hir::Variant<'_>) {
|
||||||
self.head("");
|
self.head("");
|
||||||
let generics = hir::Generics::empty();
|
let generics = hir::Generics::empty();
|
||||||
self.print_struct(&v.data, generics, v.ident.name, v.span, false);
|
self.print_struct(&v.data, generics, v.ident.name, v.span, false);
|
||||||
|
|
|
@ -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);
|
||||||
|
if let Some(ty) = last_ty {
|
||||||
|
nested_fields.push((ty, idx));
|
||||||
|
}
|
||||||
|
if field.ident(self.tcx).normalize_to_macros_2_0() == ident {
|
||||||
// Save the index of all fields regardless of their visibility in case
|
// Save the index of all fields regardless of their visibility in case
|
||||||
// of error recovery.
|
// of error recovery.
|
||||||
self.write_field_index(expr.hir_id, index);
|
self.write_field_index(expr.hir_id, first_idx, nested_fields);
|
||||||
let adjustments = self.adjust_steps(&autoderef);
|
let adjustments = self.adjust_steps(&autoderef);
|
||||||
if field.vis.is_accessible_from(def_scope, self.tcx) {
|
if field.vis.is_accessible_from(def_scope, self.tcx) {
|
||||||
self.apply_adjustments(base, adjustments);
|
self.apply_adjustments(base, adjustments);
|
||||||
self.register_predicates(autoderef.into_obligations());
|
self.register_predicates(autoderef.into_obligations());
|
||||||
|
|
||||||
self.tcx.check_stability(field.did, Some(expr.hir_id), expr.span, None);
|
self.tcx.check_stability(
|
||||||
|
field.did,
|
||||||
|
Some(expr.hir_id),
|
||||||
|
expr.span,
|
||||||
|
None,
|
||||||
|
);
|
||||||
return field_ty;
|
return field_ty;
|
||||||
}
|
}
|
||||||
private_candidate = Some((adjustments, base_def.did()));
|
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")]
|
||||||
|
|
|
@ -1084,6 +1084,8 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
|
||||||
parent_did,
|
parent_did,
|
||||||
false,
|
false,
|
||||||
data.is_non_exhaustive,
|
data.is_non_exhaustive,
|
||||||
|
// FIXME: unnamed fields in crate metadata is unimplemented yet.
|
||||||
|
false,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -1126,6 +1128,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
|
||||||
adt_kind,
|
adt_kind,
|
||||||
variants.into_iter().map(|(_, variant)| variant).collect(),
|
variants.into_iter().map(|(_, variant)| variant).collect(),
|
||||||
repr,
|
repr,
|
||||||
|
false,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -756,6 +756,13 @@ impl<'hir> Map<'hir> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn expect_field(self, id: HirId) -> &'hir FieldDef<'hir> {
|
||||||
|
match self.tcx.hir_node(id) {
|
||||||
|
Node::Field(field) => field,
|
||||||
|
_ => bug!("expected field, found {}", self.node_to_string(id)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn expect_foreign_item(self, id: OwnerId) -> &'hir ForeignItem<'hir> {
|
pub fn expect_foreign_item(self, id: OwnerId) -> &'hir ForeignItem<'hir> {
|
||||||
match self.tcx.hir_owner_node(id) {
|
match self.tcx.hir_owner_node(id) {
|
||||||
OwnerNode::ForeignItem(item) => item,
|
OwnerNode::ForeignItem(item) => item,
|
||||||
|
|
|
@ -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! }
|
||||||
|
|
|
@ -50,6 +50,8 @@ bitflags! {
|
||||||
const IS_VARIANT_LIST_NON_EXHAUSTIVE = 1 << 8;
|
const IS_VARIANT_LIST_NON_EXHAUSTIVE = 1 << 8;
|
||||||
/// Indicates whether the type is `UnsafeCell`.
|
/// Indicates whether the type is `UnsafeCell`.
|
||||||
const IS_UNSAFE_CELL = 1 << 9;
|
const IS_UNSAFE_CELL = 1 << 9;
|
||||||
|
/// Indicates whether the type is anonymous.
|
||||||
|
const IS_ANONYMOUS = 1 << 10;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
rustc_data_structures::external_bitflags_debug! { AdtFlags }
|
rustc_data_structures::external_bitflags_debug! { AdtFlags }
|
||||||
|
@ -233,8 +235,12 @@ impl AdtDefData {
|
||||||
kind: AdtKind,
|
kind: AdtKind,
|
||||||
variants: IndexVec<VariantIdx, VariantDef>,
|
variants: IndexVec<VariantIdx, VariantDef>,
|
||||||
repr: ReprOptions,
|
repr: ReprOptions,
|
||||||
|
is_anonymous: bool,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
debug!("AdtDef::new({:?}, {:?}, {:?}, {:?})", did, kind, variants, repr);
|
debug!(
|
||||||
|
"AdtDef::new({:?}, {:?}, {:?}, {:?}, {:?})",
|
||||||
|
did, kind, variants, repr, is_anonymous
|
||||||
|
);
|
||||||
let mut flags = AdtFlags::NO_ADT_FLAGS;
|
let mut flags = AdtFlags::NO_ADT_FLAGS;
|
||||||
|
|
||||||
if kind == AdtKind::Enum && tcx.has_attr(did, sym::non_exhaustive) {
|
if kind == AdtKind::Enum && tcx.has_attr(did, sym::non_exhaustive) {
|
||||||
|
@ -267,6 +273,9 @@ impl AdtDefData {
|
||||||
if Some(did) == tcx.lang_items().unsafe_cell_type() {
|
if Some(did) == tcx.lang_items().unsafe_cell_type() {
|
||||||
flags |= AdtFlags::IS_UNSAFE_CELL;
|
flags |= AdtFlags::IS_UNSAFE_CELL;
|
||||||
}
|
}
|
||||||
|
if is_anonymous {
|
||||||
|
flags |= AdtFlags::IS_ANONYMOUS;
|
||||||
|
}
|
||||||
|
|
||||||
AdtDefData { did, variants, flags, repr }
|
AdtDefData { did, variants, flags, repr }
|
||||||
}
|
}
|
||||||
|
@ -365,6 +374,12 @@ impl<'tcx> AdtDef<'tcx> {
|
||||||
self.flags().contains(AdtFlags::IS_MANUALLY_DROP)
|
self.flags().contains(AdtFlags::IS_MANUALLY_DROP)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns `true` if this is an anonymous adt
|
||||||
|
#[inline]
|
||||||
|
pub fn is_anonymous(self) -> bool {
|
||||||
|
self.flags().contains(AdtFlags::IS_ANONYMOUS)
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns `true` if this type has a destructor.
|
/// Returns `true` if this type has a destructor.
|
||||||
pub fn has_dtor(self, tcx: TyCtxt<'tcx>) -> bool {
|
pub fn has_dtor(self, tcx: TyCtxt<'tcx>) -> bool {
|
||||||
self.destructor(tcx).is_some()
|
self.destructor(tcx).is_some()
|
||||||
|
@ -386,7 +401,7 @@ impl<'tcx> AdtDef<'tcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns an iterator over all fields contained
|
/// Returns an iterator over all fields contained
|
||||||
/// by this ADT.
|
/// by this ADT (nested unnamed fields are not expanded).
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn all_fields(self) -> impl Iterator<Item = &'tcx FieldDef> + Clone {
|
pub fn all_fields(self) -> impl Iterator<Item = &'tcx FieldDef> + Clone {
|
||||||
self.variants().iter().flat_map(|v| v.fields.iter())
|
self.variants().iter().flat_map(|v| v.fields.iter())
|
||||||
|
|
|
@ -715,8 +715,16 @@ impl<'tcx> TyCtxt<'tcx> {
|
||||||
kind: AdtKind,
|
kind: AdtKind,
|
||||||
variants: IndexVec<VariantIdx, ty::VariantDef>,
|
variants: IndexVec<VariantIdx, ty::VariantDef>,
|
||||||
repr: ReprOptions,
|
repr: ReprOptions,
|
||||||
|
is_anonymous: bool,
|
||||||
) -> ty::AdtDef<'tcx> {
|
) -> ty::AdtDef<'tcx> {
|
||||||
self.mk_adt_def_from_data(ty::AdtDefData::new(self, did, kind, variants, repr))
|
self.mk_adt_def_from_data(ty::AdtDefData::new(
|
||||||
|
self,
|
||||||
|
did,
|
||||||
|
kind,
|
||||||
|
variants,
|
||||||
|
repr,
|
||||||
|
is_anonymous,
|
||||||
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Allocates a read-only byte or string literal for `mir::interpret`.
|
/// Allocates a read-only byte or string literal for `mir::interpret`.
|
||||||
|
|
|
@ -1130,6 +1130,8 @@ bitflags! {
|
||||||
/// Indicates whether this variant was obtained as part of recovering from
|
/// Indicates whether this variant was obtained as part of recovering from
|
||||||
/// a syntactic error. May be incomplete or bogus.
|
/// a syntactic error. May be incomplete or bogus.
|
||||||
const IS_RECOVERED = 1 << 1;
|
const IS_RECOVERED = 1 << 1;
|
||||||
|
/// Indicates whether this variant has unnamed fields.
|
||||||
|
const HAS_UNNAMED_FIELDS = 1 << 2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
rustc_data_structures::external_bitflags_debug! { VariantFlags }
|
rustc_data_structures::external_bitflags_debug! { VariantFlags }
|
||||||
|
@ -1143,7 +1145,7 @@ pub struct VariantDef {
|
||||||
/// `DefId` that identifies the variant's constructor.
|
/// `DefId` that identifies the variant's constructor.
|
||||||
/// If this variant is a struct variant, then this is `None`.
|
/// If this variant is a struct variant, then this is `None`.
|
||||||
pub ctor: Option<(CtorKind, DefId)>,
|
pub ctor: Option<(CtorKind, DefId)>,
|
||||||
/// Variant or struct name.
|
/// Variant or struct name, maybe empty for anonymous adt (struct or union).
|
||||||
pub name: Symbol,
|
pub name: Symbol,
|
||||||
/// Discriminant of this variant.
|
/// Discriminant of this variant.
|
||||||
pub discr: VariantDiscr,
|
pub discr: VariantDiscr,
|
||||||
|
@ -1180,11 +1182,12 @@ impl VariantDef {
|
||||||
parent_did: DefId,
|
parent_did: DefId,
|
||||||
recovered: bool,
|
recovered: bool,
|
||||||
is_field_list_non_exhaustive: bool,
|
is_field_list_non_exhaustive: bool,
|
||||||
|
has_unnamed_fields: bool,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
debug!(
|
debug!(
|
||||||
"VariantDef::new(name = {:?}, variant_did = {:?}, ctor = {:?}, discr = {:?},
|
"VariantDef::new(name = {:?}, variant_did = {:?}, ctor = {:?}, discr = {:?},
|
||||||
fields = {:?}, adt_kind = {:?}, parent_did = {:?})",
|
fields = {:?}, adt_kind = {:?}, parent_did = {:?}, has_unnamed_fields = {:?})",
|
||||||
name, variant_did, ctor, discr, fields, adt_kind, parent_did,
|
name, variant_did, ctor, discr, fields, adt_kind, parent_did, has_unnamed_fields,
|
||||||
);
|
);
|
||||||
|
|
||||||
let mut flags = VariantFlags::NO_VARIANT_FLAGS;
|
let mut flags = VariantFlags::NO_VARIANT_FLAGS;
|
||||||
|
@ -1196,6 +1199,10 @@ impl VariantDef {
|
||||||
flags |= VariantFlags::IS_RECOVERED;
|
flags |= VariantFlags::IS_RECOVERED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if has_unnamed_fields {
|
||||||
|
flags |= VariantFlags::HAS_UNNAMED_FIELDS;
|
||||||
|
}
|
||||||
|
|
||||||
VariantDef { def_id: variant_did.unwrap_or(parent_did), ctor, name, discr, fields, flags }
|
VariantDef { def_id: variant_did.unwrap_or(parent_did), ctor, name, discr, fields, flags }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1211,6 +1218,12 @@ impl VariantDef {
|
||||||
self.flags.intersects(VariantFlags::IS_RECOVERED)
|
self.flags.intersects(VariantFlags::IS_RECOVERED)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Does this variant contains unnamed fields
|
||||||
|
#[inline]
|
||||||
|
pub fn has_unnamed_fields(&self) -> bool {
|
||||||
|
self.flags.intersects(VariantFlags::HAS_UNNAMED_FIELDS)
|
||||||
|
}
|
||||||
|
|
||||||
/// Computes the `Ident` of this variant by looking up the `Span`
|
/// Computes the `Ident` of this variant by looking up the `Span`
|
||||||
pub fn ident(&self, tcx: TyCtxt<'_>) -> Ident {
|
pub fn ident(&self, tcx: TyCtxt<'_>) -> Ident {
|
||||||
Ident::new(self.name, tcx.def_ident_span(self.def_id).unwrap())
|
Ident::new(self.name, tcx.def_ident_span(self.def_id).unwrap())
|
||||||
|
@ -1374,6 +1387,11 @@ impl<'tcx> FieldDef {
|
||||||
pub fn ident(&self, tcx: TyCtxt<'_>) -> Ident {
|
pub fn ident(&self, tcx: TyCtxt<'_>) -> Ident {
|
||||||
Ident::new(self.name, tcx.def_ident_span(self.did).unwrap())
|
Ident::new(self.name, tcx.def_ident_span(self.did).unwrap())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns whether the field is unnamed
|
||||||
|
pub fn is_unnamed(&self) -> bool {
|
||||||
|
self.name == rustc_span::symbol::kw::Underscore
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq)]
|
#[derive(Debug, PartialEq, Eq)]
|
||||||
|
|
|
@ -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, ..) => {
|
||||||
|
let mut kind = ExprKind::Field {
|
||||||
lhs: self.mirror_expr(source),
|
lhs: self.mirror_expr(source),
|
||||||
variant_index: FIRST_VARIANT,
|
variant_index: FIRST_VARIANT,
|
||||||
name: self.typeck_results.field_index(expr.hir_id),
|
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();
|
||||||
|
|
|
@ -396,8 +396,9 @@ impl<'a> Parser<'a> {
|
||||||
self.parse_record_struct_body(if is_union { "union" } else { "struct" }, lo, false)?;
|
self.parse_record_struct_body(if is_union { "union" } else { "struct" }, lo, false)?;
|
||||||
let span = lo.to(self.prev_token.span);
|
let span = lo.to(self.prev_token.span);
|
||||||
self.sess.gated_spans.gate(sym::unnamed_fields, span);
|
self.sess.gated_spans.gate(sym::unnamed_fields, span);
|
||||||
// These can be rejected during AST validation in `deny_anon_struct_or_union`.
|
let id = ast::DUMMY_NODE_ID;
|
||||||
let kind = if is_union { TyKind::AnonUnion(fields) } else { TyKind::AnonStruct(fields) };
|
let kind =
|
||||||
|
if is_union { TyKind::AnonUnion(id, fields) } else { TyKind::AnonStruct(id, fields) };
|
||||||
Ok(self.mk_ty(span, kind))
|
Ok(self.mk_ty(span, kind))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -345,6 +345,7 @@ impl<'v> hir_visit::Visitor<'v> for StatCollector<'v> {
|
||||||
BareFn,
|
BareFn,
|
||||||
Never,
|
Never,
|
||||||
Tup,
|
Tup,
|
||||||
|
AnonAdt,
|
||||||
Path,
|
Path,
|
||||||
OpaqueDef,
|
OpaqueDef,
|
||||||
TraitObject,
|
TraitObject,
|
||||||
|
|
|
@ -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_struct_variant(
|
||||||
|
&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_struct_variant(
|
||||||
|
&nested_fields,
|
||||||
|
Ident::empty(),
|
||||||
|
local_def_id,
|
||||||
|
res,
|
||||||
|
// Anonymous adts inherit visibility from their parent adts.
|
||||||
|
adt_vis,
|
||||||
|
field.ty.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_struct_variant(
|
||||||
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_struct_variant(
|
||||||
|
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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -80,6 +80,22 @@ impl<'a, 'b, 'tcx> DefCollector<'a, 'b, 'tcx> {
|
||||||
let name = field.ident.map_or_else(|| sym::integer(index(self)), |ident| ident.name);
|
let name = field.ident.map_or_else(|| sym::integer(index(self)), |ident| ident.name);
|
||||||
let def = self.create_def(field.id, name, DefKind::Field, field.span);
|
let def = self.create_def(field.id, name, DefKind::Field, field.span);
|
||||||
self.with_parent(def, |this| visit::walk_field_def(this, field));
|
self.with_parent(def, |this| visit::walk_field_def(this, field));
|
||||||
|
self.visit_anon_adt(&field.ty);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_anon_adt(&mut self, ty: &'a Ty) {
|
||||||
|
let def_kind = match &ty.kind {
|
||||||
|
TyKind::AnonStruct(..) => DefKind::Struct,
|
||||||
|
TyKind::AnonUnion(..) => DefKind::Union,
|
||||||
|
_ => return,
|
||||||
|
};
|
||||||
|
match &ty.kind {
|
||||||
|
TyKind::AnonStruct(node_id, _) | TyKind::AnonUnion(node_id, _) => {
|
||||||
|
let def_id = self.create_def(*node_id, kw::Empty, def_kind, ty.span);
|
||||||
|
self.with_parent(def_id, |this| visit::walk_ty(this, ty));
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -324,8 +340,10 @@ 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),
|
||||||
|
// Anonymous structs or unions are visited later after defined.
|
||||||
|
TyKind::AnonStruct(..) | TyKind::AnonUnion(..) => {}
|
||||||
_ => 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
|
||||||
};
|
};
|
||||||
|
|
|
@ -382,6 +382,7 @@ symbols! {
|
||||||
and,
|
and,
|
||||||
and_then,
|
and_then,
|
||||||
anon,
|
anon,
|
||||||
|
anon_adt,
|
||||||
anonymous_lifetime_in_impl_trait,
|
anonymous_lifetime_in_impl_trait,
|
||||||
any,
|
any,
|
||||||
append_const_msg,
|
append_const_msg,
|
||||||
|
|
|
@ -387,7 +387,8 @@ fn encode_ty_name(tcx: TyCtxt<'_>, def_id: DefId) -> String {
|
||||||
| hir::definitions::DefPathData::Use
|
| hir::definitions::DefPathData::Use
|
||||||
| hir::definitions::DefPathData::GlobalAsm
|
| hir::definitions::DefPathData::GlobalAsm
|
||||||
| hir::definitions::DefPathData::MacroNs(..)
|
| hir::definitions::DefPathData::MacroNs(..)
|
||||||
| hir::definitions::DefPathData::LifetimeNs(..) => {
|
| hir::definitions::DefPathData::LifetimeNs(..)
|
||||||
|
| hir::definitions::DefPathData::AnonAdt => {
|
||||||
bug!("encode_ty_name: unexpected `{:?}`", disambiguated_data.data);
|
bug!("encode_ty_name: unexpected `{:?}`", disambiguated_data.data);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -748,7 +748,8 @@ impl<'tcx> Printer<'tcx> for SymbolMangler<'tcx> {
|
||||||
| DefPathData::GlobalAsm
|
| DefPathData::GlobalAsm
|
||||||
| DefPathData::Impl
|
| DefPathData::Impl
|
||||||
| DefPathData::MacroNs(_)
|
| DefPathData::MacroNs(_)
|
||||||
| DefPathData::LifetimeNs(_) => {
|
| DefPathData::LifetimeNs(_)
|
||||||
|
| DefPathData::AnonAdt => {
|
||||||
bug!("symbol_names: unexpected DefPathData: {:?}", disambiguated_data.data)
|
bug!("symbol_names: unexpected DefPathData: {:?}", disambiguated_data.data)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -2212,6 +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 implemented for an anonymous adt
|
||||||
|
// if all of its fields are `Copy` and `Clone`
|
||||||
|
ty::Adt(adt, args) if adt.is_anonymous() => {
|
||||||
|
// (*) binder moved here
|
||||||
|
Where(obligation.predicate.rebind(
|
||||||
|
adt.non_enum_variant().fields.iter().map(|f| f.ty(self.tcx(), args)).collect(),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
ty::Adt(..) | ty::Alias(..) | ty::Param(..) | ty::Placeholder(..) => {
|
ty::Adt(..) | ty::Alias(..) | ty::Param(..) | ty::Placeholder(..) => {
|
||||||
// Fallback to whatever user-defined impls exist in this case.
|
// Fallback to whatever user-defined impls exist in this case.
|
||||||
|
|
|
@ -21,8 +21,7 @@ macro_rules! rtry {
|
||||||
fn representability(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Representability {
|
fn representability(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Representability {
|
||||||
match tcx.def_kind(def_id) {
|
match tcx.def_kind(def_id) {
|
||||||
DefKind::Struct | DefKind::Union | DefKind::Enum => {
|
DefKind::Struct | DefKind::Union | DefKind::Enum => {
|
||||||
let adt_def = tcx.adt_def(def_id);
|
for variant in tcx.adt_def(def_id).variants() {
|
||||||
for variant in adt_def.variants() {
|
|
||||||
for field in variant.fields.iter() {
|
for field in variant.fields.iter() {
|
||||||
rtry!(tcx.representability(field.did.expect_local()));
|
rtry!(tcx.representability(field.did.expect_local()));
|
||||||
}
|
}
|
||||||
|
|
|
@ -1892,6 +1892,9 @@ pub(crate) fn clean_ty<'tcx>(ty: &hir::Ty<'tcx>, cx: &mut DocContext<'tcx>) -> T
|
||||||
TyKind::BareFn(barefn) => BareFunction(Box::new(clean_bare_fn_ty(barefn, cx))),
|
TyKind::BareFn(barefn) => BareFunction(Box::new(clean_bare_fn_ty(barefn, cx))),
|
||||||
// Rustdoc handles `TyKind::Err`s by turning them into `Type::Infer`s.
|
// Rustdoc handles `TyKind::Err`s by turning them into `Type::Infer`s.
|
||||||
TyKind::Infer | TyKind::Err(_) | TyKind::Typeof(..) | TyKind::InferDelegation(..) => Infer,
|
TyKind::Infer | TyKind::Err(_) | TyKind::Typeof(..) | TyKind::InferDelegation(..) => Infer,
|
||||||
|
TyKind::AnonAdt(..) => {
|
||||||
|
unimplemented!("Anonymous structs or unions are not supported yet")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -831,6 +831,7 @@ impl TyCoercionStability {
|
||||||
| TyKind::Typeof(..)
|
| TyKind::Typeof(..)
|
||||||
| TyKind::TraitObject(..)
|
| TyKind::TraitObject(..)
|
||||||
| TyKind::InferDelegation(..)
|
| TyKind::InferDelegation(..)
|
||||||
|
| TyKind::AnonAdt(..)
|
||||||
| TyKind::Err(_) => Self::Reborrow,
|
| TyKind::Err(_) => Self::Reborrow,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -515,6 +515,7 @@ impl HirEqInterExpr<'_, '_, '_> {
|
||||||
(TyKind::Path(l), TyKind::Path(r)) => self.eq_qpath(l, r),
|
(TyKind::Path(l), TyKind::Path(r)) => self.eq_qpath(l, r),
|
||||||
(&TyKind::Tup(l), &TyKind::Tup(r)) => over(l, r, |l, r| self.eq_ty(l, r)),
|
(&TyKind::Tup(l), &TyKind::Tup(r)) => over(l, r, |l, r| self.eq_ty(l, r)),
|
||||||
(&TyKind::Infer, &TyKind::Infer) => true,
|
(&TyKind::Infer, &TyKind::Infer) => true,
|
||||||
|
(TyKind::AnonAdt(l_item_id), TyKind::AnonAdt(r_item_id)) => l_item_id == r_item_id,
|
||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1108,7 +1109,7 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
|
||||||
TyKind::Typeof(anon_const) => {
|
TyKind::Typeof(anon_const) => {
|
||||||
self.hash_body(anon_const.body);
|
self.hash_body(anon_const.body);
|
||||||
},
|
},
|
||||||
TyKind::Err(_) | TyKind::Infer | TyKind::Never | TyKind::InferDelegation(..) => {},
|
TyKind::Err(_) | TyKind::Infer | TyKind::Never | TyKind::InferDelegation(..) | TyKind::AnonAdt(_) => {},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -806,8 +806,8 @@ impl Rewrite for ast::Ty {
|
||||||
ast::TyKind::Tup(ref items) => {
|
ast::TyKind::Tup(ref items) => {
|
||||||
rewrite_tuple(context, items.iter(), self.span, shape, items.len() == 1)
|
rewrite_tuple(context, items.iter(), self.span, shape, items.len() == 1)
|
||||||
}
|
}
|
||||||
ast::TyKind::AnonStruct(_) => Some(context.snippet(self.span).to_owned()),
|
ast::TyKind::AnonStruct(..) => Some(context.snippet(self.span).to_owned()),
|
||||||
ast::TyKind::AnonUnion(_) => Some(context.snippet(self.span).to_owned()),
|
ast::TyKind::AnonUnion(..) => Some(context.snippet(self.span).to_owned()),
|
||||||
ast::TyKind::Path(ref q_self, ref path) => {
|
ast::TyKind::Path(ref q_self, ref path) => {
|
||||||
rewrite_path(context, PathContext::Type, q_self, path, shape)
|
rewrite_path(context, PathContext::Type, q_self, path, shape)
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,4 +16,16 @@ struct Foo {
|
||||||
e: f32,
|
e: f32,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Test for https://github.com/rust-lang/rust/issues/117942
|
||||||
|
struct Foo {
|
||||||
|
_: union {
|
||||||
|
#[rustfmt::skip]
|
||||||
|
f: String,
|
||||||
|
},
|
||||||
|
#[rustfmt::skip]
|
||||||
|
_: struct {
|
||||||
|
g: i32,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
fn main() {}
|
fn main() {}
|
||||||
|
|
|
@ -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#1}).0: Bar::{anon_adt#1}::{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#1}).0: Foo::{anon_adt#1}::{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() {}
|
|
@ -1,24 +1,27 @@
|
||||||
|
#[repr(C)]
|
||||||
struct Foo {
|
struct Foo {
|
||||||
foo: u8,
|
foo: u8,
|
||||||
_: union { //~ ERROR unnamed fields are not yet fully implemented [E0658]
|
_: union { //~ ERROR unnamed fields are not yet fully implemented [E0658]
|
||||||
//~^ ERROR unnamed fields are not yet fully implemented [E0658]
|
//~^ ERROR unnamed fields are not yet fully implemented [E0658]
|
||||||
//~| ERROR anonymous unions are unimplemented
|
|
||||||
bar: u8,
|
bar: u8,
|
||||||
baz: u16
|
baz: u16
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
union Bar {
|
union Bar {
|
||||||
foobar: u8,
|
foobar: u8,
|
||||||
_: struct { //~ ERROR unnamed fields are not yet fully implemented [E0658]
|
_: struct { //~ ERROR unnamed fields are not yet fully implemented [E0658]
|
||||||
//~^ ERROR unnamed fields are not yet fully implemented [E0658]
|
//~^ ERROR unnamed fields are not yet fully implemented [E0658]
|
||||||
//~| ERROR anonymous structs are unimplemented
|
|
||||||
foobaz: u8,
|
foobaz: u8,
|
||||||
barbaz: u16
|
barbaz: u16
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
struct S;
|
struct S;
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
struct Baz {
|
struct Baz {
|
||||||
_: S //~ ERROR unnamed fields are not yet fully implemented [E0658]
|
_: S //~ ERROR unnamed fields are not yet fully implemented [E0658]
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
error[E0658]: unnamed fields are not yet fully implemented
|
error[E0658]: unnamed fields are not yet fully implemented
|
||||||
--> $DIR/feature-gate-unnamed_fields.rs:3:5
|
--> $DIR/feature-gate-unnamed_fields.rs:4:5
|
||||||
|
|
|
|
||||||
LL | _: union {
|
LL | _: union {
|
||||||
| ^
|
| ^
|
||||||
|
@ -9,12 +9,11 @@ LL | _: union {
|
||||||
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
|
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
|
||||||
|
|
||||||
error[E0658]: unnamed fields are not yet fully implemented
|
error[E0658]: unnamed fields are not yet fully implemented
|
||||||
--> $DIR/feature-gate-unnamed_fields.rs:3:8
|
--> $DIR/feature-gate-unnamed_fields.rs:4:8
|
||||||
|
|
|
|
||||||
LL | _: union {
|
LL | _: union {
|
||||||
| ________^
|
| ________^
|
||||||
LL | |
|
LL | |
|
||||||
LL | |
|
|
||||||
LL | | bar: u8,
|
LL | | bar: u8,
|
||||||
LL | | baz: u16
|
LL | | baz: u16
|
||||||
LL | | }
|
LL | | }
|
||||||
|
@ -25,7 +24,7 @@ LL | | }
|
||||||
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
|
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
|
||||||
|
|
||||||
error[E0658]: unnamed fields are not yet fully implemented
|
error[E0658]: unnamed fields are not yet fully implemented
|
||||||
--> $DIR/feature-gate-unnamed_fields.rs:13:5
|
--> $DIR/feature-gate-unnamed_fields.rs:14:5
|
||||||
|
|
|
|
||||||
LL | _: struct {
|
LL | _: struct {
|
||||||
| ^
|
| ^
|
||||||
|
@ -35,12 +34,11 @@ LL | _: struct {
|
||||||
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
|
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
|
||||||
|
|
||||||
error[E0658]: unnamed fields are not yet fully implemented
|
error[E0658]: unnamed fields are not yet fully implemented
|
||||||
--> $DIR/feature-gate-unnamed_fields.rs:13:8
|
--> $DIR/feature-gate-unnamed_fields.rs:14:8
|
||||||
|
|
|
|
||||||
LL | _: struct {
|
LL | _: struct {
|
||||||
| ________^
|
| ________^
|
||||||
LL | |
|
LL | |
|
||||||
LL | |
|
|
||||||
LL | | foobaz: u8,
|
LL | | foobaz: u8,
|
||||||
LL | | barbaz: u16
|
LL | | barbaz: u16
|
||||||
LL | | }
|
LL | | }
|
||||||
|
@ -51,7 +49,7 @@ LL | | }
|
||||||
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
|
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
|
||||||
|
|
||||||
error[E0658]: unnamed fields are not yet fully implemented
|
error[E0658]: unnamed fields are not yet fully implemented
|
||||||
--> $DIR/feature-gate-unnamed_fields.rs:23:5
|
--> $DIR/feature-gate-unnamed_fields.rs:26:5
|
||||||
|
|
|
|
||||||
LL | _: S
|
LL | _: S
|
||||||
| ^
|
| ^
|
||||||
|
@ -60,30 +58,6 @@ LL | _: S
|
||||||
= help: add `#![feature(unnamed_fields)]` to the crate attributes to enable
|
= help: add `#![feature(unnamed_fields)]` to the crate attributes to enable
|
||||||
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
|
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
|
||||||
|
|
||||||
error: anonymous unions are unimplemented
|
error: aborting due to 5 previous errors
|
||||||
--> $DIR/feature-gate-unnamed_fields.rs:3:8
|
|
||||||
|
|
|
||||||
LL | _: union {
|
|
||||||
| ________^
|
|
||||||
LL | |
|
|
||||||
LL | |
|
|
||||||
LL | | bar: u8,
|
|
||||||
LL | | baz: u16
|
|
||||||
LL | | }
|
|
||||||
| |_____^
|
|
||||||
|
|
||||||
error: anonymous structs are unimplemented
|
|
||||||
--> $DIR/feature-gate-unnamed_fields.rs:13:8
|
|
||||||
|
|
|
||||||
LL | _: struct {
|
|
||||||
| ________^
|
|
||||||
LL | |
|
|
||||||
LL | |
|
|
||||||
LL | | foobaz: u8,
|
|
||||||
LL | | barbaz: u16
|
|
||||||
LL | | }
|
|
||||||
| |_____^
|
|
||||||
|
|
||||||
error: aborting due to 7 previous errors
|
|
||||||
|
|
||||||
For more information about this error, try `rustc --explain E0658`.
|
For more information about this error, try `rustc --explain E0658`.
|
||||||
|
|
337
tests/ui/union/unnamed-fields/field_uniqueness_check.rs
Normal file
337
tests/ui/union/unnamed-fields/field_uniqueness_check.rs
Normal file
|
@ -0,0 +1,337 @@
|
||||||
|
#![allow(incomplete_features)]
|
||||||
|
#![feature(unnamed_fields)]
|
||||||
|
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
|
#[repr(C)]
|
||||||
|
struct Foo {
|
||||||
|
a: u8,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
|
#[repr(C)]
|
||||||
|
struct Bar {
|
||||||
|
_: union {
|
||||||
|
a: u8,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// duplicated with a normal field
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
|
#[repr(C)]
|
||||||
|
union A {
|
||||||
|
// referent field
|
||||||
|
a: u8,
|
||||||
|
|
||||||
|
// normal field
|
||||||
|
a: u8, //~ ERROR field `a` is already declared [E0124]
|
||||||
|
// nested field
|
||||||
|
_: struct {
|
||||||
|
a: u8, //~ ERROR field `a` is already declared [E0124]
|
||||||
|
a: u8, //~ ERROR field `a` is already declared [E0124]
|
||||||
|
},
|
||||||
|
// more nested field
|
||||||
|
_: union {
|
||||||
|
_: struct {
|
||||||
|
a: u8, //~ ERROR field `a` is already declared [E0124]
|
||||||
|
},
|
||||||
|
},
|
||||||
|
// nested field in a named adt
|
||||||
|
_: Foo, //~ ERROR field `a` is already declared
|
||||||
|
_: Bar, //~ ERROR field `a` is already declared
|
||||||
|
// nested field in a named adt in an anoymous adt
|
||||||
|
_: struct {
|
||||||
|
_: Foo, //~ ERROR field `a` is already declared
|
||||||
|
_: Bar, //~ ERROR field `a` is already declared
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
// duplicated with a nested field
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
|
#[repr(C)]
|
||||||
|
struct B {
|
||||||
|
_: union {
|
||||||
|
// referent field
|
||||||
|
a: u8,
|
||||||
|
|
||||||
|
// normal field (within the same anonymous adt)
|
||||||
|
a: u8, //~ ERROR field `a` is already declared [E0124]
|
||||||
|
// nested field (within the same anonymous adt)
|
||||||
|
_: struct {
|
||||||
|
a: u8, //~ ERROR field `a` is already declared [E0124]
|
||||||
|
},
|
||||||
|
// more nested field (within the same anonymous adt)
|
||||||
|
_: union {
|
||||||
|
_: struct {
|
||||||
|
a: u8, //~ ERROR field `a` is already declared [E0124]
|
||||||
|
},
|
||||||
|
},
|
||||||
|
// nested field in a named adt (within the same anonymous adt)
|
||||||
|
_: Foo, //~ ERROR field `a` is already declared
|
||||||
|
_: Bar, //~ ERROR field `a` is already declared
|
||||||
|
// nested field in a named adt in an anoymous adt (within the same anonymous adt)
|
||||||
|
_: struct {
|
||||||
|
_: Foo, //~ ERROR field `a` is already declared
|
||||||
|
_: Bar, //~ ERROR field `a` is already declared
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
// normal field
|
||||||
|
a: u8, //~ ERROR field `a` is already declared [E0124]
|
||||||
|
// nested field
|
||||||
|
_: struct {
|
||||||
|
a: u8, //~ ERROR field `a` is already declared [E0124]
|
||||||
|
},
|
||||||
|
// more nested field
|
||||||
|
_: union {
|
||||||
|
_: struct {
|
||||||
|
a: u8, //~ ERROR field `a` is already declared [E0124]
|
||||||
|
},
|
||||||
|
},
|
||||||
|
// nested field in a named adt
|
||||||
|
_: Foo, //~ ERROR field `a` is already declared
|
||||||
|
_: Bar, //~ ERROR field `a` is already declared
|
||||||
|
// nested field in a named adt in an anoymous adt
|
||||||
|
_: struct {
|
||||||
|
_: Foo, //~ ERROR field `a` is already declared
|
||||||
|
_: Bar, //~ ERROR field `a` is already declared
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
// duplicated with a more nested field
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
|
#[repr(C)]
|
||||||
|
union C {
|
||||||
|
_: struct {
|
||||||
|
_: union {
|
||||||
|
// referent field
|
||||||
|
a: u8,
|
||||||
|
|
||||||
|
// normal field (within the same anonymous adt)
|
||||||
|
a: u8, //~ ERROR field `a` is already declared [E0124]
|
||||||
|
// nested field (within the same anonymous adt)
|
||||||
|
_: struct {
|
||||||
|
a: u8, //~ ERROR field `a` is already declared [E0124]
|
||||||
|
},
|
||||||
|
// more nested field (within the same anonymous adt)
|
||||||
|
_: union {
|
||||||
|
_: struct {
|
||||||
|
a: u8, //~ ERROR field `a` is already declared [E0124]
|
||||||
|
},
|
||||||
|
},
|
||||||
|
// nested field in a named adt (within the same anonymous adt)
|
||||||
|
_: Foo, //~ ERROR field `a` is already declared
|
||||||
|
_: Bar, //~ ERROR field `a` is already declared
|
||||||
|
// nested field in a named adt in an anoymous adt (within the same anonymous adt)
|
||||||
|
_: struct {
|
||||||
|
_: Foo, //~ ERROR field `a` is already declared
|
||||||
|
_: Bar, //~ ERROR field `a` is already declared
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
// normal field (within the direct outer anonymous adt)
|
||||||
|
a: u8, //~ ERROR field `a` is already declared [E0124]
|
||||||
|
// nested field (within the direct outer anonymous adt)
|
||||||
|
_: struct {
|
||||||
|
a: u8, //~ ERROR field `a` is already declared [E0124]
|
||||||
|
},
|
||||||
|
// more nested field (within the direct outer anonymous adt)
|
||||||
|
_: union {
|
||||||
|
_: struct {
|
||||||
|
a: u8, //~ ERROR field `a` is already declared [E0124]
|
||||||
|
},
|
||||||
|
},
|
||||||
|
// nested field in a named adt (within the direct outer anonymous adt)
|
||||||
|
_: Foo, //~ ERROR field `a` is already declared
|
||||||
|
_: Bar, //~ ERROR field `a` is already declared
|
||||||
|
// nested field in a named adt in an anoymous adt (within the direct outer anonymous adt)
|
||||||
|
_: struct {
|
||||||
|
_: Foo, //~ ERROR field `a` is already declared
|
||||||
|
_: Bar, //~ ERROR field `a` is already declared
|
||||||
|
},
|
||||||
|
},
|
||||||
|
// normal field
|
||||||
|
a: u8, //~ ERROR field `a` is already declared [E0124]
|
||||||
|
// nested field
|
||||||
|
_: union {
|
||||||
|
a: u8, //~ ERROR field `a` is already declared [E0124]
|
||||||
|
},
|
||||||
|
// more nested field
|
||||||
|
_: struct {
|
||||||
|
_: union {
|
||||||
|
a: u8, //~ ERROR field `a` is already declared [E0124]
|
||||||
|
},
|
||||||
|
},
|
||||||
|
// nested field in a named adt
|
||||||
|
_: Foo, //~ ERROR field `a` is already declared
|
||||||
|
_: Bar, //~ ERROR field `a` is already declared
|
||||||
|
// nested field in a named adt in an anoymous adt
|
||||||
|
_: union {
|
||||||
|
_: Foo, //~ ERROR field `a` is already declared
|
||||||
|
_: Bar, //~ ERROR field `a` is already declared
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
// duplicated with a nested field in a named adt
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
|
#[repr(C)]
|
||||||
|
struct D {
|
||||||
|
// referent field `a`
|
||||||
|
_: Foo,
|
||||||
|
|
||||||
|
// normal field
|
||||||
|
a: u8, //~ ERROR field `a` is already declared
|
||||||
|
// nested field
|
||||||
|
_: union {
|
||||||
|
a: u8, //~ ERROR field `a` is already declared
|
||||||
|
},
|
||||||
|
// more nested field
|
||||||
|
_: struct {
|
||||||
|
_: union {
|
||||||
|
a: u8, //~ ERROR field `a` is already declared
|
||||||
|
},
|
||||||
|
},
|
||||||
|
// nested field in another named adt
|
||||||
|
_: Foo, //~ ERROR field `a` is already declared
|
||||||
|
_: Bar, //~ ERROR field `a` is already declared
|
||||||
|
// nested field in a named adt in an anoymous adt
|
||||||
|
_: union {
|
||||||
|
_: Foo, //~ ERROR field `a` is already declared
|
||||||
|
_: Bar, //~ ERROR field `a` is already declared
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
// duplicated with a nested field in a nested field of a named adt
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
|
#[repr(C)]
|
||||||
|
union D2 {
|
||||||
|
// referent field `a`
|
||||||
|
_: Bar,
|
||||||
|
|
||||||
|
// normal field
|
||||||
|
a: u8, //~ ERROR field `a` is already declared
|
||||||
|
// nested field
|
||||||
|
_: union {
|
||||||
|
a: u8, //~ ERROR field `a` is already declared
|
||||||
|
},
|
||||||
|
// more nested field
|
||||||
|
_: struct {
|
||||||
|
_: union {
|
||||||
|
a: u8, //~ ERROR field `a` is already declared
|
||||||
|
},
|
||||||
|
},
|
||||||
|
// nested field in another named adt
|
||||||
|
_: Foo, //~ ERROR field `a` is already declared
|
||||||
|
_: Bar, //~ ERROR field `a` is already declared
|
||||||
|
// nested field in a named adt in an anoymous adt
|
||||||
|
_: union {
|
||||||
|
_: Foo, //~ ERROR field `a` is already declared
|
||||||
|
_: Bar, //~ ERROR field `a` is already declared
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
// duplicated with a nested field in a named adt in an anonymous adt
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
|
#[repr(C)]
|
||||||
|
struct E {
|
||||||
|
_: struct {
|
||||||
|
// referent field `a`
|
||||||
|
_: Foo,
|
||||||
|
|
||||||
|
// normal field (within the same anonymous adt)
|
||||||
|
a: u8, //~ ERROR field `a` is already declared
|
||||||
|
// nested field (within the same anonymous adt)
|
||||||
|
_: struct {
|
||||||
|
a: u8, //~ ERROR field `a` is already declared
|
||||||
|
},
|
||||||
|
// more nested field (within the same anonymous adt)
|
||||||
|
_: union {
|
||||||
|
_: struct {
|
||||||
|
a: u8, //~ ERROR field `a` is already declared
|
||||||
|
},
|
||||||
|
},
|
||||||
|
// nested field in a named adt (within the same anonymous adt)
|
||||||
|
_: Foo, //~ ERROR field `a` is already declared
|
||||||
|
_: Bar, //~ ERROR field `a` is already declared
|
||||||
|
// nested field in a named adt in an anoymous adt (within the same anonymous adt)
|
||||||
|
_: struct {
|
||||||
|
_: Foo, //~ ERROR field `a` is already declared
|
||||||
|
_: Bar, //~ ERROR field `a` is already declared
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
// normal field
|
||||||
|
a: u8, //~ ERROR field `a` is already declared
|
||||||
|
// nested field
|
||||||
|
_: union {
|
||||||
|
a: u8, //~ ERROR field `a` is already declared
|
||||||
|
},
|
||||||
|
// more nested field
|
||||||
|
_: struct {
|
||||||
|
_: union {
|
||||||
|
a: u8, //~ ERROR field `a` is already declared
|
||||||
|
},
|
||||||
|
},
|
||||||
|
// nested field in another named adt
|
||||||
|
_: Foo, //~ ERROR field `a` is already declared
|
||||||
|
_: Bar, //~ ERROR field `a` is already declared
|
||||||
|
// nested field in a named adt in an anoymous adt
|
||||||
|
_: union {
|
||||||
|
_: Foo, //~ ERROR field `a` is already declared
|
||||||
|
_: Bar, //~ ERROR field `a` is already declared
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
// duplicated with a nested field in a named adt in an anonymous adt
|
||||||
|
#[repr(C)]
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
|
union E2 {
|
||||||
|
_: struct {
|
||||||
|
// referent field `a`
|
||||||
|
_: Bar,
|
||||||
|
|
||||||
|
// normal field (within the same anonymous adt)
|
||||||
|
a: u8, //~ ERROR field `a` is already declared
|
||||||
|
// nested field (within the same anonymous adt)
|
||||||
|
_: struct {
|
||||||
|
a: u8, //~ ERROR field `a` is already declared
|
||||||
|
},
|
||||||
|
// more nested field (within the same anonymous adt)
|
||||||
|
_: union {
|
||||||
|
_: struct {
|
||||||
|
a: u8, //~ ERROR field `a` is already declared
|
||||||
|
},
|
||||||
|
},
|
||||||
|
// nested field in a named adt (within the same anonymous adt)
|
||||||
|
_: Foo, //~ ERROR field `a` is already declared
|
||||||
|
_: Bar, //~ ERROR field `a` is already declared
|
||||||
|
// nested field in a named adt in an anoymous adt (within the same anonymous adt)
|
||||||
|
_: struct {
|
||||||
|
_: Foo, //~ ERROR field `a` is already declared
|
||||||
|
_: Bar, //~ ERROR field `a` is already declared
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
// normal field
|
||||||
|
a: u8, //~ ERROR field `a` is already declared
|
||||||
|
// nested field
|
||||||
|
_: union {
|
||||||
|
a: u8, //~ ERROR field `a` is already declared
|
||||||
|
},
|
||||||
|
// more nested field
|
||||||
|
_: struct {
|
||||||
|
_: union {
|
||||||
|
a: u8, //~ ERROR field `a` is already declared
|
||||||
|
},
|
||||||
|
},
|
||||||
|
// nested field in another named adt
|
||||||
|
_: Foo, //~ ERROR field `a` is already declared
|
||||||
|
_: Bar, //~ ERROR field `a` is already declared
|
||||||
|
// nested field in a named adt in an anoymous adt
|
||||||
|
_: union {
|
||||||
|
_: Foo, //~ ERROR field `a` is already declared
|
||||||
|
_: Bar, //~ ERROR field `a` is already declared
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
1734
tests/ui/union/unnamed-fields/field_uniqueness_check.stderr
Normal file
1734
tests/ui/union/unnamed-fields/field_uniqueness_check.stderr
Normal file
File diff suppressed because it is too large
Load diff
69
tests/ui/union/unnamed-fields/repr_check.rs
Normal file
69
tests/ui/union/unnamed-fields/repr_check.rs
Normal file
|
@ -0,0 +1,69 @@
|
||||||
|
#![allow(incomplete_features)]
|
||||||
|
#![feature(unnamed_fields)]
|
||||||
|
|
||||||
|
struct A { //~ ERROR struct with unnamed fields must have `#[repr(C)]` representation
|
||||||
|
//~^ NOTE struct `A` defined here
|
||||||
|
_: struct { //~ NOTE unnamed field defined here
|
||||||
|
a: i32,
|
||||||
|
},
|
||||||
|
_: struct { //~ NOTE unnamed field defined here
|
||||||
|
_: struct {
|
||||||
|
b: i32,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
union B { //~ ERROR union with unnamed fields must have `#[repr(C)]` representation
|
||||||
|
//~^ NOTE union `B` defined here
|
||||||
|
_: union { //~ NOTE unnamed field defined here
|
||||||
|
a: i32,
|
||||||
|
},
|
||||||
|
_: union { //~ NOTE unnamed field defined here
|
||||||
|
_: union {
|
||||||
|
b: i32,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
|
#[repr(C)]
|
||||||
|
struct Foo {}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
|
struct Bar {}
|
||||||
|
//~^ `Bar` defined here
|
||||||
|
//~| `Bar` defined here
|
||||||
|
//~| `Bar` defined here
|
||||||
|
//~| `Bar` defined here
|
||||||
|
|
||||||
|
struct C { //~ ERROR struct with unnamed fields must have `#[repr(C)]` representation
|
||||||
|
//~^ NOTE struct `C` defined here
|
||||||
|
_: Foo, //~ NOTE unnamed field defined here
|
||||||
|
}
|
||||||
|
|
||||||
|
union D { //~ ERROR union with unnamed fields must have `#[repr(C)]` representation
|
||||||
|
//~^ NOTE union `D` defined here
|
||||||
|
_: Foo, //~ NOTE unnamed field defined here
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
struct E {
|
||||||
|
_: Bar, //~ ERROR named type of unnamed field must have `#[repr(C)]` representation
|
||||||
|
//~^ NOTE unnamed field defined here
|
||||||
|
_: struct {
|
||||||
|
_: Bar, //~ ERROR named type of unnamed field must have `#[repr(C)]` representation
|
||||||
|
//~^ NOTE unnamed field defined here
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
union F {
|
||||||
|
_: Bar, //~ ERROR named type of unnamed field must have `#[repr(C)]` representation
|
||||||
|
//~^ NOTE unnamed field defined here
|
||||||
|
_: union {
|
||||||
|
_: Bar, //~ ERROR named type of unnamed field must have `#[repr(C)]` representation
|
||||||
|
//~^ NOTE unnamed field defined here
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
152
tests/ui/union/unnamed-fields/repr_check.stderr
Normal file
152
tests/ui/union/unnamed-fields/repr_check.stderr
Normal file
|
@ -0,0 +1,152 @@
|
||||||
|
error: struct with unnamed fields must have `#[repr(C)]` representation
|
||||||
|
--> $DIR/repr_check.rs:4:1
|
||||||
|
|
|
||||||
|
LL | struct A {
|
||||||
|
| ^^^^^^^^ struct `A` defined here
|
||||||
|
|
|
||||||
|
note: unnamed field defined here
|
||||||
|
--> $DIR/repr_check.rs:6:5
|
||||||
|
|
|
||||||
|
LL | / _: struct {
|
||||||
|
LL | | a: i32,
|
||||||
|
LL | | },
|
||||||
|
| |_____^
|
||||||
|
note: unnamed field defined here
|
||||||
|
--> $DIR/repr_check.rs:9:5
|
||||||
|
|
|
||||||
|
LL | / _: struct {
|
||||||
|
LL | | _: struct {
|
||||||
|
LL | | b: i32,
|
||||||
|
LL | | },
|
||||||
|
LL | | },
|
||||||
|
| |_____^
|
||||||
|
help: add `#[repr(C)]` to this struct
|
||||||
|
|
|
||||||
|
LL + #[repr(C)]
|
||||||
|
LL | struct A {
|
||||||
|
|
|
||||||
|
|
||||||
|
error: union with unnamed fields must have `#[repr(C)]` representation
|
||||||
|
--> $DIR/repr_check.rs:16:1
|
||||||
|
|
|
||||||
|
LL | union B {
|
||||||
|
| ^^^^^^^ union `B` defined here
|
||||||
|
|
|
||||||
|
note: unnamed field defined here
|
||||||
|
--> $DIR/repr_check.rs:18:5
|
||||||
|
|
|
||||||
|
LL | / _: union {
|
||||||
|
LL | | a: i32,
|
||||||
|
LL | | },
|
||||||
|
| |_____^
|
||||||
|
note: unnamed field defined here
|
||||||
|
--> $DIR/repr_check.rs:21:5
|
||||||
|
|
|
||||||
|
LL | / _: union {
|
||||||
|
LL | | _: union {
|
||||||
|
LL | | b: i32,
|
||||||
|
LL | | },
|
||||||
|
LL | | },
|
||||||
|
| |_____^
|
||||||
|
help: add `#[repr(C)]` to this union
|
||||||
|
|
|
||||||
|
LL + #[repr(C)]
|
||||||
|
LL | union B {
|
||||||
|
|
|
||||||
|
|
||||||
|
error: struct with unnamed fields must have `#[repr(C)]` representation
|
||||||
|
--> $DIR/repr_check.rs:39:1
|
||||||
|
|
|
||||||
|
LL | struct C {
|
||||||
|
| ^^^^^^^^ struct `C` defined here
|
||||||
|
|
|
||||||
|
note: unnamed field defined here
|
||||||
|
--> $DIR/repr_check.rs:41:5
|
||||||
|
|
|
||||||
|
LL | _: Foo,
|
||||||
|
| ^^^^^^
|
||||||
|
help: add `#[repr(C)]` to this struct
|
||||||
|
|
|
||||||
|
LL + #[repr(C)]
|
||||||
|
LL | struct C {
|
||||||
|
|
|
||||||
|
|
||||||
|
error: union with unnamed fields must have `#[repr(C)]` representation
|
||||||
|
--> $DIR/repr_check.rs:44:1
|
||||||
|
|
|
||||||
|
LL | union D {
|
||||||
|
| ^^^^^^^ union `D` defined here
|
||||||
|
|
|
||||||
|
note: unnamed field defined here
|
||||||
|
--> $DIR/repr_check.rs:46:5
|
||||||
|
|
|
||||||
|
LL | _: Foo,
|
||||||
|
| ^^^^^^
|
||||||
|
help: add `#[repr(C)]` to this union
|
||||||
|
|
|
||||||
|
LL + #[repr(C)]
|
||||||
|
LL | union D {
|
||||||
|
|
|
||||||
|
|
||||||
|
error: named type of unnamed field must have `#[repr(C)]` representation
|
||||||
|
--> $DIR/repr_check.rs:51:5
|
||||||
|
|
|
||||||
|
LL | struct Bar {}
|
||||||
|
| ---------- `Bar` defined here
|
||||||
|
...
|
||||||
|
LL | _: Bar,
|
||||||
|
| ^^^^^^ unnamed field defined here
|
||||||
|
|
|
||||||
|
help: add `#[repr(C)]` to this struct
|
||||||
|
|
|
||||||
|
LL + #[repr(C)]
|
||||||
|
LL | struct Bar {}
|
||||||
|
|
|
||||||
|
|
||||||
|
error: named type of unnamed field must have `#[repr(C)]` representation
|
||||||
|
--> $DIR/repr_check.rs:54:9
|
||||||
|
|
|
||||||
|
LL | struct Bar {}
|
||||||
|
| ---------- `Bar` defined here
|
||||||
|
...
|
||||||
|
LL | _: Bar,
|
||||||
|
| ^^^^^^ unnamed field defined here
|
||||||
|
|
|
||||||
|
help: add `#[repr(C)]` to this struct
|
||||||
|
|
|
||||||
|
LL + #[repr(C)]
|
||||||
|
LL | struct Bar {}
|
||||||
|
|
|
||||||
|
|
||||||
|
error: named type of unnamed field must have `#[repr(C)]` representation
|
||||||
|
--> $DIR/repr_check.rs:61:5
|
||||||
|
|
|
||||||
|
LL | struct Bar {}
|
||||||
|
| ---------- `Bar` defined here
|
||||||
|
...
|
||||||
|
LL | _: Bar,
|
||||||
|
| ^^^^^^ unnamed field defined here
|
||||||
|
|
|
||||||
|
help: add `#[repr(C)]` to this struct
|
||||||
|
|
|
||||||
|
LL + #[repr(C)]
|
||||||
|
LL | struct Bar {}
|
||||||
|
|
|
||||||
|
|
||||||
|
error: named type of unnamed field must have `#[repr(C)]` representation
|
||||||
|
--> $DIR/repr_check.rs:64:9
|
||||||
|
|
|
||||||
|
LL | struct Bar {}
|
||||||
|
| ---------- `Bar` defined here
|
||||||
|
...
|
||||||
|
LL | _: Bar,
|
||||||
|
| ^^^^^^ unnamed field defined here
|
||||||
|
|
|
||||||
|
help: add `#[repr(C)]` to this struct
|
||||||
|
|
|
||||||
|
LL + #[repr(C)]
|
||||||
|
LL | struct Bar {}
|
||||||
|
|
|
||||||
|
|
||||||
|
error: aborting due to 8 previous errors
|
||||||
|
|
|
@ -2,10 +2,8 @@
|
||||||
#![feature(unnamed_fields)]
|
#![feature(unnamed_fields)]
|
||||||
|
|
||||||
struct F {
|
struct F {
|
||||||
field: struct { field: u8 }, //~ ERROR anonymous structs are not allowed outside of unnamed struct or union fields
|
field1: struct { field2: u8 }, //~ ERROR anonymous structs are not allowed outside of unnamed struct or union fields
|
||||||
//~^ ERROR anonymous structs are unimplemented
|
_: struct { field3: u8 },
|
||||||
_: struct { field: u8 },
|
|
||||||
//~^ ERROR anonymous structs are unimplemented
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct G {
|
struct G {
|
||||||
|
@ -13,10 +11,8 @@ struct G {
|
||||||
}
|
}
|
||||||
|
|
||||||
union H {
|
union H {
|
||||||
field: struct { field: u8 }, //~ ERROR anonymous structs are not allowed outside of unnamed struct or union fields
|
field1: struct { field2: u8 }, //~ ERROR anonymous structs are not allowed outside of unnamed struct or union fields
|
||||||
//~^ ERROR anonymous structs are unimplemented
|
_: struct { field3: u8 },
|
||||||
_: struct { field: u8 },
|
|
||||||
//~^ ERROR anonymous structs are unimplemented
|
|
||||||
}
|
}
|
||||||
|
|
||||||
union I {
|
union I {
|
||||||
|
@ -27,7 +23,6 @@ enum K {
|
||||||
M {
|
M {
|
||||||
_ : struct { field: u8 }, //~ ERROR anonymous structs are not allowed outside of unnamed struct or union fields
|
_ : struct { field: u8 }, //~ ERROR anonymous structs are not allowed outside of unnamed struct or union fields
|
||||||
//~^ ERROR unnamed fields are not allowed outside of structs or unions
|
//~^ ERROR unnamed fields are not allowed outside of structs or unions
|
||||||
//~| ERROR anonymous structs are unimplemented
|
|
||||||
},
|
},
|
||||||
N {
|
N {
|
||||||
_ : u8, //~ ERROR unnamed fields are not allowed outside of structs or unions
|
_ : u8, //~ ERROR unnamed fields are not allowed outside of structs or unions
|
||||||
|
|
|
@ -1,29 +1,29 @@
|
||||||
error: anonymous structs are not allowed outside of unnamed struct or union fields
|
error: anonymous structs are not allowed outside of unnamed struct or union fields
|
||||||
--> $DIR/restrict_anonymous_structs.rs:5:12
|
--> $DIR/restrict_anonymous_structs.rs:5:13
|
||||||
|
|
|
|
||||||
LL | field: struct { field: u8 },
|
LL | field1: struct { field2: u8 },
|
||||||
| ^^^^^^^^^^^^^^^^^^^^ anonymous struct declared here
|
| ^^^^^^^^^^^^^^^^^^^^^ anonymous struct declared here
|
||||||
|
|
||||||
error: unnamed fields can only have struct or union types
|
error: unnamed fields can only have struct or union types
|
||||||
--> $DIR/restrict_anonymous_structs.rs:12:5
|
--> $DIR/restrict_anonymous_structs.rs:10:5
|
||||||
|
|
|
|
||||||
LL | _: (u8, u8),
|
LL | _: (u8, u8),
|
||||||
| ^ -------- not a struct or union
|
| ^ -------- not a struct or union
|
||||||
|
|
||||||
error: anonymous structs are not allowed outside of unnamed struct or union fields
|
error: anonymous structs are not allowed outside of unnamed struct or union fields
|
||||||
--> $DIR/restrict_anonymous_structs.rs:16:12
|
--> $DIR/restrict_anonymous_structs.rs:14:13
|
||||||
|
|
|
|
||||||
LL | field: struct { field: u8 },
|
LL | field1: struct { field2: u8 },
|
||||||
| ^^^^^^^^^^^^^^^^^^^^ anonymous struct declared here
|
| ^^^^^^^^^^^^^^^^^^^^^ anonymous struct declared here
|
||||||
|
|
||||||
error: unnamed fields can only have struct or union types
|
error: unnamed fields can only have struct or union types
|
||||||
--> $DIR/restrict_anonymous_structs.rs:23:5
|
--> $DIR/restrict_anonymous_structs.rs:19:5
|
||||||
|
|
|
|
||||||
LL | _: (u8, u8),
|
LL | _: (u8, u8),
|
||||||
| ^ -------- not a struct or union
|
| ^ -------- not a struct or union
|
||||||
|
|
||||||
error: unnamed fields are not allowed outside of structs or unions
|
error: unnamed fields are not allowed outside of structs or unions
|
||||||
--> $DIR/restrict_anonymous_structs.rs:28:9
|
--> $DIR/restrict_anonymous_structs.rs:24:9
|
||||||
|
|
|
|
||||||
LL | _ : struct { field: u8 },
|
LL | _ : struct { field: u8 },
|
||||||
| -^^^^^^^^^^^^^^^^^^^^^^^
|
| -^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
@ -31,48 +31,18 @@ LL | _ : struct { field: u8 },
|
||||||
| unnamed field declared here
|
| unnamed field declared here
|
||||||
|
|
||||||
error: anonymous structs are not allowed outside of unnamed struct or union fields
|
error: anonymous structs are not allowed outside of unnamed struct or union fields
|
||||||
--> $DIR/restrict_anonymous_structs.rs:28:13
|
--> $DIR/restrict_anonymous_structs.rs:24:13
|
||||||
|
|
|
|
||||||
LL | _ : struct { field: u8 },
|
LL | _ : struct { field: u8 },
|
||||||
| ^^^^^^^^^^^^^^^^^^^^ anonymous struct declared here
|
| ^^^^^^^^^^^^^^^^^^^^ anonymous struct declared here
|
||||||
|
|
||||||
error: unnamed fields are not allowed outside of structs or unions
|
error: unnamed fields are not allowed outside of structs or unions
|
||||||
--> $DIR/restrict_anonymous_structs.rs:33:9
|
--> $DIR/restrict_anonymous_structs.rs:28:9
|
||||||
|
|
|
|
||||||
LL | _ : u8,
|
LL | _ : u8,
|
||||||
| -^^^^^
|
| -^^^^^
|
||||||
| |
|
| |
|
||||||
| unnamed field declared here
|
| unnamed field declared here
|
||||||
|
|
||||||
error: anonymous structs are unimplemented
|
error: aborting due to 7 previous errors
|
||||||
--> $DIR/restrict_anonymous_structs.rs:5:12
|
|
||||||
|
|
|
||||||
LL | field: struct { field: u8 },
|
|
||||||
| ^^^^^^^^^^^^^^^^^^^^
|
|
||||||
|
|
||||||
error: anonymous structs are unimplemented
|
|
||||||
--> $DIR/restrict_anonymous_structs.rs:7:8
|
|
||||||
|
|
|
||||||
LL | _: struct { field: u8 },
|
|
||||||
| ^^^^^^^^^^^^^^^^^^^^
|
|
||||||
|
|
||||||
error: anonymous structs are unimplemented
|
|
||||||
--> $DIR/restrict_anonymous_structs.rs:16:12
|
|
||||||
|
|
|
||||||
LL | field: struct { field: u8 },
|
|
||||||
| ^^^^^^^^^^^^^^^^^^^^
|
|
||||||
|
|
||||||
error: anonymous structs are unimplemented
|
|
||||||
--> $DIR/restrict_anonymous_structs.rs:18:8
|
|
||||||
|
|
|
||||||
LL | _: struct { field: u8 },
|
|
||||||
| ^^^^^^^^^^^^^^^^^^^^
|
|
||||||
|
|
||||||
error: anonymous structs are unimplemented
|
|
||||||
--> $DIR/restrict_anonymous_structs.rs:28:13
|
|
||||||
|
|
|
||||||
LL | _ : struct { field: u8 },
|
|
||||||
| ^^^^^^^^^^^^^^^^^^^^
|
|
||||||
|
|
||||||
error: aborting due to 12 previous errors
|
|
||||||
|
|
||||||
|
|
|
@ -2,10 +2,8 @@
|
||||||
#![feature(unnamed_fields)]
|
#![feature(unnamed_fields)]
|
||||||
|
|
||||||
struct F {
|
struct F {
|
||||||
field: union { field: u8 }, //~ ERROR anonymous unions are not allowed outside of unnamed struct or union fields
|
field1: union { field2: u8 }, //~ ERROR anonymous unions are not allowed outside of unnamed struct or union fields
|
||||||
//~^ ERROR anonymous unions are unimplemented
|
_: union { field3: u8 },
|
||||||
_: union { field: u8 },
|
|
||||||
//~^ ERROR anonymous unions are unimplemented
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct G {
|
struct G {
|
||||||
|
@ -13,10 +11,8 @@ struct G {
|
||||||
}
|
}
|
||||||
|
|
||||||
union H {
|
union H {
|
||||||
field: union { field: u8 }, //~ ERROR anonymous unions are not allowed outside of unnamed struct or union fields
|
field1: union { field2: u8 }, //~ ERROR anonymous unions are not allowed outside of unnamed struct or union fields
|
||||||
//~^ ERROR anonymous unions are unimplemented
|
_: union { field3: u8 },
|
||||||
_: union { field: u8 },
|
|
||||||
//~^ ERROR anonymous unions are unimplemented
|
|
||||||
}
|
}
|
||||||
|
|
||||||
union I {
|
union I {
|
||||||
|
@ -27,7 +23,6 @@ enum K {
|
||||||
M {
|
M {
|
||||||
_ : union { field: u8 }, //~ ERROR anonymous unions are not allowed outside of unnamed struct or union fields
|
_ : union { field: u8 }, //~ ERROR anonymous unions are not allowed outside of unnamed struct or union fields
|
||||||
//~^ ERROR unnamed fields are not allowed outside of structs or unions
|
//~^ ERROR unnamed fields are not allowed outside of structs or unions
|
||||||
//~| ERROR anonymous unions are unimplemented
|
|
||||||
},
|
},
|
||||||
N {
|
N {
|
||||||
_ : u8, //~ ERROR unnamed fields are not allowed outside of structs or unions
|
_ : u8, //~ ERROR unnamed fields are not allowed outside of structs or unions
|
||||||
|
|
|
@ -1,29 +1,29 @@
|
||||||
error: anonymous unions are not allowed outside of unnamed struct or union fields
|
error: anonymous unions are not allowed outside of unnamed struct or union fields
|
||||||
--> $DIR/restrict_anonymous_unions.rs:5:12
|
--> $DIR/restrict_anonymous_unions.rs:5:13
|
||||||
|
|
|
|
||||||
LL | field: union { field: u8 },
|
LL | field1: union { field2: u8 },
|
||||||
| ^^^^^^^^^^^^^^^^^^^ anonymous union declared here
|
| ^^^^^^^^^^^^^^^^^^^^ anonymous union declared here
|
||||||
|
|
||||||
error: unnamed fields can only have struct or union types
|
error: unnamed fields can only have struct or union types
|
||||||
--> $DIR/restrict_anonymous_unions.rs:12:5
|
--> $DIR/restrict_anonymous_unions.rs:10:5
|
||||||
|
|
|
|
||||||
LL | _: (u8, u8),
|
LL | _: (u8, u8),
|
||||||
| ^ -------- not a struct or union
|
| ^ -------- not a struct or union
|
||||||
|
|
||||||
error: anonymous unions are not allowed outside of unnamed struct or union fields
|
error: anonymous unions are not allowed outside of unnamed struct or union fields
|
||||||
--> $DIR/restrict_anonymous_unions.rs:16:12
|
--> $DIR/restrict_anonymous_unions.rs:14:13
|
||||||
|
|
|
|
||||||
LL | field: union { field: u8 },
|
LL | field1: union { field2: u8 },
|
||||||
| ^^^^^^^^^^^^^^^^^^^ anonymous union declared here
|
| ^^^^^^^^^^^^^^^^^^^^ anonymous union declared here
|
||||||
|
|
||||||
error: unnamed fields can only have struct or union types
|
error: unnamed fields can only have struct or union types
|
||||||
--> $DIR/restrict_anonymous_unions.rs:23:5
|
--> $DIR/restrict_anonymous_unions.rs:19:5
|
||||||
|
|
|
|
||||||
LL | _: (u8, u8),
|
LL | _: (u8, u8),
|
||||||
| ^ -------- not a struct or union
|
| ^ -------- not a struct or union
|
||||||
|
|
||||||
error: unnamed fields are not allowed outside of structs or unions
|
error: unnamed fields are not allowed outside of structs or unions
|
||||||
--> $DIR/restrict_anonymous_unions.rs:28:9
|
--> $DIR/restrict_anonymous_unions.rs:24:9
|
||||||
|
|
|
|
||||||
LL | _ : union { field: u8 },
|
LL | _ : union { field: u8 },
|
||||||
| -^^^^^^^^^^^^^^^^^^^^^^
|
| -^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
@ -31,48 +31,18 @@ LL | _ : union { field: u8 },
|
||||||
| unnamed field declared here
|
| unnamed field declared here
|
||||||
|
|
||||||
error: anonymous unions are not allowed outside of unnamed struct or union fields
|
error: anonymous unions are not allowed outside of unnamed struct or union fields
|
||||||
--> $DIR/restrict_anonymous_unions.rs:28:13
|
--> $DIR/restrict_anonymous_unions.rs:24:13
|
||||||
|
|
|
|
||||||
LL | _ : union { field: u8 },
|
LL | _ : union { field: u8 },
|
||||||
| ^^^^^^^^^^^^^^^^^^^ anonymous union declared here
|
| ^^^^^^^^^^^^^^^^^^^ anonymous union declared here
|
||||||
|
|
||||||
error: unnamed fields are not allowed outside of structs or unions
|
error: unnamed fields are not allowed outside of structs or unions
|
||||||
--> $DIR/restrict_anonymous_unions.rs:33:9
|
--> $DIR/restrict_anonymous_unions.rs:28:9
|
||||||
|
|
|
|
||||||
LL | _ : u8,
|
LL | _ : u8,
|
||||||
| -^^^^^
|
| -^^^^^
|
||||||
| |
|
| |
|
||||||
| unnamed field declared here
|
| unnamed field declared here
|
||||||
|
|
||||||
error: anonymous unions are unimplemented
|
error: aborting due to 7 previous errors
|
||||||
--> $DIR/restrict_anonymous_unions.rs:5:12
|
|
||||||
|
|
|
||||||
LL | field: union { field: u8 },
|
|
||||||
| ^^^^^^^^^^^^^^^^^^^
|
|
||||||
|
|
||||||
error: anonymous unions are unimplemented
|
|
||||||
--> $DIR/restrict_anonymous_unions.rs:7:8
|
|
||||||
|
|
|
||||||
LL | _: union { field: u8 },
|
|
||||||
| ^^^^^^^^^^^^^^^^^^^
|
|
||||||
|
|
||||||
error: anonymous unions are unimplemented
|
|
||||||
--> $DIR/restrict_anonymous_unions.rs:16:12
|
|
||||||
|
|
|
||||||
LL | field: union { field: u8 },
|
|
||||||
| ^^^^^^^^^^^^^^^^^^^
|
|
||||||
|
|
||||||
error: anonymous unions are unimplemented
|
|
||||||
--> $DIR/restrict_anonymous_unions.rs:18:8
|
|
||||||
|
|
|
||||||
LL | _: union { field: u8 },
|
|
||||||
| ^^^^^^^^^^^^^^^^^^^
|
|
||||||
|
|
||||||
error: anonymous unions are unimplemented
|
|
||||||
--> $DIR/restrict_anonymous_unions.rs:28:13
|
|
||||||
|
|
|
||||||
LL | _ : union { field: u8 },
|
|
||||||
| ^^^^^^^^^^^^^^^^^^^
|
|
||||||
|
|
||||||
error: aborting due to 12 previous errors
|
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue