From ae2ad30bf1f3f924ed9ef977b3d2782f85fe2593 Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Sat, 1 Sep 2018 19:10:26 +0300 Subject: [PATCH] move the is_field_list_non_exhaustive flag to VariantDef This completely splits the IS_NON_EXHAUSTIVE flag. No functional changes intended. --- src/librustc/ich/impls_ty.rs | 14 +-- src/librustc/ty/mod.rs | 110 ++++++++++++++---------- src/librustc_metadata/decoder.rs | 28 +++--- src/librustc_metadata/encoder.rs | 4 +- src/librustc_mir/hair/pattern/_match.rs | 2 +- src/librustc_privacy/lib.rs | 2 +- src/librustc_typeck/check/_match.rs | 2 +- src/librustc_typeck/check/mod.rs | 2 +- src/librustc_typeck/collect.rs | 17 ++-- 9 files changed, 108 insertions(+), 73 deletions(-) diff --git a/src/librustc/ich/impls_ty.rs b/src/librustc/ich/impls_ty.rs index f4c46b6ce09..3a873ec739c 100644 --- a/src/librustc/ich/impls_ty.rs +++ b/src/librustc/ich/impls_ty.rs @@ -344,13 +344,13 @@ impl<'a> HashStable> for ty::AdtFlags { } } -impl_stable_hash_for!(struct ty::VariantDef { - did, - name, - discr, - fields, - ctor_kind -}); +impl<'a> HashStable> for ty::VariantFlags { + fn hash_stable(&self, + _: &mut StableHashingContext<'a>, + hasher: &mut StableHasher) { + std_hash::Hash::hash(self, hasher); + } +} impl_stable_hash_for!(enum ty::VariantDiscr { Explicit(def_id), diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index c60de9c386e..fb72585d6c6 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -1691,12 +1691,17 @@ bitflags! { const IS_FUNDAMENTAL = 1 << 2; const IS_UNION = 1 << 3; const IS_BOX = 1 << 4; - /// Indicates whether this abstract data type will be expanded on in future (new - /// fields/variants) and as such, whether downstream crates must match exhaustively on the - /// fields/variants of this data type. - /// - /// See RFC 2008 (). - const IS_NON_EXHAUSTIVE = 1 << 5; + /// Indicates whether the variant list of this ADT is `#[non_exhaustive]`. + /// (i.e., this flag is never set unless this ADT is an enum). + const IS_VARIANT_LIST_NON_EXHAUSTIVE = 1 << 5; + } +} + +bitflags! { + pub struct VariantFlags: u32 { + const NO_VARIANT_FLAGS = 0; + /// Indicates whether the field list of this variant is `#[non_exhaustive]`. + const IS_FIELD_LIST_NON_EXHAUSTIVE = 1 << 0; } } @@ -1709,8 +1714,56 @@ pub struct VariantDef { pub discr: VariantDiscr, pub fields: Vec, pub ctor_kind: CtorKind, + flags: VariantFlags, } +impl<'a, 'gcx, 'tcx> VariantDef { + /// Create a new `VariantDef`. + /// + /// - `did` is the DefId used for the variant - for tuple-structs, it is the constructor DefId, + /// and for everything else, it is the variant DefId. + /// - `attribute_def_id` is the DefId that has the variant's attributes. + pub fn new(tcx: TyCtxt<'a, 'gcx, 'tcx>, + did: DefId, + name: Name, + discr: VariantDiscr, + fields: Vec, + adt_kind: AdtKind, + ctor_kind: CtorKind) + -> Self + { + debug!("VariantDef::new({:?}, {:?}, {:?}, {:?}, {:?}, {:?})", did, name, discr, fields, + adt_kind, ctor_kind); + let mut flags = VariantFlags::NO_VARIANT_FLAGS; + if adt_kind == AdtKind::Struct && tcx.has_attr(did, "non_exhaustive") { + debug!("found non-exhaustive field list for {:?}", did); + flags = flags | VariantFlags::IS_FIELD_LIST_NON_EXHAUSTIVE; + } + VariantDef { + did, + name, + discr, + fields, + ctor_kind, + flags + } + } + + #[inline] + pub fn is_field_list_non_exhaustive(&self) -> bool { + self.flags.intersects(VariantFlags::IS_FIELD_LIST_NON_EXHAUSTIVE) + } +} + +impl_stable_hash_for!(struct VariantDef { + did, + name, + discr, + fields, + ctor_kind, + flags +}); + #[derive(Copy, Clone, Debug, PartialEq, Eq, RustcEncodable, RustcDecodable)] pub enum VariantDiscr { /// Explicit value for this variant, i.e. `X = 123`. @@ -1849,7 +1902,7 @@ impl_stable_hash_for!(struct ReprFlags { /// Represents the repr options provided by the user, -#[derive(Copy, Clone, Eq, PartialEq, RustcEncodable, RustcDecodable, Default)] +#[derive(Copy, Clone, Debug, Eq, PartialEq, RustcEncodable, RustcDecodable, Default)] pub struct ReprOptions { pub int: Option, pub align: u32, @@ -1938,6 +1991,7 @@ impl<'a, 'gcx, 'tcx> AdtDef { kind: AdtKind, variants: Vec, repr: ReprOptions) -> Self { + debug!("AdtDef::new({:?}, {:?}, {:?}, {:?})", did, kind, variants, repr); let mut flags = AdtFlags::NO_ADT_FLAGS; let attrs = tcx.get_attrs(did); if attr::contains_name(&attrs, "fundamental") { @@ -1949,8 +2003,9 @@ impl<'a, 'gcx, 'tcx> AdtDef { if Some(did) == tcx.lang_items().owned_box() { flags = flags | AdtFlags::IS_BOX; } - if tcx.has_attr(did, "non_exhaustive") { - flags = flags | AdtFlags::IS_NON_EXHAUSTIVE; + if kind == AdtKind::Enum && tcx.has_attr(did, "non_exhaustive") { + debug!("found non-exhaustive variant list for {:?}", did); + flags = flags | AdtFlags::IS_VARIANT_LIST_NON_EXHAUSTIVE; } match kind { AdtKind::Enum => flags = flags | AdtFlags::IS_ENUM, @@ -1981,28 +2036,8 @@ impl<'a, 'gcx, 'tcx> AdtDef { } #[inline] - fn is_non_exhaustive(&self) -> bool { - self.flags.intersects(AdtFlags::IS_NON_EXHAUSTIVE) - } - - #[inline] - pub fn is_enum_non_exhaustive(&self) -> bool { - match self.adt_kind() { - AdtKind::Enum => self.is_non_exhaustive(), - AdtKind::Struct | AdtKind::Union => { - bug!("is_non_exhaustive_enum called on non-enum `{:?}`", self); - } - } - } - - #[inline] - pub fn is_univariant_non_exhaustive(&self) -> bool { - match self.adt_kind() { - AdtKind::Struct | AdtKind::Union => self.is_non_exhaustive(), - AdtKind::Enum => { - bug!("is_non_exhaustive_enum called on non-enum `{:?}`", self); - } - } + pub fn is_variant_list_non_exhaustive(&self) -> bool { + self.flags.intersects(AdtFlags::IS_VARIANT_LIST_NON_EXHAUSTIVE) } /// Returns the kind of the ADT - Struct or Enum. @@ -2017,19 +2052,6 @@ impl<'a, 'gcx, 'tcx> AdtDef { } } - /// Return whether `variant` is non-exhaustive as a *struct* (i.e., whether - /// it can have additional fields). - pub fn is_variant_non_exhaustive(&self, _variant: &ty::VariantDef) -> bool { - match self.adt_kind() { - // A struct is non-exhaustive if it has a `#[non_exhaustive]` attribute. - AdtKind::Struct => self.is_non_exhaustive(), - // At this moment, all enum variants are exhaustive. - AdtKind::Enum => false, - // All unions are "exhaustive", as far as that makes sense. - AdtKind::Union => false, - } - } - pub fn descr(&self) -> &'static str { match self.adt_kind() { AdtKind::Struct => "struct", diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index f1e7e3de67d..91c762a01b9 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -507,7 +507,13 @@ impl<'a, 'tcx> CrateMetadata { self.def_path_table.def_path_hash(item_id)) } - fn get_variant(&self, item: &Entry, index: DefIndex) -> ty::VariantDef { + fn get_variant(&self, + tcx: TyCtxt<'a, 'tcx, 'tcx>, + item: &Entry, + index: DefIndex, + adt_kind: ty::AdtKind) + -> ty::VariantDef + { let data = match item.kind { EntryKind::Variant(data) | EntryKind::Struct(data, _) | @@ -515,10 +521,12 @@ impl<'a, 'tcx> CrateMetadata { _ => bug!(), }; - ty::VariantDef { - did: self.local_def_id(data.struct_ctor.unwrap_or(index)), - name: self.item_name(index).as_symbol(), - fields: item.children.decode(self).map(|index| { + ty::VariantDef::new( + tcx, + self.local_def_id(data.struct_ctor.unwrap_or(index)), + self.item_name(index).as_symbol(), + data.discr, + item.children.decode(self).map(|index| { let f = self.entry(index); ty::FieldDef { did: self.local_def_id(index), @@ -526,9 +534,9 @@ impl<'a, 'tcx> CrateMetadata { vis: f.visibility.decode(self) } }).collect(), - discr: data.discr, - ctor_kind: data.ctor_kind, - } + adt_kind, + data.ctor_kind + ) } pub fn get_adt_def(&self, @@ -549,11 +557,11 @@ impl<'a, 'tcx> CrateMetadata { item.children .decode(self) .map(|index| { - self.get_variant(&self.entry(index), index) + self.get_variant(tcx, &self.entry(index), index, kind) }) .collect() } else { - vec![self.get_variant(&item, item_id)] + vec![self.get_variant(tcx, &item, item_id, kind)] }; tcx.alloc_adt_def(did, kind, variants, repr) diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index 27f4577c442..0fd43c592c8 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -740,7 +740,9 @@ impl<'a, 'b: 'a, 'tcx: 'b> IsolatedEncoder<'a, 'b, 'tcx> { // If the structure is marked as non_exhaustive then lower the visibility // to within the crate. - if adt_def.is_univariant_non_exhaustive() && ctor_vis == ty::Visibility::Public { + if adt_def.non_enum_variant().is_field_list_non_exhaustive() && + ctor_vis == ty::Visibility::Public + { ctor_vis = ty::Visibility::Restricted(DefId::local(CRATE_DEF_INDEX)); } diff --git a/src/librustc_mir/hair/pattern/_match.rs b/src/librustc_mir/hair/pattern/_match.rs index 4f14a45bfc8..d7fbbc88cc1 100644 --- a/src/librustc_mir/hair/pattern/_match.rs +++ b/src/librustc_mir/hair/pattern/_match.rs @@ -381,7 +381,7 @@ impl<'a, 'tcx> MatchCheckCtxt<'a, 'tcx> { fn is_non_exhaustive_enum(&self, ty: Ty<'tcx>) -> bool { match ty.sty { - ty::Adt(adt_def, ..) => adt_def.is_enum() && adt_def.is_enum_non_exhaustive(), + ty::Adt(adt_def, ..) => adt_def.is_variant_list_non_exhaustive(), _ => false, } } diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs index ea13a3d0033..635f1881737 100644 --- a/src/librustc_privacy/lib.rs +++ b/src/librustc_privacy/lib.rs @@ -684,7 +684,7 @@ impl<'a, 'tcx> TypePrivacyVisitor<'a, 'tcx> { // visibility to within the crate. let struct_def_id = self.tcx.hir.get_parent_did(node_id); let adt_def = self.tcx.adt_def(struct_def_id); - if adt_def.is_univariant_non_exhaustive() + if adt_def.non_enum_variant().is_field_list_non_exhaustive() && ctor_vis == ty::Visibility::Public { ctor_vis = ty::Visibility::Restricted( diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs index b4dcea0eb32..8907ba4b7bd 100644 --- a/src/librustc_typeck/check/_match.rs +++ b/src/librustc_typeck/check/_match.rs @@ -948,7 +948,7 @@ https://doc.rust-lang.org/reference/types.html#trait-objects"); } // Require `..` if struct has non_exhaustive attribute. - if adt.is_variant_non_exhaustive(variant) && !adt.did.is_local() && !etc { + if variant.is_field_list_non_exhaustive() && !adt.did.is_local() && !etc { span_err!(tcx.sess, span, E0638, "`..` required with {} marked as non-exhaustive", kind_name); diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index d4013b10c31..cb14f4eb6eb 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -3654,7 +3654,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // Prohibit struct expressions when non exhaustive flag is set. let adt = adt_ty.ty_adt_def().expect("`check_struct_path` returned non-ADT type"); - if !adt.did.is_local() && adt.is_variant_non_exhaustive(variant) { + if !adt.did.is_local() && variant.is_field_list_non_exhaustive() { span_err!(self.tcx.sess, expr.span, E0639, "cannot create non-exhaustive {} using struct expression", adt.variant_descr()); diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index e404eb4ecca..80abf48a8a2 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -548,12 +548,13 @@ fn convert_enum_variant_types<'a, 'tcx>( } } -fn convert_struct_variant<'a, 'tcx>( +fn convert_variant<'a, 'tcx>( tcx: TyCtxt<'a, 'tcx, 'tcx>, did: DefId, name: ast::Name, discr: ty::VariantDiscr, def: &hir::VariantData, + adt_kind: ty::AdtKind ) -> ty::VariantDef { let mut seen_fields: FxHashMap = FxHashMap(); let node_id = tcx.hir.as_local_node_id(did).unwrap(); @@ -584,13 +585,13 @@ fn convert_struct_variant<'a, 'tcx>( } }) .collect(); - ty::VariantDef { + ty::VariantDef::new(tcx, did, name, discr, fields, - ctor_kind: CtorKind::from_hir(def), - } + adt_kind, + CtorKind::from_hir(def)) } fn adt_def<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> &'tcx ty::AdtDef { @@ -621,7 +622,7 @@ fn adt_def<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> &'tcx ty::Ad }; distance_from_explicit += 1; - convert_struct_variant(tcx, did, v.node.name, discr, &v.node.data) + convert_variant(tcx, did, v.node.name, discr, &v.node.data, AdtKind::Enum) }) .collect(), ) @@ -635,23 +636,25 @@ fn adt_def<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> &'tcx ty::Ad }; ( AdtKind::Struct, - vec![convert_struct_variant( + vec![convert_variant( tcx, ctor_id.unwrap_or(def_id), item.name, ty::VariantDiscr::Relative(0), def, + AdtKind::Struct )], ) } ItemKind::Union(ref def, _) => ( AdtKind::Union, - vec![convert_struct_variant( + vec![convert_variant( tcx, def_id, item.name, ty::VariantDiscr::Relative(0), def, + AdtKind::Union )], ), _ => bug!(),