Skip to content

Commit 9768ef5

Browse files
committed
rustc: add a TyLayout helper for type-related layout queries.
1 parent 58c701f commit 9768ef5

File tree

3 files changed

+267
-13
lines changed

3 files changed

+267
-13
lines changed

src/librustc/ty/layout.rs

+264-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,33 @@ 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+
let count = count as u64;
1094+
if element_size.checked_mul(count, dl).is_none() {
1095+
return Err(LayoutError::SizeOverflow(ty));
1096+
}
10901097
Array {
10911098
sized: true,
10921099
align: element.align(dl),
1093-
size: element.size(dl).checked_mul(count as u64, dl)
1094-
.map_or(Err(LayoutError::SizeOverflow(ty)), Ok)?
1100+
element_size: element_size,
1101+
count: count
10951102
}
10961103
}
10971104
ty::TySlice(element) => {
1105+
let element = element.layout(infcx)?;
10981106
Array {
10991107
sized: false,
1100-
align: element.layout(infcx)?.align(dl),
1101-
size: Size::from_bytes(0)
1108+
align: element.align(dl),
1109+
element_size: element.size(dl),
1110+
count: 0
11021111
}
11031112
}
11041113
ty::TyStr => {
11051114
Array {
11061115
sized: false,
11071116
align: dl.i8_align,
1108-
size: Size::from_bytes(0)
1117+
element_size: Size::from_bytes(1),
1118+
count: 0
11091119
}
11101120
}
11111121

@@ -1447,15 +1457,23 @@ impl<'a, 'gcx, 'tcx> Layout {
14471457
}
14481458

14491459
Vector { element, count } => {
1450-
let elem_size = element.size(dl);
1451-
let vec_size = match elem_size.checked_mul(count, dl) {
1460+
let element_size = element.size(dl);
1461+
let vec_size = match element_size.checked_mul(count, dl) {
14521462
Some(size) => size,
14531463
None => bug!("Layout::size({:?}): {} * {} overflowed",
1454-
self, elem_size.bytes(), count)
1464+
self, element_size.bytes(), count)
14551465
};
14561466
vec_size.abi_align(self.align(dl))
14571467
}
14581468

1469+
Array { element_size, count, .. } => {
1470+
match element_size.checked_mul(count, dl) {
1471+
Some(size) => size,
1472+
None => bug!("Layout::size({:?}): {} * {} overflowed",
1473+
self, element_size.bytes(), count)
1474+
}
1475+
}
1476+
14591477
FatPointer { metadata, .. } => {
14601478
// Effectively a (ptr, meta) tuple.
14611479
Pointer.size(dl).abi_align(metadata.align(dl))
@@ -1464,7 +1482,7 @@ impl<'a, 'gcx, 'tcx> Layout {
14641482
}
14651483

14661484
CEnum { discr, .. } => Int(discr).size(dl),
1467-
Array { size, .. } | General { size, .. } => size,
1485+
General { size, .. } => size,
14681486
UntaggedUnion { ref variants } => variants.stride(),
14691487

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

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

src/librustc_trans/context.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -831,9 +831,9 @@ impl<'b, 'tcx> CrateContext<'b, 'tcx> {
831831
TypeOfDepthLock(self.local())
832832
}
833833

834-
pub fn layout_of(&self, ty: Ty<'tcx>) -> &'tcx ty::layout::Layout {
834+
pub fn layout_of(&self, ty: Ty<'tcx>) -> ty::layout::TyLayout<'tcx> {
835835
self.tcx().infer_ctxt((), traits::Reveal::All).enter(|infcx| {
836-
ty.layout(&infcx).unwrap_or_else(|e| {
836+
ty::layout::TyLayout::of(&infcx, ty).unwrap_or_else(|e| {
837837
match e {
838838
ty::layout::LayoutError::SizeOverflow(_) =>
839839
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)