1
Fork 0

Auto merge of #36016 - petrochenkov:union, r=nikomatsakis

Implement untagged unions (RFC 1444)

cc https://github.com/rust-lang/rust/issues/32836

Notes:
- The RFC doesn't talk about `#[packed]` unions, this implementation supports them, packing changes union's alignment to 1 and removes trailing padding.
- The RFC doesn't talk about dynamically sized unions, this implementation doesn't support them and rejects them during wf-checking (similarly, dynamically sized enums are not supported as well).
- The lint for drop fields in unions can't work precisely before monomorphization, so it works pessimistically - non-`Copy` generic fields are reported, types not implementing `Drop` directly, but having non-trivial drop code are reported.

    ```
    struct S(String); // Doesn't implement `Drop`
    union U<T> {
        a: S, // Reported
        b: T, // Reported
    }
    ```

- https://github.com/rust-lang/rust/pull/35764 was indeed helpful and landed timely, I didn't have to implement internal drop flags for unions.
- Unions are not permitted in constant patterns, because matching on union fields is unsafe, I didn't want unsafety checker to dig into all constants to uncover this possible unsafety.
- The RFC doesn't talk about `#[derive]`, generally trait impls cannot be derived for unions, but some of them can. I implemented only `#[derive(Copy)]` so far. In theory shallow `#[derive(Clone)]` can be derived as well if all union fields are `Copy`, I left it for later though, it requires changing how `Clone` impls are generated.
- Moving union fields is implemented as per https://github.com/rust-lang/rust/issues/32836#issuecomment-242511491.
- Testing strategy: union specific behavior is tested, sometimes very basically (e.g. debuginfo), behavior common for all ADTs (e.g. something like coherence
checks) is not generally tested.

r? @eddyb
This commit is contained in:
bors 2016-09-03 07:48:06 -07:00 committed by GitHub
commit d748fa6ecc
167 changed files with 2897 additions and 360 deletions

View file

