Skip to content

Commit 49872b8

Browse files
committed
rustc: add a TyLayout helper for type-related layout queries.
1 parent a610117 commit 49872b8

File tree

3 files changed

+237
-13
lines changed

3 files changed

+237
-13
lines changed

src/librustc/ty/layout.rs

+234-10
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ use std::cmp;
2525
use std::fmt;
2626
use std::i64;
2727
use std::iter;
28+
use std::ops::Deref;
2829

2930
/// Parsed [Data layout](http://llvm.org/docs/LangRef.html#data-layout)
3031
/// for a target, which contains everything needed to compute layouts.
@@ -904,7 +905,8 @@ pub enum Layout {
904905
/// If true, the size is exact, otherwise it's only a lower bound.
905906
sized: bool,
906907
align: Align,
907-
size: Size
908+
element_size: Size,
909+
count: u64
908910
},
909911

910912
/// TyRawPtr or TyRef with a !Sized pointee.
@@ -1087,25 +1089,35 @@ impl<'a, 'gcx, 'tcx> Layout {
10871089
// Arrays and slices.
10881090
ty::TyArray(element, count) => {
10891091
let element = element.layout(infcx)?;
1092+
let element_size = element.size(dl);
1093+
// FIXME(eddyb) Don't use host `usize` for array lengths.
1094+
let usize_count: usize = count;
1095+
let count = usize_count as u64;
1096+
if element_size.checked_mul(count, dl).is_none() {
1097+
return Err(LayoutError::SizeOverflow(ty));
1098+
}
10901099
Array {
10911100
sized: true,
10921101
align: element.align(dl),
1093-
size: element.size(dl).checked_mul(count as u64, dl)
1094-
.map_or(Err(LayoutError::SizeOverflow(ty)), Ok)?
1102+
element_size: element_size,
1103+
count: count
10951104
}
10961105
}
10971106
ty::TySlice(element) => {
1107+
let element = element.layout(infcx)?;
10981108
Array {
10991109
sized: false,
1100-
align: element.layout(infcx)?.align(dl),
1101-
size: Size::from_bytes(0)
1110+
align: element.align(dl),
1111+
element_size: element.size(dl),
1112+
count: 0
11021113
}
11031114
}
11041115
ty::TyStr => {
11051116
Array {
11061117
sized: false,
11071118
align: dl.i8_align,
1108-
size: Size::from_bytes(0)
1119+
element_size: Size::from_bytes(1),
1120+
count: 0
11091121
}
11101122
}
11111123

@@ -1447,15 +1459,23 @@ impl<'a, 'gcx, 'tcx> Layout {
14471459
}
14481460

14491461
Vector { element, count } => {
1450-
let elem_size = element.size(dl);
1451-
let vec_size = match elem_size.checked_mul(count, dl) {
1462+
let element_size = element.size(dl);
1463+
let vec_size = match element_size.checked_mul(count, dl) {
14521464
Some(size) => size,
14531465
None => bug!("Layout::size({:?}): {} * {} overflowed",
1454-
self, elem_size.bytes(), count)
1466+
self, element_size.bytes(), count)
14551467
};
14561468
vec_size.abi_align(self.align(dl))
14571469
}
14581470

1471+
Array { element_size, count, .. } => {
1472+
match element_size.checked_mul(count, dl) {
1473+
Some(size) => size,
1474+
None => bug!("Layout::size({:?}): {} * {} overflowed",
1475+
self, element_size.bytes(), count)
1476+
}
1477+
}
1478+
14591479
FatPointer { metadata, .. } => {
14601480
// Effectively a (ptr, meta) tuple.
14611481
Pointer.size(dl).abi_align(metadata.align(dl))
@@ -1464,7 +1484,7 @@ impl<'a, 'gcx, 'tcx> Layout {
14641484
}
14651485

14661486
CEnum { discr, .. } => Int(discr).size(dl),
1467-
Array { size, .. } | General { size, .. } => size,
1487+
General { size, .. } => size,
14681488
UntaggedUnion { ref variants } => variants.stride(),
14691489

