]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_target/src/abi/mod.rs
Clarify `Layout` interning.
[rust.git] / compiler / rustc_target / src / abi / mod.rs
1 pub use Integer::*;
2 pub use Primitive::*;
3
4 use crate::spec::Target;
5
6 use std::convert::{TryFrom, TryInto};
7 use std::fmt;
8 use std::iter::Step;
9 use std::num::NonZeroUsize;
10 use std::ops::{Add, AddAssign, Deref, Mul, RangeInclusive, Sub};
11 use std::str::FromStr;
12
13 use rustc_data_structures::intern::Interned;
14 use rustc_index::vec::{Idx, IndexVec};
15 use rustc_macros::HashStable_Generic;
16 use rustc_serialize::json::{Json, ToJson};
17
18 pub mod call;
19
20 /// Parsed [Data layout](https://llvm.org/docs/LangRef.html#data-layout)
21 /// for a target, which contains everything needed to compute layouts.
22 pub struct TargetDataLayout {
23     pub endian: Endian,
24     pub i1_align: AbiAndPrefAlign,
25     pub i8_align: AbiAndPrefAlign,
26     pub i16_align: AbiAndPrefAlign,
27     pub i32_align: AbiAndPrefAlign,
28     pub i64_align: AbiAndPrefAlign,
29     pub i128_align: AbiAndPrefAlign,
30     pub f32_align: AbiAndPrefAlign,
31     pub f64_align: AbiAndPrefAlign,
32     pub pointer_size: Size,
33     pub pointer_align: AbiAndPrefAlign,
34     pub aggregate_align: AbiAndPrefAlign,
35
36     /// Alignments for vector types.
37     pub vector_align: Vec<(Size, AbiAndPrefAlign)>,
38
39     pub instruction_address_space: AddressSpace,
40
41     /// Minimum size of #[repr(C)] enums (default I32 bits)
42     pub c_enum_min_size: Integer,
43 }
44
45 impl Default for TargetDataLayout {
46     /// Creates an instance of `TargetDataLayout`.
47     fn default() -> TargetDataLayout {
48         let align = |bits| Align::from_bits(bits).unwrap();
49         TargetDataLayout {
50             endian: Endian::Big,
51             i1_align: AbiAndPrefAlign::new(align(8)),
52             i8_align: AbiAndPrefAlign::new(align(8)),
53             i16_align: AbiAndPrefAlign::new(align(16)),
54             i32_align: AbiAndPrefAlign::new(align(32)),
55             i64_align: AbiAndPrefAlign { abi: align(32), pref: align(64) },
56             i128_align: AbiAndPrefAlign { abi: align(32), pref: align(64) },
57             f32_align: AbiAndPrefAlign::new(align(32)),
58             f64_align: AbiAndPrefAlign::new(align(64)),
59             pointer_size: Size::from_bits(64),
60             pointer_align: AbiAndPrefAlign::new(align(64)),
61             aggregate_align: AbiAndPrefAlign { abi: align(0), pref: align(64) },
62             vector_align: vec![
63                 (Size::from_bits(64), AbiAndPrefAlign::new(align(64))),
64                 (Size::from_bits(128), AbiAndPrefAlign::new(align(128))),
65             ],
66             instruction_address_space: AddressSpace::DATA,
67             c_enum_min_size: Integer::I32,
68         }
69     }
70 }
71
72 impl TargetDataLayout {
73     pub fn parse(target: &Target) -> Result<TargetDataLayout, String> {
74         // Parse an address space index from a string.
75         let parse_address_space = |s: &str, cause: &str| {
76             s.parse::<u32>().map(AddressSpace).map_err(|err| {
77                 format!("invalid address space `{}` for `{}` in \"data-layout\": {}", s, cause, err)
78             })
79         };
80
81         // Parse a bit count from a string.
82         let parse_bits = |s: &str, kind: &str, cause: &str| {
83             s.parse::<u64>().map_err(|err| {
84                 format!("invalid {} `{}` for `{}` in \"data-layout\": {}", kind, s, cause, err)
85             })
86         };
87
88         // Parse a size string.
89         let size = |s: &str, cause: &str| parse_bits(s, "size", cause).map(Size::from_bits);
90
91         // Parse an alignment string.
92         let align = |s: &[&str], cause: &str| {
93             if s.is_empty() {
94                 return Err(format!("missing alignment for `{}` in \"data-layout\"", cause));
95             }
96             let align_from_bits = |bits| {
97                 Align::from_bits(bits).map_err(|err| {
98                     format!("invalid alignment for `{}` in \"data-layout\": {}", cause, err)
99                 })
100             };
101             let abi = parse_bits(s[0], "alignment", cause)?;
102             let pref = s.get(1).map_or(Ok(abi), |pref| parse_bits(pref, "alignment", cause))?;
103             Ok(AbiAndPrefAlign { abi: align_from_bits(abi)?, pref: align_from_bits(pref)? })
104         };
105
106         let mut dl = TargetDataLayout::default();
107         let mut i128_align_src = 64;
108         for spec in target.data_layout.split('-') {
109             let spec_parts = spec.split(':').collect::<Vec<_>>();
110
111             match &*spec_parts {
112                 ["e"] => dl.endian = Endian::Little,
113                 ["E"] => dl.endian = Endian::Big,
114                 [p] if p.starts_with('P') => {
115                     dl.instruction_address_space = parse_address_space(&p[1..], "P")?
116                 }
117                 ["a", ref a @ ..] => dl.aggregate_align = align(a, "a")?,
118                 ["f32", ref a @ ..] => dl.f32_align = align(a, "f32")?,
119                 ["f64", ref a @ ..] => dl.f64_align = align(a, "f64")?,
120                 [p @ "p", s, ref a @ ..] | [p @ "p0", s, ref a @ ..] => {
121                     dl.pointer_size = size(s, p)?;
122                     dl.pointer_align = align(a, p)?;
123                 }
124                 [s, ref a @ ..] if s.starts_with('i') => {
125                     let Ok(bits) = s[1..].parse::<u64>() else {
126                         size(&s[1..], "i")?; // For the user error.
127                         continue;
128                     };
129                     let a = align(a, s)?;
130                     match bits {
131                         1 => dl.i1_align = a,
132                         8 => dl.i8_align = a,
133                         16 => dl.i16_align = a,
134                         32 => dl.i32_align = a,
135                         64 => dl.i64_align = a,
136                         _ => {}
137                     }
138                     if bits >= i128_align_src && bits <= 128 {
139                         // Default alignment for i128 is decided by taking the alignment of
140                         // largest-sized i{64..=128}.
141                         i128_align_src = bits;
142                         dl.i128_align = a;
143                     }
144                 }
145                 [s, ref a @ ..] if s.starts_with('v') => {
146                     let v_size = size(&s[1..], "v")?;
147                     let a = align(a, s)?;
148                     if let Some(v) = dl.vector_align.iter_mut().find(|v| v.0 == v_size) {
149                         v.1 = a;
150                         continue;
151                     }
152                     // No existing entry, add a new one.
153                     dl.vector_align.push((v_size, a));
154                 }
155                 _ => {} // Ignore everything else.
156             }
157         }
158
159         // Perform consistency checks against the Target information.
160         if dl.endian != target.endian {
161             return Err(format!(
162                 "inconsistent target specification: \"data-layout\" claims \
163                  architecture is {}-endian, while \"target-endian\" is `{}`",
164                 dl.endian.as_str(),
165                 target.endian.as_str(),
166             ));
167         }
168
169         if dl.pointer_size.bits() != target.pointer_width.into() {
170             return Err(format!(
171                 "inconsistent target specification: \"data-layout\" claims \
172                  pointers are {}-bit, while \"target-pointer-width\" is `{}`",
173                 dl.pointer_size.bits(),
174                 target.pointer_width
175             ));
176         }
177
178         dl.c_enum_min_size = Integer::from_size(Size::from_bits(target.c_enum_min_bits))?;
179
180         Ok(dl)
181     }
182
183     /// Returns exclusive upper bound on object size.
184     ///
185     /// The theoretical maximum object size is defined as the maximum positive `isize` value.
186     /// This ensures that the `offset` semantics remain well-defined by allowing it to correctly
187     /// index every address within an object along with one byte past the end, along with allowing
188     /// `isize` to store the difference between any two pointers into an object.
189     ///
190     /// The upper bound on 64-bit currently needs to be lower because LLVM uses a 64-bit integer
191     /// to represent object size in bits. It would need to be 1 << 61 to account for this, but is
192     /// currently conservatively bounded to 1 << 47 as that is enough to cover the current usable
193     /// address space on 64-bit ARMv8 and x86_64.
194     #[inline]
195     pub fn obj_size_bound(&self) -> u64 {
196         match self.pointer_size.bits() {
197             16 => 1 << 15,
198             32 => 1 << 31,
199             64 => 1 << 47,
200             bits => panic!("obj_size_bound: unknown pointer bit size {}", bits),
201         }
202     }
203
204     #[inline]
205     pub fn ptr_sized_integer(&self) -> Integer {
206         match self.pointer_size.bits() {
207             16 => I16,
208             32 => I32,
209             64 => I64,
210             bits => panic!("ptr_sized_integer: unknown pointer bit size {}", bits),
211         }
212     }
213
214     #[inline]
215     pub fn vector_align(&self, vec_size: Size) -> AbiAndPrefAlign {
216         for &(size, align) in &self.vector_align {
217             if size == vec_size {
218                 return align;
219             }
220         }
221         // Default to natural alignment, which is what LLVM does.
222         // That is, use the size, rounded up to a power of 2.
223         AbiAndPrefAlign::new(Align::from_bytes(vec_size.bytes().next_power_of_two()).unwrap())
224     }
225 }
226
227 pub trait HasDataLayout {
228     fn data_layout(&self) -> &TargetDataLayout;
229 }
230
231 impl HasDataLayout for TargetDataLayout {
232     #[inline]
233     fn data_layout(&self) -> &TargetDataLayout {
234         self
235     }
236 }
237
238 /// Endianness of the target, which must match cfg(target-endian).
239 #[derive(Copy, Clone, PartialEq)]
240 pub enum Endian {
241     Little,
242     Big,
243 }
244
245 impl Endian {
246     pub fn as_str(&self) -> &'static str {
247         match self {
248             Self::Little => "little",
249             Self::Big => "big",
250         }
251     }
252 }
253
254 impl fmt::Debug for Endian {
255     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
256         f.write_str(self.as_str())
257     }
258 }
259
260 impl FromStr for Endian {
261     type Err = String;
262
263     fn from_str(s: &str) -> Result<Self, Self::Err> {
264         match s {
265             "little" => Ok(Self::Little),
266             "big" => Ok(Self::Big),
267             _ => Err(format!(r#"unknown endian: "{}""#, s)),
268         }
269     }
270 }
271
272 impl ToJson for Endian {
273     fn to_json(&self) -> Json {
274         self.as_str().to_json()
275     }
276 }
277
278 /// Size of a type in bytes.
279 #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Encodable, Decodable)]
280 #[derive(HashStable_Generic)]
281 pub struct Size {
282     // The top 3 bits are ALWAYS zero.
283     raw: u64,
284 }
285
286 impl Size {
287     pub const ZERO: Size = Size { raw: 0 };
288
289     /// Rounds `bits` up to the next-higher byte boundary, if `bits` is
290     /// is not aligned.
291     pub fn from_bits(bits: impl TryInto<u64>) -> Size {
292         let bits = bits.try_into().ok().unwrap();
293
294         #[cold]
295         fn overflow(bits: u64) -> ! {
296             panic!("Size::from_bits({}) has overflowed", bits);
297         }
298
299         // This is the largest value of `bits` that does not cause overflow
300         // during rounding, and guarantees that the resulting number of bytes
301         // cannot cause overflow when multiplied by 8.
302         if bits > 0xffff_ffff_ffff_fff8 {
303             overflow(bits);
304         }
305
306         // Avoid potential overflow from `bits + 7`.
307         Size { raw: bits / 8 + ((bits % 8) + 7) / 8 }
308     }
309
310     #[inline]
311     pub fn from_bytes(bytes: impl TryInto<u64>) -> Size {
312         let bytes: u64 = bytes.try_into().ok().unwrap();
313         Size { raw: bytes }
314     }
315
316     #[inline]
317     pub fn bytes(self) -> u64 {
318         self.raw
319     }
320
321     #[inline]
322     pub fn bytes_usize(self) -> usize {
323         self.bytes().try_into().unwrap()
324     }
325
326     #[inline]
327     pub fn bits(self) -> u64 {
328         self.raw << 3
329     }
330
331     #[inline]
332     pub fn bits_usize(self) -> usize {
333         self.bits().try_into().unwrap()
334     }
335
336     #[inline]
337     pub fn align_to(self, align: Align) -> Size {
338         let mask = align.bytes() - 1;
339         Size::from_bytes((self.bytes() + mask) & !mask)
340     }
341
342     #[inline]
343     pub fn is_aligned(self, align: Align) -> bool {
344         let mask = align.bytes() - 1;
345         self.bytes() & mask == 0
346     }
347
348     #[inline]
349     pub fn checked_add<C: HasDataLayout>(self, offset: Size, cx: &C) -> Option<Size> {
350         let dl = cx.data_layout();
351
352         let bytes = self.bytes().checked_add(offset.bytes())?;
353
354         if bytes < dl.obj_size_bound() { Some(Size::from_bytes(bytes)) } else { None }
355     }
356
357     #[inline]
358     pub fn checked_mul<C: HasDataLayout>(self, count: u64, cx: &C) -> Option<Size> {
359         let dl = cx.data_layout();
360
361         let bytes = self.bytes().checked_mul(count)?;
362         if bytes < dl.obj_size_bound() { Some(Size::from_bytes(bytes)) } else { None }
363     }
364
365     /// Truncates `value` to `self` bits and then sign-extends it to 128 bits
366     /// (i.e., if it is negative, fill with 1's on the left).
367     #[inline]
368     pub fn sign_extend(self, value: u128) -> u128 {
369         let size = self.bits();
370         if size == 0 {
371             // Truncated until nothing is left.
372             return 0;
373         }
374         // Sign-extend it.
375         let shift = 128 - size;
376         // Shift the unsigned value to the left, then shift back to the right as signed
377         // (essentially fills with sign bit on the left).
378         (((value << shift) as i128) >> shift) as u128
379     }
380
381     /// Truncates `value` to `self` bits.
382     #[inline]
383     pub fn truncate(self, value: u128) -> u128 {
384         let size = self.bits();
385         if size == 0 {
386             // Truncated until nothing is left.
387             return 0;
388         }
389         let shift = 128 - size;
390         // Truncate (shift left to drop out leftover values, shift right to fill with zeroes).
391         (value << shift) >> shift
392     }
393
394     #[inline]
395     pub fn signed_int_min(&self) -> i128 {
396         self.sign_extend(1_u128 << (self.bits() - 1)) as i128
397     }
398
399     #[inline]
400     pub fn signed_int_max(&self) -> i128 {
401         i128::MAX >> (128 - self.bits())
402     }
403
404     #[inline]
405     pub fn unsigned_int_max(&self) -> u128 {
406         u128::MAX >> (128 - self.bits())
407     }
408 }
409
410 // Panicking addition, subtraction and multiplication for convenience.
411 // Avoid during layout computation, return `LayoutError` instead.
412
413 impl Add for Size {
414     type Output = Size;
415     #[inline]
416     fn add(self, other: Size) -> Size {
417         Size::from_bytes(self.bytes().checked_add(other.bytes()).unwrap_or_else(|| {
418             panic!("Size::add: {} + {} doesn't fit in u64", self.bytes(), other.bytes())
419         }))
420     }
421 }
422
423 impl Sub for Size {
424     type Output = Size;
425     #[inline]
426     fn sub(self, other: Size) -> Size {
427         Size::from_bytes(self.bytes().checked_sub(other.bytes()).unwrap_or_else(|| {
428             panic!("Size::sub: {} - {} would result in negative size", self.bytes(), other.bytes())
429         }))
430     }
431 }
432
433 impl Mul<Size> for u64 {
434     type Output = Size;
435     #[inline]
436     fn mul(self, size: Size) -> Size {
437         size * self
438     }
439 }
440
441 impl Mul<u64> for Size {
442     type Output = Size;
443     #[inline]
444     fn mul(self, count: u64) -> Size {
445         match self.bytes().checked_mul(count) {
446             Some(bytes) => Size::from_bytes(bytes),
447             None => panic!("Size::mul: {} * {} doesn't fit in u64", self.bytes(), count),
448         }
449     }
450 }
451
452 impl AddAssign for Size {
453     #[inline]
454     fn add_assign(&mut self, other: Size) {
455         *self = *self + other;
456     }
457 }
458
459 impl Step for Size {
460     #[inline]
461     fn steps_between(start: &Self, end: &Self) -> Option<usize> {
462         u64::steps_between(&start.bytes(), &end.bytes())
463     }
464
465     #[inline]
466     fn forward_checked(start: Self, count: usize) -> Option<Self> {
467         u64::forward_checked(start.bytes(), count).map(Self::from_bytes)
468     }
469
470     #[inline]
471     fn forward(start: Self, count: usize) -> Self {
472         Self::from_bytes(u64::forward(start.bytes(), count))
473     }
474
475     #[inline]
476     unsafe fn forward_unchecked(start: Self, count: usize) -> Self {
477         Self::from_bytes(u64::forward_unchecked(start.bytes(), count))
478     }
479
480     #[inline]
481     fn backward_checked(start: Self, count: usize) -> Option<Self> {
482         u64::backward_checked(start.bytes(), count).map(Self::from_bytes)
483     }
484
485     #[inline]
486     fn backward(start: Self, count: usize) -> Self {
487         Self::from_bytes(u64::backward(start.bytes(), count))
488     }
489
490     #[inline]
491     unsafe fn backward_unchecked(start: Self, count: usize) -> Self {
492         Self::from_bytes(u64::backward_unchecked(start.bytes(), count))
493     }
494 }
495
496 /// Alignment of a type in bytes (always a power of two).
497 #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Encodable, Decodable)]
498 #[derive(HashStable_Generic)]
499 pub struct Align {
500     pow2: u8,
501 }
502
503 impl Align {
504     pub const ONE: Align = Align { pow2: 0 };
505
506     #[inline]
507     pub fn from_bits(bits: u64) -> Result<Align, String> {
508         Align::from_bytes(Size::from_bits(bits).bytes())
509     }
510
511     #[inline]
512     pub fn from_bytes(align: u64) -> Result<Align, String> {
513         // Treat an alignment of 0 bytes like 1-byte alignment.
514         if align == 0 {
515             return Ok(Align::ONE);
516         }
517
518         #[cold]
519         fn not_power_of_2(align: u64) -> String {
520             format!("`{}` is not a power of 2", align)
521         }
522
523         #[cold]
524         fn too_large(align: u64) -> String {
525             format!("`{}` is too large", align)
526         }
527
528         let mut bytes = align;
529         let mut pow2: u8 = 0;
530         while (bytes & 1) == 0 {
531             pow2 += 1;
532             bytes >>= 1;
533         }
534         if bytes != 1 {
535             return Err(not_power_of_2(align));
536         }
537         if pow2 > 29 {
538             return Err(too_large(align));
539         }
540
541         Ok(Align { pow2 })
542     }
543
544     #[inline]
545     pub fn bytes(self) -> u64 {
546         1 << self.pow2
547     }
548
549     #[inline]
550     pub fn bits(self) -> u64 {
551         self.bytes() * 8
552     }
553
554     /// Computes the best alignment possible for the given offset
555     /// (the largest power of two that the offset is a multiple of).
556     ///
557     /// N.B., for an offset of `0`, this happens to return `2^64`.
558     #[inline]
559     pub fn max_for_offset(offset: Size) -> Align {
560         Align { pow2: offset.bytes().trailing_zeros() as u8 }
561     }
562
563     /// Lower the alignment, if necessary, such that the given offset
564     /// is aligned to it (the offset is a multiple of the alignment).
565     #[inline]
566     pub fn restrict_for_offset(self, offset: Size) -> Align {
567         self.min(Align::max_for_offset(offset))
568     }
569 }
570
571 /// A pair of alignments, ABI-mandated and preferred.
572 #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, Encodable, Decodable)]
573 #[derive(HashStable_Generic)]
574 pub struct AbiAndPrefAlign {
575     pub abi: Align,
576     pub pref: Align,
577 }
578
579 impl AbiAndPrefAlign {
580     #[inline]
581     pub fn new(align: Align) -> AbiAndPrefAlign {
582         AbiAndPrefAlign { abi: align, pref: align }
583     }
584
585     #[inline]
586     pub fn min(self, other: AbiAndPrefAlign) -> AbiAndPrefAlign {
587         AbiAndPrefAlign { abi: self.abi.min(other.abi), pref: self.pref.min(other.pref) }
588     }
589
590     #[inline]
591     pub fn max(self, other: AbiAndPrefAlign) -> AbiAndPrefAlign {
592         AbiAndPrefAlign { abi: self.abi.max(other.abi), pref: self.pref.max(other.pref) }
593     }
594 }
595
596 /// Integers, also used for enum discriminants.
597 #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, HashStable_Generic)]
598 pub enum Integer {
599     I8,
600     I16,
601     I32,
602     I64,
603     I128,
604 }
605
606 impl Integer {
607     #[inline]
608     pub fn size(self) -> Size {
609         match self {
610             I8 => Size::from_bytes(1),
611             I16 => Size::from_bytes(2),
612             I32 => Size::from_bytes(4),
613             I64 => Size::from_bytes(8),
614             I128 => Size::from_bytes(16),
615         }
616     }
617
618     pub fn align<C: HasDataLayout>(self, cx: &C) -> AbiAndPrefAlign {
619         let dl = cx.data_layout();
620
621         match self {
622             I8 => dl.i8_align,
623             I16 => dl.i16_align,
624             I32 => dl.i32_align,
625             I64 => dl.i64_align,
626             I128 => dl.i128_align,
627         }
628     }
629
630     /// Finds the smallest Integer type which can represent the signed value.
631     #[inline]
632     pub fn fit_signed(x: i128) -> Integer {
633         match x {
634             -0x0000_0000_0000_0080..=0x0000_0000_0000_007f => I8,
635             -0x0000_0000_0000_8000..=0x0000_0000_0000_7fff => I16,
636             -0x0000_0000_8000_0000..=0x0000_0000_7fff_ffff => I32,
637             -0x8000_0000_0000_0000..=0x7fff_ffff_ffff_ffff => I64,
638             _ => I128,
639         }
640     }
641
642     /// Finds the smallest Integer type which can represent the unsigned value.
643     #[inline]
644     pub fn fit_unsigned(x: u128) -> Integer {
645         match x {
646             0..=0x0000_0000_0000_00ff => I8,
647             0..=0x0000_0000_0000_ffff => I16,
648             0..=0x0000_0000_ffff_ffff => I32,
649             0..=0xffff_ffff_ffff_ffff => I64,
650             _ => I128,
651         }
652     }
653
654     /// Finds the smallest integer with the given alignment.
655     pub fn for_align<C: HasDataLayout>(cx: &C, wanted: Align) -> Option<Integer> {
656         let dl = cx.data_layout();
657
658         for candidate in [I8, I16, I32, I64, I128] {
659             if wanted == candidate.align(dl).abi && wanted.bytes() == candidate.size().bytes() {
660                 return Some(candidate);
661             }
662         }
663         None
664     }
665
666     /// Find the largest integer with the given alignment or less.
667     pub fn approximate_align<C: HasDataLayout>(cx: &C, wanted: Align) -> Integer {
668         let dl = cx.data_layout();
669
670         // FIXME(eddyb) maybe include I128 in the future, when it works everywhere.
671         for candidate in [I64, I32, I16] {
672             if wanted >= candidate.align(dl).abi && wanted.bytes() >= candidate.size().bytes() {
673                 return candidate;
674             }
675         }
676         I8
677     }
678
679     // FIXME(eddyb) consolidate this and other methods that find the appropriate
680     // `Integer` given some requirements.
681     #[inline]
682     fn from_size(size: Size) -> Result<Self, String> {
683         match size.bits() {
684             8 => Ok(Integer::I8),
685             16 => Ok(Integer::I16),
686             32 => Ok(Integer::I32),
687             64 => Ok(Integer::I64),
688             128 => Ok(Integer::I128),
689             _ => Err(format!("rust does not support integers with {} bits", size.bits())),
690         }
691     }
692 }
693
694 /// Fundamental unit of memory access and layout.
695 #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, HashStable_Generic)]
696 pub enum Primitive {
697     /// The `bool` is the signedness of the `Integer` type.
698     ///
699     /// One would think we would not care about such details this low down,
700     /// but some ABIs are described in terms of C types and ISAs where the
701     /// integer arithmetic is done on {sign,zero}-extended registers, e.g.
702     /// a negative integer passed by zero-extension will appear positive in
703     /// the callee, and most operations on it will produce the wrong values.
704     Int(Integer, bool),
705     F32,
706     F64,
707     Pointer,
708 }
709
710 impl Primitive {
711     pub fn size<C: HasDataLayout>(self, cx: &C) -> Size {
712         let dl = cx.data_layout();
713
714         match self {
715             Int(i, _) => i.size(),
716             F32 => Size::from_bits(32),
717             F64 => Size::from_bits(64),
718             Pointer => dl.pointer_size,
719         }
720     }
721
722     pub fn align<C: HasDataLayout>(self, cx: &C) -> AbiAndPrefAlign {
723         let dl = cx.data_layout();
724
725         match self {
726             Int(i, _) => i.align(dl),
727             F32 => dl.f32_align,
728             F64 => dl.f64_align,
729             Pointer => dl.pointer_align,
730         }
731     }
732
733     // FIXME(eddyb) remove, it's trivial thanks to `matches!`.
734     #[inline]
735     pub fn is_float(self) -> bool {
736         matches!(self, F32 | F64)
737     }
738
739     // FIXME(eddyb) remove, it's completely unused.
740     #[inline]
741     pub fn is_int(self) -> bool {
742         matches!(self, Int(..))
743     }
744 }
745
746 /// Inclusive wrap-around range of valid values, that is, if
747 /// start > end, it represents `start..=MAX`,
748 /// followed by `0..=end`.
749 ///
750 /// That is, for an i8 primitive, a range of `254..=2` means following
751 /// sequence:
752 ///
753 ///    254 (-2), 255 (-1), 0, 1, 2
754 ///
755 /// This is intended specifically to mirror LLVM’s `!range` metadata semantics.
756 #[derive(Clone, Copy, PartialEq, Eq, Hash)]
757 #[derive(HashStable_Generic)]
758 pub struct WrappingRange {
759     pub start: u128,
760     pub end: u128,
761 }
762
763 impl WrappingRange {
764     /// Returns `true` if `v` is contained in the range.
765     #[inline(always)]
766     pub fn contains(&self, v: u128) -> bool {
767         if self.start <= self.end {
768             self.start <= v && v <= self.end
769         } else {
770             self.start <= v || v <= self.end
771         }
772     }
773
774     /// Returns `self` with replaced `start`
775     #[inline(always)]
776     pub fn with_start(mut self, start: u128) -> Self {
777         self.start = start;
778         self
779     }
780
781     /// Returns `self` with replaced `end`
782     #[inline(always)]
783     pub fn with_end(mut self, end: u128) -> Self {
784         self.end = end;
785         self
786     }
787
788     /// Returns `true` if `size` completely fills the range.
789     #[inline]
790     pub fn is_full_for(&self, size: Size) -> bool {
791         let max_value = size.unsigned_int_max();
792         debug_assert!(self.start <= max_value && self.end <= max_value);
793         self.start == (self.end.wrapping_add(1) & max_value)
794     }
795 }
796
797 impl fmt::Debug for WrappingRange {
798     fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
799         if self.start > self.end {
800             write!(fmt, "(..={}) | ({}..)", self.end, self.start)?;
801         } else {
802             write!(fmt, "{}..={}", self.start, self.end)?;
803         }
804         Ok(())
805     }
806 }
807
808 /// Information about one scalar component of a Rust type.
809 #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
810 #[derive(HashStable_Generic)]
811 pub struct Scalar {
812     pub value: Primitive,
813
814     // FIXME(eddyb) always use the shortest range, e.g., by finding
815     // the largest space between two consecutive valid values and
816     // taking everything else as the (shortest) valid range.
817     pub valid_range: WrappingRange,
818 }
819
820 impl Scalar {
821     #[inline]
822     pub fn is_bool(&self) -> bool {
823         matches!(
824             self,
825             Scalar { value: Int(I8, false), valid_range: WrappingRange { start: 0, end: 1 } }
826         )
827     }
828
829     /// Returns `true` if all possible numbers are valid, i.e `valid_range` covers the whole layout
830     #[inline]
831     pub fn is_always_valid<C: HasDataLayout>(&self, cx: &C) -> bool {
832         self.valid_range.is_full_for(self.value.size(cx))
833     }
834 }
835
836 /// Describes how the fields of a type are located in memory.
837 #[derive(PartialEq, Eq, Hash, Debug, HashStable_Generic)]
838 pub enum FieldsShape {
839     /// Scalar primitives and `!`, which never have fields.
840     Primitive,
841
842     /// All fields start at no offset. The `usize` is the field count.
843     Union(NonZeroUsize),
844
845     /// Array/vector-like placement, with all fields of identical types.
846     Array { stride: Size, count: u64 },
847
848     /// Struct-like placement, with precomputed offsets.
849     ///
850     /// Fields are guaranteed to not overlap, but note that gaps
851     /// before, between and after all the fields are NOT always
852     /// padding, and as such their contents may not be discarded.
853     /// For example, enum variants leave a gap at the start,
854     /// where the discriminant field in the enum layout goes.
855     Arbitrary {
856         /// Offsets for the first byte of each field,
857         /// ordered to match the source definition order.
858         /// This vector does not go in increasing order.
859         // FIXME(eddyb) use small vector optimization for the common case.
860         offsets: Vec<Size>,
861
862         /// Maps source order field indices to memory order indices,
863         /// depending on how the fields were reordered (if at all).
864         /// This is a permutation, with both the source order and the
865         /// memory order using the same (0..n) index ranges.
866         ///
867         /// Note that during computation of `memory_index`, sometimes
868         /// it is easier to operate on the inverse mapping (that is,
869         /// from memory order to source order), and that is usually
870         /// named `inverse_memory_index`.
871         ///
872         // FIXME(eddyb) build a better abstraction for permutations, if possible.
873         // FIXME(camlorn) also consider small vector  optimization here.
874         memory_index: Vec<u32>,
875     },
876 }
877
878 impl FieldsShape {
879     #[inline]
880     pub fn count(&self) -> usize {
881         match *self {
882             FieldsShape::Primitive => 0,
883             FieldsShape::Union(count) => count.get(),
884             FieldsShape::Array { count, .. } => count.try_into().unwrap(),
885             FieldsShape::Arbitrary { ref offsets, .. } => offsets.len(),
886         }
887     }
888
889     #[inline]
890     pub fn offset(&self, i: usize) -> Size {
891         match *self {
892             FieldsShape::Primitive => {
893                 unreachable!("FieldsShape::offset: `Primitive`s have no fields")
894             }
895             FieldsShape::Union(count) => {
896                 assert!(
897                     i < count.get(),
898                     "tried to access field {} of union with {} fields",
899                     i,
900                     count
901                 );
902                 Size::ZERO
903             }
904             FieldsShape::Array { stride, count } => {
905                 let i = u64::try_from(i).unwrap();
906                 assert!(i < count);
907                 stride * i
908             }
909             FieldsShape::Arbitrary { ref offsets, .. } => offsets[i],
910         }
911     }
912
913     #[inline]
914     pub fn memory_index(&self, i: usize) -> usize {
915         match *self {
916             FieldsShape::Primitive => {
917                 unreachable!("FieldsShape::memory_index: `Primitive`s have no fields")
918             }
919             FieldsShape::Union(_) | FieldsShape::Array { .. } => i,
920             FieldsShape::Arbitrary { ref memory_index, .. } => memory_index[i].try_into().unwrap(),
921         }
922     }
923
924     /// Gets source indices of the fields by increasing offsets.
925     #[inline]
926     pub fn index_by_increasing_offset<'a>(&'a self) -> impl Iterator<Item = usize> + 'a {
927         let mut inverse_small = [0u8; 64];
928         let mut inverse_big = vec![];
929         let use_small = self.count() <= inverse_small.len();
930
931         // We have to write this logic twice in order to keep the array small.
932         if let FieldsShape::Arbitrary { ref memory_index, .. } = *self {
933             if use_small {
934                 for i in 0..self.count() {
935                     inverse_small[memory_index[i] as usize] = i as u8;
936                 }
937             } else {
938                 inverse_big = vec![0; self.count()];
939                 for i in 0..self.count() {
940                     inverse_big[memory_index[i] as usize] = i as u32;
941                 }
942             }
943         }
944
945         (0..self.count()).map(move |i| match *self {
946             FieldsShape::Primitive | FieldsShape::Union(_) | FieldsShape::Array { .. } => i,
947             FieldsShape::Arbitrary { .. } => {
948                 if use_small {
949                     inverse_small[i] as usize
950                 } else {
951                     inverse_big[i] as usize
952                 }
953             }
954         })
955     }
956 }
957
958 /// An identifier that specifies the address space that some operation
959 /// should operate on. Special address spaces have an effect on code generation,
960 /// depending on the target and the address spaces it implements.
961 #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
962 pub struct AddressSpace(pub u32);
963
964 impl AddressSpace {
965     /// The default address space, corresponding to data space.
966     pub const DATA: Self = AddressSpace(0);
967 }
968
969 /// Describes how values of the type are passed by target ABIs,
970 /// in terms of categories of C types there are ABI rules for.
971 #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, HashStable_Generic)]
972 pub enum Abi {
973     Uninhabited,
974     Scalar(Scalar),
975     ScalarPair(Scalar, Scalar),
976     Vector {
977         element: Scalar,
978         count: u64,
979     },
980     Aggregate {
981         /// If true, the size is exact, otherwise it's only a lower bound.
982         sized: bool,
983     },
984 }
985
986 impl Abi {
987     /// Returns `true` if the layout corresponds to an unsized type.
988     #[inline]
989     pub fn is_unsized(&self) -> bool {
990         match *self {
991             Abi::Uninhabited | Abi::Scalar(_) | Abi::ScalarPair(..) | Abi::Vector { .. } => false,
992             Abi::Aggregate { sized } => !sized,
993         }
994     }
995
996     /// Returns `true` if this is a single signed integer scalar
997     #[inline]
998     pub fn is_signed(&self) -> bool {
999         match self {
1000             Abi::Scalar(scal) => match scal.value {
1001                 Primitive::Int(_, signed) => signed,
1002                 _ => false,
1003             },
1004             _ => panic!("`is_signed` on non-scalar ABI {:?}", self),
1005         }
1006     }
1007
1008     /// Returns `true` if this is an uninhabited type
1009     #[inline]
1010     pub fn is_uninhabited(&self) -> bool {
1011         matches!(*self, Abi::Uninhabited)
1012     }
1013
1014     /// Returns `true` is this is a scalar type
1015     #[inline]
1016     pub fn is_scalar(&self) -> bool {
1017         matches!(*self, Abi::Scalar(_))
1018     }
1019 }
1020
1021 rustc_index::newtype_index! {
1022     pub struct VariantIdx {
1023         derive [HashStable_Generic]
1024     }
1025 }
1026
1027 #[derive(PartialEq, Eq, Hash, Debug, HashStable_Generic)]
1028 pub enum Variants<'a> {
1029     /// Single enum variants, structs/tuples, unions, and all non-ADTs.
1030     Single { index: VariantIdx },
1031
1032     /// Enum-likes with more than one inhabited variant: each variant comes with
1033     /// a *discriminant* (usually the same as the variant index but the user can
1034     /// assign explicit discriminant values).  That discriminant is encoded
1035     /// as a *tag* on the machine.  The layout of each variant is
1036     /// a struct, and they all have space reserved for the tag.
1037     /// For enums, the tag is the sole field of the layout.
1038     Multiple {
1039         tag: Scalar,
1040         tag_encoding: TagEncoding,
1041         tag_field: usize,
1042         variants: IndexVec<VariantIdx, Layout<'a>>,
1043     },
1044 }
1045
1046 #[derive(PartialEq, Eq, Hash, Debug, HashStable_Generic)]
1047 pub enum TagEncoding {
1048     /// The tag directly stores the discriminant, but possibly with a smaller layout
1049     /// (so converting the tag to the discriminant can require sign extension).
1050     Direct,
1051
1052     /// Niche (values invalid for a type) encoding the discriminant:
1053     /// Discriminant and variant index coincide.
1054     /// The variant `dataful_variant` contains a niche at an arbitrary
1055     /// offset (field `tag_field` of the enum), which for a variant with
1056     /// discriminant `d` is set to
1057     /// `(d - niche_variants.start).wrapping_add(niche_start)`.
1058     ///
1059     /// For example, `Option<(usize, &T)>`  is represented such that
1060     /// `None` has a null pointer for the second tuple field, and
1061     /// `Some` is the identity function (with a non-null reference).
1062     Niche {
1063         dataful_variant: VariantIdx,
1064         niche_variants: RangeInclusive<VariantIdx>,
1065         niche_start: u128,
1066     },
1067 }
1068
1069 #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, HashStable_Generic)]
1070 pub struct Niche {
1071     pub offset: Size,
1072     pub scalar: Scalar,
1073 }
1074
1075 impl Niche {
1076     pub fn from_scalar<C: HasDataLayout>(cx: &C, offset: Size, scalar: Scalar) -> Option<Self> {
1077         let niche = Niche { offset, scalar };
1078         if niche.available(cx) > 0 { Some(niche) } else { None }
1079     }
1080
1081     pub fn available<C: HasDataLayout>(&self, cx: &C) -> u128 {
1082         let Scalar { value, valid_range: v } = self.scalar;
1083         let size = value.size(cx);
1084         assert!(size.bits() <= 128);
1085         let max_value = size.unsigned_int_max();
1086
1087         // Find out how many values are outside the valid range.
1088         let niche = v.end.wrapping_add(1)..v.start;
1089         niche.end.wrapping_sub(niche.start) & max_value
1090     }
1091
1092     pub fn reserve<C: HasDataLayout>(&self, cx: &C, count: u128) -> Option<(u128, Scalar)> {
1093         assert!(count > 0);
1094
1095         let Scalar { value, valid_range: v } = self.scalar;
1096         let size = value.size(cx);
1097         assert!(size.bits() <= 128);
1098         let max_value = size.unsigned_int_max();
1099
1100         let niche = v.end.wrapping_add(1)..v.start;
1101         let available = niche.end.wrapping_sub(niche.start) & max_value;
1102         if count > available {
1103             return None;
1104         }
1105
1106         // Extend the range of valid values being reserved by moving either `v.start` or `v.end` bound.
1107         // Given an eventual `Option<T>`, we try to maximize the chance for `None` to occupy the niche of zero.
1108         // This is accomplished by prefering enums with 2 variants(`count==1`) and always taking the shortest path to niche zero.
1109         // Having `None` in niche zero can enable some special optimizations.
1110         //
1111         // Bound selection criteria:
1112         // 1. Select closest to zero given wrapping semantics.
1113         // 2. Avoid moving past zero if possible.
1114         //
1115         // In practice this means that enums with `count > 1` are unlikely to claim niche zero, since they have to fit perfectly.
1116         // If niche zero is already reserved, the selection of bounds are of little interest.
1117         let move_start = |v: WrappingRange| {
1118             let start = v.start.wrapping_sub(count) & max_value;
1119             Some((start, Scalar { value, valid_range: v.with_start(start) }))
1120         };
1121         let move_end = |v: WrappingRange| {
1122             let start = v.end.wrapping_add(1) & max_value;
1123             let end = v.end.wrapping_add(count) & max_value;
1124             Some((start, Scalar { value, valid_range: v.with_end(end) }))
1125         };
1126         let distance_end_zero = max_value - v.end;
1127         if v.start > v.end {
1128             // zero is unavailable because wrapping occurs
1129             move_end(v)
1130         } else if v.start <= distance_end_zero {
1131             if count <= v.start {
1132                 move_start(v)
1133             } else {
1134                 // moved past zero, use other bound
1135                 move_end(v)
1136             }
1137         } else {
1138             let end = v.end.wrapping_add(count) & max_value;
1139             let overshot_zero = (1..=v.end).contains(&end);
1140             if overshot_zero {
1141                 // moved past zero, use other bound
1142                 move_start(v)
1143             } else {
1144                 move_end(v)
1145             }
1146         }
1147     }
1148 }
1149
1150 #[derive(PartialEq, Eq, Hash, HashStable_Generic)]
1151 pub struct LayoutS<'a> {
1152     /// Says where the fields are located within the layout.
1153     pub fields: FieldsShape,
1154
1155     /// Encodes information about multi-variant layouts.
1156     /// Even with `Multiple` variants, a layout still has its own fields! Those are then
1157     /// shared between all variants. One of them will be the discriminant,
1158     /// but e.g. generators can have more.
1159     ///
1160     /// To access all fields of this layout, both `fields` and the fields of the active variant
1161     /// must be taken into account.
1162     pub variants: Variants<'a>,
1163
1164     /// The `abi` defines how this data is passed between functions, and it defines
1165     /// value restrictions via `valid_range`.
1166     ///
1167     /// Note that this is entirely orthogonal to the recursive structure defined by
1168     /// `variants` and `fields`; for example, `ManuallyDrop<Result<isize, isize>>` has
1169     /// `Abi::ScalarPair`! So, even with non-`Aggregate` `abi`, `fields` and `variants`
1170     /// have to be taken into account to find all fields of this layout.
1171     pub abi: Abi,
1172
1173     /// The leaf scalar with the largest number of invalid values
1174     /// (i.e. outside of its `valid_range`), if it exists.
1175     pub largest_niche: Option<Niche>,
1176
1177     pub align: AbiAndPrefAlign,
1178     pub size: Size,
1179 }
1180
1181 impl<'a> LayoutS<'a> {
1182     pub fn scalar<C: HasDataLayout>(cx: &C, scalar: Scalar) -> Self {
1183         let largest_niche = Niche::from_scalar(cx, Size::ZERO, scalar);
1184         let size = scalar.value.size(cx);
1185         let align = scalar.value.align(cx);
1186         LayoutS {
1187             variants: Variants::Single { index: VariantIdx::new(0) },
1188             fields: FieldsShape::Primitive,
1189             abi: Abi::Scalar(scalar),
1190             largest_niche,
1191             size,
1192             align,
1193         }
1194     }
1195 }
1196
1197 impl<'a> fmt::Debug for LayoutS<'a> {
1198     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1199         // This is how `Layout` used to print before it become
1200         // `Interned<LayoutS>`. We print it like this to avoid having to update
1201         // expected output in a lot of tests.
1202         f.debug_struct("Layout")
1203             .field("fields", &self.fields)
1204             .field("variants", &self.variants)
1205             .field("abi", &self.abi)
1206             .field("largest_niche", &self.largest_niche)
1207             .field("align", &self.align)
1208             .field("size", &self.size)
1209             .finish()
1210     }
1211 }
1212
1213 #[derive(Copy, Clone, PartialEq, Eq, Hash, HashStable_Generic)]
1214 #[cfg_attr(not(bootstrap), rustc_pass_by_value)]
1215 pub struct Layout<'a>(pub Interned<'a, LayoutS<'a>>);
1216
1217 impl<'a> fmt::Debug for Layout<'a> {
1218     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1219         // See comment on `<LayoutS as Debug>::fmt` above.
1220         self.0.0.fmt(f)
1221     }
1222 }
1223
1224 impl<'a> Layout<'a> {
1225     pub fn fields(self) -> &'a FieldsShape {
1226         &self.0.0.fields
1227     }
1228
1229     pub fn variants(self) -> &'a Variants<'a> {
1230         &self.0.0.variants
1231     }
1232
1233     pub fn abi(self) -> Abi {
1234         self.0.0.abi
1235     }
1236
1237     pub fn largest_niche(self) -> Option<Niche> {
1238         self.0.0.largest_niche
1239     }
1240
1241     pub fn align(self) -> AbiAndPrefAlign {
1242         self.0.0.align
1243     }
1244
1245     pub fn size(self) -> Size {
1246         self.0.0.size
1247     }
1248 }
1249
1250 /// The layout of a type, alongside the type itself.
1251 /// Provides various type traversal APIs (e.g., recursing into fields).
1252 ///
1253 /// Note that the layout is NOT guaranteed to always be identical
1254 /// to that obtained from `layout_of(ty)`, as we need to produce
1255 /// layouts for which Rust types do not exist, such as enum variants
1256 /// or synthetic fields of enums (i.e., discriminants) and fat pointers.
1257 #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, HashStable_Generic)]
1258 pub struct TyAndLayout<'a, Ty> {
1259     pub ty: Ty,
1260     pub layout: Layout<'a>,
1261 }
1262
1263 impl<'a, Ty> Deref for TyAndLayout<'a, Ty> {
1264     type Target = &'a LayoutS<'a>;
1265     fn deref(&self) -> &&'a LayoutS<'a> {
1266         &self.layout.0.0
1267     }
1268 }
1269
1270 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
1271 pub enum PointerKind {
1272     /// Most general case, we know no restrictions to tell LLVM.
1273     Shared,
1274
1275     /// `&T` where `T` contains no `UnsafeCell`, is `noalias` and `readonly`.
1276     Frozen,
1277
1278     /// `&mut T` which is `noalias` but not `readonly`.
1279     UniqueBorrowed,
1280
1281     /// `Box<T>`, unlike `UniqueBorrowed`, it also has `noalias` on returns.
1282     UniqueOwned,
1283 }
1284
1285 #[derive(Copy, Clone, Debug)]
1286 pub struct PointeeInfo {
1287     pub size: Size,
1288     pub align: Align,
1289     pub safe: Option<PointerKind>,
1290     pub address_space: AddressSpace,
1291 }
1292
1293 /// Trait that needs to be implemented by the higher-level type representation
1294 /// (e.g. `rustc_middle::ty::Ty`), to provide `rustc_target::abi` functionality.
1295 pub trait TyAbiInterface<'a, C>: Sized {
1296     fn ty_and_layout_for_variant(
1297         this: TyAndLayout<'a, Self>,
1298         cx: &C,
1299         variant_index: VariantIdx,
1300     ) -> TyAndLayout<'a, Self>;
1301     fn ty_and_layout_field(this: TyAndLayout<'a, Self>, cx: &C, i: usize) -> TyAndLayout<'a, Self>;
1302     fn ty_and_layout_pointee_info_at(
1303         this: TyAndLayout<'a, Self>,
1304         cx: &C,
1305         offset: Size,
1306     ) -> Option<PointeeInfo>;
1307 }
1308
1309 impl<'a, Ty> TyAndLayout<'a, Ty> {
1310     pub fn for_variant<C>(self, cx: &C, variant_index: VariantIdx) -> Self
1311     where
1312         Ty: TyAbiInterface<'a, C>,
1313     {
1314         Ty::ty_and_layout_for_variant(self, cx, variant_index)
1315     }
1316
1317     pub fn field<C>(self, cx: &C, i: usize) -> Self
1318     where
1319         Ty: TyAbiInterface<'a, C>,
1320     {
1321         Ty::ty_and_layout_field(self, cx, i)
1322     }
1323
1324     pub fn pointee_info_at<C>(self, cx: &C, offset: Size) -> Option<PointeeInfo>
1325     where
1326         Ty: TyAbiInterface<'a, C>,
1327     {
1328         Ty::ty_and_layout_pointee_info_at(self, cx, offset)
1329     }
1330
1331     pub fn is_single_fp_element<C>(self, cx: &C) -> bool
1332     where
1333         Ty: TyAbiInterface<'a, C>,
1334         C: HasDataLayout,
1335     {
1336         match self.abi {
1337             Abi::Scalar(scalar) => scalar.value.is_float(),
1338             Abi::Aggregate { .. } => {
1339                 if self.fields.count() == 1 && self.fields.offset(0).bytes() == 0 {
1340                     self.field(cx, 0).is_single_fp_element(cx)
1341                 } else {
1342                     false
1343                 }
1344             }
1345             _ => false,
1346         }
1347     }
1348 }
1349
1350 impl<'a, Ty> TyAndLayout<'a, Ty> {
1351     /// Returns `true` if the layout corresponds to an unsized type.
1352     pub fn is_unsized(&self) -> bool {
1353         self.abi.is_unsized()
1354     }
1355
1356     /// Returns `true` if the type is a ZST and not unsized.
1357     pub fn is_zst(&self) -> bool {
1358         match self.abi {
1359             Abi::Scalar(_) | Abi::ScalarPair(..) | Abi::Vector { .. } => false,
1360             Abi::Uninhabited => self.size.bytes() == 0,
1361             Abi::Aggregate { sized } => sized && self.size.bytes() == 0,
1362         }
1363     }
1364
1365     /// Determines if this type permits "raw" initialization by just transmuting some
1366     /// memory into an instance of `T`.
1367     /// `zero` indicates if the memory is zero-initialized, or alternatively
1368     /// left entirely uninitialized.
1369     /// This is conservative: in doubt, it will answer `true`.
1370     ///
1371     /// FIXME: Once we removed all the conservatism, we could alternatively
1372     /// create an all-0/all-undef constant and run the const value validator to see if
1373     /// this is a valid value for the given type.
1374     pub fn might_permit_raw_init<C>(self, cx: &C, zero: bool) -> bool
1375     where
1376         Self: Copy,
1377         Ty: TyAbiInterface<'a, C>,
1378         C: HasDataLayout,
1379     {
1380         let scalar_allows_raw_init = move |s: Scalar| -> bool {
1381             if zero {
1382                 // The range must contain 0.
1383                 s.valid_range.contains(0)
1384             } else {
1385                 // The range must include all values.
1386                 s.is_always_valid(cx)
1387             }
1388         };
1389
1390         // Check the ABI.
1391         let valid = match self.abi {
1392             Abi::Uninhabited => false, // definitely UB
1393             Abi::Scalar(s) => scalar_allows_raw_init(s),
1394             Abi::ScalarPair(s1, s2) => scalar_allows_raw_init(s1) && scalar_allows_raw_init(s2),
1395             Abi::Vector { element: s, count } => count == 0 || scalar_allows_raw_init(s),
1396             Abi::Aggregate { .. } => true, // Fields are checked below.
1397         };
1398         if !valid {
1399             // This is definitely not okay.
1400             return false;
1401         }
1402
1403         // If we have not found an error yet, we need to recursively descend into fields.
1404         match &self.fields {
1405             FieldsShape::Primitive | FieldsShape::Union { .. } => {}
1406             FieldsShape::Array { .. } => {
1407                 // FIXME(#66151): For now, we are conservative and do not check arrays.
1408             }
1409             FieldsShape::Arbitrary { offsets, .. } => {
1410                 for idx in 0..offsets.len() {
1411                     if !self.field(cx, idx).might_permit_raw_init(cx, zero) {
1412                         // We found a field that is unhappy with this kind of initialization.
1413                         return false;
1414                     }
1415                 }
1416             }
1417         }
1418
1419         // FIXME(#66151): For now, we are conservative and do not check `self.variants`.
1420         true
1421     }
1422 }