diff options
| author | Tyler Mandry <tmandry@gmail.com> | 2019-04-02 15:57:50 -0700 |
|---|---|---|
| committer | Tyler Mandry <tmandry@gmail.com> | 2019-04-11 17:44:43 -0700 |
| commit | 7c626a67ba02bc7b7bcb5a7e7809e9d54e099d2c (patch) | |
| tree | 0bef686fb730123107ecf0524299a4e5d322bc54 /src/librustc_codegen_llvm | |
| parent | b58624727cfbc29ecd711222264c38adaebce0e1 (diff) | |
| download | rust-7c626a67ba02bc7b7bcb5a7e7809e9d54e099d2c.tar.gz rust-7c626a67ba02bc7b7bcb5a7e7809e9d54e099d2c.zip | |
Add discr_index to multi-variant layouts
We relax the assumption that the discriminant is always field 0, in preparations for layouts like generators where this is not going to be the case.
Diffstat (limited to 'src/librustc_codegen_llvm')
| -rw-r--r-- | src/librustc_codegen_llvm/debuginfo/metadata.rs | 36 | ||||
| -rw-r--r-- | src/librustc_codegen_llvm/type_of.rs | 34 |
2 files changed, 39 insertions, 31 deletions
diff --git a/src/librustc_codegen_llvm/debuginfo/metadata.rs b/src/librustc_codegen_llvm/debuginfo/metadata.rs index ca056c6034a..6560ed0a8e6 100644 --- a/src/librustc_codegen_llvm/debuginfo/metadata.rs +++ b/src/librustc_codegen_llvm/debuginfo/metadata.rs @@ -22,6 +22,7 @@ use rustc::hir::CodegenFnAttrFlags; use rustc::hir::def::CtorKind; use rustc::hir::def_id::{DefId, CrateNum, LOCAL_CRATE}; use rustc::ich::NodeIdHashingMode; +use rustc::mir::Field; use rustc::mir::interpret::truncate; use rustc_data_structures::fingerprint::Fingerprint; use rustc::ty::Instance; @@ -1306,12 +1307,15 @@ impl EnumMemberDescriptionFactory<'ll, 'tcx> { } layout::Variants::Multiple { discr_kind: layout::DiscriminantKind::Tag, + discr_index, ref variants, .. } => { let discriminant_info = if fallback { - RegularDiscriminant(self.discriminant_type_metadata - .expect("")) + RegularDiscriminant { + discr_field: Field::from(discr_index), + discr_type_metadata: self.discriminant_type_metadata.unwrap() + } } else { // This doesn't matter in this case. NoDiscriminant @@ -1358,6 +1362,7 @@ impl EnumMemberDescriptionFactory<'ll, 'tcx> { }, ref discr, ref variants, + discr_index, } => { if fallback { let variant = self.layout.for_variant(cx, dataful_variant); @@ -1403,8 +1408,8 @@ impl EnumMemberDescriptionFactory<'ll, 'tcx> { } compute_field_path(cx, &mut name, self.layout, - self.layout.fields.offset(0), - self.layout.field(cx, 0).size); + self.layout.fields.offset(discr_index), + self.layout.field(cx, discr_index).size); name.push_str(&adt.variants[*niche_variants.start()].ident.as_str()); // Create the (singleton) list of descriptions of union members. @@ -1486,6 +1491,8 @@ impl VariantMemberDescriptionFactory<'ll, 'tcx> { name: name.to_string(), type_metadata: if use_enum_fallback(cx) { match self.discriminant_type_metadata { + // Discriminant is always the first field of our variant + // when using the enum fallback. Some(metadata) if i == 0 => metadata, _ => type_metadata(cx, ty, self.span) } @@ -1504,7 +1511,7 @@ impl VariantMemberDescriptionFactory<'ll, 'tcx> { #[derive(Copy, Clone)] enum EnumDiscriminantInfo<'ll> { - RegularDiscriminant(&'ll DIType), + RegularDiscriminant{ discr_field: Field, discr_type_metadata: &'ll DIType }, OptimizedDiscriminant, NoDiscriminant } @@ -1547,11 +1554,14 @@ fn describe_enum_variant( let (offsets, args) = if use_enum_fallback(cx) { // If this is not a univariant enum, there is also the discriminant field. let (discr_offset, discr_arg) = match discriminant_info { - RegularDiscriminant(_) => { + RegularDiscriminant { discr_field, .. } => { // We have the layout of an enum variant, we need the layout of the outer enum let enum_layout = cx.layout_of(layout.ty); - (Some(enum_layout.fields.offset(0)), - Some(("RUST$ENUM$DISR".to_owned(), enum_layout.field(cx, 0).ty))) + let offset = enum_layout.fields.offset(discr_field.as_usize()); + let args = ( + "RUST$ENUM$DISR".to_owned(), + enum_layout.field(cx, discr_field.as_usize()).ty); + (Some(offset), Some(args)) } _ => (None, None), }; @@ -1579,8 +1589,8 @@ fn describe_enum_variant( offsets, args, discriminant_type_metadata: match discriminant_info { - RegularDiscriminant(discriminant_type_metadata) => { - Some(discriminant_type_metadata) + RegularDiscriminant { discr_type_metadata, .. } => { + Some(discr_type_metadata) } _ => None }, @@ -1730,6 +1740,7 @@ fn prepare_enum_metadata( layout::Variants::Multiple { discr_kind: layout::DiscriminantKind::Niche { .. }, ref discr, + discr_index, .. } => { // Find the integer type of the correct size. @@ -1753,7 +1764,7 @@ fn prepare_enum_metadata( UNKNOWN_LINE_NUMBER, size.bits(), align.abi.bits() as u32, - layout.fields.offset(0).bits(), + layout.fields.offset(discr_index).bits(), DIFlags::FlagArtificial, discr_metadata)) } @@ -1762,6 +1773,7 @@ fn prepare_enum_metadata( layout::Variants::Multiple { discr_kind: layout::DiscriminantKind::Tag, ref discr, + discr_index, .. } => { let discr_type = discr.value.to_ty(cx.tcx); @@ -1777,7 +1789,7 @@ fn prepare_enum_metadata( UNKNOWN_LINE_NUMBER, size.bits(), align.bits() as u32, - layout.fields.offset(0).bits(), + layout.fields.offset(discr_index).bits(), DIFlags::FlagArtificial, discr_metadata)) } diff --git a/src/librustc_codegen_llvm/type_of.rs b/src/librustc_codegen_llvm/type_of.rs index 020447608ee..d42fa829161 100644 --- a/src/librustc_codegen_llvm/type_of.rs +++ b/src/librustc_codegen_llvm/type_of.rs @@ -452,31 +452,27 @@ impl<'tcx> LayoutLlvmExt<'tcx> for TyLayout<'tcx> { _ => { let mut data_variant = match self.variants { + // Within the discriminant field, only the niche itself is + // always initialized, so we only check for a pointer at its + // offset. + // + // If the niche is a pointer, it's either valid (according + // to its type), or null (which the niche field's scalar + // validity range encodes). This allows using + // `dereferenceable_or_null` for e.g., `Option<&T>`, and + // this will continue to work as long as we don't start + // using more niches than just null (e.g., the first page of + // the address space, or unaligned pointers). layout::Variants::Multiple { discr_kind: layout::DiscriminantKind::Niche { dataful_variant, .. }, + discr_index, .. - } => { - // Only the niche itself is always initialized, - // so only check for a pointer at its offset. - // - // If the niche is a pointer, it's either valid - // (according to its type), or null (which the - // niche field's scalar validity range encodes). - // This allows using `dereferenceable_or_null` - // for e.g., `Option<&T>`, and this will continue - // to work as long as we don't start using more - // niches than just null (e.g., the first page - // of the address space, or unaligned pointers). - if self.fields.offset(0) == offset { - Some(self.for_variant(cx, dataful_variant)) - } else { - None - } - } - _ => Some(*self) + } if self.fields.offset(discr_index) == offset => + Some(self.for_variant(cx, dataful_variant)), + _ => Some(*self), }; if let Some(variant) = data_variant { |