14701490
Univariant { ref variant, .. } |
@@ -1513,6 +1533,59 @@ impl<'a, 'gcx, 'tcx> Layout {
15131533
}
15141534
}
15151535
}
1536+
1537+
pub fn field_offset(&self,
1538+
dl: &TargetDataLayout,
1539+
i: usize,
1540+
variant_index: Option<usize>)
1541+
-> Size {
1542+
match *self {
1543+
Scalar { .. } |
1544+
CEnum { .. } |
1545+
UntaggedUnion { .. } |
1546+
RawNullablePointer { .. } => {
1547+
Size::from_bytes(0)
1548+
}
1549+
1550+
Vector { element, count } => {
1551+
let element_size = element.size(dl);
1552+
let i = i as u64;
1553+
assert!(i < count);
1554+
Size::from_bytes(element_size.bytes() * count)
1555+
}
1556+
1557+
Array { element_size, count, .. } => {
1558+
let i = i as u64;
1559+
assert!(i < count);
1560+
Size::from_bytes(element_size.bytes() * count)
1561+
}
1562+
1563+
FatPointer { metadata, .. } => {
1564+
// Effectively a (ptr, meta) tuple.
1565+
assert!(i < 2);
1566+
if i == 0 {
1567+
Size::from_bytes(0)
1568+
} else {
1569+
Pointer.size(dl).abi_align(metadata.align(dl))
1570+
}
1571+
}
1572+
1573+
Univariant { ref variant, .. } => variant.offsets[i],
1574+
1575+
General { ref variants, .. } => {
1576+
let v = variant_index.expect("variant index required");
1577+
variants[v].offsets[i + 1]
1578+
}
1579+
1580+
StructWrappedNullablePointer { nndiscr, ref nonnull, .. } => {
1581+
if Some(nndiscr as usize) == variant_index {
1582+
nonnull.offsets[i]
1583+
} else {
1584+
Size::from_bytes(0)
1585+
}
1586+
}
1587+
}
1588+
}
15161589
}
15171590

