From f2b672d5567c3b20542e845baaf8a9c47d9df907 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Tue, 6 Sep 2016 01:26:02 +0300 Subject: [PATCH 1/2] Refactor `TyStruct`/`TyEnum`/`TyUnion` into `TyAdt` --- src/librustc/infer/error_reporting.rs | 5 +- src/librustc/infer/freshen.rs | 4 +- src/librustc/middle/dead.rs | 23 +- src/librustc/middle/effect.rs | 14 +- src/librustc/middle/expr_use_visitor.rs | 43 +- src/librustc/middle/mem_categorization.rs | 5 +- src/librustc/middle/stability.rs | 62 ++- src/librustc/mir/tcx.rs | 7 +- src/librustc/traits/coherence.rs | 6 +- src/librustc/traits/error_reporting.rs | 38 +- src/librustc/traits/select.rs | 16 +- src/librustc/ty/cast.rs | 2 +- src/librustc/ty/contents.rs | 3 +- src/librustc/ty/context.rs | 22 +- src/librustc/ty/error.rs | 8 +- src/librustc/ty/fast_reject.rs | 14 +- src/librustc/ty/flags.rs | 2 +- src/librustc/ty/item_path.rs | 8 +- src/librustc/ty/layout.rs | 426 +++++++++--------- src/librustc/ty/mod.rs | 44 +- src/librustc/ty/outlives.rs | 4 +- src/librustc/ty/relate.rs | 18 +- src/librustc/ty/structural_impls.rs | 8 +- src/librustc/ty/sty.rs | 43 +- src/librustc/ty/util.rs | 118 ++--- src/librustc/ty/walk.rs | 5 +- src/librustc/ty/wf.rs | 4 +- src/librustc/util/ppaux.rs | 4 +- src/librustc_borrowck/borrowck/check_loans.rs | 4 +- src/librustc_borrowck/borrowck/fragments.rs | 99 ++-- .../borrowck/gather_loans/gather_moves.rs | 2 +- .../borrowck/gather_loans/move_error.rs | 4 +- .../borrowck/gather_loans/restrictions.rs | 9 +- .../borrowck/mir/elaborate_drops.rs | 4 +- src/librustc_borrowck/borrowck/mir/mod.rs | 2 +- src/librustc_borrowck/borrowck/move_data.rs | 57 +-- src/librustc_const_eval/check_match.rs | 39 +- src/librustc_const_eval/eval.rs | 15 +- src/librustc_lint/builtin.rs | 6 +- src/librustc_lint/types.rs | 176 ++++---- src/librustc_lint/unused.rs | 4 +- src/librustc_metadata/decoder.rs | 17 +- src/librustc_metadata/tydecode.rs | 18 +- src/librustc_metadata/tyencode.rs | 12 +- src/librustc_mir/build/expr/as_rvalue.rs | 2 +- src/librustc_mir/hair/cx/expr.rs | 91 ++-- src/librustc_mir/hair/cx/pattern.rs | 10 +- src/librustc_mir/transform/type_check.rs | 16 +- src/librustc_passes/consts.rs | 4 +- src/librustc_privacy/lib.rs | 14 +- src/librustc_save_analysis/dump_visitor.rs | 2 +- src/librustc_save_analysis/lib.rs | 10 +- src/librustc_trans/adt.rs | 300 ++++++------ src/librustc_trans/base.rs | 3 +- src/librustc_trans/collector.rs | 12 +- src/librustc_trans/common.rs | 7 +- src/librustc_trans/context.rs | 10 +- src/librustc_trans/debuginfo/metadata.rs | 58 ++- src/librustc_trans/debuginfo/mod.rs | 2 +- src/librustc_trans/debuginfo/type_names.rs | 4 +- src/librustc_trans/glue.rs | 163 +++---- src/librustc_trans/intrinsic.rs | 2 +- src/librustc_trans/trans_item.rs | 4 +- src/librustc_trans/type_of.rs | 14 +- src/librustc_typeck/check/_match.rs | 6 +- src/librustc_typeck/check/cast.rs | 2 +- src/librustc_typeck/check/dropck.rs | 26 +- src/librustc_typeck/check/method/probe.rs | 4 +- src/librustc_typeck/check/method/suggest.rs | 6 +- src/librustc_typeck/check/mod.rs | 38 +- src/librustc_typeck/coherence/mod.rs | 15 +- src/librustc_typeck/coherence/orphan.rs | 15 +- src/librustc_typeck/collect.rs | 14 +- src/librustc_typeck/variance/constraints.rs | 4 +- src/librustdoc/clean/inline.rs | 2 +- src/librustdoc/clean/mod.rs | 14 +- src/test/run-pass/auxiliary/issue13507.rs | 4 +- 77 files changed, 1087 insertions(+), 1215 deletions(-) diff --git a/src/librustc/infer/error_reporting.rs b/src/librustc/infer/error_reporting.rs index 38f3f055cbb24..b8a3bdfcf2573 100644 --- a/src/librustc/infer/error_reporting.rs +++ b/src/librustc/infer/error_reporting.rs @@ -488,10 +488,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { // if they are both "path types", there's a chance of ambiguity // due to different versions of the same crate match (&exp_found.expected.sty, &exp_found.found.sty) { - (&ty::TyEnum(ref exp_adt, _), &ty::TyEnum(ref found_adt, _)) | - (&ty::TyStruct(ref exp_adt, _), &ty::TyStruct(ref found_adt, _)) | - (&ty::TyEnum(ref exp_adt, _), &ty::TyStruct(ref found_adt, _)) | - (&ty::TyStruct(ref exp_adt, _), &ty::TyEnum(ref found_adt, _)) => { + (&ty::TyAdt(exp_adt, _), &ty::TyAdt(found_adt, _)) => { report_path_match(err, exp_adt.did, found_adt.did); }, _ => () diff --git a/src/librustc/infer/freshen.rs b/src/librustc/infer/freshen.rs index 8aeb0757f5de2..eea12b7f19712 100644 --- a/src/librustc/infer/freshen.rs +++ b/src/librustc/infer/freshen.rs @@ -156,7 +156,7 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for TypeFreshener<'a, 'gcx, 'tcx> { ty::TyInt(..) | ty::TyUint(..) | ty::TyFloat(..) | - ty::TyEnum(..) | + ty::TyAdt(..) | ty::TyBox(..) | ty::TyStr | ty::TyError | @@ -167,8 +167,6 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for TypeFreshener<'a, 'gcx, 'tcx> { ty::TyFnDef(..) | ty::TyFnPtr(_) | ty::TyTrait(..) | - ty::TyStruct(..) | - ty::TyUnion(..) | ty::TyClosure(..) | ty::TyNever | ty::TyTuple(..) | diff --git a/src/librustc/middle/dead.rs b/src/librustc/middle/dead.rs index 26a89feb2181f..9db6ac1dcefd0 100644 --- a/src/librustc/middle/dead.rs +++ b/src/librustc/middle/dead.rs @@ -86,8 +86,6 @@ impl<'a, 'tcx> MarkSymbolVisitor<'a, 'tcx> { } fn lookup_and_handle_definition(&mut self, id: ast::NodeId) { - use ty::TypeVariants::{TyEnum, TyStruct, TyUnion}; - let def = self.tcx.expect_def(id); // If `bar` is a trait item, make sure to mark Foo as alive in `Foo::bar` @@ -95,11 +93,8 @@ impl<'a, 'tcx> MarkSymbolVisitor<'a, 'tcx> { Def::AssociatedTy(..) | Def::Method(_) | Def::AssociatedConst(_) if self.tcx.trait_of_item(def.def_id()).is_some() => { if let Some(substs) = self.tcx.tables.borrow().item_substs.get(&id) { - match substs.substs.type_at(0).sty { - TyEnum(tyid, _) | TyStruct(tyid, _) | TyUnion(tyid, _) => { - self.check_def_id(tyid.did) - } - _ => {} + if let ty::TyAdt(tyid, _) = substs.substs.type_at(0).sty { + self.check_def_id(tyid.did); } } } @@ -133,23 +128,27 @@ impl<'a, 'tcx> MarkSymbolVisitor<'a, 'tcx> { fn handle_field_access(&mut self, lhs: &hir::Expr, name: ast::Name) { match self.tcx.expr_ty_adjusted(lhs).sty { - ty::TyStruct(def, _) | ty::TyUnion(def, _) => { + ty::TyAdt(def, _) => { self.insert_def_id(def.struct_variant().field_named(name).did); } - _ => span_bug!(lhs.span, "named field access on non-struct/union"), + _ => span_bug!(lhs.span, "named field access on non-ADT"), } } fn handle_tup_field_access(&mut self, lhs: &hir::Expr, idx: usize) { - if let ty::TyStruct(def, _) = self.tcx.expr_ty_adjusted(lhs).sty { - self.insert_def_id(def.struct_variant().fields[idx].did); + match self.tcx.expr_ty_adjusted(lhs).sty { + ty::TyAdt(def, _) => { + self.insert_def_id(def.struct_variant().fields[idx].did); + } + ty::TyTuple(..) => {} + _ => span_bug!(lhs.span, "numeric field access on non-ADT"), } } fn handle_field_pattern_match(&mut self, lhs: &hir::Pat, pats: &[codemap::Spanned]) { let variant = match self.tcx.node_id_to_type(lhs.id).sty { - ty::TyStruct(adt, _) | ty::TyUnion(adt, _) | ty::TyEnum(adt, _) => { + ty::TyAdt(adt, _) => { adt.variant_of_def(self.tcx.expect_def(lhs.id)) } _ => span_bug!(lhs.span, "non-ADT in struct pattern") diff --git a/src/librustc/middle/effect.rs b/src/librustc/middle/effect.rs index a7af0b50b8494..8b8d15b0b6ebf 100644 --- a/src/librustc/middle/effect.rs +++ b/src/librustc/middle/effect.rs @@ -178,8 +178,10 @@ impl<'a, 'tcx, 'v> Visitor<'v> for EffectCheckVisitor<'a, 'tcx> { } } hir::ExprField(ref base_expr, field) => { - if let ty::TyUnion(..) = self.tcx.expr_ty_adjusted(base_expr).sty { - self.require_unsafe(field.span, "access to union field"); + if let ty::TyAdt(adt, ..) = self.tcx.expr_ty_adjusted(base_expr).sty { + if adt.is_union() { + self.require_unsafe(field.span, "access to union field"); + } } } _ => {} @@ -190,9 +192,11 @@ impl<'a, 'tcx, 'v> Visitor<'v> for EffectCheckVisitor<'a, 'tcx> { fn visit_pat(&mut self, pat: &hir::Pat) { if let PatKind::Struct(_, ref fields, _) = pat.node { - if let ty::TyUnion(..) = self.tcx.pat_ty(pat).sty { - for field in fields { - self.require_unsafe(field.span, "matching on union field"); + if let ty::TyAdt(adt, ..) = self.tcx.pat_ty(pat).sty { + if adt.is_union() { + for field in fields { + self.require_unsafe(field.span, "matching on union field"); + } } } } diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs index d32954d3800ad..9f05dde4e66f4 100644 --- a/src/librustc/middle/expr_use_visitor.rs +++ b/src/librustc/middle/expr_use_visitor.rs @@ -671,28 +671,31 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { // Select just those fields of the `with` // expression that will actually be used - if let ty::TyStruct(def, substs) = with_cmt.ty.sty { - // Consume those fields of the with expression that are needed. - for with_field in &def.struct_variant().fields { - if !contains_field_named(with_field, fields) { - let cmt_field = self.mc.cat_field( - &*with_expr, - with_cmt.clone(), - with_field.name, - with_field.ty(self.tcx(), substs) - ); - self.delegate_consume(with_expr.id, with_expr.span, cmt_field); + match with_cmt.ty.sty { + ty::TyAdt(adt, substs) if adt.is_struct() => { + // Consume those fields of the with expression that are needed. + for with_field in &adt.struct_variant().fields { + if !contains_field_named(with_field, fields) { + let cmt_field = self.mc.cat_field( + &*with_expr, + with_cmt.clone(), + with_field.name, + with_field.ty(self.tcx(), substs) + ); + self.delegate_consume(with_expr.id, with_expr.span, cmt_field); + } } } - } else { - // the base expression should always evaluate to a - // struct; however, when EUV is run during typeck, it - // may not. This will generate an error earlier in typeck, - // so we can just ignore it. - if !self.tcx().sess.has_errors() { - span_bug!( - with_expr.span, - "with expression doesn't evaluate to a struct"); + _ => { + // the base expression should always evaluate to a + // struct; however, when EUV is run during typeck, it + // may not. This will generate an error earlier in typeck, + // so we can just ignore it. + if !self.tcx().sess.has_errors() { + span_bug!( + with_expr.span, + "with expression doesn't evaluate to a struct"); + } } } diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index f8eb0d4a0ece8..39d5487e8beb1 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -223,8 +223,7 @@ fn deref_kind(t: Ty, context: DerefKindContext) -> McResult { Ok(deref_ptr(UnsafePtr(mt.mutbl))) } - ty::TyEnum(..) | - ty::TyStruct(..) => { // newtype + ty::TyAdt(..) => { // newtype Ok(deref_interior(InteriorField(PositionalField(0)))) } @@ -1154,7 +1153,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { } Def::Struct(..) => { match self.pat_ty(&pat)?.sty { - ty::TyStruct(adt_def, _) => { + ty::TyAdt(adt_def, _) => { adt_def.struct_variant().fields.len() } ref ty => { diff --git a/src/librustc/middle/stability.rs b/src/librustc/middle/stability.rs index c62c99c3b7062..9a56959de38bc 100644 --- a/src/librustc/middle/stability.rs +++ b/src/librustc/middle/stability.rs @@ -20,7 +20,7 @@ use lint; use middle::cstore::LOCAL_CRATE; use hir::def::Def; use hir::def_id::{CRATE_DEF_INDEX, DefId, DefIndex}; -use ty::{self, TyCtxt}; +use ty::{self, TyCtxt, AdtKind}; use middle::privacy::AccessLevels; use syntax::parse::token::InternedString; use syntax_pos::{Span, DUMMY_SP}; @@ -561,17 +561,19 @@ pub fn check_expr<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, e: &hir::Expr, hir::ExprField(ref base_e, ref field) => { span = field.span; match tcx.expr_ty_adjusted(base_e).sty { - ty::TyStruct(def, _) | ty::TyUnion(def, _) => { + ty::TyAdt(def, _) => { def.struct_variant().field_named(field.node).did } _ => span_bug!(e.span, - "stability::check_expr: named field access on non-struct/union") + "stability::check_expr: named field access on non-ADT") } } hir::ExprTupField(ref base_e, ref field) => { span = field.span; match tcx.expr_ty_adjusted(base_e).sty { - ty::TyStruct(def, _) => def.struct_variant().fields[field.node].did, + ty::TyAdt(def, _) => { + def.struct_variant().fields[field.node].did + } ty::TyTuple(..) => return, _ => span_bug!(e.span, "stability::check_expr: unnamed field access on \ @@ -579,31 +581,28 @@ pub fn check_expr<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, e: &hir::Expr, } } hir::ExprStruct(_, ref expr_fields, _) => { - let type_ = tcx.expr_ty(e); - match type_.sty { - ty::TyStruct(def, _) | ty::TyUnion(def, _) => { - // check the stability of each field that appears - // in the construction expression. - for field in expr_fields { - let did = def.struct_variant() - .field_named(field.name.node) - .did; - maybe_do_stability_check(tcx, did, field.span, cb); - } + match tcx.expr_ty(e).sty { + ty::TyAdt(adt, ..) => match adt.adt_kind() { + AdtKind::Struct | AdtKind::Union => { + // check the stability of each field that appears + // in the construction expression. + for field in expr_fields { + let did = adt.struct_variant().field_named(field.name.node).did; + maybe_do_stability_check(tcx, did, field.span, cb); + } - // we're done. - return - } - // we don't look at stability attributes on - // struct-like enums (yet...), but it's definitely not - // a bug to have construct one. - ty::TyEnum(..) => return, - _ => { - span_bug!(e.span, - "stability::check_expr: struct construction \ - of non-struct/union, type {:?}", - type_); - } + // we're done. + return + } + AdtKind::Enum => { + // we don't look at stability attributes on + // struct-like enums (yet...), but it's definitely not + // a bug to have construct one. + return + } + }, + ref ty => span_bug!(e.span, "stability::check_expr: struct \ + construction of non-ADT type: {:?}", ty) } } _ => return @@ -648,10 +647,9 @@ pub fn check_pat<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, pat: &hir::Pat, debug!("check_pat(pat = {:?})", pat); if is_internal(tcx, pat.span) { return; } - let v = match tcx.pat_ty_opt(pat) { - Some(&ty::TyS { sty: ty::TyStruct(def, _), .. }) | - Some(&ty::TyS { sty: ty::TyUnion(def, _), .. }) => def.struct_variant(), - Some(_) | None => return, + let v = match tcx.pat_ty_opt(pat).map(|ty| &ty.sty) { + Some(&ty::TyAdt(adt, _)) if !adt.is_enum() => adt.struct_variant(), + _ => return, }; match pat.node { // Foo(a, b, c) diff --git a/src/librustc/mir/tcx.rs b/src/librustc/mir/tcx.rs index c82e723525b45..74ad6c602f6cd 100644 --- a/src/librustc/mir/tcx.rs +++ b/src/librustc/mir/tcx.rs @@ -40,7 +40,7 @@ impl<'a, 'gcx, 'tcx> LvalueTy<'tcx> { LvalueTy::Ty { ty } => ty, LvalueTy::Downcast { adt_def, substs, variant_index: _ } => - tcx.mk_enum(adt_def, substs), + tcx.mk_adt(adt_def, substs), } } @@ -75,7 +75,8 @@ impl<'a, 'gcx, 'tcx> LvalueTy<'tcx> { } ProjectionElem::Downcast(adt_def1, index) => match self.to_ty(tcx).sty { - ty::TyEnum(adt_def, substs) => { + ty::TyAdt(adt_def, substs) => { + assert!(adt_def.is_enum()); assert!(index < adt_def.variants.len()); assert_eq!(adt_def, adt_def1); LvalueTy::Downcast { adt_def: adt_def, @@ -83,7 +84,7 @@ impl<'a, 'gcx, 'tcx> LvalueTy<'tcx> { variant_index: index } } _ => { - bug!("cannot downcast non-enum type: `{:?}`", self) + bug!("cannot downcast non-ADT type: `{:?}`", self) } }, ProjectionElem::Field(_, fty) => LvalueTy::Ty { ty: fty } diff --git a/src/librustc/traits/coherence.rs b/src/librustc/traits/coherence.rs index 0a7d3e6e76d8f..83774f0cf7ead 100644 --- a/src/librustc/traits/coherence.rs +++ b/src/librustc/traits/coherence.rs @@ -224,7 +224,7 @@ fn fundamental_ty(tcx: TyCtxt, ty: Ty) -> bool { match ty.sty { ty::TyBox(..) | ty::TyRef(..) => true, - ty::TyEnum(def, _) | ty::TyStruct(def, _) | ty::TyUnion(def, _) => + ty::TyAdt(def, _) => def.is_fundamental(), ty::TyTrait(ref data) => tcx.has_attr(data.principal.def_id(), "fundamental"), @@ -260,9 +260,7 @@ fn ty_is_local_constructor(tcx: TyCtxt, ty: Ty, infer_is_local: InferIsLocal)-> infer_is_local.0 } - ty::TyEnum(def, _) | - ty::TyStruct(def, _) | - ty::TyUnion(def, _) => { + ty::TyAdt(def, _) => { def.did.is_local() } diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index e5ebe96932d4f..52ddd8ab5dac0 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -27,7 +27,7 @@ use super::{ use fmt_macros::{Parser, Piece, Position}; use hir::def_id::DefId; use infer::{self, InferCtxt, TypeOrigin}; -use ty::{self, ToPredicate, ToPolyTraitRef, Ty, TyCtxt, TypeFoldable}; +use ty::{self, AdtKind, ToPredicate, ToPolyTraitRef, Ty, TyCtxt, TypeFoldable}; use ty::error::ExpectedFound; use ty::fast_reject; use ty::fold::TypeFolder; @@ -151,32 +151,30 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { ty::TyBool => Some(0), ty::TyChar => Some(1), ty::TyStr => Some(2), - ty::TyInt(..) | ty::TyUint(..) | - ty::TyInfer(ty::IntVar(..)) => Some(3), + ty::TyInt(..) | ty::TyUint(..) | ty::TyInfer(ty::IntVar(..)) => Some(3), ty::TyFloat(..) | ty::TyInfer(ty::FloatVar(..)) => Some(4), - ty::TyEnum(..) => Some(5), - ty::TyStruct(..) => Some(6), - ty::TyBox(..) | ty::TyRef(..) | ty::TyRawPtr(..) => Some(7), - ty::TyArray(..) | ty::TySlice(..) => Some(8), - ty::TyFnDef(..) | ty::TyFnPtr(..) => Some(9), - ty::TyTrait(..) => Some(10), - ty::TyClosure(..) => Some(11), - ty::TyTuple(..) => Some(12), - ty::TyProjection(..) => Some(13), - ty::TyParam(..) => Some(14), - ty::TyAnon(..) => Some(15), - ty::TyNever => Some(16), - ty::TyUnion(..) => Some(17), + ty::TyBox(..) | ty::TyRef(..) | ty::TyRawPtr(..) => Some(5), + ty::TyArray(..) | ty::TySlice(..) => Some(6), + ty::TyFnDef(..) | ty::TyFnPtr(..) => Some(7), + ty::TyTrait(..) => Some(8), + ty::TyClosure(..) => Some(9), + ty::TyTuple(..) => Some(10), + ty::TyProjection(..) => Some(11), + ty::TyParam(..) => Some(12), + ty::TyAnon(..) => Some(13), + ty::TyNever => Some(14), + ty::TyAdt(adt, ..) => match adt.adt_kind() { + AdtKind::Struct => Some(15), + AdtKind::Union => Some(16), + AdtKind::Enum => Some(17), + }, ty::TyInfer(..) | ty::TyError => None } } match (type_category(a), type_category(b)) { (Some(cat_a), Some(cat_b)) => match (&a.sty, &b.sty) { - (&ty::TyStruct(def_a, _), &ty::TyStruct(def_b, _)) | - (&ty::TyUnion(def_a, _), &ty::TyUnion(def_b, _)) | - (&ty::TyEnum(def_a, _), &ty::TyEnum(def_b, _)) => - def_a == def_b, + (&ty::TyAdt(def_a, _), &ty::TyAdt(def_b, _)) => def_a == def_b, _ => cat_a == cat_b }, // infer and error can be equated to all types diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs index 3f2bc8cbd13c5..94dba7d12a8c7 100644 --- a/src/librustc/traits/select.rs +++ b/src/librustc/traits/select.rs @@ -1638,7 +1638,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { (&ty::TyArray(..), &ty::TySlice(_)) => true, // Struct -> Struct. - (&ty::TyStruct(def_id_a, _), &ty::TyStruct(def_id_b, _)) => { + (&ty::TyAdt(def_id_a, _), &ty::TyAdt(def_id_b, _)) if def_id_a.is_struct() => { def_id_a == def_id_b } @@ -1780,8 +1780,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { Where(ty::Binder(tys.last().into_iter().cloned().collect())) } - ty::TyStruct(def, substs) | ty::TyUnion(def, substs) | - ty::TyEnum(def, substs) => { + ty::TyAdt(def, substs) => { let sized_crit = def.sized_constraint(self.tcx()); // (*) binder moved here Where(ty::Binder(match sized_crit.sty { @@ -1837,8 +1836,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { Where(ty::Binder(tys.to_vec())) } - ty::TyStruct(..) | ty::TyUnion(..) | ty::TyEnum(..) | - ty::TyProjection(..) | ty::TyParam(..) | ty::TyAnon(..) => { + ty::TyAdt(..) | ty::TyProjection(..) | ty::TyParam(..) | ty::TyAnon(..) => { // Fallback to whatever user-defined impls exist in this case. None } @@ -1930,11 +1928,11 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { } // for `PhantomData`, we pass `T` - ty::TyStruct(def, substs) if def.is_phantom_data() => { + ty::TyAdt(def, substs) if def.is_phantom_data() => { substs.types().collect() } - ty::TyStruct(def, substs) | ty::TyUnion(def, substs) | ty::TyEnum(def, substs) => { + ty::TyAdt(def, substs) => { def.all_fields() .map(|f| f.ty(self.tcx(), substs)) .collect() @@ -2566,7 +2564,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { } // Struct -> Struct. - (&ty::TyStruct(def, substs_a), &ty::TyStruct(_, substs_b)) => { + (&ty::TyAdt(def, substs_a), &ty::TyAdt(_, substs_b)) => { let fields = def .all_fields() .map(|f| f.unsubst_ty()) @@ -2621,7 +2619,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { k } }); - let new_struct = tcx.mk_struct(def, Substs::new(tcx, params)); + let new_struct = tcx.mk_adt(def, Substs::new(tcx, params)); let origin = TypeOrigin::Misc(obligation.cause.span); let InferOk { obligations, .. } = self.infcx.sub_types(false, origin, new_struct, target) diff --git a/src/librustc/ty/cast.rs b/src/librustc/ty/cast.rs index c8d282d18af1d..0badb85e9e095 100644 --- a/src/librustc/ty/cast.rs +++ b/src/librustc/ty/cast.rs @@ -65,7 +65,7 @@ impl<'tcx> CastTy<'tcx> { ty::TyInt(_) => Some(CastTy::Int(IntTy::I)), ty::TyUint(u) => Some(CastTy::Int(IntTy::U(u))), ty::TyFloat(_) => Some(CastTy::Float), - ty::TyEnum(d,_) if d.is_payloadfree() => + ty::TyAdt(d,_) if d.is_enum() && d.is_payloadfree() => Some(CastTy::Int(IntTy::CEnum)), ty::TyRawPtr(ref mt) => Some(CastTy::Ptr(mt)), ty::TyRef(_, ref mt) => Some(CastTy::RPtr(mt)), diff --git a/src/librustc/ty/contents.rs b/src/librustc/ty/contents.rs index e0e8a329e6e1d..b499e1346e73c 100644 --- a/src/librustc/ty/contents.rs +++ b/src/librustc/ty/contents.rs @@ -224,8 +224,7 @@ impl<'a, 'tcx> ty::TyS<'tcx> { |ty| tc_ty(tcx, *ty, cache)) } - ty::TyStruct(def, substs) | ty::TyUnion(def, substs) | - ty::TyEnum(def, substs) => { + ty::TyAdt(def, substs) => { let mut res = TypeContents::union(&def.variants, |v| { TypeContents::union(&v.fields, |f| { diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index 0fc1641d31f70..20601493d68f3 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -27,7 +27,7 @@ use ty::subst::Substs; use traits; use ty::{self, TraitRef, Ty, TypeAndMut}; use ty::{TyS, TypeVariants}; -use ty::{AdtDef, ClosureSubsts, Region}; +use ty::{AdtKind, AdtDef, ClosureSubsts, Region}; use hir::FreevarMap; use ty::{BareFnTy, InferTy, ParamTy, ProjectionTy, TraitObject}; use ty::{TyVar, TyVid, IntVar, IntVid, FloatVar, FloatVid}; @@ -620,7 +620,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { pub fn intern_adt_def(self, did: DefId, - kind: ty::AdtKind, + kind: AdtKind, variants: Vec>) -> ty::AdtDefMaster<'gcx> { let def = ty::AdtDefData::new(self, did, kind, variants); @@ -1032,8 +1032,8 @@ impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> { pub fn print_debug_stats(self) { sty_debug_print!( self, - TyEnum, TyBox, TyArray, TySlice, TyRawPtr, TyRef, TyFnDef, TyFnPtr, TyTrait, - TyStruct, TyUnion, TyClosure, TyTuple, TyParam, TyInfer, TyProjection, TyAnon); + TyAdt, TyBox, TyArray, TySlice, TyRawPtr, TyRef, TyFnDef, TyFnPtr, + TyTrait, TyClosure, TyTuple, TyParam, TyInfer, TyProjection, TyAnon); println!("Substs interner: #{}", self.interners.substs.borrow().len()); println!("BareFnTy interner: #{}", self.interners.bare_fn.borrow().len()); @@ -1227,9 +1227,9 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { self.mk_imm_ref(self.mk_region(ty::ReStatic), self.mk_str()) } - pub fn mk_enum(self, def: AdtDef<'tcx>, substs: &'tcx Substs<'tcx>) -> Ty<'tcx> { + pub fn mk_adt(self, def: AdtDef<'tcx>, substs: &'tcx Substs<'tcx>) -> Ty<'tcx> { // take a copy of substs so that we own the vectors inside - self.mk_ty(TyEnum(def, substs)) + self.mk_ty(TyAdt(def, substs)) } pub fn mk_box(self, ty: Ty<'tcx>) -> Ty<'tcx> { @@ -1316,16 +1316,6 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { self.mk_ty(TyProjection(inner)) } - pub fn mk_struct(self, def: AdtDef<'tcx>, substs: &'tcx Substs<'tcx>) -> Ty<'tcx> { - // take a copy of substs so that we own the vectors inside - self.mk_ty(TyStruct(def, substs)) - } - - pub fn mk_union(self, def: AdtDef<'tcx>, substs: &'tcx Substs<'tcx>) -> Ty<'tcx> { - // take a copy of substs so that we own the vectors inside - self.mk_ty(TyUnion(def, substs)) - } - pub fn mk_closure(self, closure_id: DefId, substs: &'tcx Substs<'tcx>, diff --git a/src/librustc/ty/error.rs b/src/librustc/ty/error.rs index 0e33e396f7e18..d820fddea3907 100644 --- a/src/librustc/ty/error.rs +++ b/src/librustc/ty/error.rs @@ -216,7 +216,7 @@ impl<'a, 'gcx, 'lcx, 'tcx> ty::TyS<'tcx> { ty::TyUint(_) | ty::TyFloat(_) | ty::TyStr | ty::TyNever => self.to_string(), ty::TyTuple(ref tys) if tys.is_empty() => self.to_string(), - ty::TyEnum(def, _) => format!("enum `{}`", tcx.item_path_str(def.did)), + ty::TyAdt(def, _) => format!("{} `{}`", def.descr(), tcx.item_path_str(def.did)), ty::TyBox(_) => "box".to_string(), ty::TyArray(_, n) => format!("array of {} elements", n), ty::TySlice(_) => "slice".to_string(), @@ -244,12 +244,6 @@ impl<'a, 'gcx, 'lcx, 'tcx> ty::TyS<'tcx> { ty::TyTrait(ref inner) => { format!("trait {}", tcx.item_path_str(inner.principal.def_id())) } - ty::TyStruct(def, _) => { - format!("struct `{}`", tcx.item_path_str(def.did)) - } - ty::TyUnion(def, _) => { - format!("union `{}`", tcx.item_path_str(def.did)) - } ty::TyClosure(..) => "closure".to_string(), ty::TyTuple(_) => "tuple".to_string(), ty::TyInfer(ty::TyVar(_)) => "inferred type".to_string(), diff --git a/src/librustc/ty/fast_reject.rs b/src/librustc/ty/fast_reject.rs index 84f34a640dd8e..ee1544d2d996d 100644 --- a/src/librustc/ty/fast_reject.rs +++ b/src/librustc/ty/fast_reject.rs @@ -22,15 +22,13 @@ pub enum SimplifiedType { IntSimplifiedType(ast::IntTy), UintSimplifiedType(ast::UintTy), FloatSimplifiedType(ast::FloatTy), - EnumSimplifiedType(DefId), + AdtSimplifiedType(DefId), StrSimplifiedType, VecSimplifiedType, PtrSimplifiedType, NeverSimplifiedType, TupleSimplifiedType(usize), TraitSimplifiedType(DefId), - StructSimplifiedType(DefId), - UnionSimplifiedType(DefId), ClosureSimplifiedType(DefId), AnonSimplifiedType(DefId), FunctionSimplifiedType(usize), @@ -57,19 +55,13 @@ pub fn simplify_type<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>, ty::TyInt(int_type) => Some(IntSimplifiedType(int_type)), ty::TyUint(uint_type) => Some(UintSimplifiedType(uint_type)), ty::TyFloat(float_type) => Some(FloatSimplifiedType(float_type)), - ty::TyEnum(def, _) => Some(EnumSimplifiedType(def.did)), + ty::TyAdt(def, _) => Some(AdtSimplifiedType(def.did)), ty::TyStr => Some(StrSimplifiedType), ty::TyArray(..) | ty::TySlice(_) => Some(VecSimplifiedType), ty::TyRawPtr(_) => Some(PtrSimplifiedType), ty::TyTrait(ref trait_info) => { Some(TraitSimplifiedType(trait_info.principal.def_id())) } - ty::TyStruct(def, _) => { - Some(StructSimplifiedType(def.did)) - } - ty::TyUnion(def, _) => { - Some(UnionSimplifiedType(def.did)) - } ty::TyRef(_, mt) => { // since we introduce auto-refs during method lookup, we // just treat &T and T as equivalent from the point of @@ -79,7 +71,7 @@ pub fn simplify_type<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>, ty::TyBox(_) => { // treat like we would treat `Box` match tcx.lang_items.require_owned_box() { - Ok(def_id) => Some(StructSimplifiedType(def_id)), + Ok(def_id) => Some(AdtSimplifiedType(def_id)), Err(msg) => tcx.sess.fatal(&msg), } } diff --git a/src/librustc/ty/flags.rs b/src/librustc/ty/flags.rs index ce6e4d6516ec6..cddd59fa83c1b 100644 --- a/src/librustc/ty/flags.rs +++ b/src/librustc/ty/flags.rs @@ -102,7 +102,7 @@ impl FlagComputation { } } - &ty::TyEnum(_, substs) | &ty::TyStruct(_, substs) | &ty::TyUnion(_, substs) => { + &ty::TyAdt(_, substs) => { self.add_substs(substs); } diff --git a/src/librustc/ty/item_path.rs b/src/librustc/ty/item_path.rs index ddb0a6970cba5..b6b55fc0e33dd 100644 --- a/src/librustc/ty/item_path.rs +++ b/src/librustc/ty/item_path.rs @@ -262,9 +262,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { // impl on `Foo`, but fallback to `::bar` if self-type is // anything other than a simple path. match self_ty.sty { - ty::TyStruct(adt_def, substs) | - ty::TyUnion(adt_def, substs) | - ty::TyEnum(adt_def, substs) => { + ty::TyAdt(adt_def, substs) => { if substs.types().next().is_none() { // ignore regions self.push_item_path(buffer, adt_def.did); } else { @@ -320,9 +318,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { /// decisions and we may want to adjust it later. pub fn characteristic_def_id_of_type(ty: Ty) -> Option { match ty.sty { - ty::TyStruct(adt_def, _) | - ty::TyUnion(adt_def, _) | - ty::TyEnum(adt_def, _) => Some(adt_def.did), + ty::TyAdt(adt_def, _) => Some(adt_def.did), ty::TyTrait(ref data) => Some(data.principal.def_id()), diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs index 276fc708eed1b..3c0aa041d2dd3 100644 --- a/src/librustc/ty/layout.rs +++ b/src/librustc/ty/layout.rs @@ -15,7 +15,7 @@ pub use self::Primitive::*; use infer::InferCtxt; use session::Session; use traits; -use ty::{self, Ty, TyCtxt, TypeFoldable}; +use ty::{self, AdtKind, Ty, TyCtxt, TypeFoldable}; use syntax::ast::{FloatTy, IntTy, UintTy}; use syntax::attr; @@ -555,7 +555,7 @@ impl<'a, 'gcx, 'tcx> Struct { } // Is this the NonZero lang item wrapping a pointer or integer type? - (&Univariant { non_zero: true, .. }, &ty::TyStruct(def, substs)) => { + (&Univariant { non_zero: true, .. }, &ty::TyAdt(def, substs)) if def.is_struct() => { let fields = &def.struct_variant().fields; assert_eq!(fields.len(), 1); match *fields[0].ty(tcx, substs).layout(infcx)? { @@ -573,7 +573,7 @@ impl<'a, 'gcx, 'tcx> Struct { // Perhaps one of the fields of this struct is non-zero // let's recurse and find out - (_, &ty::TyStruct(def, substs)) => { + (_, &ty::TyAdt(def, substs)) if def.is_struct() => { Struct::non_zero_field_path(infcx, def.struct_variant().fields .iter().map(|field| { field.ty(tcx, substs) @@ -694,7 +694,7 @@ pub enum Layout { non_zero: bool }, - /// SIMD vectors, from TyStruct marked with #[repr(simd)]. + /// SIMD vectors, from structs marked with #[repr(simd)]. Vector { element: Primitive, count: u64 @@ -715,7 +715,7 @@ pub enum Layout { non_zero: bool }, - // Remaining variants are all ADTs such as TyStruct, TyEnum or TyTuple. + // Remaining variants are all ADTs such as structs, enums or tuples. /// C-like enums; basically an integer. CEnum { @@ -919,240 +919,242 @@ impl<'a, 'gcx, 'tcx> Layout { } // ADTs. - ty::TyStruct(def, substs) => { - if ty.is_simd() { - // SIMD vector types. - let element = ty.simd_type(tcx); - match *element.layout(infcx)? { - Scalar { value, .. } => { - return success(Vector { - element: value, - count: ty.simd_size(tcx) as u64 - }); - } - _ => { - tcx.sess.fatal(&format!("monomorphising SIMD type `{}` with \ - a non-machine element type `{}`", - ty, element)); + ty::TyAdt(def, substs) => match def.adt_kind() { + AdtKind::Struct => { + if ty.is_simd() { + // SIMD vector types. + let element = ty.simd_type(tcx); + match *element.layout(infcx)? { + Scalar { value, .. } => { + return success(Vector { + element: value, + count: ty.simd_size(tcx) as u64 + }); + } + _ => { + tcx.sess.fatal(&format!("monomorphising SIMD type `{}` with \ + a non-machine element type `{}`", + ty, element)); + } } } - } - let fields = def.struct_variant().fields.iter().map(|field| { - field.ty(tcx, substs).layout(infcx) - }); - let packed = tcx.lookup_packed(def.did); - let mut st = Struct::new(dl, packed); - st.extend(dl, fields, ty)?; - - Univariant { - variant: st, - non_zero: Some(def.did) == tcx.lang_items.non_zero() - } - } - ty::TyUnion(def, substs) => { - let fields = def.struct_variant().fields.iter().map(|field| { - field.ty(tcx, substs).layout(infcx) - }); - let packed = tcx.lookup_packed(def.did); - let mut un = Union::new(dl, packed); - un.extend(dl, fields, ty)?; - UntaggedUnion { variants: un } - } - ty::TyEnum(def, substs) => { - let hint = *tcx.lookup_repr_hints(def.did).get(0) - .unwrap_or(&attr::ReprAny); - - if def.variants.is_empty() { - // Uninhabitable; represent as unit - // (Typechecking will reject discriminant-sizing attrs.) - assert_eq!(hint, attr::ReprAny); - - return success(Univariant { - variant: Struct::new(dl, false), - non_zero: false - }); - } - - if def.variants.iter().all(|v| v.fields.is_empty()) { - // All bodies empty -> intlike - let (mut min, mut max) = (i64::MAX, i64::MIN); - for v in &def.variants { - let x = v.disr_val.to_u64_unchecked() as i64; - if x < min { min = x; } - if x > max { max = x; } - } - - let (discr, signed) = Integer::repr_discr(tcx, hint, min, max); - return success(CEnum { - discr: discr, - signed: signed, - min: min as u64, - max: max as u64 + let fields = def.struct_variant().fields.iter().map(|field| { + field.ty(tcx, substs).layout(infcx) }); - } + let packed = tcx.lookup_packed(def.did); + let mut st = Struct::new(dl, packed); + st.extend(dl, fields, ty)?; - // Since there's at least one - // non-empty body, explicit discriminants should have - // been rejected by a checker before this point. - for (i, v) in def.variants.iter().enumerate() { - if i as u64 != v.disr_val.to_u64_unchecked() { - bug!("non-C-like enum {} with specified discriminants", - tcx.item_path_str(def.did)); + Univariant { + variant: st, + non_zero: Some(def.did) == tcx.lang_items.non_zero() } } - - if def.variants.len() == 1 { - // Equivalent to a struct/tuple/newtype. - // (Typechecking will reject discriminant-sizing attrs.) - assert_eq!(hint, attr::ReprAny); - let fields = def.variants[0].fields.iter().map(|field| { + AdtKind::Union => { + let fields = def.struct_variant().fields.iter().map(|field| { field.ty(tcx, substs).layout(infcx) }); - let mut st = Struct::new(dl, false); - st.extend(dl, fields, ty)?; - return success(Univariant { variant: st, non_zero: false }); + let packed = tcx.lookup_packed(def.did); + let mut un = Union::new(dl, packed); + un.extend(dl, fields, ty)?; + UntaggedUnion { variants: un } } + AdtKind::Enum => { + let hint = *tcx.lookup_repr_hints(def.did).get(0) + .unwrap_or(&attr::ReprAny); + + if def.variants.is_empty() { + // Uninhabitable; represent as unit + // (Typechecking will reject discriminant-sizing attrs.) + assert_eq!(hint, attr::ReprAny); + + return success(Univariant { + variant: Struct::new(dl, false), + non_zero: false + }); + } - // Cache the substituted and normalized variant field types. - let variants = def.variants.iter().map(|v| { - v.fields.iter().map(|field| field.ty(tcx, substs)).collect::>() - }).collect::>(); + if def.variants.iter().all(|v| v.fields.is_empty()) { + // All bodies empty -> intlike + let (mut min, mut max) = (i64::MAX, i64::MIN); + for v in &def.variants { + let x = v.disr_val.to_u64_unchecked() as i64; + if x < min { min = x; } + if x > max { max = x; } + } - if variants.len() == 2 && hint == attr::ReprAny { - // Nullable pointer optimization - for discr in 0..2 { - let other_fields = variants[1 - discr].iter().map(|ty| { - ty.layout(infcx) + let (discr, signed) = Integer::repr_discr(tcx, hint, min, max); + return success(CEnum { + discr: discr, + signed: signed, + min: min as u64, + max: max as u64 }); - if !Struct::would_be_zero_sized(dl, other_fields)? { - continue; + } + + // Since there's at least one + // non-empty body, explicit discriminants should have + // been rejected by a checker before this point. + for (i, v) in def.variants.iter().enumerate() { + if i as u64 != v.disr_val.to_u64_unchecked() { + bug!("non-C-like enum {} with specified discriminants", + tcx.item_path_str(def.did)); } - let path = Struct::non_zero_field_path(infcx, - variants[discr].iter().cloned())?; - let mut path = if let Some(p) = path { p } else { continue }; - - // FIXME(eddyb) should take advantage of a newtype. - if path == &[0] && variants[discr].len() == 1 { - match *variants[discr][0].layout(infcx)? { - Scalar { value, .. } => { - return success(RawNullablePointer { - nndiscr: discr as u64, - value: value - }); - } - _ => { - bug!("Layout::compute: `{}`'s non-zero \ - `{}` field not scalar?!", - ty, variants[discr][0]) + } + + if def.variants.len() == 1 { + // Equivalent to a struct/tuple/newtype. + // (Typechecking will reject discriminant-sizing attrs.) + assert_eq!(hint, attr::ReprAny); + let fields = def.variants[0].fields.iter().map(|field| { + field.ty(tcx, substs).layout(infcx) + }); + let mut st = Struct::new(dl, false); + st.extend(dl, fields, ty)?; + return success(Univariant { variant: st, non_zero: false }); + } + + // Cache the substituted and normalized variant field types. + let variants = def.variants.iter().map(|v| { + v.fields.iter().map(|field| field.ty(tcx, substs)).collect::>() + }).collect::>(); + + if variants.len() == 2 && hint == attr::ReprAny { + // Nullable pointer optimization + for discr in 0..2 { + let other_fields = variants[1 - discr].iter().map(|ty| { + ty.layout(infcx) + }); + if !Struct::would_be_zero_sized(dl, other_fields)? { + continue; + } + let path = Struct::non_zero_field_path(infcx, + variants[discr].iter().cloned())?; + let mut path = if let Some(p) = path { p } else { continue }; + + // FIXME(eddyb) should take advantage of a newtype. + if path == &[0] && variants[discr].len() == 1 { + match *variants[discr][0].layout(infcx)? { + Scalar { value, .. } => { + return success(RawNullablePointer { + nndiscr: discr as u64, + value: value + }); + } + _ => { + bug!("Layout::compute: `{}`'s non-zero \ + `{}` field not scalar?!", + ty, variants[discr][0]) + } } } + + path.push(0); // For GEP through a pointer. + path.reverse(); + let mut st = Struct::new(dl, false); + st.extend(dl, variants[discr].iter().map(|ty| ty.layout(infcx)), ty)?; + return success(StructWrappedNullablePointer { + nndiscr: discr as u64, + nonnull: st, + discrfield: path + }); } + } - path.push(0); // For GEP through a pointer. - path.reverse(); - let mut st = Struct::new(dl, false); - st.extend(dl, variants[discr].iter().map(|ty| ty.layout(infcx)), ty)?; - return success(StructWrappedNullablePointer { - nndiscr: discr as u64, - nonnull: st, - discrfield: path + // The general case. + let discr_max = (variants.len() - 1) as i64; + assert!(discr_max >= 0); + let (min_ity, _) = Integer::repr_discr(tcx, hint, 0, discr_max); + + let mut align = dl.aggregate_align; + let mut size = Size::from_bytes(0); + + // We're interested in the smallest alignment, so start large. + let mut start_align = Align::from_bytes(256, 256).unwrap(); + + // Create the set of structs that represent each variant + // Use the minimum integer type we figured out above + let discr = Some(Scalar { value: Int(min_ity), non_zero: false }); + let mut variants = variants.into_iter().map(|fields| { + let mut found_start = false; + let fields = fields.into_iter().map(|field| { + let field = field.layout(infcx)?; + if !found_start { + // Find the first field we can't move later + // to make room for a larger discriminant. + let field_align = field.align(dl); + if field.size(dl).bytes() != 0 || field_align.abi() != 1 { + start_align = start_align.min(field_align); + found_start = true; + } + } + Ok(field) }); + let mut st = Struct::new(dl, false); + st.extend(dl, discr.iter().map(Ok).chain(fields), ty)?; + size = cmp::max(size, st.min_size()); + align = align.max(st.align); + Ok(st) + }).collect::, _>>()?; + + // Align the maximum variant size to the largest alignment. + size = size.abi_align(align); + + if size.bytes() >= dl.obj_size_bound() { + return Err(LayoutError::SizeOverflow(ty)); } - } - // The general case. - let discr_max = (variants.len() - 1) as i64; - assert!(discr_max >= 0); - let (min_ity, _) = Integer::repr_discr(tcx, hint, 0, discr_max); - - let mut align = dl.aggregate_align; - let mut size = Size::from_bytes(0); - - // We're interested in the smallest alignment, so start large. - let mut start_align = Align::from_bytes(256, 256).unwrap(); - - // Create the set of structs that represent each variant - // Use the minimum integer type we figured out above - let discr = Some(Scalar { value: Int(min_ity), non_zero: false }); - let mut variants = variants.into_iter().map(|fields| { - let mut found_start = false; - let fields = fields.into_iter().map(|field| { - let field = field.layout(infcx)?; - if !found_start { - // Find the first field we can't move later - // to make room for a larger discriminant. - let field_align = field.align(dl); - if field.size(dl).bytes() != 0 || field_align.abi() != 1 { - start_align = start_align.min(field_align); - found_start = true; - } + // Check to see if we should use a different type for the + // discriminant. We can safely use a type with the same size + // as the alignment of the first field of each variant. + // We increase the size of the discriminant to avoid LLVM copying + // padding when it doesn't need to. This normally causes unaligned + // load/stores and excessive memcpy/memset operations. By using a + // bigger integer size, LLVM can be sure about it's contents and + // won't be so conservative. + + // Use the initial field alignment + let wanted = start_align.abi(); + let mut ity = min_ity; + for &candidate in &[I16, I32, I64] { + let ty = Int(candidate); + if wanted == ty.align(dl).abi() && wanted == ty.size(dl).bytes() { + ity = candidate; + break; } - Ok(field) - }); - let mut st = Struct::new(dl, false); - st.extend(dl, discr.iter().map(Ok).chain(fields), ty)?; - size = cmp::max(size, st.min_size()); - align = align.max(st.align); - Ok(st) - }).collect::, _>>()?; - - // Align the maximum variant size to the largest alignment. - size = size.abi_align(align); - - if size.bytes() >= dl.obj_size_bound() { - return Err(LayoutError::SizeOverflow(ty)); - } - - // Check to see if we should use a different type for the - // discriminant. We can safely use a type with the same size - // as the alignment of the first field of each variant. - // We increase the size of the discriminant to avoid LLVM copying - // padding when it doesn't need to. This normally causes unaligned - // load/stores and excessive memcpy/memset operations. By using a - // bigger integer size, LLVM can be sure about it's contents and - // won't be so conservative. - - // Use the initial field alignment - let wanted = start_align.abi(); - let mut ity = min_ity; - for &candidate in &[I16, I32, I64] { - let ty = Int(candidate); - if wanted == ty.align(dl).abi() && wanted == ty.size(dl).bytes() { - ity = candidate; - break; } - } - // FIXME(eddyb) conservative only to avoid diverging from trans::adt. - if align.abi() != start_align.abi() { - ity = min_ity; - } + // FIXME(eddyb) conservative only to avoid diverging from trans::adt. + if align.abi() != start_align.abi() { + ity = min_ity; + } - // If the alignment is not larger than the chosen discriminant size, - // don't use the alignment as the final size. - if ity <= min_ity { - ity = min_ity; - } else { - // Patch up the variants' first few fields. - let old_ity_size = Int(min_ity).size(dl); - let new_ity_size = Int(ity).size(dl); - for variant in &mut variants { - for offset in &mut variant.offset_after_field { - if *offset > old_ity_size { - break; + // If the alignment is not larger than the chosen discriminant size, + // don't use the alignment as the final size. + if ity <= min_ity { + ity = min_ity; + } else { + // Patch up the variants' first few fields. + let old_ity_size = Int(min_ity).size(dl); + let new_ity_size = Int(ity).size(dl); + for variant in &mut variants { + for offset in &mut variant.offset_after_field { + if *offset > old_ity_size { + break; + } + *offset = new_ity_size; } - *offset = new_ity_size; } } - } - General { - discr: ity, - variants: variants, - size: size, - align: align + General { + discr: ity, + variants: variants, + size: size, + align: align + } } - } + }, // Types with no meaningful known layout. ty::TyProjection(_) | ty::TyAnon(..) => { @@ -1317,9 +1319,9 @@ impl<'a, 'gcx, 'tcx> SizeSkeleton<'gcx> { } } - ty::TyStruct(def, substs) | ty::TyEnum(def, substs) => { + ty::TyAdt(def, substs) => { // Only newtypes and enums w/ nullable pointer optimization. - if def.variants.is_empty() || def.variants.len() > 2 { + if def.is_union() || def.variants.is_empty() || def.variants.len() > 2 { return Err(err); } diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index dfe24d5627bf1..91e3950745089 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -952,9 +952,7 @@ impl<'tcx> TraitPredicate<'tcx> { self.input_types() .flat_map(|t| t.walk()) .filter_map(|t| match t.sty { - ty::TyStruct(adt_def, _) | - ty::TyUnion(adt_def, _) | - ty::TyEnum(adt_def, _) => + ty::TyAdt(adt_def, _) => Some(adt_def.did), _ => None @@ -1573,18 +1571,49 @@ impl<'a, 'gcx, 'tcx, 'container> AdtDefData<'gcx, 'container> { self.flags.set(self.flags.get() | AdtFlags::IS_DTORCK_VALID) } + #[inline] + pub fn is_struct(&self) -> bool { + !self.is_union() && !self.is_enum() + } + + #[inline] + pub fn is_union(&self) -> bool { + self.flags.get().intersects(AdtFlags::IS_UNION) + } + + #[inline] + pub fn is_enum(&self) -> bool { + self.flags.get().intersects(AdtFlags::IS_ENUM) + } + /// Returns the kind of the ADT - Struct or Enum. #[inline] pub fn adt_kind(&self) -> AdtKind { - if self.flags.get().intersects(AdtFlags::IS_ENUM) { + if self.is_enum() { AdtKind::Enum - } else if self.flags.get().intersects(AdtFlags::IS_UNION) { + } else if self.is_union() { AdtKind::Union } else { AdtKind::Struct } } + pub fn descr(&self) -> &'static str { + match self.adt_kind() { + AdtKind::Struct => "struct", + AdtKind::Union => "union", + AdtKind::Enum => "enum", + } + } + + pub fn variant_descr(&self) -> &'static str { + match self.adt_kind() { + AdtKind::Struct => "struct", + AdtKind::Union => "union", + AdtKind::Enum => "variant", + } + } + /// Returns whether this is a dtorck type. If this returns /// true, this type being safe for destruction requires it to be /// alive; Otherwise, only the contents are required to be. @@ -1622,8 +1651,7 @@ impl<'a, 'gcx, 'tcx, 'container> AdtDefData<'gcx, 'container> { /// Asserts this is a struct and returns the struct's unique /// variant. pub fn struct_variant(&self) -> &VariantDefData<'gcx, 'container> { - let adt_kind = self.adt_kind(); - assert!(adt_kind == AdtKind::Struct || adt_kind == AdtKind::Union); + assert!(!self.is_enum()); &self.variants[0] } @@ -1832,7 +1860,7 @@ impl<'a, 'tcx> AdtDefData<'tcx, 'tcx> { } } - TyEnum(adt, substs) | TyStruct(adt, substs) | TyUnion(adt, substs) => { + TyAdt(adt, substs) => { // recursive case let adt = tcx.lookup_adt_def_master(adt.did); adt.calculate_sized_constraint_inner(tcx, stack); diff --git a/src/librustc/ty/outlives.rs b/src/librustc/ty/outlives.rs index a7bb0374b75bf..a4edd3b93c949 100644 --- a/src/librustc/ty/outlives.rs +++ b/src/librustc/ty/outlives.rs @@ -172,9 +172,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { ty::TyUint(..) | // OutlivesScalar ty::TyFloat(..) | // OutlivesScalar ty::TyNever | // ... - ty::TyEnum(..) | // OutlivesNominalType - ty::TyStruct(..) | // OutlivesNominalType - ty::TyUnion(..) | // OutlivesNominalType + ty::TyAdt(..) | // OutlivesNominalType ty::TyBox(..) | // OutlivesNominalType (ish) ty::TyAnon(..) | // OutlivesNominalType (ish) ty::TyStr | // OutlivesScalar (ish) diff --git a/src/librustc/ty/relate.rs b/src/librustc/ty/relate.rs index dfae19487b6f0..b10c731fe27d0 100644 --- a/src/librustc/ty/relate.rs +++ b/src/librustc/ty/relate.rs @@ -414,11 +414,11 @@ pub fn super_relate_tys<'a, 'gcx, 'tcx, R>(relation: &mut R, Ok(a) } - (&ty::TyEnum(a_def, a_substs), &ty::TyEnum(b_def, b_substs)) + (&ty::TyAdt(a_def, a_substs), &ty::TyAdt(b_def, b_substs)) if a_def == b_def => { let substs = relate_item_substs(relation, a_def.did, a_substs, b_substs)?; - Ok(tcx.mk_enum(a_def, substs)) + Ok(tcx.mk_adt(a_def, substs)) } (&ty::TyTrait(ref a_obj), &ty::TyTrait(ref b_obj)) => @@ -440,20 +440,6 @@ pub fn super_relate_tys<'a, 'gcx, 'tcx, R>(relation: &mut R, })) } - (&ty::TyStruct(a_def, a_substs), &ty::TyStruct(b_def, b_substs)) - if a_def == b_def => - { - let substs = relate_item_substs(relation, a_def.did, a_substs, b_substs)?; - Ok(tcx.mk_struct(a_def, substs)) - } - - (&ty::TyUnion(a_def, a_substs), &ty::TyUnion(b_def, b_substs)) - if a_def == b_def => - { - let substs = relate_item_substs(relation, a_def.did, a_substs, b_substs)?; - Ok(tcx.mk_union(a_def, substs)) - } - (&ty::TyClosure(a_id, a_substs), &ty::TyClosure(b_id, b_substs)) if a_id == b_id => diff --git a/src/librustc/ty/structural_impls.rs b/src/librustc/ty/structural_impls.rs index 952641f6832f9..6c3dabfe113fe 100644 --- a/src/librustc/ty/structural_impls.rs +++ b/src/librustc/ty/structural_impls.rs @@ -482,7 +482,7 @@ impl<'tcx> TypeFoldable<'tcx> for Ty<'tcx> { ty::TyRawPtr(tm) => ty::TyRawPtr(tm.fold_with(folder)), ty::TyArray(typ, sz) => ty::TyArray(typ.fold_with(folder), sz), ty::TySlice(typ) => ty::TySlice(typ.fold_with(folder)), - ty::TyEnum(tid, substs) => ty::TyEnum(tid, substs.fold_with(folder)), + ty::TyAdt(tid, substs) => ty::TyAdt(tid, substs.fold_with(folder)), ty::TyTrait(ref trait_ty) => ty::TyTrait(trait_ty.fold_with(folder)), ty::TyTuple(ts) => ty::TyTuple(ts.fold_with(folder)), ty::TyFnDef(def_id, substs, f) => { @@ -494,8 +494,6 @@ impl<'tcx> TypeFoldable<'tcx> for Ty<'tcx> { ty::TyRef(ref r, tm) => { ty::TyRef(r.fold_with(folder), tm.fold_with(folder)) } - ty::TyStruct(did, substs) => ty::TyStruct(did, substs.fold_with(folder)), - ty::TyUnion(did, substs) => ty::TyUnion(did, substs.fold_with(folder)), ty::TyClosure(did, substs) => ty::TyClosure(did, substs.fold_with(folder)), ty::TyProjection(ref data) => ty::TyProjection(data.fold_with(folder)), ty::TyAnon(did, substs) => ty::TyAnon(did, substs.fold_with(folder)), @@ -516,7 +514,7 @@ impl<'tcx> TypeFoldable<'tcx> for Ty<'tcx> { ty::TyRawPtr(ref tm) => tm.visit_with(visitor), ty::TyArray(typ, _sz) => typ.visit_with(visitor), ty::TySlice(typ) => typ.visit_with(visitor), - ty::TyEnum(_tid, ref substs) => substs.visit_with(visitor), + ty::TyAdt(_, substs) => substs.visit_with(visitor), ty::TyTrait(ref trait_ty) => trait_ty.visit_with(visitor), ty::TyTuple(ts) => ts.visit_with(visitor), ty::TyFnDef(_, substs, ref f) => { @@ -524,8 +522,6 @@ impl<'tcx> TypeFoldable<'tcx> for Ty<'tcx> { } ty::TyFnPtr(ref f) => f.visit_with(visitor), ty::TyRef(r, ref tm) => r.visit_with(visitor) || tm.visit_with(visitor), - ty::TyStruct(_did, ref substs) => substs.visit_with(visitor), - ty::TyUnion(_did, ref substs) => substs.visit_with(visitor), ty::TyClosure(_did, ref substs) => substs.visit_with(visitor), ty::TyProjection(ref data) => data.visit_with(visitor), ty::TyAnon(_, ref substs) => substs.visit_with(visitor), diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs index 7ded2b05f3b5b..a755dd056cd84 100644 --- a/src/librustc/ty/sty.rs +++ b/src/librustc/ty/sty.rs @@ -106,24 +106,13 @@ pub enum TypeVariants<'tcx> { /// A primitive floating-point type. For example, `f64`. TyFloat(ast::FloatTy), - /// An enumerated type, defined with `enum`. + /// Structures, enumerations and unions. /// /// Substs here, possibly against intuition, *may* contain `TyParam`s. /// That is, even after substitution it is possible that there are type - /// variables. This happens when the `TyEnum` corresponds to an enum - /// definition and not a concrete use of it. This is true for `TyStruct` - /// and `TyUnion` as well. - TyEnum(AdtDef<'tcx>, &'tcx Substs<'tcx>), - - /// A structure type, defined with `struct`. - /// - /// See warning about substitutions for enumerated types. - TyStruct(AdtDef<'tcx>, &'tcx Substs<'tcx>), - - /// A union type, defined with `union`. - /// - /// See warning about substitutions for enumerated types. - TyUnion(AdtDef<'tcx>, &'tcx Substs<'tcx>), + /// variables. This happens when the `TyAdt` corresponds to an ADT + /// definition and not a concrete use of it. + TyAdt(AdtDef<'tcx>, &'tcx Substs<'tcx>), /// `Box`; this is nominally a struct in the documentation, but is /// special-cased internally. For example, it is possible to implicitly @@ -922,7 +911,7 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> { // FIXME(#24885): be smarter here, the AdtDefData::is_empty method could easily be made // more complete. match self.sty { - TyEnum(def, _) | TyStruct(def, _) | TyUnion(def, _) => def.is_empty(), + TyAdt(def, _) => def.is_empty(), // FIXME(canndrew): There's no reason why these can't be uncommented, they're tested // and they don't break anything. But I'm keeping my changes small for now. @@ -950,7 +939,7 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> { } pub fn is_phantom_data(&self) -> bool { - if let TyStruct(def, _) = self.sty { + if let TyAdt(def, _) = self.sty { def.is_phantom_data() } else { false @@ -985,8 +974,7 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> { pub fn is_structural(&self) -> bool { match self.sty { - TyStruct(..) | TyUnion(..) | TyTuple(..) | TyEnum(..) | - TyArray(..) | TyClosure(..) => true, + TyAdt(..) | TyTuple(..) | TyArray(..) | TyClosure(..) => true, _ => self.is_slice() | self.is_trait() } } @@ -994,7 +982,7 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> { #[inline] pub fn is_simd(&self) -> bool { match self.sty { - TyStruct(def, _) => def.is_simd(), + TyAdt(def, _) => def.is_simd(), _ => false } } @@ -1009,7 +997,7 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> { pub fn simd_type(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Ty<'tcx> { match self.sty { - TyStruct(def, substs) => { + TyAdt(def, substs) => { def.struct_variant().fields[0].ty(tcx, substs) } _ => bug!("simd_type called on invalid type") @@ -1018,7 +1006,7 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> { pub fn simd_size(&self, _cx: TyCtxt) -> usize { match self.sty { - TyStruct(def, _) => def.struct_variant().fields.len(), + TyAdt(def, _) => def.struct_variant().fields.len(), _ => bug!("simd_size called on invalid type") } } @@ -1203,9 +1191,7 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> { pub fn ty_to_def_id(&self) -> Option { match self.sty { TyTrait(ref tt) => Some(tt.principal.def_id()), - TyStruct(def, _) | - TyUnion(def, _) | - TyEnum(def, _) => Some(def.did), + TyAdt(def, _) => Some(def.did), TyClosure(id, _) => Some(id), _ => None } @@ -1213,7 +1199,7 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> { pub fn ty_adt_def(&self) -> Option> { match self.sty { - TyStruct(adt, _) | TyUnion(adt, _) | TyEnum(adt, _) => Some(adt), + TyAdt(adt, _) => Some(adt), _ => None } } @@ -1231,10 +1217,7 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> { v.extend(obj.principal.skip_binder().substs.regions()); v } - TyEnum(_, substs) | - TyStruct(_, substs) | - TyUnion(_, substs) | - TyAnon(_, substs) => { + TyAdt(_, substs) | TyAnon(_, substs) => { substs.regions().collect() } TyClosure(_, ref substs) => { diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs index 51ca6bfeb5aff..68de8d96f33dc 100644 --- a/src/librustc/ty/util.rs +++ b/src/librustc/ty/util.rs @@ -14,7 +14,7 @@ use hir::def_id::DefId; use infer::InferCtxt; use hir::pat_util; use traits::{self, Reveal}; -use ty::{self, Ty, TyCtxt, TypeAndMut, TypeFlags, TypeFoldable}; +use ty::{self, Ty, AdtKind, TyCtxt, TypeAndMut, TypeFlags, TypeFoldable}; use ty::{Disr, ParameterEnvironment}; use ty::fold::TypeVisitor; use ty::layout::{Layout, LayoutError}; @@ -138,28 +138,30 @@ impl<'tcx> ParameterEnvironment<'tcx> { // FIXME: (@jroesch) float this code up tcx.infer_ctxt(None, Some(self.clone()), Reveal::ExactMatch).enter(|infcx| { let adt = match self_type.sty { - ty::TyStruct(struct_def, substs) | ty::TyUnion(struct_def, substs) => { - for field in struct_def.all_fields() { - let field_ty = field.ty(tcx, substs); - if infcx.type_moves_by_default(field_ty, span) { - return Err(CopyImplementationError::InfrigingField( - field.name)) - } - } - struct_def - } - ty::TyEnum(enum_def, substs) => { - for variant in &enum_def.variants { - for field in &variant.fields { + ty::TyAdt(adt, substs) => match adt.adt_kind() { + AdtKind::Struct | AdtKind::Union => { + for field in adt.all_fields() { let field_ty = field.ty(tcx, substs); if infcx.type_moves_by_default(field_ty, span) { - return Err(CopyImplementationError::InfrigingVariant( - variant.name)) + return Err(CopyImplementationError::InfrigingField( + field.name)) } } + adt } - enum_def - } + AdtKind::Enum => { + for variant in &adt.variants { + for field in &variant.fields { + let field_ty = field.ty(tcx, substs); + if infcx.type_moves_by_default(field_ty, span) { + return Err(CopyImplementationError::InfrigingVariant( + variant.name)) + } + } + } + adt + } + }, _ => return Err(CopyImplementationError::NotAnAdt) }; @@ -183,7 +185,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { pub fn has_error_field(self, ty: Ty<'tcx>) -> bool { match ty.sty { - ty::TyStruct(def, substs) | ty::TyUnion(def, substs) | ty::TyEnum(def, substs) => { + ty::TyAdt(def, substs) => { for field in def.all_fields() { let field_ty = field.ty(self, substs); if let TyError = field_ty.sty { @@ -203,16 +205,12 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { i: usize, variant: Option) -> Option> { match (&ty.sty, variant) { - (&TyStruct(def, substs), None) | - (&TyUnion(def, substs), None) => { - def.struct_variant().fields.get(i).map(|f| f.ty(self, substs)) + (&TyAdt(adt, substs), Some(vid)) => { + adt.variant_with_id(vid).fields.get(i).map(|f| f.ty(self, substs)) } - (&TyEnum(def, substs), Some(vid)) => { - def.variant_with_id(vid).fields.get(i).map(|f| f.ty(self, substs)) - } - (&TyEnum(def, substs), None) => { - assert!(def.is_univariant()); - def.variants[0].fields.get(i).map(|f| f.ty(self, substs)) + (&TyAdt(adt, substs), None) => { + // Don't use `struct_variant`, this may be a univariant enum. + adt.variants[0].fields.get(i).map(|f| f.ty(self, substs)) } (&TyTuple(ref v), None) => v.get(i).cloned(), _ => None @@ -226,12 +224,11 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { n: Name, variant: Option) -> Option> { match (&ty.sty, variant) { - (&TyStruct(def, substs), None) | - (&TyUnion(def, substs), None) => { - def.struct_variant().find_field_named(n).map(|f| f.ty(self, substs)) + (&TyAdt(adt, substs), Some(vid)) => { + adt.variant_with_id(vid).find_field_named(n).map(|f| f.ty(self, substs)) } - (&TyEnum(def, substs), Some(vid)) => { - def.variant_with_id(vid).find_field_named(n).map(|f| f.ty(self, substs)) + (&TyAdt(adt, substs), None) => { + adt.struct_variant().find_field_named(n).map(|f| f.ty(self, substs)) } _ => return None } @@ -256,10 +253,15 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { /// if not a structure at all. Corresponds to the only possible unsized /// field, and its type can be used to determine unsizing strategy. pub fn struct_tail(self, mut ty: Ty<'tcx>) -> Ty<'tcx> { - while let TyStruct(def, substs) = ty.sty { - match def.struct_variant().fields.last() { - Some(f) => ty = f.ty(self, substs), - None => break + loop { + match ty.sty { + TyAdt(def, substs) if def.is_struct() => { + match def.struct_variant().fields.last() { + Some(f) => ty = f.ty(self, substs), + None => break + } + } + _ => break } } ty @@ -275,15 +277,19 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { target: Ty<'tcx>) -> (Ty<'tcx>, Ty<'tcx>) { let (mut a, mut b) = (source, target); - while let (&TyStruct(a_def, a_substs), &TyStruct(b_def, b_substs)) = (&a.sty, &b.sty) { - if a_def != b_def { - break; - } - if let Some(f) = a_def.struct_variant().fields.last() { - a = f.ty(self, a_substs); - b = f.ty(self, b_substs); - } else { - break; + loop { + match (&a.sty, &b.sty) { + (&TyAdt(a_def, a_substs), &TyAdt(b_def, b_substs)) + if a_def == b_def && a_def.is_struct() => { + match a_def.struct_variant().fields.last() { + Some(f) => { + a = f.ty(self, a_substs); + b = f.ty(self, b_substs); + } + _ => break + } + } + _ => break } } (a, b) @@ -431,9 +437,7 @@ impl<'a, 'gcx, 'tcx> TypeVisitor<'tcx> for TypeIdHasher<'a, 'gcx, 'tcx> { TyInt(i) => self.hash(i), TyUint(u) => self.hash(u), TyFloat(f) => self.hash(f), - TyStruct(d, _) | - TyUnion(d, _) | - TyEnum(d, _) => self.def_id(d.did), + TyAdt(d, _) => self.def_id(d.did), TyArray(_, n) => self.hash(n), TyRawPtr(m) | TyRef(_, m) => self.hash(m.mutbl), @@ -560,8 +564,8 @@ impl<'a, 'tcx> ty::TyS<'tcx> { mutbl: hir::MutMutable, .. }) => Some(true), - TyArray(..) | TySlice(_) | TyTrait(..) | TyTuple(..) | - TyClosure(..) | TyEnum(..) | TyStruct(..) | TyUnion(..) | TyAnon(..) | + TyArray(..) | TySlice(..) | TyTrait(..) | TyTuple(..) | + TyClosure(..) | TyAdt(..) | TyAnon(..) | TyProjection(..) | TyParam(..) | TyInfer(..) | TyError => None }.unwrap_or_else(|| !self.impls_bound(tcx, param_env, ty::BoundCopy, span)); @@ -601,7 +605,7 @@ impl<'a, 'tcx> ty::TyS<'tcx> { TyStr | TyTrait(..) | TySlice(_) => Some(false), - TyEnum(..) | TyStruct(..) | TyUnion(..) | TyProjection(..) | TyParam(..) | + TyAdt(..) | TyProjection(..) | TyParam(..) | TyInfer(..) | TyAnon(..) | TyError => None }.unwrap_or_else(|| self.impls_bound(tcx, param_env, ty::BoundSized, span)); @@ -663,7 +667,7 @@ impl<'a, 'tcx> ty::TyS<'tcx> { TyArray(ty, _) => { is_type_structurally_recursive(tcx, sp, seen, ty) } - TyStruct(def, substs) | TyUnion(def, substs) | TyEnum(def, substs) => { + TyAdt(def, substs) => { find_nonrepresentable(tcx, sp, seen, @@ -680,7 +684,7 @@ impl<'a, 'tcx> ty::TyS<'tcx> { fn same_struct_or_enum<'tcx>(ty: Ty<'tcx>, def: ty::AdtDef<'tcx>) -> bool { match ty.sty { - TyStruct(ty_def, _) | TyUnion(ty_def, _) | TyEnum(ty_def, _) => { + TyAdt(ty_def, _) => { ty_def == def } _ => false @@ -689,9 +693,7 @@ impl<'a, 'tcx> ty::TyS<'tcx> { fn same_type<'tcx>(a: Ty<'tcx>, b: Ty<'tcx>) -> bool { match (&a.sty, &b.sty) { - (&TyStruct(did_a, ref substs_a), &TyStruct(did_b, ref substs_b)) | - (&TyUnion(did_a, ref substs_a), &TyUnion(did_b, ref substs_b)) | - (&TyEnum(did_a, ref substs_a), &TyEnum(did_b, ref substs_b)) => { + (&TyAdt(did_a, substs_a), &TyAdt(did_b, substs_b)) => { if did_a != did_b { return false; } @@ -713,7 +715,7 @@ impl<'a, 'tcx> ty::TyS<'tcx> { debug!("is_type_structurally_recursive: {:?}", ty); match ty.sty { - TyStruct(def, _) | TyUnion(def, _) | TyEnum(def, _) => { + TyAdt(def, _) => { { // Iterate through stack of previously seen types. let mut iter = seen.iter(); diff --git a/src/librustc/ty/walk.rs b/src/librustc/ty/walk.rs index cea3bd6348dbe..dd3a62f7cd2dd 100644 --- a/src/librustc/ty/walk.rs +++ b/src/librustc/ty/walk.rs @@ -93,10 +93,7 @@ fn push_subtypes<'tcx>(stack: &mut Vec>, parent_ty: Ty<'tcx>) { pred.0.ty }).rev()); } - ty::TyEnum(_, ref substs) | - ty::TyStruct(_, ref substs) | - ty::TyUnion(_, ref substs) | - ty::TyAnon(_, ref substs) => { + ty::TyAdt(_, substs) | ty::TyAnon(_, substs) => { stack.extend(substs.types().rev()); } ty::TyClosure(_, ref substs) => { diff --git a/src/librustc/ty/wf.rs b/src/librustc/ty/wf.rs index 599e2be4db247..0557660e98c2f 100644 --- a/src/librustc/ty/wf.rs +++ b/src/librustc/ty/wf.rs @@ -336,9 +336,7 @@ impl<'a, 'gcx, 'tcx> WfPredicates<'a, 'gcx, 'tcx> { self.compute_projection(data); } - ty::TyEnum(def, substs) | - ty::TyStruct(def, substs) | - ty::TyUnion(def, substs) => { + ty::TyAdt(def, substs) => { // WfNominalType let obligations = self.nominal_obligations(def.did, substs); self.out.extend(obligations); diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index d0e02f2e8acdd..3b84ff86ab9fb 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -11,7 +11,7 @@ use hir::def_id::DefId; use ty::subst::{self, Subst, Substs}; use ty::{BrAnon, BrEnv, BrFresh, BrNamed}; -use ty::{TyBool, TyChar, TyStruct, TyUnion, TyEnum}; +use ty::{TyBool, TyChar, TyAdt}; use ty::{TyError, TyStr, TyArray, TySlice, TyFloat, TyFnDef, TyFnPtr}; use ty::{TyParam, TyRawPtr, TyRef, TyNever, TyTuple}; use ty::TyClosure; @@ -868,7 +868,7 @@ impl<'tcx> fmt::Display for ty::TypeVariants<'tcx> { TyInfer(infer_ty) => write!(f, "{}", infer_ty), TyError => write!(f, "[type error]"), TyParam(ref param_ty) => write!(f, "{}", param_ty), - TyEnum(def, substs) | TyStruct(def, substs) | TyUnion(def, substs) => { + TyAdt(def, substs) => { ty::tls::with(|tcx| { if def.did.is_local() && !tcx.tcache.borrow().contains_key(&def.did) { diff --git a/src/librustc_borrowck/borrowck/check_loans.rs b/src/librustc_borrowck/borrowck/check_loans.rs index 6f4c48d632a7a..089733da536d8 100644 --- a/src/librustc_borrowck/borrowck/check_loans.rs +++ b/src/librustc_borrowck/borrowck/check_loans.rs @@ -796,9 +796,7 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> { } LpExtend(ref lp_base, _, LpInterior(_, InteriorField(_))) => { match lp_base.to_type().sty { - ty::TyStruct(def, _) | - ty::TyUnion(def, _) | - ty::TyEnum(def, _) if def.has_dtor() => { + ty::TyAdt(def, _) if def.has_dtor() => { // In the case where the owner implements drop, then // the path must be initialized to prevent a case of // partial reinitialization diff --git a/src/librustc_borrowck/borrowck/fragments.rs b/src/librustc_borrowck/borrowck/fragments.rs index 45f5c3288a6d0..515868c460d07 100644 --- a/src/librustc_borrowck/borrowck/fragments.rs +++ b/src/librustc_borrowck/borrowck/fragments.rs @@ -21,7 +21,7 @@ use borrowck::LoanPathElem::{LpDeref, LpInterior}; use borrowck::move_data::InvalidMovePathIndex; use borrowck::move_data::{MoveData, MovePathIndex}; use rustc::hir::def_id::{DefId}; -use rustc::ty::{self, TyCtxt}; +use rustc::ty::{self, AdtKind, TyCtxt}; use rustc::middle::mem_categorization as mc; use std::mem; @@ -422,8 +422,8 @@ fn add_fragment_siblings_for_extension<'a, 'tcx>(this: &MoveData<'tcx>, variant_did); }; - match (&parent_ty.sty, enum_variant_info) { - (&ty::TyTuple(ref v), None) => { + match parent_ty.sty { + ty::TyTuple(ref v) => { let tuple_idx = match *origin_field_name { mc::PositionalField(tuple_idx) => tuple_idx, mc::NamedField(_) => @@ -438,69 +438,68 @@ fn add_fragment_siblings_for_extension<'a, 'tcx>(this: &MoveData<'tcx>, } } - (&ty::TyStruct(def, _), None) => { - match *origin_field_name { - mc::NamedField(ast_name) => { - for f in &def.struct_variant().fields { - if f.name == ast_name { - continue; + ty::TyAdt(def, ..) => match def.adt_kind() { + AdtKind::Struct => { + match *origin_field_name { + mc::NamedField(ast_name) => { + for f in &def.struct_variant().fields { + if f.name == ast_name { + continue; + } + let field_name = mc::NamedField(f.name); + add_fragment_sibling_local(field_name, None); } - let field_name = mc::NamedField(f.name); - add_fragment_sibling_local(field_name, None); } - } - mc::PositionalField(tuple_idx) => { - for (i, _f) in def.struct_variant().fields.iter().enumerate() { - if i == tuple_idx { - continue + mc::PositionalField(tuple_idx) => { + for (i, _f) in def.struct_variant().fields.iter().enumerate() { + if i == tuple_idx { + continue + } + let field_name = mc::PositionalField(i); + add_fragment_sibling_local(field_name, None); } - let field_name = mc::PositionalField(i); - add_fragment_sibling_local(field_name, None); } } } - } - - (&ty::TyUnion(..), None) => { - // Do nothing, all union fields are moved/assigned together. - } - - (&ty::TyEnum(def, _), ref enum_variant_info) => { - let variant = match *enum_variant_info { - Some((vid, ref _lp2)) => def.variant_with_id(vid), - None => { - assert!(def.is_univariant()); - &def.variants[0] - } - }; - match *origin_field_name { - mc::NamedField(ast_name) => { - for field in &variant.fields { - if field.name == ast_name { - continue; + AdtKind::Union => { + // Do nothing, all union fields are moved/assigned together. + } + AdtKind::Enum => { + let variant = match enum_variant_info { + Some((vid, ref _lp2)) => def.variant_with_id(vid), + None => { + assert!(def.is_univariant()); + &def.variants[0] + } + }; + match *origin_field_name { + mc::NamedField(ast_name) => { + for field in &variant.fields { + if field.name == ast_name { + continue; + } + let field_name = mc::NamedField(field.name); + add_fragment_sibling_local(field_name, Some(variant.did)); } - let field_name = mc::NamedField(field.name); - add_fragment_sibling_local(field_name, Some(variant.did)); } - } - mc::PositionalField(tuple_idx) => { - for (i, _f) in variant.fields.iter().enumerate() { - if tuple_idx == i { - continue; + mc::PositionalField(tuple_idx) => { + for (i, _f) in variant.fields.iter().enumerate() { + if tuple_idx == i { + continue; + } + let field_name = mc::PositionalField(i); + add_fragment_sibling_local(field_name, None); } - let field_name = mc::PositionalField(i); - add_fragment_sibling_local(field_name, None); } } } - } + }, - ref sty_and_variant_info => { + ref ty => { let opt_span = origin_id.and_then(|id|tcx.map.opt_span(id)); span_bug!(opt_span.unwrap_or(DUMMY_SP), "type {:?} ({:?}) is not fragmentable", - parent_ty, - sty_and_variant_info); + parent_ty, ty); } } } diff --git a/src/librustc_borrowck/borrowck/gather_loans/gather_moves.rs b/src/librustc_borrowck/borrowck/gather_loans/gather_moves.rs index 5f2d6c406c4b9..3e335dacc8ed9 100644 --- a/src/librustc_borrowck/borrowck/gather_loans/gather_moves.rs +++ b/src/librustc_borrowck/borrowck/gather_loans/gather_moves.rs @@ -178,7 +178,7 @@ fn check_and_get_illegal_move_origin<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>, Categorization::Interior(ref b, mc::InteriorField(_)) | Categorization::Interior(ref b, mc::InteriorElement(Kind::Pattern, _)) => { match b.ty.sty { - ty::TyStruct(def, _) | ty::TyUnion(def, _) | ty::TyEnum(def, _) => { + ty::TyAdt(def, _) => { if def.has_dtor() { Some(cmt.clone()) } else { diff --git a/src/librustc_borrowck/borrowck/gather_loans/move_error.rs b/src/librustc_borrowck/borrowck/gather_loans/move_error.rs index bda68a1cd1ceb..3fa7c252b842c 100644 --- a/src/librustc_borrowck/borrowck/gather_loans/move_error.rs +++ b/src/librustc_borrowck/borrowck/gather_loans/move_error.rs @@ -148,9 +148,7 @@ fn report_cannot_move_out_of<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>, Categorization::Downcast(ref b, _) | Categorization::Interior(ref b, mc::InteriorField(_)) => { match b.ty.sty { - ty::TyStruct(def, _) | - ty::TyUnion(def, _) | - ty::TyEnum(def, _) if def.has_dtor() => { + ty::TyAdt(def, _) if def.has_dtor() => { let mut err = struct_span_err!(bccx, move_from.span, E0509, "cannot move out of type `{}`, \ which implements the `Drop` trait", diff --git a/src/librustc_borrowck/borrowck/gather_loans/restrictions.rs b/src/librustc_borrowck/borrowck/gather_loans/restrictions.rs index c08dc9330b8fd..fdcefdc0d4307 100644 --- a/src/librustc_borrowck/borrowck/gather_loans/restrictions.rs +++ b/src/librustc_borrowck/borrowck/gather_loans/restrictions.rs @@ -103,8 +103,8 @@ impl<'a, 'tcx> RestrictionsContext<'a, 'tcx> { let base_ty = cmt_base.ty; let result = self.restrict(cmt_base); // Borrowing one union field automatically borrows all its fields. - if let ty::TyUnion(ref adt_def, _) = base_ty.sty { - match result { + match base_ty.sty { + ty::TyAdt(adt_def, _) if adt_def.is_union() => match result { RestrictionResult::Safe => RestrictionResult::Safe, RestrictionResult::SafeIf(base_lp, mut base_vec) => { for field in &adt_def.struct_variant().fields { @@ -124,9 +124,8 @@ impl<'a, 'tcx> RestrictionsContext<'a, 'tcx> { LpInterior(opt_variant_id, interior))); RestrictionResult::SafeIf(lp, base_vec) } - } - } else { - self.extend(result, &cmt, LpInterior(opt_variant_id, interior)) + }, + _ => self.extend(result, &cmt, LpInterior(opt_variant_id, interior)) } } diff --git a/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs b/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs index c5d1034537989..71274b7e0218a 100644 --- a/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs +++ b/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs @@ -709,7 +709,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { fn open_drop<'a>(&mut self, c: &DropCtxt<'a, 'tcx>) -> BasicBlock { let ty = c.lvalue.ty(self.mir, self.tcx).to_ty(self.tcx); match ty.sty { - ty::TyStruct(def, substs) | ty::TyUnion(def, substs) | ty::TyEnum(def, substs) => { + ty::TyAdt(def, substs) => { self.open_drop_for_adt(c, def, substs) } ty::TyTuple(tys) | ty::TyClosure(_, ty::ClosureSubsts { @@ -893,7 +893,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { let ty = c.lvalue.ty(self.mir, self.tcx).to_ty(self.tcx); match ty.sty { - ty::TyStruct(def, _) | ty::TyUnion(def, _) | ty::TyEnum(def, _) => { + ty::TyAdt(def, _) => { if def.has_dtor() { self.tcx.sess.span_warn( c.source_info.span, diff --git a/src/librustc_borrowck/borrowck/mir/mod.rs b/src/librustc_borrowck/borrowck/mir/mod.rs index 9c462feeaadd7..e035e268b1c4c 100644 --- a/src/librustc_borrowck/borrowck/mir/mod.rs +++ b/src/librustc_borrowck/borrowck/mir/mod.rs @@ -261,7 +261,7 @@ fn lvalue_contents_drop_state_cannot_differ<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx lv, ty); true } - ty::TyStruct(def, _) | ty::TyUnion(def, _) | ty::TyEnum(def, _) if def.has_dtor() => { + ty::TyAdt(def, _) if def.has_dtor() => { debug!("lvalue_contents_drop_state_cannot_differ lv: {:?} ty: {:?} Drop => false", lv, ty); true diff --git a/src/librustc_borrowck/borrowck/move_data.rs b/src/librustc_borrowck/borrowck/move_data.rs index 0c9261df54870..e9ba406389f88 100644 --- a/src/librustc_borrowck/borrowck/move_data.rs +++ b/src/librustc_borrowck/borrowck/move_data.rs @@ -367,20 +367,22 @@ impl<'a, 'tcx> MoveData<'tcx> { kind: MoveKind) { // Moving one union field automatically moves all its fields. if let LpExtend(ref base_lp, mutbl, LpInterior(opt_variant_id, interior)) = lp.kind { - if let ty::TyUnion(ref adt_def, _) = base_lp.ty.sty { - for field in &adt_def.struct_variant().fields { - let field = InteriorKind::InteriorField(mc::NamedField(field.name)); - let field_ty = if field == interior { - lp.ty - } else { - tcx.types.err // Doesn't matter - }; - let sibling_lp_kind = LpExtend(base_lp.clone(), mutbl, - LpInterior(opt_variant_id, field)); - let sibling_lp = Rc::new(LoanPath::new(sibling_lp_kind, field_ty)); - self.add_move_helper(tcx, sibling_lp, id, kind); + if let ty::TyAdt(adt_def, _) = base_lp.ty.sty { + if adt_def.is_union() { + for field in &adt_def.struct_variant().fields { + let field = InteriorKind::InteriorField(mc::NamedField(field.name)); + let field_ty = if field == interior { + lp.ty + } else { + tcx.types.err // Doesn't matter + }; + let sibling_lp_kind = LpExtend(base_lp.clone(), mutbl, + LpInterior(opt_variant_id, field)); + let sibling_lp = Rc::new(LoanPath::new(sibling_lp_kind, field_ty)); + self.add_move_helper(tcx, sibling_lp, id, kind); + } + return; } - return; } } @@ -422,20 +424,23 @@ impl<'a, 'tcx> MoveData<'tcx> { mode: euv::MutateMode) { // Assigning to one union field automatically assigns to all its fields. if let LpExtend(ref base_lp, mutbl, LpInterior(opt_variant_id, interior)) = lp.kind { - if let ty::TyUnion(ref adt_def, _) = base_lp.ty.sty { - for field in &adt_def.struct_variant().fields { - let field = InteriorKind::InteriorField(mc::NamedField(field.name)); - let field_ty = if field == interior { - lp.ty - } else { - tcx.types.err // Doesn't matter - }; - let sibling_lp_kind = LpExtend(base_lp.clone(), mutbl, - LpInterior(opt_variant_id, field)); - let sibling_lp = Rc::new(LoanPath::new(sibling_lp_kind, field_ty)); - self.add_assignment_helper(tcx, sibling_lp, assign_id, span, assignee_id, mode); + if let ty::TyAdt(adt_def, _) = base_lp.ty.sty { + if adt_def.is_union() { + for field in &adt_def.struct_variant().fields { + let field = InteriorKind::InteriorField(mc::NamedField(field.name)); + let field_ty = if field == interior { + lp.ty + } else { + tcx.types.err // Doesn't matter + }; + let sibling_lp_kind = LpExtend(base_lp.clone(), mutbl, + LpInterior(opt_variant_id, field)); + let sibling_lp = Rc::new(LoanPath::new(sibling_lp_kind, field_ty)); + self.add_assignment_helper(tcx, sibling_lp, assign_id, + span, assignee_id, mode); + } + return; } - return; } } diff --git a/src/librustc_const_eval/check_match.rs b/src/librustc_const_eval/check_match.rs index e49011d887370..da4445ef68947 100644 --- a/src/librustc_const_eval/check_match.rs +++ b/src/librustc_const_eval/check_match.rs @@ -245,21 +245,23 @@ fn check_for_bindings_named_the_same_as_variants(cx: &MatchCheckCtxt, pat: &Pat) pat.walk(|p| { if let PatKind::Binding(hir::BindByValue(hir::MutImmutable), name, None) = p.node { let pat_ty = cx.tcx.pat_ty(p); - if let ty::TyEnum(edef, _) = pat_ty.sty { - if let Def::Local(..) = cx.tcx.expect_def(p.id) { - if edef.variants.iter().any(|variant| { - variant.name == name.node && variant.kind == VariantKind::Unit - }) { - let ty_path = cx.tcx.item_path_str(edef.did); - let mut err = struct_span_warn!(cx.tcx.sess, p.span, E0170, - "pattern binding `{}` is named the same as one \ - of the variants of the type `{}`", - name.node, ty_path); - help!(err, - "if you meant to match on a variant, \ - consider making the path in the pattern qualified: `{}::{}`", - ty_path, name.node); - err.emit(); + if let ty::TyAdt(edef, _) = pat_ty.sty { + if edef.is_enum() { + if let Def::Local(..) = cx.tcx.expect_def(p.id) { + if edef.variants.iter().any(|variant| { + variant.name == name.node && variant.kind == VariantKind::Unit + }) { + let ty_path = cx.tcx.item_path_str(edef.did); + let mut err = struct_span_warn!(cx.tcx.sess, p.span, E0170, + "pattern binding `{}` is named the same as one \ + of the variants of the type `{}`", + name.node, ty_path); + help!(err, + "if you meant to match on a variant, \ + consider making the path in the pattern qualified: `{}::{}`", + ty_path, name.node); + err.emit(); + } } } } @@ -566,7 +568,7 @@ fn construct_witness<'a,'tcx>(cx: &MatchCheckCtxt<'a,'tcx>, ctor: &Constructor, let pat = match left_ty.sty { ty::TyTuple(..) => PatKind::Tuple(pats.collect(), None), - ty::TyEnum(adt, _) | ty::TyStruct(adt, _) | ty::TyUnion(adt, _) => { + ty::TyAdt(adt, _) => { let v = ctor.variant_for_adt(adt); match v.kind { VariantKind::Struct => { @@ -659,7 +661,8 @@ fn all_constructors(_cx: &MatchCheckCtxt, left_ty: Ty, [true, false].iter().map(|b| ConstantValue(ConstVal::Bool(*b))).collect(), ty::TySlice(_) => (0..max_slice_length+1).map(|length| Slice(length)).collect(), - ty::TyEnum(def, _) => def.variants.iter().map(|v| Variant(v.did)).collect(), + ty::TyAdt(def, _) if def.is_enum() => + def.variants.iter().map(|v| Variant(v.did)).collect(), _ => vec![Single] } } @@ -837,7 +840,7 @@ pub fn constructor_arity(_cx: &MatchCheckCtxt, ctor: &Constructor, ty: Ty) -> us _ => bug!() }, ty::TyRef(..) => 1, - ty::TyEnum(adt, _) | ty::TyStruct(adt, _) | ty::TyUnion(adt, _) => { + ty::TyAdt(adt, _) => { ctor.variant_for_adt(adt).fields.len() } ty::TyArray(_, n) => n, diff --git a/src/librustc_const_eval/eval.rs b/src/librustc_const_eval/eval.rs index 30e5a0cacf551..4f4c16d3f6a61 100644 --- a/src/librustc_const_eval/eval.rs +++ b/src/librustc_const_eval/eval.rs @@ -257,8 +257,11 @@ pub fn const_expr_to_pat<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, span, format!("floating point constants cannot be used in patterns")); } - ty::TyEnum(adt_def, _) | - ty::TyStruct(adt_def, _) => { + ty::TyAdt(adt_def, _) if adt_def.is_union() => { + // Matching on union fields is unsafe, we can't hide it in constants + tcx.sess.span_err(span, "cannot use unions in constant patterns"); + } + ty::TyAdt(adt_def, _) => { if !tcx.has_attr(adt_def.did, "structural_match") { tcx.sess.add_lint( lint::builtin::ILLEGAL_STRUCT_OR_ENUM_CONSTANT_PATTERN, @@ -271,10 +274,6 @@ pub fn const_expr_to_pat<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, tcx.item_path_str(adt_def.did))); } } - ty::TyUnion(..) => { - // Matching on union fields is unsafe, we can't hide it in constants - tcx.sess.span_err(span, "cannot use unions in constant patterns"); - } _ => { } } let pat = match expr.node { @@ -1039,7 +1038,7 @@ fn infer<'a, 'tcx>(i: ConstInt, (&ty::TyInt(ity), i) => Err(TypeMismatch(ity.to_string(), i)), (&ty::TyUint(ity), i) => Err(TypeMismatch(ity.to_string(), i)), - (&ty::TyEnum(ref adt, _), i) => { + (&ty::TyAdt(adt, _), i) if adt.is_enum() => { let hints = tcx.lookup_repr_hints(adt.did); let int_ty = tcx.enum_repr_type(hints.iter().next()); infer(i, tcx, &int_ty.to_ty(tcx).sty) @@ -1230,7 +1229,7 @@ fn lit_to_const<'a, 'tcx>(lit: &ast::LitKind, infer(Infer(n), tcx, &ty::TyUint(uty)).map(Integral) }, None => Ok(Integral(Infer(n))), - Some(&ty::TyEnum(ref adt, _)) => { + Some(&ty::TyAdt(adt, _)) => { let hints = tcx.lookup_repr_hints(adt.did); let int_ty = tcx.enum_repr_type(hints.iter().next()); infer(Infer(n), tcx, &int_ty.to_ty(tcx).sty).map(Integral) diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index a73930fa52517..b610a924a3396 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -468,21 +468,21 @@ impl LateLintPass for MissingCopyImplementations { return; } let def = cx.tcx.lookup_adt_def(cx.tcx.map.local_def_id(item.id)); - (def, cx.tcx.mk_struct(def, Substs::empty(cx.tcx))) + (def, cx.tcx.mk_adt(def, Substs::empty(cx.tcx))) } hir::ItemUnion(_, ref ast_generics) => { if ast_generics.is_parameterized() { return; } let def = cx.tcx.lookup_adt_def(cx.tcx.map.local_def_id(item.id)); - (def, cx.tcx.mk_union(def, Substs::empty(cx.tcx))) + (def, cx.tcx.mk_adt(def, Substs::empty(cx.tcx))) } hir::ItemEnum(_, ref ast_generics) => { if ast_generics.is_parameterized() { return; } let def = cx.tcx.lookup_adt_def(cx.tcx.map.local_def_id(item.id)); - (def, cx.tcx.mk_enum(def, Substs::empty(cx.tcx))) + (def, cx.tcx.mk_adt(def, Substs::empty(cx.tcx))) } _ => return, }; diff --git a/src/librustc_lint/types.rs b/src/librustc_lint/types.rs index 54cec3fd7e135..a6049acdb10d4 100644 --- a/src/librustc_lint/types.rs +++ b/src/librustc_lint/types.rs @@ -12,7 +12,7 @@ use rustc::hir::def_id::DefId; use rustc::ty::subst::Substs; -use rustc::ty::{self, Ty, TyCtxt}; +use rustc::ty::{self, AdtKind, Ty, TyCtxt}; use rustc::ty::layout::{Layout, Primitive}; use rustc::traits::Reveal; use middle::const_val::ConstVal; @@ -431,110 +431,112 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { } match ty.sty { - ty::TyStruct(def, substs) => { - if !cx.lookup_repr_hints(def.did).contains(&attr::ReprExtern) { - return FfiUnsafe( - "found struct without foreign-function-safe \ - representation annotation in foreign module, \ - consider adding a #[repr(C)] attribute to \ - the type"); - } + ty::TyAdt(def, substs) => match def.adt_kind() { + AdtKind::Struct => { + if !cx.lookup_repr_hints(def.did).contains(&attr::ReprExtern) { + return FfiUnsafe( + "found struct without foreign-function-safe \ + representation annotation in foreign module, \ + consider adding a #[repr(C)] attribute to \ + the type"); + } - // We can't completely trust repr(C) markings; make sure the - // fields are actually safe. - if def.struct_variant().fields.is_empty() { - return FfiUnsafe( - "found zero-size struct in foreign module, consider \ - adding a member to this struct"); - } + // We can't completely trust repr(C) markings; make sure the + // fields are actually safe. + if def.struct_variant().fields.is_empty() { + return FfiUnsafe( + "found zero-size struct in foreign module, consider \ + adding a member to this struct"); + } - for field in &def.struct_variant().fields { - let field_ty = cx.normalize_associated_type(&field.ty(cx, substs)); - let r = self.check_type_for_ffi(cache, field_ty); - match r { - FfiSafe => {} - FfiBadStruct(..) | FfiBadUnion(..) | FfiBadEnum(..) => { return r; } - FfiUnsafe(s) => { return FfiBadStruct(def.did, s); } + for field in &def.struct_variant().fields { + let field_ty = cx.normalize_associated_type(&field.ty(cx, substs)); + let r = self.check_type_for_ffi(cache, field_ty); + match r { + FfiSafe => {} + FfiBadStruct(..) | FfiBadUnion(..) | FfiBadEnum(..) => { return r; } + FfiUnsafe(s) => { return FfiBadStruct(def.did, s); } + } } + FfiSafe } - FfiSafe - } - ty::TyUnion(def, substs) => { - if !cx.lookup_repr_hints(def.did).contains(&attr::ReprExtern) { - return FfiUnsafe( - "found union without foreign-function-safe \ - representation annotation in foreign module, \ - consider adding a #[repr(C)] attribute to \ - the type"); - } + AdtKind::Union => { + if !cx.lookup_repr_hints(def.did).contains(&attr::ReprExtern) { + return FfiUnsafe( + "found union without foreign-function-safe \ + representation annotation in foreign module, \ + consider adding a #[repr(C)] attribute to \ + the type"); + } - for field in &def.struct_variant().fields { - let field_ty = cx.normalize_associated_type(&field.ty(cx, substs)); - let r = self.check_type_for_ffi(cache, field_ty); - match r { - FfiSafe => {} - FfiBadStruct(..) | FfiBadUnion(..) | FfiBadEnum(..) => { return r; } - FfiUnsafe(s) => { return FfiBadUnion(def.did, s); } + for field in &def.struct_variant().fields { + let field_ty = cx.normalize_associated_type(&field.ty(cx, substs)); + let r = self.check_type_for_ffi(cache, field_ty); + match r { + FfiSafe => {} + FfiBadStruct(..) | FfiBadUnion(..) | FfiBadEnum(..) => { return r; } + FfiUnsafe(s) => { return FfiBadUnion(def.did, s); } + } } + FfiSafe } - FfiSafe - } - ty::TyEnum(def, substs) => { - if def.variants.is_empty() { - // Empty enums are okay... although sort of useless. - return FfiSafe - } + AdtKind::Enum => { + if def.variants.is_empty() { + // Empty enums are okay... although sort of useless. + return FfiSafe + } - // Check for a repr() attribute to specify the size of the - // discriminant. - let repr_hints = cx.lookup_repr_hints(def.did); - match &repr_hints[..] { - &[] => { - // Special-case types like `Option`. - if !is_repr_nullable_ptr(cx, def, substs) { - return FfiUnsafe( - "found enum without foreign-function-safe \ - representation annotation in foreign module, \ - consider adding a #[repr(...)] attribute to \ - the type") + // Check for a repr() attribute to specify the size of the + // discriminant. + let repr_hints = cx.lookup_repr_hints(def.did); + match &repr_hints[..] { + &[] => { + // Special-case types like `Option`. + if !is_repr_nullable_ptr(cx, def, substs) { + return FfiUnsafe( + "found enum without foreign-function-safe \ + representation annotation in foreign module, \ + consider adding a #[repr(...)] attribute to \ + the type") + } } - } - &[ref hint] => { - if !hint.is_ffi_safe() { + &[ref hint] => { + if !hint.is_ffi_safe() { + // FIXME: This shouldn't be reachable: we should check + // this earlier. + return FfiUnsafe( + "enum has unexpected #[repr(...)] attribute") + } + + // Enum with an explicitly sized discriminant; either + // a C-style enum or a discriminated union. + + // The layout of enum variants is implicitly repr(C). + // FIXME: Is that correct? + } + _ => { // FIXME: This shouldn't be reachable: we should check // this earlier. return FfiUnsafe( - "enum has unexpected #[repr(...)] attribute") + "enum has too many #[repr(...)] attributes"); } - - // Enum with an explicitly sized discriminant; either - // a C-style enum or a discriminated union. - - // The layout of enum variants is implicitly repr(C). - // FIXME: Is that correct? - } - _ => { - // FIXME: This shouldn't be reachable: we should check - // this earlier. - return FfiUnsafe( - "enum has too many #[repr(...)] attributes"); } - } - // Check the contained variants. - for variant in &def.variants { - for field in &variant.fields { - let arg = cx.normalize_associated_type(&field.ty(cx, substs)); - let r = self.check_type_for_ffi(cache, arg); - match r { - FfiSafe => {} - FfiBadStruct(..) | FfiBadUnion(..) | FfiBadEnum(..) => { return r; } - FfiUnsafe(s) => { return FfiBadEnum(def.did, s); } + // Check the contained variants. + for variant in &def.variants { + for field in &variant.fields { + let arg = cx.normalize_associated_type(&field.ty(cx, substs)); + let r = self.check_type_for_ffi(cache, arg); + match r { + FfiSafe => {} + FfiBadStruct(..) | FfiBadUnion(..) | FfiBadEnum(..) => { return r; } + FfiUnsafe(s) => { return FfiBadEnum(def.did, s); } + } } } + FfiSafe } - FfiSafe - } + }, ty::TyChar => { FfiUnsafe("found Rust type `char` in foreign module, while \ diff --git a/src/librustc_lint/unused.rs b/src/librustc_lint/unused.rs index f07720f5202bd..d31f16df69356 100644 --- a/src/librustc_lint/unused.rs +++ b/src/librustc_lint/unused.rs @@ -136,9 +136,7 @@ impl LateLintPass for UnusedResults { ty::TyTuple(ref tys) if tys.is_empty() => return, ty::TyNever => return, ty::TyBool => return, - ty::TyStruct(def, _) | - ty::TyUnion(def, _) | - ty::TyEnum(def, _) => { + ty::TyAdt(def, _) => { let attrs = cx.tcx.get_attrs(def.did); check_must_use(cx, &attrs[..], s.span) } diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index 6b48b4dfabcfd..4dc06f0d02496 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -36,7 +36,7 @@ use rustc::hir::def::Def; use rustc::hir::def_id::{DefId, DefIndex}; use middle::lang_items; use rustc::ty::{ImplContainer, TraitContainer}; -use rustc::ty::{self, Ty, TyCtxt, TypeFoldable, VariantKind}; +use rustc::ty::{self, AdtKind, Ty, TyCtxt, TypeFoldable, VariantKind}; use rustc_const_math::ConstInt; @@ -453,23 +453,19 @@ pub fn get_adt_def<'a, 'tcx>(cdata: Cmd, let mut ctor_did = None; let (kind, variants) = match item_family(doc) { Enum => { - (ty::AdtKind::Enum, - get_enum_variants(cdata, doc)) + (AdtKind::Enum, get_enum_variants(cdata, doc)) } Struct(..) => { // Use separate constructor id for unit/tuple structs and reuse did for braced structs. ctor_did = reader::maybe_get_doc(doc, tag_items_data_item_struct_ctor).map(|ctor_doc| { translated_def_id(cdata, ctor_doc) }); - (ty::AdtKind::Struct, - vec![get_struct_variant(cdata, doc, ctor_did.unwrap_or(did))]) + (AdtKind::Struct, vec![get_struct_variant(cdata, doc, ctor_did.unwrap_or(did))]) } Union => { - (ty::AdtKind::Union, - vec![get_struct_variant(cdata, doc, did)]) + (AdtKind::Union, vec![get_struct_variant(cdata, doc, did)]) } - _ => bug!("get_adt_def called on a non-ADT {:?} - {:?}", - item_family(doc), did) + _ => bug!("get_adt_def called on a non-ADT {:?} - {:?}", item_family(doc), did) }; let adt = tcx.intern_adt_def(did, kind, variants); @@ -481,8 +477,7 @@ pub fn get_adt_def<'a, 'tcx>(cdata: Cmd, // this needs to be done *after* the variant is interned, // to support recursive structures for variant in &adt.variants { - if variant.kind == ty::VariantKind::Tuple && - adt.adt_kind() == ty::AdtKind::Enum { + if variant.kind == ty::VariantKind::Tuple && adt.is_enum() { // tuple-like enum variant fields aren't real items - get the types // from the ctor. debug!("evaluating the ctor-type of {:?}", diff --git a/src/librustc_metadata/tydecode.rs b/src/librustc_metadata/tydecode.rs index 55ff4817683de..bcaf1640bc41b 100644 --- a/src/librustc_metadata/tydecode.rs +++ b/src/librustc_metadata/tydecode.rs @@ -358,14 +358,6 @@ impl<'a,'tcx> TyDecoder<'a,'tcx> { } } 'c' => return tcx.types.char, - 't' => { - assert_eq!(self.next(), '['); - let did = self.parse_def(); - let substs = self.parse_substs(); - assert_eq!(self.next(), ']'); - let def = self.tcx.lookup_adt_def(did); - return tcx.mk_enum(def, substs); - } 'x' => { assert_eq!(self.next(), '['); let trait_ref = ty::Binder(self.parse_existential_trait_ref()); @@ -470,15 +462,7 @@ impl<'a,'tcx> TyDecoder<'a,'tcx> { let substs = self.parse_substs(); assert_eq!(self.next(), ']'); let def = self.tcx.lookup_adt_def(did); - return self.tcx.mk_struct(def, substs); - } - 'U' => { - assert_eq!(self.next(), '['); - let did = self.parse_def(); - let substs = self.parse_substs(); - assert_eq!(self.next(), ']'); - let def = self.tcx.lookup_adt_def(did); - return self.tcx.mk_union(def, substs); + return self.tcx.mk_adt(def, substs); } 'k' => { assert_eq!(self.next(), '['); diff --git a/src/librustc_metadata/tyencode.rs b/src/librustc_metadata/tyencode.rs index bef3cf3a1940f..8030abf6330e7 100644 --- a/src/librustc_metadata/tyencode.rs +++ b/src/librustc_metadata/tyencode.rs @@ -97,11 +97,6 @@ pub fn enc_ty<'a, 'tcx>(w: &mut Cursor>, cx: &ctxt<'a, 'tcx>, t: Ty<'tcx ast::FloatTy::F64 => write!(w, "MF"), }; } - ty::TyEnum(def, substs) => { - write!(w, "t[{}|", (cx.ds)(cx.tcx, def.did)); - enc_substs(w, cx, substs); - write!(w, "]"); - } ty::TyTrait(ref obj) => { write!(w, "x["); enc_existential_trait_ref(w, cx, obj.principal.0); @@ -165,16 +160,11 @@ pub fn enc_ty<'a, 'tcx>(w: &mut Cursor>, cx: &ctxt<'a, 'tcx>, t: Ty<'tcx ty::TyParam(p) => { write!(w, "p[{}|{}]", p.idx, p.name); } - ty::TyStruct(def, substs) => { + ty::TyAdt(def, substs) => { write!(w, "a[{}|", (cx.ds)(cx.tcx, def.did)); enc_substs(w, cx, substs); write!(w, "]"); } - ty::TyUnion(def, substs) => { - write!(w, "U[{}|", (cx.ds)(cx.tcx, def.did)); - enc_substs(w, cx, substs); - write!(w, "]"); - } ty::TyClosure(def, substs) => { write!(w, "k[{}|", (cx.ds)(cx.tcx, def)); enc_substs(w, cx, substs.func_substs); diff --git a/src/librustc_mir/build/expr/as_rvalue.rs b/src/librustc_mir/build/expr/as_rvalue.rs index 6ea1fb5036065..a40571c5d8597 100644 --- a/src/librustc_mir/build/expr/as_rvalue.rs +++ b/src/librustc_mir/build/expr/as_rvalue.rs @@ -181,7 +181,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { ExprKind::Adt { adt_def, variant_index, substs, fields, base } => { // see (*) above - let is_union = adt_def.adt_kind() == ty::AdtKind::Union; + let is_union = adt_def.is_union(); let active_field_index = if is_union { Some(fields[0].name.index()) } else { None }; // first process the set of fields that were provided diff --git a/src/librustc_mir/hair/cx/expr.rs b/src/librustc_mir/hair/cx/expr.rs index 8812287c34294..4518f8cb373fa 100644 --- a/src/librustc_mir/hair/cx/expr.rs +++ b/src/librustc_mir/hair/cx/expr.rs @@ -19,7 +19,7 @@ use rustc::hir::def::Def; use rustc::middle::const_val::ConstVal; use rustc_const_eval as const_eval; use rustc::middle::region::CodeExtent; -use rustc::ty::{self, VariantDef, Ty}; +use rustc::ty::{self, AdtKind, VariantDef, Ty}; use rustc::ty::cast::CastKind as TyCastKind; use rustc::mir::repr::*; use rustc::hir; @@ -459,48 +459,50 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, hir::ExprStruct(_, ref fields, ref base) => { match expr_ty.sty { - ty::TyStruct(adt, substs) | ty::TyUnion(adt, substs) => { - let field_refs = field_refs(&adt.variants[0], fields); - ExprKind::Adt { - adt_def: adt, - variant_index: 0, - substs: substs, - fields: field_refs, - base: base.as_ref().map(|base| { - FruInfo { - base: base.to_ref(), - field_types: cx.tcx.tables - .borrow() - .fru_field_types[&expr.id] - .clone() - } - }) + ty::TyAdt(adt, substs) => match adt.adt_kind() { + AdtKind::Struct | AdtKind::Union => { + let field_refs = field_refs(&adt.variants[0], fields); + ExprKind::Adt { + adt_def: adt, + variant_index: 0, + substs: substs, + fields: field_refs, + base: base.as_ref().map(|base| { + FruInfo { + base: base.to_ref(), + field_types: cx.tcx.tables + .borrow() + .fru_field_types[&expr.id] + .clone() + } + }) + } } - } - ty::TyEnum(adt, substs) => { - match cx.tcx.expect_def(expr.id) { - Def::Variant(enum_id, variant_id) => { - debug_assert!(adt.did == enum_id); - assert!(base.is_none()); - - let index = adt.variant_index_with_id(variant_id); - let field_refs = field_refs(&adt.variants[index], fields); - ExprKind::Adt { - adt_def: adt, - variant_index: index, - substs: substs, - fields: field_refs, - base: None + AdtKind::Enum => { + match cx.tcx.expect_def(expr.id) { + Def::Variant(enum_id, variant_id) => { + debug_assert!(adt.did == enum_id); + assert!(base.is_none()); + + let index = adt.variant_index_with_id(variant_id); + let field_refs = field_refs(&adt.variants[index], fields); + ExprKind::Adt { + adt_def: adt, + variant_index: index, + substs: substs, + fields: field_refs, + base: None + } + } + ref def => { + span_bug!( + expr.span, + "unexpected def: {:?}", + def); } - } - ref def => { - span_bug!( - expr.span, - "unexpected def: {:?}", - def); } } - } + }, _ => { span_bug!( expr.span, @@ -579,13 +581,10 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, body: block::to_expr_ref(cx, body) }, hir::ExprField(ref source, name) => { let index = match cx.tcx.expr_ty_adjusted(source).sty { - ty::TyStruct(adt_def, _) | ty::TyUnion(adt_def, _) => + ty::TyAdt(adt_def, _) => adt_def.variants[0].index_of_field_named(name.node), ref ty => - span_bug!( - expr.span, - "field of non-struct: {:?}", - ty), + span_bug!(expr.span, "field of non-ADT: {:?}", ty), }; let index = index.unwrap_or_else(|| { span_bug!( @@ -680,7 +679,7 @@ fn convert_path_expr<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, ty::TyFnDef(..) => def_id, // A unit struct which is used as a value. We return a completely different ExprKind // here to account for this special case. - ty::TyStruct(adt_def, substs) => return ExprKind::Adt { + ty::TyAdt(adt_def, substs) => return ExprKind::Adt { adt_def: adt_def, variant_index: 0, substs: substs, @@ -694,7 +693,7 @@ fn convert_path_expr<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, // expression. ty::TyFnDef(..) => variant_id, // A unit variant, similar special case to the struct case above. - ty::TyEnum(adt_def, substs) => { + ty::TyAdt(adt_def, substs) => { debug_assert!(adt_def.did == enum_id); let index = adt_def.variant_index_with_id(variant_id); return ExprKind::Adt { diff --git a/src/librustc_mir/hair/cx/pattern.rs b/src/librustc_mir/hair/cx/pattern.rs index 30f79796aaa6d..3639b165eb5ab 100644 --- a/src/librustc_mir/hair/cx/pattern.rs +++ b/src/librustc_mir/hair/cx/pattern.rs @@ -198,8 +198,8 @@ impl<'patcx, 'cx, 'gcx, 'tcx> PatCx<'patcx, 'cx, 'gcx, 'tcx> { PatKind::TupleStruct(_, ref subpatterns, ddpos) => { let pat_ty = self.cx.tcx.node_id_to_type(pat.id); let adt_def = match pat_ty.sty { - ty::TyStruct(adt_def, _) | ty::TyEnum(adt_def, _) => adt_def, - _ => span_bug!(pat.span, "tuple struct pattern not applied to struct or enum"), + ty::TyAdt(adt_def, _) => adt_def, + _ => span_bug!(pat.span, "tuple struct pattern not applied to an ADT"), }; let variant_def = adt_def.variant_of_def(self.cx.tcx.expect_def(pat.id)); @@ -217,13 +217,11 @@ impl<'patcx, 'cx, 'gcx, 'tcx> PatCx<'patcx, 'cx, 'gcx, 'tcx> { PatKind::Struct(_, ref fields, _) => { let pat_ty = self.cx.tcx.node_id_to_type(pat.id); let adt_def = match pat_ty.sty { - ty::TyStruct(adt_def, _) | - ty::TyUnion(adt_def, _) | - ty::TyEnum(adt_def, _) => adt_def, + ty::TyAdt(adt_def, _) => adt_def, _ => { span_bug!( pat.span, - "struct pattern not applied to struct or enum"); + "struct pattern not applied to an ADT"); } }; let variant_def = adt_def.variant_of_def(self.cx.tcx.expect_def(pat.id)); diff --git a/src/librustc_mir/transform/type_check.rs b/src/librustc_mir/transform/type_check.rs index e260b1d262aed..7fda658185e07 100644 --- a/src/librustc_mir/transform/type_check.rs +++ b/src/librustc_mir/transform/type_check.rs @@ -218,7 +218,7 @@ impl<'a, 'b, 'gcx, 'tcx> TypeVerifier<'a, 'b, 'gcx, 'tcx> { } ProjectionElem::Downcast(adt_def1, index) => match base_ty.sty { - ty::TyEnum(adt_def, substs) if adt_def == adt_def1 => { + ty::TyAdt(adt_def, substs) if adt_def.is_enum() && adt_def == adt_def1 => { if index >= adt_def.variants.len() { LvalueTy::Ty { ty: span_mirbug_and_err!( @@ -281,10 +281,7 @@ impl<'a, 'b, 'gcx, 'tcx> TypeVerifier<'a, 'b, 'gcx, 'tcx> { (&adt_def.variants[variant_index], substs) } LvalueTy::Ty { ty } => match ty.sty { - ty::TyStruct(adt_def, substs) | - ty::TyUnion(adt_def, substs) | - ty::TyEnum(adt_def, substs) - if adt_def.is_univariant() => { + ty::TyAdt(adt_def, substs) if adt_def.is_univariant() => { (&adt_def.variants[0], substs) } ty::TyTuple(tys) | ty::TyClosure(_, ty::ClosureSubsts { @@ -364,7 +361,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { StatementKind::SetDiscriminant{ ref lvalue, variant_index } => { let lvalue_type = lvalue.ty(mir, tcx).to_ty(tcx); let adt = match lvalue_type.sty { - TypeVariants::TyEnum(adt, _) => adt, + TypeVariants::TyAdt(adt, _) if adt.is_enum() => adt, _ => { span_bug!(stmt.source_info.span, "bad set discriminant ({:?} = {:?}): lhs is not an enum", @@ -444,9 +441,10 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { TerminatorKind::Switch { ref discr, adt_def, ref targets } => { let discr_ty = discr.ty(mir, tcx).to_ty(tcx); match discr_ty.sty { - ty::TyEnum(def, _) - if def == adt_def && adt_def.variants.len() == targets.len() - => {}, + ty::TyAdt(def, _) if def.is_enum() && + def == adt_def && + adt_def.variants.len() == targets.len() + => {}, _ => { span_mirbug!(self, term, "bad Switch ({:?} on {:?})", adt_def, discr_ty); diff --git a/src/librustc_passes/consts.rs b/src/librustc_passes/consts.rs index d4e8eb51cde27..f919e42b6bd7d 100644 --- a/src/librustc_passes/consts.rs +++ b/src/librustc_passes/consts.rs @@ -439,9 +439,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for CheckCrateVisitor<'a, 'tcx> { /// instead of producing errors. fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, e: &hir::Expr, node_ty: Ty<'tcx>) { match node_ty.sty { - ty::TyStruct(def, _) | - ty::TyUnion(def, _) | - ty::TyEnum(def, _) if def.has_dtor() => { + ty::TyAdt(def, _) if def.has_dtor() => { v.add_qualif(ConstQualif::NEEDS_DROP); } _ => {} diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs index 8c72933c4ce46..4012c1cb34889 100644 --- a/src/librustc_privacy/lib.rs +++ b/src/librustc_privacy/lib.rs @@ -384,11 +384,9 @@ impl<'a, 'tcx> PrivacyVisitor<'a, 'tcx> { // Checks that a field is in scope. fn check_field(&mut self, span: Span, def: ty::AdtDef<'tcx>, field: ty::FieldDef<'tcx>) { - if def.adt_kind() != ty::AdtKind::Enum && - !field.vis.is_accessible_from(self.curitem, &self.tcx.map) { - let kind_descr = if def.adt_kind() == ty::AdtKind::Union { "union" } else { "struct" }; + if !def.is_enum() && !field.vis.is_accessible_from(self.curitem, &self.tcx.map) { struct_span_err!(self.tcx.sess, span, E0451, "field `{}` of {} `{}` is private", - field.name, kind_descr, self.tcx.item_path_str(def.did)) + field.name, def.variant_descr(), self.tcx.item_path_str(def.did)) .span_label(span, &format!("field `{}` is private", field.name)) .emit(); } @@ -438,7 +436,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for PrivacyVisitor<'a, 'tcx> { // (i.e. `all_fields - fields`), just check them all, // unless the ADT is a union, then unmentioned fields // are not checked. - if adt.adt_kind() == ty::AdtKind::Union { + if adt.is_union() { for expr_field in expr_fields { self.check_field(expr.span, adt, variant.field_named(expr_field.name.node)); } @@ -511,7 +509,8 @@ impl<'a, 'tcx, 'v> Visitor<'v> for PrivacyVisitor<'a, 'tcx> { } PatKind::TupleStruct(_, ref fields, ddpos) => { match self.tcx.pat_ty(pattern).sty { - ty::TyStruct(def, _) => { + // enum fields have no privacy at this time + ty::TyAdt(def, _) if !def.is_enum() => { let expected_len = def.struct_variant().fields.len(); for (i, field) in fields.iter().enumerate_and_adjust(expected_len, ddpos) { if let PatKind::Wild = field.node { @@ -520,9 +519,6 @@ impl<'a, 'tcx, 'v> Visitor<'v> for PrivacyVisitor<'a, 'tcx> { self.check_field(field.span, def, &def.struct_variant().fields[i]); } } - ty::TyEnum(..) => { - // enum fields have no privacy at this time - } _ => {} } } diff --git a/src/librustc_save_analysis/dump_visitor.rs b/src/librustc_save_analysis/dump_visitor.rs index ebd0bdc71d7f0..27ee5765c99fa 100644 --- a/src/librustc_save_analysis/dump_visitor.rs +++ b/src/librustc_save_analysis/dump_visitor.rs @@ -1338,7 +1338,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump +'ll> Visitor for DumpVisitor<'l, 'tcx, 'll, D> }; let ty = &self.tcx.expr_ty_adjusted(&hir_node).sty; match *ty { - ty::TyStruct(def, _) => { + ty::TyAdt(def, _) => { let sub_span = self.span.sub_span_after_token(ex.span, token::Dot); if !self.span.filter_generated(sub_span, ex.span) { self.dumper.variable_ref(VariableRefData { diff --git a/src/librustc_save_analysis/lib.rs b/src/librustc_save_analysis/lib.rs index 04cd72ac2d364..868e3bb1f1b73 100644 --- a/src/librustc_save_analysis/lib.rs +++ b/src/librustc_save_analysis/lib.rs @@ -420,7 +420,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { } }; match self.tcx.expr_ty_adjusted(&hir_node).sty { - ty::TyStruct(def, _) | ty::TyUnion(def, _) => { + ty::TyAdt(def, _) if !def.is_enum() => { let f = def.struct_variant().field_named(ident.node.name); let sub_span = self.span_utils.span_for_last_ident(expr.span); filter!(self.span_utils, sub_span, expr.span, None); @@ -432,14 +432,14 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { })); } _ => { - debug!("Expected struct type, found {:?}", ty); + debug!("Expected struct or union type, found {:?}", ty); None } } } ast::ExprKind::Struct(ref path, ..) => { match self.tcx.expr_ty_adjusted(&hir_node).sty { - ty::TyStruct(def, _) | ty::TyUnion(def, _) => { + ty::TyAdt(def, _) if !def.is_enum() => { let sub_span = self.span_utils.span_for_last_ident(path.span); filter!(self.span_utils, sub_span, path.span, None); Some(Data::TypeRefData(TypeRefData { @@ -450,9 +450,9 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { })) } _ => { - // FIXME ty could legitimately be a TyEnum, but then we will fail + // FIXME ty could legitimately be an enum, but then we will fail // later if we try to look up the fields. - debug!("expected TyStruct, found {:?}", ty); + debug!("expected struct or union, found {:?}", ty); None } } diff --git a/src/librustc_trans/adt.rs b/src/librustc_trans/adt.rs index 9eeefa079fb63..e8498363e45a3 100644 --- a/src/librustc_trans/adt.rs +++ b/src/librustc_trans/adt.rs @@ -49,7 +49,7 @@ use std::rc::Rc; use llvm::{ValueRef, True, IntEQ, IntNE}; use rustc::ty::subst::Substs; -use rustc::ty::{self, Ty, TyCtxt}; +use rustc::ty::{self, AdtKind, Ty, TyCtxt}; use syntax::ast; use syntax::attr; use syntax::attr::IntType; @@ -179,172 +179,174 @@ fn represent_type_uncached<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, ty::TyTuple(ref elems) => { Univariant(mk_struct(cx, &elems[..], false, t)) } - ty::TyStruct(def, substs) => { - let ftys = def.struct_variant().fields.iter().map(|field| { - monomorphize::field_ty(cx.tcx(), substs, field) - }).collect::>(); - let packed = cx.tcx().lookup_packed(def.did); - - Univariant(mk_struct(cx, &ftys[..], packed, t)) - } - ty::TyUnion(def, substs) => { - let ftys = def.struct_variant().fields.iter().map(|field| { - monomorphize::field_ty(cx.tcx(), substs, field) - }).collect::>(); - let packed = cx.tcx().lookup_packed(def.did); - UntaggedUnion(mk_union(cx, &ftys[..], packed, t)) - } ty::TyClosure(_, ref substs) => { Univariant(mk_struct(cx, &substs.upvar_tys, false, t)) } - ty::TyEnum(def, substs) => { - let cases = get_cases(cx.tcx(), def, substs); - let hint = *cx.tcx().lookup_repr_hints(def.did).get(0) - .unwrap_or(&attr::ReprAny); - - if cases.is_empty() { - // Uninhabitable; represent as unit - // (Typechecking will reject discriminant-sizing attrs.) - assert_eq!(hint, attr::ReprAny); - return Univariant(mk_struct(cx, &[], false, t)); + ty::TyAdt(def, substs) => match def.adt_kind() { + AdtKind::Struct => { + let ftys = def.struct_variant().fields.iter().map(|field| { + monomorphize::field_ty(cx.tcx(), substs, field) + }).collect::>(); + let packed = cx.tcx().lookup_packed(def.did); + + Univariant(mk_struct(cx, &ftys[..], packed, t)) } - - if cases.iter().all(|c| c.tys.is_empty()) { - // All bodies empty -> intlike - let discrs: Vec<_> = cases.iter().map(|c| Disr::from(c.discr)).collect(); - let bounds = IntBounds { - ulo: discrs.iter().min().unwrap().0, - uhi: discrs.iter().max().unwrap().0, - slo: discrs.iter().map(|n| n.0 as i64).min().unwrap(), - shi: discrs.iter().map(|n| n.0 as i64).max().unwrap() - }; - return mk_cenum(cx, hint, &bounds); + AdtKind::Union => { + let ftys = def.struct_variant().fields.iter().map(|field| { + monomorphize::field_ty(cx.tcx(), substs, field) + }).collect::>(); + let packed = cx.tcx().lookup_packed(def.did); + UntaggedUnion(mk_union(cx, &ftys[..], packed, t)) } + AdtKind::Enum => { + let cases = get_cases(cx.tcx(), def, substs); + let hint = *cx.tcx().lookup_repr_hints(def.did).get(0) + .unwrap_or(&attr::ReprAny); + + if cases.is_empty() { + // Uninhabitable; represent as unit + // (Typechecking will reject discriminant-sizing attrs.) + assert_eq!(hint, attr::ReprAny); + return Univariant(mk_struct(cx, &[], false, t)); + } - // Since there's at least one - // non-empty body, explicit discriminants should have - // been rejected by a checker before this point. - if !cases.iter().enumerate().all(|(i,c)| c.discr == Disr::from(i)) { - bug!("non-C-like enum {} with specified discriminants", - cx.tcx().item_path_str(def.did)); - } + if cases.iter().all(|c| c.tys.is_empty()) { + // All bodies empty -> intlike + let discrs: Vec<_> = cases.iter().map(|c| Disr::from(c.discr)).collect(); + let bounds = IntBounds { + ulo: discrs.iter().min().unwrap().0, + uhi: discrs.iter().max().unwrap().0, + slo: discrs.iter().map(|n| n.0 as i64).min().unwrap(), + shi: discrs.iter().map(|n| n.0 as i64).max().unwrap() + }; + return mk_cenum(cx, hint, &bounds); + } - if cases.len() == 1 && hint == attr::ReprAny { - // Equivalent to a struct/tuple/newtype. - return Univariant(mk_struct(cx, &cases[0].tys, false, t)); - } + // Since there's at least one + // non-empty body, explicit discriminants should have + // been rejected by a checker before this point. + if !cases.iter().enumerate().all(|(i,c)| c.discr == Disr::from(i)) { + bug!("non-C-like enum {} with specified discriminants", + cx.tcx().item_path_str(def.did)); + } - if cases.len() == 2 && hint == attr::ReprAny { - // Nullable pointer optimization - let mut discr = 0; - while discr < 2 { - if cases[1 - discr].is_zerolen(cx, t) { - let st = mk_struct(cx, &cases[discr].tys, - false, t); - match cases[discr].find_ptr(cx) { - Some(ref df) if df.len() == 1 && st.fields.len() == 1 => { - return RawNullablePointer { - nndiscr: Disr::from(discr), - nnty: st.fields[0], - nullfields: cases[1 - discr].tys.clone() - }; - } - Some(mut discrfield) => { - discrfield.push(0); - discrfield.reverse(); - return StructWrappedNullablePointer { - nndiscr: Disr::from(discr), - nonnull: st, - discrfield: discrfield, - nullfields: cases[1 - discr].tys.clone() - }; + if cases.len() == 1 && hint == attr::ReprAny { + // Equivalent to a struct/tuple/newtype. + return Univariant(mk_struct(cx, &cases[0].tys, false, t)); + } + + if cases.len() == 2 && hint == attr::ReprAny { + // Nullable pointer optimization + let mut discr = 0; + while discr < 2 { + if cases[1 - discr].is_zerolen(cx, t) { + let st = mk_struct(cx, &cases[discr].tys, + false, t); + match cases[discr].find_ptr(cx) { + Some(ref df) if df.len() == 1 && st.fields.len() == 1 => { + return RawNullablePointer { + nndiscr: Disr::from(discr), + nnty: st.fields[0], + nullfields: cases[1 - discr].tys.clone() + }; + } + Some(mut discrfield) => { + discrfield.push(0); + discrfield.reverse(); + return StructWrappedNullablePointer { + nndiscr: Disr::from(discr), + nonnull: st, + discrfield: discrfield, + nullfields: cases[1 - discr].tys.clone() + }; + } + None => {} } - None => {} } + discr += 1; } - discr += 1; } - } - // The general case. - assert!((cases.len() - 1) as i64 >= 0); - let bounds = IntBounds { ulo: 0, uhi: (cases.len() - 1) as u64, - slo: 0, shi: (cases.len() - 1) as i64 }; - let min_ity = range_to_inttype(cx, hint, &bounds); - - // Create the set of structs that represent each variant - // Use the minimum integer type we figured out above - let fields : Vec<_> = cases.iter().map(|c| { - let mut ftys = vec!(ty_of_inttype(cx.tcx(), min_ity)); - ftys.extend_from_slice(&c.tys); - mk_struct(cx, &ftys, false, t) - }).collect(); - - - // Check to see if we should use a different type for the - // discriminant. If the overall alignment of the type is - // the same as the first field in each variant, we can safely use - // an alignment-sized type. - // We increase the size of the discriminant to avoid LLVM copying - // padding when it doesn't need to. This normally causes unaligned - // load/stores and excessive memcpy/memset operations. By using a - // bigger integer size, LLVM can be sure about it's contents and - // won't be so conservative. - // This check is needed to avoid increasing the size of types when - // the alignment of the first field is smaller than the overall - // alignment of the type. - let (_, align) = union_size_and_align(&fields); - let mut use_align = true; - for st in &fields { - // Get the first non-zero-sized field - let field = st.fields.iter().skip(1).filter(|ty| { - let t = type_of::sizing_type_of(cx, **ty); - machine::llsize_of_real(cx, t) != 0 || - // This case is only relevant for zero-sized types with large alignment - machine::llalign_of_min(cx, t) != 1 - }).next(); - - if let Some(field) = field { - let field_align = type_of::align_of(cx, *field); - if field_align != align { - use_align = false; - break; + // The general case. + assert!((cases.len() - 1) as i64 >= 0); + let bounds = IntBounds { ulo: 0, uhi: (cases.len() - 1) as u64, + slo: 0, shi: (cases.len() - 1) as i64 }; + let min_ity = range_to_inttype(cx, hint, &bounds); + + // Create the set of structs that represent each variant + // Use the minimum integer type we figured out above + let fields : Vec<_> = cases.iter().map(|c| { + let mut ftys = vec!(ty_of_inttype(cx.tcx(), min_ity)); + ftys.extend_from_slice(&c.tys); + mk_struct(cx, &ftys, false, t) + }).collect(); + + + // Check to see if we should use a different type for the + // discriminant. If the overall alignment of the type is + // the same as the first field in each variant, we can safely use + // an alignment-sized type. + // We increase the size of the discriminant to avoid LLVM copying + // padding when it doesn't need to. This normally causes unaligned + // load/stores and excessive memcpy/memset operations. By using a + // bigger integer size, LLVM can be sure about it's contents and + // won't be so conservative. + // This check is needed to avoid increasing the size of types when + // the alignment of the first field is smaller than the overall + // alignment of the type. + let (_, align) = union_size_and_align(&fields); + let mut use_align = true; + for st in &fields { + // Get the first non-zero-sized field + let field = st.fields.iter().skip(1).filter(|ty| { + let t = type_of::sizing_type_of(cx, **ty); + machine::llsize_of_real(cx, t) != 0 || + // This case is only relevant for zero-sized types with large alignment + machine::llalign_of_min(cx, t) != 1 + }).next(); + + if let Some(field) = field { + let field_align = type_of::align_of(cx, *field); + if field_align != align { + use_align = false; + break; + } } } - } - // If the alignment is smaller than the chosen discriminant size, don't use the - // alignment as the final size. - let min_ty = ll_inttype(&cx, min_ity); - let min_size = machine::llsize_of_real(cx, min_ty); - if (align as u64) < min_size { - use_align = false; - } - - let ity = if use_align { - // Use the overall alignment - match align { - 1 => attr::UnsignedInt(ast::UintTy::U8), - 2 => attr::UnsignedInt(ast::UintTy::U16), - 4 => attr::UnsignedInt(ast::UintTy::U32), - 8 if machine::llalign_of_min(cx, Type::i64(cx)) == 8 => - attr::UnsignedInt(ast::UintTy::U64), - _ => min_ity // use min_ity as a fallback + // If the alignment is smaller than the chosen discriminant size, don't use the + // alignment as the final size. + let min_ty = ll_inttype(&cx, min_ity); + let min_size = machine::llsize_of_real(cx, min_ty); + if (align as u64) < min_size { + use_align = false; } - } else { - min_ity - }; - let fields : Vec<_> = cases.iter().map(|c| { - let mut ftys = vec!(ty_of_inttype(cx.tcx(), ity)); - ftys.extend_from_slice(&c.tys); - mk_struct(cx, &ftys[..], false, t) - }).collect(); + let ity = if use_align { + // Use the overall alignment + match align { + 1 => attr::UnsignedInt(ast::UintTy::U8), + 2 => attr::UnsignedInt(ast::UintTy::U16), + 4 => attr::UnsignedInt(ast::UintTy::U32), + 8 if machine::llalign_of_min(cx, Type::i64(cx)) == 8 => + attr::UnsignedInt(ast::UintTy::U64), + _ => min_ity // use min_ity as a fallback + } + } else { + min_ity + }; - ensure_enum_fits_in_address_space(cx, &fields[..], t); + let fields : Vec<_> = cases.iter().map(|c| { + let mut ftys = vec!(ty_of_inttype(cx.tcx(), ity)); + ftys.extend_from_slice(&c.tys); + mk_struct(cx, &ftys[..], false, t) + }).collect(); - General(ity, fields) - } + ensure_enum_fits_in_address_space(cx, &fields[..], t); + + General(ity, fields) + } + }, _ => bug!("adt::represent_type called on non-ADT type: {}", t) } } @@ -376,7 +378,7 @@ fn find_discr_field_candidate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, ty::TyFnPtr(_) => Some(path), // Is this the NonZero lang item wrapping a pointer or integer type? - ty::TyStruct(def, substs) if Some(def.did) == tcx.lang_items.non_zero() => { + ty::TyAdt(def, substs) if Some(def.did) == tcx.lang_items.non_zero() => { let nonzero_fields = &def.struct_variant().fields; assert_eq!(nonzero_fields.len(), 1); let field_ty = monomorphize::field_ty(tcx, substs, &nonzero_fields[0]); @@ -395,7 +397,7 @@ fn find_discr_field_candidate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // Perhaps one of the fields of this struct is non-zero // let's recurse and find out - ty::TyStruct(def, substs) => { + ty::TyAdt(def, substs) if def.is_struct() => { for (j, field) in def.struct_variant().fields.iter().enumerate() { let field_ty = monomorphize::field_ty(tcx, substs, field); if let Some(mut fpath) = find_discr_field_candidate(tcx, field_ty, path.clone()) { diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs index ec8ab33c4ca54..a6581ae605b56 100644 --- a/src/librustc_trans/base.rs +++ b/src/librustc_trans/base.rs @@ -467,8 +467,7 @@ pub fn coerce_unsized_into<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, } // This can be extended to enums and tuples in the future. - // (&ty::TyEnum(def_id_a, _), &ty::TyEnum(def_id_b, _)) | - (&ty::TyStruct(def_a, _), &ty::TyStruct(def_b, _)) => { + (&ty::TyAdt(def_a, _), &ty::TyAdt(def_b, _)) => { assert_eq!(def_a, def_b); let src_repr = adt::represent_type(bcx.ccx(), src_ty); diff --git a/src/librustc_trans/collector.rs b/src/librustc_trans/collector.rs index 704fac5ce7e53..5a8ab62a2aa2d 100644 --- a/src/librustc_trans/collector.rs +++ b/src/librustc_trans/collector.rs @@ -743,9 +743,7 @@ fn find_drop_glue_neighbors<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, // If the type implements Drop, also add a translation item for the // monomorphized Drop::drop() implementation. let destructor_did = match ty.sty { - ty::TyStruct(def, _) | - ty::TyUnion(def, _) | - ty::TyEnum(def, _) => def.destructor(), + ty::TyAdt(def, _) => def.destructor(), _ => None }; @@ -798,9 +796,7 @@ fn find_drop_glue_neighbors<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, ty::TyTrait(_) => { /* nothing to do */ } - ty::TyStruct(ref adt_def, substs) | - ty::TyUnion(ref adt_def, substs) | - ty::TyEnum(ref adt_def, substs) => { + ty::TyAdt(adt_def, substs) => { for field in adt_def.all_fields() { let field_type = monomorphize::apply_param_substs(scx, substs, @@ -989,8 +985,8 @@ fn find_vtable_types_for_unsizing<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, } } - (&ty::TyStruct(source_adt_def, source_substs), - &ty::TyStruct(target_adt_def, target_substs)) => { + (&ty::TyAdt(source_adt_def, source_substs), + &ty::TyAdt(target_adt_def, target_substs)) => { assert_eq!(source_adt_def, target_adt_def); let kind = custom_coerce_unsize_info(scx, source_ty, target_ty); diff --git a/src/librustc_trans/common.rs b/src/librustc_trans/common.rs index bd98eee8869b1..e0de04d150ca7 100644 --- a/src/librustc_trans/common.rs +++ b/src/librustc_trans/common.rs @@ -88,8 +88,7 @@ pub fn type_is_immediate<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ty: Ty<'tcx>) - return false; } match ty.sty { - ty::TyStruct(..) | ty::TyUnion(..) | ty::TyEnum(..) | - ty::TyTuple(..) | ty::TyArray(..) | ty::TyClosure(..) => { + ty::TyAdt(..) | ty::TyTuple(..) | ty::TyArray(..) | ty::TyClosure(..) => { let llty = sizing_type_of(ccx, ty); llsize_of_alloc(ccx, llty) <= llsize_of_alloc(ccx, ccx.int_type()) } @@ -101,7 +100,7 @@ pub fn type_is_immediate<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ty: Ty<'tcx>) - pub fn type_pair_fields<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ty: Ty<'tcx>) -> Option<[Ty<'tcx>; 2]> { match ty.sty { - ty::TyEnum(adt, substs) | ty::TyStruct(adt, substs) => { + ty::TyAdt(adt, substs) => { assert_eq!(adt.variants.len(), 1); let fields = &adt.variants[0].fields; if fields.len() != 2 { @@ -205,7 +204,7 @@ impl<'a, 'tcx> VariantInfo<'tcx> { -> Self { match ty.sty { - ty::TyStruct(adt, substs) | ty::TyUnion(adt, substs) | ty::TyEnum(adt, substs) => { + ty::TyAdt(adt, substs) => { let variant = match opt_def { None => adt.struct_variant(), Some(def) => adt.variant_of_def(def) diff --git a/src/librustc_trans/context.rs b/src/librustc_trans/context.rs index 2422b9f30069b..b10129d1019ae 100644 --- a/src/librustc_trans/context.rs +++ b/src/librustc_trans/context.rs @@ -223,13 +223,9 @@ impl<'gcx> DepTrackingMapConfig for ProjectionCache<'gcx> { let def_ids: Vec = key.walk() .filter_map(|t| match t.sty { - ty::TyStruct(adt_def, _) | - ty::TyEnum(adt_def, _) => - Some(adt_def.did), - ty::TyProjection(ref proj) => - Some(proj.trait_ref.def_id), - _ => - None + ty::TyAdt(adt_def, _) => Some(adt_def.did), + ty::TyProjection(ref proj) => Some(proj.trait_ref.def_id), + _ => None, }) .collect(); DepNode::TraitSelect(def_ids) diff --git a/src/librustc_trans/debuginfo/metadata.rs b/src/librustc_trans/debuginfo/metadata.rs index 1bf1023dcd895..31df49609cb8b 100644 --- a/src/librustc_trans/debuginfo/metadata.rs +++ b/src/librustc_trans/debuginfo/metadata.rs @@ -30,7 +30,7 @@ use rustc::hir; use {type_of, adt, machine, monomorphize}; use common::CrateContext; use type_::Type; -use rustc::ty::{self, Ty}; +use rustc::ty::{self, AdtKind, Ty}; use session::config; use util::nodemap::FnvHashMap; use util::common::path2cstr; @@ -176,18 +176,10 @@ impl<'tcx> TypeMap<'tcx> { ty::TyFloat(_) => { push_debuginfo_type_name(cx, type_, false, &mut unique_type_id); }, - ty::TyEnum(def, substs) => { - unique_type_id.push_str("enum "); + ty::TyAdt(def, substs) => { + unique_type_id.push_str(&(String::from(def.descr()) + " ")); from_def_id_and_substs(self, cx, def.did, substs, &mut unique_type_id); - }, - ty::TyStruct(def, substs) => { - unique_type_id.push_str("struct "); - from_def_id_and_substs(self, cx, def.did, substs, &mut unique_type_id); - }, - ty::TyUnion(def, substs) => { - unique_type_id.push_str("union "); - from_def_id_and_substs(self, cx, def.did, substs, &mut unique_type_id); - }, + } ty::TyTuple(component_types) if component_types.is_empty() => { push_debuginfo_type_name(cx, type_, false, &mut unique_type_id); }, @@ -705,13 +697,6 @@ pub fn type_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, ty::TyTuple(ref elements) if elements.is_empty() => { MetadataCreationResult::new(basic_type_metadata(cx, t), false) } - ty::TyEnum(def, _) => { - prepare_enum_metadata(cx, - t, - def.did, - unique_type_id, - usage_site_span).finalize(cx) - } ty::TyArray(typ, len) => { fixed_vec_metadata(cx, unique_type_id, typ, Some(len as u64), usage_site_span) } @@ -779,18 +764,27 @@ pub fn type_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, unique_type_id, usage_site_span).finalize(cx) } - ty::TyStruct(..) => { - prepare_struct_metadata(cx, + ty::TyAdt(def, ..) => match def.adt_kind() { + AdtKind::Struct => { + prepare_struct_metadata(cx, + t, + unique_type_id, + usage_site_span).finalize(cx) + } + AdtKind::Union => { + prepare_union_metadata(cx, t, unique_type_id, usage_site_span).finalize(cx) - } - ty::TyUnion(..) => { - prepare_union_metadata(cx, - t, - unique_type_id, - usage_site_span).finalize(cx) - } + } + AdtKind::Enum => { + prepare_enum_metadata(cx, + t, + def.did, + unique_type_id, + usage_site_span).finalize(cx) + } + }, ty::TyTuple(ref elements) => { prepare_tuple_metadata(cx, t, @@ -1134,8 +1128,8 @@ fn prepare_struct_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, let struct_llvm_type = type_of::in_memory_type_of(cx, struct_type); let (struct_def_id, variant, substs) = match struct_type.sty { - ty::TyStruct(def, substs) => (def.did, def.struct_variant(), substs), - _ => bug!("prepare_struct_metadata on a non-struct") + ty::TyAdt(def, substs) => (def.did, def.struct_variant(), substs), + _ => bug!("prepare_struct_metadata on a non-ADT") }; let (containing_scope, _) = get_namespace_and_span_for_item(cx, struct_def_id); @@ -1250,8 +1244,8 @@ fn prepare_union_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, let union_llvm_type = type_of::in_memory_type_of(cx, union_type); let (union_def_id, variant, substs) = match union_type.sty { - ty::TyUnion(def, substs) => (def.did, def.struct_variant(), substs), - _ => bug!("prepare_union_metadata on a non-union") + ty::TyAdt(def, substs) => (def.did, def.struct_variant(), substs), + _ => bug!("prepare_union_metadata on a non-ADT") }; let (containing_scope, _) = get_namespace_and_span_for_item(cx, union_def_id); diff --git a/src/librustc_trans/debuginfo/mod.rs b/src/librustc_trans/debuginfo/mod.rs index 20a33498475a2..bcd288671bc19 100644 --- a/src/librustc_trans/debuginfo/mod.rs +++ b/src/librustc_trans/debuginfo/mod.rs @@ -421,7 +421,7 @@ pub fn create_function_debug_context<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, // Only "class" methods are generally understood by LLVM, // so avoid methods on other types (e.g. `<*mut T>::null`). match impl_self_ty.sty { - ty::TyStruct(..) | ty::TyUnion(..) | ty::TyEnum(..) => { + ty::TyAdt(..) => { Some(type_metadata(cx, impl_self_ty, syntax_pos::DUMMY_SP)) } _ => None diff --git a/src/librustc_trans/debuginfo/type_names.rs b/src/librustc_trans/debuginfo/type_names.rs index 8291f84054d0c..7f021bee37199 100644 --- a/src/librustc_trans/debuginfo/type_names.rs +++ b/src/librustc_trans/debuginfo/type_names.rs @@ -44,9 +44,7 @@ pub fn push_debuginfo_type_name<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, ty::TyInt(int_ty) => output.push_str(int_ty.ty_to_string()), ty::TyUint(uint_ty) => output.push_str(uint_ty.ty_to_string()), ty::TyFloat(float_ty) => output.push_str(float_ty.ty_to_string()), - ty::TyStruct(def, substs) | - ty::TyUnion(def, substs) | - ty::TyEnum(def, substs) => { + ty::TyAdt(def, substs) => { push_item_name(cx, def.did, qualified, output); push_type_params(cx, substs, output); }, diff --git a/src/librustc_trans/glue.rs b/src/librustc_trans/glue.rs index 34c92f334d0ac..6c1c5ac2d10e8 100644 --- a/src/librustc_trans/glue.rs +++ b/src/librustc_trans/glue.rs @@ -19,7 +19,7 @@ use llvm::{ValueRef, get_param}; use middle::lang_items::ExchangeFreeFnLangItem; use rustc::ty::subst::{Substs}; use rustc::traits; -use rustc::ty::{self, Ty, TyCtxt, TypeFoldable}; +use rustc::ty::{self, AdtKind, Ty, TyCtxt, TypeFoldable}; use adt; use base::*; use build::*; @@ -338,7 +338,7 @@ pub fn size_and_align_of_dst<'blk, 'tcx>(bcx: &BlockAndBuilder<'blk, 'tcx>, return (C_undef(llty), C_undef(llty)); } match t.sty { - ty::TyStruct(def, substs) => { + ty::TyAdt(def, substs) => { let ccx = bcx.ccx(); // First get the size of all statically known fields. // Don't use type_of::sizing_type_of because that expects t to be sized, @@ -487,16 +487,11 @@ fn make_drop_glue<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, v0: ValueRef, g: DropGlueK DebugLoc::None); bcx } - ty::TyStruct(def, _) | ty::TyEnum(def, _) - if def.dtor_kind().is_present() && !skip_dtor => { - trans_custom_dtor(bcx, t, v0, false) + ty::TyAdt(def, ..) if def.dtor_kind().is_present() && !skip_dtor => { + trans_custom_dtor(bcx, t, v0, def.is_union()) } - ty::TyUnion(def, _) => { - if def.dtor_kind().is_present() && !skip_dtor { - trans_custom_dtor(bcx, t, v0, true) - } else { - bcx - } + ty::TyAdt(def, ..) if def.is_union() => { + bcx } _ => { if bcx.fcx.type_needs_drop(t) { @@ -544,23 +539,6 @@ fn drop_structural_ty<'blk, 'tcx>(cx: Block<'blk, 'tcx>, let mut cx = cx; match t.sty { - ty::TyStruct(..) => { - let repr = adt::represent_type(cx.ccx(), t); - let VariantInfo { fields, discr } = VariantInfo::from_ty(cx.tcx(), t, None); - for (i, &Field(_, field_ty)) in fields.iter().enumerate() { - let llfld_a = adt::trans_field_ptr(cx, &repr, value, Disr::from(discr), i); - - let val = if type_is_sized(cx.tcx(), field_ty) { - llfld_a - } else { - let scratch = alloc_ty(cx, field_ty, "__fat_ptr_iter"); - Store(cx, llfld_a, get_dataptr(cx, scratch)); - Store(cx, value.meta, get_meta(cx, scratch)); - scratch - }; - cx = drop_ty(cx, val, field_ty, DebugLoc::None); - } - } ty::TyClosure(_, ref substs) => { let repr = adt::represent_type(cx.ccx(), t); for (i, upvar_ty) in substs.upvar_tys.iter().enumerate() { @@ -587,63 +565,86 @@ fn drop_structural_ty<'blk, 'tcx>(cx: Block<'blk, 'tcx>, cx = drop_ty(cx, llfld_a, *arg, DebugLoc::None); } } - ty::TyEnum(en, substs) => { - let fcx = cx.fcx; - let ccx = fcx.ccx; - - let repr = adt::represent_type(ccx, t); - let n_variants = en.variants.len(); - - // NB: we must hit the discriminant first so that structural - // comparison know not to proceed when the discriminants differ. - - match adt::trans_switch(cx, &repr, av, false) { - (adt::BranchKind::Single, None) => { - if n_variants != 0 { - assert!(n_variants == 1); - cx = iter_variant(cx, &repr, adt::MaybeSizedValue::sized(av), - &en.variants[0], substs); - } + ty::TyAdt(adt, substs) => match adt.adt_kind() { + AdtKind::Struct => { + let repr = adt::represent_type(cx.ccx(), t); + let VariantInfo { fields, discr } = VariantInfo::from_ty(cx.tcx(), t, None); + for (i, &Field(_, field_ty)) in fields.iter().enumerate() { + let llfld_a = adt::trans_field_ptr(cx, &repr, value, Disr::from(discr), i); + + let val = if type_is_sized(cx.tcx(), field_ty) { + llfld_a + } else { + let scratch = alloc_ty(cx, field_ty, "__fat_ptr_iter"); + Store(cx, llfld_a, get_dataptr(cx, scratch)); + Store(cx, value.meta, get_meta(cx, scratch)); + scratch + }; + cx = drop_ty(cx, val, field_ty, DebugLoc::None); } - (adt::BranchKind::Switch, Some(lldiscrim_a)) => { - cx = drop_ty(cx, lldiscrim_a, cx.tcx().types.isize, DebugLoc::None); - - // Create a fall-through basic block for the "else" case of - // the switch instruction we're about to generate. Note that - // we do **not** use an Unreachable instruction here, even - // though most of the time this basic block will never be hit. - // - // When an enum is dropped it's contents are currently - // overwritten to DTOR_DONE, which means the discriminant - // could have changed value to something not within the actual - // range of the discriminant. Currently this function is only - // used for drop glue so in this case we just return quickly - // from the outer function, and any other use case will only - // call this for an already-valid enum in which case the `ret - // void` will never be hit. - let ret_void_cx = fcx.new_block("enum-iter-ret-void"); - RetVoid(ret_void_cx, DebugLoc::None); - let llswitch = Switch(cx, lldiscrim_a, ret_void_cx.llbb, n_variants); - let next_cx = fcx.new_block("enum-iter-next"); - - for variant in &en.variants { - let variant_cx = fcx.new_block(&format!("enum-iter-variant-{}", - &variant.disr_val - .to_string())); - let case_val = adt::trans_case(cx, &repr, Disr::from(variant.disr_val)); - AddCase(llswitch, case_val, variant_cx.llbb); - let variant_cx = iter_variant(variant_cx, - &repr, - value, - variant, - substs); - Br(variant_cx, next_cx.llbb, DebugLoc::None); + } + AdtKind::Union => { + bug!("Union in `glue::drop_structural_ty`"); + } + AdtKind::Enum => { + let fcx = cx.fcx; + let ccx = fcx.ccx; + + let repr = adt::represent_type(ccx, t); + let n_variants = adt.variants.len(); + + // NB: we must hit the discriminant first so that structural + // comparison know not to proceed when the discriminants differ. + + match adt::trans_switch(cx, &repr, av, false) { + (adt::BranchKind::Single, None) => { + if n_variants != 0 { + assert!(n_variants == 1); + cx = iter_variant(cx, &repr, adt::MaybeSizedValue::sized(av), + &adt.variants[0], substs); + } } - cx = next_cx; + (adt::BranchKind::Switch, Some(lldiscrim_a)) => { + cx = drop_ty(cx, lldiscrim_a, cx.tcx().types.isize, DebugLoc::None); + + // Create a fall-through basic block for the "else" case of + // the switch instruction we're about to generate. Note that + // we do **not** use an Unreachable instruction here, even + // though most of the time this basic block will never be hit. + // + // When an enum is dropped it's contents are currently + // overwritten to DTOR_DONE, which means the discriminant + // could have changed value to something not within the actual + // range of the discriminant. Currently this function is only + // used for drop glue so in this case we just return quickly + // from the outer function, and any other use case will only + // call this for an already-valid enum in which case the `ret + // void` will never be hit. + let ret_void_cx = fcx.new_block("enum-iter-ret-void"); + RetVoid(ret_void_cx, DebugLoc::None); + let llswitch = Switch(cx, lldiscrim_a, ret_void_cx.llbb, n_variants); + let next_cx = fcx.new_block("enum-iter-next"); + + for variant in &adt.variants { + let variant_cx = fcx.new_block(&format!("enum-iter-variant-{}", + &variant.disr_val + .to_string())); + let case_val = adt::trans_case(cx, &repr, Disr::from(variant.disr_val)); + AddCase(llswitch, case_val, variant_cx.llbb); + let variant_cx = iter_variant(variant_cx, + &repr, + value, + variant, + substs); + Br(variant_cx, next_cx.llbb, DebugLoc::None); + } + cx = next_cx; + } + _ => ccx.sess().unimpl("value from adt::trans_switch in drop_structural_ty"), } - _ => ccx.sess().unimpl("value from adt::trans_switch in drop_structural_ty"), } - } + }, + _ => { cx.sess().unimpl(&format!("type in drop_structural_ty: {}", t)) } diff --git a/src/librustc_trans/intrinsic.rs b/src/librustc_trans/intrinsic.rs index c0ff6c508bf3e..2049696ee4f71 100644 --- a/src/librustc_trans/intrinsic.rs +++ b/src/librustc_trans/intrinsic.rs @@ -408,7 +408,7 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, (_, "discriminant_value") => { let val_ty = substs.type_at(0); match val_ty.sty { - ty::TyEnum(..) => { + ty::TyAdt(adt, ..) if adt.is_enum() => { let repr = adt::represent_type(ccx, val_ty); adt::trans_get_discr(bcx, &repr, llargs[0], Some(llret_ty), true) diff --git a/src/librustc_trans/trans_item.rs b/src/librustc_trans/trans_item.rs index e078d46274d3e..44e613c4c2b04 100644 --- a/src/librustc_trans/trans_item.rs +++ b/src/librustc_trans/trans_item.rs @@ -396,9 +396,7 @@ pub fn push_unique_type_name<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, ty::TyUint(ast::UintTy::U64) => output.push_str("u64"), ty::TyFloat(ast::FloatTy::F32) => output.push_str("f32"), ty::TyFloat(ast::FloatTy::F64) => output.push_str("f64"), - ty::TyStruct(adt_def, substs) | - ty::TyUnion(adt_def, substs) | - ty::TyEnum(adt_def, substs) => { + ty::TyAdt(adt_def, substs) => { push_item_name(tcx, adt_def.did, output); push_type_params(tcx, substs, &[], output); }, diff --git a/src/librustc_trans/type_of.rs b/src/librustc_trans/type_of.rs index b5565109306b4..3873c24a9f676 100644 --- a/src/librustc_trans/type_of.rs +++ b/src/librustc_trans/type_of.rs @@ -89,7 +89,7 @@ pub fn sizing_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) -> Typ Type::nil(cx) } - ty::TyStruct(..) if t.is_simd() => { + ty::TyAdt(..) if t.is_simd() => { let e = t.simd_type(cx.tcx()); if !e.is_machine() { cx.sess().fatal(&format!("monomorphising SIMD type `{}` with \ @@ -102,8 +102,7 @@ pub fn sizing_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) -> Typ Type::vector(&llet, n) } - ty::TyTuple(..) | ty::TyStruct(..) | ty::TyUnion(..) | - ty::TyEnum(..) | ty::TyClosure(..) => { + ty::TyTuple(..) | ty::TyAdt(..) | ty::TyClosure(..) => { let repr = adt::represent_type(cx, t); adt::sizing_type_of(cx, &repr, false) } @@ -294,7 +293,7 @@ pub fn in_memory_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) -> let repr = adt::represent_type(cx, t); adt::type_of(cx, &repr) } - ty::TyStruct(..) if t.is_simd() => { + ty::TyAdt(..) if t.is_simd() => { let e = t.simd_type(cx.tcx()); if !e.is_machine() { cx.sess().fatal(&format!("monomorphising SIMD type `{}` with \ @@ -306,9 +305,7 @@ pub fn in_memory_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) -> ensure_array_fits_in_address_space(cx, llet, n, t); Type::vector(&llet, n) } - ty::TyStruct(def, ref substs) | - ty::TyUnion(def, ref substs) | - ty::TyEnum(def, ref substs) => { + ty::TyAdt(def, substs) => { // Only create the named struct, but don't fill it in. We // fill it in *after* placing it into the type cache. This // avoids creating more than one copy of the enum when one @@ -331,8 +328,7 @@ pub fn in_memory_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) -> // If this was an enum or struct, fill in the type now. match t.sty { - ty::TyEnum(..) | ty::TyStruct(..) | ty::TyUnion(..) | ty::TyClosure(..) - if !t.is_simd() => { + ty::TyAdt(..) | ty::TyClosure(..) if !t.is_simd() => { let repr = adt::represent_type(cx, t); adt::finish_type_of(cx, &repr, &mut llty); } diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs index 17fb683391982..dd3ac6ff2d457 100644 --- a/src/librustc_typeck/check/_match.rs +++ b/src/librustc_typeck/check/_match.rs @@ -617,7 +617,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { if subpats.len() == variant.fields.len() || subpats.len() < variant.fields.len() && ddpos.is_some() { let substs = match pat_ty.sty { - ty::TyStruct(_, substs) | ty::TyEnum(_, substs) => substs, + ty::TyAdt(_, substs) => substs, ref ty => bug!("unexpected pattern type {:?}", ty), }; for (i, subpat) in subpats.iter().enumerate_and_adjust(variant.fields.len(), ddpos) { @@ -657,9 +657,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let tcx = self.tcx; let (substs, kind_name) = match adt_ty.sty { - ty::TyEnum(_, substs) => (substs, "variant"), - ty::TyStruct(_, substs) => (substs, "struct"), - ty::TyUnion(_, substs) => (substs, "union"), + ty::TyAdt(adt, substs) => (substs, adt.variant_descr()), _ => span_bug!(span, "struct pattern is not an ADT") }; diff --git a/src/librustc_typeck/check/cast.rs b/src/librustc_typeck/check/cast.rs index 0c9da86563ab2..51a9b18392dcf 100644 --- a/src/librustc_typeck/check/cast.rs +++ b/src/librustc_typeck/check/cast.rs @@ -79,7 +79,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { match t.sty { ty::TySlice(_) | ty::TyStr => Some(UnsizeKind::Length), ty::TyTrait(ref tty) => Some(UnsizeKind::Vtable(tty.principal.def_id())), - ty::TyStruct(def, substs) => { + ty::TyAdt(def, substs) if def.is_struct() => { // FIXME(arielb1): do some kind of normalization match def.struct_variant().fields.last() { None => None, diff --git a/src/librustc_typeck/check/dropck.rs b/src/librustc_typeck/check/dropck.rs index 88add66b7dcb0..cc958fb3b2343 100644 --- a/src/librustc_typeck/check/dropck.rs +++ b/src/librustc_typeck/check/dropck.rs @@ -16,7 +16,7 @@ use middle::free_region::FreeRegionMap; use rustc::infer; use middle::region; use rustc::ty::subst::{Subst, Substs}; -use rustc::ty::{self, Ty, TyCtxt}; +use rustc::ty::{self, AdtKind, Ty, TyCtxt}; use rustc::traits::{self, Reveal}; use util::nodemap::FnvHashSet; @@ -44,9 +44,7 @@ pub fn check_drop_impl(ccx: &CrateCtxt, drop_impl_did: DefId) -> Result<(), ()> let dtor_self_type = ccx.tcx.lookup_item_type(drop_impl_did).ty; let dtor_predicates = ccx.tcx.lookup_predicates(drop_impl_did); match dtor_self_type.sty { - ty::TyEnum(adt_def, self_to_impl_substs) | - ty::TyUnion(adt_def, self_to_impl_substs) | - ty::TyStruct(adt_def, self_to_impl_substs) => { + ty::TyAdt(adt_def, self_to_impl_substs) => { ensure_drop_params_and_item_params_correspond(ccx, drop_impl_did, dtor_self_type, @@ -301,13 +299,13 @@ pub fn check_safety_of_destructor_if_necessary<'a, 'gcx, 'tcx>( TypeContext::ADT { def_id, variant, field } => { let adt = tcx.lookup_adt_def(def_id); let variant_name = match adt.adt_kind() { - ty::AdtKind::Enum => format!("enum {} variant {}", - tcx.item_path_str(def_id), - variant), - ty::AdtKind::Struct => format!("struct {}", - tcx.item_path_str(def_id)), - ty::AdtKind::Union => format!("union {}", - tcx.item_path_str(def_id)), + AdtKind::Enum => format!("enum {} variant {}", + tcx.item_path_str(def_id), + variant), + AdtKind::Struct => format!("struct {}", + tcx.item_path_str(def_id)), + AdtKind::Union => format!("union {}", + tcx.item_path_str(def_id)), }; span_note!( &mut err, @@ -435,14 +433,14 @@ fn iterate_over_potentially_unsafe_regions_in_type<'a, 'b, 'gcx, 'tcx>( cx, context, ity, depth+1) } - ty::TyStruct(def, substs) if def.is_phantom_data() => { + ty::TyAdt(def, substs) if def.is_phantom_data() => { // PhantomData - behaves identically to T let ity = substs.type_at(0); iterate_over_potentially_unsafe_regions_in_type( cx, context, ity, depth+1) } - ty::TyStruct(def, substs) | ty::TyUnion(def, substs) | ty::TyEnum(def, substs) => { + ty::TyAdt(def, substs) => { let did = def.did; for variant in &def.variants { for field in variant.fields.iter() { @@ -497,7 +495,7 @@ fn iterate_over_potentially_unsafe_regions_in_type<'a, 'b, 'gcx, 'tcx>( fn has_dtor_of_interest<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>, ty: Ty<'tcx>) -> bool { match ty.sty { - ty::TyEnum(def, _) | ty::TyStruct(def, _) | ty::TyUnion(def, _) => { + ty::TyAdt(def, _) => { def.is_dtorck(tcx) } ty::TyTrait(..) | ty::TyProjection(..) | ty::TyAnon(..) => { diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs index 058049992dc00..81e95c91e7ff9 100644 --- a/src/librustc_typeck/check/method/probe.rs +++ b/src/librustc_typeck/check/method/probe.rs @@ -292,9 +292,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { self.assemble_inherent_candidates_from_object(self_ty, data.principal); self.assemble_inherent_impl_candidates_for_type(data.principal.def_id()); } - ty::TyEnum(def, _) | - ty::TyStruct(def, _) | - ty::TyUnion(def, _) => { + ty::TyAdt(def, _) => { self.assemble_inherent_impl_candidates_for_type(def.did); } ty::TyBox(_) => { diff --git a/src/librustc_typeck/check/method/suggest.rs b/src/librustc_typeck/check/method/suggest.rs index e4ea9bb407d96..3692d6fbf73d6 100644 --- a/src/librustc_typeck/check/method/suggest.rs +++ b/src/librustc_typeck/check/method/suggest.rs @@ -165,7 +165,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { if let Some(expr) = rcvr_expr { for (ty, _) in self.autoderef(span, rcvr_ty) { match ty.sty { - ty::TyStruct(def, substs) | ty::TyUnion(def, substs) => { + ty::TyAdt(def, substs) if !def.is_enum() => { if let Some(field) = def.struct_variant(). find_field_named(item_name) { let snippet = tcx.sess.codemap().span_to_snippet(expr.span); @@ -359,9 +359,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { rcvr_expr: Option<&hir::Expr>) -> bool { fn is_local(ty: Ty) -> bool { match ty.sty { - ty::TyEnum(def, _) | ty::TyStruct(def, _) | ty::TyUnion(def, _) => { - def.did.is_local() - } + ty::TyAdt(def, _) => def.did.is_local(), ty::TyTrait(ref tr) => tr.principal.def_id().is_local(), diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index b059c2ab9f3a8..005cd2e46b89f 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -1200,7 +1200,7 @@ fn check_representable<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, pub fn check_simd<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, sp: Span, id: ast::NodeId) { let t = tcx.node_id_to_type(id); match t.sty { - ty::TyStruct(def, substs) => { + ty::TyAdt(def, substs) if def.is_struct() => { let fields = &def.struct_variant().fields; if fields.is_empty() { span_err!(tcx.sess, sp, E0075, "SIMD vector cannot be empty"); @@ -2911,7 +2911,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let mut autoderef = self.autoderef(expr.span, expr_t); while let Some((base_t, autoderefs)) = autoderef.next() { match base_t.sty { - ty::TyStruct(base_def, substs) | ty::TyUnion(base_def, substs) => { + ty::TyAdt(base_def, substs) if !base_def.is_enum() => { debug!("struct named {:?}", base_t); if let Some(field) = base_def.struct_variant().find_field_named(field.node) { let field_ty = self.field_ty(expr.span, field, substs); @@ -2957,7 +2957,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { field.node, actual) }, expr_t); match expr_t.sty { - ty::TyStruct(def, _) | ty::TyUnion(def, _) => { + ty::TyAdt(def, _) if !def.is_enum() => { if let Some(suggested_field_name) = Self::suggest_field_name(def.struct_variant(), field, vec![]) { err.span_help(field.span, @@ -3009,7 +3009,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let mut autoderef = self.autoderef(expr.span, expr_t); while let Some((base_t, autoderefs)) = autoderef.next() { let field = match base_t.sty { - ty::TyStruct(base_def, substs) => { + ty::TyAdt(base_def, substs) if base_def.is_struct() => { tuple_like = base_def.struct_variant().kind == ty::VariantKind::Tuple; if !tuple_like { continue } @@ -3074,14 +3074,17 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { kind_name: &str) { let mut err = self.type_error_struct_with_diag( field.name.span, - |actual| if let ty::TyEnum(..) = ty.sty { - struct_span_err!(self.tcx.sess, field.name.span, E0559, - "{} `{}::{}` has no field named `{}`", - kind_name, actual, variant.name.as_str(), field.name.node) - } else { - struct_span_err!(self.tcx.sess, field.name.span, E0560, - "{} `{}` has no field named `{}`", - kind_name, actual, field.name.node) + |actual| match ty.sty { + ty::TyAdt(adt, ..) if adt.is_enum() => { + struct_span_err!(self.tcx.sess, field.name.span, E0559, + "{} `{}::{}` has no field named `{}`", + kind_name, actual, variant.name.as_str(), field.name.node) + } + _ => { + struct_span_err!(self.tcx.sess, field.name.span, E0560, + "{} `{}` has no field named `{}`", + kind_name, actual, field.name.node) + } }, ty); // prevent all specified fields from being suggested @@ -3102,9 +3105,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { check_completeness: bool) { let tcx = self.tcx; let (substs, kind_name) = match adt_ty.sty { - ty::TyEnum(_, substs) => (substs, "variant"), - ty::TyStruct(_, substs) => (substs, "struct"), - ty::TyUnion(_, substs) => (substs, "union"), + ty::TyAdt(adt, substs) => (substs, adt.variant_descr()), _ => span_bug!(span, "non-ADT passed to check_expr_struct_fields") }; @@ -3199,8 +3200,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } Def::TyAlias(did) => { match self.tcx.opt_lookup_item_type(did).map(|scheme| &scheme.ty.sty) { - Some(&ty::TyStruct(adt, _)) | - Some(&ty::TyUnion(adt, _)) => Some((did, adt.struct_variant())), + Some(&ty::TyAdt(adt, _)) if !adt.is_enum() => { + Some((did, adt.struct_variant())) + } _ => None, } } @@ -3246,7 +3248,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { if let &Some(ref base_expr) = base_expr { self.check_expr_has_type(base_expr, struct_ty); match struct_ty.sty { - ty::TyStruct(adt, substs) => { + ty::TyAdt(adt, substs) if adt.is_struct() => { self.tables.borrow_mut().fru_field_types.insert( expr.id, adt.struct_variant().fields.iter().map(|f| { diff --git a/src/librustc_typeck/coherence/mod.rs b/src/librustc_typeck/coherence/mod.rs index d2b7f07b9ce6c..046ba5fb4523c 100644 --- a/src/librustc_typeck/coherence/mod.rs +++ b/src/librustc_typeck/coherence/mod.rs @@ -22,9 +22,9 @@ use rustc::ty::{self, TyCtxt, TypeFoldable}; use rustc::traits::{self, Reveal}; use rustc::ty::{ImplOrTraitItemId, ConstTraitItemId}; use rustc::ty::{MethodTraitItemId, TypeTraitItemId, ParameterEnvironment}; -use rustc::ty::{Ty, TyBool, TyChar, TyEnum, TyError}; +use rustc::ty::{Ty, TyBool, TyChar, TyError}; use rustc::ty::{TyParam, TyRawPtr}; -use rustc::ty::{TyRef, TyStruct, TyUnion, TyTrait, TyNever, TyTuple}; +use rustc::ty::{TyRef, TyAdt, TyTrait, TyNever, TyTuple}; use rustc::ty::{TyStr, TyArray, TySlice, TyFloat, TyInfer, TyInt}; use rustc::ty::{TyUint, TyClosure, TyBox, TyFnDef, TyFnPtr}; use rustc::ty::{TyProjection, TyAnon}; @@ -69,9 +69,7 @@ impl<'a, 'gcx, 'tcx> CoherenceChecker<'a, 'gcx, 'tcx> { // Returns the def ID of the base type, if there is one. fn get_base_type_def_id(&self, span: Span, ty: Ty<'tcx>) -> Option { match ty.sty { - TyEnum(def, _) | - TyStruct(def, _) | - TyUnion(def, _) => { + TyAdt(def, _) => { Some(def.did) } @@ -241,9 +239,7 @@ impl<'a, 'gcx, 'tcx> CoherenceChecker<'a, 'gcx, 'tcx> { let self_type = tcx.lookup_item_type(impl_did); match self_type.ty.sty { - ty::TyEnum(type_def, _) | - ty::TyStruct(type_def, _) | - ty::TyUnion(type_def, _) => { + ty::TyAdt(type_def, _) => { type_def.set_destructor(method_def_id.def_id()); } _ => { @@ -426,7 +422,8 @@ impl<'a, 'gcx, 'tcx> CoherenceChecker<'a, 'gcx, 'tcx> { check_mutbl(mt_a, mt_b, &|ty| tcx.mk_imm_ptr(ty)) } - (&ty::TyStruct(def_a, substs_a), &ty::TyStruct(def_b, substs_b)) => { + (&ty::TyAdt(def_a, substs_a), &ty::TyAdt(def_b, substs_b)) + if def_a.is_struct() && def_b.is_struct() => { if def_a != def_b { let source_path = tcx.item_path_str(def_a.did); let target_path = tcx.item_path_str(def_b.did); diff --git a/src/librustc_typeck/coherence/orphan.rs b/src/librustc_typeck/coherence/orphan.rs index cb424eb48e932..d1eb0f995de13 100644 --- a/src/librustc_typeck/coherence/orphan.rs +++ b/src/librustc_typeck/coherence/orphan.rs @@ -75,9 +75,7 @@ impl<'cx, 'tcx> OrphanChecker<'cx, 'tcx> { self.tcx.map.node_to_string(item.id)); let self_ty = self.tcx.lookup_item_type(def_id).ty; match self_ty.sty { - ty::TyEnum(def, _) | - ty::TyStruct(def, _) | - ty::TyUnion(def, _) => { + ty::TyAdt(def, _) => { self.check_def_id(item, def.did); } ty::TyTrait(ref data) => { @@ -294,14 +292,9 @@ impl<'cx, 'tcx> OrphanChecker<'cx, 'tcx> { { let self_ty = trait_ref.self_ty(); let opt_self_def_id = match self_ty.sty { - ty::TyStruct(self_def, _) | - ty::TyUnion(self_def, _) | - ty::TyEnum(self_def, _) => - Some(self_def.did), - ty::TyBox(..) => - self.tcx.lang_items.owned_box(), - _ => - None + ty::TyAdt(self_def, _) => Some(self_def.did), + ty::TyBox(..) => self.tcx.lang_items.owned_box(), + _ => None, }; let msg = match opt_self_def_id { diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index fcc0b09e31acf..082690149c9d1 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -67,7 +67,7 @@ use rustc_const_eval::EvalHint::UncheckedExprHint; use rustc_const_eval::{eval_const_expr_partial, report_const_eval_err}; use rustc::ty::subst::Substs; use rustc::ty::{ToPredicate, ImplContainer, ImplOrTraitItemContainer, TraitContainer}; -use rustc::ty::{self, ToPolyTraitRef, Ty, TyCtxt, TypeScheme}; +use rustc::ty::{self, AdtKind, ToPolyTraitRef, Ty, TyCtxt, TypeScheme}; use rustc::ty::{VariantKind}; use rustc::ty::util::IntTypeExt; use rscope::*; @@ -1062,7 +1062,7 @@ fn convert_struct_def<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, let ctor_id = if !def.is_struct() { Some(ccx.tcx.map.local_def_id(def.id())) } else { None }; let variants = vec![convert_struct_variant(ccx, ctor_id.unwrap_or(did), it.name, ConstInt::Infer(0), def)]; - let adt = ccx.tcx.intern_adt_def(did, ty::AdtKind::Struct, variants); + let adt = ccx.tcx.intern_adt_def(did, AdtKind::Struct, variants); if let Some(ctor_id) = ctor_id { // Make adt definition available through constructor id as well. ccx.tcx.insert_adt_def(ctor_id, adt); @@ -1077,7 +1077,7 @@ fn convert_union_def<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, { let did = ccx.tcx.map.local_def_id(it.id); let variants = vec![convert_struct_variant(ccx, did, it.name, ConstInt::Infer(0), def)]; - ccx.tcx.intern_adt_def(did, ty::AdtKind::Union, variants) + ccx.tcx.intern_adt_def(did, AdtKind::Union, variants) } fn evaluate_disr_expr(ccx: &CrateCtxt, repr_ty: attr::IntType, e: &hir::Expr) @@ -1157,7 +1157,7 @@ fn convert_enum_def<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, let did = tcx.map.local_def_id(v.node.data.id()); convert_struct_variant(ccx, did, v.node.name, disr, &v.node.data) }).collect(); - tcx.intern_adt_def(tcx.map.local_def_id(it.id), ty::AdtKind::Enum, variants) + tcx.intern_adt_def(tcx.map.local_def_id(it.id), AdtKind::Enum, variants) } /// Ensures that the super-predicates of the trait with def-id @@ -1581,17 +1581,17 @@ fn type_of_def_id<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, ItemEnum(ref ei, ref generics) => { let def = convert_enum_def(ccx, item, ei); let substs = mk_item_substs(&ccx.icx(generics), item.span, def_id); - ccx.tcx.mk_enum(def, substs) + ccx.tcx.mk_adt(def, substs) } ItemStruct(ref si, ref generics) => { let def = convert_struct_def(ccx, item, si); let substs = mk_item_substs(&ccx.icx(generics), item.span, def_id); - ccx.tcx.mk_struct(def, substs) + ccx.tcx.mk_adt(def, substs) } ItemUnion(ref un, ref generics) => { let def = convert_union_def(ccx, item, un); let substs = mk_item_substs(&ccx.icx(generics), item.span, def_id); - ccx.tcx.mk_union(def, substs) + ccx.tcx.mk_adt(def, substs) } ItemDefaultImpl(..) | ItemTrait(..) | diff --git a/src/librustc_typeck/variance/constraints.rs b/src/librustc_typeck/variance/constraints.rs index 1e38f464651b9..b18792d894287 100644 --- a/src/librustc_typeck/variance/constraints.rs +++ b/src/librustc_typeck/variance/constraints.rs @@ -344,9 +344,7 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> { } } - ty::TyEnum(def, substs) | - ty::TyStruct(def, substs) | - ty::TyUnion(def, substs) => { + ty::TyAdt(def, substs) => { let item_type = self.tcx().lookup_item_type(def.did); // This edge is actually implied by the call to diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index 18c12f98fb428..f1b907e70d74e 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -238,7 +238,7 @@ fn build_type<'a, 'tcx>(cx: &DocContext, tcx: TyCtxt<'a, 'tcx, 'tcx>, let t = tcx.lookup_item_type(did); let predicates = tcx.lookup_predicates(did); match t.ty.sty { - ty::TyEnum(edef, _) if !tcx.sess.cstore.is_typedef(did) => { + ty::TyAdt(edef, _) if edef.is_enum() && !tcx.sess.cstore.is_typedef(did) => { return clean::EnumItem(clean::Enum { generics: (t.generics, &predicates).clean(cx), variants_stripped: false, diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 79c66be5e57d7..b9dc75cdd9f12 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -41,7 +41,7 @@ use rustc::hir::def_id::{DefId, DefIndex, CRATE_DEF_INDEX}; use rustc::hir::fold::Folder; use rustc::hir::print as pprust; use rustc::ty::subst::Substs; -use rustc::ty; +use rustc::ty::{self, AdtKind}; use rustc::middle::stability; use rustc::util::nodemap::{FnvHashMap, FnvHashSet}; @@ -1811,14 +1811,12 @@ impl<'tcx> Clean for ty::Ty<'tcx> { decl: (cx.map.local_def_id(0), &fty.sig).clean(cx), abi: fty.abi, }), - ty::TyStruct(def, substs) | - ty::TyUnion(def, substs) | - ty::TyEnum(def, substs) => { + ty::TyAdt(def, substs) => { let did = def.did; - let kind = match self.sty { - ty::TyStruct(..) => TypeStruct, - ty::TyUnion(..) => TypeUnion, - _ => TypeEnum, + let kind = match def.adt_kind() { + AdtKind::Struct => TypeStruct, + AdtKind::Union => TypeUnion, + AdtKind::Enum => TypeEnum, }; inline::record_extern_fqn(cx, did, kind); let path = external_path(cx, &cx.tcx().item_name(did).as_str(), diff --git a/src/test/run-pass/auxiliary/issue13507.rs b/src/test/run-pass/auxiliary/issue13507.rs index 4cb846b51868f..ca1027b11adce 100644 --- a/src/test/run-pass/auxiliary/issue13507.rs +++ b/src/test/run-pass/auxiliary/issue13507.rs @@ -75,13 +75,13 @@ pub mod testtypes { fn foo_method(&self) -> usize; } - // Tests TyStruct + // Tests struct pub struct FooStruct { pub pub_foo_field: usize, foo_field: usize } - // Tests TyEnum + // Tests enum pub enum FooEnum { VarA(usize), VarB(usize, usize) From 553d5f0a38a1ce79e78e7216b493e95b63d29563 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Tue, 6 Sep 2016 01:26:02 +0300 Subject: [PATCH 2/2] Address comments --- src/librustc/ty/layout.rs | 404 ++++++++++++++++++-------------------- src/librustc/ty/util.rs | 35 ++-- 2 files changed, 210 insertions(+), 229 deletions(-) diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs index 3c0aa041d2dd3..e3f3da916a0a9 100644 --- a/src/librustc/ty/layout.rs +++ b/src/librustc/ty/layout.rs @@ -15,7 +15,7 @@ pub use self::Primitive::*; use infer::InferCtxt; use session::Session; use traits; -use ty::{self, AdtKind, Ty, TyCtxt, TypeFoldable}; +use ty::{self, Ty, TyCtxt, TypeFoldable}; use syntax::ast::{FloatTy, IntTy, UintTy}; use syntax::attr; @@ -555,7 +555,7 @@ impl<'a, 'gcx, 'tcx> Struct { } // Is this the NonZero lang item wrapping a pointer or integer type? - (&Univariant { non_zero: true, .. }, &ty::TyAdt(def, substs)) if def.is_struct() => { + (&Univariant { non_zero: true, .. }, &ty::TyAdt(def, substs)) => { let fields = &def.struct_variant().fields; assert_eq!(fields.len(), 1); match *fields[0].ty(tcx, substs).layout(infcx)? { @@ -918,243 +918,229 @@ impl<'a, 'gcx, 'tcx> Layout { Univariant { variant: st, non_zero: false } } - // ADTs. - ty::TyAdt(def, substs) => match def.adt_kind() { - AdtKind::Struct => { - if ty.is_simd() { - // SIMD vector types. - let element = ty.simd_type(tcx); - match *element.layout(infcx)? { - Scalar { value, .. } => { - return success(Vector { - element: value, - count: ty.simd_size(tcx) as u64 - }); - } - _ => { - tcx.sess.fatal(&format!("monomorphising SIMD type `{}` with \ - a non-machine element type `{}`", - ty, element)); - } - } + // SIMD vector types. + ty::TyAdt(def, ..) if def.is_simd() => { + let element = ty.simd_type(tcx); + match *element.layout(infcx)? { + Scalar { value, .. } => { + return success(Vector { + element: value, + count: ty.simd_size(tcx) as u64 + }); } - let fields = def.struct_variant().fields.iter().map(|field| { - field.ty(tcx, substs).layout(infcx) + _ => { + tcx.sess.fatal(&format!("monomorphising SIMD type `{}` with \ + a non-machine element type `{}`", + ty, element)); + } + } + } + + // ADTs. + ty::TyAdt(def, substs) => { + let hint = *tcx.lookup_repr_hints(def.did).get(0) + .unwrap_or(&attr::ReprAny); + + if def.variants.is_empty() { + // Uninhabitable; represent as unit + // (Typechecking will reject discriminant-sizing attrs.) + assert_eq!(hint, attr::ReprAny); + + return success(Univariant { + variant: Struct::new(dl, false), + non_zero: false }); - let packed = tcx.lookup_packed(def.did); - let mut st = Struct::new(dl, packed); - st.extend(dl, fields, ty)?; + } - Univariant { - variant: st, - non_zero: Some(def.did) == tcx.lang_items.non_zero() + if def.is_enum() && def.variants.iter().all(|v| v.fields.is_empty()) { + // All bodies empty -> intlike + let (mut min, mut max) = (i64::MAX, i64::MIN); + for v in &def.variants { + let x = v.disr_val.to_u64_unchecked() as i64; + if x < min { min = x; } + if x > max { max = x; } } + + let (discr, signed) = Integer::repr_discr(tcx, hint, min, max); + return success(CEnum { + discr: discr, + signed: signed, + min: min as u64, + max: max as u64 + }); } - AdtKind::Union => { - let fields = def.struct_variant().fields.iter().map(|field| { + + if def.variants.len() == 1 { + // Struct, or union, or univariant enum equivalent to a struct. + // (Typechecking will reject discriminant-sizing attrs.) + assert!(!def.is_enum() || hint == attr::ReprAny); + let fields = def.variants[0].fields.iter().map(|field| { field.ty(tcx, substs).layout(infcx) }); let packed = tcx.lookup_packed(def.did); - let mut un = Union::new(dl, packed); - un.extend(dl, fields, ty)?; - UntaggedUnion { variants: un } + let layout = if def.is_union() { + let mut un = Union::new(dl, packed); + un.extend(dl, fields, ty)?; + UntaggedUnion { variants: un } + } else { + let mut st = Struct::new(dl, packed); + st.extend(dl, fields, ty)?; + let non_zero = Some(def.did) == tcx.lang_items.non_zero(); + Univariant { variant: st, non_zero: non_zero } + }; + return success(layout); } - AdtKind::Enum => { - let hint = *tcx.lookup_repr_hints(def.did).get(0) - .unwrap_or(&attr::ReprAny); - - if def.variants.is_empty() { - // Uninhabitable; represent as unit - // (Typechecking will reject discriminant-sizing attrs.) - assert_eq!(hint, attr::ReprAny); - - return success(Univariant { - variant: Struct::new(dl, false), - non_zero: false - }); - } - - if def.variants.iter().all(|v| v.fields.is_empty()) { - // All bodies empty -> intlike - let (mut min, mut max) = (i64::MAX, i64::MIN); - for v in &def.variants { - let x = v.disr_val.to_u64_unchecked() as i64; - if x < min { min = x; } - if x > max { max = x; } - } - let (discr, signed) = Integer::repr_discr(tcx, hint, min, max); - return success(CEnum { - discr: discr, - signed: signed, - min: min as u64, - max: max as u64 - }); + // Since there's at least one + // non-empty body, explicit discriminants should have + // been rejected by a checker before this point. + for (i, v) in def.variants.iter().enumerate() { + if i as u64 != v.disr_val.to_u64_unchecked() { + bug!("non-C-like enum {} with specified discriminants", + tcx.item_path_str(def.did)); } + } - // Since there's at least one - // non-empty body, explicit discriminants should have - // been rejected by a checker before this point. - for (i, v) in def.variants.iter().enumerate() { - if i as u64 != v.disr_val.to_u64_unchecked() { - bug!("non-C-like enum {} with specified discriminants", - tcx.item_path_str(def.did)); - } - } + // Cache the substituted and normalized variant field types. + let variants = def.variants.iter().map(|v| { + v.fields.iter().map(|field| field.ty(tcx, substs)).collect::>() + }).collect::>(); - if def.variants.len() == 1 { - // Equivalent to a struct/tuple/newtype. - // (Typechecking will reject discriminant-sizing attrs.) - assert_eq!(hint, attr::ReprAny); - let fields = def.variants[0].fields.iter().map(|field| { - field.ty(tcx, substs).layout(infcx) + if variants.len() == 2 && hint == attr::ReprAny { + // Nullable pointer optimization + for discr in 0..2 { + let other_fields = variants[1 - discr].iter().map(|ty| { + ty.layout(infcx) }); - let mut st = Struct::new(dl, false); - st.extend(dl, fields, ty)?; - return success(Univariant { variant: st, non_zero: false }); - } - - // Cache the substituted and normalized variant field types. - let variants = def.variants.iter().map(|v| { - v.fields.iter().map(|field| field.ty(tcx, substs)).collect::>() - }).collect::>(); - - if variants.len() == 2 && hint == attr::ReprAny { - // Nullable pointer optimization - for discr in 0..2 { - let other_fields = variants[1 - discr].iter().map(|ty| { - ty.layout(infcx) - }); - if !Struct::would_be_zero_sized(dl, other_fields)? { - continue; - } - let path = Struct::non_zero_field_path(infcx, - variants[discr].iter().cloned())?; - let mut path = if let Some(p) = path { p } else { continue }; - - // FIXME(eddyb) should take advantage of a newtype. - if path == &[0] && variants[discr].len() == 1 { - match *variants[discr][0].layout(infcx)? { - Scalar { value, .. } => { - return success(RawNullablePointer { - nndiscr: discr as u64, - value: value - }); - } - _ => { - bug!("Layout::compute: `{}`'s non-zero \ - `{}` field not scalar?!", - ty, variants[discr][0]) - } + if !Struct::would_be_zero_sized(dl, other_fields)? { + continue; + } + let path = Struct::non_zero_field_path(infcx, + variants[discr].iter().cloned())?; + let mut path = if let Some(p) = path { p } else { continue }; + + // FIXME(eddyb) should take advantage of a newtype. + if path == &[0] && variants[discr].len() == 1 { + match *variants[discr][0].layout(infcx)? { + Scalar { value, .. } => { + return success(RawNullablePointer { + nndiscr: discr as u64, + value: value + }); + } + _ => { + bug!("Layout::compute: `{}`'s non-zero \ + `{}` field not scalar?!", + ty, variants[discr][0]) } } - - path.push(0); // For GEP through a pointer. - path.reverse(); - let mut st = Struct::new(dl, false); - st.extend(dl, variants[discr].iter().map(|ty| ty.layout(infcx)), ty)?; - return success(StructWrappedNullablePointer { - nndiscr: discr as u64, - nonnull: st, - discrfield: path - }); } - } - // The general case. - let discr_max = (variants.len() - 1) as i64; - assert!(discr_max >= 0); - let (min_ity, _) = Integer::repr_discr(tcx, hint, 0, discr_max); - - let mut align = dl.aggregate_align; - let mut size = Size::from_bytes(0); - - // We're interested in the smallest alignment, so start large. - let mut start_align = Align::from_bytes(256, 256).unwrap(); - - // Create the set of structs that represent each variant - // Use the minimum integer type we figured out above - let discr = Some(Scalar { value: Int(min_ity), non_zero: false }); - let mut variants = variants.into_iter().map(|fields| { - let mut found_start = false; - let fields = fields.into_iter().map(|field| { - let field = field.layout(infcx)?; - if !found_start { - // Find the first field we can't move later - // to make room for a larger discriminant. - let field_align = field.align(dl); - if field.size(dl).bytes() != 0 || field_align.abi() != 1 { - start_align = start_align.min(field_align); - found_start = true; - } - } - Ok(field) - }); + path.push(0); // For GEP through a pointer. + path.reverse(); let mut st = Struct::new(dl, false); - st.extend(dl, discr.iter().map(Ok).chain(fields), ty)?; - size = cmp::max(size, st.min_size()); - align = align.max(st.align); - Ok(st) - }).collect::, _>>()?; - - // Align the maximum variant size to the largest alignment. - size = size.abi_align(align); - - if size.bytes() >= dl.obj_size_bound() { - return Err(LayoutError::SizeOverflow(ty)); + st.extend(dl, variants[discr].iter().map(|ty| ty.layout(infcx)), ty)?; + return success(StructWrappedNullablePointer { + nndiscr: discr as u64, + nonnull: st, + discrfield: path + }); } + } - // Check to see if we should use a different type for the - // discriminant. We can safely use a type with the same size - // as the alignment of the first field of each variant. - // We increase the size of the discriminant to avoid LLVM copying - // padding when it doesn't need to. This normally causes unaligned - // load/stores and excessive memcpy/memset operations. By using a - // bigger integer size, LLVM can be sure about it's contents and - // won't be so conservative. - - // Use the initial field alignment - let wanted = start_align.abi(); - let mut ity = min_ity; - for &candidate in &[I16, I32, I64] { - let ty = Int(candidate); - if wanted == ty.align(dl).abi() && wanted == ty.size(dl).bytes() { - ity = candidate; - break; + // The general case. + let discr_max = (variants.len() - 1) as i64; + assert!(discr_max >= 0); + let (min_ity, _) = Integer::repr_discr(tcx, hint, 0, discr_max); + + let mut align = dl.aggregate_align; + let mut size = Size::from_bytes(0); + + // We're interested in the smallest alignment, so start large. + let mut start_align = Align::from_bytes(256, 256).unwrap(); + + // Create the set of structs that represent each variant + // Use the minimum integer type we figured out above + let discr = Some(Scalar { value: Int(min_ity), non_zero: false }); + let mut variants = variants.into_iter().map(|fields| { + let mut found_start = false; + let fields = fields.into_iter().map(|field| { + let field = field.layout(infcx)?; + if !found_start { + // Find the first field we can't move later + // to make room for a larger discriminant. + let field_align = field.align(dl); + if field.size(dl).bytes() != 0 || field_align.abi() != 1 { + start_align = start_align.min(field_align); + found_start = true; + } } - } + Ok(field) + }); + let mut st = Struct::new(dl, false); + st.extend(dl, discr.iter().map(Ok).chain(fields), ty)?; + size = cmp::max(size, st.min_size()); + align = align.max(st.align); + Ok(st) + }).collect::, _>>()?; + + // Align the maximum variant size to the largest alignment. + size = size.abi_align(align); + + if size.bytes() >= dl.obj_size_bound() { + return Err(LayoutError::SizeOverflow(ty)); + } - // FIXME(eddyb) conservative only to avoid diverging from trans::adt. - if align.abi() != start_align.abi() { - ity = min_ity; + // Check to see if we should use a different type for the + // discriminant. We can safely use a type with the same size + // as the alignment of the first field of each variant. + // We increase the size of the discriminant to avoid LLVM copying + // padding when it doesn't need to. This normally causes unaligned + // load/stores and excessive memcpy/memset operations. By using a + // bigger integer size, LLVM can be sure about it's contents and + // won't be so conservative. + + // Use the initial field alignment + let wanted = start_align.abi(); + let mut ity = min_ity; + for &candidate in &[I16, I32, I64] { + let ty = Int(candidate); + if wanted == ty.align(dl).abi() && wanted == ty.size(dl).bytes() { + ity = candidate; + break; } + } - // If the alignment is not larger than the chosen discriminant size, - // don't use the alignment as the final size. - if ity <= min_ity { - ity = min_ity; - } else { - // Patch up the variants' first few fields. - let old_ity_size = Int(min_ity).size(dl); - let new_ity_size = Int(ity).size(dl); - for variant in &mut variants { - for offset in &mut variant.offset_after_field { - if *offset > old_ity_size { - break; - } - *offset = new_ity_size; + // FIXME(eddyb) conservative only to avoid diverging from trans::adt. + if align.abi() != start_align.abi() { + ity = min_ity; + } + + // If the alignment is not larger than the chosen discriminant size, + // don't use the alignment as the final size. + if ity <= min_ity { + ity = min_ity; + } else { + // Patch up the variants' first few fields. + let old_ity_size = Int(min_ity).size(dl); + let new_ity_size = Int(ity).size(dl); + for variant in &mut variants { + for offset in &mut variant.offset_after_field { + if *offset > old_ity_size { + break; } + *offset = new_ity_size; } } + } - General { - discr: ity, - variants: variants, - size: size, - align: align - } + General { + discr: ity, + variants: variants, + size: size, + align: align } - }, + } // Types with no meaningful known layout. ty::TyProjection(_) | ty::TyAnon(..) => { diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs index 68de8d96f33dc..6b3ebaa895fa3 100644 --- a/src/librustc/ty/util.rs +++ b/src/librustc/ty/util.rs @@ -253,15 +253,13 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { /// if not a structure at all. Corresponds to the only possible unsized /// field, and its type can be used to determine unsizing strategy. pub fn struct_tail(self, mut ty: Ty<'tcx>) -> Ty<'tcx> { - loop { - match ty.sty { - TyAdt(def, substs) if def.is_struct() => { - match def.struct_variant().fields.last() { - Some(f) => ty = f.ty(self, substs), - None => break - } - } - _ => break + while let TyAdt(def, substs) = ty.sty { + if !def.is_struct() { + break + } + match def.struct_variant().fields.last() { + Some(f) => ty = f.ty(self, substs), + None => break } } ty @@ -277,17 +275,14 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { target: Ty<'tcx>) -> (Ty<'tcx>, Ty<'tcx>) { let (mut a, mut b) = (source, target); - loop { - match (&a.sty, &b.sty) { - (&TyAdt(a_def, a_substs), &TyAdt(b_def, b_substs)) - if a_def == b_def && a_def.is_struct() => { - match a_def.struct_variant().fields.last() { - Some(f) => { - a = f.ty(self, a_substs); - b = f.ty(self, b_substs); - } - _ => break - } + while let (&TyAdt(a_def, a_substs), &TyAdt(b_def, b_substs)) = (&a.sty, &b.sty) { + if a_def != b_def || !a_def.is_struct() { + break + } + match a_def.struct_variant().fields.last() { + Some(f) => { + a = f.ty(self, a_substs); + b = f.ty(self, b_substs); } _ => break }