@ -18,6 +18,7 @@ use syntax::visit::Visitor;
enum Target {
Fn,
Struct,
Union,
Enum,
Other,
}
@ -27,6 +28,7 @@ impl Target {
match item.node {
ast::ItemKind::Fn(..) => Target::Fn,
ast::ItemKind::Struct(..) => Target::Struct,
ast::ItemKind::Union(..) => Target::Union,
ast::ItemKind::Enum(..) => Target::Enum,
_ => Target::Other,
}
@ -62,8 +64,10 @@ impl<'a> CheckAttrVisitor<'a> {
let message = match &*name {
"C" => {
conflicting_reprs += 1;
if target != Target::Struct && target != Target::Enum {
"attribute should be applied to struct or enum"
if target != Target::Struct &&
target != Target::Union &&
target != Target::Enum {
"attribute should be applied to struct, enum or union"
} else {
continue
}
@ -71,8 +75,9 @@ impl<'a> CheckAttrVisitor<'a> {
"packed" => {
// Do not increment conflicting_reprs here, because "packed"
// can be used to modify another repr hint
if target != Target::Struct {
"attribute should be applied to struct"
if target != Target::Struct &&
target != Target::Union {
"attribute should be applied to struct or union"
} else {
continue
}

View file

@ -41,6 +41,7 @@ pub enum Def {
// If Def::Struct lives in value namespace (e.g. tuple struct, unit struct expressions)
// it denotes a constructor and its DefId refers to NodeId of the struct's constructor.
Struct(DefId),
Union(DefId),
Label(ast::NodeId),
Method(DefId),
Err,
@ -109,7 +110,7 @@ impl Def {
Def::Fn(..) | Def::Mod(..) | Def::ForeignMod(..) | Def::Static(..) |
Def::Variant(..) | Def::Enum(..) | Def::TyAlias(..) | Def::AssociatedTy(..) |
Def::TyParam(..) | Def::Struct(..) | Def::Trait(..) |
Def::TyParam(..) | Def::Struct(..) | Def::Union(..) | Def::Trait(..) |
Def::Method(..) | Def::Const(..) | Def::AssociatedConst(..) |
Def::PrimTy(..) | Def::Label(..) | Def::SelfTy(..) | Def::Err => {
bug!("attempted .var_id() on invalid {:?}", self)
@ -121,7 +122,7 @@ impl Def {
match *self {
Def::Fn(id) | Def::Mod(id) | Def::ForeignMod(id) | Def::Static(id, _) |
Def::Variant(_, id) | Def::Enum(id) | Def::TyAlias(id) | Def::AssociatedTy(_, id) |
Def::TyParam(id) | Def::Struct(id) | Def::Trait(id) |
Def::TyParam(id) | Def::Struct(id) | Def::Union(id) | Def::Trait(id) |
Def::Method(id) | Def::Const(id) | Def::AssociatedConst(id) |
Def::Local(id, _) | Def::Upvar(id, _, _, _) => {
id
@ -147,6 +148,7 @@ impl Def {
Def::TyAlias(..) => "type",
Def::AssociatedTy(..) => "associated type",
Def::Struct(..) => "struct",
Def::Union(..) => "union",
Def::Trait(..) => "trait",
Def::Method(..) => "method",
Def::Const(..) => "constant",

View file

@ -761,6 +761,10 @@ pub fn noop_fold_item_underscore<T: Folder>(i: Item_, folder: &mut T) -> Item_ {
let struct_def = folder.fold_variant_data(struct_def);
ItemStruct(struct_def, folder.fold_generics(generics))
}
ItemUnion(struct_def, generics) => {
let struct_def = folder.fold_variant_data(struct_def);
ItemUnion(struct_def, folder.fold_generics(generics))
}
ItemDefaultImpl(unsafety, ref trait_ref) => {
ItemDefaultImpl(unsafety, folder.fold_trait_ref((*trait_ref).clone()))
}

View file

@ -348,7 +348,8 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item) {
visitor.visit_ty(typ);
walk_list!(visitor, visit_impl_item, impl_items);
}
ItemStruct(ref struct_definition, ref generics) => {
ItemStruct(ref struct_definition, ref generics) |
ItemUnion(ref struct_definition, ref generics) => {
visitor.visit_generics(generics);
visitor.visit_id(item.id);
visitor.visit_variant_data(struct_definition, item.name, generics, item.id, item.span);

View file

@ -638,7 +638,10 @@ impl<'a> LoweringContext<'a> {
let struct_def = self.lower_variant_data(struct_def);
hir::ItemStruct(struct_def, self.lower_generics(generics))
}
ItemKind::Union(..) => panic!("`union` is not yet implemented"),
ItemKind::Union(ref vdata, ref generics) => {
let vdata = self.lower_variant_data(vdata);
hir::ItemUnion(vdata, self.lower_generics(generics))
}
ItemKind::DefaultImpl(unsafety, ref trait_ref) => {
hir::ItemDefaultImpl(self.lower_unsafety(unsafety),
self.lower_trait_ref(trait_ref))

View file

@ -302,9 +302,9 @@ impl<'ast> intravisit::Visitor<'ast> for DefCollector<'ast> {
let def_data = match i.node {
hir::ItemDefaultImpl(..) | hir::ItemImpl(..) =>
DefPathData::Impl,
hir::ItemEnum(..) | hir::ItemStruct(..) | hir::ItemTrait(..) |
hir::ItemExternCrate(..) | hir::ItemMod(..) | hir::ItemForeignMod(..) |
hir::ItemTy(..) =>
hir::ItemEnum(..) | hir::ItemStruct(..) | hir::ItemUnion(..) |
hir::ItemTrait(..) | hir::ItemExternCrate(..) | hir::ItemMod(..) |
hir::ItemForeignMod(..) | hir::ItemTy(..) =>
DefPathData::TypeNs(i.name.as_str()),
hir::ItemStatic(..) | hir::ItemConst(..) | hir::ItemFn(..) =>
DefPathData::ValueNs(i.name.as_str()),
@ -331,7 +331,8 @@ impl<'ast> intravisit::Visitor<'ast> for DefCollector<'ast> {
});
}
}
hir::ItemStruct(ref struct_def, _) => {
hir::ItemStruct(ref struct_def, _) |
hir::ItemUnion(ref struct_def, _) => {
// If this is a tuple-like struct, register the constructor.
if !struct_def.is_struct() {
this.create_def(struct_def.id(),

View file

@ -1030,6 +1030,7 @@ fn node_id_to_string(map: &Map, id: NodeId, include_id: bool) -> String {
ItemTy(..) => "ty",
ItemEnum(..) => "enum",
ItemStruct(..) => "struct",
ItemUnion(..) => "union",
ItemTrait(..) => "trait",
ItemImpl(..) => "impl",
ItemDefaultImpl(..) => "default impl",

View file

@ -1483,6 +1483,8 @@ pub enum Item_ {
ItemEnum(EnumDef, Generics),
/// A struct definition, e.g. `struct Foo<A> {x: A}`
ItemStruct(VariantData, Generics),
/// A union definition, e.g. `union Foo<A, B> {x: A, y: B}`
ItemUnion(VariantData, Generics),
/// Represents a Trait Declaration
ItemTrait(Unsafety, Generics, TyParamBounds, HirVec<TraitItem>),
@ -1512,6 +1514,7 @@ impl Item_ {
ItemTy(..) => "type alias",
ItemEnum(..) => "enum",
ItemStruct(..) => "struct",
ItemUnion(..) => "union",
ItemTrait(..) => "trait",
ItemImpl(..) |
ItemDefaultImpl(..) => "item",

View file

@ -752,7 +752,10 @@ impl<'a> State<'a> {
self.head(&visibility_qualified(&item.vis, "struct"))?;
self.print_struct(struct_def, generics, item.name, item.span, true)?;
}
hir::ItemUnion(ref struct_def, ref generics) => {
self.head(&visibility_qualified(&item.vis, "union"))?;
self.print_struct(struct_def, generics, item.name, item.span, true)?;
}
hir::ItemDefaultImpl(unsafety, ref trait_ref) => {
self.head("")?;
self.print_visibility(&item.vis)?;

View file

@ -105,6 +105,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
match item.node {
hir::ItemImpl(..) => "impl",
hir::ItemStruct(..) => "struct",
hir::ItemUnion(..) => "union",
hir::ItemEnum(..) => "enum",
hir::ItemTrait(..) => "trait",
hir::ItemFn(..) => "function body",
@ -1370,7 +1371,8 @@ impl<'a, 'gcx, 'tcx> Rebuilder<'a, 'gcx, 'tcx> {
}
hir::TyPath(ref maybe_qself, ref path) => {
match self.tcx.expect_def(cur_ty.id) {
Def::Enum(did) | Def::TyAlias(did) | Def::Struct(did) => {
Def::Enum(did) | Def::TyAlias(did) |
Def::Struct(did) | Def::Union(did) => {
let generics = self.tcx.lookup_generics(did);
let expected =

View file

@ -168,6 +168,7 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for TypeFreshener<'a, 'gcx, 'tcx> {
ty::TyFnPtr(_) |
ty::TyTrait(..) |
ty::TyStruct(..) |
ty::TyUnion(..) |
ty::TyClosure(..) |
ty::TyNever |
ty::TyTuple(..) |

View file

@ -86,7 +86,7 @@ impl<'a, 'tcx> MarkSymbolVisitor<'a, 'tcx> {
}
fn lookup_and_handle_definition(&mut self, id: ast::NodeId) {
use ty::TypeVariants::{TyEnum, TyStruct};
use ty::TypeVariants::{TyEnum, TyStruct, TyUnion};
let def = self.tcx.expect_def(id);
@ -96,7 +96,7 @@ impl<'a, 'tcx> MarkSymbolVisitor<'a, 'tcx> {
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, _) => {
TyEnum(tyid, _) | TyStruct(tyid, _) | TyUnion(tyid, _) => {
self.check_def_id(tyid.did)
}
_ => {}
@ -132,10 +132,11 @@ impl<'a, 'tcx> MarkSymbolVisitor<'a, 'tcx> {
}
fn handle_field_access(&mut self, lhs: &hir::Expr, name: ast::Name) {
if let ty::TyStruct(def, _) = self.tcx.expr_ty_adjusted(lhs).sty {
self.insert_def_id(def.struct_variant().field_named(name).did);
} else {
span_bug!(lhs.span, "named field access on non-struct")
match self.tcx.expr_ty_adjusted(lhs).sty {
ty::TyStruct(def, _) | ty::TyUnion(def, _) => {
self.insert_def_id(def.struct_variant().field_named(name).did);
}
_ => span_bug!(lhs.span, "named field access on non-struct/union"),
}
}
@ -148,7 +149,7 @@ impl<'a, 'tcx> MarkSymbolVisitor<'a, 'tcx> {
fn handle_field_pattern_match(&mut self, lhs: &hir::Pat,
pats: &[codemap::Spanned<hir::FieldPat>]) {
let variant = match self.tcx.node_id_to_type(lhs.id).sty {
ty::TyStruct(adt, _) | ty::TyEnum(adt, _) => {
ty::TyStruct(adt, _) | ty::TyUnion(adt, _) | ty::TyEnum(adt, _) => {
adt.variant_of_def(self.tcx.expect_def(lhs.id))
}
_ => span_bug!(lhs.span, "non-ADT in struct pattern")
@ -185,7 +186,7 @@ impl<'a, 'tcx> MarkSymbolVisitor<'a, 'tcx> {
match *node {
ast_map::NodeItem(item) => {
match item.node {
hir::ItemStruct(..) => {
hir::ItemStruct(..) | hir::ItemUnion(..) => {
self.struct_has_extern_repr = item.attrs.iter().any(|attr| {
attr::find_repr_attrs(self.tcx.sess.diagnostic(), attr)
.contains(&attr::ReprExtern)
@ -423,7 +424,8 @@ impl<'a, 'tcx> DeadVisitor<'a, 'tcx> {
| hir::ItemConst(..)
| hir::ItemFn(..)
| hir::ItemEnum(..)
| hir::ItemStruct(..) => true,
| hir::ItemStruct(..)
| hir::ItemUnion(..) => true,
_ => false
};
let ctor_id = get_struct_ctor_id(item);

View file

@ -13,15 +13,14 @@
use self::RootUnsafeContext::*;
use dep_graph::DepNode;
use hir::def::Def;
use ty::{self, Ty, TyCtxt};
use ty::MethodCall;
use syntax::ast;
use syntax_pos::Span;
use hir;
use hir::intravisit;
use hir::intravisit::{FnKind, Visitor};
use hir::{self, PatKind};
use hir::def::Def;
use hir::intravisit::{self, FnKind, Visitor};
#[derive(Copy, Clone)]
struct UnsafeContext {
@ -178,11 +177,28 @@ impl<'a, 'tcx, 'v> Visitor<'v> for EffectCheckVisitor<'a, 'tcx> {
self.require_unsafe(expr.span, "use of mutable static");
}
}
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");
}
}
_ => {}
}
intravisit::walk_expr(self, expr);
}
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");
}
}
}
intravisit::walk_pat(self, pat);
}
}
pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {

View file

@ -414,7 +414,7 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> {
}
hir::ExprStruct(_, ref fields, ref opt_with) => {
self.walk_struct_expr(expr, fields, opt_with);
self.walk_struct_expr(fields, opt_with);
}
hir::ExprTup(ref exprs) => {
@ -655,7 +655,6 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> {
}
fn walk_struct_expr(&mut self,
_expr: &hir::Expr,
fields: &[hir::Field],
opt_with: &Option<P<hir::Expr>>) {
// Consume the expressions supplying values for each field.
@ -695,7 +694,7 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> {
with_expr.span,
"with expression doesn't evaluate to a struct");
}
};
}
// walk the with expression so that complex expressions
// are properly handled.
@ -1012,7 +1011,8 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> {
debug!("variant downcast_cmt={:?} pat={:?}", downcast_cmt, pat);
delegate.matched_pat(pat, downcast_cmt, match_mode);
}
Some(Def::Struct(..)) | Some(Def::TyAlias(..)) | Some(Def::AssociatedTy(..)) => {
Some(Def::Struct(..)) | Some(Def::Union(..)) |
Some(Def::TyAlias(..)) | Some(Def::AssociatedTy(..)) => {
debug!("struct cmt_pat={:?} pat={:?}", cmt_pat, pat);
delegate.matched_pat(pat, cmt_pat, match_mode);
}

View file

@ -572,7 +572,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
id, expr_ty, def);
match def {
Def::Struct(..) | Def::Variant(..) | Def::Const(..) |
Def::Struct(..) | Def::Union(..) | Def::Variant(..) | Def::Const(..) |
Def::AssociatedConst(..) | Def::Fn(..) | Def::Method(..) => {
Ok(self.cat_rvalue_node(id, span, expr_ty))
}

View file

@ -269,7 +269,7 @@ impl<'a, 'tcx> ReachableContext<'a, 'tcx> {
hir::ItemMod(..) | hir::ItemForeignMod(..) |
hir::ItemImpl(..) | hir::ItemTrait(..) |
hir::ItemStruct(..) | hir::ItemEnum(..) |
hir::ItemDefaultImpl(..) => {}
hir::ItemUnion(..) | hir::ItemDefaultImpl(..) => {}
}
}
ast_map::NodeTraitItem(trait_method) => {

View file

@ -156,6 +156,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for LifetimeContext<'a, 'tcx> {
hir::ItemTy(_, ref generics) |
hir::ItemEnum(_, ref generics) |
hir::ItemStruct(_, ref generics) |
hir::ItemUnion(_, ref generics) |
hir::ItemTrait(_, ref generics, _, _) |
hir::ItemImpl(_, _, ref generics, _, _, _) => {
// These kinds of items have only early bound lifetime parameters.

View file

@ -561,9 +561,11 @@ 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, _) => def.struct_variant().field_named(field.node).did,
ty::TyStruct(def, _) | ty::TyUnion(def, _) => {
def.struct_variant().field_named(field.node).did
}
_ => span_bug!(e.span,
"stability::check_expr: named field access on non-struct")
"stability::check_expr: named field access on non-struct/union")
}
}
hir::ExprTupField(ref base_e, ref field) => {
@ -579,7 +581,7 @@ 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::TyStruct(def, _) | ty::TyUnion(def, _) => {
// check the stability of each field that appears
// in the construction expression.
for field in expr_fields {
@ -599,7 +601,7 @@ pub fn check_expr<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, e: &hir::Expr,
_ => {
span_bug!(e.span,
"stability::check_expr: struct construction \
of non-struct, type {:?}",
of non-struct/union, type {:?}",
type_);
}
}
@ -647,7 +649,8 @@ pub fn check_pat<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, pat: &hir::Pat,
if is_internal(tcx, pat.span) { return; }
let v = match tcx.pat_ty_opt(pat) {
Some(&ty::TyS { sty: ty::TyStruct(def, _), .. }) => def.struct_variant(),
Some(&ty::TyS { sty: ty::TyStruct(def, _), .. }) |
Some(&ty::TyS { sty: ty::TyUnion(def, _), .. }) => def.struct_variant(),
Some(_) | None => return,
};
match pat.node {

View file

@ -962,7 +962,10 @@ pub enum CastKind {
pub enum AggregateKind<'tcx> {
Vec,
Tuple,
Adt(AdtDef<'tcx>, usize, &'tcx Substs<'tcx>),
/// The second field is variant number (discriminant), it's equal to 0
/// for struct and union expressions. The fourth field is active field
/// number and is present only for union expressions.
Adt(AdtDef<'tcx>, usize, &'tcx Substs<'tcx>, Option<usize>),
Closure(DefId, ClosureSubsts<'tcx>),
}
@ -1069,7 +1072,7 @@ impl<'tcx> Debug for Rvalue<'tcx> {
}
}
Adt(adt_def, variant, substs) => {
Adt(adt_def, variant, substs, _) => {
let variant_def = &adt_def.variants[variant];
ppaux::parameterized(fmt, substs, variant_def.did,

View file

@ -187,7 +187,7 @@ impl<'tcx> Rvalue<'tcx> {
ops.iter().map(|op| op.ty(mir, tcx)).collect()
))
}
AggregateKind::Adt(def, _, substs) => {
AggregateKind::Adt(def, _, substs, _) => {
Some(tcx.lookup_item_type(def.did).ty.subst(tcx, substs))
}
AggregateKind::Closure(did, substs) => {

View file

@ -536,7 +536,8 @@ macro_rules! make_mir_visitor {
}
AggregateKind::Adt(_adt_def,
_variant_index,
ref $($mutability)* substs) => {
ref $($mutability)* substs,
_active_field_index) => {
self.visit_substs(substs);
}
AggregateKind::Closure(ref $($mutability)* def_id,

View file

@ -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::TyEnum(def, _) | ty::TyStruct(def, _) | ty::TyUnion(def, _) =>
def.is_fundamental(),
ty::TyTrait(ref data) =>
tcx.has_attr(data.principal.def_id(), "fundamental"),
@ -261,7 +261,8 @@ fn ty_is_local_constructor(tcx: TyCtxt, ty: Ty, infer_is_local: InferIsLocal)->
}
ty::TyEnum(def, _) |
ty::TyStruct(def, _) => {
ty::TyStruct(def, _) |
ty::TyUnion(def, _) => {
def.did.is_local()
}

View file

@ -166,6 +166,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
ty::TyParam(..) => Some(14),
ty::TyAnon(..) => Some(15),
ty::TyNever => Some(16),
ty::TyUnion(..) => Some(17),
ty::TyInfer(..) | ty::TyError => None
}
}
@ -173,6 +174,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
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,
_ => cat_a == cat_b

View file

@ -1780,7 +1780,8 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
Where(ty::Binder(tys.last().into_iter().cloned().collect()))
}
ty::TyStruct(def, substs) | ty::TyEnum(def, substs) => {
ty::TyStruct(def, substs) | ty::TyUnion(def, substs) |
ty::TyEnum(def, substs) => {
let sized_crit = def.sized_constraint(self.tcx());
// (*) binder moved here
Where(ty::Binder(match sized_crit.sty {
@ -1836,7 +1837,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
Where(ty::Binder(tys.to_vec()))
}
ty::TyStruct(..) | ty::TyEnum(..) |
ty::TyStruct(..) | ty::TyUnion(..) | ty::TyEnum(..) |
ty::TyProjection(..) | ty::TyParam(..) | ty::TyAnon(..) => {
// Fallback to whatever user-defined impls exist in this case.
None
@ -1933,7 +1934,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
substs.types().collect()
}
ty::TyStruct(def, substs) | ty::TyEnum(def, substs) => {
ty::TyStruct(def, substs) | ty::TyUnion(def, substs) | ty::TyEnum(def, substs) => {
def.all_fields()
.map(|f| f.ty(self.tcx(), substs))
.collect()

View file

@ -224,7 +224,8 @@ impl<'a, 'tcx> ty::TyS<'tcx> {
|ty| tc_ty(tcx, *ty, cache))
}
ty::TyStruct(def, substs) | ty::TyEnum(def, substs) => {
ty::TyStruct(def, substs) | ty::TyUnion(def, substs) |
ty::TyEnum(def, substs) => {
let mut res =
TypeContents::union(&def.variants, |v| {
TypeContents::union(&v.fields, |f| {

View file

@ -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, TyClosure, TyTuple, TyParam, TyInfer, TyProjection, TyAnon);
TyEnum, TyBox, TyArray, TySlice, TyRawPtr, TyRef, TyFnDef, TyFnPtr, TyTrait,
TyStruct, TyUnion, TyClosure, TyTuple, TyParam, TyInfer, TyProjection, TyAnon);
println!("Substs interner: #{}", self.interners.substs.borrow().len());
println!("BareFnTy interner: #{}", self.interners.bare_fn.borrow().len());
@ -1321,6 +1321,11 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
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>,

View file

@ -247,6 +247,9 @@ impl<'a, 'gcx, 'lcx, 'tcx> ty::TyS<'tcx> {
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(),

View file

@ -30,6 +30,7 @@ pub enum SimplifiedType {
TupleSimplifiedType(usize),
TraitSimplifiedType(DefId),
StructSimplifiedType(DefId),
UnionSimplifiedType(DefId),
ClosureSimplifiedType(DefId),
AnonSimplifiedType(DefId),
FunctionSimplifiedType(usize),
@ -66,6 +67,9 @@ pub fn simplify_type<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
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

View file

@ -102,7 +102,7 @@ impl FlagComputation {
}
}
&ty::TyEnum(_, substs) | &ty::TyStruct(_, substs) => {
&ty::TyEnum(_, substs) | &ty::TyStruct(_, substs) | &ty::TyUnion(_, substs) => {
self.add_substs(substs);
}

View file

@ -263,6 +263,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
// 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) => {
if substs.types().next().is_none() { // ignore regions
self.push_item_path(buffer, adt_def.did);
@ -320,6 +321,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
pub fn characteristic_def_id_of_type(ty: Ty) -> Option<DefId> {
match ty.sty {
ty::TyStruct(adt_def, _) |
ty::TyUnion(adt_def, _) |
ty::TyEnum(adt_def, _) => Some(adt_def.did),
ty::TyTrait(ref data) => Some(data.principal.def_id()),

View file

@ -488,7 +488,7 @@ impl<'a, 'gcx, 'tcx> Struct {
for field in fields {
if !self.sized {
bug!("Struct::compute: field #{} of `{}` comes after unsized field",
bug!("Struct::extend: field #{} of `{}` comes after unsized field",
self.offset_after_field.len(), scapegoat);
}
@ -623,6 +623,54 @@ impl<'a, 'gcx, 'tcx> Struct {
}
}
/// An untagged union.
#[derive(PartialEq, Eq, Hash, Debug)]
pub struct Union {
pub align: Align,
pub min_size: Size,
/// If true, no alignment padding is used.
pub packed: bool,
}
impl<'a, 'gcx, 'tcx> Union {
pub fn new(dl: &TargetDataLayout, packed: bool) -> Union {
Union {
align: if packed { dl.i8_align } else { dl.aggregate_align },
min_size: Size::from_bytes(0),
packed: packed,
}
}
/// Extend the Struct with more fields.
pub fn extend<I>(&mut self, dl: &TargetDataLayout,
fields: I,
scapegoat: Ty<'gcx>)
-> Result<(), LayoutError<'gcx>>
where I: Iterator<Item=Result<&'a Layout, LayoutError<'gcx>>> {
for (index, field) in fields.enumerate() {
let field = field?;
if field.is_unsized() {
bug!("Union::extend: field #{} of `{}` is unsized",
index, scapegoat);
}
if !self.packed {
self.align = self.align.max(field.align(dl));
}
self.min_size = cmp::max(self.min_size, field.size(dl));
}
Ok(())
}
/// Get the size with trailing aligment padding.
pub fn stride(&self) -> Size {
self.min_size.abi_align(self.align)
}
}
/// The first half of a fat pointer.
/// - For a trait object, this is the address of the box.
/// - For a slice, this is the base address.
@ -690,6 +738,11 @@ pub enum Layout {
non_zero: bool
},
/// Untagged unions.
UntaggedUnion {
variants: Union,
},
/// General-case enums: for each case there is a struct, and they
/// all start with a field for the discriminant.
General {
@ -896,6 +949,15 @@ impl<'a, 'gcx, 'tcx> Layout {
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);
@ -1115,7 +1177,7 @@ impl<'a, 'gcx, 'tcx> Layout {
pub fn is_unsized(&self) -> bool {
match *self {
Scalar {..} | Vector {..} | FatPointer {..} |
CEnum {..} | General {..} |
CEnum {..} | UntaggedUnion {..} | General {..} |
RawNullablePointer {..} |
StructWrappedNullablePointer {..} => false,
@ -1149,6 +1211,7 @@ impl<'a, 'gcx, 'tcx> Layout {
CEnum { discr, .. } => Int(discr).size(dl),
Array { size, .. } | General { size, .. } => size,
UntaggedUnion { ref variants } => variants.stride(),
Univariant { ref variant, .. } |
StructWrappedNullablePointer { nonnull: ref variant, .. } => {
@ -1188,6 +1251,7 @@ impl<'a, 'gcx, 'tcx> Layout {
CEnum { discr, .. } => Int(discr).align(dl),
Array { align, .. } | General { align, .. } => align,
UntaggedUnion { ref variants } => variants.align,
Univariant { ref variant, .. } |
StructWrappedNullablePointer { nonnull: ref variant, .. } => {

View file

@ -948,6 +948,7 @@ impl<'tcx> TraitPredicate<'tcx> {
.flat_map(|t| t.walk())
.filter_map(|t| match t.sty {
ty::TyStruct(adt_def, _) |
ty::TyUnion(adt_def, _) |
ty::TyEnum(adt_def, _) =>
Some(adt_def.did),
_ =>
@ -1341,6 +1342,7 @@ impl<'a, 'tcx> ParameterEnvironment<'tcx> {
}
hir::ItemEnum(..) |
hir::ItemStruct(..) |
hir::ItemUnion(..) |
hir::ItemTy(..) |
hir::ItemImpl(..) |
hir::ItemConst(..) |
@ -1421,6 +1423,7 @@ bitflags! {
const IS_PHANTOM_DATA = 1 << 3,
const IS_SIMD = 1 << 4,
const IS_FUNDAMENTAL = 1 << 5,
const IS_UNION = 1 << 6,
}
}
@ -1513,7 +1516,7 @@ impl<'tcx> Decodable for AdtDef<'tcx> {
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum AdtKind { Struct, Enum }
pub enum AdtKind { Struct, Union, Enum }
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)]
pub enum VariantKind { Struct, Tuple, Unit }
@ -1544,8 +1547,10 @@ impl<'a, 'gcx, 'tcx, 'container> AdtDefData<'gcx, 'container> {
if Some(did) == tcx.lang_items.phantom_data() {
flags = flags | AdtFlags::IS_PHANTOM_DATA;
}
if let AdtKind::Enum = kind {
flags = flags | AdtFlags::IS_ENUM;
match kind {
AdtKind::Enum => flags = flags | AdtFlags::IS_ENUM,
AdtKind::Union => flags = flags | AdtFlags::IS_UNION,
AdtKind::Struct => {}
}
AdtDefData {
did: did,
@ -1568,6 +1573,8 @@ impl<'a, 'gcx, 'tcx, 'container> AdtDefData<'gcx, 'container> {
pub fn adt_kind(&self) -> AdtKind {
if self.flags.get().intersects(AdtFlags::IS_ENUM) {
AdtKind::Enum
} else if self.flags.get().intersects(AdtFlags::IS_UNION) {
AdtKind::Union
} else {
AdtKind::Struct
}
@ -1610,7 +1617,8 @@ 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> {
assert_eq!(self.adt_kind(), AdtKind::Struct);
let adt_kind = self.adt_kind();
assert!(adt_kind == AdtKind::Struct || adt_kind == AdtKind::Union);
&self.variants[0]
}
@ -1669,7 +1677,8 @@ impl<'a, 'gcx, 'tcx, 'container> AdtDefData<'gcx, 'container> {
pub fn variant_of_def(&self, def: Def) -> &VariantDefData<'gcx, 'container> {
match def {
Def::Variant(_, vid) => self.variant_with_id(vid),
Def::Struct(..) | Def::TyAlias(..) | Def::AssociatedTy(..) => self.struct_variant(),
Def::Struct(..) | Def::Union(..) |
Def::TyAlias(..) | Def::AssociatedTy(..) => self.struct_variant(),
_ => bug!("unexpected def {:?} in variant_of_def", def)
}
}
@ -1818,7 +1827,7 @@ impl<'a, 'tcx> AdtDefData<'tcx, 'tcx> {
}
}
TyEnum(adt, substs) | TyStruct(adt, substs) => {
TyEnum(adt, substs) | TyStruct(adt, substs) | TyUnion(adt, substs) => {
// recursive case
let adt = tcx.lookup_adt_def_master(adt.did);
adt.calculate_sized_constraint_inner(tcx, stack);
@ -2408,7 +2417,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
Def::Variant(enum_did, did) => {
self.lookup_adt_def(enum_did).variant_with_id(did)
}
Def::Struct(did) => {
Def::Struct(did) | Def::Union(did) => {
self.lookup_adt_def(did).struct_variant()
}
_ => bug!("expect_variant_def used with unexpected def {:?}", def)

View file

@ -174,6 +174,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
ty::TyNever | // ...
ty::TyEnum(..) | // OutlivesNominalType
ty::TyStruct(..) | // OutlivesNominalType
ty::TyUnion(..) | // OutlivesNominalType
ty::TyBox(..) | // OutlivesNominalType (ish)
ty::TyAnon(..) | // OutlivesNominalType (ish)
ty::TyStr | // OutlivesScalar (ish)

View file

@ -447,6 +447,13 @@ pub fn super_relate_tys<'a, 'gcx, 'tcx, R>(relation: &mut R,
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 =>

View file

@ -495,6 +495,7 @@ impl<'tcx> TypeFoldable<'tcx> for Ty<'tcx> {
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)),
@ -524,6 +525,7 @@ 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),

View file

@ -112,7 +112,7 @@ pub enum TypeVariants<'tcx> {
/// 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`
/// as well.
/// and `TyUnion` as well.
TyEnum(AdtDef<'tcx>, &'tcx Substs<'tcx>),
/// A structure type, defined with `struct`.
@ -120,6 +120,11 @@ pub enum TypeVariants<'tcx> {
/// 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>),
/// `Box<T>`; this is nominally a struct in the documentation, but is
/// special-cased internally. For example, it is possible to implicitly
/// move the contents of a box out of that box, and methods of any type
@ -917,7 +922,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, _) => def.is_empty(),
TyEnum(def, _) | TyStruct(def, _) | TyUnion(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.
@ -980,7 +985,7 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> {
pub fn is_structural(&self) -> bool {
match self.sty {
TyStruct(..) | TyTuple(_) | TyEnum(..) |
TyStruct(..) | TyUnion(..) | TyTuple(..) | TyEnum(..) |
TyArray(..) | TyClosure(..) => true,
_ => self.is_slice() | self.is_trait()
}
@ -1199,6 +1204,7 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> {
match self.sty {
TyTrait(ref tt) => Some(tt.principal.def_id()),
TyStruct(def, _) |
TyUnion(def, _) |
TyEnum(def, _) => Some(def.did),
TyClosure(id, _) => Some(id),
_ => None
@ -1207,7 +1213,7 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> {
pub fn ty_adt_def(&self) -> Option<AdtDef<'tcx>> {
match self.sty {
TyStruct(adt, _) | TyEnum(adt, _) => Some(adt),
TyStruct(adt, _) | TyUnion(adt, _) | TyEnum(adt, _) => Some(adt),
_ => None
}
}
@ -1227,6 +1233,7 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> {
}
TyEnum(_, substs) |
TyStruct(_, substs) |
TyUnion(_, substs) |
TyAnon(_, substs) => {
substs.regions().collect()
}

View file

@ -138,7 +138,7 @@ 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::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) {
@ -183,7 +183,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::TyEnum(def, substs) => {
ty::TyStruct(def, substs) | ty::TyUnion(def, substs) | ty::TyEnum(def, substs) => {
for field in def.all_fields() {
let field_ty = field.ty(self, substs);
if let TyError = field_ty.sty {
@ -203,7 +203,8 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
i: usize,
variant: Option<DefId>) -> Option<Ty<'tcx>> {
match (&ty.sty, variant) {
(&TyStruct(def, substs), None) => {
(&TyStruct(def, substs), None) |
(&TyUnion(def, substs), None) => {
def.struct_variant().fields.get(i).map(|f| f.ty(self, substs))
}
(&TyEnum(def, substs), Some(vid)) => {
@ -225,7 +226,8 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
n: Name,
variant: Option<DefId>) -> Option<Ty<'tcx>> {
match (&ty.sty, variant) {
(&TyStruct(def, substs), None) => {
(&TyStruct(def, substs), None) |
(&TyUnion(def, substs), None) => {
def.struct_variant().find_field_named(n).map(|f| f.ty(self, substs))
}
(&TyEnum(def, substs), Some(vid)) => {
@ -430,6 +432,7 @@ impl<'a, 'gcx, 'tcx> TypeVisitor<'tcx> for TypeIdHasher<'a, 'gcx, 'tcx> {
TyUint(u) => self.hash(u),
TyFloat(f) => self.hash(f),
TyStruct(d, _) |
TyUnion(d, _) |
TyEnum(d, _) => self.def_id(d.did),
TyArray(_, n) => self.hash(n),
TyRawPtr(m) |
@ -558,7 +561,7 @@ impl<'a, 'tcx> ty::TyS<'tcx> {
}) => Some(true),
TyArray(..) | TySlice(_) | TyTrait(..) | TyTuple(..) |
TyClosure(..) | TyEnum(..) | TyStruct(..) | TyAnon(..) |
TyClosure(..) | TyEnum(..) | TyStruct(..) | TyUnion(..) | TyAnon(..) |
TyProjection(..) | TyParam(..) | TyInfer(..) | TyError => None
}.unwrap_or_else(|| !self.impls_bound(tcx, param_env, ty::BoundCopy, span));
@ -598,7 +601,7 @@ impl<'a, 'tcx> ty::TyS<'tcx> {
TyStr | TyTrait(..) | TySlice(_) => Some(false),
TyEnum(..) | TyStruct(..) | TyProjection(..) | TyParam(..) |
TyEnum(..) | TyStruct(..) | TyUnion(..) | TyProjection(..) | TyParam(..) |
TyInfer(..) | TyAnon(..) | TyError => None
}.unwrap_or_else(|| self.impls_bound(tcx, param_env, ty::BoundSized, span));
@ -660,7 +663,7 @@ impl<'a, 'tcx> ty::TyS<'tcx> {
TyArray(ty, _) => {
is_type_structurally_recursive(tcx, sp, seen, ty)
}
TyStruct(def, substs) | TyEnum(def, substs) => {
TyStruct(def, substs) | TyUnion(def, substs) | TyEnum(def, substs) => {
find_nonrepresentable(tcx,
sp,
seen,
@ -677,7 +680,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, _) | TyEnum(ty_def, _) => {
TyStruct(ty_def, _) | TyUnion(ty_def, _) | TyEnum(ty_def, _) => {
ty_def == def
}
_ => false
@ -687,6 +690,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)) => {
if did_a != did_b {
return false;
@ -709,7 +713,7 @@ impl<'a, 'tcx> ty::TyS<'tcx> {
debug!("is_type_structurally_recursive: {:?}", ty);
match ty.sty {
TyStruct(def, _) | TyEnum(def, _) => {
TyStruct(def, _) | TyUnion(def, _) | TyEnum(def, _) => {
{
// Iterate through stack of previously seen types.
let mut iter = seen.iter();

View file

@ -95,6 +95,7 @@ fn push_subtypes<'tcx>(stack: &mut Vec<Ty<'tcx>>, parent_ty: Ty<'tcx>) {
}
ty::TyEnum(_, ref substs) |
ty::TyStruct(_, ref substs) |
ty::TyUnion(_, ref substs) |
ty::TyAnon(_, ref substs) => {
stack.extend(substs.types().rev());
}

View file

@ -337,7 +337,8 @@ impl<'a, 'gcx, 'tcx> WfPredicates<'a, 'gcx, 'tcx> {
}
ty::TyEnum(def, substs) |
ty::TyStruct(def, substs) => {
ty::TyStruct(def, substs) |
ty::TyUnion(def, substs) => {
// WfNominalType
let obligations = self.nominal_obligations(def.did, substs);
self.out.extend(obligations);

View file

@ -8,11 +8,10 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use hir::def_id::DefId;
use ty::subst::{self, Subst, Substs};
use ty::{BrAnon, BrEnv, BrFresh, BrNamed};
use ty::{TyBool, TyChar, TyStruct, TyEnum};
use ty::{TyBool, TyChar, TyStruct, TyUnion, TyEnum};
use ty::{TyError, TyStr, TyArray, TySlice, TyFloat, TyFnDef, TyFnPtr};
use ty::{TyParam, TyRawPtr, TyRef, TyNever, TyTuple};
use ty::TyClosure;
@ -869,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) => {
TyEnum(def, substs) | TyStruct(def, substs) | TyUnion(def, substs) => {
ty::tls::with(|tcx| {
if def.did.is_local() &&
!tcx.tcache.borrow().contains_key(&def.did) {

View file

@ -796,7 +796,9 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> {
}
LpExtend(ref lp_base, _, LpInterior(_, InteriorField(_))) => {
match lp_base.to_type().sty {
ty::TyStruct(def, _) | ty::TyEnum(def, _) if def.has_dtor() => {
ty::TyStruct(def, _) |
ty::TyUnion(def, _) |
ty::TyEnum(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

View file

@ -461,6 +461,10 @@ fn add_fragment_siblings_for_extension<'a, 'tcx>(this: &MoveData<'tcx>,
}
}
(&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),

View file

@ -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::TyEnum(def, _) => {
ty::TyStruct(def, _) | ty::TyUnion(def, _) | ty::TyEnum(def, _) => {
if def.has_dtor() {
Some(cmt.clone())
} else {

View file

@ -149,6 +149,7 @@ fn report_cannot_move_out_of<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
Categorization::Interior(ref b, mc::InteriorField(_)) => {
match b.ty.sty {
ty::TyStruct(def, _) |
ty::TyUnion(def, _) |
ty::TyEnum(def, _) if def.has_dtor() => {
let mut err = struct_span_err!(bccx, move_from.span, E0509,
"cannot move out of type `{}`, \

View file

@ -89,7 +89,7 @@ impl<'a, 'tcx> RestrictionsContext<'a, 'tcx> {
self.restrict(cmt_base)
}
Categorization::Interior(cmt_base, i) => {
Categorization::Interior(cmt_base, interior) => {
// R-Field
//
// Overwriting the base would not change the type of
@ -99,8 +99,35 @@ impl<'a, 'tcx> RestrictionsContext<'a, 'tcx> {
Categorization::Downcast(_, variant_id) => Some(variant_id),
_ => None
};
let interior = interior.cleaned();
let base_ty = cmt_base.ty;
let result = self.restrict(cmt_base);
self.extend(result, &cmt, LpInterior(opt_variant_id, i.cleaned()))
// Borrowing one union field automatically borrows all its fields.
if let ty::TyUnion(ref adt_def, _) = base_ty.sty {
match result {
RestrictionResult::Safe => RestrictionResult::Safe,
RestrictionResult::SafeIf(base_lp, mut base_vec) => {
for field in &adt_def.struct_variant().fields {
let field = InteriorKind::InteriorField(mc::NamedField(field.name));
let field_ty = if field == interior {
cmt.ty
} else {
self.bccx.tcx.types.err // Doesn't matter
};
let sibling_lp_kind = LpExtend(base_lp.clone(), cmt.mutbl,
LpInterior(opt_variant_id, field));
let sibling_lp = Rc::new(LoanPath::new(sibling_lp_kind, field_ty));
base_vec.push(sibling_lp);
}
let lp = new_lp(LpExtend(base_lp, cmt.mutbl,
LpInterior(opt_variant_id, interior)));
RestrictionResult::SafeIf(lp, base_vec)
}
}
} else {
self.extend(result, &cmt, LpInterior(opt_variant_id, interior))
}
}
Categorization::StaticItem => {

View file

@ -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::TyEnum(def, substs) => {
ty::TyStruct(def, substs) | ty::TyUnion(def, substs) | ty::TyEnum(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::TyEnum(def, _) => {
ty::TyStruct(def, _) | ty::TyUnion(def, _) | ty::TyEnum(def, _) => {
if def.has_dtor() {
self.tcx.sess.span_warn(
c.source_info.span,

View file

@ -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::TyEnum(def, _) if def.has_dtor() => {
ty::TyStruct(def, _) | ty::TyUnion(def, _) | ty::TyEnum(def, _) if def.has_dtor() => {
debug!("lvalue_contents_drop_state_cannot_differ lv: {:?} ty: {:?} Drop => false",
lv, ty);
true

View file

@ -477,8 +477,6 @@ impl<'a, 'tcx> LoanPath<'tcx> {
base.common(&base2).map(|x| {
let xd = x.depth();
if base.depth() == xd && base2.depth() == xd {
assert_eq!(base.ty, base2.ty);
assert_eq!(self.ty, other.ty);
LoanPath {
kind: LpExtend(Rc::new(x), a, LpInterior(opt_variant_id, id)),
ty: self.ty,
@ -495,7 +493,6 @@ impl<'a, 'tcx> LoanPath<'tcx> {
(_, &LpExtend(ref other, _, LpDeref(_))) => self.common(&other),
(&LpVar(id), &LpVar(id2)) => {
if id == id2 {
assert_eq!(self.ty, other.ty);
Some(LoanPath { kind: LpVar(id), ty: self.ty })
} else {
None
@ -503,7 +500,6 @@ impl<'a, 'tcx> LoanPath<'tcx> {
}
(&LpUpvar(id), &LpUpvar(id2)) => {
if id == id2 {
assert_eq!(self.ty, other.ty);
Some(LoanPath { kind: LpUpvar(id), ty: self.ty })
} else {
None
@ -1136,7 +1132,6 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
out.push(')');
}
LpExtend(ref lp_base, _, LpInterior(_, InteriorField(fname))) => {
self.append_autoderefd_loan_path_to_string(&lp_base, out);
match fname {

View file

@ -21,7 +21,8 @@ use rustc::middle::dataflow::DataFlowOperator;
use rustc::middle::dataflow::KillFrom;
use rustc::middle::expr_use_visitor as euv;
use rustc::middle::expr_use_visitor::MutateMode;
use rustc::ty::TyCtxt;
use rustc::middle::mem_categorization as mc;
use rustc::ty::{self, TyCtxt};
use rustc::util::nodemap::{FnvHashMap, NodeSet};
use std::cell::RefCell;
@ -364,6 +365,32 @@ impl<'a, 'tcx> MoveData<'tcx> {
lp: Rc<LoanPath<'tcx>>,
id: ast::NodeId,
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);
}
return;
}
}
self.add_move_helper(tcx, lp.clone(), id, kind);
}
fn add_move_helper(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>,
lp: Rc<LoanPath<'tcx>>,
id: ast::NodeId,
kind: MoveKind) {
debug!("add_move(lp={:?}, id={}, kind={:?})",
lp,
id,
@ -393,6 +420,34 @@ impl<'a, 'tcx> MoveData<'tcx> {
span: Span,
assignee_id: ast::NodeId,
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);
}
return;
}
}
self.add_assignment_helper(tcx, lp.clone(), assign_id, span, assignee_id, mode);
}
fn add_assignment_helper(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>,
lp: Rc<LoanPath<'tcx>>,
assign_id: ast::NodeId,
span: Span,
assignee_id: ast::NodeId,
mode: euv::MutateMode) {
debug!("add_assignment(lp={:?}, assign_id={}, assignee_id={}",
lp, assign_id, assignee_id);

View file

@ -566,7 +566,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::TyEnum(adt, _) | ty::TyStruct(adt, _) | ty::TyUnion(adt, _) => {
let v = ctor.variant_for_adt(adt);
match v.kind {
VariantKind::Struct => {
@ -792,7 +792,8 @@ fn pat_constructors(cx: &MatchCheckCtxt, p: &Pat,
PatKind::Struct(..) | PatKind::TupleStruct(..) | PatKind::Path(..) =>
match cx.tcx.expect_def(pat.id) {
Def::Variant(_, id) => vec![Variant(id)],
Def::Struct(..) | Def::TyAlias(..) | Def::AssociatedTy(..) => vec![Single],
Def::Struct(..) | Def::Union(..) |
Def::TyAlias(..) | Def::AssociatedTy(..) => vec![Single],
Def::Const(..) | Def::AssociatedConst(..) =>
span_bug!(pat.span, "const pattern should've been rewritten"),
def => span_bug!(pat.span, "pat_constructors: unexpected definition {:?}", def),
@ -836,7 +837,7 @@ pub fn constructor_arity(_cx: &MatchCheckCtxt, ctor: &Constructor, ty: Ty) -> us
_ => bug!()
},
ty::TyRef(..) => 1,
ty::TyEnum(adt, _) | ty::TyStruct(adt, _) => {
ty::TyEnum(adt, _) | ty::TyStruct(adt, _) | ty::TyUnion(adt, _) => {
ctor.variant_for_adt(adt).fields.len()
}
ty::TyArray(_, n) => n,

View file

@ -271,6 +271,10 @@ 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 {

View file

@ -220,6 +220,7 @@ impl<'a, 'gcx, 'tcx> Env<'a, 'gcx, 'tcx> {
hir::ItemEnum(..) |
hir::ItemStruct(..) |
hir::ItemUnion(..) |
hir::ItemTrait(..) |
hir::ItemImpl(..) |
hir::ItemDefaultImpl(..) => {

View file

@ -419,6 +419,7 @@ impl<'a, 'hash, 'tcx> StrictVersionHashVisitor<'a, 'hash, 'tcx> {
Def::AssociatedTy(..) |
Def::TyParam(..) |
Def::Struct(..) |
Def::Union(..) |
Def::Trait(..) |
Def::Method(..) |
Def::Const(..) |

View file

@ -111,7 +111,7 @@ impl LateLintPass for NonCamelCaseTypes {
}
match it.node {
hir::ItemTy(..) | hir::ItemStruct(..) => {
hir::ItemTy(..) | hir::ItemStruct(..) | hir::ItemUnion(..) => {
self.check_case(cx, "type", it.name, it.span)
}
hir::ItemTrait(..) => {

View file

@ -116,7 +116,8 @@ impl LateLintPass for BoxPointers {
hir::ItemFn(..) |
hir::ItemTy(..) |
hir::ItemEnum(..) |
hir::ItemStruct(..) =>
hir::ItemStruct(..) |
hir::ItemUnion(..) =>
self.check_heap_type(cx, it.span,
cx.tcx.node_id_to_type(it.id)),
_ => ()
@ -124,7 +125,8 @@ impl LateLintPass for BoxPointers {
// If it's a struct, we also have to check the fields' types
match it.node {
hir::ItemStruct(ref struct_def, _) => {
hir::ItemStruct(ref struct_def, _) |
hir::ItemUnion(ref struct_def, _) => {
for struct_field in struct_def.fields() {
self.check_heap_type(cx, struct_field.span,
cx.tcx.node_id_to_type(struct_field.id));
@ -348,6 +350,7 @@ impl LateLintPass for MissingDoc {
hir::ItemMod(..) => "a module",
hir::ItemEnum(..) => "an enum",
hir::ItemStruct(..) => "a struct",
hir::ItemUnion(..) => "a union",
hir::ItemTrait(_, _, _, ref items) => {
// Issue #11592, traits are always considered exported, even when private.
if it.vis == hir::Visibility::Inherited {
@ -467,6 +470,13 @@ impl LateLintPass for MissingCopyImplementations {
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)))
}
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)))
}
hir::ItemEnum(_, ref ast_generics) => {
if ast_generics.is_parameterized() {
return;
@ -523,7 +533,7 @@ impl LateLintPass for MissingDebugImplementations {
}
match item.node {
hir::ItemStruct(..) | hir::ItemEnum(..) => {},
hir::ItemStruct(..) | hir::ItemUnion(..) | hir::ItemEnum(..) => {},
_ => return,
}
@ -1154,3 +1164,36 @@ impl LateLintPass for UnstableFeatures {
}
}
}
/// Lint for unions that contain fields with possibly non-trivial destructors.
pub struct UnionsWithDropFields;
declare_lint! {
UNIONS_WITH_DROP_FIELDS,
Warn,
"use of unions that contain fields with possibly non-trivial drop code"
}
impl LintPass for UnionsWithDropFields {
fn get_lints(&self) -> LintArray {
lint_array!(UNIONS_WITH_DROP_FIELDS)
}
}
impl LateLintPass for UnionsWithDropFields {
fn check_item(&mut self, ctx: &LateContext, item: &hir::Item) {
if let hir::ItemUnion(ref vdata, _) = item.node {
let param_env = &ty::ParameterEnvironment::for_item(ctx.tcx, item.id);
for field in vdata.fields() {
let field_ty = ctx.tcx.node_id_to_type(field.id);
if ctx.tcx.type_needs_drop_given_env(field_ty, param_env) {
ctx.span_lint(UNIONS_WITH_DROP_FIELDS,
field.span,
"union contains a field with possibly non-trivial drop code, \
drop code of union fields is ignored when dropping the union");
return;
}
}
}
}
}

View file

@ -128,6 +128,7 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) {
InvalidNoMangleItems,
PluginAsLibrary,
MutableTransmutes,
UnionsWithDropFields,
);
add_builtin_with_new!(sess,

View file

@ -377,7 +377,8 @@ enum FfiResult {
FfiSafe,
FfiUnsafe(&'static str),
FfiBadStruct(DefId, &'static str),
FfiBadEnum(DefId, &'static str)
FfiBadUnion(DefId, &'static str),
FfiBadEnum(DefId, &'static str),
}
/// Check if this enum can be safely exported based on the
@ -452,12 +453,32 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
let r = self.check_type_for_ffi(cache, field_ty);
match r {
FfiSafe => {}
FfiBadStruct(..) | FfiBadEnum(..) => { return r; }
FfiBadStruct(..) | FfiBadUnion(..) | FfiBadEnum(..) => { return r; }
FfiUnsafe(s) => { return FfiBadStruct(def.did, s); }
}
}
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");
}
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
}
ty::TyEnum(def, substs) => {
if def.variants.is_empty() {
// Empty enums are okay... although sort of useless.
@ -507,7 +528,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
let r = self.check_type_for_ffi(cache, arg);
match r {
FfiSafe => {}
FfiBadStruct(..) | FfiBadEnum(..) => { return r; }
FfiBadStruct(..) | FfiBadUnion(..) | FfiBadEnum(..) => { return r; }
FfiUnsafe(s) => { return FfiBadEnum(def.did, s); }
}
}
@ -614,6 +635,13 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
&format!("found non-foreign-function-safe member in \
struct marked #[repr(C)]: {}", s));
}
FfiResult::FfiBadUnion(_, s) => {
// FIXME: This diagnostic is difficult to read, and doesn't
// point at the relevant field.
self.cx.span_lint(IMPROPER_CTYPES, sp,
&format!("found non-foreign-function-safe member in \
union marked #[repr(C)]: {}", s));
}
FfiResult::FfiBadEnum(_, s) => {
// FIXME: This diagnostic is difficult to read, and doesn't
// point at the relevant variant.

View file

@ -137,6 +137,7 @@ impl LateLintPass for UnusedResults {
ty::TyNever => return,
ty::TyBool => return,
ty::TyStruct(def, _) |
ty::TyUnion(def, _) |
ty::TyEnum(def, _) => {
let attrs = cx.tcx.get_attrs(def.did);
check_must_use(cx, &attrs[..], s.span)

View file

@ -416,6 +416,7 @@ impl tr for Def {
Def::Upvar(did1, nid1, index, nid2)
}
Def::Struct(did) => Def::Struct(did.tr(dcx)),
Def::Union(did) => Def::Union(did.tr(dcx)),
Def::Label(nid) => Def::Label(dcx.tr_id(nid)),
Def::Err => Def::Err,
}

View file

@ -133,6 +133,7 @@ enum Family {
DefaultImpl, // d
Trait, // I
Struct(VariantKind), // S, s, u
Union, // U
PublicField, // g
InheritedField, // N
Constant, // C
@ -160,6 +161,7 @@ fn item_family(item: rbml::Doc) -> Family {
'S' => Struct(VariantKind::Struct),
's' => Struct(VariantKind::Tuple),
'u' => Struct(VariantKind::Unit),
'U' => Union,
'g' => PublicField,
'N' => InheritedField,
c => bug!("unexpected family char: {}", c)
@ -289,7 +291,7 @@ fn maybe_item_name(item: rbml::Doc) -> Option<ast::Name> {
fn family_to_variant_kind<'tcx>(family: Family) -> Option<ty::VariantKind> {
match family {
Struct(VariantKind::Struct) | Variant(VariantKind::Struct) =>
Struct(VariantKind::Struct) | Variant(VariantKind::Struct) | Union =>
Some(ty::VariantKind::Struct),
Struct(VariantKind::Tuple) | Variant(VariantKind::Tuple) =>
Some(ty::VariantKind::Tuple),
@ -317,6 +319,7 @@ fn item_to_def_like(cdata: Cmd, item: rbml::Doc, did: DefId) -> DefLike {
ImmStatic => DlDef(Def::Static(did, false)),
MutStatic => DlDef(Def::Static(did, true)),
Struct(..) => DlDef(Def::Struct(did)),
Union => DlDef(Def::Union(did)),
Fn => DlDef(Def::Fn(did)),
Method | StaticMethod => {
DlDef(Def::Method(did))
@ -461,6 +464,10 @@ pub fn get_adt_def<'a, 'tcx>(cdata: Cmd,
(ty::AdtKind::Struct,
vec![get_struct_variant(cdata, doc, ctor_did.unwrap_or(did))])
}
Union => {
(ty::AdtKind::Union,
vec![get_struct_variant(cdata, doc, did)])
}
_ => bug!("get_adt_def called on a non-ADT {:?} - {:?}",
item_family(doc), did)
};

View file

@ -1029,6 +1029,33 @@ impl<'a, 'tcx, 'encoder> ItemContentBuilder<'a, 'tcx, 'encoder> {
def_to_u64(ctor_did));
}
}
hir::ItemUnion(..) => {
let def = ecx.tcx.lookup_adt_def(def_id);
let variant = def.struct_variant();
encode_def_id_and_key(ecx, self.rbml_w, def_id);
encode_family(self.rbml_w, 'U');
self.encode_bounds_and_type_for_item(item.id);
encode_item_variances(self.rbml_w, ecx, item.id);
encode_name(self.rbml_w, item.name);
encode_attributes(self.rbml_w, &item.attrs);
encode_stability(self.rbml_w, stab);
encode_deprecation(self.rbml_w, depr);
self.encode_visibility(vis);
self.encode_repr_attrs(&item.attrs);
/* Encode def_ids for each field and method
for methods, write all the stuff get_trait_method
needs to know*/
self.encode_struct_fields(variant);
encode_inlined_item(ecx, self.rbml_w, InlinedItemRef::Item(def_id, item));
self.encode_mir(item.id);
// Encode inherent implementations for self union.
encode_inherent_implementations(ecx, self.rbml_w, def_id);
}
hir::ItemDefaultImpl(unsafety, _) => {
encode_def_id_and_key(ecx, self.rbml_w, def_id);
encode_family(self.rbml_w, 'd');
@ -1179,6 +1206,9 @@ impl<'a, 'tcx, 'encoder> IndexBuilder<'a, 'tcx, 'encoder> {
hir::ItemStruct(ref struct_def, _) => {
self.encode_addl_struct_info(def_id, struct_def.id(), item);
}
hir::ItemUnion(..) => {
self.encode_addl_union_info(def_id);
}
hir::ItemImpl(_, _, _, _, _, ref ast_items) => {
self.encode_addl_impl_info(def_id, item.id, ast_items);
}
@ -1214,6 +1244,10 @@ impl<'a, 'tcx, 'encoder> IndexBuilder<'a, 'tcx, 'encoder> {
}
}
fn encode_addl_union_info(&mut self, def_id: DefId) {
self.encode_fields(def_id);
}
fn encode_addl_impl_info(&mut self,
def_id: DefId,
impl_id: ast::NodeId,

View file

@ -472,6 +472,14 @@ impl<'a,'tcx> TyDecoder<'a,'tcx> {
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);
}
'k' => {
assert_eq!(self.next(), '[');
let did = self.parse_def();

View file

@ -170,6 +170,11 @@ pub fn enc_ty<'a, 'tcx>(w: &mut Cursor<Vec<u8>>, cx: &ctxt<'a, 'tcx>, t: Ty<'tcx
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);

View file

@ -181,6 +181,9 @@ 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 active_field_index = if is_union { Some(fields[0].name.index()) } else { None };
// first process the set of fields that were provided
// (evaluating them in order given by user)
let fields_map: FnvHashMap<_, _> =
@ -204,11 +207,11 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
})
.collect()
} else {
field_names.iter().map(|n| fields_map[n].clone()).collect()
field_names.iter().filter_map(|n| fields_map.get(n).cloned()).collect()
};
block.and(Rvalue::Aggregate(AggregateKind::Adt(adt_def, variant_index, substs),
fields))
let adt = AggregateKind::Adt(adt_def, variant_index, substs, active_field_index);
block.and(Rvalue::Aggregate(adt, fields))
}
ExprKind::Assign { .. } |
ExprKind::AssignOp { .. } => {

View file

@ -459,7 +459,7 @@ 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::TyStruct(adt, substs) | ty::TyUnion(adt, substs) => {
let field_refs = field_refs(&adt.variants[0], fields);
ExprKind::Adt {
adt_def: adt,
@ -579,7 +579,7 @@ 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::TyStruct(adt_def, _) | ty::TyUnion(adt_def, _) =>
adt_def.variants[0].index_of_field_named(name.node),
ref ty =>
span_bug!(

View file

@ -217,7 +217,9 @@ 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::TyEnum(adt_def, _) => adt_def,
ty::TyStruct(adt_def, _) |
ty::TyUnion(adt_def, _) |
ty::TyEnum(adt_def, _) => adt_def,
_ => {
span_bug!(
pat.span,
@ -313,7 +315,8 @@ impl<'patcx, 'cx, 'gcx, 'tcx> PatCx<'patcx, 'cx, 'gcx, 'tcx> {
}
}
Def::Struct(..) | Def::TyAlias(..) | Def::AssociatedTy(..) => {
Def::Struct(..) | Def::Union(..) |
Def::TyAlias(..) | Def::AssociatedTy(..) => {
PatternKind::Leaf { subpatterns: subpatterns }
}

View file

@ -57,7 +57,7 @@ impl<'tcx> MirPass<'tcx> for Deaggregator {
_ => span_bug!(src_info.span, "expected aggregate, not {:?}", rhs),
};
let (adt_def, variant, substs) = match agg_kind {
&AggregateKind::Adt(adt_def, variant, substs) => (adt_def, variant, substs),
&AggregateKind::Adt(adt_def, variant, substs, None) => (adt_def, variant, substs),
_ => span_bug!(src_info.span, "expected struct, not {:?}", rhs),
};
let n = bb.statements.len();
@ -120,7 +120,7 @@ fn get_aggregate_statement_index<'a, 'tcx, 'b>(start: usize,
_ => continue,
};
let (adt_def, variant) = match kind {
&AggregateKind::Adt(adt_def, variant, _) => (adt_def, variant),
&AggregateKind::Adt(adt_def, variant, _, None) => (adt_def, variant),
_ => continue,
};
if operands.len() == 0 {

View file

@ -705,7 +705,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
}
Rvalue::Aggregate(ref kind, _) => {
if let AggregateKind::Adt(def, _, _) = *kind {
if let AggregateKind::Adt(def, _, _, _) = *kind {
if def.has_dtor() {
self.add(Qualif::NEEDS_DROP);
self.deny_drop();

View file

@ -281,7 +281,9 @@ 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::TyEnum(adt_def, substs)
ty::TyStruct(adt_def, substs) |
ty::TyUnion(adt_def, substs) |
ty::TyEnum(adt_def, substs)
if adt_def.is_univariant() => {
(&adt_def.variants[0], substs)
}

View file

@ -196,6 +196,16 @@ impl<'a> Visitor for AstValidator<'a> {
// Ensure that `path` attributes on modules are recorded as used (c.f. #35584).
attr::first_attr_value_str_by_name(&item.attrs, "path");
}
ItemKind::Union(ref vdata, _) => {
if !vdata.is_struct() {
self.err_handler().span_err(item.span,
"tuple and unit unions are not permitted");
}
if vdata.fields().len() == 0 {
self.err_handler().span_err(item.span,
"unions cannot have zero fields");
}
}
_ => {}
}

View file

@ -440,6 +440,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for CheckCrateVisitor<'a, 'tcx> {
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() => {
v.add_qualif(ConstQualif::NEEDS_DROP);
}

View file

@ -174,7 +174,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for EmbargoVisitor<'a, 'tcx> {
self.update(trait_item.id, item_level);
}
}
hir::ItemStruct(ref def, _) => {
hir::ItemStruct(ref def, _) | hir::ItemUnion(ref def, _) => {
if !def.is_struct() {
self.update(def.id(), item_level);
}
@ -234,7 +234,8 @@ impl<'a, 'tcx, 'v> Visitor<'v> for EmbargoVisitor<'a, 'tcx> {
}
}
// Visit everything except for private fields
hir::ItemStruct(ref struct_def, ref generics) => {
hir::ItemStruct(ref struct_def, ref generics) |
hir::ItemUnion(ref struct_def, ref generics) => {
if item_level.is_some() {
self.reach().visit_generics(generics);
for field in struct_def.fields() {
@ -320,8 +321,8 @@ impl<'b, 'a, 'tcx: 'a, 'v> Visitor<'v> for ReachEverythingInTheInterfaceVisitor<
if let hir::TyPath(_, ref path) = ty.node {
let def = self.ev.tcx.expect_def(ty.id);
match def {
Def::Struct(def_id) | Def::Enum(def_id) | Def::TyAlias(def_id) |
Def::Trait(def_id) | Def::AssociatedTy(def_id, _) => {
Def::Struct(def_id) | Def::Union(def_id) | Def::Enum(def_id) |
Def::TyAlias(def_id) | Def::Trait(def_id) | Def::AssociatedTy(def_id, _) => {
if let Some(node_id) = self.ev.tcx.map.as_local_node_id(def_id) {
let item = self.ev.tcx.map.expect_item(node_id);
if let Def::TyAlias(..) = def {
@ -382,10 +383,11 @@ 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::Struct &&
if def.adt_kind() != ty::AdtKind::Enum &&
!field.vis.is_accessible_from(self.curitem, &self.tcx.map) {
struct_span_err!(self.tcx.sess, span, E0451, "field `{}` of struct `{}` is private",
field.name, self.tcx.item_path_str(def.did))
let kind_descr = if def.adt_kind() == ty::AdtKind::Union { "union" } else { "struct" };
struct_span_err!(self.tcx.sess, span, E0451, "field `{}` of {} `{}` is private",
field.name, kind_descr, self.tcx.item_path_str(def.did))
.span_label(span, &format!("field `{}` is private", field.name))
.emit();
}
@ -427,19 +429,24 @@ impl<'a, 'tcx, 'v> Visitor<'v> for PrivacyVisitor<'a, 'tcx> {
let method = self.tcx.tables.borrow().method_map[&method_call];
self.check_method(expr.span, method.def_id);
}
hir::ExprStruct(_, ref fields, _) => {
hir::ExprStruct(_, ref expr_fields, _) => {
let adt = self.tcx.expr_ty(expr).ty_adt_def().unwrap();
let variant = adt.variant_of_def(self.tcx.expect_def(expr.id));
// RFC 736: ensure all unmentioned fields are visible.
// Rather than computing the set of unmentioned fields
// (i.e. `all_fields - fields`), just check them all.
for field in variant.fields.iter() {
let span = if let Some(f) = fields.iter().find(|f| f.name.node == field.name) {
f.span
} else {
expr.span
};
self.check_field(span, adt, field);
// (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 {
for expr_field in expr_fields {
self.check_field(expr.span, adt, variant.field_named(expr_field.name.node));
}
} else {
for field in &variant.fields {
let expr_field = expr_fields.iter().find(|f| f.name.node == field.name);
let span = if let Some(f) = expr_field { f.span } else { expr.span };
self.check_field(span, adt, field);
}
}
}
hir::ExprPath(..) => {
@ -942,8 +949,8 @@ impl<'a, 'tcx: 'a, 'v> Visitor<'v> for SearchInterfaceForPrivateItemsVisitor<'a,
// free type aliases, but this isn't done yet.
return
}
Def::Struct(def_id) | Def::Enum(def_id) | Def::TyAlias(def_id) |
Def::Trait(def_id) | Def::AssociatedTy(def_id, _) => {
Def::Struct(def_id) | Def::Union(def_id) | Def::Enum(def_id) |
Def::TyAlias(def_id) | Def::Trait(def_id) | Def::AssociatedTy(def_id, _) => {
// Non-local means public (private items can't leave their crate, modulo bugs)
if let Some(node_id) = self.tcx.map.as_local_node_id(def_id) {
let item = self.tcx.map.expect_item(node_id);
@ -1067,8 +1074,9 @@ impl<'a, 'tcx, 'v> Visitor<'v> for PrivateItemsInPublicInterfacesVisitor<'a, 'tc
check.visit_foreign_item(foreign_item);
}
}
// Subitems of structs have their own publicity
hir::ItemStruct(ref struct_def, ref generics) => {
// Subitems of structs and unions have their own publicity
hir::ItemStruct(ref struct_def, ref generics) |
hir::ItemUnion(ref struct_def, ref generics) => {
check.required_visibility = item_visibility;
check.visit_generics(generics);

View file

@ -278,7 +278,19 @@ impl<'b> Resolver<'b> {
self.structs.insert(item_def_id, field_names);
}
ItemKind::Union(..) => panic!("`union` is not yet implemented"),
ItemKind::Union(ref vdata, _) => {
let def = Def::Union(self.definitions.local_def_id(item.id));
self.define(parent, name, TypeNS, (def, sp, vis));
// Record the def ID and fields of this union.
let field_names = vdata.fields().iter().enumerate().map(|(index, field)| {
self.resolve_visibility(&field.vis);
field.ident.map(|ident| ident.name)
.unwrap_or_else(|| token::intern(&index.to_string()))
}).collect();
let item_def_id = self.definitions.local_def_id(item.id);
self.structs.insert(item_def_id, field_names);
}
ItemKind::DefaultImpl(_, _) | ItemKind::Impl(..) => {}
@ -461,6 +473,13 @@ impl<'b> Resolver<'b> {
let fields = self.session.cstore.struct_field_names(def_id);
self.structs.insert(def_id, fields);
}
Def::Union(def_id) => {
let _ = self.try_define(parent, name, TypeNS, (def, DUMMY_SP, vis));
// Record the def ID and fields of this union.
let fields = self.session.cstore.struct_field_names(def_id);
self.structs.insert(def_id, fields);
}
Def::Struct(..) => {}
Def::Local(..) |
Def::PrimTy(..) |

View file

@ -2187,6 +2187,7 @@ impl<'a> Resolver<'a> {
Def::Trait(_) |
Def::Enum(_) |
Def::Struct(_) |
Def::Union(_) |
Def::TyAlias(_) => true,
_ => false,
},
@ -2389,7 +2390,7 @@ impl<'a> Resolver<'a> {
PatKind::Struct(ref path, _, _) => {
self.resolve_pattern_path(pat.id, None, path, TypeNS, |def| {
match def {
Def::Struct(..) | Def::Variant(..) |
Def::Struct(..) | Def::Union(..) | Def::Variant(..) |
Def::TyAlias(..) | Def::AssociatedTy(..) => true,
_ => false,
}
@ -2735,7 +2736,7 @@ impl<'a> Resolver<'a> {
// Look for a field with the same name in the current self_type.
if let Some(resolution) = self.def_map.get(&node_id) {
match resolution.base_def {
Def::Enum(did) | Def::TyAlias(did) |
Def::Enum(did) | Def::TyAlias(did) | Def::Union(did) |
Def::Struct(did) | Def::Variant(_, did) if resolution.depth == 0 => {
if let Some(fields) = self.structs.get(&did) {
if fields.iter().any(|&field_name| name == field_name) {

View file

@ -300,6 +300,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> {
}.lower(self.tcx));
}
Def::Struct(..) |
Def::Union(..) |
Def::Enum(..) |
Def::TyAlias(..) |
Def::AssociatedTy(..) |

View file

@ -404,7 +404,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
}
};
match self.tcx.expr_ty_adjusted(&hir_node).sty {
ty::TyStruct(def, _) => {
ty::TyStruct(def, _) | ty::TyUnion(def, _) => {
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);
@ -423,7 +423,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
}
ast::ExprKind::Struct(ref path, _, _) => {
match self.tcx.expr_ty_adjusted(&hir_node).sty {
ty::TyStruct(def, _) => {
ty::TyStruct(def, _) | ty::TyUnion(def, _) => {
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 {
@ -487,6 +487,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
}))
}
Def::Struct(def_id) |
Def::Union(def_id) |
Def::Enum(def_id) |
Def::TyAlias(def_id) |
Def::Trait(def_id) |

View file

@ -79,6 +79,8 @@ pub enum Repr<'tcx> {
CEnum(IntType, Disr, Disr), // discriminant range (signedness based on the IntType)
/// Single-case variants, and structs/tuples/records.
Univariant(Struct<'tcx>),
/// Untagged unions.
UntaggedUnion(Union<'tcx>),
/// General-case enums: for each case there is a struct, and they
/// all start with a field for the discriminant.
General(IntType, Vec<Struct<'tcx>>),
@ -121,6 +123,15 @@ pub struct Struct<'tcx> {
pub fields: Vec<Ty<'tcx>>,
}
/// For untagged unions.
#[derive(Eq, PartialEq, Debug)]
pub struct Union<'tcx> {
pub min_size: u64,
pub align: u32,
pub packed: bool,
pub fields: Vec<Ty<'tcx>>,
}
#[derive(Copy, Clone)]
pub struct MaybeSizedValue {
pub value: ValueRef,
@ -176,6 +187,13 @@ fn represent_type_uncached<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
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::<Vec<_>>();
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))
}
@ -479,6 +497,31 @@ fn mk_struct<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
}
}
fn mk_union<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
tys: &[Ty<'tcx>], packed: bool,
_scapegoat: Ty<'tcx>)
-> Union<'tcx> {
let mut min_size = 0;
let mut align = 0;
for llty in tys.iter().map(|&ty| type_of::sizing_type_of(cx, ty)) {
let field_size = machine::llsize_of_alloc(cx, llty);
if min_size < field_size {
min_size = field_size;
}
let field_align = machine::llalign_of_min(cx, llty);
if align < field_align {
align = field_align;
}
}
Union {
min_size: min_size,
align: if packed { 1 } else { align },
packed: packed,
fields: tys.to_vec(),
}
}
#[derive(Debug)]
struct IntBounds {
slo: i64,
@ -643,7 +686,7 @@ pub fn incomplete_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
pub fn finish_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
r: &Repr<'tcx>, llty: &mut Type) {
match *r {
CEnum(..) | General(..) | RawNullablePointer { .. } => { }
CEnum(..) | General(..) | UntaggedUnion(..) | RawNullablePointer { .. } => { }
Univariant(ref st) | StructWrappedNullablePointer { nonnull: ref st, .. } =>
llty.set_struct_body(&struct_llfields(cx, st, false, false),
st.packed)
@ -687,6 +730,34 @@ fn generic_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
}
}
}
UntaggedUnion(ref un) => {
// Use alignment-sized ints to fill all the union storage.
let (size, align) = (roundup(un.min_size, un.align), un.align);
let align_s = align as u64;
assert_eq!(size % align_s, 0); // Ensure division in align_units comes out evenly
let align_units = size / align_s;
let fill_ty = match align_s {
1 => Type::array(&Type::i8(cx), align_units),
2 => Type::array(&Type::i16(cx), align_units),
4 => Type::array(&Type::i32(cx), align_units),
8 if machine::llalign_of_min(cx, Type::i64(cx)) == 8 =>
Type::array(&Type::i64(cx), align_units),
a if a.count_ones() == 1 => Type::array(&Type::vector(&Type::i32(cx), a / 4),
align_units),
_ => bug!("unsupported union alignment: {}", align)
};
match name {
None => {
Type::struct_(cx, &[fill_ty], un.packed)
}
Some(name) => {
let mut llty = Type::named_struct(cx, name);
llty.set_struct_body(&[fill_ty], un.packed);
llty
}
}
}
General(ity, ref sts) => {
// We need a representation that has:
// * The alignment of the most-aligned field
@ -759,7 +830,7 @@ pub fn trans_switch<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
RawNullablePointer { .. } | StructWrappedNullablePointer { .. } => {
(BranchKind::Switch, Some(trans_get_discr(bcx, r, scrutinee, None, range_assert)))
}
Univariant(..) => {
Univariant(..) | UntaggedUnion(..) => {
// N.B.: Univariant means <= 1 enum variants (*not* == 1 variants).
(BranchKind::Single, None)
}
@ -770,7 +841,7 @@ pub fn is_discr_signed<'tcx>(r: &Repr<'tcx>) -> bool {
match *r {
CEnum(ity, _, _) => ity.is_signed(),
General(ity, _) => ity.is_signed(),
Univariant(..) => false,
Univariant(..) | UntaggedUnion(..) => false,
RawNullablePointer { .. } => false,
StructWrappedNullablePointer { .. } => false,
}
@ -791,7 +862,7 @@ pub fn trans_get_discr<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, r: &Repr<'tcx>,
load_discr(bcx, ity, ptr, Disr(0), Disr(cases.len() as u64 - 1),
range_assert)
}
Univariant(..) => C_u8(bcx.ccx(), 0),
Univariant(..) | UntaggedUnion(..) => C_u8(bcx.ccx(), 0),
RawNullablePointer { nndiscr, nnty, .. } => {
let cmp = if nndiscr == Disr(0) { IntEQ } else { IntNE };
let llptrty = type_of::sizing_type_of(bcx.ccx(), nnty);
@ -853,8 +924,8 @@ pub fn trans_case<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, r: &Repr, discr: Disr)
General(ity, _) => {
C_integral(ll_inttype(bcx.ccx(), ity), discr.0, true)
}
Univariant(..) => {
bug!("no cases for univariants or structs")
Univariant(..) | UntaggedUnion(..) => {
bug!("no cases for univariants, structs or unions")
}
RawNullablePointer { .. } |
StructWrappedNullablePointer { .. } => {
@ -881,6 +952,9 @@ pub fn trans_set_discr<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, r: &Repr<'tcx>,
Univariant(_) => {
assert_eq!(discr, Disr(0));
}
UntaggedUnion(..) => {
assert_eq!(discr, Disr(0));
}
RawNullablePointer { nndiscr, nnty, ..} => {
if discr != nndiscr {
let llptrty = type_of::sizing_type_of(bcx.ccx(), nnty);
@ -936,6 +1010,11 @@ pub fn trans_field_ptr_builder<'blk, 'tcx>(bcx: &BlockAndBuilder<'blk, 'tcx>,
General(_, ref cases) => {
struct_field_ptr(bcx, &cases[discr.0 as usize], val, ix + 1, true)
}
UntaggedUnion(ref un) => {
let ty = type_of::in_memory_type_of(bcx.ccx(), un.fields[ix]);
if bcx.is_unreachable() { return C_undef(ty.ptr_to()); }
bcx.pointercast(val.value, ty.ptr_to())
}
RawNullablePointer { nndiscr, ref nullfields, .. } |
StructWrappedNullablePointer { nndiscr, ref nullfields, .. } if discr != nndiscr => {
// The unit-like case might have a nonzero number of unit-like fields.
@ -1097,6 +1176,11 @@ pub fn trans_const<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, r: &Repr<'tcx>, discr
contents.extend_from_slice(&[padding(ccx, max_sz - case.size)]);
C_struct(ccx, &contents[..], false)
}
UntaggedUnion(ref un) => {
assert_eq!(discr, Disr(0));
let contents = build_const_union(ccx, un, vals[0]);
C_struct(ccx, &contents, un.packed)
}
Univariant(ref st) => {
assert_eq!(discr, Disr(0));
let contents = build_const_struct(ccx, st, vals);
@ -1190,6 +1274,21 @@ fn build_const_struct<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
cfields
}
fn build_const_union<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
un: &Union<'tcx>,
field_val: ValueRef)
-> Vec<ValueRef> {
let mut cfields = vec![field_val];
let offset = machine::llsize_of_alloc(ccx, val_ty(field_val));
let size = roundup(un.min_size, un.align);
if offset != size {
cfields.push(padding(ccx, size - offset));
}
cfields
}
fn padding(ccx: &CrateContext, size: u64) -> ValueRef {
C_undef(Type::array(&Type::i8(ccx), size))
}
@ -1208,6 +1307,7 @@ pub fn const_get_field(r: &Repr, val: ValueRef, _discr: Disr,
match *r {
CEnum(..) => bug!("element access in C-like enum const"),
Univariant(..) => const_struct_field(val, ix),
UntaggedUnion(..) => const_struct_field(val, 0),
General(..) => const_struct_field(val, ix + 1),
RawNullablePointer { .. } => {
assert_eq!(ix, 0);

View file

@ -744,6 +744,7 @@ fn find_drop_glue_neighbors<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>,
// monomorphized Drop::drop() implementation.
let destructor_did = match ty.sty {
ty::TyStruct(def, _) |
ty::TyUnion(def, _) |
ty::TyEnum(def, _) => def.destructor(),
_ => None
};
@ -798,6 +799,7 @@ fn find_drop_glue_neighbors<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>,
/* nothing to do */
}
ty::TyStruct(ref adt_def, substs) |
ty::TyUnion(ref adt_def, substs) |
ty::TyEnum(ref adt_def, substs) => {
for field in adt_def.all_fields() {
let field_type = monomorphize::apply_param_substs(scx,
@ -1121,8 +1123,9 @@ impl<'b, 'a, 'v> hir_visit::Visitor<'v> for RootCollector<'b, 'a, 'v> {
}
}
hir::ItemEnum(_, ref generics) |
hir::ItemStruct(_, ref generics) => {
hir::ItemEnum(_, ref generics) |
hir::ItemStruct(_, ref generics) |
hir::ItemUnion(_, ref generics) => {
if !generics.is_parameterized() {
let ty = {
let tables = self.scx.tcx().tables.borrow();

View file

@ -88,8 +88,8 @@ pub fn type_is_immediate<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ty: Ty<'tcx>) -
return false;
}
match ty.sty {
ty::TyStruct(..) | ty::TyEnum(..) | ty::TyTuple(..) | ty::TyArray(_, _) |
ty::TyClosure(..) => {
ty::TyStruct(..) | ty::TyUnion(..) | ty::TyEnum(..) |
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())
}
@ -205,7 +205,7 @@ impl<'a, 'tcx> VariantInfo<'tcx> {
-> Self
{
match ty.sty {
ty::TyStruct(adt, substs) | ty::TyEnum(adt, substs) => {
ty::TyStruct(adt, substs) | ty::TyUnion(adt, substs) | ty::TyEnum(adt, substs) => {
let variant = match opt_def {
None => adt.struct_variant(),
Some(def) => adt.variant_of_def(def)

View file

@ -184,6 +184,10 @@ impl<'tcx> TypeMap<'tcx> {
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);
},
@ -781,6 +785,12 @@ pub fn type_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
unique_type_id,
usage_site_span).finalize(cx)
}
ty::TyUnion(..) => {
prepare_union_metadata(cx,
t,
unique_type_id,
usage_site_span).finalize(cx)
}
ty::TyTuple(ref elements) => {
prepare_tuple_metadata(cx,
t,
@ -1031,6 +1041,7 @@ enum MemberDescriptionFactory<'tcx> {
StructMDF(StructMemberDescriptionFactory<'tcx>),
TupleMDF(TupleMemberDescriptionFactory<'tcx>),
EnumMDF(EnumMemberDescriptionFactory<'tcx>),
UnionMDF(UnionMemberDescriptionFactory<'tcx>),
VariantMDF(VariantMemberDescriptionFactory<'tcx>)
}
@ -1047,6 +1058,9 @@ impl<'tcx> MemberDescriptionFactory<'tcx> {
EnumMDF(ref this) => {
this.create_member_descriptions(cx)
}
UnionMDF(ref this) => {
this.create_member_descriptions(cx)
}
VariantMDF(ref this) => {
this.create_member_descriptions(cx)
}
@ -1147,7 +1161,6 @@ fn prepare_struct_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
)
}
//=-----------------------------------------------------------------------------
// Tuples
//=-----------------------------------------------------------------------------
@ -1202,6 +1215,66 @@ fn prepare_tuple_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
)
}
//=-----------------------------------------------------------------------------
// Unions
//=-----------------------------------------------------------------------------
struct UnionMemberDescriptionFactory<'tcx> {
variant: ty::VariantDef<'tcx>,
substs: &'tcx Substs<'tcx>,
span: Span,
}
impl<'tcx> UnionMemberDescriptionFactory<'tcx> {
fn create_member_descriptions<'a>(&self, cx: &CrateContext<'a, 'tcx>)
-> Vec<MemberDescription> {
self.variant.fields.iter().map(|field| {
let fty = monomorphize::field_ty(cx.tcx(), self.substs, field);
MemberDescription {
name: field.name.to_string(),
llvm_type: type_of::type_of(cx, fty),
type_metadata: type_metadata(cx, fty, self.span),
offset: FixedMemberOffset { bytes: 0 },
flags: FLAGS_NONE,
}
}).collect()
}
}
fn prepare_union_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
union_type: Ty<'tcx>,
unique_type_id: UniqueTypeId,
span: Span)
-> RecursiveTypeDescription<'tcx> {
let union_name = compute_debuginfo_type_name(cx, union_type, false);
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")
};
let (containing_scope, _) = get_namespace_and_span_for_item(cx, union_def_id);
let union_metadata_stub = create_union_stub(cx,
union_llvm_type,
&union_name,
unique_type_id,
containing_scope);
create_and_register_recursive_type_forward_declaration(
cx,
union_type,
unique_type_id,
union_metadata_stub,
union_llvm_type,
UnionMDF(UnionMemberDescriptionFactory {
variant: variant,
substs: substs,
span: span,
})
)
}
//=-----------------------------------------------------------------------------
// Enums
@ -1411,7 +1484,9 @@ impl<'tcx> EnumMemberDescriptionFactory<'tcx> {
}
]
},
adt::CEnum(..) => span_bug!(self.span, "This should be unreachable.")
adt::CEnum(..) | adt::UntaggedUnion(..) => {
span_bug!(self.span, "This should be unreachable.")
}
}
}
}
@ -1609,7 +1684,7 @@ fn prepare_enum_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
},
adt::RawNullablePointer { .. } |
adt::StructWrappedNullablePointer { .. } |
adt::Univariant(..) => None,
adt::Univariant(..) | adt::UntaggedUnion(..) => None,
adt::General(inttype, _) => Some(discriminant_type_metadata(inttype)),
};
@ -1789,6 +1864,42 @@ fn create_struct_stub(cx: &CrateContext,
return metadata_stub;
}
fn create_union_stub(cx: &CrateContext,
union_llvm_type: Type,
union_type_name: &str,
unique_type_id: UniqueTypeId,
containing_scope: DIScope)
-> DICompositeType {
let (union_size, union_align) = size_and_align_of(cx, union_llvm_type);
let unique_type_id_str = debug_context(cx).type_map
.borrow()
.get_unique_type_id_as_string(unique_type_id);
let name = CString::new(union_type_name).unwrap();
let unique_type_id = CString::new(unique_type_id_str.as_bytes()).unwrap();
let metadata_stub = unsafe {
// LLVMRustDIBuilderCreateUnionType() wants an empty array. A null
// pointer will lead to hard to trace and debug LLVM assertions
// later on in llvm/lib/IR/Value.cpp.
let empty_array = create_DIArray(DIB(cx), &[]);
llvm::LLVMRustDIBuilderCreateUnionType(
DIB(cx),
containing_scope,
name.as_ptr(),
unknown_file_metadata(cx),
UNKNOWN_LINE_NUMBER,
bytes_to_bits(union_size),
bytes_to_bits(union_align),
0, // Flags
empty_array,
0, // RuntimeLang
unique_type_id.as_ptr())
};
return metadata_stub;
}
/// Creates debug information for the given global variable.
///
/// Adds the created metadata nodes directly to the crate's IR.

View file

@ -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::TyEnum(..) => {
ty::TyStruct(..) | ty::TyUnion(..) | ty::TyEnum(..) => {
Some(type_metadata(cx, impl_self_ty, syntax_pos::DUMMY_SP))
}
_ => None

View file

@ -45,6 +45,7 @@ pub fn push_debuginfo_type_name<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
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) => {
push_item_name(cx, def.did, qualified, output);
push_type_params(cx, substs, output);

View file

@ -265,12 +265,13 @@ pub fn implement_drop_glue<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
fcx.finish(bcx, DebugLoc::None);
}
fn trans_struct_drop<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
fn trans_custom_dtor<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
t: Ty<'tcx>,
v0: ValueRef)
v0: ValueRef,
shallow_drop: bool)
-> Block<'blk, 'tcx>
{
debug!("trans_struct_drop t: {}", t);
debug!("trans_custom_dtor t: {}", t);
let tcx = bcx.tcx();
let mut bcx = bcx;
@ -286,7 +287,9 @@ fn trans_struct_drop<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
// Issue #23611: schedule cleanup of contents, re-inspecting the
// discriminant (if any) in case of variant swap in drop code.
bcx.fcx.schedule_drop_adt_contents(contents_scope, v0, t);
if !shallow_drop {
bcx.fcx.schedule_drop_adt_contents(contents_scope, v0, t);
}
let (sized_args, unsized_args);
let args: &[ValueRef] = if type_is_sized(tcx, t) {
@ -486,7 +489,14 @@ fn make_drop_glue<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, v0: ValueRef, g: DropGlueK
}
ty::TyStruct(def, _) | ty::TyEnum(def, _)
if def.dtor_kind().is_present() && !skip_dtor => {
trans_struct_drop(bcx, t, v0)
trans_custom_dtor(bcx, t, v0, false)
}
ty::TyUnion(def, _) => {
if def.dtor_kind().is_present() && !skip_dtor {
trans_custom_dtor(bcx, t, v0, true)
} else {
bcx
}
}
_ => {
if bcx.fcx.type_needs_drop(t) {

View file

@ -547,7 +547,7 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> {
self.monomorphize(&substs));
}
let val = if let mir::AggregateKind::Adt(adt_def, index, _) = *kind {
let val = if let mir::AggregateKind::Adt(adt_def, index, _, _) = *kind {
let repr = adt::represent_type(self.ccx, dest_ty);
let disr = Disr::from(adt_def.variants[index].disr_val);
adt::trans_const(self.ccx, &repr, disr, &fields)

View file

@ -110,9 +110,9 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
mir::Rvalue::Aggregate(ref kind, ref operands) => {
match *kind {
mir::AggregateKind::Adt(adt_def, index, _) => {
mir::AggregateKind::Adt(adt_def, variant_index, _, active_field_index) => {
let repr = adt::represent_type(bcx.ccx(), dest.ty.to_ty(bcx.tcx()));
let disr = Disr::from(adt_def.variants[index].disr_val);
let disr = Disr::from(adt_def.variants[variant_index].disr_val);
bcx.with_block(|bcx| {
adt::trans_set_discr(bcx, &repr, dest.llval, Disr::from(disr));
});
@ -121,8 +121,9 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
// Do not generate stores and GEPis for zero-sized fields.
if !common::type_is_zero_size(bcx.ccx(), op.ty) {
let val = adt::MaybeSizedValue::sized(dest.llval);
let lldest_i = adt::trans_field_ptr_builder(&bcx, &repr,
val, disr, i);
let field_index = active_field_index.unwrap_or(i);
let lldest_i = adt::trans_field_ptr_builder(&bcx, &repr, val,
disr, field_index);
self.store_operand(&bcx, lldest_i, op);
}
}

View file

@ -397,6 +397,7 @@ pub fn push_unique_type_name<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
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) => {
push_item_name(tcx, adt_def.did, output);
push_type_params(tcx, substs, &[], output);

View file

@ -89,27 +89,23 @@ pub fn sizing_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) -> Typ
Type::nil(cx)
}
ty::TyTuple(..) | ty::TyEnum(..) | ty::TyClosure(..) => {
let repr = adt::represent_type(cx, t);
adt::sizing_type_of(cx, &repr, false)
ty::TyStruct(..) if t.is_simd() => {
let e = t.simd_type(cx.tcx());
if !e.is_machine() {
cx.sess().fatal(&format!("monomorphising SIMD type `{}` with \
a non-machine element type `{}`",
t, e))
}
let llet = type_of(cx, e);
let n = t.simd_size(cx.tcx()) as u64;
ensure_array_fits_in_address_space(cx, llet, n, t);
Type::vector(&llet, n)
}
ty::TyStruct(..) => {
if t.is_simd() {
let e = t.simd_type(cx.tcx());
if !e.is_machine() {
cx.sess().fatal(&format!("monomorphising SIMD type `{}` with \
a non-machine element type `{}`",
t, e))
}
let llet = type_of(cx, e);
let n = t.simd_size(cx.tcx()) as u64;
ensure_array_fits_in_address_space(cx, llet, n, t);
Type::vector(&llet, n)
} else {
let repr = adt::represent_type(cx, t);
adt::sizing_type_of(cx, &repr, false)
}
ty::TyTuple(..) | ty::TyStruct(..) | ty::TyUnion(..) |
ty::TyEnum(..) | ty::TyClosure(..) => {
let repr = adt::represent_type(cx, t);
adt::sizing_type_of(cx, &repr, false)
}
ty::TyProjection(..) | ty::TyInfer(..) | ty::TyParam(..) |
@ -244,15 +240,6 @@ pub fn in_memory_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) ->
ty::TyUint(t) => Type::uint_from_ty(cx, t),
ty::TyFloat(t) => Type::float_from_ty(cx, t),
ty::TyNever => Type::nil(cx),
ty::TyEnum(def, ref 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
// of the enum's variants refers to the enum itself.
let repr = adt::represent_type(cx, t);
let name = llvm_type_name(cx, def.did, substs);
adt::incomplete_type_of(cx, &repr, &name[..])
}
ty::TyClosure(..) => {
// Only create the named struct, but don't fill it in. We
// fill it in *after* placing it into the type cache.
@ -307,26 +294,28 @@ 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(def, ref substs) => {
if t.is_simd() {
let e = t.simd_type(cx.tcx());
if !e.is_machine() {
cx.sess().fatal(&format!("monomorphising SIMD type `{}` with \
a non-machine element type `{}`",
t, e))
}
let llet = in_memory_type_of(cx, e);
let n = t.simd_size(cx.tcx()) as u64;
ensure_array_fits_in_address_space(cx, llet, n, t);
Type::vector(&llet, n)
} else {
// Only create the named struct, but don't fill it in. We fill it
// in *after* placing it into the type cache. This prevents
// infinite recursion with recursive struct types.
let repr = adt::represent_type(cx, t);
let name = llvm_type_name(cx, def.did, substs);
adt::incomplete_type_of(cx, &repr, &name[..])
ty::TyStruct(..) if t.is_simd() => {
let e = t.simd_type(cx.tcx());
if !e.is_machine() {
cx.sess().fatal(&format!("monomorphising SIMD type `{}` with \
a non-machine element type `{}`",
t, e))
}
let llet = in_memory_type_of(cx, e);
let n = t.simd_size(cx.tcx()) as u64;
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) => {
// 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
// of the enum's variants refers to the enum itself.
let repr = adt::represent_type(cx, t);
let name = llvm_type_name(cx, def.did, substs);
adt::incomplete_type_of(cx, &repr, &name[..])
}
ty::TyInfer(..) |
@ -342,7 +331,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::TyClosure(..)
ty::TyEnum(..) | ty::TyStruct(..) | ty::TyUnion(..) | ty::TyClosure(..)
if !t.is_simd() => {
let repr = adt::represent_type(cx, t);
adt::finish_type_of(cx, &repr, &mut llty);

View file

@ -1476,7 +1476,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
span,
partition_bounds(tcx, span, &[]))
}
Def::Enum(did) | Def::TyAlias(did) | Def::Struct(did) => {
Def::Enum(did) | Def::TyAlias(did) | Def::Struct(did) | Def::Union(did) => {
tcx.prohibit_type_params(base_segments.split_last().unwrap().1);
self.ast_path_to_ty(rscope,
span,

View file

@ -11,7 +11,6 @@
use hir::def::Def;
use rustc::infer::{self, InferOk, TypeOrigin};
use hir::pat_util::EnumerateAndAdjustIterator;
use rustc::ty::subst::Substs;
use rustc::ty::{self, Ty, TypeFoldable, LvaluePreference, VariantKind};
use check::{FnCtxt, Expectation};
use lint;
@ -509,11 +508,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
self.demand_eqtype(pat.span, expected, pat_ty);
// Type check subpatterns.
let substs = match pat_ty.sty {
ty::TyStruct(_, substs) | ty::TyEnum(_, substs) => substs,
_ => span_bug!(pat.span, "struct variant is not an ADT")
};
self.check_struct_pat_fields(pat.span, fields, variant, substs, etc);
self.check_struct_pat_fields(pat_ty, pat.span, variant, fields, etc);
}
fn check_pat_path(&self,
@ -658,19 +653,21 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
}
}
/// `path` is the AST path item naming the type of this struct.
/// `fields` is the field patterns of the struct pattern.
/// `struct_fields` describes the type of each field of the struct.
/// `struct_id` is the ID of the struct.
/// `etc` is true if the pattern said '...' and false otherwise.
pub fn check_struct_pat_fields(&self,
span: Span,
fields: &'gcx [Spanned<hir::FieldPat>],
variant: ty::VariantDef<'tcx>,
substs: &Substs<'tcx>,
etc: bool) {
fn check_struct_pat_fields(&self,
adt_ty: Ty<'tcx>,
span: Span,
variant: ty::VariantDef<'tcx>,
fields: &'gcx [Spanned<hir::FieldPat>],
etc: 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"),
_ => span_bug!(span, "struct pattern is not an ADT")
};
// Index the struct fields' types.
let field_map = variant.fields
.iter()
@ -700,11 +697,13 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
.map(|f| self.field_ty(span, f, substs))
.unwrap_or_else(|| {
struct_span_err!(tcx.sess, span, E0026,
"struct `{}` does not have a field named `{}`",
"{} `{}` does not have a field named `{}`",
kind_name,
tcx.item_path_str(variant.did),
field.name)
.span_label(span,
&format!("struct `{}` does not have field `{}`",
&format!("{} `{}` does not have field `{}`",
kind_name,
tcx.item_path_str(variant.did),
field.name))
.emit();
@ -717,8 +716,15 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
self.check_pat(&field.pat, field_ty);
}
// Report an error if not all the fields were specified.
if !etc {
// Report an error if incorrect number of the fields were specified.
if kind_name == "union" {
if fields.len() != 1 {
tcx.sess.span_err(span, "union patterns should have exactly one field");
}
if etc {
tcx.sess.span_err(span, "`..` cannot be used in union patterns");
}
} else if !etc {
for field in variant.fields
.iter()
.filter(|field| !used_fields.contains_key(&field.name)) {

View file

@ -45,6 +45,7 @@ pub fn check_drop_impl(ccx: &CrateCtxt, drop_impl_did: DefId) -> Result<(), ()>
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) => {
ensure_drop_params_and_item_params_correspond(ccx,
drop_impl_did,
@ -304,7 +305,9 @@ pub fn check_safety_of_destructor_if_necessary<'a, 'gcx, 'tcx>(
tcx.item_path_str(def_id),
variant),
ty::AdtKind::Struct => format!("struct {}",
tcx.item_path_str(def_id))
tcx.item_path_str(def_id)),
ty::AdtKind::Union => format!("union {}",
tcx.item_path_str(def_id)),
};
span_note!(
&mut err,
@ -439,7 +442,7 @@ fn iterate_over_potentially_unsafe_regions_in_type<'a, 'b, 'gcx, 'tcx>(
cx, context, ity, depth+1)
}
ty::TyStruct(def, substs) | ty::TyEnum(def, substs) => {
ty::TyStruct(def, substs) | ty::TyUnion(def, substs) | ty::TyEnum(def, substs) => {
let did = def.did;
for variant in &def.variants {
for field in variant.fields.iter() {
@ -494,7 +497,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::TyEnum(def, _) | ty::TyStruct(def, _) | ty::TyUnion(def, _) => {
def.is_dtorck(tcx)
}
ty::TyTrait(..) | ty::TyProjection(..) | ty::TyAnon(..) => {

View file

@ -293,7 +293,8 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
self.assemble_inherent_impl_candidates_for_type(data.principal.def_id());
}
ty::TyEnum(def, _) |
ty::TyStruct(def, _) => {
ty::TyStruct(def, _) |
ty::TyUnion(def, _) => {
self.assemble_inherent_impl_candidates_for_type(def.did);
}
ty::TyBox(_) => {

View file

@ -164,30 +164,34 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
// give a helping note that it has to be called as (x.f)(...).
if let Some(expr) = rcvr_expr {
for (ty, _) in self.autoderef(span, rcvr_ty) {
if let ty::TyStruct(def, substs) = ty.sty {
if let Some(field) = def.struct_variant().find_field_named(item_name) {
let snippet = tcx.sess.codemap().span_to_snippet(expr.span);
let expr_string = match snippet {
Ok(expr_string) => expr_string,
_ => "s".into() // Default to a generic placeholder for the
// expression when we can't generate a
// string snippet
};
match ty.sty {
ty::TyStruct(def, substs) | ty::TyUnion(def, substs) => {
if let Some(field) = def.struct_variant().
find_field_named(item_name) {
let snippet = tcx.sess.codemap().span_to_snippet(expr.span);
let expr_string = match snippet {
Ok(expr_string) => expr_string,
_ => "s".into() // Default to a generic placeholder for the
// expression when we can't generate a
// string snippet
};
let field_ty = field.ty(tcx, substs);
let field_ty = field.ty(tcx, substs);
if self.is_fn_ty(&field_ty, span) {
err.span_note(span, &format!(
"use `({0}.{1})(...)` if you meant to call the function \
stored in the `{1}` field",
expr_string, item_name));
} else {
err.span_note(span, &format!(
"did you mean to write `{0}.{1}`?",
expr_string, item_name));
if self.is_fn_ty(&field_ty, span) {
err.span_note(span, &format!(
"use `({0}.{1})(...)` if you meant to call the \
function stored in the `{1}` field",
expr_string, item_name));
} else {
err.span_note(span, &format!(
"did you mean to write `{0}.{1}`?",
expr_string, item_name));
}
break;
}
break;
}
_ => {}
}
}
}
@ -355,7 +359,9 @@ 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, _) => def.did.is_local(),
ty::TyEnum(def, _) | ty::TyStruct(def, _) | ty::TyUnion(def, _) => {
def.did.is_local()
}
ty::TyTrait(ref tr) => tr.principal.def_id().is_local(),

View file

@ -713,16 +713,18 @@ fn check_fn<'a, 'gcx, 'tcx>(inherited: &'a Inherited<'a, 'gcx, 'tcx>,
fcx
}
pub fn check_struct(ccx: &CrateCtxt, id: ast::NodeId, span: Span) {
let tcx = ccx.tcx;
fn check_struct(ccx: &CrateCtxt, id: ast::NodeId, span: Span) {
check_representable(ccx.tcx, span, id);
check_representable(tcx, span, id, "struct");
if tcx.lookup_simd(ccx.tcx.map.local_def_id(id)) {
check_simd(tcx, span, id);
if ccx.tcx.lookup_simd(ccx.tcx.map.local_def_id(id)) {
check_simd(ccx.tcx, span, id);
}
}
fn check_union(ccx: &CrateCtxt, id: ast::NodeId, span: Span) {
check_representable(ccx.tcx, span, id);
}
pub fn check_item_type<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, it: &'tcx hir::Item) {
debug!("check_item_type(it.id={}, it.name={})",
it.id,
@ -762,6 +764,9 @@ pub fn check_item_type<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, it: &'tcx hir::Item) {
hir::ItemStruct(..) => {
check_struct(ccx, it.id, it.span);
}
hir::ItemUnion(..) => {
check_union(ccx, it.id, it.span);
}
hir::ItemTy(_, ref generics) => {
let pty_ty = ccx.tcx.node_id_to_type(it.id);
check_bounds_are_used(ccx, generics, pty_ty);
@ -1171,10 +1176,10 @@ fn check_const<'a, 'tcx>(ccx: &CrateCtxt<'a,'tcx>,
/// Checks whether a type can be represented in memory. In particular, it
/// identifies types that contain themselves without indirection through a
/// pointer, which would mean their size is unbounded.
pub fn check_representable<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
sp: Span,
item_id: ast::NodeId,
_designation: &str) -> bool {
fn check_representable<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
sp: Span,
item_id: ast::NodeId)
-> bool {
let rty = tcx.node_id_to_type(item_id);
// Check that it is possible to represent this type. This call identifies
@ -1274,7 +1279,7 @@ pub fn check_enum_variants<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>,
disr_vals.push(current_disr_val);
}
check_representable(ccx.tcx, sp, id, "enum");
check_representable(ccx.tcx, sp, id);
}
impl<'a, 'gcx, 'tcx> AstConv<'gcx, 'tcx> for FnCtxt<'a, 'gcx, 'tcx> {
@ -2942,18 +2947,21 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
let mut private_candidate = None;
let mut autoderef = self.autoderef(expr.span, expr_t);
while let Some((base_t, autoderefs)) = autoderef.next() {
if let ty::TyStruct(base_def, substs) = base_t.sty {
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);
if field.vis.is_accessible_from(self.body_id, &self.tcx().map) {
autoderef.finalize(lvalue_pref, Some(base));
self.write_ty(expr.id, field_ty);
self.write_autoderef_adjustment(base.id, autoderefs);
return;
match base_t.sty {
ty::TyStruct(base_def, substs) | ty::TyUnion(base_def, substs) => {
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);
if field.vis.is_accessible_from(self.body_id, &self.tcx().map) {
autoderef.finalize(lvalue_pref, Some(base));
self.write_ty(expr.id, field_ty);
self.write_autoderef_adjustment(base.id, autoderefs);
return;
}
private_candidate = Some((base_def.did, field_ty));
}
private_candidate = Some((base_def.did, field_ty));
}
_ => {}
}
}
autoderef.unambiguous_final_ty();
@ -2986,12 +2994,15 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
but no field with that name was found",
field.node, actual)
}, expr_t);
if let ty::TyRawPtr(..) = expr_t.sty {
err.note(&format!("`{0}` is a native pointer; perhaps you need to deref with \
`(*{0}).{1}`", pprust::expr_to_string(base), field.node));
}
if let ty::TyStruct(def, _) = expr_t.sty {
Self::suggest_field_names(&mut err, def.struct_variant(), field, vec![]);
match expr_t.sty {
ty::TyStruct(def, _) | ty::TyUnion(def, _) => {
Self::suggest_field_names(&mut err, def.struct_variant(), field, vec![]);
}
ty::TyRawPtr(..) => {
err.note(&format!("`{0}` is a native pointer; perhaps you need to deref with \
`(*{0}).{1}`", pprust::expr_to_string(base), field.node));
}
_ => {}
}
err.emit();
self.write_error(expr.id);
@ -3098,17 +3109,18 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
ty: Ty<'tcx>,
variant: ty::VariantDef<'tcx>,
field: &hir::Field,
skip_fields: &[hir::Field]) {
skip_fields: &[hir::Field],
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,
"struct variant `{}::{}` has no field named `{}`",
actual, variant.name.as_str(), field.name.node)
"{} `{}::{}` 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,
"structure `{}` has no field named `{}`",
actual, field.name.node)
"{} `{}` has no field named `{}`",
kind_name, actual, field.name.node)
},
ty);
// prevent all specified fields from being suggested
@ -3124,8 +3136,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
ast_fields: &'gcx [hir::Field],
check_completeness: bool) {
let tcx = self.tcx;
let substs = match adt_ty.sty {
ty::TyStruct(_, substs) | ty::TyEnum(_, substs) => substs,
let (substs, kind_name) = match adt_ty.sty {
ty::TyEnum(_, substs) => (substs, "variant"),
ty::TyStruct(_, substs) => (substs, "struct"),
ty::TyUnion(_, substs) => (substs, "union"),
_ => span_bug!(span, "non-ADT passed to check_expr_struct_fields")
};
@ -3164,7 +3178,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
err.emit();
} else {
self.report_unknown_field(adt_ty, variant, field, ast_fields);
self.report_unknown_field(adt_ty, variant, field, ast_fields, kind_name);
}
}
@ -3173,11 +3187,12 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
self.check_expr_coercable_to_type(&field.expr, expected_field_type);
}
// Make sure the programmer specified all the fields.
if check_completeness &&
!error_happened &&
!remaining_fields.is_empty()
{
// Make sure the programmer specified correct number of fields.
if kind_name == "union" {
if ast_fields.len() != 1 {
tcx.sess.span_err(span, "union expressions should have exactly one field");
}
} else if check_completeness && !error_happened && !remaining_fields.is_empty() {
span_err!(tcx.sess, span, E0063,
"missing field{} {} in initializer of `{}`",
if remaining_fields.len() == 1 {""} else {"s"},
@ -3187,7 +3202,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
.join(", "),
adt_ty);
}
}
fn check_struct_fields_on_error(&self,
@ -3217,15 +3231,14 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
self.set_tainted_by_errors();
return None;
}
Def::Variant(type_did, _) | Def::Struct(type_did) => {
Def::Variant(type_did, _) | Def::Struct(type_did) | Def::Union(type_did) => {
Some((type_did, self.tcx.expect_variant_def(def)))
}
Def::TyAlias(did) => {
if let Some(&ty::TyStruct(adt, _)) = self.tcx.opt_lookup_item_type(did)
.map(|scheme| &scheme.ty.sty) {
Some((did, adt.struct_variant()))
} else {
None
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())),
_ => None,
}
}
_ => None
@ -4118,6 +4131,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
match def {
// Case 1 and 1b. Reference to a *type* or *enum variant*.
Def::Struct(def_id) |
Def::Union(def_id) |
Def::Variant(_, def_id) |
Def::Enum(def_id) |
Def::TyAlias(def_id) |

View file

@ -136,14 +136,21 @@ impl<'ccx, 'gcx> CheckTypeWellFormedVisitor<'ccx, 'gcx> {
self.check_item_type(item);
}
hir::ItemStruct(ref struct_def, ref ast_generics) => {
self.check_type_defn(item, |fcx| {
self.check_type_defn(item, false, |fcx| {
vec![fcx.struct_variant(struct_def)]
});
self.check_variances_for_type_defn(item, ast_generics);
}
hir::ItemUnion(ref struct_def, ref ast_generics) => {
self.check_type_defn(item, true, |fcx| {
vec![fcx.struct_variant(struct_def)]
});
self.check_variances_for_type_defn(item, ast_generics);
}
hir::ItemEnum(ref enum_def, ref ast_generics) => {
self.check_type_defn(item, |fcx| {
self.check_type_defn(item, false, |fcx| {
fcx.enum_variants(enum_def)
});
@ -216,24 +223,22 @@ impl<'ccx, 'gcx> CheckTypeWellFormedVisitor<'ccx, 'gcx> {
}
/// In a type definition, we check that to ensure that the types of the fields are well-formed.
fn check_type_defn<F>(&mut self, item: &hir::Item, mut lookup_fields: F) where
F: for<'fcx, 'tcx> FnMut(&FnCtxt<'fcx, 'gcx, 'tcx>)
-> Vec<AdtVariant<'tcx>>
fn check_type_defn<F>(&mut self, item: &hir::Item, all_sized: bool, mut lookup_fields: F)
where F: for<'fcx, 'tcx> FnMut(&FnCtxt<'fcx, 'gcx, 'tcx>) -> Vec<AdtVariant<'tcx>>
{
self.for_item(item).with_fcx(|fcx, this| {
let variants = lookup_fields(fcx);
for variant in &variants {
// For DST, all intermediate types must be sized.
if let Some((_, fields)) = variant.fields.split_last() {
for field in fields {
fcx.register_builtin_bound(
field.ty,
ty::BoundSized,
traits::ObligationCause::new(field.span,
fcx.body_id,
traits::FieldSized));
}
let unsized_len = if all_sized || variant.fields.is_empty() { 0 } else { 1 };
for field in &variant.fields[..variant.fields.len() - unsized_len] {
fcx.register_builtin_bound(
field.ty,
ty::BoundSized,
traits::ObligationCause::new(field.span,
fcx.body_id,
traits::FieldSized));
}
// All field types must be well-formed.

View file

@ -24,7 +24,7 @@ use rustc::ty::{ImplOrTraitItemId, ConstTraitItemId};
use rustc::ty::{MethodTraitItemId, TypeTraitItemId, ParameterEnvironment};
use rustc::ty::{Ty, TyBool, TyChar, TyEnum, TyError};
use rustc::ty::{TyParam, TyRawPtr};
use rustc::ty::{TyRef, TyStruct, TyTrait, TyNever, TyTuple};
use rustc::ty::{TyRef, TyStruct, TyUnion, 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};
@ -70,7 +70,8 @@ impl<'a, 'gcx, 'tcx> CoherenceChecker<'a, 'gcx, 'tcx> {
fn get_base_type_def_id(&self, span: Span, ty: Ty<'tcx>) -> Option<DefId> {
match ty.sty {
TyEnum(def, _) |
TyStruct(def, _) => {
TyStruct(def, _) |
TyUnion(def, _) => {
Some(def.did)
}
@ -241,7 +242,8 @@ 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::TyStruct(type_def, _) |
ty::TyUnion(type_def, _) => {
type_def.set_destructor(method_def_id.def_id());
}
_ => {

View file

@ -76,7 +76,8 @@ impl<'cx, 'tcx> OrphanChecker<'cx, 'tcx> {
let self_ty = self.tcx.lookup_item_type(def_id).ty;
match self_ty.sty {
ty::TyEnum(def, _) |
ty::TyStruct(def, _) => {
ty::TyStruct(def, _) |
ty::TyUnion(def, _) => {
self.check_def_id(item, def.did);
}
ty::TyTrait(ref data) => {
@ -293,7 +294,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::TyEnum(self_def, _) =>
ty::TyStruct(self_def, _) |
ty::TyUnion(self_def, _) |
ty::TyEnum(self_def, _) =>
Some(self_def.did),
ty::TyBox(..) =>
self.tcx.lang_items.owned_box(),

View file

@ -97,7 +97,7 @@ impl<'cx, 'tcx> OverlapChecker<'cx, 'tcx> {
impl<'cx, 'tcx,'v> intravisit::Visitor<'v> for OverlapChecker<'cx, 'tcx> {
fn visit_item(&mut self, item: &'v hir::Item) {
match item.node {
hir::ItemEnum(..) | hir::ItemStruct(..) => {
hir::ItemEnum(..) | hir::ItemStruct(..) | hir::ItemUnion(..) => {
let type_def_id = self.tcx.map.local_def_id(item.id);
self.check_for_overlapping_inherent_impls(type_def_id);
}

View file

@ -931,7 +931,8 @@ fn convert_item(ccx: &CrateCtxt, it: &hir::Item) {
tcx.trait_item_def_ids.borrow_mut().insert(ccx.tcx.map.local_def_id(it.id),
trait_item_def_ids);
},
hir::ItemStruct(ref struct_def, _) => {
hir::ItemStruct(ref struct_def, _) |
hir::ItemUnion(ref struct_def, _) => {
let def_id = ccx.tcx.map.local_def_id(it.id);
let scheme = type_scheme_of_def_id(ccx, def_id);
let predicates = predicates_of_item(ccx, it);
@ -1069,6 +1070,16 @@ fn convert_struct_def<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
adt
}
fn convert_union_def<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
it: &hir::Item,
def: &hir::VariantData)
-> ty::AdtDefMaster<'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)
}
fn evaluate_disr_expr(ccx: &CrateCtxt, repr_ty: attr::IntType, e: &hir::Expr)
-> Option<ty::Disr> {
debug!("disr expr, checking {}", pprust::expr_to_string(e));
@ -1439,7 +1450,8 @@ fn generics_of_def_id<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
ItemTy(_, ref generics) |
ItemEnum(_, ref generics) |
ItemStruct(_, ref generics) => {
ItemStruct(_, ref generics) |
ItemUnion(_, ref generics) => {
allow_defaults = true;
generics
}
@ -1576,6 +1588,11 @@ fn type_of_def_id<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
let substs = mk_item_substs(&ccx.icx(generics), item.span, def_id);
ccx.tcx.mk_struct(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)
}
ItemDefaultImpl(..) |
ItemTrait(..) |
ItemImpl(..) |
@ -1637,7 +1654,8 @@ fn predicates_of_item<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
hir::ItemFn(_, _, _, _, ref generics, _) |
hir::ItemTy(_, ref generics) |
hir::ItemEnum(_, ref generics) |
hir::ItemStruct(_, ref generics) => generics,
hir::ItemStruct(_, ref generics) |
hir::ItemUnion(_, ref generics) => generics,
_ => &no_generics
};

View file

@ -80,7 +80,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for ConstraintContext<'a, 'tcx> {
debug!("visit_item item={}", tcx.map.node_to_string(item.id));
match item.node {
hir::ItemEnum(..) | hir::ItemStruct(..) => {
hir::ItemEnum(..) | hir::ItemStruct(..) | hir::ItemUnion(..) => {
let scheme = tcx.lookup_item_type(did);
// Not entirely obvious: constraints on structs/enums do not
@ -185,6 +185,7 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> {
hir::ItemTy(..) |
hir::ItemEnum(..) |
hir::ItemStruct(..) |
hir::ItemUnion(..) |
hir::ItemTrait(..) => is_inferred = true,
hir::ItemFn(..) => is_inferred = false,
_ => cannot_happen!(),
@ -344,7 +345,8 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> {
}
ty::TyEnum(def, substs) |
ty::TyStruct(def, substs) => {
ty::TyStruct(def, substs) |
ty::TyUnion(def, substs) => {
let item_type = self.tcx().lookup_item_type(def.did);
// This edge is actually implied by the call to

View file

@ -234,7 +234,8 @@ impl<'a, 'tcx, 'v> Visitor<'v> for TermsContext<'a, 'tcx> {
match item.node {
hir::ItemEnum(_, ref generics) |
hir::ItemStruct(_, ref generics) => {
hir::ItemStruct(_, ref generics) |
hir::ItemUnion(_, ref generics) => {
self.add_inferreds_for_item(item.id, false, generics);
}
hir::ItemTrait(_, ref generics, _, _) => {

Some files were not shown because too many files have changed in this diff Show more