]> git.proxmox.com Git - rustc.git/blame - src/librustc/ty/layout.rs
New upstream version 1.21.0+dfsg1
[rustc.git] / src / librustc / ty / layout.rs
CommitLineData
54a0048b
SL
1// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
2// file at the top-level directory of this distribution and at
3// http://rust-lang.org/COPYRIGHT.
4//
5// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8// option. This file may not be copied, modified, or distributed
9// except according to those terms.
10
11pub use self::Integer::*;
12pub use self::Layout::*;
13pub use self::Primitive::*;
14
7cac9316 15use session::{self, DataTypeKind, Session};
cc61c64b 16use ty::{self, Ty, TyCtxt, TypeFoldable, ReprOptions, ReprFlags};
54a0048b 17
7cac9316 18use syntax::ast::{self, FloatTy, IntTy, UintTy};
54a0048b 19use syntax::attr;
3157f602 20use syntax_pos::DUMMY_SP;
54a0048b
SL
21
22use std::cmp;
23use std::fmt;
24use std::i64;
476ff2be 25use std::iter;
cc61c64b 26use std::ops::Deref;
54a0048b
SL
27
28/// Parsed [Data layout](http://llvm.org/docs/LangRef.html#data-layout)
29/// for a target, which contains everything needed to compute layouts.
30pub struct TargetDataLayout {
31 pub endian: Endian,
32 pub i1_align: Align,
33 pub i8_align: Align,
34 pub i16_align: Align,
35 pub i32_align: Align,
36 pub i64_align: Align,
32a655c1 37 pub i128_align: Align,
54a0048b
SL
38 pub f32_align: Align,
39 pub f64_align: Align,
40 pub pointer_size: Size,
41 pub pointer_align: Align,
42 pub aggregate_align: Align,
43
44 /// Alignments for vector types.
45 pub vector_align: Vec<(Size, Align)>
46}
47
48impl Default for TargetDataLayout {
9e0c209e 49 /// Creates an instance of `TargetDataLayout`.
54a0048b
SL
50 fn default() -> TargetDataLayout {
51 TargetDataLayout {
52 endian: Endian::Big,
53 i1_align: Align::from_bits(8, 8).unwrap(),
54 i8_align: Align::from_bits(8, 8).unwrap(),
55 i16_align: Align::from_bits(16, 16).unwrap(),
56 i32_align: Align::from_bits(32, 32).unwrap(),
57 i64_align: Align::from_bits(32, 64).unwrap(),
32a655c1 58 i128_align: Align::from_bits(32, 64).unwrap(),
54a0048b
SL
59 f32_align: Align::from_bits(32, 32).unwrap(),
60 f64_align: Align::from_bits(64, 64).unwrap(),
61 pointer_size: Size::from_bits(64),
62 pointer_align: Align::from_bits(64, 64).unwrap(),
63 aggregate_align: Align::from_bits(0, 64).unwrap(),
64 vector_align: vec![
65 (Size::from_bits(64), Align::from_bits(64, 64).unwrap()),
66 (Size::from_bits(128), Align::from_bits(128, 128).unwrap())
67 ]
68 }
69 }
70}
71
72impl TargetDataLayout {
73 pub fn parse(sess: &Session) -> TargetDataLayout {
74 // Parse a bit count from a string.
75 let parse_bits = |s: &str, kind: &str, cause: &str| {
76 s.parse::<u64>().unwrap_or_else(|err| {
77 sess.err(&format!("invalid {} `{}` for `{}` in \"data-layout\": {}",
78 kind, s, cause, err));
79 0
80 })
81 };
82
83 // Parse a size string.
84 let size = |s: &str, cause: &str| {
85 Size::from_bits(parse_bits(s, "size", cause))
86 };
87
88 // Parse an alignment string.
89 let align = |s: &[&str], cause: &str| {
90 if s.is_empty() {
91 sess.err(&format!("missing alignment for `{}` in \"data-layout\"", cause));
92 }
93 let abi = parse_bits(s[0], "alignment", cause);
94 let pref = s.get(1).map_or(abi, |pref| parse_bits(pref, "alignment", cause));
95 Align::from_bits(abi, pref).unwrap_or_else(|err| {
96 sess.err(&format!("invalid alignment for `{}` in \"data-layout\": {}",
97 cause, err));
98 Align::from_bits(8, 8).unwrap()
99 })
100 };
101
102 let mut dl = TargetDataLayout::default();
32a655c1 103 let mut i128_align_src = 64;
54a0048b 104 for spec in sess.target.target.data_layout.split("-") {
5bcae85e 105 match &spec.split(":").collect::<Vec<_>>()[..] {
3157f602
XL
106 &["e"] => dl.endian = Endian::Little,
107 &["E"] => dl.endian = Endian::Big,
108 &["a", ref a..] => dl.aggregate_align = align(a, "a"),
109 &["f32", ref a..] => dl.f32_align = align(a, "f32"),
110 &["f64", ref a..] => dl.f64_align = align(a, "f64"),
111 &[p @ "p", s, ref a..] | &[p @ "p0", s, ref a..] => {
54a0048b
SL
112 dl.pointer_size = size(s, p);
113 dl.pointer_align = align(a, p);
114 }
3157f602 115 &[s, ref a..] if s.starts_with("i") => {
32a655c1
SL
116 let bits = match s[1..].parse::<u64>() {
117 Ok(bits) => bits,
54a0048b
SL
118 Err(_) => {
119 size(&s[1..], "i"); // For the user error.
120 continue;
121 }
122 };
32a655c1
SL
123 let a = align(a, s);
124 match bits {
125 1 => dl.i1_align = a,
126 8 => dl.i8_align = a,
127 16 => dl.i16_align = a,
128 32 => dl.i32_align = a,
129 64 => dl.i64_align = a,
130 _ => {}
131 }
132 if bits >= i128_align_src && bits <= 128 {
133 // Default alignment for i128 is decided by taking the alignment of
134 // largest-sized i{64...128}.
135 i128_align_src = bits;
136 dl.i128_align = a;
137 }
54a0048b 138 }
3157f602 139 &[s, ref a..] if s.starts_with("v") => {
54a0048b
SL
140 let v_size = size(&s[1..], "v");
141 let a = align(a, s);
142 if let Some(v) = dl.vector_align.iter_mut().find(|v| v.0 == v_size) {
143 v.1 = a;
144 continue;
145 }
146 // No existing entry, add a new one.
147 dl.vector_align.push((v_size, a));
148 }
149 _ => {} // Ignore everything else.
150 }
151 }
152
153 // Perform consistency checks against the Target information.
154 let endian_str = match dl.endian {
155 Endian::Little => "little",
156 Endian::Big => "big"
157 };
158 if endian_str != sess.target.target.target_endian {
159 sess.err(&format!("inconsistent target specification: \"data-layout\" claims \
160 architecture is {}-endian, while \"target-endian\" is `{}`",
161 endian_str, sess.target.target.target_endian));
162 }
163
164 if dl.pointer_size.bits().to_string() != sess.target.target.target_pointer_width {
165 sess.err(&format!("inconsistent target specification: \"data-layout\" claims \
166 pointers are {}-bit, while \"target-pointer-width\" is `{}`",
167 dl.pointer_size.bits(), sess.target.target.target_pointer_width));
168 }
169
170 dl
171 }
172
173 /// Return exclusive upper bound on object size.
174 ///
175 /// The theoretical maximum object size is defined as the maximum positive `isize` value.
176 /// This ensures that the `offset` semantics remain well-defined by allowing it to correctly
177 /// index every address within an object along with one byte past the end, along with allowing
178 /// `isize` to store the difference between any two pointers into an object.
179 ///
180 /// The upper bound on 64-bit currently needs to be lower because LLVM uses a 64-bit integer
181 /// to represent object size in bits. It would need to be 1 << 61 to account for this, but is
182 /// currently conservatively bounded to 1 << 47 as that is enough to cover the current usable
183 /// address space on 64-bit ARMv8 and x86_64.
184 pub fn obj_size_bound(&self) -> u64 {
185 match self.pointer_size.bits() {
3157f602 186 16 => 1 << 15,
54a0048b
SL
187 32 => 1 << 31,
188 64 => 1 << 47,
189 bits => bug!("obj_size_bound: unknown pointer bit size {}", bits)
190 }
191 }
192
193 pub fn ptr_sized_integer(&self) -> Integer {
194 match self.pointer_size.bits() {
3157f602 195 16 => I16,
54a0048b
SL
196 32 => I32,
197 64 => I64,
198 bits => bug!("ptr_sized_integer: unknown pointer bit size {}", bits)
199 }
200 }
201}
202
cc61c64b
XL
203pub trait HasDataLayout: Copy {
204 fn data_layout(&self) -> &TargetDataLayout;
205}
206
207impl<'a> HasDataLayout for &'a TargetDataLayout {
208 fn data_layout(&self) -> &TargetDataLayout {
209 self
210 }
211}
212
7cac9316
XL
213impl<'a, 'tcx> HasDataLayout for TyCtxt<'a, 'tcx, 'tcx> {
214 fn data_layout(&self) -> &TargetDataLayout {
215 &self.data_layout
216 }
217}
218
54a0048b
SL
219/// Endianness of the target, which must match cfg(target-endian).
220#[derive(Copy, Clone)]
221pub enum Endian {
222 Little,
223 Big
224}
225
226/// Size of a type in bytes.
227#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
228pub struct Size {
229 raw: u64
230}
231
232impl Size {
233 pub fn from_bits(bits: u64) -> Size {
234 Size::from_bytes((bits + 7) / 8)
235 }
236
237 pub fn from_bytes(bytes: u64) -> Size {
238 if bytes >= (1 << 61) {
239 bug!("Size::from_bytes: {} bytes in bits doesn't fit in u64", bytes)
240 }
241 Size {
242 raw: bytes
243 }
244 }
245
246 pub fn bytes(self) -> u64 {
247 self.raw
248 }
249
250 pub fn bits(self) -> u64 {
251 self.bytes() * 8
252 }
253
254 pub fn abi_align(self, align: Align) -> Size {
255 let mask = align.abi() - 1;
256 Size::from_bytes((self.bytes() + mask) & !mask)
257 }
258
cc61c64b
XL
259 pub fn checked_add<C: HasDataLayout>(self, offset: Size, cx: C) -> Option<Size> {
260 let dl = cx.data_layout();
261
54a0048b
SL
262 // Each Size is less than dl.obj_size_bound(), so the sum is
263 // also less than 1 << 62 (and therefore can't overflow).
264 let bytes = self.bytes() + offset.bytes();
265
266 if bytes < dl.obj_size_bound() {
267 Some(Size::from_bytes(bytes))
268 } else {
269 None
270 }
271 }
272
cc61c64b
XL
273 pub fn checked_mul<C: HasDataLayout>(self, count: u64, cx: C) -> Option<Size> {
274 let dl = cx.data_layout();
275
54a0048b
SL
276 // Each Size is less than dl.obj_size_bound(), so the sum is
277 // also less than 1 << 62 (and therefore can't overflow).
278 match self.bytes().checked_mul(count) {
279 Some(bytes) if bytes < dl.obj_size_bound() => {
280 Some(Size::from_bytes(bytes))
281 }
282 _ => None
283 }
284 }
285}
286
287/// Alignment of a type in bytes, both ABI-mandated and preferred.
041b39d2
XL
288/// Each field is a power of two, giving the alignment a maximum
289/// value of 2^(2^8 - 1), which is limited by LLVM to a i32, with
290/// a maximum capacity of 2^31 - 1 or 2147483647.
54a0048b
SL
291#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
292pub struct Align {
041b39d2
XL
293 abi: u8,
294 pref: u8,
54a0048b
SL
295}
296
297impl Align {
298 pub fn from_bits(abi: u64, pref: u64) -> Result<Align, String> {
299 Align::from_bytes((abi + 7) / 8, (pref + 7) / 8)
300 }
301
302 pub fn from_bytes(abi: u64, pref: u64) -> Result<Align, String> {
041b39d2 303 let log2 = |align: u64| {
54a0048b
SL
304 // Treat an alignment of 0 bytes like 1-byte alignment.
305 if align == 0 {
306 return Ok(0);
307 }
308
309 let mut bytes = align;
310 let mut pow: u8 = 0;
311 while (bytes & 1) == 0 {
312 pow += 1;
313 bytes >>= 1;
314 }
315 if bytes != 1 {
316 Err(format!("`{}` is not a power of 2", align))
041b39d2 317 } else if pow > 30 {
54a0048b
SL
318 Err(format!("`{}` is too large", align))
319 } else {
320 Ok(pow)
321 }
322 };
323
324 Ok(Align {
041b39d2
XL
325 abi: log2(abi)?,
326 pref: log2(pref)?,
54a0048b
SL
327 })
328 }
329
330 pub fn abi(self) -> u64 {
041b39d2 331 1 << self.abi
54a0048b
SL
332 }
333
334 pub fn pref(self) -> u64 {
041b39d2 335 1 << self.pref
54a0048b
SL
336 }
337
338 pub fn min(self, other: Align) -> Align {
54a0048b 339 Align {
041b39d2
XL
340 abi: cmp::min(self.abi, other.abi),
341 pref: cmp::min(self.pref, other.pref),
54a0048b
SL
342 }
343 }
344
345 pub fn max(self, other: Align) -> Align {
54a0048b 346 Align {
041b39d2
XL
347 abi: cmp::max(self.abi, other.abi),
348 pref: cmp::max(self.pref, other.pref),
54a0048b
SL
349 }
350 }
351}
352
353/// Integers, also used for enum discriminants.
354#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
355pub enum Integer {
356 I1,
357 I8,
358 I16,
359 I32,
32a655c1
SL
360 I64,
361 I128,
54a0048b
SL
362}
363
364impl Integer {
9e0c209e
SL
365 pub fn size(&self) -> Size {
366 match *self {
367 I1 => Size::from_bits(1),
368 I8 => Size::from_bytes(1),
369 I16 => Size::from_bytes(2),
370 I32 => Size::from_bytes(4),
371 I64 => Size::from_bytes(8),
32a655c1 372 I128 => Size::from_bytes(16),
9e0c209e
SL
373 }
374 }
375
cc61c64b
XL
376 pub fn align<C: HasDataLayout>(&self, cx: C) -> Align {
377 let dl = cx.data_layout();
378
9e0c209e
SL
379 match *self {
380 I1 => dl.i1_align,
381 I8 => dl.i8_align,
382 I16 => dl.i16_align,
383 I32 => dl.i32_align,
384 I64 => dl.i64_align,
32a655c1 385 I128 => dl.i128_align,
9e0c209e
SL
386 }
387 }
388
389 pub fn to_ty<'a, 'tcx>(&self, tcx: &ty::TyCtxt<'a, 'tcx, 'tcx>,
390 signed: bool) -> Ty<'tcx> {
391 match (*self, signed) {
392 (I1, false) => tcx.types.u8,
393 (I8, false) => tcx.types.u8,
394 (I16, false) => tcx.types.u16,
395 (I32, false) => tcx.types.u32,
396 (I64, false) => tcx.types.u64,
32a655c1 397 (I128, false) => tcx.types.u128,
9e0c209e
SL
398 (I1, true) => tcx.types.i8,
399 (I8, true) => tcx.types.i8,
400 (I16, true) => tcx.types.i16,
401 (I32, true) => tcx.types.i32,
402 (I64, true) => tcx.types.i64,
32a655c1 403 (I128, true) => tcx.types.i128,
9e0c209e
SL
404 }
405 }
406
54a0048b
SL
407 /// Find the smallest Integer type which can represent the signed value.
408 pub fn fit_signed(x: i64) -> Integer {
409 match x {
32a655c1
SL
410 -0x0000_0000_0000_0001...0x0000_0000_0000_0000 => I1,
411 -0x0000_0000_0000_0080...0x0000_0000_0000_007f => I8,
412 -0x0000_0000_0000_8000...0x0000_0000_0000_7fff => I16,
413 -0x0000_0000_8000_0000...0x0000_0000_7fff_ffff => I32,
414 -0x8000_0000_0000_0000...0x7fff_ffff_ffff_ffff => I64,
415 _ => I128
54a0048b
SL
416 }
417 }
418
419 /// Find the smallest Integer type which can represent the unsigned value.
420 pub fn fit_unsigned(x: u64) -> Integer {
421 match x {
32a655c1
SL
422 0...0x0000_0000_0000_0001 => I1,
423 0...0x0000_0000_0000_00ff => I8,
424 0...0x0000_0000_0000_ffff => I16,
425 0...0x0000_0000_ffff_ffff => I32,
426 0...0xffff_ffff_ffff_ffff => I64,
427 _ => I128,
54a0048b
SL
428 }
429 }
430
9e0c209e 431 /// Find the smallest integer with the given alignment.
cc61c64b
XL
432 pub fn for_abi_align<C: HasDataLayout>(cx: C, align: Align) -> Option<Integer> {
433 let dl = cx.data_layout();
434
9e0c209e
SL
435 let wanted = align.abi();
436 for &candidate in &[I8, I16, I32, I64] {
437 let ty = Int(candidate);
438 if wanted == ty.align(dl).abi() && wanted == ty.size(dl).bytes() {
439 return Some(candidate);
440 }
441 }
442 None
443 }
444
54a0048b 445 /// Get the Integer type from an attr::IntType.
cc61c64b
XL
446 pub fn from_attr<C: HasDataLayout>(cx: C, ity: attr::IntType) -> Integer {
447 let dl = cx.data_layout();
448
54a0048b
SL
449 match ity {
450 attr::SignedInt(IntTy::I8) | attr::UnsignedInt(UintTy::U8) => I8,
451 attr::SignedInt(IntTy::I16) | attr::UnsignedInt(UintTy::U16) => I16,
452 attr::SignedInt(IntTy::I32) | attr::UnsignedInt(UintTy::U32) => I32,
453 attr::SignedInt(IntTy::I64) | attr::UnsignedInt(UintTy::U64) => I64,
32a655c1 454 attr::SignedInt(IntTy::I128) | attr::UnsignedInt(UintTy::U128) => I128,
54a0048b
SL
455 attr::SignedInt(IntTy::Is) | attr::UnsignedInt(UintTy::Us) => {
456 dl.ptr_sized_integer()
457 }
458 }
459 }
460
461 /// Find the appropriate Integer type and signedness for the given
462 /// signed discriminant range and #[repr] attribute.
463 /// N.B.: u64 values above i64::MAX will be treated as signed, but
464 /// that shouldn't affect anything, other than maybe debuginfo.
7cac9316
XL
465 fn repr_discr<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
466 ty: Ty<'tcx>,
467 repr: &ReprOptions,
468 min: i64,
469 max: i64)
470 -> (Integer, bool) {
54a0048b
SL
471 // Theoretically, negative values could be larger in unsigned representation
472 // than the unsigned representation of the signed minimum. However, if there
473 // are any negative values, the only valid unsigned representation is u64
474 // which can fit all i64 values, so the result remains unaffected.
475 let unsigned_fit = Integer::fit_unsigned(cmp::max(min as u64, max as u64));
476 let signed_fit = cmp::max(Integer::fit_signed(min), Integer::fit_signed(max));
477
476ff2be
SL
478 let mut min_from_extern = None;
479 let min_default = I8;
480
8bb4bdeb 481 if let Some(ity) = repr.int {
cc61c64b 482 let discr = Integer::from_attr(tcx, ity);
8bb4bdeb
XL
483 let fit = if ity.is_signed() { signed_fit } else { unsigned_fit };
484 if discr < fit {
485 bug!("Integer::repr_discr: `#[repr]` hint too small for \
486 discriminant range of enum `{}", ty)
487 }
488 return (discr, ity.is_signed());
489 }
490
cc61c64b 491 if repr.c() {
8bb4bdeb
XL
492 match &tcx.sess.target.target.arch[..] {
493 // WARNING: the ARM EABI has two variants; the one corresponding
494 // to `at_least == I32` appears to be used on Linux and NetBSD,
495 // but some systems may use the variant corresponding to no
496 // lower bound. However, we don't run on those yet...?
497 "arm" => min_from_extern = Some(I32),
498 _ => min_from_extern = Some(I32),
54a0048b 499 }
476ff2be
SL
500 }
501
502 let at_least = min_from_extern.unwrap_or(min_default);
54a0048b
SL
503
504 // If there are no negative values, we can use the unsigned fit.
505 if min >= 0 {
506 (cmp::max(unsigned_fit, at_least), false)
507 } else {
508 (cmp::max(signed_fit, at_least), true)
509 }
510 }
511}
512
513/// Fundamental unit of memory access and layout.
514#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
515pub enum Primitive {
516 Int(Integer),
517 F32,
518 F64,
519 Pointer
520}
521
522impl Primitive {
cc61c64b
XL
523 pub fn size<C: HasDataLayout>(self, cx: C) -> Size {
524 let dl = cx.data_layout();
525
54a0048b
SL
526 match self {
527 Int(I1) | Int(I8) => Size::from_bits(8),
528 Int(I16) => Size::from_bits(16),
529 Int(I32) | F32 => Size::from_bits(32),
530 Int(I64) | F64 => Size::from_bits(64),
32a655c1 531 Int(I128) => Size::from_bits(128),
54a0048b
SL
532 Pointer => dl.pointer_size
533 }
534 }
535
cc61c64b
XL
536 pub fn align<C: HasDataLayout>(self, cx: C) -> Align {
537 let dl = cx.data_layout();
538
54a0048b
SL
539 match self {
540 Int(I1) => dl.i1_align,
541 Int(I8) => dl.i8_align,
542 Int(I16) => dl.i16_align,
543 Int(I32) => dl.i32_align,
544 Int(I64) => dl.i64_align,
32a655c1 545 Int(I128) => dl.i128_align,
54a0048b
SL
546 F32 => dl.f32_align,
547 F64 => dl.f64_align,
548 Pointer => dl.pointer_align
549 }
550 }
551}
552
553/// Path through fields of nested structures.
554// FIXME(eddyb) use small vector optimization for the common case.
555pub type FieldPath = Vec<u32>;
556
557/// A structure, a product type in ADT terms.
558#[derive(PartialEq, Eq, Hash, Debug)]
559pub struct Struct {
cc61c64b 560 /// Maximum alignment of fields and repr alignment.
54a0048b
SL
561 pub align: Align,
562
cc61c64b
XL
563 /// Primitive alignment of fields without repr alignment.
564 pub primitive_align: Align,
565
54a0048b
SL
566 /// If true, no alignment padding is used.
567 pub packed: bool,
568
569 /// If true, the size is exact, otherwise it's only a lower bound.
570 pub sized: bool,
571
476ff2be
SL
572 /// Offsets for the first byte of each field, ordered to match the source definition order.
573 /// This vector does not go in increasing order.
c30ab7b3
SL
574 /// FIXME(eddyb) use small vector optimization for the common case.
575 pub offsets: Vec<Size>,
576
476ff2be
SL
577 /// Maps source order field indices to memory order indices, depending how fields were permuted.
578 /// FIXME (camlorn) also consider small vector optimization here.
579 pub memory_index: Vec<u32>,
580
c30ab7b3 581 pub min_size: Size,
54a0048b
SL
582}
583
3b2f2976 584/// Info required to optimize struct layout.
476ff2be
SL
585#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Debug)]
586enum StructKind {
3b2f2976 587 /// A tuple, closure, or univariant which cannot be coerced to unsized.
476ff2be 588 AlwaysSizedUnivariant,
3b2f2976 589 /// A univariant, the last field of which may be coerced to unsized.
476ff2be 590 MaybeUnsizedUnivariant,
3b2f2976 591 /// A univariant, but part of an enum.
476ff2be
SL
592 EnumVariant,
593}
594
7cac9316
XL
595impl<'a, 'tcx> Struct {
596 fn new(dl: &TargetDataLayout,
597 fields: &Vec<&'a Layout>,
598 repr: &ReprOptions,
599 kind: StructKind,
600 scapegoat: Ty<'tcx>)
601 -> Result<Struct, LayoutError<'tcx>> {
cc61c64b
XL
602 if repr.packed() && repr.align > 0 {
603 bug!("Struct cannot be packed and aligned");
604 }
605
606 let align = if repr.packed() {
607 dl.i8_align
608 } else {
609 dl.aggregate_align
610 };
611
476ff2be 612 let mut ret = Struct {
041b39d2 613 align,
cc61c64b
XL
614 primitive_align: align,
615 packed: repr.packed(),
54a0048b 616 sized: true,
c30ab7b3 617 offsets: vec![],
476ff2be 618 memory_index: vec![],
c30ab7b3 619 min_size: Size::from_bytes(0),
476ff2be
SL
620 };
621
8bb4bdeb 622 // Anything with repr(C) or repr(packed) doesn't optimize.
476ff2be
SL
623 // Neither do 1-member and 2-member structs.
624 // In addition, code in trans assume that 2-element structs can become pairs.
625 // It's easier to just short-circuit here.
cc61c64b
XL
626 let can_optimize = (fields.len() > 2 || StructKind::EnumVariant == kind)
627 && (repr.flags & ReprFlags::IS_UNOPTIMISABLE).is_empty();
476ff2be
SL
628
629 let (optimize, sort_ascending) = match kind {
630 StructKind::AlwaysSizedUnivariant => (can_optimize, false),
631 StructKind::MaybeUnsizedUnivariant => (can_optimize, false),
632 StructKind::EnumVariant => {
633 assert!(fields.len() >= 1, "Enum variants must have discriminants.");
634 (can_optimize && fields[0].size(dl).bytes() == 1, true)
635 }
636 };
c30ab7b3 637
476ff2be
SL
638 ret.offsets = vec![Size::from_bytes(0); fields.len()];
639 let mut inverse_memory_index: Vec<u32> = (0..fields.len() as u32).collect();
54a0048b 640
476ff2be
SL
641 if optimize {
642 let start = if let StructKind::EnumVariant = kind { 1 } else { 0 };
643 let end = if let StructKind::MaybeUnsizedUnivariant = kind {
644 fields.len() - 1
645 } else {
646 fields.len()
647 };
648 if end > start {
649 let optimizing = &mut inverse_memory_index[start..end];
650 if sort_ascending {
651 optimizing.sort_by_key(|&x| fields[x as usize].align(dl).abi());
652 } else {
653 optimizing.sort_by(| &a, &b | {
654 let a = fields[a as usize].align(dl).abi();
655 let b = fields[b as usize].align(dl).abi();
656 b.cmp(&a)
657 });
658 }
659 }
660 }
661
662 // inverse_memory_index holds field indices by increasing memory offset.
663 // That is, if field 5 has offset 0, the first element of inverse_memory_index is 5.
664 // We now write field offsets to the corresponding offset slot;
665 // field 5 with offset 0 puts 0 in offsets[5].
666 // At the bottom of this function, we use inverse_memory_index to produce memory_index.
667
668 if let StructKind::EnumVariant = kind {
669 assert_eq!(inverse_memory_index[0], 0,
670 "Enum variant discriminants must have the lowest offset.");
671 }
672
673 let mut offset = Size::from_bytes(0);
674
675 for i in inverse_memory_index.iter() {
676 let field = fields[*i as usize];
677 if !ret.sized {
678 bug!("Struct::new: field #{} of `{}` comes after unsized field",
679 ret.offsets.len(), scapegoat);
54a0048b
SL
680 }
681
54a0048b 682 if field.is_unsized() {
476ff2be 683 ret.sized = false;
54a0048b
SL
684 }
685
686 // Invariant: offset < dl.obj_size_bound() <= 1<<61
476ff2be 687 if !ret.packed {
54a0048b 688 let align = field.align(dl);
cc61c64b 689 let primitive_align = field.primitive_align(dl);
476ff2be 690 ret.align = ret.align.max(align);
cc61c64b 691 ret.primitive_align = ret.primitive_align.max(primitive_align);
c30ab7b3
SL
692 offset = offset.abi_align(align);
693 }
694
476ff2be
SL
695 debug!("Struct::new offset: {:?} field: {:?} {:?}", offset, field, field.size(dl));
696 ret.offsets[*i as usize] = offset;
54a0048b
SL
697
698 offset = offset.checked_add(field.size(dl), dl)
699 .map_or(Err(LayoutError::SizeOverflow(scapegoat)), Ok)?;
54a0048b
SL
700 }
701
cc61c64b
XL
702 if repr.align > 0 {
703 let repr_align = repr.align as u64;
704 ret.align = ret.align.max(Align::from_bytes(repr_align, repr_align).unwrap());
705 debug!("Struct::new repr_align: {:?}", repr_align);
706 }
c30ab7b3 707
476ff2be
SL
708 debug!("Struct::new min_size: {:?}", offset);
709 ret.min_size = offset;
54a0048b 710
476ff2be
SL
711 // As stated above, inverse_memory_index holds field indices by increasing offset.
712 // This makes it an already-sorted view of the offsets vec.
713 // To invert it, consider:
714 // If field 5 has offset 0, offsets[0] is 5, and memory_index[5] should be 0.
715 // Field 5 would be the first element, so memory_index is i:
716 // Note: if we didn't optimize, it's already right.
717
718 if optimize {
719 ret.memory_index = vec![0; inverse_memory_index.len()];
720
721 for i in 0..inverse_memory_index.len() {
722 ret.memory_index[inverse_memory_index[i] as usize] = i as u32;
723 }
724 } else {
725 ret.memory_index = inverse_memory_index;
726 }
54a0048b 727
476ff2be
SL
728 Ok(ret)
729 }
730
731 /// Get the size with trailing alignment padding.
54a0048b 732 pub fn stride(&self) -> Size {
c30ab7b3 733 self.min_size.abi_align(self.align)
54a0048b
SL
734 }
735
736 /// Determine whether a structure would be zero-sized, given its fields.
cc61c64b 737 fn would_be_zero_sized<I>(dl: &TargetDataLayout, fields: I)
7cac9316
XL
738 -> Result<bool, LayoutError<'tcx>>
739 where I: Iterator<Item=Result<&'a Layout, LayoutError<'tcx>>> {
54a0048b
SL
740 for field in fields {
741 let field = field?;
742 if field.is_unsized() || field.size(dl).bytes() > 0 {
743 return Ok(false);
744 }
745 }
746 Ok(true)
747 }
748
476ff2be
SL
749 /// Get indices of the tys that made this struct by increasing offset.
750 #[inline]
751 pub fn field_index_by_increasing_offset<'b>(&'b self) -> impl iter::Iterator<Item=usize>+'b {
752 let mut inverse_small = [0u8; 64];
753 let mut inverse_big = vec![];
754 let use_small = self.memory_index.len() <= inverse_small.len();
755
756 // We have to write this logic twice in order to keep the array small.
757 if use_small {
758 for i in 0..self.memory_index.len() {
759 inverse_small[self.memory_index[i] as usize] = i as u8;
760 }
761 } else {
762 inverse_big = vec![0; self.memory_index.len()];
763 for i in 0..self.memory_index.len() {
764 inverse_big[self.memory_index[i] as usize] = i as u32;
765 }
766 }
767
768 (0..self.memory_index.len()).map(move |i| {
769 if use_small { inverse_small[i] as usize }
770 else { inverse_big[i] as usize }
771 })
772 }
773
54a0048b
SL
774 /// Find the path leading to a non-zero leaf field, starting from
775 /// the given type and recursing through aggregates.
476ff2be
SL
776 /// The tuple is `(path, source_path)`,
777 /// where `path` is in memory order and `source_path` in source order.
54a0048b 778 // FIXME(eddyb) track value ranges and traverse already optimized enums.
7cac9316
XL
779 fn non_zero_field_in_type(tcx: TyCtxt<'a, 'tcx, 'tcx>,
780 param_env: ty::ParamEnv<'tcx>,
781 ty: Ty<'tcx>)
782 -> Result<Option<(FieldPath, FieldPath)>, LayoutError<'tcx>> {
783 match (ty.layout(tcx, param_env)?, &ty.sty) {
c30ab7b3 784 (&Scalar { non_zero: true, .. }, _) |
476ff2be 785 (&CEnum { non_zero: true, .. }, _) => Ok(Some((vec![], vec![]))),
54a0048b 786 (&FatPointer { non_zero: true, .. }, _) => {
476ff2be 787 Ok(Some((vec![FAT_PTR_ADDR as u32], vec![FAT_PTR_ADDR as u32])))
54a0048b
SL
788 }
789
790 // Is this the NonZero lang item wrapping a pointer or integer type?
9e0c209e 791 (&Univariant { non_zero: true, .. }, &ty::TyAdt(def, substs)) => {
54a0048b
SL
792 let fields = &def.struct_variant().fields;
793 assert_eq!(fields.len(), 1);
7cac9316 794 match *fields[0].ty(tcx, substs).layout(tcx, param_env)? {
54a0048b
SL
795 // FIXME(eddyb) also allow floating-point types here.
796 Scalar { value: Int(_), non_zero: false } |
797 Scalar { value: Pointer, non_zero: false } => {
476ff2be 798 Ok(Some((vec![0], vec![0])))
54a0048b
SL
799 }
800 FatPointer { non_zero: false, .. } => {
476ff2be
SL
801 let tmp = vec![FAT_PTR_ADDR as u32, 0];
802 Ok(Some((tmp.clone(), tmp)))
54a0048b
SL
803 }
804 _ => Ok(None)
805 }
806 }
807
808 // Perhaps one of the fields of this struct is non-zero
809 // let's recurse and find out
476ff2be 810 (&Univariant { ref variant, .. }, &ty::TyAdt(def, substs)) if def.is_struct() => {
7cac9316
XL
811 Struct::non_zero_field_paths(
812 tcx,
813 param_env,
814 def.struct_variant().fields.iter().map(|field| {
815 field.ty(tcx, substs)
816 }),
817 Some(&variant.memory_index[..]))
54a0048b
SL
818 }
819
820 // Perhaps one of the upvars of this closure is non-zero
476ff2be
SL
821 (&Univariant { ref variant, .. }, &ty::TyClosure(def, substs)) => {
822 let upvar_tys = substs.upvar_tys(def, tcx);
7cac9316
XL
823 Struct::non_zero_field_paths(
824 tcx,
825 param_env,
826 upvar_tys,
476ff2be
SL
827 Some(&variant.memory_index[..]))
828 }
54a0048b 829 // Can we use one of the fields in this tuple?
8bb4bdeb 830 (&Univariant { ref variant, .. }, &ty::TyTuple(tys, _)) => {
7cac9316
XL
831 Struct::non_zero_field_paths(
832 tcx,
833 param_env,
834 tys.iter().cloned(),
476ff2be 835 Some(&variant.memory_index[..]))
54a0048b
SL
836 }
837
838 // Is this a fixed-size array of something non-zero
839 // with at least one element?
840 (_, &ty::TyArray(ety, d)) if d > 0 => {
7cac9316
XL
841 Struct::non_zero_field_paths(
842 tcx,
843 param_env,
844 Some(ety).into_iter(),
845 None)
54a0048b
SL
846 }
847
5bcae85e 848 (_, &ty::TyProjection(_)) | (_, &ty::TyAnon(..)) => {
7cac9316 849 let normalized = tcx.normalize_associated_type_in_env(&ty, param_env);
5bcae85e
SL
850 if ty == normalized {
851 return Ok(None);
852 }
7cac9316 853 return Struct::non_zero_field_in_type(tcx, param_env, normalized);
5bcae85e
SL
854 }
855
54a0048b
SL
856 // Anything else is not a non-zero type.
857 _ => Ok(None)
858 }
859 }
860
861 /// Find the path leading to a non-zero leaf field, starting from
862 /// the given set of fields and recursing through aggregates.
476ff2be
SL
863 /// Returns Some((path, source_path)) on success.
864 /// `path` is translated to memory order. `source_path` is not.
7cac9316
XL
865 fn non_zero_field_paths<I>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
866 param_env: ty::ParamEnv<'tcx>,
867 fields: I,
868 permutation: Option<&[u32]>)
869 -> Result<Option<(FieldPath, FieldPath)>, LayoutError<'tcx>>
870 where I: Iterator<Item=Ty<'tcx>> {
54a0048b 871 for (i, ty) in fields.enumerate() {
7cac9316
XL
872 let r = Struct::non_zero_field_in_type(tcx, param_env, ty)?;
873 if let Some((mut path, mut source_path)) = r {
476ff2be
SL
874 source_path.push(i as u32);
875 let index = if let Some(p) = permutation {
876 p[i] as usize
877 } else {
878 i
879 };
880 path.push(index as u32);
881 return Ok(Some((path, source_path)));
54a0048b
SL
882 }
883 }
884 Ok(None)
885 }
cc61c64b
XL
886
887 pub fn over_align(&self) -> Option<u32> {
888 let align = self.align.abi();
889 let primitive_align = self.primitive_align.abi();
890 if align > primitive_align {
891 Some(align as u32)
892 } else {
893 None
894 }
895 }
9e0c209e
SL
896}
897
898/// An untagged union.
899#[derive(PartialEq, Eq, Hash, Debug)]
900pub struct Union {
901 pub align: Align,
cc61c64b 902 pub primitive_align: Align,
9e0c209e
SL
903
904 pub min_size: Size,
905
906 /// If true, no alignment padding is used.
907 pub packed: bool,
908}
909
7cac9316 910impl<'a, 'tcx> Union {
3b2f2976
XL
911 fn new(dl: &TargetDataLayout, repr: &ReprOptions) -> Union {
912 if repr.packed() && repr.align > 0 {
913 bug!("Union cannot be packed and aligned");
914 }
915
916 let primitive_align = if repr.packed() {
917 dl.i8_align
918 } else {
919 dl.aggregate_align
920 };
921
922 let align = if repr.align > 0 {
923 let repr_align = repr.align as u64;
924 debug!("Union::new repr_align: {:?}", repr_align);
925 primitive_align.max(Align::from_bytes(repr_align, repr_align).unwrap())
926 } else {
927 primitive_align
928 };
929
9e0c209e 930 Union {
041b39d2 931 align,
3b2f2976 932 primitive_align,
9e0c209e 933 min_size: Size::from_bytes(0),
3b2f2976 934 packed: repr.packed(),
9e0c209e
SL
935 }
936 }
937
938 /// Extend the Struct with more fields.
cc61c64b
XL
939 fn extend<I>(&mut self, dl: &TargetDataLayout,
940 fields: I,
7cac9316
XL
941 scapegoat: Ty<'tcx>)
942 -> Result<(), LayoutError<'tcx>>
943 where I: Iterator<Item=Result<&'a Layout, LayoutError<'tcx>>> {
9e0c209e
SL
944 for (index, field) in fields.enumerate() {
945 let field = field?;
946 if field.is_unsized() {
947 bug!("Union::extend: field #{} of `{}` is unsized",
948 index, scapegoat);
949 }
950
476ff2be
SL
951 debug!("Union::extend field: {:?} {:?}", field, field.size(dl));
952
9e0c209e
SL
953 if !self.packed {
954 self.align = self.align.max(field.align(dl));
cc61c64b 955 self.primitive_align = self.primitive_align.max(field.primitive_align(dl));
9e0c209e
SL
956 }
957 self.min_size = cmp::max(self.min_size, field.size(dl));
958 }
959
476ff2be
SL
960 debug!("Union::extend min-size: {:?}", self.min_size);
961
9e0c209e
SL
962 Ok(())
963 }
964
476ff2be 965 /// Get the size with trailing alignment padding.
9e0c209e
SL
966 pub fn stride(&self) -> Size {
967 self.min_size.abi_align(self.align)
968 }
cc61c64b
XL
969
970 pub fn over_align(&self) -> Option<u32> {
971 let align = self.align.abi();
972 let primitive_align = self.primitive_align.abi();
973 if align > primitive_align {
974 Some(align as u32)
975 } else {
976 None
977 }
978 }
54a0048b
SL
979}
980
981/// The first half of a fat pointer.
982/// - For a trait object, this is the address of the box.
983/// - For a slice, this is the base address.
984pub const FAT_PTR_ADDR: usize = 0;
985
986/// The second half of a fat pointer.
987/// - For a trait object, this is the address of the vtable.
988/// - For a slice, this is the length.
989pub const FAT_PTR_EXTRA: usize = 1;
990
991/// Type layout, from which size and alignment can be cheaply computed.
992/// For ADTs, it also includes field placement and enum optimizations.
993/// NOTE: Because Layout is interned, redundant information should be
994/// kept to a minimum, e.g. it includes no sub-component Ty or Layout.
995#[derive(Debug, PartialEq, Eq, Hash)]
996pub enum Layout {
997 /// TyBool, TyChar, TyInt, TyUint, TyFloat, TyRawPtr, TyRef or TyFnPtr.
998 Scalar {
999 value: Primitive,
1000 // If true, the value cannot represent a bit pattern of all zeroes.
1001 non_zero: bool
1002 },
1003
9e0c209e 1004 /// SIMD vectors, from structs marked with #[repr(simd)].
54a0048b
SL
1005 Vector {
1006 element: Primitive,
1007 count: u64
1008 },
1009
1010 /// TyArray, TySlice or TyStr.
1011 Array {
1012 /// If true, the size is exact, otherwise it's only a lower bound.
1013 sized: bool,
1014 align: Align,
cc61c64b
XL
1015 primitive_align: Align,
1016 element_size: Size,
1017 count: u64
54a0048b
SL
1018 },
1019
1020 /// TyRawPtr or TyRef with a !Sized pointee.
1021 FatPointer {
1022 metadata: Primitive,
3b2f2976 1023 /// If true, the pointer cannot be null.
54a0048b
SL
1024 non_zero: bool
1025 },
1026
9e0c209e 1027 // Remaining variants are all ADTs such as structs, enums or tuples.
54a0048b
SL
1028
1029 /// C-like enums; basically an integer.
1030 CEnum {
1031 discr: Integer,
1032 signed: bool,
c30ab7b3 1033 non_zero: bool,
3b2f2976
XL
1034 /// Inclusive discriminant range.
1035 /// If min > max, it represents min...u64::MAX followed by 0...max.
54a0048b
SL
1036 // FIXME(eddyb) always use the shortest range, e.g. by finding
1037 // the largest space between two consecutive discriminants and
1038 // taking everything else as the (shortest) discriminant range.
1039 min: u64,
1040 max: u64
1041 },
1042
1043 /// Single-case enums, and structs/tuples.
1044 Univariant {
1045 variant: Struct,
3b2f2976 1046 /// If true, the structure is NonZero.
54a0048b
SL
1047 // FIXME(eddyb) use a newtype Layout kind for this.
1048 non_zero: bool
1049 },
1050
9e0c209e
SL
1051 /// Untagged unions.
1052 UntaggedUnion {
1053 variants: Union,
1054 },
1055
54a0048b
SL
1056 /// General-case enums: for each case there is a struct, and they
1057 /// all start with a field for the discriminant.
1058 General {
1059 discr: Integer,
1060 variants: Vec<Struct>,
1061 size: Size,
cc61c64b
XL
1062 align: Align,
1063 primitive_align: Align,
54a0048b
SL
1064 },
1065
1066 /// Two cases distinguished by a nullable pointer: the case with discriminant
1067 /// `nndiscr` must have single field which is known to be nonnull due to its type.
1068 /// The other case is known to be zero sized. Hence we represent the enum
1069 /// as simply a nullable pointer: if not null it indicates the `nndiscr` variant,
1070 /// otherwise it indicates the other case.
1071 ///
1072 /// For example, `std::option::Option` instantiated at a safe pointer type
1073 /// is represented such that `None` is a null pointer and `Some` is the
1074 /// identity function.
1075 RawNullablePointer {
1076 nndiscr: u64,
1077 value: Primitive
1078 },
1079
1080 /// Two cases distinguished by a nullable pointer: the case with discriminant
1081 /// `nndiscr` is represented by the struct `nonnull`, where the `discrfield`th
1082 /// field is known to be nonnull due to its type; if that field is null, then
1083 /// it represents the other case, which is known to be zero sized.
1084 StructWrappedNullablePointer {
1085 nndiscr: u64,
1086 nonnull: Struct,
3b2f2976 1087 /// N.B. There is a 0 at the start, for LLVM GEP through a pointer.
476ff2be 1088 discrfield: FieldPath,
3b2f2976 1089 /// Like discrfield, but in source order. For debuginfo.
476ff2be 1090 discrfield_source: FieldPath
54a0048b
SL
1091 }
1092}
1093
1094#[derive(Copy, Clone, Debug)]
1095pub enum LayoutError<'tcx> {
1096 Unknown(Ty<'tcx>),
1097 SizeOverflow(Ty<'tcx>)
1098}
1099
1100impl<'tcx> fmt::Display for LayoutError<'tcx> {
1101 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1102 match *self {
1103 LayoutError::Unknown(ty) => {
1104 write!(f, "the type `{:?}` has an unknown layout", ty)
1105 }
1106 LayoutError::SizeOverflow(ty) => {
1107 write!(f, "the type `{:?}` is too big for the current architecture", ty)
1108 }
1109 }
1110 }
1111}
1112
7cac9316
XL
1113impl<'a, 'tcx> Layout {
1114 pub fn compute_uncached(tcx: TyCtxt<'a, 'tcx, 'tcx>,
1115 param_env: ty::ParamEnv<'tcx>,
1116 ty: Ty<'tcx>)
1117 -> Result<&'tcx Layout, LayoutError<'tcx>> {
5bcae85e 1118 let success = |layout| Ok(tcx.intern_layout(layout));
54a0048b
SL
1119 let dl = &tcx.data_layout;
1120 assert!(!ty.has_infer_types());
1121
7cac9316 1122 let ptr_layout = |pointee: Ty<'tcx>| {
32a655c1 1123 let non_zero = !ty.is_unsafe_ptr();
7cac9316
XL
1124 let pointee = tcx.normalize_associated_type_in_env(&pointee, param_env);
1125 if pointee.is_sized(tcx, param_env, DUMMY_SP) {
32a655c1
SL
1126 Ok(Scalar { value: Pointer, non_zero: non_zero })
1127 } else {
1128 let unsized_part = tcx.struct_tail(pointee);
1129 let meta = match unsized_part.sty {
1130 ty::TySlice(_) | ty::TyStr => {
1131 Int(dl.ptr_sized_integer())
1132 }
1133 ty::TyDynamic(..) => Pointer,
1134 _ => return Err(LayoutError::Unknown(unsized_part))
1135 };
1136 Ok(FatPointer { metadata: meta, non_zero: non_zero })
1137 }
1138 };
476ff2be 1139
54a0048b
SL
1140 let layout = match ty.sty {
1141 // Basic scalars.
1142 ty::TyBool => Scalar { value: Int(I1), non_zero: false },
1143 ty::TyChar => Scalar { value: Int(I32), non_zero: false },
1144 ty::TyInt(ity) => {
1145 Scalar {
1146 value: Int(Integer::from_attr(dl, attr::SignedInt(ity))),
1147 non_zero: false
1148 }
1149 }
1150 ty::TyUint(ity) => {
1151 Scalar {
1152 value: Int(Integer::from_attr(dl, attr::UnsignedInt(ity))),
1153 non_zero: false
1154 }
1155 }
1156 ty::TyFloat(FloatTy::F32) => Scalar { value: F32, non_zero: false },
1157 ty::TyFloat(FloatTy::F64) => Scalar { value: F64, non_zero: false },
1158 ty::TyFnPtr(_) => Scalar { value: Pointer, non_zero: true },
1159
5bcae85e 1160 // The never type.
476ff2be 1161 ty::TyNever => Univariant {
8bb4bdeb 1162 variant: Struct::new(dl, &vec![], &ReprOptions::default(),
476ff2be
SL
1163 StructKind::AlwaysSizedUnivariant, ty)?,
1164 non_zero: false
1165 },
5bcae85e 1166
54a0048b 1167 // Potentially-fat pointers.
54a0048b
SL
1168 ty::TyRef(_, ty::TypeAndMut { ty: pointee, .. }) |
1169 ty::TyRawPtr(ty::TypeAndMut { ty: pointee, .. }) => {
32a655c1
SL
1170 ptr_layout(pointee)?
1171 }
1172 ty::TyAdt(def, _) if def.is_box() => {
1173 ptr_layout(ty.boxed_ty())?
54a0048b
SL
1174 }
1175
1176 // Arrays and slices.
1177 ty::TyArray(element, count) => {
7cac9316 1178 let element = element.layout(tcx, param_env)?;
cc61c64b
XL
1179 let element_size = element.size(dl);
1180 // FIXME(eddyb) Don't use host `usize` for array lengths.
1181 let usize_count: usize = count;
1182 let count = usize_count as u64;
1183 if element_size.checked_mul(count, dl).is_none() {
1184 return Err(LayoutError::SizeOverflow(ty));
1185 }
54a0048b
SL
1186 Array {
1187 sized: true,
1188 align: element.align(dl),
cc61c64b 1189 primitive_align: element.primitive_align(dl),
041b39d2
XL
1190 element_size,
1191 count,
54a0048b
SL
1192 }
1193 }
1194 ty::TySlice(element) => {
7cac9316 1195 let element = element.layout(tcx, param_env)?;
54a0048b
SL
1196 Array {
1197 sized: false,
cc61c64b
XL
1198 align: element.align(dl),
1199 primitive_align: element.primitive_align(dl),
1200 element_size: element.size(dl),
1201 count: 0
54a0048b
SL
1202 }
1203 }
1204 ty::TyStr => {
1205 Array {
1206 sized: false,
1207 align: dl.i8_align,
cc61c64b
XL
1208 primitive_align: dl.i8_align,
1209 element_size: Size::from_bytes(1),
1210 count: 0
54a0048b
SL
1211 }
1212 }
1213
1214 // Odd unit types.
1215 ty::TyFnDef(..) => {
1216 Univariant {
476ff2be 1217 variant: Struct::new(dl, &vec![],
8bb4bdeb 1218 &ReprOptions::default(), StructKind::AlwaysSizedUnivariant, ty)?,
54a0048b
SL
1219 non_zero: false
1220 }
1221 }
476ff2be 1222 ty::TyDynamic(..) => {
8bb4bdeb 1223 let mut unit = Struct::new(dl, &vec![], &ReprOptions::default(),
476ff2be 1224 StructKind::AlwaysSizedUnivariant, ty)?;
54a0048b
SL
1225 unit.sized = false;
1226 Univariant { variant: unit, non_zero: false }
1227 }
1228
9e0c209e 1229 // Tuples and closures.
476ff2be
SL
1230 ty::TyClosure(def_id, ref substs) => {
1231 let tys = substs.upvar_tys(def_id, tcx);
1232 let st = Struct::new(dl,
7cac9316 1233 &tys.map(|ty| ty.layout(tcx, param_env))
476ff2be 1234 .collect::<Result<Vec<_>, _>>()?,
8bb4bdeb 1235 &ReprOptions::default(),
476ff2be
SL
1236 StructKind::AlwaysSizedUnivariant, ty)?;
1237 Univariant { variant: st, non_zero: false }
1238 }
1239
8bb4bdeb 1240 ty::TyTuple(tys, _) => {
041b39d2
XL
1241 let kind = if tys.len() == 0 {
1242 StructKind::AlwaysSizedUnivariant
1243 } else {
1244 StructKind::MaybeUnsizedUnivariant
1245 };
1246
476ff2be 1247 let st = Struct::new(dl,
7cac9316 1248 &tys.iter().map(|ty| ty.layout(tcx, param_env))
476ff2be 1249 .collect::<Result<Vec<_>, _>>()?,
041b39d2 1250 &ReprOptions::default(), kind, ty)?;
54a0048b
SL
1251 Univariant { variant: st, non_zero: false }
1252 }
1253
9e0c209e 1254 // SIMD vector types.
cc61c64b 1255 ty::TyAdt(def, ..) if def.repr.simd() => {
9e0c209e 1256 let element = ty.simd_type(tcx);
7cac9316 1257 match *element.layout(tcx, param_env)? {
9e0c209e
SL
1258 Scalar { value, .. } => {
1259 return success(Vector {
1260 element: value,
1261 count: ty.simd_size(tcx) as u64
1262 });
1263 }
1264 _ => {
1265 tcx.sess.fatal(&format!("monomorphising SIMD type `{}` with \
1266 a non-machine element type `{}`",
1267 ty, element));
54a0048b 1268 }
54a0048b
SL
1269 }
1270 }
9e0c209e
SL
1271
1272 // ADTs.
1273 ty::TyAdt(def, substs) => {
54a0048b
SL
1274 if def.variants.is_empty() {
1275 // Uninhabitable; represent as unit
1276 // (Typechecking will reject discriminant-sizing attrs.)
54a0048b 1277
9e0c209e 1278 return success(Univariant {
476ff2be 1279 variant: Struct::new(dl, &vec![],
8bb4bdeb 1280 &def.repr, StructKind::AlwaysSizedUnivariant, ty)?,
9e0c209e
SL
1281 non_zero: false
1282 });
54a0048b
SL
1283 }
1284
9e0c209e 1285 if def.is_enum() && def.variants.iter().all(|v| v.fields.is_empty()) {
54a0048b 1286 // All bodies empty -> intlike
32a655c1
SL
1287 let (mut min, mut max, mut non_zero) = (i64::max_value(),
1288 i64::min_value(),
1289 true);
8bb4bdeb
XL
1290 for discr in def.discriminants(tcx) {
1291 let x = discr.to_u128_unchecked() as i64;
c30ab7b3 1292 if x == 0 { non_zero = false; }
54a0048b
SL
1293 if x < min { min = x; }
1294 if x > max { max = x; }
1295 }
1296
32a655c1
SL
1297 // FIXME: should handle i128? signed-value based impl is weird and hard to
1298 // grok.
8bb4bdeb 1299 let (discr, signed) = Integer::repr_discr(tcx, ty, &def.repr, min, max);
5bcae85e 1300 return success(CEnum {
041b39d2
XL
1301 discr,
1302 signed,
1303 non_zero,
32a655c1 1304 // FIXME: should be u128?
54a0048b
SL
1305 min: min as u64,
1306 max: max as u64
1307 });
1308 }
1309
8bb4bdeb
XL
1310 if !def.is_enum() || (def.variants.len() == 1 &&
1311 !def.repr.inhibit_enum_layout_opt()) {
9e0c209e
SL
1312 // Struct, or union, or univariant enum equivalent to a struct.
1313 // (Typechecking will reject discriminant-sizing attrs.)
1314
476ff2be
SL
1315 let kind = if def.is_enum() || def.variants[0].fields.len() == 0{
1316 StructKind::AlwaysSizedUnivariant
1317 } else {
7cac9316 1318 let param_env = tcx.param_env(def.did);
476ff2be
SL
1319 let fields = &def.variants[0].fields;
1320 let last_field = &fields[fields.len()-1];
7cac9316
XL
1321 let always_sized = tcx.type_of(last_field.did)
1322 .is_sized(tcx, param_env, DUMMY_SP);
476ff2be
SL
1323 if !always_sized { StructKind::MaybeUnsizedUnivariant }
1324 else { StructKind::AlwaysSizedUnivariant }
1325 };
1326
9e0c209e 1327 let fields = def.variants[0].fields.iter().map(|field| {
7cac9316 1328 field.ty(tcx, substs).layout(tcx, param_env)
476ff2be 1329 }).collect::<Result<Vec<_>, _>>()?;
9e0c209e 1330 let layout = if def.is_union() {
3b2f2976 1331 let mut un = Union::new(dl, &def.repr);
476ff2be 1332 un.extend(dl, fields.iter().map(|&f| Ok(f)), ty)?;
9e0c209e
SL
1333 UntaggedUnion { variants: un }
1334 } else {
8bb4bdeb 1335 let st = Struct::new(dl, &fields, &def.repr,
476ff2be 1336 kind, ty)?;
9e0c209e
SL
1337 let non_zero = Some(def.did) == tcx.lang_items.non_zero();
1338 Univariant { variant: st, non_zero: non_zero }
1339 };
1340 return success(layout);
1341 }
1342
54a0048b
SL
1343 // Since there's at least one
1344 // non-empty body, explicit discriminants should have
1345 // been rejected by a checker before this point.
1346 for (i, v) in def.variants.iter().enumerate() {
8bb4bdeb 1347 if v.discr != ty::VariantDiscr::Relative(i) {
54a0048b 1348 bug!("non-C-like enum {} with specified discriminants",
9e0c209e 1349 tcx.item_path_str(def.did));
54a0048b
SL
1350 }
1351 }
1352
54a0048b
SL
1353 // Cache the substituted and normalized variant field types.
1354 let variants = def.variants.iter().map(|v| {
5bcae85e 1355 v.fields.iter().map(|field| field.ty(tcx, substs)).collect::<Vec<_>>()
54a0048b
SL
1356 }).collect::<Vec<_>>();
1357
8bb4bdeb 1358 if variants.len() == 2 && !def.repr.inhibit_enum_layout_opt() {
54a0048b
SL
1359 // Nullable pointer optimization
1360 for discr in 0..2 {
1361 let other_fields = variants[1 - discr].iter().map(|ty| {
7cac9316 1362 ty.layout(tcx, param_env)
54a0048b
SL
1363 });
1364 if !Struct::would_be_zero_sized(dl, other_fields)? {
1365 continue;
1366 }
7cac9316
XL
1367 let paths = Struct::non_zero_field_paths(tcx,
1368 param_env,
1369 variants[discr].iter().cloned(),
1370 None)?;
476ff2be
SL
1371 let (mut path, mut path_source) = if let Some(p) = paths { p }
1372 else { continue };
54a0048b
SL
1373
1374 // FIXME(eddyb) should take advantage of a newtype.
1375 if path == &[0] && variants[discr].len() == 1 {
7cac9316 1376 let value = match *variants[discr][0].layout(tcx, param_env)? {
c30ab7b3
SL
1377 Scalar { value, .. } => value,
1378 CEnum { discr, .. } => Int(discr),
1379 _ => bug!("Layout::compute: `{}`'s non-zero \
1380 `{}` field not scalar?!",
1381 ty, variants[discr][0])
1382 };
1383 return success(RawNullablePointer {
1384 nndiscr: discr as u64,
041b39d2 1385 value,
c30ab7b3 1386 });
54a0048b
SL
1387 }
1388
476ff2be 1389 let st = Struct::new(dl,
7cac9316 1390 &variants[discr].iter().map(|ty| ty.layout(tcx, param_env))
476ff2be 1391 .collect::<Result<Vec<_>, _>>()?,
8bb4bdeb 1392 &def.repr, StructKind::AlwaysSizedUnivariant, ty)?;
476ff2be
SL
1393
1394 // We have to fix the last element of path here.
1395 let mut i = *path.last().unwrap();
1396 i = st.memory_index[i as usize];
1397 *path.last_mut().unwrap() = i;
54a0048b
SL
1398 path.push(0); // For GEP through a pointer.
1399 path.reverse();
476ff2be
SL
1400 path_source.push(0);
1401 path_source.reverse();
1402
5bcae85e 1403 return success(StructWrappedNullablePointer {
54a0048b
SL
1404 nndiscr: discr as u64,
1405 nonnull: st,
476ff2be
SL
1406 discrfield: path,
1407 discrfield_source: path_source
54a0048b
SL
1408 });
1409 }
1410 }
1411
1412 // The general case.
1413 let discr_max = (variants.len() - 1) as i64;
1414 assert!(discr_max >= 0);
8bb4bdeb 1415 let (min_ity, _) = Integer::repr_discr(tcx, ty, &def.repr, 0, discr_max);
54a0048b 1416 let mut align = dl.aggregate_align;
cc61c64b 1417 let mut primitive_align = dl.aggregate_align;
54a0048b
SL
1418 let mut size = Size::from_bytes(0);
1419
1420 // We're interested in the smallest alignment, so start large.
1421 let mut start_align = Align::from_bytes(256, 256).unwrap();
1422
1423 // Create the set of structs that represent each variant
1424 // Use the minimum integer type we figured out above
476ff2be 1425 let discr = Scalar { value: Int(min_ity), non_zero: false };
54a0048b 1426 let mut variants = variants.into_iter().map(|fields| {
476ff2be 1427 let mut fields = fields.into_iter().map(|field| {
7cac9316 1428 field.layout(tcx, param_env)
476ff2be
SL
1429 }).collect::<Result<Vec<_>, _>>()?;
1430 fields.insert(0, &discr);
1431 let st = Struct::new(dl,
1432 &fields,
8bb4bdeb 1433 &def.repr, StructKind::EnumVariant, ty)?;
476ff2be
SL
1434 // Find the first field we can't move later
1435 // to make room for a larger discriminant.
1436 // It is important to skip the first field.
1437 for i in st.field_index_by_increasing_offset().skip(1) {
1438 let field = fields[i];
1439 let field_align = field.align(dl);
1440 if field.size(dl).bytes() != 0 || field_align.abi() != 1 {
1441 start_align = start_align.min(field_align);
1442 break;
54a0048b 1443 }
476ff2be 1444 }
c30ab7b3 1445 size = cmp::max(size, st.min_size);
54a0048b 1446 align = align.max(st.align);
cc61c64b 1447 primitive_align = primitive_align.max(st.primitive_align);
54a0048b
SL
1448 Ok(st)
1449 }).collect::<Result<Vec<_>, _>>()?;
1450
1451 // Align the maximum variant size to the largest alignment.
1452 size = size.abi_align(align);
1453
1454 if size.bytes() >= dl.obj_size_bound() {
1455 return Err(LayoutError::SizeOverflow(ty));
1456 }
1457
8bb4bdeb
XL
1458 let typeck_ity = Integer::from_attr(dl, def.repr.discr_type());
1459 if typeck_ity < min_ity {
1460 // It is a bug if Layout decided on a greater discriminant size than typeck for
1461 // some reason at this point (based on values discriminant can take on). Mostly
1462 // because this discriminant will be loaded, and then stored into variable of
1463 // type calculated by typeck. Consider such case (a bug): typeck decided on
1464 // byte-sized discriminant, but layout thinks we need a 16-bit to store all
1465 // discriminant values. That would be a bug, because then, in trans, in order
1466 // to store this 16-bit discriminant into 8-bit sized temporary some of the
1467 // space necessary to represent would have to be discarded (or layout is wrong
1468 // on thinking it needs 16 bits)
1469 bug!("layout decided on a larger discriminant type ({:?}) than typeck ({:?})",
1470 min_ity, typeck_ity);
1471 // However, it is fine to make discr type however large (as an optimisation)
1472 // after this point – we’ll just truncate the value we load in trans.
1473 }
1474
54a0048b
SL
1475 // Check to see if we should use a different type for the
1476 // discriminant. We can safely use a type with the same size
1477 // as the alignment of the first field of each variant.
1478 // We increase the size of the discriminant to avoid LLVM copying
1479 // padding when it doesn't need to. This normally causes unaligned
1480 // load/stores and excessive memcpy/memset operations. By using a
1481 // bigger integer size, LLVM can be sure about it's contents and
1482 // won't be so conservative.
1483
1484 // Use the initial field alignment
9e0c209e 1485 let mut ity = Integer::for_abi_align(dl, start_align).unwrap_or(min_ity);
54a0048b
SL
1486
1487 // If the alignment is not larger than the chosen discriminant size,
1488 // don't use the alignment as the final size.
1489 if ity <= min_ity {
1490 ity = min_ity;
1491 } else {
1492 // Patch up the variants' first few fields.
1493 let old_ity_size = Int(min_ity).size(dl);
1494 let new_ity_size = Int(ity).size(dl);
1495 for variant in &mut variants {
476ff2be
SL
1496 for i in variant.offsets.iter_mut() {
1497 // The first field is the discrimminant, at offset 0.
1498 // These aren't in order, and we need to skip it.
1499 if *i <= old_ity_size && *i > Size::from_bytes(0) {
1500 *i = new_ity_size;
54a0048b 1501 }
54a0048b 1502 }
c30ab7b3
SL
1503 // We might be making the struct larger.
1504 if variant.min_size <= old_ity_size {
1505 variant.min_size = new_ity_size;
1506 }
54a0048b
SL
1507 }
1508 }
1509
1510 General {
1511 discr: ity,
041b39d2
XL
1512 variants,
1513 size,
1514 align,
1515 primitive_align,
54a0048b
SL
1516 }
1517 }
1518
1519 // Types with no meaningful known layout.
5bcae85e 1520 ty::TyProjection(_) | ty::TyAnon(..) => {
7cac9316 1521 let normalized = tcx.normalize_associated_type_in_env(&ty, param_env);
5bcae85e
SL
1522 if ty == normalized {
1523 return Err(LayoutError::Unknown(ty));
1524 }
7cac9316 1525 return normalized.layout(tcx, param_env);
5bcae85e
SL
1526 }
1527 ty::TyParam(_) => {
54a0048b
SL
1528 return Err(LayoutError::Unknown(ty));
1529 }
1530 ty::TyInfer(_) | ty::TyError => {
1531 bug!("Layout::compute: unexpected type `{}`", ty)
1532 }
1533 };
1534
5bcae85e 1535 success(layout)
54a0048b
SL
1536 }
1537
1538 /// Returns true if the layout corresponds to an unsized type.
1539 pub fn is_unsized(&self) -> bool {
1540 match *self {
1541 Scalar {..} | Vector {..} | FatPointer {..} |
9e0c209e 1542 CEnum {..} | UntaggedUnion {..} | General {..} |
54a0048b
SL
1543 RawNullablePointer {..} |
1544 StructWrappedNullablePointer {..} => false,
1545
1546 Array { sized, .. } |
1547 Univariant { variant: Struct { sized, .. }, .. } => !sized
1548 }
1549 }
1550
cc61c64b
XL
1551 pub fn size<C: HasDataLayout>(&self, cx: C) -> Size {
1552 let dl = cx.data_layout();
1553
54a0048b
SL
1554 match *self {
1555 Scalar { value, .. } | RawNullablePointer { value, .. } => {
1556 value.size(dl)
1557 }
1558
1559 Vector { element, count } => {
cc61c64b
XL
1560 let element_size = element.size(dl);
1561 let vec_size = match element_size.checked_mul(count, dl) {
54a0048b
SL
1562 Some(size) => size,
1563 None => bug!("Layout::size({:?}): {} * {} overflowed",
cc61c64b 1564 self, element_size.bytes(), count)
54a0048b
SL
1565 };
1566 vec_size.abi_align(self.align(dl))
1567 }
1568
cc61c64b
XL
1569 Array { element_size, count, .. } => {
1570 match element_size.checked_mul(count, dl) {
1571 Some(size) => size,
1572 None => bug!("Layout::size({:?}): {} * {} overflowed",
1573 self, element_size.bytes(), count)
1574 }
1575 }
1576
54a0048b
SL
1577 FatPointer { metadata, .. } => {
1578 // Effectively a (ptr, meta) tuple.
1579 Pointer.size(dl).abi_align(metadata.align(dl))
1580 .checked_add(metadata.size(dl), dl).unwrap()
1581 .abi_align(self.align(dl))
1582 }
1583
1584 CEnum { discr, .. } => Int(discr).size(dl),
cc61c64b 1585 General { size, .. } => size,
9e0c209e 1586 UntaggedUnion { ref variants } => variants.stride(),
54a0048b
SL
1587
1588 Univariant { ref variant, .. } |
1589 StructWrappedNullablePointer { nonnull: ref variant, .. } => {
1590 variant.stride()
1591 }
1592 }
1593 }
1594
cc61c64b
XL
1595 pub fn align<C: HasDataLayout>(&self, cx: C) -> Align {
1596 let dl = cx.data_layout();
1597
54a0048b
SL
1598 match *self {
1599 Scalar { value, .. } | RawNullablePointer { value, .. } => {
1600 value.align(dl)
1601 }
1602
1603 Vector { element, count } => {
1604 let elem_size = element.size(dl);
1605 let vec_size = match elem_size.checked_mul(count, dl) {
1606 Some(size) => size,
1607 None => bug!("Layout::align({:?}): {} * {} overflowed",
1608 self, elem_size.bytes(), count)
1609 };
1610 for &(size, align) in &dl.vector_align {
1611 if size == vec_size {
1612 return align;
1613 }
1614 }
1615 // Default to natural alignment, which is what LLVM does.
1616 // That is, use the size, rounded up to a power of 2.
1617 let align = vec_size.bytes().next_power_of_two();
1618 Align::from_bytes(align, align).unwrap()
1619 }
1620
1621 FatPointer { metadata, .. } => {
1622 // Effectively a (ptr, meta) tuple.
1623 Pointer.align(dl).max(metadata.align(dl))
1624 }
1625
1626 CEnum { discr, .. } => Int(discr).align(dl),
1627 Array { align, .. } | General { align, .. } => align,
9e0c209e 1628 UntaggedUnion { ref variants } => variants.align,
54a0048b
SL
1629
1630 Univariant { ref variant, .. } |
1631 StructWrappedNullablePointer { nonnull: ref variant, .. } => {
1632 variant.align
1633 }
1634 }
1635 }
cc61c64b
XL
1636
1637 /// Returns alignment before repr alignment is applied
1638 pub fn primitive_align(&self, dl: &TargetDataLayout) -> Align {
1639 match *self {
1640 Array { primitive_align, .. } | General { primitive_align, .. } => primitive_align,
1641 Univariant { ref variant, .. } |
1642 StructWrappedNullablePointer { nonnull: ref variant, .. } => {
1643 variant.primitive_align
1644 },
1645
1646 _ => self.align(dl)
1647 }
1648 }
1649
1650 /// Returns repr alignment if it is greater than the primitive alignment.
1651 pub fn over_align(&self, dl: &TargetDataLayout) -> Option<u32> {
1652 let align = self.align(dl);
1653 let primitive_align = self.primitive_align(dl);
1654 if align.abi() > primitive_align.abi() {
1655 Some(align.abi() as u32)
1656 } else {
1657 None
1658 }
1659 }
1660
1661 pub fn field_offset<C: HasDataLayout>(&self,
1662 cx: C,
1663 i: usize,
1664 variant_index: Option<usize>)
1665 -> Size {
1666 let dl = cx.data_layout();
1667
1668 match *self {
1669 Scalar { .. } |
1670 CEnum { .. } |
1671 UntaggedUnion { .. } |
1672 RawNullablePointer { .. } => {
1673 Size::from_bytes(0)
1674 }
1675
1676 Vector { element, count } => {
1677 let element_size = element.size(dl);
1678 let i = i as u64;
1679 assert!(i < count);
1680 Size::from_bytes(element_size.bytes() * count)
1681 }
1682
1683 Array { element_size, count, .. } => {
1684 let i = i as u64;
1685 assert!(i < count);
1686 Size::from_bytes(element_size.bytes() * count)
1687 }
1688
1689 FatPointer { metadata, .. } => {
1690 // Effectively a (ptr, meta) tuple.
1691 assert!(i < 2);
1692 if i == 0 {
1693 Size::from_bytes(0)
1694 } else {
1695 Pointer.size(dl).abi_align(metadata.align(dl))
1696 }
1697 }
1698
1699 Univariant { ref variant, .. } => variant.offsets[i],
1700
1701 General { ref variants, .. } => {
1702 let v = variant_index.expect("variant index required");
1703 variants[v].offsets[i + 1]
1704 }
1705
1706 StructWrappedNullablePointer { nndiscr, ref nonnull, .. } => {
1707 if Some(nndiscr as usize) == variant_index {
1708 nonnull.offsets[i]
1709 } else {
1710 Size::from_bytes(0)
1711 }
1712 }
1713 }
1714 }
7cac9316
XL
1715
1716 /// This is invoked by the `layout_raw` query to record the final
1717 /// layout of each type.
1718 #[inline]
1719 pub fn record_layout_for_printing(tcx: TyCtxt<'a, 'tcx, 'tcx>,
1720 ty: Ty<'tcx>,
1721 param_env: ty::ParamEnv<'tcx>,
1722 layout: &Layout) {
1723 // If we are running with `-Zprint-type-sizes`, record layouts for
1724 // dumping later. Ignore layouts that are done with non-empty
1725 // environments or non-monomorphic layouts, as the user only wants
1726 // to see the stuff resulting from the final trans session.
1727 if
1728 !tcx.sess.opts.debugging_opts.print_type_sizes ||
1729 ty.has_param_types() ||
1730 ty.has_self_ty() ||
1731 !param_env.caller_bounds.is_empty()
1732 {
1733 return;
1734 }
1735
1736 Self::record_layout_for_printing_outlined(tcx, ty, param_env, layout)
1737 }
1738
1739 fn record_layout_for_printing_outlined(tcx: TyCtxt<'a, 'tcx, 'tcx>,
1740 ty: Ty<'tcx>,
1741 param_env: ty::ParamEnv<'tcx>,
1742 layout: &Layout) {
1743 // (delay format until we actually need it)
1744 let record = |kind, opt_discr_size, variants| {
1745 let type_desc = format!("{:?}", ty);
1746 let overall_size = layout.size(tcx);
1747 let align = layout.align(tcx);
1748 tcx.sess.code_stats.borrow_mut().record_type_size(kind,
1749 type_desc,
1750 align,
1751 overall_size,
1752 opt_discr_size,
1753 variants);
1754 };
1755
1756 let (adt_def, substs) = match ty.sty {
1757 ty::TyAdt(ref adt_def, substs) => {
1758 debug!("print-type-size t: `{:?}` process adt", ty);
1759 (adt_def, substs)
1760 }
1761
1762 ty::TyClosure(..) => {
1763 debug!("print-type-size t: `{:?}` record closure", ty);
1764 record(DataTypeKind::Closure, None, vec![]);
1765 return;
1766 }
1767
1768 _ => {
1769 debug!("print-type-size t: `{:?}` skip non-nominal", ty);
1770 return;
1771 }
1772 };
1773
1774 let adt_kind = adt_def.adt_kind();
1775
1776 let build_field_info = |(field_name, field_ty): (ast::Name, Ty<'tcx>), offset: &Size| {
1777 let layout = field_ty.layout(tcx, param_env);
1778 match layout {
1779 Err(_) => bug!("no layout found for field {} type: `{:?}`", field_name, field_ty),
1780 Ok(field_layout) => {
1781 session::FieldInfo {
1782 name: field_name.to_string(),
1783 offset: offset.bytes(),
1784 size: field_layout.size(tcx).bytes(),
1785 align: field_layout.align(tcx).abi(),
1786 }
1787 }
1788 }
1789 };
1790
1791 let build_primitive_info = |name: ast::Name, value: &Primitive| {
1792 session::VariantInfo {
1793 name: Some(name.to_string()),
1794 kind: session::SizeKind::Exact,
1795 align: value.align(tcx).abi(),
1796 size: value.size(tcx).bytes(),
1797 fields: vec![],
1798 }
1799 };
1800
1801 enum Fields<'a> {
1802 WithDiscrim(&'a Struct),
1803 NoDiscrim(&'a Struct),
1804 }
1805
1806 let build_variant_info = |n: Option<ast::Name>,
1807 flds: &[(ast::Name, Ty<'tcx>)],
1808 layout: Fields| {
1809 let (s, field_offsets) = match layout {
1810 Fields::WithDiscrim(s) => (s, &s.offsets[1..]),
1811 Fields::NoDiscrim(s) => (s, &s.offsets[0..]),
1812 };
1813 let field_info: Vec<_> =
1814 flds.iter()
1815 .zip(field_offsets.iter())
1816 .map(|(&field_name_ty, offset)| build_field_info(field_name_ty, offset))
1817 .collect();
1818
1819 session::VariantInfo {
1820 name: n.map(|n|n.to_string()),
1821 kind: if s.sized {
1822 session::SizeKind::Exact
1823 } else {
1824 session::SizeKind::Min
1825 },
1826 align: s.align.abi(),
1827 size: s.min_size.bytes(),
1828 fields: field_info,
1829 }
1830 };
1831
1832 match *layout {
1833 Layout::StructWrappedNullablePointer { nonnull: ref variant_layout,
1834 nndiscr,
1835 discrfield: _,
1836 discrfield_source: _ } => {
1837 debug!("print-type-size t: `{:?}` adt struct-wrapped nullable nndiscr {} is {:?}",
1838 ty, nndiscr, variant_layout);
1839 let variant_def = &adt_def.variants[nndiscr as usize];
1840 let fields: Vec<_> =
1841 variant_def.fields.iter()
1842 .map(|field_def| (field_def.name, field_def.ty(tcx, substs)))
1843 .collect();
1844 record(adt_kind.into(),
1845 None,
1846 vec![build_variant_info(Some(variant_def.name),
1847 &fields,
1848 Fields::NoDiscrim(variant_layout))]);
1849 }
1850 Layout::RawNullablePointer { nndiscr, value } => {
1851 debug!("print-type-size t: `{:?}` adt raw nullable nndiscr {} is {:?}",
1852 ty, nndiscr, value);
1853 let variant_def = &adt_def.variants[nndiscr as usize];
1854 record(adt_kind.into(), None,
1855 vec![build_primitive_info(variant_def.name, &value)]);
1856 }
1857 Layout::Univariant { variant: ref variant_layout, non_zero: _ } => {
1858 let variant_names = || {
1859 adt_def.variants.iter().map(|v|format!("{}", v.name)).collect::<Vec<_>>()
1860 };
1861 debug!("print-type-size t: `{:?}` adt univariant {:?} variants: {:?}",
1862 ty, variant_layout, variant_names());
1863 assert!(adt_def.variants.len() <= 1,
1864 "univariant with variants {:?}", variant_names());
1865 if adt_def.variants.len() == 1 {
1866 let variant_def = &adt_def.variants[0];
1867 let fields: Vec<_> =
1868 variant_def.fields.iter()
1869 .map(|f| (f.name, f.ty(tcx, substs)))
1870 .collect();
1871 record(adt_kind.into(),
1872 None,
1873 vec![build_variant_info(Some(variant_def.name),
1874 &fields,
1875 Fields::NoDiscrim(variant_layout))]);
1876 } else {
1877 // (This case arises for *empty* enums; so give it
1878 // zero variants.)
1879 record(adt_kind.into(), None, vec![]);
1880 }
1881 }
1882
1883 Layout::General { ref variants, discr, .. } => {
1884 debug!("print-type-size t: `{:?}` adt general variants def {} layouts {} {:?}",
1885 ty, adt_def.variants.len(), variants.len(), variants);
1886 let variant_infos: Vec<_> =
1887 adt_def.variants.iter()
1888 .zip(variants.iter())
1889 .map(|(variant_def, variant_layout)| {
1890 let fields: Vec<_> =
1891 variant_def.fields
1892 .iter()
1893 .map(|f| (f.name, f.ty(tcx, substs)))
1894 .collect();
1895 build_variant_info(Some(variant_def.name),
1896 &fields,
1897 Fields::WithDiscrim(variant_layout))
1898 })
1899 .collect();
1900 record(adt_kind.into(), Some(discr.size()), variant_infos);
1901 }
1902
1903 Layout::UntaggedUnion { ref variants } => {
1904 debug!("print-type-size t: `{:?}` adt union variants {:?}",
1905 ty, variants);
1906 // layout does not currently store info about each
1907 // variant...
1908 record(adt_kind.into(), None, Vec::new());
1909 }
1910
1911 Layout::CEnum { discr, .. } => {
1912 debug!("print-type-size t: `{:?}` adt c-like enum", ty);
1913 let variant_infos: Vec<_> =
1914 adt_def.variants.iter()
1915 .map(|variant_def| {
1916 build_primitive_info(variant_def.name,
1917 &Primitive::Int(discr))
1918 })
1919 .collect();
1920 record(adt_kind.into(), Some(discr.size()), variant_infos);
1921 }
1922
1923 // other cases provide little interesting (i.e. adjustable
1924 // via representation tweaks) size info beyond total size.
1925 Layout::Scalar { .. } |
1926 Layout::Vector { .. } |
1927 Layout::Array { .. } |
1928 Layout::FatPointer { .. } => {
1929 debug!("print-type-size t: `{:?}` adt other", ty);
1930 record(adt_kind.into(), None, Vec::new())
1931 }
1932 }
1933 }
54a0048b
SL
1934}
1935
1936/// Type size "skeleton", i.e. the only information determining a type's size.
1937/// While this is conservative, (aside from constant sizes, only pointers,
1938/// newtypes thereof and null pointer optimized enums are allowed), it is
1939/// enough to statically check common usecases of transmute.
1940#[derive(Copy, Clone, Debug)]
1941pub enum SizeSkeleton<'tcx> {
1942 /// Any statically computable Layout.
1943 Known(Size),
1944
1945 /// A potentially-fat pointer.
1946 Pointer {
3b2f2976 1947 /// If true, this pointer is never null.
54a0048b 1948 non_zero: bool,
3b2f2976
XL
1949 /// The type which determines the unsized metadata, if any,
1950 /// of this pointer. Either a type parameter or a projection
1951 /// depending on one, with regions erased.
54a0048b
SL
1952 tail: Ty<'tcx>
1953 }
1954}
1955
7cac9316
XL
1956impl<'a, 'tcx> SizeSkeleton<'tcx> {
1957 pub fn compute(ty: Ty<'tcx>,
1958 tcx: TyCtxt<'a, 'tcx, 'tcx>,
1959 param_env: ty::ParamEnv<'tcx>)
1960 -> Result<SizeSkeleton<'tcx>, LayoutError<'tcx>> {
54a0048b
SL
1961 assert!(!ty.has_infer_types());
1962
1963 // First try computing a static layout.
7cac9316 1964 let err = match ty.layout(tcx, param_env) {
54a0048b 1965 Ok(layout) => {
cc61c64b 1966 return Ok(SizeSkeleton::Known(layout.size(tcx)));
54a0048b
SL
1967 }
1968 Err(err) => err
1969 };
1970
7cac9316 1971 let ptr_skeleton = |pointee: Ty<'tcx>| {
32a655c1
SL
1972 let non_zero = !ty.is_unsafe_ptr();
1973 let tail = tcx.struct_tail(pointee);
1974 match tail.sty {
1975 ty::TyParam(_) | ty::TyProjection(_) => {
1976 assert!(tail.has_param_types() || tail.has_self_ty());
1977 Ok(SizeSkeleton::Pointer {
041b39d2 1978 non_zero,
32a655c1
SL
1979 tail: tcx.erase_regions(&tail)
1980 })
1981 }
1982 _ => {
1983 bug!("SizeSkeleton::compute({}): layout errored ({}), yet \
1984 tail `{}` is not a type parameter or a projection",
1985 ty, err, tail)
1986 }
1987 }
1988 };
1989
54a0048b 1990 match ty.sty {
54a0048b
SL
1991 ty::TyRef(_, ty::TypeAndMut { ty: pointee, .. }) |
1992 ty::TyRawPtr(ty::TypeAndMut { ty: pointee, .. }) => {
32a655c1
SL
1993 ptr_skeleton(pointee)
1994 }
1995 ty::TyAdt(def, _) if def.is_box() => {
1996 ptr_skeleton(ty.boxed_ty())
54a0048b
SL
1997 }
1998
9e0c209e 1999 ty::TyAdt(def, substs) => {
54a0048b 2000 // Only newtypes and enums w/ nullable pointer optimization.
9e0c209e 2001 if def.is_union() || def.variants.is_empty() || def.variants.len() > 2 {
54a0048b
SL
2002 return Err(err);
2003 }
2004
2005 // Get a zero-sized variant or a pointer newtype.
2006 let zero_or_ptr_variant = |i: usize| {
2007 let fields = def.variants[i].fields.iter().map(|field| {
7cac9316 2008 SizeSkeleton::compute(field.ty(tcx, substs), tcx, param_env)
54a0048b
SL
2009 });
2010 let mut ptr = None;
2011 for field in fields {
2012 let field = field?;
2013 match field {
2014 SizeSkeleton::Known(size) => {
2015 if size.bytes() > 0 {
2016 return Err(err);
2017 }
2018 }
2019 SizeSkeleton::Pointer {..} => {
2020 if ptr.is_some() {
2021 return Err(err);
2022 }
2023 ptr = Some(field);
2024 }
2025 }
2026 }
2027 Ok(ptr)
2028 };
2029
2030 let v0 = zero_or_ptr_variant(0)?;
2031 // Newtype.
2032 if def.variants.len() == 1 {
2033 if let Some(SizeSkeleton::Pointer { non_zero, tail }) = v0 {
2034 return Ok(SizeSkeleton::Pointer {
2035 non_zero: non_zero ||
2036 Some(def.did) == tcx.lang_items.non_zero(),
041b39d2 2037 tail,
54a0048b
SL
2038 });
2039 } else {
2040 return Err(err);
2041 }
2042 }
2043
2044 let v1 = zero_or_ptr_variant(1)?;
2045 // Nullable pointer enum optimization.
2046 match (v0, v1) {
2047 (Some(SizeSkeleton::Pointer { non_zero: true, tail }), None) |
2048 (None, Some(SizeSkeleton::Pointer { non_zero: true, tail })) => {
2049 Ok(SizeSkeleton::Pointer {
2050 non_zero: false,
041b39d2 2051 tail,
54a0048b
SL
2052 })
2053 }
2054 _ => Err(err)
2055 }
2056 }
2057
5bcae85e 2058 ty::TyProjection(_) | ty::TyAnon(..) => {
7cac9316 2059 let normalized = tcx.normalize_associated_type_in_env(&ty, param_env);
5bcae85e
SL
2060 if ty == normalized {
2061 Err(err)
2062 } else {
7cac9316 2063 SizeSkeleton::compute(normalized, tcx, param_env)
5bcae85e
SL
2064 }
2065 }
2066
54a0048b
SL
2067 _ => Err(err)
2068 }
2069 }
2070
2071 pub fn same_size(self, other: SizeSkeleton) -> bool {
2072 match (self, other) {
2073 (SizeSkeleton::Known(a), SizeSkeleton::Known(b)) => a == b,
2074 (SizeSkeleton::Pointer { tail: a, .. },
2075 SizeSkeleton::Pointer { tail: b, .. }) => a == b,
2076 _ => false
2077 }
2078 }
2079}
cc61c64b
XL
2080
2081/// A pair of a type and its layout. Implements various
2082/// type traversal APIs (e.g. recursing into fields).
2083#[derive(Copy, Clone, Debug)]
2084pub struct TyLayout<'tcx> {
2085 pub ty: Ty<'tcx>,
2086 pub layout: &'tcx Layout,
2087 pub variant_index: Option<usize>,
2088}
2089
2090impl<'tcx> Deref for TyLayout<'tcx> {
2091 type Target = Layout;
2092 fn deref(&self) -> &Layout {
2093 self.layout
2094 }
2095}
2096
7cac9316
XL
2097pub trait LayoutTyper<'tcx>: HasDataLayout {
2098 type TyLayout;
2099
cc61c64b 2100 fn tcx<'a>(&'a self) -> TyCtxt<'a, 'tcx, 'tcx>;
7cac9316
XL
2101 fn layout_of(self, ty: Ty<'tcx>) -> Self::TyLayout;
2102 fn normalize_projections(self, ty: Ty<'tcx>) -> Ty<'tcx>;
cc61c64b
XL
2103}
2104
7cac9316
XL
2105/// Combines a tcx with the parameter environment so that you can
2106/// compute layout operations.
2107#[derive(Copy, Clone)]
2108pub struct LayoutCx<'a, 'tcx: 'a> {
2109 tcx: TyCtxt<'a, 'tcx, 'tcx>,
2110 param_env: ty::ParamEnv<'tcx>,
cc61c64b
XL
2111}
2112
7cac9316
XL
2113impl<'a, 'tcx> LayoutCx<'a, 'tcx> {
2114 pub fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>, param_env: ty::ParamEnv<'tcx>) -> Self {
2115 LayoutCx { tcx, param_env }
cc61c64b
XL
2116 }
2117}
2118
7cac9316 2119impl<'a, 'tcx> HasDataLayout for LayoutCx<'a, 'tcx> {
cc61c64b
XL
2120 fn data_layout(&self) -> &TargetDataLayout {
2121 &self.tcx.data_layout
2122 }
2123}
2124
7cac9316
XL
2125impl<'a, 'tcx> LayoutTyper<'tcx> for LayoutCx<'a, 'tcx> {
2126 type TyLayout = Result<TyLayout<'tcx>, LayoutError<'tcx>>;
cc61c64b 2127
7cac9316
XL
2128 fn tcx<'b>(&'b self) -> TyCtxt<'b, 'tcx, 'tcx> {
2129 self.tcx
2130 }
cc61c64b 2131
7cac9316 2132 fn layout_of(self, ty: Ty<'tcx>) -> Self::TyLayout {
cc61c64b
XL
2133 let ty = self.normalize_projections(ty);
2134
2135 Ok(TyLayout {
041b39d2 2136 ty,
7cac9316 2137 layout: ty.layout(self.tcx, self.param_env)?,
cc61c64b
XL
2138 variant_index: None
2139 })
2140 }
2141
7cac9316
XL
2142 fn normalize_projections(self, ty: Ty<'tcx>) -> Ty<'tcx> {
2143 self.tcx.normalize_associated_type_in_env(&ty, self.param_env)
cc61c64b
XL
2144 }
2145}
2146
2147impl<'a, 'tcx> TyLayout<'tcx> {
2148 pub fn for_variant(&self, variant_index: usize) -> Self {
2149 TyLayout {
2150 variant_index: Some(variant_index),
2151 ..*self
2152 }
2153 }
2154
2155 pub fn field_offset<C: HasDataLayout>(&self, cx: C, i: usize) -> Size {
2156 self.layout.field_offset(cx, i, self.variant_index)
2157 }
2158
2159 pub fn field_count(&self) -> usize {
2160 // Handle enum/union through the type rather than Layout.
2161 if let ty::TyAdt(def, _) = self.ty.sty {
2162 let v = self.variant_index.unwrap_or(0);
2163 if def.variants.is_empty() {
2164 assert_eq!(v, 0);
2165 return 0;
2166 } else {
2167 return def.variants[v].fields.len();
2168 }
2169 }
2170
2171 match *self.layout {
2172 Scalar { .. } => {
2173 bug!("TyLayout::field_count({:?}): not applicable", self)
2174 }
2175
2176 // Handled above (the TyAdt case).
2177 CEnum { .. } |
2178 General { .. } |
2179 UntaggedUnion { .. } |
2180 RawNullablePointer { .. } |
2181 StructWrappedNullablePointer { .. } => bug!(),
2182
2183 FatPointer { .. } => 2,
2184
2185 Vector { count, .. } |
2186 Array { count, .. } => {
2187 let usize_count = count as usize;
2188 assert_eq!(usize_count as u64, count);
2189 usize_count
2190 }
2191
2192 Univariant { ref variant, .. } => variant.offsets.len(),
2193 }
2194 }
2195
7cac9316 2196 pub fn field_type<C: LayoutTyper<'tcx>>(&self, cx: C, i: usize) -> Ty<'tcx> {
cc61c64b
XL
2197 let tcx = cx.tcx();
2198
2199 let ptr_field_type = |pointee: Ty<'tcx>| {
3b2f2976 2200 assert!(i < 2);
cc61c64b 2201 let slice = |element: Ty<'tcx>| {
cc61c64b
XL
2202 if i == 0 {
2203 tcx.mk_mut_ptr(element)
2204 } else {
2205 tcx.types.usize
2206 }
2207 };
2208 match tcx.struct_tail(pointee).sty {
2209 ty::TySlice(element) => slice(element),
2210 ty::TyStr => slice(tcx.types.u8),
2211 ty::TyDynamic(..) => tcx.mk_mut_ptr(tcx.mk_nil()),
2212 _ => bug!("TyLayout::field_type({:?}): not applicable", self)
2213 }
2214 };
2215
2216 match self.ty.sty {
2217 ty::TyBool |
2218 ty::TyChar |
2219 ty::TyInt(_) |
2220 ty::TyUint(_) |
2221 ty::TyFloat(_) |
2222 ty::TyFnPtr(_) |
2223 ty::TyNever |
2224 ty::TyFnDef(..) |
2225 ty::TyDynamic(..) => {
2226 bug!("TyLayout::field_type({:?}): not applicable", self)
2227 }
2228
2229 // Potentially-fat pointers.
2230 ty::TyRef(_, ty::TypeAndMut { ty: pointee, .. }) |
2231 ty::TyRawPtr(ty::TypeAndMut { ty: pointee, .. }) => {
2232 ptr_field_type(pointee)
2233 }
2234 ty::TyAdt(def, _) if def.is_box() => {
2235 ptr_field_type(self.ty.boxed_ty())
2236 }
2237
2238 // Arrays and slices.
2239 ty::TyArray(element, _) |
2240 ty::TySlice(element) => element,
2241 ty::TyStr => tcx.types.u8,
2242
2243 // Tuples and closures.
2244 ty::TyClosure(def_id, ref substs) => {
2245 substs.upvar_tys(def_id, tcx).nth(i).unwrap()
2246 }
2247
2248 ty::TyTuple(tys, _) => tys[i],
2249
2250 // SIMD vector types.
2251 ty::TyAdt(def, ..) if def.repr.simd() => {
2252 self.ty.simd_type(tcx)
2253 }
2254
2255 // ADTs.
2256 ty::TyAdt(def, substs) => {
2257 def.variants[self.variant_index.unwrap_or(0)].fields[i].ty(tcx, substs)
2258 }
2259
2260 ty::TyProjection(_) | ty::TyAnon(..) | ty::TyParam(_) |
2261 ty::TyInfer(_) | ty::TyError => {
2262 bug!("TyLayout::field_type: unexpected type `{}`", self.ty)
2263 }
2264 }
2265 }
2266
7cac9316
XL
2267 pub fn field<C: LayoutTyper<'tcx>>(&self,
2268 cx: C,
2269 i: usize)
2270 -> C::TyLayout {
cc61c64b
XL
2271 cx.layout_of(cx.normalize_projections(self.field_type(cx, i)))
2272 }
2273}