15181591
/// Type size "skeleton", i.e. the only information determining a type's size.
@@ -1658,3 +1731,154 @@ impl<'a, 'gcx, 'tcx> SizeSkeleton<'gcx> {
16581731
}
16591732
}
16601733
}
1734+
1735+
/// A pair of a type and its layout. Implements various
1736+
/// type traversal APIs (e.g. recursing into fields).
1737+
#[derive(Copy, Clone, Debug)]
1738+
pub struct TyLayout<'tcx> {
1739+
pub ty: Ty<'tcx>,
1740+
pub layout: &'tcx Layout,
1741+
pub variant_index: Option<usize>,
1742+
}
1743+
1744+
impl<'tcx> Deref for TyLayout<'tcx> {
1745+
type Target = Layout;
1746+
fn deref(&self) -> &Layout {
1747+
self.layout
1748+
}
1749+
}
1750+
1751+
impl<'a, 'gcx, 'tcx> TyLayout<'gcx> {
1752+
pub fn of(infcx: &InferCtxt<'a, 'gcx, 'tcx>, ty: Ty<'gcx>)
1753+
-> Result<Self, LayoutError<'gcx>> {
1754+
let ty = normalize_associated_type(infcx, ty);
1755+
1756+
Ok(TyLayout {
1757+
ty: ty,
1758+
layout: ty.layout(infcx)?,
1759+
variant_index: None
1760+
})
1761+
}
1762+
1763+
pub fn for_variant(&self, variant_index: usize) -> Self {
1764+
TyLayout {
1765+
variant_index: Some(variant_index),
1766+
..*self
1767+
}
1768+
}
1769+
1770+
pub fn field_offset(&self, dl: &TargetDataLayout, i: usize) -> Size {
1771+
self.layout.field_offset(dl, i, self.variant_index)
1772+
}
1773+
1774+
pub fn field_count(&self) -> usize {
1775+
// Handle enum/union through the type rather than Layout.
1776+
if let ty::TyAdt(def, _) = self.ty.sty {
1777+
let v = self.variant_index.unwrap_or(0);
1778+
if def.variants.is_empty() {
1779+
assert_eq!(v, 0);
1780+
return 0;
1781+
} else {
1782+
return def.variants[v].fields.len();
1783+
}
1784+
}
1785+
1786+
match *self.layout {
1787+
Scalar { .. } => {
1788+
bug!("TyLayout::field_count({:?}): not applicable", self)
1789+
}
1790+
1791+
// Handled above (the TyAdt case).
1792+
CEnum { .. } |
1793+
General { .. } |
1794+
UntaggedUnion { .. } |
1795+
RawNullablePointer { .. } |
1796+
StructWrappedNullablePointer { .. } => bug!(),
1797+
1798+
FatPointer { .. } => 2,
1799+
1800+
Vector { count, .. } |
1801+
Array { count, .. } => {
1802+
let usize_count = count as usize;
1803+
assert_eq!(usize_count as u64, count);
1804+
usize_count
1805+
}
1806+
1807+
Univariant { ref variant, .. } => variant.offsets.len(),
1808+
}
1809+
}
1810+
1811+
pub fn field_type(&self, tcx: TyCtxt<'a, 'gcx, 'gcx>, i: usize) -> Ty<'gcx> {
1812+
let ptr_field_type = |pointee: Ty<'gcx>| {
1813+
let slice = |element: Ty<'gcx>| {
1814+
assert!(i < 2);
1815+
if i == 0 {
1816+
tcx.mk_mut_ptr(element)
1817+
} else {
1818+
tcx.types.usize
1819+
}
1820+
};
1821+
match tcx.struct_tail(pointee).sty {
1822+
ty::TySlice(element) => slice(element),
1823+
ty::TyStr => slice(tcx.types.u8),
1824+
ty::TyDynamic(..) => tcx.mk_mut_ptr(tcx.mk_nil()),
1825+
_ => bug!("TyLayout::field_type({:?}): not applicable", self)
1826+
}
1827+
};
1828+
1829+
match self.ty.sty {
1830+
ty::TyBool |
1831+
ty::TyChar |
1832+
ty::TyInt(_) |
1833+
ty::TyUint(_) |
1834+
ty::TyFloat(_) |
1835+
ty::TyFnPtr(_) |
1836+
ty::TyNever |
1837+
ty::TyFnDef(..) |
1838+
ty::TyDynamic(..) => {
1839+
bug!("TyLayout::field_type({:?}): not applicable", self)
1840+
}
1841+
1842+
// Potentially-fat pointers.
1843+
ty::TyRef(_, ty::TypeAndMut { ty: pointee, .. }) |
1844+
ty::TyRawPtr(ty::TypeAndMut { ty: pointee, .. }) => {
1845+
ptr_field_type(pointee)
1846+
}
1847+
ty::TyAdt(def, _) if def.is_box() => {
1848+
ptr_field_type(self.ty.boxed_ty())
1849+
}
1850+
1851+
// Arrays and slices.
1852+
ty::TyArray(element, _) |
1853+
ty::TySlice(element) => element,
1854+
ty::TyStr => tcx.types.u8,
1855+
1856+
// Tuples and closures.
1857+
ty::TyClosure(def_id, ref substs) => {
1858+
substs.upvar_tys(def_id, tcx).nth(i).unwrap()
1859+
}
1860+
1861+
ty::TyTuple(tys, _) => tys[i],
1862+
1863+
// SIMD vector types.
1864+
ty::TyAdt(def, ..) if def.repr.simd => {
1865+
self.ty.simd_type(tcx)
1866+
}
1867+
1868+
// ADTs.
1869+
ty::TyAdt(def, substs) => {
1870+
def.variants[self.variant_index.unwrap_or(0)].fields[i].ty(tcx, substs)
1871+
}
1872+
1873+
ty::TyProjection(_) | ty::TyAnon(..) | ty::TyParam(_) |
1874+
ty::TyInfer(_) | ty::TyError => {
1875+
bug!("TyLayout::field_type: unexpected type `{}`", self.ty)
1876+
}
1877+
}
1878+
}
1879+
1880+
pub fn field(&self, infcx: &InferCtxt<'a, 'gcx, 'tcx>, i: usize)
1881+
-> Result<Self, LayoutError<'gcx>> {
1882+
TyLayout::of(infcx, self.field_type(infcx.tcx.global_tcx(), i))
1883+
}
1884+
}

src/librustc_trans/context.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -828,9 +828,9 @@ impl<'b, 'tcx> CrateContext<'b, 'tcx> {
828828
TypeOfDepthLock(self.local())
829829
}
830830

831-
pub fn layout_of(&self, ty: Ty<'tcx>) -> &'tcx ty::layout::Layout {
831+
pub fn layout_of(&self, ty: Ty<'tcx>) -> ty::layout::TyLayout<'tcx> {
832832
self.tcx().infer_ctxt((), traits::Reveal::All).enter(|infcx| {
833-
ty.layout(&infcx).unwrap_or_else(|e| {
833+
ty::layout::TyLayout::of(&infcx, ty).unwrap_or_else(|e| {
834834
match e {
835835
ty::layout::LayoutError::SizeOverflow(_) =>
836836
self.sess().fatal(&e.to_string()),

src/librustc_trans/debuginfo/metadata.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1564,7 +1564,7 @@ fn prepare_enum_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
15641564
enum_llvm_type,
15651565
EnumMDF(EnumMemberDescriptionFactory {
15661566
enum_type: enum_type,
1567-
type_rep: type_rep,
1567+
type_rep: type_rep.layout,
15681568
discriminant_type_metadata: discriminant_type_metadata,
15691569
containing_scope: containing_scope,
15701570
file_metadata: file_metadata,

0 commit comments

Comments
 (0)