]>
Commit | Line | Data |
---|---|---|
1a4d82fc JJ |
1 | // Copyright 2012-2013 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 | ||
83c7162d | 11 | use abi::{FnType, FnTypeExt}; |
54a0048b | 12 | use common::*; |
ff7c6d11 | 13 | use rustc::hir; |
54a0048b | 14 | use rustc::ty::{self, Ty, TypeFoldable}; |
ff7c6d11 | 15 | use rustc::ty::layout::{self, Align, LayoutOf, Size, TyLayout}; |
94b46f34 | 16 | use rustc_target::abi::FloatTy; |
8faf50e0 | 17 | use rustc_mir::monomorphize::item::DefPathBasedNames; |
54a0048b SL |
18 | use type_::Type; |
19 | ||
ff7c6d11 | 20 | use std::fmt::Write; |
1a4d82fc | 21 | |
2c00a5a8 | 22 | fn uncached_llvm_type<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, |
ff7c6d11 | 23 | layout: TyLayout<'tcx>, |
b7449926 XL |
24 | defer: &mut Option<(&'a Type, TyLayout<'tcx>)>) |
25 | -> &'a Type { | |
ff7c6d11 XL |
26 | match layout.abi { |
27 | layout::Abi::Scalar(_) => bug!("handled elsewhere"), | |
28 | layout::Abi::Vector { ref element, count } => { | |
29 | // LLVM has a separate type for 64-bit SIMD vectors on X86 called | |
30 | // `x86_mmx` which is needed for some SIMD operations. As a bit of a | |
31 | // hack (all SIMD definitions are super unstable anyway) we | |
32 | // recognize any one-element SIMD vector as "this should be an | |
33 | // x86_mmx" type. In general there shouldn't be a need for other | |
34 | // one-element SIMD vectors, so it's assumed this won't clash with | |
35 | // much else. | |
36 | let use_x86_mmx = count == 1 && layout.size.bits() == 64 && | |
2c00a5a8 XL |
37 | (cx.sess().target.target.arch == "x86" || |
38 | cx.sess().target.target.arch == "x86_64"); | |
ff7c6d11 | 39 | if use_x86_mmx { |
2c00a5a8 | 40 | return Type::x86_mmx(cx) |
ff7c6d11 | 41 | } else { |
94b46f34 | 42 | let element = layout.scalar_llvm_type_at(cx, element, Size::ZERO); |
b7449926 | 43 | return Type::vector(element, count); |
ff7c6d11 | 44 | } |
a7813a04 | 45 | } |
ff7c6d11 | 46 | layout::Abi::ScalarPair(..) => { |
2c00a5a8 | 47 | return Type::struct_(cx, &[ |
8faf50e0 XL |
48 | layout.scalar_pair_element_llvm_type(cx, 0, false), |
49 | layout.scalar_pair_element_llvm_type(cx, 1, false), | |
ff7c6d11 | 50 | ], false); |
32a655c1 | 51 | } |
ff7c6d11 XL |
52 | layout::Abi::Uninhabited | |
53 | layout::Abi::Aggregate { .. } => {} | |
a7813a04 | 54 | } |
a7813a04 | 55 | |
ff7c6d11 | 56 | let name = match layout.ty.sty { |
b7449926 XL |
57 | ty::Closure(..) | |
58 | ty::Generator(..) | | |
59 | ty::Adt(..) | | |
ff7c6d11 XL |
60 | // FIXME(eddyb) producing readable type names for trait objects can result |
61 | // in problematically distinct types due to HRTB and subtyping (see #47638). | |
b7449926 XL |
62 | // ty::Dynamic(..) | |
63 | ty::Foreign(..) | | |
64 | ty::Str => { | |
ff7c6d11 | 65 | let mut name = String::with_capacity(32); |
2c00a5a8 | 66 | let printer = DefPathBasedNames::new(cx.tcx, true, true); |
ff7c6d11 XL |
67 | printer.push_type_name(layout.ty, &mut name); |
68 | match (&layout.ty.sty, &layout.variants) { | |
b7449926 | 69 | (&ty::Adt(def, _), &layout::Variants::Single { index }) => { |
ff7c6d11 XL |
70 | if def.is_enum() && !def.variants.is_empty() { |
71 | write!(&mut name, "::{}", def.variants[index].name).unwrap(); | |
72 | } | |
73 | } | |
74 | _ => {} | |
75 | } | |
76 | Some(name) | |
77 | } | |
78 | _ => None | |
79 | }; | |
80 | ||
81 | match layout.fields { | |
82 | layout::FieldPlacement::Union(_) => { | |
2c00a5a8 | 83 | let fill = Type::padding_filler(cx, layout.size, layout.align); |
ff7c6d11 XL |
84 | let packed = false; |
85 | match name { | |
86 | None => { | |
2c00a5a8 | 87 | Type::struct_(cx, &[fill], packed) |
ff7c6d11 XL |
88 | } |
89 | Some(ref name) => { | |
b7449926 | 90 | let llty = Type::named_struct(cx, name); |
ff7c6d11 XL |
91 | llty.set_struct_body(&[fill], packed); |
92 | llty | |
93 | } | |
94 | } | |
95 | } | |
96 | layout::FieldPlacement::Array { count, .. } => { | |
b7449926 | 97 | Type::array(layout.field(cx, 0).llvm_type(cx), count) |
ff7c6d11 XL |
98 | } |
99 | layout::FieldPlacement::Arbitrary { .. } => { | |
100 | match name { | |
101 | None => { | |
2c00a5a8 XL |
102 | let (llfields, packed) = struct_llfields(cx, layout); |
103 | Type::struct_(cx, &llfields, packed) | |
ff7c6d11 XL |
104 | } |
105 | Some(ref name) => { | |
2c00a5a8 | 106 | let llty = Type::named_struct(cx, name); |
ff7c6d11 XL |
107 | *defer = Some((llty, layout)); |
108 | llty | |
109 | } | |
110 | } | |
54a0048b | 111 | } |
85aaf69f SL |
112 | } |
113 | } | |
114 | ||
2c00a5a8 | 115 | fn struct_llfields<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, |
ff7c6d11 | 116 | layout: TyLayout<'tcx>) |
b7449926 | 117 | -> (Vec<&'a Type>, bool) { |
ff7c6d11 XL |
118 | debug!("struct_llfields: {:#?}", layout); |
119 | let field_count = layout.fields.count(); | |
120 | ||
121 | let mut packed = false; | |
94b46f34 | 122 | let mut offset = Size::ZERO; |
b7449926 XL |
123 | let mut prev_effective_align = layout.align; |
124 | let mut result: Vec<_> = Vec::with_capacity(1 + field_count * 2); | |
ff7c6d11 | 125 | for i in layout.fields.index_by_increasing_offset() { |
ff7c6d11 | 126 | let target_offset = layout.fields.offset(i as usize); |
b7449926 XL |
127 | let field = layout.field(cx, i); |
128 | let effective_field_align = layout.align | |
129 | .min(field.align) | |
130 | .restrict_for_offset(target_offset); | |
131 | packed |= effective_field_align.abi() < field.align.abi(); | |
132 | ||
133 | debug!("struct_llfields: {}: {:?} offset: {:?} target_offset: {:?} \ | |
134 | effective_field_align: {}", | |
135 | i, field, offset, target_offset, effective_field_align.abi()); | |
ff7c6d11 XL |
136 | assert!(target_offset >= offset); |
137 | let padding = target_offset - offset; | |
b7449926 | 138 | let padding_align = prev_effective_align.min(effective_field_align); |
ff7c6d11 | 139 | assert_eq!(offset.abi_align(padding_align) + padding, target_offset); |
2c00a5a8 | 140 | result.push(Type::padding_filler(cx, padding, padding_align)); |
ff7c6d11 XL |
141 | debug!(" padding before: {:?}", padding); |
142 | ||
2c00a5a8 | 143 | result.push(field.llvm_type(cx)); |
ff7c6d11 | 144 | offset = target_offset + field.size; |
b7449926 | 145 | prev_effective_align = effective_field_align; |
ff7c6d11 XL |
146 | } |
147 | if !layout.is_unsized() && field_count > 0 { | |
148 | if offset > layout.size { | |
149 | bug!("layout: {:#?} stride: {:?} offset: {:?}", | |
150 | layout, layout.size, offset); | |
151 | } | |
152 | let padding = layout.size - offset; | |
b7449926 | 153 | let padding_align = prev_effective_align; |
ff7c6d11 XL |
154 | assert_eq!(offset.abi_align(padding_align) + padding, layout.size); |
155 | debug!("struct_llfields: pad_bytes: {:?} offset: {:?} stride: {:?}", | |
156 | padding, offset, layout.size); | |
2c00a5a8 | 157 | result.push(Type::padding_filler(cx, padding, padding_align)); |
ff7c6d11 | 158 | assert!(result.len() == 1 + field_count * 2); |
1a4d82fc | 159 | } else { |
ff7c6d11 XL |
160 | debug!("struct_llfields: offset: {:?} stride: {:?}", |
161 | offset, layout.size); | |
1a4d82fc | 162 | } |
1a4d82fc | 163 | |
ff7c6d11 | 164 | (result, packed) |
c34b1796 | 165 | } |
1a4d82fc | 166 | |
2c00a5a8 | 167 | impl<'a, 'tcx> CodegenCx<'a, 'tcx> { |
ff7c6d11 XL |
168 | pub fn align_of(&self, ty: Ty<'tcx>) -> Align { |
169 | self.layout_of(ty).align | |
1a4d82fc JJ |
170 | } |
171 | ||
ff7c6d11 XL |
172 | pub fn size_of(&self, ty: Ty<'tcx>) -> Size { |
173 | self.layout_of(ty).size | |
174 | } | |
1a4d82fc | 175 | |
ff7c6d11 XL |
176 | pub fn size_and_align_of(&self, ty: Ty<'tcx>) -> (Size, Align) { |
177 | self.layout_of(ty).size_and_align() | |
178 | } | |
179 | } | |
180 | ||
181 | #[derive(Copy, Clone, PartialEq, Eq)] | |
182 | pub enum PointerKind { | |
183 | /// Most general case, we know no restrictions to tell LLVM. | |
184 | Shared, | |
185 | ||
186 | /// `&T` where `T` contains no `UnsafeCell`, is `noalias` and `readonly`. | |
187 | Frozen, | |
1a4d82fc | 188 | |
ff7c6d11 XL |
189 | /// `&mut T`, when we know `noalias` is safe for LLVM. |
190 | UniqueBorrowed, | |
1a4d82fc | 191 | |
ff7c6d11 XL |
192 | /// `Box<T>`, unlike `UniqueBorrowed`, it also has `noalias` on returns. |
193 | UniqueOwned | |
194 | } | |
195 | ||
196 | #[derive(Copy, Clone)] | |
197 | pub struct PointeeInfo { | |
198 | pub size: Size, | |
199 | pub align: Align, | |
200 | pub safe: Option<PointerKind>, | |
201 | } | |
202 | ||
203 | pub trait LayoutLlvmExt<'tcx> { | |
204 | fn is_llvm_immediate(&self) -> bool; | |
205 | fn is_llvm_scalar_pair<'a>(&self) -> bool; | |
b7449926 XL |
206 | fn llvm_type<'a>(&self, cx: &CodegenCx<'a, 'tcx>) -> &'a Type; |
207 | fn immediate_llvm_type<'a>(&self, cx: &CodegenCx<'a, 'tcx>) -> &'a Type; | |
2c00a5a8 | 208 | fn scalar_llvm_type_at<'a>(&self, cx: &CodegenCx<'a, 'tcx>, |
b7449926 | 209 | scalar: &layout::Scalar, offset: Size) -> &'a Type; |
2c00a5a8 | 210 | fn scalar_pair_element_llvm_type<'a>(&self, cx: &CodegenCx<'a, 'tcx>, |
b7449926 | 211 | index: usize, immediate: bool) -> &'a Type; |
ff7c6d11 | 212 | fn llvm_field_index(&self, index: usize) -> u64; |
2c00a5a8 | 213 | fn pointee_info_at<'a>(&self, cx: &CodegenCx<'a, 'tcx>, offset: Size) |
ff7c6d11 XL |
214 | -> Option<PointeeInfo>; |
215 | } | |
216 | ||
217 | impl<'tcx> LayoutLlvmExt<'tcx> for TyLayout<'tcx> { | |
218 | fn is_llvm_immediate(&self) -> bool { | |
219 | match self.abi { | |
ff7c6d11 XL |
220 | layout::Abi::Scalar(_) | |
221 | layout::Abi::Vector { .. } => true, | |
222 | layout::Abi::ScalarPair(..) => false, | |
83c7162d | 223 | layout::Abi::Uninhabited | |
ff7c6d11 XL |
224 | layout::Abi::Aggregate { .. } => self.is_zst() |
225 | } | |
1a4d82fc JJ |
226 | } |
227 | ||
ff7c6d11 XL |
228 | fn is_llvm_scalar_pair<'a>(&self) -> bool { |
229 | match self.abi { | |
230 | layout::Abi::ScalarPair(..) => true, | |
231 | layout::Abi::Uninhabited | | |
232 | layout::Abi::Scalar(_) | | |
233 | layout::Abi::Vector { .. } | | |
234 | layout::Abi::Aggregate { .. } => false | |
235 | } | |
236 | } | |
237 | ||
238 | /// Get the LLVM type corresponding to a Rust type, i.e. `rustc::ty::Ty`. | |
239 | /// The pointee type of the pointer in `PlaceRef` is always this type. | |
240 | /// For sized types, it is also the right LLVM type for an `alloca` | |
241 | /// containing a value of that type, and most immediates (except `bool`). | |
242 | /// Unsized types, however, are represented by a "minimal unit", e.g. | |
243 | /// `[T]` becomes `T`, while `str` and `Trait` turn into `i8` - this | |
244 | /// is useful for indexing slices, as `&[T]`'s data pointer is `T*`. | |
245 | /// If the type is an unsized struct, the regular layout is generated, | |
246 | /// with the inner-most trailing unsized field using the "minimal unit" | |
247 | /// of that field's type - this is useful for taking the address of | |
248 | /// that field and ensuring the struct has the right alignment. | |
b7449926 | 249 | fn llvm_type<'a>(&self, cx: &CodegenCx<'a, 'tcx>) -> &'a Type { |
ff7c6d11 XL |
250 | if let layout::Abi::Scalar(ref scalar) = self.abi { |
251 | // Use a different cache for scalars because pointers to DSTs | |
252 | // can be either fat or thin (data pointers of fat pointers). | |
2c00a5a8 | 253 | if let Some(&llty) = cx.scalar_lltypes.borrow().get(&self.ty) { |
ff7c6d11 | 254 | return llty; |
32a655c1 | 255 | } |
ff7c6d11 | 256 | let llty = match self.ty.sty { |
b7449926 XL |
257 | ty::Ref(_, ty, _) | |
258 | ty::RawPtr(ty::TypeAndMut { ty, .. }) => { | |
2c00a5a8 | 259 | cx.layout_of(ty).llvm_type(cx).ptr_to() |
ff7c6d11 | 260 | } |
b7449926 | 261 | ty::Adt(def, _) if def.is_box() => { |
2c00a5a8 | 262 | cx.layout_of(self.ty.boxed_ty()).llvm_type(cx).ptr_to() |
ff7c6d11 | 263 | } |
b7449926 | 264 | ty::FnPtr(sig) => { |
0531ce1d XL |
265 | let sig = cx.tcx.normalize_erasing_late_bound_regions( |
266 | ty::ParamEnv::reveal_all(), | |
267 | &sig, | |
268 | ); | |
2c00a5a8 | 269 | FnType::new(cx, sig, &[]).llvm_type(cx).ptr_to() |
ff7c6d11 | 270 | } |
94b46f34 | 271 | _ => self.scalar_llvm_type_at(cx, scalar, Size::ZERO) |
ff7c6d11 | 272 | }; |
2c00a5a8 | 273 | cx.scalar_lltypes.borrow_mut().insert(self.ty, llty); |
ff7c6d11 | 274 | return llty; |
32a655c1 | 275 | } |
32a655c1 | 276 | |
1a4d82fc | 277 | |
ff7c6d11 XL |
278 | // Check the cache. |
279 | let variant_index = match self.variants { | |
280 | layout::Variants::Single { index } => Some(index), | |
281 | _ => None | |
282 | }; | |
2c00a5a8 | 283 | if let Some(&llty) = cx.lltypes.borrow().get(&(self.ty, variant_index)) { |
ff7c6d11 XL |
284 | return llty; |
285 | } | |
286 | ||
287 | debug!("llvm_type({:#?})", self); | |
288 | ||
289 | assert!(!self.ty.has_escaping_regions(), "{:?} has escaping regions", self.ty); | |
290 | ||
291 | // Make sure lifetimes are erased, to avoid generating distinct LLVM | |
292 | // types for Rust types that only differ in the choice of lifetimes. | |
2c00a5a8 | 293 | let normal_ty = cx.tcx.erase_regions(&self.ty); |
1a4d82fc | 294 | |
ff7c6d11 XL |
295 | let mut defer = None; |
296 | let llty = if self.ty != normal_ty { | |
2c00a5a8 | 297 | let mut layout = cx.layout_of(normal_ty); |
ff7c6d11 | 298 | if let Some(v) = variant_index { |
2c00a5a8 | 299 | layout = layout.for_variant(cx, v); |
ff7c6d11 | 300 | } |
2c00a5a8 | 301 | layout.llvm_type(cx) |
ff7c6d11 | 302 | } else { |
2c00a5a8 | 303 | uncached_llvm_type(cx, *self, &mut defer) |
ff7c6d11 XL |
304 | }; |
305 | debug!("--> mapped {:#?} to llty={:?}", self, llty); | |
306 | ||
2c00a5a8 | 307 | cx.lltypes.borrow_mut().insert((self.ty, variant_index), llty); |
1a4d82fc | 308 | |
b7449926 | 309 | if let Some((llty, layout)) = defer { |
2c00a5a8 | 310 | let (llfields, packed) = struct_llfields(cx, layout); |
ff7c6d11 | 311 | llty.set_struct_body(&llfields, packed) |
1a4d82fc | 312 | } |
1a4d82fc | 313 | |
ff7c6d11 XL |
314 | llty |
315 | } | |
1a4d82fc | 316 | |
b7449926 | 317 | fn immediate_llvm_type<'a>(&self, cx: &CodegenCx<'a, 'tcx>) -> &'a Type { |
ff7c6d11 XL |
318 | if let layout::Abi::Scalar(ref scalar) = self.abi { |
319 | if scalar.is_bool() { | |
2c00a5a8 | 320 | return Type::i1(cx); |
ff7c6d11 XL |
321 | } |
322 | } | |
2c00a5a8 | 323 | self.llvm_type(cx) |
cc61c64b XL |
324 | } |
325 | ||
2c00a5a8 | 326 | fn scalar_llvm_type_at<'a>(&self, cx: &CodegenCx<'a, 'tcx>, |
b7449926 | 327 | scalar: &layout::Scalar, offset: Size) -> &'a Type { |
ff7c6d11 | 328 | match scalar.value { |
2c00a5a8 | 329 | layout::Int(i, _) => Type::from_integer(cx, i), |
94b46f34 XL |
330 | layout::Float(FloatTy::F32) => Type::f32(cx), |
331 | layout::Float(FloatTy::F64) => Type::f64(cx), | |
ff7c6d11 XL |
332 | layout::Pointer => { |
333 | // If we know the alignment, pick something better than i8. | |
2c00a5a8 XL |
334 | let pointee = if let Some(pointee) = self.pointee_info_at(cx, offset) { |
335 | Type::pointee_for_abi_align(cx, pointee.align) | |
ff7c6d11 | 336 | } else { |
2c00a5a8 | 337 | Type::i8(cx) |
ff7c6d11 XL |
338 | }; |
339 | pointee.ptr_to() | |
340 | } | |
341 | } | |
cc61c64b XL |
342 | } |
343 | ||
2c00a5a8 | 344 | fn scalar_pair_element_llvm_type<'a>(&self, cx: &CodegenCx<'a, 'tcx>, |
b7449926 | 345 | index: usize, immediate: bool) -> &'a Type { |
ff7c6d11 XL |
346 | // HACK(eddyb) special-case fat pointers until LLVM removes |
347 | // pointee types, to avoid bitcasting every `OperandRef::deref`. | |
348 | match self.ty.sty { | |
b7449926 XL |
349 | ty::Ref(..) | |
350 | ty::RawPtr(_) => { | |
2c00a5a8 | 351 | return self.field(cx, index).llvm_type(cx); |
ff7c6d11 | 352 | } |
b7449926 | 353 | ty::Adt(def, _) if def.is_box() => { |
2c00a5a8 | 354 | let ptr_ty = cx.tcx.mk_mut_ptr(self.ty.boxed_ty()); |
8faf50e0 | 355 | return cx.layout_of(ptr_ty).scalar_pair_element_llvm_type(cx, index, immediate); |
ff7c6d11 XL |
356 | } |
357 | _ => {} | |
358 | } | |
359 | ||
360 | let (a, b) = match self.abi { | |
361 | layout::Abi::ScalarPair(ref a, ref b) => (a, b), | |
362 | _ => bug!("TyLayout::scalar_pair_element_llty({:?}): not applicable", self) | |
363 | }; | |
364 | let scalar = [a, b][index]; | |
365 | ||
8faf50e0 XL |
366 | // Make sure to return the same type `immediate_llvm_type` would when |
367 | // dealing with an immediate pair. This means that `(bool, bool)` is | |
368 | // effectively represented as `{i8, i8}` in memory and two `i1`s as an | |
369 | // immediate, just like `bool` is typically `i8` in memory and only `i1` | |
370 | // when immediate. We need to load/store `bool` as `i8` to avoid | |
371 | // crippling LLVM optimizations or triggering other LLVM bugs with `i1`. | |
372 | if immediate && scalar.is_bool() { | |
2c00a5a8 | 373 | return Type::i1(cx); |
ff7c6d11 XL |
374 | } |
375 | ||
376 | let offset = if index == 0 { | |
94b46f34 | 377 | Size::ZERO |
cc61c64b | 378 | } else { |
2c00a5a8 | 379 | a.value.size(cx).abi_align(b.value.align(cx)) |
ff7c6d11 | 380 | }; |
2c00a5a8 | 381 | self.scalar_llvm_type_at(cx, scalar, offset) |
ff7c6d11 XL |
382 | } |
383 | ||
384 | fn llvm_field_index(&self, index: usize) -> u64 { | |
385 | match self.abi { | |
386 | layout::Abi::Scalar(_) | | |
387 | layout::Abi::ScalarPair(..) => { | |
388 | bug!("TyLayout::llvm_field_index({:?}): not applicable", self) | |
389 | } | |
390 | _ => {} | |
391 | } | |
392 | match self.fields { | |
393 | layout::FieldPlacement::Union(_) => { | |
394 | bug!("TyLayout::llvm_field_index({:?}): not applicable", self) | |
395 | } | |
396 | ||
397 | layout::FieldPlacement::Array { .. } => { | |
398 | index as u64 | |
399 | } | |
400 | ||
401 | layout::FieldPlacement::Arbitrary { .. } => { | |
402 | 1 + (self.fields.memory_index(index) as u64) * 2 | |
403 | } | |
cc61c64b XL |
404 | } |
405 | } | |
1a4d82fc | 406 | |
2c00a5a8 | 407 | fn pointee_info_at<'a>(&self, cx: &CodegenCx<'a, 'tcx>, offset: Size) |
ff7c6d11 | 408 | -> Option<PointeeInfo> { |
2c00a5a8 | 409 | if let Some(&pointee) = cx.pointee_infos.borrow().get(&(self.ty, offset)) { |
ff7c6d11 XL |
410 | return pointee; |
411 | } | |
412 | ||
413 | let mut result = None; | |
414 | match self.ty.sty { | |
b7449926 | 415 | ty::RawPtr(mt) if offset.bytes() == 0 => { |
2c00a5a8 | 416 | let (size, align) = cx.size_and_align_of(mt.ty); |
ff7c6d11 XL |
417 | result = Some(PointeeInfo { |
418 | size, | |
419 | align, | |
420 | safe: None | |
421 | }); | |
422 | } | |
423 | ||
b7449926 | 424 | ty::Ref(_, ty, mt) if offset.bytes() == 0 => { |
94b46f34 | 425 | let (size, align) = cx.size_and_align_of(ty); |
ff7c6d11 | 426 | |
94b46f34 XL |
427 | let kind = match mt { |
428 | hir::MutImmutable => if cx.type_is_freeze(ty) { | |
ff7c6d11 XL |
429 | PointerKind::Frozen |
430 | } else { | |
431 | PointerKind::Shared | |
432 | }, | |
433 | hir::MutMutable => { | |
4462d4a0 XL |
434 | // Previously we would only emit noalias annotations for LLVM >= 6 or in |
435 | // panic=abort mode. That was deemed right, as prior versions had many bugs | |
436 | // in conjunction with unwinding, but later versions didn’t seem to have | |
437 | // said issues. See issue #31681. | |
438 | // | |
439 | // Alas, later on we encountered a case where noalias would generate wrong | |
440 | // code altogether even with recent versions of LLVM in *safe* code with no | |
441 | // unwinding involved. See #54462. | |
442 | // | |
443 | // For now, do not enable mutable_noalias by default at all, while the | |
444 | // issue is being figured out. | |
94b46f34 | 445 | let mutable_noalias = cx.tcx.sess.opts.debugging_opts.mutable_noalias |
4462d4a0 | 446 | .unwrap_or(false); |
94b46f34 | 447 | if mutable_noalias { |
ff7c6d11 XL |
448 | PointerKind::UniqueBorrowed |
449 | } else { | |
450 | PointerKind::Shared | |
451 | } | |
452 | } | |
453 | }; | |
454 | ||
455 | result = Some(PointeeInfo { | |
456 | size, | |
457 | align, | |
458 | safe: Some(kind) | |
459 | }); | |
460 | } | |
461 | ||
462 | _ => { | |
463 | let mut data_variant = match self.variants { | |
464 | layout::Variants::NicheFilling { dataful_variant, .. } => { | |
465 | // Only the niche itself is always initialized, | |
466 | // so only check for a pointer at its offset. | |
467 | // | |
468 | // If the niche is a pointer, it's either valid | |
469 | // (according to its type), or null (which the | |
470 | // niche field's scalar validity range encodes). | |
471 | // This allows using `dereferenceable_or_null` | |
472 | // for e.g. `Option<&T>`, and this will continue | |
473 | // to work as long as we don't start using more | |
474 | // niches than just null (e.g. the first page | |
475 | // of the address space, or unaligned pointers). | |
476 | if self.fields.offset(0) == offset { | |
2c00a5a8 | 477 | Some(self.for_variant(cx, dataful_variant)) |
ff7c6d11 XL |
478 | } else { |
479 | None | |
480 | } | |
481 | } | |
482 | _ => Some(*self) | |
483 | }; | |
484 | ||
485 | if let Some(variant) = data_variant { | |
486 | // We're not interested in any unions. | |
487 | if let layout::FieldPlacement::Union(_) = variant.fields { | |
488 | data_variant = None; | |
489 | } | |
490 | } | |
491 | ||
492 | if let Some(variant) = data_variant { | |
2c00a5a8 | 493 | let ptr_end = offset + layout::Pointer.size(cx); |
ff7c6d11 XL |
494 | for i in 0..variant.fields.count() { |
495 | let field_start = variant.fields.offset(i); | |
496 | if field_start <= offset { | |
2c00a5a8 | 497 | let field = variant.field(cx, i); |
ff7c6d11 XL |
498 | if ptr_end <= field_start + field.size { |
499 | // We found the right field, look inside it. | |
2c00a5a8 | 500 | result = field.pointee_info_at(cx, offset - field_start); |
ff7c6d11 XL |
501 | break; |
502 | } | |
503 | } | |
504 | } | |
505 | } | |
506 | ||
507 | // FIXME(eddyb) This should be for `ptr::Unique<T>`, not `Box<T>`. | |
508 | if let Some(ref mut pointee) = result { | |
b7449926 | 509 | if let ty::Adt(def, _) = self.ty.sty { |
ff7c6d11 XL |
510 | if def.is_box() && offset.bytes() == 0 { |
511 | pointee.safe = Some(PointerKind::UniqueOwned); | |
512 | } | |
513 | } | |
514 | } | |
515 | } | |
516 | } | |
517 | ||
2c00a5a8 | 518 | cx.pointee_infos.borrow_mut().insert((self.ty, offset), result); |
ff7c6d11 XL |
519 | result |
520 | } | |
1a4d82fc | 521 | } |