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:
commit
d748fa6ecc
167 changed files with 2897 additions and 360 deletions
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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()))
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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(),
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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)?;
|
||||
|
|
|
@ -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 =
|
||||
|
|
|
@ -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(..) |
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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>) {
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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))
|
||||
}
|
||||
|
|
|
@ -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) => {
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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) => {
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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()
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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| {
|
||||
|
|
|
@ -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>,
|
||||
|
|
|
@ -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(),
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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()),
|
||||
|
|
|
@ -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, .. } => {
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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 =>
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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()
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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 `{}`, \
|
||||
|
|
|
@ -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 => {
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -220,6 +220,7 @@ impl<'a, 'gcx, 'tcx> Env<'a, 'gcx, 'tcx> {
|
|||
|
||||
hir::ItemEnum(..) |
|
||||
hir::ItemStruct(..) |
|
||||
hir::ItemUnion(..) |
|
||||
hir::ItemTrait(..) |
|
||||
hir::ItemImpl(..) |
|
||||
hir::ItemDefaultImpl(..) => {
|
||||
|
|
|
@ -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(..) |
|
||||
|
|
|
@ -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(..) => {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -128,6 +128,7 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) {
|
|||
InvalidNoMangleItems,
|
||||
PluginAsLibrary,
|
||||
MutableTransmutes,
|
||||
UnionsWithDropFields,
|
||||
);
|
||||
|
||||
add_builtin_with_new!(sess,
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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,
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
};
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 { .. } => {
|
||||
|
|
|
@ -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!(
|
||||
|
|
|
@ -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 }
|
||||
}
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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(..) |
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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(..) |
|
||||
|
|
|
@ -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) |
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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)) {
|
||||
|
|
|
@ -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(..) => {
|
||||
|
|
|
@ -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(_) => {
|
||||
|
|
|
@ -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(),
|
||||
|
||||
|
|
|
@ -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) |
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
_ => {
|
||||
|
|
|
@ -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(),
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
};
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
Loading…
Add table
Add a link
Reference in a new issue