]>
Commit | Line | Data |
---|---|---|
9fa01778 | 1 | use crate::common::*; |
94222f64 | 2 | use crate::context::TypeLowering; |
5e7ed085 | 3 | use crate::llvm_util::get_version; |
9fa01778 | 4 | use crate::type_::Type; |
dfeec247 | 5 | use rustc_codegen_ssa::traits::*; |
ba9703b0 | 6 | use rustc_middle::bug; |
c295e0f8 XL |
7 | use rustc_middle::ty::layout::{FnAbiOf, LayoutOf, TyAndLayout}; |
8 | use rustc_middle::ty::print::{with_no_trimmed_paths, with_no_visible_paths}; | |
064997fb | 9 | use rustc_middle::ty::{self, Ty, TypeVisitable}; |
3dfed10e | 10 | use rustc_target::abi::{Abi, AddressSpace, Align, FieldsShape}; |
ba9703b0 | 11 | use rustc_target::abi::{Int, Pointer, F32, F64}; |
c295e0f8 | 12 | use rustc_target::abi::{PointeeInfo, Scalar, Size, TyAbiInterface, Variants}; |
94222f64 | 13 | use smallvec::{smallvec, SmallVec}; |
54a0048b | 14 | |
ff7c6d11 | 15 | use std::fmt::Write; |
1a4d82fc | 16 | |
dfeec247 XL |
17 | fn uncached_llvm_type<'a, 'tcx>( |
18 | cx: &CodegenCx<'a, 'tcx>, | |
ba9703b0 XL |
19 | layout: TyAndLayout<'tcx>, |
20 | defer: &mut Option<(&'a Type, TyAndLayout<'tcx>)>, | |
94222f64 | 21 | field_remapping: &mut Option<SmallVec<[u32; 4]>>, |
dfeec247 | 22 | ) -> &'a Type { |
ff7c6d11 | 23 | match layout.abi { |
ba9703b0 | 24 | Abi::Scalar(_) => bug!("handled elsewhere"), |
c295e0f8 | 25 | Abi::Vector { element, count } => { |
1b1a35ee XL |
26 | let element = layout.scalar_llvm_type_at(cx, element, Size::ZERO); |
27 | return cx.type_vector(element, count); | |
a7813a04 | 28 | } |
ba9703b0 | 29 | Abi::ScalarPair(..) => { |
dfeec247 XL |
30 | return cx.type_struct( |
31 | &[ | |
32 | layout.scalar_pair_element_llvm_type(cx, 0, false), | |
33 | layout.scalar_pair_element_llvm_type(cx, 1, false), | |
34 | ], | |
35 | false, | |
36 | ); | |
32a655c1 | 37 | } |
ba9703b0 | 38 | Abi::Uninhabited | Abi::Aggregate { .. } => {} |
a7813a04 | 39 | } |
a7813a04 | 40 | |
1b1a35ee | 41 | let name = match layout.ty.kind() { |
ff7c6d11 XL |
42 | // FIXME(eddyb) producing readable type names for trait objects can result |
43 | // in problematically distinct types due to HRTB and subtyping (see #47638). | |
b7449926 | 44 | // ty::Dynamic(..) | |
5e7ed085 FG |
45 | ty::Adt(..) | ty::Closure(..) | ty::Foreign(..) | ty::Generator(..) | ty::Str |
46 | // For performance reasons we use names only when emitting LLVM IR. Unless we are on | |
47 | // LLVM < 14, where the use of unnamed types resulted in various issues, e.g., #76213, | |
48 | // #79564, and #79246. | |
49 | if get_version() < (14, 0, 0) || !cx.sess().fewer_names() => | |
50 | { | |
51 | let mut name = with_no_visible_paths!(with_no_trimmed_paths!(layout.ty.to_string())); | |
1b1a35ee XL |
52 | if let (&ty::Adt(def, _), &Variants::Single { index }) = |
53 | (layout.ty.kind(), &layout.variants) | |
0bf4aa26 | 54 | { |
5e7ed085 FG |
55 | if def.is_enum() && !def.variants().is_empty() { |
56 | write!(&mut name, "::{}", def.variant(index).name).unwrap(); | |
ff7c6d11 | 57 | } |
ff7c6d11 | 58 | } |
1b1a35ee XL |
59 | if let (&ty::Generator(_, _, _), &Variants::Single { index }) = |
60 | (layout.ty.kind(), &layout.variants) | |
48663c56 | 61 | { |
f035d41b | 62 | write!(&mut name, "::{}", ty::GeneratorSubsts::variant_name(index)).unwrap(); |
48663c56 | 63 | } |
ff7c6d11 XL |
64 | Some(name) |
65 | } | |
5e7ed085 FG |
66 | // Use identified structure types for ADT. Due to pointee types in LLVM IR their definition |
67 | // might be recursive. Other cases are non-recursive and we can use literal structure types. | |
68 | ty::Adt(..) => Some(String::new()), | |
1b1a35ee | 69 | _ => None, |
ff7c6d11 XL |
70 | }; |
71 | ||
72 | match layout.fields { | |
ba9703b0 | 73 | FieldsShape::Primitive | FieldsShape::Union(_) => { |
a1dfa0c6 | 74 | let fill = cx.type_padding_filler(layout.size, layout.align.abi); |
ff7c6d11 XL |
75 | let packed = false; |
76 | match name { | |
dfeec247 | 77 | None => cx.type_struct(&[fill], packed), |
ff7c6d11 | 78 | Some(ref name) => { |
0731742a | 79 | let llty = cx.type_named_struct(name); |
a1dfa0c6 | 80 | cx.set_struct_body(llty, &[fill], packed); |
ff7c6d11 XL |
81 | llty |
82 | } | |
83 | } | |
84 | } | |
ba9703b0 XL |
85 | FieldsShape::Array { count, .. } => cx.type_array(layout.field(cx, 0).llvm_type(cx), count), |
86 | FieldsShape::Arbitrary { .. } => match name { | |
dfeec247 | 87 | None => { |
94222f64 XL |
88 | let (llfields, packed, new_field_remapping) = struct_llfields(cx, layout); |
89 | *field_remapping = new_field_remapping; | |
dfeec247 | 90 | cx.type_struct(&llfields, packed) |
ff7c6d11 | 91 | } |
dfeec247 XL |
92 | Some(ref name) => { |
93 | let llty = cx.type_named_struct(name); | |
94 | *defer = Some((llty, layout)); | |
95 | llty | |
96 | } | |
97 | }, | |
85aaf69f SL |
98 | } |
99 | } | |
100 | ||
dfeec247 XL |
101 | fn struct_llfields<'a, 'tcx>( |
102 | cx: &CodegenCx<'a, 'tcx>, | |
ba9703b0 | 103 | layout: TyAndLayout<'tcx>, |
94222f64 | 104 | ) -> (Vec<&'a Type>, bool, Option<SmallVec<[u32; 4]>>) { |
ff7c6d11 XL |
105 | debug!("struct_llfields: {:#?}", layout); |
106 | let field_count = layout.fields.count(); | |
107 | ||
108 | let mut packed = false; | |
94b46f34 | 109 | let mut offset = Size::ZERO; |
a1dfa0c6 | 110 | let mut prev_effective_align = layout.align.abi; |
b7449926 | 111 | let mut result: Vec<_> = Vec::with_capacity(1 + field_count * 2); |
94222f64 | 112 | let mut field_remapping = smallvec![0; field_count]; |
ff7c6d11 | 113 | for i in layout.fields.index_by_increasing_offset() { |
ff7c6d11 | 114 | let target_offset = layout.fields.offset(i as usize); |
b7449926 | 115 | let field = layout.field(cx, i); |
dfeec247 XL |
116 | let effective_field_align = |
117 | layout.align.abi.min(field.align.abi).restrict_for_offset(target_offset); | |
a1dfa0c6 | 118 | packed |= effective_field_align < field.align.abi; |
b7449926 | 119 | |
dfeec247 XL |
120 | debug!( |
121 | "struct_llfields: {}: {:?} offset: {:?} target_offset: {:?} \ | |
b7449926 | 122 | effective_field_align: {}", |
dfeec247 XL |
123 | i, |
124 | field, | |
125 | offset, | |
126 | target_offset, | |
127 | effective_field_align.bytes() | |
128 | ); | |
ff7c6d11 XL |
129 | assert!(target_offset >= offset); |
130 | let padding = target_offset - offset; | |
94222f64 XL |
131 | if padding != Size::ZERO { |
132 | let padding_align = prev_effective_align.min(effective_field_align); | |
133 | assert_eq!(offset.align_to(padding_align) + padding, target_offset); | |
134 | result.push(cx.type_padding_filler(padding, padding_align)); | |
135 | debug!(" padding before: {:?}", padding); | |
136 | } | |
137 | field_remapping[i] = result.len() as u32; | |
2c00a5a8 | 138 | result.push(field.llvm_type(cx)); |
ff7c6d11 | 139 | offset = target_offset + field.size; |
b7449926 | 140 | prev_effective_align = effective_field_align; |
ff7c6d11 | 141 | } |
94222f64 | 142 | let padding_used = result.len() > field_count; |
ff7c6d11 XL |
143 | if !layout.is_unsized() && field_count > 0 { |
144 | if offset > layout.size { | |
dfeec247 | 145 | bug!("layout: {:#?} stride: {:?} offset: {:?}", layout, layout.size, offset); |
ff7c6d11 XL |
146 | } |
147 | let padding = layout.size - offset; | |
94222f64 XL |
148 | if padding != Size::ZERO { |
149 | let padding_align = prev_effective_align; | |
150 | assert_eq!(offset.align_to(padding_align) + padding, layout.size); | |
151 | debug!( | |
152 | "struct_llfields: pad_bytes: {:?} offset: {:?} stride: {:?}", | |
153 | padding, offset, layout.size | |
154 | ); | |
155 | result.push(cx.type_padding_filler(padding, padding_align)); | |
156 | } | |
1a4d82fc | 157 | } else { |
dfeec247 | 158 | debug!("struct_llfields: offset: {:?} stride: {:?}", offset, layout.size); |
1a4d82fc | 159 | } |
94222f64 XL |
160 | let field_remapping = if padding_used { Some(field_remapping) } else { None }; |
161 | (result, packed, field_remapping) | |
c34b1796 | 162 | } |
1a4d82fc | 163 | |
2c00a5a8 | 164 | impl<'a, 'tcx> CodegenCx<'a, 'tcx> { |
ff7c6d11 | 165 | pub fn align_of(&self, ty: Ty<'tcx>) -> Align { |
a1dfa0c6 | 166 | self.layout_of(ty).align.abi |
1a4d82fc JJ |
167 | } |
168 | ||
ff7c6d11 XL |
169 | pub fn size_of(&self, ty: Ty<'tcx>) -> Size { |
170 | self.layout_of(ty).size | |
171 | } | |
1a4d82fc | 172 | |
ff7c6d11 | 173 | pub fn size_and_align_of(&self, ty: Ty<'tcx>) -> (Size, Align) { |
a1dfa0c6 XL |
174 | let layout = self.layout_of(ty); |
175 | (layout.size, layout.align.abi) | |
ff7c6d11 XL |
176 | } |
177 | } | |
178 | ||
ff7c6d11 XL |
179 | pub trait LayoutLlvmExt<'tcx> { |
180 | fn is_llvm_immediate(&self) -> bool; | |
dc9dc135 | 181 | fn is_llvm_scalar_pair(&self) -> bool; |
b7449926 XL |
182 | fn llvm_type<'a>(&self, cx: &CodegenCx<'a, 'tcx>) -> &'a Type; |
183 | fn immediate_llvm_type<'a>(&self, cx: &CodegenCx<'a, 'tcx>) -> &'a Type; | |
dfeec247 XL |
184 | fn scalar_llvm_type_at<'a>( |
185 | &self, | |
186 | cx: &CodegenCx<'a, 'tcx>, | |
c295e0f8 | 187 | scalar: Scalar, |
dfeec247 XL |
188 | offset: Size, |
189 | ) -> &'a Type; | |
190 | fn scalar_pair_element_llvm_type<'a>( | |
191 | &self, | |
192 | cx: &CodegenCx<'a, 'tcx>, | |
193 | index: usize, | |
194 | immediate: bool, | |
195 | ) -> &'a Type; | |
94222f64 | 196 | fn llvm_field_index<'a>(&self, cx: &CodegenCx<'a, 'tcx>, index: usize) -> u64; |
dfeec247 | 197 | fn pointee_info_at<'a>(&self, cx: &CodegenCx<'a, 'tcx>, offset: Size) -> Option<PointeeInfo>; |
ff7c6d11 XL |
198 | } |
199 | ||
ba9703b0 | 200 | impl<'tcx> LayoutLlvmExt<'tcx> for TyAndLayout<'tcx> { |
ff7c6d11 XL |
201 | fn is_llvm_immediate(&self) -> bool { |
202 | match self.abi { | |
ba9703b0 XL |
203 | Abi::Scalar(_) | Abi::Vector { .. } => true, |
204 | Abi::ScalarPair(..) => false, | |
205 | Abi::Uninhabited | Abi::Aggregate { .. } => self.is_zst(), | |
ff7c6d11 | 206 | } |
1a4d82fc JJ |
207 | } |
208 | ||
dc9dc135 | 209 | fn is_llvm_scalar_pair(&self) -> bool { |
ff7c6d11 | 210 | match self.abi { |
ba9703b0 XL |
211 | Abi::ScalarPair(..) => true, |
212 | Abi::Uninhabited | Abi::Scalar(_) | Abi::Vector { .. } | Abi::Aggregate { .. } => false, | |
ff7c6d11 XL |
213 | } |
214 | } | |
215 | ||
ba9703b0 | 216 | /// Gets the LLVM type corresponding to a Rust type, i.e., `rustc_middle::ty::Ty`. |
ff7c6d11 XL |
217 | /// The pointee type of the pointer in `PlaceRef` is always this type. |
218 | /// For sized types, it is also the right LLVM type for an `alloca` | |
219 | /// containing a value of that type, and most immediates (except `bool`). | |
220 | /// Unsized types, however, are represented by a "minimal unit", e.g. | |
221 | /// `[T]` becomes `T`, while `str` and `Trait` turn into `i8` - this | |
222 | /// is useful for indexing slices, as `&[T]`'s data pointer is `T*`. | |
223 | /// If the type is an unsized struct, the regular layout is generated, | |
224 | /// with the inner-most trailing unsized field using the "minimal unit" | |
225 | /// of that field's type - this is useful for taking the address of | |
226 | /// that field and ensuring the struct has the right alignment. | |
b7449926 | 227 | fn llvm_type<'a>(&self, cx: &CodegenCx<'a, 'tcx>) -> &'a Type { |
c295e0f8 | 228 | if let Abi::Scalar(scalar) = self.abi { |
ff7c6d11 XL |
229 | // Use a different cache for scalars because pointers to DSTs |
230 | // can be either fat or thin (data pointers of fat pointers). | |
2c00a5a8 | 231 | if let Some(&llty) = cx.scalar_lltypes.borrow().get(&self.ty) { |
ff7c6d11 | 232 | return llty; |
32a655c1 | 233 | } |
1b1a35ee | 234 | let llty = match *self.ty.kind() { |
dfeec247 | 235 | ty::Ref(_, ty, _) | ty::RawPtr(ty::TypeAndMut { ty, .. }) => { |
a1dfa0c6 | 236 | cx.type_ptr_to(cx.layout_of(ty).llvm_type(cx)) |
ff7c6d11 | 237 | } |
b7449926 | 238 | ty::Adt(def, _) if def.is_box() => { |
a1dfa0c6 | 239 | cx.type_ptr_to(cx.layout_of(self.ty.boxed_ty()).llvm_type(cx)) |
ff7c6d11 | 240 | } |
c295e0f8 XL |
241 | ty::FnPtr(sig) => { |
242 | cx.fn_ptr_backend_type(cx.fn_abi_of_fn_ptr(sig, ty::List::empty())) | |
243 | } | |
dfeec247 | 244 | _ => self.scalar_llvm_type_at(cx, scalar, Size::ZERO), |
ff7c6d11 | 245 | }; |
2c00a5a8 | 246 | cx.scalar_lltypes.borrow_mut().insert(self.ty, llty); |
ff7c6d11 | 247 | return llty; |
32a655c1 | 248 | } |
32a655c1 | 249 | |
ff7c6d11 XL |
250 | // Check the cache. |
251 | let variant_index = match self.variants { | |
ba9703b0 | 252 | Variants::Single { index } => Some(index), |
dfeec247 | 253 | _ => None, |
ff7c6d11 | 254 | }; |
c295e0f8 | 255 | if let Some(llty) = cx.type_lowering.borrow().get(&(self.ty, variant_index)) { |
94222f64 | 256 | return llty.lltype; |
ff7c6d11 XL |
257 | } |
258 | ||
259 | debug!("llvm_type({:#?})", self); | |
260 | ||
a1dfa0c6 | 261 | assert!(!self.ty.has_escaping_bound_vars(), "{:?} has escaping bound vars", self.ty); |
ff7c6d11 XL |
262 | |
263 | // Make sure lifetimes are erased, to avoid generating distinct LLVM | |
264 | // types for Rust types that only differ in the choice of lifetimes. | |
fc512014 | 265 | let normal_ty = cx.tcx.erase_regions(self.ty); |
1a4d82fc | 266 | |
ff7c6d11 | 267 | let mut defer = None; |
94222f64 | 268 | let mut field_remapping = None; |
ff7c6d11 | 269 | let llty = if self.ty != normal_ty { |
2c00a5a8 | 270 | let mut layout = cx.layout_of(normal_ty); |
ff7c6d11 | 271 | if let Some(v) = variant_index { |
2c00a5a8 | 272 | layout = layout.for_variant(cx, v); |
ff7c6d11 | 273 | } |
2c00a5a8 | 274 | layout.llvm_type(cx) |
ff7c6d11 | 275 | } else { |
94222f64 | 276 | uncached_llvm_type(cx, *self, &mut defer, &mut field_remapping) |
ff7c6d11 XL |
277 | }; |
278 | debug!("--> mapped {:#?} to llty={:?}", self, llty); | |
279 | ||
c295e0f8 XL |
280 | cx.type_lowering |
281 | .borrow_mut() | |
282 | .insert((self.ty, variant_index), TypeLowering { lltype: llty, field_remapping }); | |
1a4d82fc | 283 | |
b7449926 | 284 | if let Some((llty, layout)) = defer { |
94222f64 XL |
285 | let (llfields, packed, new_field_remapping) = struct_llfields(cx, layout); |
286 | cx.set_struct_body(llty, &llfields, packed); | |
287 | cx.type_lowering | |
288 | .borrow_mut() | |
289 | .get_mut(&(self.ty, variant_index)) | |
290 | .unwrap() | |
291 | .field_remapping = new_field_remapping; | |
1a4d82fc | 292 | } |
ff7c6d11 XL |
293 | llty |
294 | } | |
1a4d82fc | 295 | |
b7449926 | 296 | fn immediate_llvm_type<'a>(&self, cx: &CodegenCx<'a, 'tcx>) -> &'a Type { |
c295e0f8 | 297 | if let Abi::Scalar(scalar) = self.abi { |
ff7c6d11 | 298 | if scalar.is_bool() { |
a1dfa0c6 | 299 | return cx.type_i1(); |
ff7c6d11 XL |
300 | } |
301 | } | |
2c00a5a8 | 302 | self.llvm_type(cx) |
cc61c64b XL |
303 | } |
304 | ||
dfeec247 XL |
305 | fn scalar_llvm_type_at<'a>( |
306 | &self, | |
307 | cx: &CodegenCx<'a, 'tcx>, | |
c295e0f8 | 308 | scalar: Scalar, |
dfeec247 XL |
309 | offset: Size, |
310 | ) -> &'a Type { | |
04454e1e | 311 | match scalar.primitive() { |
ba9703b0 XL |
312 | Int(i, _) => cx.type_from_integer(i), |
313 | F32 => cx.type_f32(), | |
314 | F64 => cx.type_f64(), | |
315 | Pointer => { | |
ff7c6d11 | 316 | // If we know the alignment, pick something better than i8. |
3dfed10e XL |
317 | let (pointee, address_space) = |
318 | if let Some(pointee) = self.pointee_info_at(cx, offset) { | |
319 | (cx.type_pointee_for_align(pointee.align), pointee.address_space) | |
320 | } else { | |
321 | (cx.type_i8(), AddressSpace::DATA) | |
322 | }; | |
323 | cx.type_ptr_to_ext(pointee, address_space) | |
ff7c6d11 XL |
324 | } |
325 | } | |
cc61c64b XL |
326 | } |
327 | ||
dfeec247 XL |
328 | fn scalar_pair_element_llvm_type<'a>( |
329 | &self, | |
330 | cx: &CodegenCx<'a, 'tcx>, | |
331 | index: usize, | |
332 | immediate: bool, | |
333 | ) -> &'a Type { | |
ff7c6d11 XL |
334 | // HACK(eddyb) special-case fat pointers until LLVM removes |
335 | // pointee types, to avoid bitcasting every `OperandRef::deref`. | |
1b1a35ee | 336 | match self.ty.kind() { |
dfeec247 | 337 | ty::Ref(..) | ty::RawPtr(_) => { |
2c00a5a8 | 338 | return self.field(cx, index).llvm_type(cx); |
ff7c6d11 | 339 | } |
5099ac24 FG |
340 | // only wide pointer boxes are handled as pointers |
341 | // thin pointer boxes with scalar allocators are handled by the general logic below | |
342 | ty::Adt(def, substs) if def.is_box() && cx.layout_of(substs.type_at(1)).is_zst() => { | |
2c00a5a8 | 343 | let ptr_ty = cx.tcx.mk_mut_ptr(self.ty.boxed_ty()); |
8faf50e0 | 344 | return cx.layout_of(ptr_ty).scalar_pair_element_llvm_type(cx, index, immediate); |
ff7c6d11 XL |
345 | } |
346 | _ => {} | |
347 | } | |
348 | ||
5e7ed085 FG |
349 | let Abi::ScalarPair(a, b) = self.abi else { |
350 | bug!("TyAndLayout::scalar_pair_element_llty({:?}): not applicable", self); | |
ff7c6d11 XL |
351 | }; |
352 | let scalar = [a, b][index]; | |
353 | ||
8faf50e0 XL |
354 | // Make sure to return the same type `immediate_llvm_type` would when |
355 | // dealing with an immediate pair. This means that `(bool, bool)` is | |
356 | // effectively represented as `{i8, i8}` in memory and two `i1`s as an | |
357 | // immediate, just like `bool` is typically `i8` in memory and only `i1` | |
358 | // when immediate. We need to load/store `bool` as `i8` to avoid | |
359 | // crippling LLVM optimizations or triggering other LLVM bugs with `i1`. | |
360 | if immediate && scalar.is_bool() { | |
a1dfa0c6 | 361 | return cx.type_i1(); |
ff7c6d11 XL |
362 | } |
363 | ||
04454e1e | 364 | let offset = if index == 0 { Size::ZERO } else { a.size(cx).align_to(b.align(cx).abi) }; |
2c00a5a8 | 365 | self.scalar_llvm_type_at(cx, scalar, offset) |
ff7c6d11 XL |
366 | } |
367 | ||
94222f64 | 368 | fn llvm_field_index<'a>(&self, cx: &CodegenCx<'a, 'tcx>, index: usize) -> u64 { |
ff7c6d11 | 369 | match self.abi { |
ba9703b0 XL |
370 | Abi::Scalar(_) | Abi::ScalarPair(..) => { |
371 | bug!("TyAndLayout::llvm_field_index({:?}): not applicable", self) | |
ff7c6d11 XL |
372 | } |
373 | _ => {} | |
374 | } | |
375 | match self.fields { | |
ba9703b0 XL |
376 | FieldsShape::Primitive | FieldsShape::Union(_) => { |
377 | bug!("TyAndLayout::llvm_field_index({:?}): not applicable", self) | |
ff7c6d11 XL |
378 | } |
379 | ||
ba9703b0 | 380 | FieldsShape::Array { .. } => index as u64, |
ff7c6d11 | 381 | |
94222f64 XL |
382 | FieldsShape::Arbitrary { .. } => { |
383 | let variant_index = match self.variants { | |
384 | Variants::Single { index } => Some(index), | |
385 | _ => None, | |
386 | }; | |
387 | ||
388 | // Look up llvm field if indexes do not match memory order due to padding. If | |
389 | // `field_remapping` is `None` no padding was used and the llvm field index | |
390 | // matches the memory index. | |
391 | match cx.type_lowering.borrow().get(&(self.ty, variant_index)) { | |
392 | Some(TypeLowering { field_remapping: Some(ref remap), .. }) => { | |
393 | remap[index] as u64 | |
394 | } | |
395 | Some(_) => self.fields.memory_index(index) as u64, | |
396 | None => { | |
397 | bug!("TyAndLayout::llvm_field_index({:?}): type info not found", self) | |
398 | } | |
399 | } | |
400 | } | |
cc61c64b XL |
401 | } |
402 | } | |
1a4d82fc | 403 | |
94222f64 XL |
404 | // FIXME(eddyb) this having the same name as `TyAndLayout::pointee_info_at` |
405 | // (the inherent method, which is lacking this caching logic) can result in | |
406 | // the uncached version being called - not wrong, but potentially inefficient. | |
dfeec247 | 407 | fn pointee_info_at<'a>(&self, cx: &CodegenCx<'a, 'tcx>, offset: Size) -> Option<PointeeInfo> { |
2c00a5a8 | 408 | if let Some(&pointee) = cx.pointee_infos.borrow().get(&(self.ty, offset)) { |
ff7c6d11 XL |
409 | return pointee; |
410 | } | |
411 | ||
94222f64 | 412 | let result = Ty::ty_and_layout_pointee_info_at(*self, cx, offset); |
ff7c6d11 | 413 | |
2c00a5a8 | 414 | cx.pointee_infos.borrow_mut().insert((self.ty, offset), result); |
ff7c6d11 XL |
415 | result |
416 | } | |
1a4d82fc | 417 | } |