Skip to content

Commit

Permalink
rustc: add some abstractions to ty::layout for a more concise API.
Browse files Browse the repository at this point in the history
  • Loading branch information
eddyb committed Apr 8, 2017
1 parent c977daf commit 43b227f
Show file tree
Hide file tree
Showing 17 changed files with 188 additions and 80 deletions.
2 changes: 1 addition & 1 deletion src/librustc/middle/intrinsicck.rs
Expand Up @@ -89,7 +89,7 @@ impl<'a, 'gcx, 'tcx> ExprVisitor<'a, 'gcx, 'tcx> {
let from = unpack_option_like(self.infcx.tcx.global_tcx(), from);
match (&from.sty, sk_to) {
(&ty::TyFnDef(..), SizeSkeleton::Known(size_to))
if size_to == Pointer.size(&self.infcx.tcx.data_layout) => {
if size_to == Pointer.size(self.infcx) => {
struct_span_err!(self.infcx.tcx.sess, span, E0591,
"`{}` is zero-sized and can't be transmuted to `{}`",
from, to)
Expand Down
140 changes: 104 additions & 36 deletions src/librustc/ty/layout.rs
Expand Up @@ -202,6 +202,16 @@ impl TargetDataLayout {
}
}

pub trait HasDataLayout: Copy {
fn data_layout(&self) -> &TargetDataLayout;
}

impl<'a> HasDataLayout for &'a TargetDataLayout {
fn data_layout(&self) -> &TargetDataLayout {
self
}
}

/// Endianness of the target, which must match cfg(target-endian).
#[derive(Copy, Clone)]
pub enum Endian {
Expand Down Expand Up @@ -242,7 +252,9 @@ impl Size {
Size::from_bytes((self.bytes() + mask) & !mask)
}

pub fn checked_add(self, offset: Size, dl: &TargetDataLayout) -> Option<Size> {
pub fn checked_add<C: HasDataLayout>(self, offset: Size, cx: C) -> Option<Size> {
let dl = cx.data_layout();

// Each Size is less than dl.obj_size_bound(), so the sum is
// also less than 1 << 62 (and therefore can't overflow).
let bytes = self.bytes() + offset.bytes();
Expand All @@ -254,7 +266,9 @@ impl Size {
}
}

pub fn checked_mul(self, count: u64, dl: &TargetDataLayout) -> Option<Size> {
pub fn checked_mul<C: HasDataLayout>(self, count: u64, cx: C) -> Option<Size> {
let dl = cx.data_layout();

// Each Size is less than dl.obj_size_bound(), so the sum is
// also less than 1 << 62 (and therefore can't overflow).
match self.bytes().checked_mul(count) {
Expand Down Expand Up @@ -354,7 +368,9 @@ impl Integer {
}
}

pub fn align(&self, dl: &TargetDataLayout)-> Align {
pub fn align<C: HasDataLayout>(&self, cx: C) -> Align {
let dl = cx.data_layout();

match *self {
I1 => dl.i1_align,
I8 => dl.i8_align,
Expand Down Expand Up @@ -408,7 +424,9 @@ impl Integer {
}

/// Find the smallest integer with the given alignment.
pub fn for_abi_align(dl: &TargetDataLayout, align: Align) -> Option<Integer> {
pub fn for_abi_align<C: HasDataLayout>(cx: C, align: Align) -> Option<Integer> {
let dl = cx.data_layout();

let wanted = align.abi();
for &candidate in &[I8, I16, I32, I64] {
let ty = Int(candidate);
Expand All @@ -420,7 +438,9 @@ impl Integer {
}

/// Get the Integer type from an attr::IntType.
pub fn from_attr(dl: &TargetDataLayout, ity: attr::IntType) -> Integer {
pub fn from_attr<C: HasDataLayout>(cx: C, ity: attr::IntType) -> Integer {
let dl = cx.data_layout();

match ity {
attr::SignedInt(IntTy::I8) | attr::UnsignedInt(UintTy::U8) => I8,
attr::SignedInt(IntTy::I16) | attr::UnsignedInt(UintTy::U16) => I16,
Expand Down Expand Up @@ -450,7 +470,7 @@ impl Integer {
let min_default = I8;

if let Some(ity) = repr.int {
let discr = Integer::from_attr(&tcx.data_layout, ity);
let discr = Integer::from_attr(tcx, ity);
let fit = if ity.is_signed() { signed_fit } else { unsigned_fit };
if discr < fit {
bug!("Integer::repr_discr: `#[repr]` hint too small for \
Expand Down Expand Up @@ -491,7 +511,9 @@ pub enum Primitive {
}

impl Primitive {
pub fn size(self, dl: &TargetDataLayout) -> Size {
pub fn size<C: HasDataLayout>(self, cx: C) -> Size {
let dl = cx.data_layout();

match self {
Int(I1) | Int(I8) => Size::from_bits(8),
Int(I16) => Size::from_bits(16),
Expand All @@ -502,7 +524,9 @@ impl Primitive {
}
}

pub fn align(self, dl: &TargetDataLayout) -> Align {
pub fn align<C: HasDataLayout>(self, cx: C) -> Align {
let dl = cx.data_layout();

match self {
Int(I1) => dl.i1_align,
Int(I8) => dl.i8_align,
Expand Down Expand Up @@ -682,8 +706,8 @@ impl<'a, 'gcx, 'tcx> Struct {
}

/// Determine whether a structure would be zero-sized, given its fields.
pub fn would_be_zero_sized<I>(dl: &TargetDataLayout, fields: I)
-> Result<bool, LayoutError<'gcx>>
fn would_be_zero_sized<I>(dl: &TargetDataLayout, fields: I)
-> Result<bool, LayoutError<'gcx>>
where I: Iterator<Item=Result<&'a Layout, LayoutError<'gcx>>> {
for field in fields {
let field = field?;
Expand Down Expand Up @@ -831,7 +855,7 @@ pub struct Union {
}

impl<'a, 'gcx, 'tcx> Union {
pub fn new(dl: &TargetDataLayout, packed: bool) -> Union {
fn new(dl: &TargetDataLayout, packed: bool) -> Union {
Union {
align: if packed { dl.i8_align } else { dl.aggregate_align },
min_size: Size::from_bytes(0),
Expand All @@ -840,10 +864,10 @@ impl<'a, 'gcx, 'tcx> Union {
}

/// Extend the Struct with more fields.
pub fn extend<I>(&mut self, dl: &TargetDataLayout,
fields: I,
scapegoat: Ty<'gcx>)
-> Result<(), LayoutError<'gcx>>
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?;
Expand Down Expand Up @@ -1452,7 +1476,9 @@ impl<'a, 'gcx, 'tcx> Layout {
}
}

pub fn size(&self, dl: &TargetDataLayout) -> Size {
pub fn size<C: HasDataLayout>(&self, cx: C) -> Size {
let dl = cx.data_layout();

match *self {
Scalar { value, .. } | RawNullablePointer { value, .. } => {
value.size(dl)
Expand Down Expand Up @@ -1494,7 +1520,9 @@ impl<'a, 'gcx, 'tcx> Layout {
}
}

pub fn align(&self, dl: &TargetDataLayout) -> Align {
pub fn align<C: HasDataLayout>(&self, cx: C) -> Align {
let dl = cx.data_layout();

match *self {
Scalar { value, .. } | RawNullablePointer { value, .. } => {
value.align(dl)
Expand Down Expand Up @@ -1534,11 +1562,13 @@ impl<'a, 'gcx, 'tcx> Layout {
}
}

pub fn field_offset(&self,
dl: &TargetDataLayout,
i: usize,
variant_index: Option<usize>)
-> Size {
pub fn field_offset<C: HasDataLayout>(&self,
cx: C,
i: usize,
variant_index: Option<usize>)
-> Size {
let dl = cx.data_layout();

match *self {
Scalar { .. } |
CEnum { .. } |
Expand Down Expand Up @@ -1617,7 +1647,7 @@ impl<'a, 'gcx, 'tcx> SizeSkeleton<'gcx> {
// First try computing a static layout.
let err = match ty.layout(infcx) {
Ok(layout) => {
return Ok(SizeSkeleton::Known(layout.size(&tcx.data_layout)));
return Ok(SizeSkeleton::Known(layout.size(tcx)));
}
Err(err) => err
};
Expand Down Expand Up @@ -1748,27 +1778,64 @@ impl<'tcx> Deref for TyLayout<'tcx> {
}
}

impl<'a, 'gcx, 'tcx> TyLayout<'gcx> {
pub fn of(infcx: &InferCtxt<'a, 'gcx, 'tcx>, ty: Ty<'gcx>)
-> Result<Self, LayoutError<'gcx>> {
let ty = normalize_associated_type(infcx, ty);
pub trait HasTyCtxt<'tcx>: HasDataLayout {
fn tcx<'a>(&'a self) -> TyCtxt<'a, 'tcx, 'tcx>;
}

impl<'a, 'gcx, 'tcx> HasDataLayout for TyCtxt<'a, 'gcx, 'tcx> {
fn data_layout(&self) -> &TargetDataLayout {
&self.data_layout
}
}

impl<'a, 'gcx, 'tcx> HasTyCtxt<'gcx> for TyCtxt<'a, 'gcx, 'tcx> {
fn tcx<'b>(&'b self) -> TyCtxt<'b, 'gcx, 'gcx> {
self.global_tcx()
}
}

impl<'a, 'gcx, 'tcx> HasDataLayout for &'a InferCtxt<'a, 'gcx, 'tcx> {
fn data_layout(&self) -> &TargetDataLayout {
&self.tcx.data_layout
}
}

impl<'a, 'gcx, 'tcx> HasTyCtxt<'gcx> for &'a InferCtxt<'a, 'gcx, 'tcx> {
fn tcx<'b>(&'b self) -> TyCtxt<'b, 'gcx, 'gcx> {
self.tcx.global_tcx()
}
}

pub trait LayoutTyper<'tcx>: HasTyCtxt<'tcx> {
type TyLayout;

fn layout_of(self, ty: Ty<'tcx>) -> Self::TyLayout;
}

impl<'a, 'gcx, 'tcx> LayoutTyper<'gcx> for &'a InferCtxt<'a, 'gcx, 'tcx> {
type TyLayout = Result<TyLayout<'gcx>, LayoutError<'gcx>>;

fn layout_of(self, ty: Ty<'gcx>) -> Self::TyLayout {
let ty = normalize_associated_type(self, ty);

Ok(TyLayout {
ty: ty,
layout: ty.layout(infcx)?,
layout: ty.layout(self)?,
variant_index: None
})
}
}

impl<'a, 'tcx> TyLayout<'tcx> {
pub fn for_variant(&self, variant_index: usize) -> Self {
TyLayout {
variant_index: Some(variant_index),
..*self
}
}

pub fn field_offset(&self, dl: &TargetDataLayout, i: usize) -> Size {
self.layout.field_offset(dl, i, self.variant_index)
pub fn field_offset<C: HasDataLayout>(&self, cx: C, i: usize) -> Size {
self.layout.field_offset(cx, i, self.variant_index)
}

pub fn field_count(&self) -> usize {
Expand Down Expand Up @@ -1808,9 +1875,11 @@ impl<'a, 'gcx, 'tcx> TyLayout<'gcx> {
}
}

pub fn field_type(&self, tcx: TyCtxt<'a, 'gcx, 'gcx>, i: usize) -> Ty<'gcx> {
let ptr_field_type = |pointee: Ty<'gcx>| {
let slice = |element: Ty<'gcx>| {
pub fn field_type<C: HasTyCtxt<'tcx>>(&self, cx: C, i: usize) -> Ty<'tcx> {
let tcx = cx.tcx();

let ptr_field_type = |pointee: Ty<'tcx>| {
let slice = |element: Ty<'tcx>| {
assert!(i < 2);
if i == 0 {
tcx.mk_mut_ptr(element)
Expand Down Expand Up @@ -1877,8 +1946,7 @@ impl<'a, 'gcx, 'tcx> TyLayout<'gcx> {
}
}

pub fn field(&self, infcx: &InferCtxt<'a, 'gcx, 'tcx>, i: usize)
-> Result<Self, LayoutError<'gcx>> {
TyLayout::of(infcx, self.field_type(infcx.tcx.global_tcx(), i))
pub fn field<C: LayoutTyper<'tcx>>(&self, cx: C, i: usize) -> C::TyLayout {
cx.layout_of(self.field_type(cx, i))
}
}
2 changes: 1 addition & 1 deletion src/librustc_lint/types.rs
Expand Up @@ -733,7 +733,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for VariantSizeDifferences {
});

if let Layout::General { ref variants, ref size, discr, .. } = *layout {
let discr_size = Primitive::Int(discr).size(&cx.tcx.data_layout).bytes();
let discr_size = Primitive::Int(discr).size(cx.tcx).bytes();

debug!("enum `{}` is {} bytes large with layout:\n{:#?}",
t, size.bytes(), layout);
Expand Down
2 changes: 1 addition & 1 deletion src/librustc_trans/abi.rs
Expand Up @@ -35,13 +35,13 @@ use type_of;

use rustc::hir;
use rustc::ty::{self, Ty};
use rustc::ty::layout::{Layout, LayoutTyper};

use libc::c_uint;
use std::cmp;

pub use syntax::abi::Abi;
pub use rustc::ty::layout::{FAT_PTR_ADDR, FAT_PTR_EXTRA};
use rustc::ty::layout::Layout;

#[derive(Clone, Copy, PartialEq, Debug)]
enum ArgKind {
Expand Down
5 changes: 2 additions & 3 deletions src/librustc_trans/adt.rs
Expand Up @@ -46,8 +46,8 @@ use super::Disr;
use std;

use llvm::{ValueRef, True, IntEQ, IntNE};
use rustc::ty::layout;
use rustc::ty::{self, Ty};
use rustc::ty::layout::{self, LayoutTyper};
use common::*;
use builder::Builder;
use base;
Expand Down Expand Up @@ -246,9 +246,8 @@ fn union_fill(cx: &CrateContext, size: u64, align: u64) -> Type {
assert_eq!(size%align, 0);
assert_eq!(align.count_ones(), 1, "Alignment must be a power fof 2. Got {}", align);
let align_units = size/align;
let dl = &cx.tcx().data_layout;
let layout_align = layout::Align::from_bytes(align, align).unwrap();
if let Some(ity) = layout::Integer::for_abi_align(dl, layout_align) {
if let Some(ity) = layout::Integer::for_abi_align(cx, layout_align) {
Type::array(&Type::from_integer(cx, ity), align_units)
} else {
Type::array(&Type::vector(&Type::i32(cx), align/4),
Expand Down
12 changes: 6 additions & 6 deletions src/librustc_trans/base.rs
Expand Up @@ -1295,8 +1295,8 @@ fn gather_type_sizes<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
// (delay format until we actually need it)
let record = |kind, opt_discr_size, variants| {
let type_desc = format!("{:?}", ty);
let overall_size = layout.size(&tcx.data_layout);
let align = layout.align(&tcx.data_layout);
let overall_size = layout.size(tcx);
let align = layout.align(tcx);
tcx.sess.code_stats.borrow_mut().record_type_size(kind,
type_desc,
align,
Expand Down Expand Up @@ -1332,8 +1332,8 @@ fn gather_type_sizes<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
session::FieldInfo {
name: field_name.to_string(),
offset: offset.bytes(),
size: field_layout.size(&tcx.data_layout).bytes(),
align: field_layout.align(&tcx.data_layout).abi(),
size: field_layout.size(tcx).bytes(),
align: field_layout.align(tcx).abi(),
}
}
}
Expand All @@ -1343,8 +1343,8 @@ fn gather_type_sizes<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
session::VariantInfo {
name: Some(name.to_string()),
kind: session::SizeKind::Exact,
align: value.align(&tcx.data_layout).abi(),
size: value.size(&tcx.data_layout).bytes(),
align: value.align(tcx).abi(),
size: value.size(tcx).bytes(),
fields: vec![],
}
};
Expand Down
6 changes: 3 additions & 3 deletions src/librustc_trans/common.rs
Expand Up @@ -27,7 +27,7 @@ use monomorphize;
use type_::Type;
use value::Value;
use rustc::ty::{self, Ty, TyCtxt};
use rustc::ty::layout::Layout;
use rustc::ty::layout::{Layout, LayoutTyper};
use rustc::ty::subst::{Subst, Substs};
use rustc::hir;

Expand Down Expand Up @@ -63,7 +63,7 @@ pub fn type_is_immediate<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ty: Ty<'tcx>) -
Layout::UntaggedUnion { .. } |
Layout::RawNullablePointer { .. } |
Layout::StructWrappedNullablePointer { .. } => {
!layout.is_unsized() && layout.size(&ccx.tcx().data_layout).bytes() == 0
!layout.is_unsized() && layout.size(ccx).bytes() == 0
}
}
}
Expand Down Expand Up @@ -126,7 +126,7 @@ pub fn type_is_imm_pair<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ty: Ty<'tcx>)
/// Identify types which have size zero at runtime.
pub fn type_is_zero_size<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ty: Ty<'tcx>) -> bool {
let layout = ccx.layout_of(ty);
!layout.is_unsized() && layout.size(&ccx.tcx().data_layout).bytes() == 0
!layout.is_unsized() && layout.size(ccx).bytes() == 0
}

/*
Expand Down

0 comments on commit 43b227f

Please sign in to comment.