1 // Copyright 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
11 /*!
12 * # Representation of Algebraic Data Types
13 *
14 * This module determines how to represent enums, structs, and tuples
15 * based on their monomorphized types; it is responsible both for
16 * choosing a representation and translating basic operations on
17 * values of those types. (Note: exporting the representations for
18 * debuggers is handled in debuginfo.rs, not here.)
19 *
20 * Note that the interface treats everything as a general case of an
21 * enum, so structs/tuples/etc. have one pseudo-variant with
22 * discriminant 0; i.e., as if they were a univariant enum.
23 *
24 * Having everything in one place will enable improvements to data
25 * structure representation; possibilities include:
26 *
27 * - User-specified alignment (e.g., cacheline-aligning parts of
28 * concurrently accessed data structures); LLVM can't represent this
29 * directly, so we'd have to insert padding fields in any structure
30 * that might contain one and adjust GEP indices accordingly. See
31 * issue #4578.
32 *
33 * - Store nested enums' discriminants in the same word. Rather, if
34 * some variants start with enums, and those enums representations
35 * have unused alignment padding between discriminant and body, the
36 * outer enum's discriminant can be stored there and those variants
37 * can start at offset 0. Kind of fancy, and might need work to
38 * make copies of the inner enum type cooperate, but it could help
39 * with `Option` or `Result` wrapped around another enum.
40 *
41 * - Tagged pointers would be neat, but given that any type can be
42 * used unboxed and any field can have pointers (including mutable)
43 * taken to it, implementing them for Rust seems difficult.
44 */
45
46 #![allow(unsigned_negate)]
47
48 use std::container::Map;
49 use libc::c_ulonglong;
50 use std::num::{Bitwise};
51 use std::rc::Rc;
52
53 use lib::llvm::{ValueRef, True, IntEQ, IntNE};
54 use middle::trans::_match;
55 use middle::trans::build::*;
56 use middle::trans::common::*;
57 use middle::trans::machine;
58 use middle::trans::type_::Type;
59 use middle::trans::type_of;
60 use middle::ty;
61 use middle::ty::Disr;
62 use syntax::abi::{X86, X86_64, Arm, Mips};
63 use syntax::ast;
64 use syntax::attr;
65 use syntax::attr::IntType;
66 use util::ppaux::ty_to_str;
67
68 type Hint = attr::ReprAttr;
69
70
71 /// Representations.
72 pub enum Repr {
73 /// C-like enums; basically an int.
74 CEnum(IntType, Disr, Disr), // discriminant range (signedness based on the IntType)
75 /**
76 * Single-case variants, and structs/tuples/records.
77 *
78 * Structs with destructors need a dynamic destroyedness flag to
79 * avoid running the destructor too many times; this is included
80 * in the `Struct` if present.
81 */
82 Univariant(Struct, bool),
83 /**
84 * General-case enums: for each case there is a struct, and they
85 * all start with a field for the discriminant.
86 */
87 General(IntType, Vec<Struct>),
88 /**
89 * Two cases distinguished by a nullable pointer: the case with discriminant
90 * `nndiscr` is represented by the struct `nonnull`, where the `ptrfield`th
91 * field is known to be nonnull due to its type; if that field is null, then
92 * it represents the other case, which is inhabited by at most one value
93 * (and all other fields are undefined/unused).
94 *
95 * For example, `std::option::Option` instantiated at a safe pointer type
96 * is represented such that `None` is a null pointer and `Some` is the
97 * identity function.
98 */
99 NullablePointer {
100 pub nonnull: Struct,
101 pub nndiscr: Disr,
102 pub ptrfield: uint,
103 pub nullfields: Vec<ty::t>,
104 }
105 }
106
107 /// For structs, and struct-like parts of anything fancier.
108 pub struct Struct {
109 pub size: u64,
110 pub align: u64,
111 pub packed: bool,
112 pub fields: Vec<ty::t>,
113 }
114
115 /**
116 * Convenience for `represent_type`. There should probably be more or
117 * these, for places in trans where the `ty::t` isn't directly
118 * available.
119 */
120 pub fn represent_node(bcx: &Block, node: ast::NodeId) -> Rc<Repr> {
121 represent_type(bcx.ccx(), node_id_type(bcx, node))
122 }
123
124 /// Decides how to represent a given type.
125 pub fn represent_type(cx: &CrateContext, t: ty::t) -> Rc<Repr> {
126 debug!("Representing: {}", ty_to_str(cx.tcx(), t));
127 match cx.adt_reprs.borrow().find(&t) {
128 Some(repr) => return repr.clone(),
129 None => {}
130 }
131
132 let repr = Rc::new(represent_type_uncached(cx, t));
133 debug!("Represented as: {:?}", repr)
134 cx.adt_reprs.borrow_mut().insert(t, repr.clone());
135 repr
136 }
137
138 fn represent_type_uncached(cx: &CrateContext, t: ty::t) -> Repr {
139 match ty::get(t).sty {
140 ty::ty_tup(ref elems) => {
141 return Univariant(mk_struct(cx, elems.as_slice(), false), false)
142 }
143 ty::ty_struct(def_id, ref substs) => {
144 let fields = ty::lookup_struct_fields(cx.tcx(), def_id);
145 let mut ftys = fields.iter().map(|field| {
146 ty::lookup_field_type(cx.tcx(), def_id, field.id, substs)
147 }).collect::<Vec<_>>();
148 let packed = ty::lookup_packed(cx.tcx(), def_id);
149 let dtor = ty::ty_dtor(cx.tcx(), def_id).has_drop_flag();
150 if dtor { ftys.push(ty::mk_bool()); }
151
152 return Univariant(mk_struct(cx, ftys.as_slice(), packed), dtor)
153 }
154 ty::ty_enum(def_id, ref substs) => {
155 let cases = get_cases(cx.tcx(), def_id, substs);
156 let hint = ty::lookup_repr_hint(cx.tcx(), def_id);
157
158 if cases.len() == 0 {
159 // Uninhabitable; represent as unit
160 // (Typechecking will reject discriminant-sizing attrs.)
161 assert_eq!(hint, attr::ReprAny);
162 return Univariant(mk_struct(cx, [], false), false);
163 }
164
165 if cases.iter().all(|c| c.tys.len() == 0) {
166 // All bodies empty -> intlike
167 let discrs: Vec<u64> = cases.iter().map(|c| c.discr).collect();
168 let bounds = IntBounds {
169 ulo: *discrs.iter().min().unwrap(),
170 uhi: *discrs.iter().max().unwrap(),
171 slo: discrs.iter().map(|n| *n as i64).min().unwrap(),
172 shi: discrs.iter().map(|n| *n as i64).max().unwrap()
173 };
174 return mk_cenum(cx, hint, &bounds);
175 }
176
177 // Since there's at least one
178 // non-empty body, explicit discriminants should have
179 // been rejected by a checker before this point.
180 if !cases.iter().enumerate().all(|(i,c)| c.discr == (i as Disr)) {
181 cx.sess().bug(format!("non-C-like enum {} with specified \
182 discriminants",
183 ty::item_path_str(cx.tcx(), def_id)))
184 }
185
186 if cases.len() == 1 {
187 // Equivalent to a struct/tuple/newtype.
188 // (Typechecking will reject discriminant-sizing attrs.)
189 assert_eq!(hint, attr::ReprAny);
190 return Univariant(mk_struct(cx,
191 cases.get(0).tys.as_slice(),
192 false),
193 false)
194 }
195
196 if cases.len() == 2 && hint == attr::ReprAny {
197 // Nullable pointer optimization
198 let mut discr = 0;
199 while discr < 2 {
200 if cases.get(1 - discr).is_zerolen(cx) {
201 match cases.get(discr).find_ptr() {
202 Some(ptrfield) => {
203 return NullablePointer {
204 nndiscr: discr as u64,
205 nonnull: mk_struct(cx,
206 cases.get(discr)
207 .tys
208 .as_slice(),
209 false),
210 ptrfield: ptrfield,
211 nullfields: cases.get(1 - discr).tys
212 .clone()
213 }
214 }
215 None => { }
216 }
217 }
218 discr += 1;
219 }
220 }
221
222 // The general case.
223 assert!((cases.len() - 1) as i64 >= 0);
224 let bounds = IntBounds { ulo: 0, uhi: (cases.len() - 1) as u64,
225 slo: 0, shi: (cases.len() - 1) as i64 };
226 let ity = range_to_inttype(cx, hint, &bounds);
227 return General(ity, cases.iter().map(|c| {
228 let discr = vec!(ty_of_inttype(ity));
229 mk_struct(cx, discr.append(c.tys.as_slice()).as_slice(), false)
230 }).collect())
231 }
232 _ => cx.sess().bug("adt::represent_type called on non-ADT type")
233 }
234 }
235
236 /// Determine, without doing translation, whether an ADT must be FFI-safe.
237 /// For use in lint or similar, where being sound but slightly incomplete is acceptable.
238 pub fn is_ffi_safe(tcx: &ty::ctxt, def_id: ast::DefId) -> bool {
239 match ty::get(ty::lookup_item_type(tcx, def_id).ty).sty {
240 ty::ty_enum(def_id, _) => {
241 let variants = ty::enum_variants(tcx, def_id);
242 // Univariant => like struct/tuple.
243 if variants.len() <= 1 {
244 return true;
245 }
246 let hint = ty::lookup_repr_hint(tcx, def_id);
247 // Appropriate representation explicitly selected?
248 if hint.is_ffi_safe() {
249 return true;
250 }
251 // Option<Box<T>> and similar are used in FFI. Rather than try to
252 // resolve type parameters and recognize this case exactly, this
253 // overapproximates -- assuming that if a non-C-like enum is being
254 // used in FFI then the user knows what they're doing.
255 if variants.iter().any(|vi| !vi.args.is_empty()) {
256 return true;
257 }
258 false
259 }
260 // struct, tuple, etc.
261 // (is this right in the present of typedefs?)
262 _ => true
263 }
264 }
265
266 // this should probably all be in ty
267 struct Case { discr: Disr, tys: Vec<ty::t> }
268 impl Case {
269 fn is_zerolen(&self, cx: &CrateContext) -> bool {
270 mk_struct(cx, self.tys.as_slice(), false).size == 0
271 }
272 fn find_ptr(&self) -> Option<uint> {
273 self.tys.iter().position(|&ty| {
274 match ty::get(ty).sty {
275 ty::ty_rptr(_, mt) => match ty::get(mt.ty).sty {
276 ty::ty_vec(_, None) | ty::ty_str => false,
277 _ => true,
278 },
279 ty::ty_uniq(..) | ty::ty_box(..) |
280 ty::ty_bare_fn(..) => true,
281 // Is that everything? Would closures or slices qualify?
282 _ => false
283 }
284 })
285 }
286 }
287
288 fn get_cases(tcx: &ty::ctxt, def_id: ast::DefId, substs: &ty::substs) -> Vec<Case> {
289 ty::enum_variants(tcx, def_id).iter().map(|vi| {
290 let arg_tys = vi.args.iter().map(|&raw_ty| {
291 ty::subst(tcx, substs, raw_ty)
292 }).collect();
293 Case { discr: vi.disr_val, tys: arg_tys }
294 }).collect()
295 }
296
297
298 fn mk_struct(cx: &CrateContext, tys: &[ty::t], packed: bool) -> Struct {
299 let lltys = tys.iter().map(|&ty| type_of::sizing_type_of(cx, ty)).collect::<Vec<_>>();
300 let llty_rec = Type::struct_(cx, lltys.as_slice(), packed);
301 Struct {
302 size: machine::llsize_of_alloc(cx, llty_rec) /*bad*/as u64,
303 align: machine::llalign_of_min(cx, llty_rec) /*bad*/as u64,
304 packed: packed,
305 fields: Vec::from_slice(tys),
306 }
307 }
308
309 struct IntBounds {
310 slo: i64,
311 shi: i64,
312 ulo: u64,
313 uhi: u64
314 }
315
316 fn mk_cenum(cx: &CrateContext, hint: Hint, bounds: &IntBounds) -> Repr {
317 let it = range_to_inttype(cx, hint, bounds);
318 match it {
319 attr::SignedInt(_) => CEnum(it, bounds.slo as Disr, bounds.shi as Disr),
320 attr::UnsignedInt(_) => CEnum(it, bounds.ulo, bounds.uhi)
321 }
322 }
323
324 fn range_to_inttype(cx: &CrateContext, hint: Hint, bounds: &IntBounds) -> IntType {
325 debug!("range_to_inttype: {:?} {:?}", hint, bounds);
326 // Lists of sizes to try. u64 is always allowed as a fallback.
327 static choose_shortest: &'static[IntType] = &[
328 attr::UnsignedInt(ast::TyU8), attr::SignedInt(ast::TyI8),
329 attr::UnsignedInt(ast::TyU16), attr::SignedInt(ast::TyI16),
330 attr::UnsignedInt(ast::TyU32), attr::SignedInt(ast::TyI32)];
331 static at_least_32: &'static[IntType] = &[
332 attr::UnsignedInt(ast::TyU32), attr::SignedInt(ast::TyI32)];
333
334 let attempts;
335 match hint {
336 attr::ReprInt(span, ity) => {
337 if !bounds_usable(cx, ity, bounds) {
338 cx.sess().span_bug(span, "representation hint insufficient for discriminant range")
339 }
340 return ity;
341 }
342 attr::ReprExtern => {
343 attempts = match cx.sess().targ_cfg.arch {
344 X86 | X86_64 => at_least_32,
345 // WARNING: the ARM EABI has two variants; the one corresponding to `at_least_32`
346 // appears to be used on Linux and NetBSD, but some systems may use the variant
347 // corresponding to `choose_shortest`. However, we don't run on those yet...?
348 Arm => at_least_32,
349 Mips => at_least_32,
350 }
351 }
352 attr::ReprAny => {
353 attempts = choose_shortest;
354 }
355 }
356 for &ity in attempts.iter() {
357 if bounds_usable(cx, ity, bounds) {
358 return ity;
359 }
360 }
361 return attr::UnsignedInt(ast::TyU64);
362 }
363
364 pub fn ll_inttype(cx: &CrateContext, ity: IntType) -> Type {
365 match ity {
366 attr::SignedInt(t) => Type::int_from_ty(cx, t),
367 attr::UnsignedInt(t) => Type::uint_from_ty(cx, t)
368 }
369 }
370
371 fn bounds_usable(cx: &CrateContext, ity: IntType, bounds: &IntBounds) -> bool {
372 debug!("bounds_usable: {:?} {:?}", ity, bounds);
373 match ity {
374 attr::SignedInt(_) => {
375 let lllo = C_integral(ll_inttype(cx, ity), bounds.slo as u64, true);
376 let llhi = C_integral(ll_inttype(cx, ity), bounds.shi as u64, true);
377 bounds.slo == const_to_int(lllo) as i64 && bounds.shi == const_to_int(llhi) as i64
378 }
379 attr::UnsignedInt(_) => {
380 let lllo = C_integral(ll_inttype(cx, ity), bounds.ulo, false);
381 let llhi = C_integral(ll_inttype(cx, ity), bounds.uhi, false);
382 bounds.ulo == const_to_uint(lllo) as u64 && bounds.uhi == const_to_uint(llhi) as u64
383 }
384 }
385 }
386
387 pub fn ty_of_inttype(ity: IntType) -> ty::t {
388 match ity {
389 attr::SignedInt(t) => ty::mk_mach_int(t),
390 attr::UnsignedInt(t) => ty::mk_mach_uint(t)
391 }
392 }
393
394
395 /**
396 * LLVM-level types are a little complicated.
397 *
398 * C-like enums need to be actual ints, not wrapped in a struct,
399 * because that changes the ABI on some platforms (see issue #10308).
400 *
401 * For nominal types, in some cases, we need to use LLVM named structs
402 * and fill in the actual contents in a second pass to prevent
403 * unbounded recursion; see also the comments in `trans::type_of`.
404 */
405 pub fn type_of(cx: &CrateContext, r: &Repr) -> Type {
406 generic_type_of(cx, r, None, false)
407 }
408 pub fn sizing_type_of(cx: &CrateContext, r: &Repr) -> Type {
409 generic_type_of(cx, r, None, true)
410 }
411 pub fn incomplete_type_of(cx: &CrateContext, r: &Repr, name: &str) -> Type {
412 generic_type_of(cx, r, Some(name), false)
413 }
414 pub fn finish_type_of(cx: &CrateContext, r: &Repr, llty: &mut Type) {
415 match *r {
416 CEnum(..) | General(..) => { }
417 Univariant(ref st, _) | NullablePointer{ nonnull: ref st, .. } =>
418 llty.set_struct_body(struct_llfields(cx, st, false).as_slice(),
419 st.packed)
420 }
421 }
422
423 fn generic_type_of(cx: &CrateContext, r: &Repr, name: Option<&str>, sizing: bool) -> Type {
424 match *r {
425 CEnum(ity, _, _) => ll_inttype(cx, ity),
426 Univariant(ref st, _) | NullablePointer{ nonnull: ref st, .. } => {
427 match name {
428 None => {
429 Type::struct_(cx, struct_llfields(cx, st, sizing).as_slice(),
430 st.packed)
431 }
432 Some(name) => { assert_eq!(sizing, false); Type::named_struct(cx, name) }
433 }
434 }
435 General(ity, ref sts) => {
436 // We need a representation that has:
437 // * The alignment of the most-aligned field
438 // * The size of the largest variant (rounded up to that alignment)
439 // * No alignment padding anywhere any variant has actual data
440 // (currently matters only for enums small enough to be immediate)
441 // * The discriminant in an obvious place.
442 //
443 // So we start with the discriminant, pad it up to the alignment with
444 // more of its own type, then use alignment-sized ints to get the rest
445 // of the size.
446 //
447 // FIXME #10604: this breaks when vector types are present.
448 let size = sts.iter().map(|st| st.size).max().unwrap();
449 let most_aligned = sts.iter().max_by(|st| st.align).unwrap();
450 let align = most_aligned.align;
451 let discr_ty = ll_inttype(cx, ity);
452 let discr_size = machine::llsize_of_alloc(cx, discr_ty) as u64;
453 let align_units = (size + align - 1) / align - 1;
454 let pad_ty = match align {
455 1 => Type::array(&Type::i8(cx), align_units),
456 2 => Type::array(&Type::i16(cx), align_units),
457 4 => Type::array(&Type::i32(cx), align_units),
458 8 if machine::llalign_of_min(cx, Type::i64(cx)) == 8 =>
459 Type::array(&Type::i64(cx), align_units),
460 a if a.count_ones() == 1 => Type::array(&Type::vector(&Type::i32(cx), a / 4),
461 align_units),
462 _ => fail!("unsupported enum alignment: {:?}", align)
463 };
464 assert_eq!(machine::llalign_of_min(cx, pad_ty) as u64, align);
465 assert_eq!(align % discr_size, 0);
466 let fields = vec!(discr_ty,
467 Type::array(&discr_ty, align / discr_size - 1),
468 pad_ty);
469 match name {
470 None => Type::struct_(cx, fields.as_slice(), false),
471 Some(name) => {
472 let mut llty = Type::named_struct(cx, name);
473 llty.set_struct_body(fields.as_slice(), false);
474 llty
475 }
476 }
477 }
478 }
479 }
480
481 fn struct_llfields(cx: &CrateContext, st: &Struct, sizing: bool) -> Vec<Type> {
482 if sizing {
483 st.fields.iter().map(|&ty| type_of::sizing_type_of(cx, ty)).collect()
484 } else {
485 st.fields.iter().map(|&ty| type_of::type_of(cx, ty)).collect()
486 }
487 }
488
489 /**
490 * Obtain a representation of the discriminant sufficient to translate
491 * destructuring; this may or may not involve the actual discriminant.
492 *
493 * This should ideally be less tightly tied to `_match`.
494 */
495 pub fn trans_switch(bcx: &Block, r: &Repr, scrutinee: ValueRef)
496 -> (_match::branch_kind, Option<ValueRef>) {
497 match *r {
498 CEnum(..) | General(..) => {
499 (_match::switch, Some(trans_get_discr(bcx, r, scrutinee, None)))
500 }
501 NullablePointer{ nonnull: ref nonnull, nndiscr, ptrfield, .. } => {
502 (_match::switch, Some(nullable_bitdiscr(bcx, nonnull, nndiscr, ptrfield, scrutinee)))
503 }
504 Univariant(..) => {
505 (_match::single, None)
506 }
507 }
508 }
509
510
511
512 /// Obtain the actual discriminant of a value.
513 pub fn trans_get_discr(bcx: &Block, r: &Repr, scrutinee: ValueRef, cast_to: Option<Type>)
514 -> ValueRef {
515 let signed;
516 let val;
517 match *r {
518 CEnum(ity, min, max) => {
519 val = load_discr(bcx, ity, scrutinee, min, max);
520 signed = ity.is_signed();
521 }
522 General(ity, ref cases) => {
523 let ptr = GEPi(bcx, scrutinee, [0, 0]);
524 val = load_discr(bcx, ity, ptr, 0, (cases.len() - 1) as Disr);
525 signed = ity.is_signed();
526 }
527 Univariant(..) => {
528 val = C_u8(bcx.ccx(), 0);
529 signed = false;
530 }
531 NullablePointer{ nonnull: ref nonnull, nndiscr, ptrfield, .. } => {
532 val = nullable_bitdiscr(bcx, nonnull, nndiscr, ptrfield, scrutinee);
533 signed = false;
534 }
535 }
536 match cast_to {
537 None => val,
538 Some(llty) => if signed { SExt(bcx, val, llty) } else { ZExt(bcx, val, llty) }
539 }
540 }
541
542 fn nullable_bitdiscr(bcx: &Block, nonnull: &Struct, nndiscr: Disr, ptrfield: uint,
543 scrutinee: ValueRef) -> ValueRef {
544 let cmp = if nndiscr == 0 { IntEQ } else { IntNE };
545 let llptr = Load(bcx, GEPi(bcx, scrutinee, [0, ptrfield]));
546 let llptrty = type_of::type_of(bcx.ccx(), *nonnull.fields.get(ptrfield));
547 ICmp(bcx, cmp, llptr, C_null(llptrty))
548 }
549
550 /// Helper for cases where the discriminant is simply loaded.
551 fn load_discr(bcx: &Block, ity: IntType, ptr: ValueRef, min: Disr, max: Disr)
552 -> ValueRef {
553 let llty = ll_inttype(bcx.ccx(), ity);
554 assert_eq!(val_ty(ptr), llty.ptr_to());
555 let bits = machine::llbitsize_of_real(bcx.ccx(), llty);
556 assert!(bits <= 64);
557 let mask = (-1u64 >> (64 - bits)) as Disr;
558 if (max + 1) & mask == min & mask {
559 // i.e., if the range is everything. The lo==hi case would be
560 // rejected by the LLVM verifier (it would mean either an
561 // empty set, which is impossible, or the entire range of the
562 // type, which is pointless).
563 Load(bcx, ptr)
564 } else {
565 // llvm::ConstantRange can deal with ranges that wrap around,
566 // so an overflow on (max + 1) is fine.
567 LoadRangeAssert(bcx, ptr, min as c_ulonglong,
568 (max + 1) as c_ulonglong,
569 /* signed: */ True)
570 }
571 }
572
573 /**
574 * Yield information about how to dispatch a case of the
575 * discriminant-like value returned by `trans_switch`.
576 *
577 * This should ideally be less tightly tied to `_match`.
578 */
579 pub fn trans_case<'a>(bcx: &'a Block<'a>, r: &Repr, discr: Disr)
580 -> _match::opt_result<'a> {
581 match *r {
582 CEnum(ity, _, _) => {
583 _match::single_result(Result::new(bcx, C_integral(ll_inttype(bcx.ccx(), ity),
584 discr as u64, true)))
585 }
586 General(ity, _) => {
587 _match::single_result(Result::new(bcx, C_integral(ll_inttype(bcx.ccx(), ity),
588 discr as u64, true)))
589 }
590 Univariant(..) => {
591 bcx.ccx().sess().bug("no cases for univariants or structs")
592 }
593 NullablePointer{ .. } => {
594 assert!(discr == 0 || discr == 1);
595 _match::single_result(Result::new(bcx, C_i1(bcx.ccx(), discr != 0)))
596 }
597 }
598 }
599
600 /**
601 * Begin initializing a new value of the given case of the given
602 * representation. The fields, if any, should then be initialized via
603 * `trans_field_ptr`.
604 */
605 pub fn trans_start_init(bcx: &Block, r: &Repr, val: ValueRef, discr: Disr) {
606 match *r {
607 CEnum(ity, min, max) => {
608 assert_discr_in_range(ity, min, max, discr);
609 Store(bcx, C_integral(ll_inttype(bcx.ccx(), ity), discr as u64, true),
610 val)
611 }
612 General(ity, _) => {
613 Store(bcx, C_integral(ll_inttype(bcx.ccx(), ity), discr as u64, true),
614 GEPi(bcx, val, [0, 0]))
615 }
616 Univariant(ref st, true) => {
617 assert_eq!(discr, 0);
618 Store(bcx, C_bool(bcx.ccx(), true),
619 GEPi(bcx, val, [0, st.fields.len() - 1]))
620 }
621 Univariant(..) => {
622 assert_eq!(discr, 0);
623 }
624 NullablePointer{ nonnull: ref nonnull, nndiscr, ptrfield, .. } => {
625 if discr != nndiscr {
626 let llptrptr = GEPi(bcx, val, [0, ptrfield]);
627 let llptrty = type_of::type_of(bcx.ccx(),
628 *nonnull.fields.get(ptrfield));
629 Store(bcx, C_null(llptrty), llptrptr)
630 }
631 }
632 }
633 }
634
635 fn assert_discr_in_range(ity: IntType, min: Disr, max: Disr, discr: Disr) {
636 match ity {
637 attr::UnsignedInt(_) => assert!(min <= discr && discr <= max),
638 attr::SignedInt(_) => assert!(min as i64 <= discr as i64 && discr as i64 <= max as i64)
639 }
640 }
641
642 /**
643 * The number of fields in a given case; for use when obtaining this
644 * information from the type or definition is less convenient.
645 */
646 pub fn num_args(r: &Repr, discr: Disr) -> uint {
647 match *r {
648 CEnum(..) => 0,
649 Univariant(ref st, dtor) => {
650 assert_eq!(discr, 0);
651 st.fields.len() - (if dtor { 1 } else { 0 })
652 }
653 General(_, ref cases) => cases.get(discr as uint).fields.len() - 1,
654 NullablePointer{ nonnull: ref nonnull, nndiscr,
655 nullfields: ref nullfields, .. } => {
656 if discr == nndiscr { nonnull.fields.len() } else { nullfields.len() }
657 }
658 }
659 }
660
661 /// Access a field, at a point when the value's case is known.
662 pub fn trans_field_ptr(bcx: &Block, r: &Repr, val: ValueRef, discr: Disr,
663 ix: uint) -> ValueRef {
664 // Note: if this ever needs to generate conditionals (e.g., if we
665 // decide to do some kind of cdr-coding-like non-unique repr
666 // someday), it will need to return a possibly-new bcx as well.
667 match *r {
668 CEnum(..) => {
669 bcx.ccx().sess().bug("element access in C-like enum")
670 }
671 Univariant(ref st, _dtor) => {
672 assert_eq!(discr, 0);
673 struct_field_ptr(bcx, st, val, ix, false)
674 }
675 General(_, ref cases) => {
676 struct_field_ptr(bcx, cases.get(discr as uint), val, ix + 1, true)
677 }
678 NullablePointer{ nonnull: ref nonnull, nullfields: ref nullfields,
679 nndiscr, .. } => {
680 if discr == nndiscr {
681 struct_field_ptr(bcx, nonnull, val, ix, false)
682 } else {
683 // The unit-like case might have a nonzero number of unit-like fields.
684 // (e.g., Result or Either with () as one side.)
685 let ty = type_of::type_of(bcx.ccx(), *nullfields.get(ix));
686 assert_eq!(machine::llsize_of_alloc(bcx.ccx(), ty), 0);
687 // The contents of memory at this pointer can't matter, but use
688 // the value that's "reasonable" in case of pointer comparison.
689 PointerCast(bcx, val, ty.ptr_to())
690 }
691 }
692 }
693 }
694
695 fn struct_field_ptr(bcx: &Block, st: &Struct, val: ValueRef, ix: uint,
696 needs_cast: bool) -> ValueRef {
697 let ccx = bcx.ccx();
698
699 let val = if needs_cast {
700 let fields = st.fields.iter().map(|&ty| type_of::type_of(ccx, ty)).collect::<Vec<_>>();
701 let real_ty = Type::struct_(ccx, fields.as_slice(), st.packed);
702 PointerCast(bcx, val, real_ty.ptr_to())
703 } else {
704 val
705 };
706
707 GEPi(bcx, val, [0, ix])
708 }
709
710 /// Access the struct drop flag, if present.
711 pub fn trans_drop_flag_ptr(bcx: &Block, r: &Repr, val: ValueRef) -> ValueRef {
712 match *r {
713 Univariant(ref st, true) => GEPi(bcx, val, [0, st.fields.len() - 1]),
714 _ => bcx.ccx().sess().bug("tried to get drop flag of non-droppable type")
715 }
716 }
717
718 /**
719 * Construct a constant value, suitable for initializing a
720 * GlobalVariable, given a case and constant values for its fields.
721 * Note that this may have a different LLVM type (and different
722 * alignment!) from the representation's `type_of`, so it needs a
723 * pointer cast before use.
724 *
725 * The LLVM type system does not directly support unions, and only
726 * pointers can be bitcast, so a constant (and, by extension, the
727 * GlobalVariable initialized by it) will have a type that can vary
728 * depending on which case of an enum it is.
729 *
730 * To understand the alignment situation, consider `enum E { V64(u64),
731 * V32(u32, u32) }` on win32. The type has 8-byte alignment to
732 * accommodate the u64, but `V32(x, y)` would have LLVM type `{i32,
733 * i32, i32}`, which is 4-byte aligned.
734 *
735 * Currently the returned value has the same size as the type, but
736 * this could be changed in the future to avoid allocating unnecessary
737 * space after values of shorter-than-maximum cases.
738 */
739 pub fn trans_const(ccx: &CrateContext, r: &Repr, discr: Disr,
740 vals: &[ValueRef]) -> ValueRef {
741 match *r {
742 CEnum(ity, min, max) => {
743 assert_eq!(vals.len(), 0);
744 assert_discr_in_range(ity, min, max, discr);
745 C_integral(ll_inttype(ccx, ity), discr as u64, true)
746 }
747 General(ity, ref cases) => {
748 let case = cases.get(discr as uint);
749 let max_sz = cases.iter().map(|x| x.size).max().unwrap();
750 let lldiscr = C_integral(ll_inttype(ccx, ity), discr as u64, true);
751 let contents = build_const_struct(ccx,
752 case,
753 (vec!(lldiscr)).append(vals).as_slice());
754 C_struct(ccx, contents.append([padding(ccx, max_sz - case.size)]).as_slice(),
755 false)
756 }
757 Univariant(ref st, _dro) => {
758 assert!(discr == 0);
759 let contents = build_const_struct(ccx, st, vals);
760 C_struct(ccx, contents.as_slice(), st.packed)
761 }
762 NullablePointer{ nonnull: ref nonnull, nndiscr, .. } => {
763 if discr == nndiscr {
764 C_struct(ccx, build_const_struct(ccx,
765 nonnull,
766 vals).as_slice(),
767 false)
768 } else {
769 let vals = nonnull.fields.iter().map(|&ty| {
770 // Always use null even if it's not the `ptrfield`th
771 // field; see #8506.
772 C_null(type_of::sizing_type_of(ccx, ty))
773 }).collect::<Vec<ValueRef>>();
774 C_struct(ccx, build_const_struct(ccx,
775 nonnull,
776 vals.as_slice()).as_slice(),
777 false)
778 }
779 }
780 }
781 }
782
783 /**
784 * Compute struct field offsets relative to struct begin.
785 */
786 fn compute_struct_field_offsets(ccx: &CrateContext, st: &Struct) -> Vec<u64> {
787 let mut offsets = vec!();
788
789 let mut offset = 0;
790 for &ty in st.fields.iter() {
791 let llty = type_of::sizing_type_of(ccx, ty);
792 if !st.packed {
793 let type_align = machine::llalign_of_min(ccx, llty) as u64;
794 offset = roundup(offset, type_align);
795 }
796 offsets.push(offset);
797 offset += machine::llsize_of_alloc(ccx, llty) as u64;
798 }
799 assert_eq!(st.fields.len(), offsets.len());
800 offsets
801 }
802
803 /**
804 * Building structs is a little complicated, because we might need to
805 * insert padding if a field's value is less aligned than its type.
806 *
807 * Continuing the example from `trans_const`, a value of type `(u32,
808 * E)` should have the `E` at offset 8, but if that field's
809 * initializer is 4-byte aligned then simply translating the tuple as
810 * a two-element struct will locate it at offset 4, and accesses to it
811 * will read the wrong memory.
812 */
813 fn build_const_struct(ccx: &CrateContext, st: &Struct, vals: &[ValueRef])
814 -> Vec<ValueRef> {
815 assert_eq!(vals.len(), st.fields.len());
816
817 let target_offsets = compute_struct_field_offsets(ccx, st);
818
819 // offset of current value
820 let mut offset = 0;
821 let mut cfields = Vec::new();
822 for (&val, &target_offset) in vals.iter().zip(target_offsets.iter()) {
823 if !st.packed {
824 let val_align = machine::llalign_of_min(ccx, val_ty(val))
825 /*bad*/as u64;
826 offset = roundup(offset, val_align);
827 }
828 if offset != target_offset {
829 cfields.push(padding(ccx, target_offset - offset));
830 offset = target_offset;
831 }
832 assert!(!is_undef(val));
833 cfields.push(val);
834 offset += machine::llsize_of_alloc(ccx, val_ty(val)) as u64;
835 }
836
837 assert!(offset <= st.size);
838 if offset != st.size {
839 cfields.push(padding(ccx, st.size - offset));
840 }
841
842 cfields
843 }
844
845 fn padding(ccx: &CrateContext, size: u64) -> ValueRef {
846 C_undef(Type::array(&Type::i8(ccx), size))
847 }
848
849 // FIXME this utility routine should be somewhere more general
850 #[inline]
851 fn roundup(x: u64, a: u64) -> u64 { ((x + (a - 1)) / a) * a }
852
853 /// Get the discriminant of a constant value. (Not currently used.)
854 pub fn const_get_discrim(ccx: &CrateContext, r: &Repr, val: ValueRef)
855 -> Disr {
856 match *r {
857 CEnum(ity, _, _) => {
858 match ity {
859 attr::SignedInt(..) => const_to_int(val) as Disr,
860 attr::UnsignedInt(..) => const_to_uint(val) as Disr
861 }
862 }
863 General(ity, _) => {
864 match ity {
865 attr::SignedInt(..) => const_to_int(const_get_elt(ccx, val, [0])) as Disr,
866 attr::UnsignedInt(..) => const_to_uint(const_get_elt(ccx, val, [0])) as Disr
867 }
868 }
869 Univariant(..) => 0,
870 NullablePointer{ nndiscr, ptrfield, .. } => {
871 if is_null(const_struct_field(ccx, val, ptrfield)) {
872 /* subtraction as uint is ok because nndiscr is either 0 or 1 */
873 (1 - nndiscr) as Disr
874 } else {
875 nndiscr
876 }
877 }
878 }
879 }
880
881 /**
882 * Extract a field of a constant value, as appropriate for its
883 * representation.
884 *
885 * (Not to be confused with `common::const_get_elt`, which operates on
886 * raw LLVM-level structs and arrays.)
887 */
888 pub fn const_get_field(ccx: &CrateContext, r: &Repr, val: ValueRef,
889 _discr: Disr, ix: uint) -> ValueRef {
890 match *r {
891 CEnum(..) => ccx.sess().bug("element access in C-like enum const"),
892 Univariant(..) => const_struct_field(ccx, val, ix),
893 General(..) => const_struct_field(ccx, val, ix + 1),
894 NullablePointer{ .. } => const_struct_field(ccx, val, ix)
895 }
896 }
897
898 /// Extract field of struct-like const, skipping our alignment padding.
899 fn const_struct_field(ccx: &CrateContext, val: ValueRef, ix: uint)
900 -> ValueRef {
901 // Get the ix-th non-undef element of the struct.
902 let mut real_ix = 0; // actual position in the struct
903 let mut ix = ix; // logical index relative to real_ix
904 let mut field;
905 loop {
906 loop {
907 field = const_get_elt(ccx, val, [real_ix]);
908 if !is_undef(field) {
909 break;
910 }
911 real_ix = real_ix + 1;
912 }
913 if ix == 0 {
914 return field;
915 }
916 ix = ix - 1;
917 real_ix = real_ix + 1;
918 }
919 }
librustc/middle/trans/adt.rs:308:1-308:1 -struct- definition:
struct IntBounds {
slo: i64,
shi: i64,
references:- 5167: let discrs: Vec<u64> = cases.iter().map(|c| c.discr).collect();
168: let bounds = IntBounds {
169: ulo: *discrs.iter().min().unwrap(),
--
223: assert!((cases.len() - 1) as i64 >= 0);
224: let bounds = IntBounds { ulo: 0, uhi: (cases.len() - 1) as u64,
225: slo: 0, shi: (cases.len() - 1) as i64 };
--
371: fn bounds_usable(cx: &CrateContext, ity: IntType, bounds: &IntBounds) -> bool {
372: debug!("bounds_usable: {:?} {:?}", ity, bounds);
librustc/middle/trans/adt.rs:370:1-370:1 -fn- definition:
fn bounds_usable(cx: &CrateContext, ity: IntType, bounds: &IntBounds) -> bool {
debug!("bounds_usable: {:?} {:?}", ity, bounds);
match ity {
references:- 2356: for &ity in attempts.iter() {
357: if bounds_usable(cx, ity, bounds) {
358: return ity;
librustc/middle/trans/adt.rs:738:4-738:4 -fn- definition:
*/
pub fn trans_const(ccx: &CrateContext, r: &Repr, discr: Disr,
vals: &[ValueRef]) -> ValueRef {
references:- 5librustc/middle/trans/consts.rs:
556: }));
557: (adt::trans_const(cx, &*repr, discr, cs.as_slice()),
558: inlineable.iter().fold(true, |a, &b| a && b))
--
655: let (arg_vals, inlineable) = map_list(args.as_slice());
656: (adt::trans_const(cx, &*repr, 0, arg_vals.as_slice()),
657: inlineable)
--
665: let (arg_vals, inlineable) = map_list(args.as_slice());
666: (adt::trans_const(cx,
667: &*repr,
librustc/middle/trans/adt.rs:407:2-407:2 -fn- definition:
}
pub fn sizing_type_of(cx: &CrateContext, r: &Repr) -> Type {
generic_type_of(cx, r, None, true)
references:- 2librustc/middle/trans/type_of.rs:
140: let repr = adt::represent_type(cx, t);
141: adt::sizing_type_of(cx, &*repr)
142: }
--
150: let repr = adt::represent_type(cx, t);
151: adt::sizing_type_of(cx, &*repr)
152: }
librustc/middle/trans/adt.rs:887:4-887:4 -fn- definition:
*/
pub fn const_get_field(ccx: &CrateContext, r: &Repr, val: ValueRef,
_discr: Disr, ix: uint) -> ValueRef {
references:- 3librustc/middle/trans/consts.rs:
548: Some((bv, inlineable)) => {
549: (adt::const_get_field(cx, &*repr, bv, discr, ix),
550: inlineable)
librustc/middle/trans/adt.rs:323:1-323:1 -fn- definition:
fn range_to_inttype(cx: &CrateContext, hint: Hint, bounds: &IntBounds) -> IntType {
debug!("range_to_inttype: {:?} {:?}", hint, bounds);
// Lists of sizes to try. u64 is always allowed as a fallback.
references:- 2225: slo: 0, shi: (cases.len() - 1) as i64 };
226: let ity = range_to_inttype(cx, hint, &bounds);
227: return General(ity, cases.iter().map(|c| {
--
316: fn mk_cenum(cx: &CrateContext, hint: Hint, bounds: &IntBounds) -> Repr {
317: let it = range_to_inttype(cx, hint, bounds);
318: match it {
librustc/middle/trans/adt.rs:71:21-71:21 -enum- definition:
/// Representations.
pub enum Repr {
/// C-like enums; basically an int.
references:- 25512: /// Obtain the actual discriminant of a value.
513: pub fn trans_get_discr(bcx: &Block, r: &Repr, scrutinee: ValueRef, cast_to: Option<Type>)
514: -> ValueRef {
--
604: */
605: pub fn trans_start_init(bcx: &Block, r: &Repr, val: ValueRef, discr: Disr) {
606: match *r {
--
853: /// Get the discriminant of a constant value. (Not currently used.)
854: pub fn const_get_discrim(ccx: &CrateContext, r: &Repr, val: ValueRef)
855: -> Disr {
--
887: */
888: pub fn const_get_field(ccx: &CrateContext, r: &Repr, val: ValueRef,
889: _discr: Disr, ix: uint) -> ValueRef {
librustc/middle/trans/expr.rs:
1035: bcx: &'a Block<'a>,
1036: repr: &adt::Repr,
1037: discr: ty::Disr,
librustc/middle/trans/context.rs:
109: pub llsizingtypes: RefCell<HashMap<ty::t, Type>>,
110: pub adt_reprs: RefCell<HashMap<ty::t, Rc<adt::Repr>>>,
111: pub symbol_hasher: RefCell<Sha256>,
librustc/middle/trans/base.rs:
669: cx: &'b Block<'b>,
670: repr: &adt::Repr,
671: av: ValueRef,
librustc/middle/trans/_match.rs:
252: lit(Lit),
253: var(ty::Disr, Rc<adt::Repr>),
254: range(@ast::Expr, @ast::Expr),
--
973: bcx: &'a Block<'a>,
974: repr: &adt::Repr,
975: disr_val: ty::Disr,
librustc/middle/trans/debuginfo.rs:
1393: struct GeneralMemberDescriptionFactory {
1394: type_rep: Rc<adt::Repr>,
1395: variants: Rc<Vec<Rc<ty::VariantInfo>>>,
librustc/middle/trans/adt.rs:
710: /// Access the struct drop flag, if present.
711: pub fn trans_drop_flag_ptr(bcx: &Block, r: &Repr, val: ValueRef) -> ValueRef {
712: match *r {
librustc/middle/trans/adt.rs:812:4-812:4 -fn- definition:
*/
fn build_const_struct(ccx: &CrateContext, st: &Struct, vals: &[ValueRef])
-> Vec<ValueRef> {
references:- 4750: let lldiscr = C_integral(ll_inttype(ccx, ity), discr as u64, true);
751: let contents = build_const_struct(ccx,
752: case,
--
773: }).collect::<Vec<ValueRef>>();
774: C_struct(ccx, build_const_struct(ccx,
775: nonnull,
librustc/middle/trans/adt.rs:850:10-850:10 -fn- definition:
fn roundup(x: u64, a: u64) -> u64 { ((x + (a - 1)) / a) * a }
/// Get the discriminant of a constant value. (Not currently used.)
pub fn const_get_discrim(ccx: &CrateContext, r: &Repr, val: ValueRef)
references:- 2793: let type_align = machine::llalign_of_min(ccx, llty) as u64;
794: offset = roundup(offset, type_align);
795: }
--
825: /*bad*/as u64;
826: offset = roundup(offset, val_align);
827: }
librustc/middle/trans/adt.rs:422:1-422:1 -fn- definition:
fn generic_type_of(cx: &CrateContext, r: &Repr, name: Option<&str>, sizing: bool) -> Type {
match *r {
CEnum(ity, _, _) => ll_inttype(cx, ity),
references:- 3411: pub fn incomplete_type_of(cx: &CrateContext, r: &Repr, name: &str) -> Type {
412: generic_type_of(cx, r, Some(name), false)
413: }
librustc/middle/trans/adt.rs:386:1-386:1 -fn- definition:
pub fn ty_of_inttype(ity: IntType) -> ty::t {
match ity {
attr::SignedInt(t) => ty::mk_mach_int(t),
references:- 2227: return General(ity, cases.iter().map(|c| {
228: let discr = vec!(ty_of_inttype(ity));
229: mk_struct(cx, discr.append(c.tys.as_slice()).as_slice(), false)
librustc/middle/trans/debuginfo.rs:
1581: let discriminant_base_type_metadata = type_metadata(cx,
1582: adt::ty_of_inttype(inttype),
1583: codemap::DUMMY_SP);
librustc/middle/trans/adt.rs:67:1-67:1 -NK_AS_STR_TODO- definition:
type Hint = attr::ReprAttr;
/// Representations.
pub enum Repr {
references:- 2324: fn range_to_inttype(cx: &CrateContext, hint: Hint, bounds: &IntBounds) -> IntType {
325: debug!("range_to_inttype: {:?} {:?}", hint, bounds);
librustc/middle/trans/adt.rs:578:4-578:4 -fn- definition:
*/
pub fn trans_case<'a>(bcx: &'a Block<'a>, r: &Repr, discr: Disr)
-> _match::opt_result<'a> {
references:- 2librustc/middle/trans/base.rs:
738: variant.disr_val.to_str());
739: match adt::trans_case(cx, &*repr, variant.disr_val) {
740: _match::single_result(r) => {
librustc/middle/trans/_match.rs:
318: var(disr_val, ref repr) => {
319: return adt::trans_case(bcx, &**repr, disr_val);
320: }
librustc/middle/trans/adt.rs:410:2-410:2 -fn- definition:
}
pub fn incomplete_type_of(cx: &CrateContext, r: &Repr, name: &str) -> Type {
generic_type_of(cx, r, Some(name), false)
references:- 2librustc/middle/trans/type_of.rs:
266: substs.tps.as_slice());
267: adt::incomplete_type_of(cx, &*repr, name)
268: }
librustc/middle/trans/adt.rs:266:37-266:37 -struct- definition:
// this should probably all be in ty
struct Case { discr: Disr, tys: Vec<ty::t> }
impl Case {
references:- 3292: }).collect();
293: Case { discr: vi.disr_val, tys: arg_tys }
294: }).collect()
librustc/middle/trans/adt.rs:119:4-119:4 -fn- definition:
*/
pub fn represent_node(bcx: &Block, node: ast::NodeId) -> Rc<Repr> {
represent_type(bcx.ccx(), node_id_type(bcx, node))
references:- 4librustc/middle/trans/_match.rs:
2222: // This is the tuple struct case.
2223: let repr = adt::represent_node(bcx, pat.id);
2224: for (i, elem) in elems.iter().enumerate() {
--
2255: ast::PatTup(ref elems) => {
2256: let repr = adt::represent_node(bcx, pat.id);
2257: for (i, elem) in elems.iter().enumerate() {
librustc/middle/trans/adt.rs:480:1-480:1 -fn- definition:
fn struct_llfields(cx: &CrateContext, st: &Struct, sizing: bool) -> Vec<Type> {
if sizing {
st.fields.iter().map(|&ty| type_of::sizing_type_of(cx, ty)).collect()
references:- 2428: None => {
429: Type::struct_(cx, struct_llfields(cx, st, sizing).as_slice(),
430: st.packed)
librustc/middle/trans/adt.rs:124:43-124:43 -fn- definition:
/// Decides how to represent a given type.
pub fn represent_type(cx: &CrateContext, t: ty::t) -> Rc<Repr> {
debug!("Representing: {}", ty_to_str(cx.tcx(), t));
references:- 34librustc/middle/trans/glue.rs:
librustc/middle/trans/expr.rs:
librustc/middle/trans/consts.rs:
librustc/middle/trans/type_of.rs:
librustc/middle/trans/base.rs:
librustc/middle/trans/_match.rs:
librustc/middle/trans/reflect.rs:
librustc/middle/trans/debuginfo.rs:
librustc/middle/trans/type_of.rs:
librustc/middle/trans/adt.rs:512:47-512:47 -fn- definition:
/// Obtain the actual discriminant of a value.
pub fn trans_get_discr(bcx: &Block, r: &Repr, scrutinee: ValueRef, cast_to: Option<Type>)
-> ValueRef {
references:- 3498: CEnum(..) | General(..) => {
499: (_match::switch, Some(trans_get_discr(bcx, r, scrutinee, None)))
500: }
librustc/middle/trans/expr.rs:
1581: let lldiscrim_a =
1582: adt::trans_get_discr(bcx, &*repr, llexpr_ptr, Some(Type::i64(ccx)));
1583: match k_out {
librustc/middle/trans/reflect.rs:
306: let arg = BitCast(bcx, arg, llptrty);
307: let ret = adt::trans_get_discr(bcx, &*repr, arg, Some(Type::i64(ccx)));
308: Store(bcx, ret, fcx.llretptr.get().unwrap());
librustc/middle/trans/adt.rs:661:63-661:63 -fn- definition:
/// Access a field, at a point when the value's case is known.
pub fn trans_field_ptr(bcx: &Block, r: &Repr, val: ValueRef, discr: Disr,
ix: uint) -> ValueRef {
references:- 18librustc/middle/trans/glue.rs:
262: for (i, fld) in field_tys.iter().enumerate() {
263: let llfld_a = adt::trans_field_ptr(bcx, &*repr, v0, 0, i);
264: bcx.fcx.schedule_drop_mem(cleanup::CustomScope(field_scope),
librustc/middle/trans/expr.rs:
444: field_tys[ix].mt.ty,
445: |srcval| adt::trans_field_ptr(bcx, &*repr, srcval, discr, ix));
446: DatumBlock { datum: d.to_expr_datum(), bcx: bcx }
--
1242: adt::trans_start_init(bcx, &*repr, addr, 0);
1243: let field_dest = adt::trans_field_ptr(bcx, &*repr, addr, 0, 0);
1244: contents_datum.store_to(bcx, field_dest)
librustc/middle/trans/base.rs:
1546: for (i, arg_datum) in arg_datums.move_iter().enumerate() {
1547: let lldestptr = adt::trans_field_ptr(bcx,
1548: &*repr,
librustc/middle/trans/_match.rs:
979: let args = Vec::from_fn(adt::num_args(repr, disr_val), |i| {
980: adt::trans_field_ptr(bcx, repr, val, disr_val, i)
981: });
--
2257: for (i, elem) in elems.iter().enumerate() {
2258: let fldptr = adt::trans_field_ptr(bcx, &*repr, val, 0, i);
2259: bcx = bind_irrefutable_pat(bcx, *elem, fldptr,
librustc/middle/trans/reflect.rs:
331: let null = C_null(llptrty);
332: let ptr = adt::trans_field_ptr(bcx, &*repr, null, v.disr_val, j);
333: let offset = p2i(ccx, ptr);
librustc/middle/trans/base.rs:
693: for (i, field_ty) in field_tys.iter().enumerate() {
694: let llfld_a = adt::trans_field_ptr(cx, &*repr, av, discr, i);
695: cx = f(cx, llfld_a, field_ty.mt.ty);
librustc/middle/trans/adt.rs:604:4-604:4 -fn- definition:
*/
pub fn trans_start_init(bcx: &Block, r: &Repr, val: ValueRef, discr: Disr) {
match *r {
references:- 5librustc/middle/trans/expr.rs:
808: let repr = adt::represent_type(bcx.ccx(), ty);
809: adt::trans_start_init(bcx, &*repr, lldest, 0);
810: }
--
1241: let repr = adt::represent_type(bcx.ccx(), expr_ty);
1242: adt::trans_start_init(bcx, &*repr, addr, 0);
1243: let field_dest = adt::trans_field_ptr(bcx, &*repr, addr, 0, 0);
librustc/middle/trans/base.rs:
1544: let repr = adt::represent_type(ccx, result_ty);
1545: adt::trans_start_init(bcx, &*repr, fcx.llretptr.get().unwrap(), disr);
1546: for (i, arg_datum) in arg_datums.move_iter().enumerate() {
librustc/middle/trans/expr.rs:
798: let repr = adt::represent_type(bcx.ccx(), ty);
799: adt::trans_start_init(bcx, &*repr, lldest,
800: variant_info.disr_val);
librustc/middle/trans/adt.rs:844:1-844:1 -fn- definition:
fn padding(ccx: &CrateContext, size: u64) -> ValueRef {
C_undef(Type::array(&Type::i8(ccx), size))
}
references:- 3753: (vec!(lldiscr)).append(vals).as_slice());
754: C_struct(ccx, contents.append([padding(ccx, max_sz - case.size)]).as_slice(),
755: false)
--
828: if offset != target_offset {
829: cfields.push(padding(ccx, target_offset - offset));
830: offset = target_offset;
--
838: if offset != st.size {
839: cfields.push(padding(ccx, st.size - offset));
840: }
librustc/middle/trans/adt.rs:297:1-297:1 -fn- definition:
fn mk_struct(cx: &CrateContext, tys: &[ty::t], packed: bool) -> Struct {
let lltys = tys.iter().map(|&ty| type_of::sizing_type_of(cx, ty)).collect::<Vec<_>>();
let llty_rec = Type::struct_(cx, lltys.as_slice(), packed);
references:- 7152: return Univariant(mk_struct(cx, ftys.as_slice(), packed), dtor)
153: }
--
204: nndiscr: discr as u64,
205: nonnull: mk_struct(cx,
206: cases.get(discr)
--
269: fn is_zerolen(&self, cx: &CrateContext) -> bool {
270: mk_struct(cx, self.tys.as_slice(), false).size == 0
271: }
librustc/middle/trans/adt.rs:541:1-541:1 -fn- definition:
fn nullable_bitdiscr(bcx: &Block, nonnull: &Struct, nndiscr: Disr, ptrfield: uint,
scrutinee: ValueRef) -> ValueRef {
let cmp = if nndiscr == 0 { IntEQ } else { IntNE };
references:- 2501: NullablePointer{ nonnull: ref nonnull, nndiscr, ptrfield, .. } => {
502: (_match::switch, Some(nullable_bitdiscr(bcx, nonnull, nndiscr, ptrfield, scrutinee)))
503: }
--
531: NullablePointer{ nonnull: ref nonnull, nndiscr, ptrfield, .. } => {
532: val = nullable_bitdiscr(bcx, nonnull, nndiscr, ptrfield, scrutinee);
533: signed = false;
librustc/middle/trans/adt.rs:694:1-694:1 -fn- definition:
fn struct_field_ptr(bcx: &Block, st: &Struct, val: ValueRef, ix: uint,
needs_cast: bool) -> ValueRef {
let ccx = bcx.ccx();
references:- 3672: assert_eq!(discr, 0);
673: struct_field_ptr(bcx, st, val, ix, false)
674: }
675: General(_, ref cases) => {
676: struct_field_ptr(bcx, cases.get(discr as uint), val, ix + 1, true)
677: }
--
680: if discr == nndiscr {
681: struct_field_ptr(bcx, nonnull, val, ix, false)
682: } else {
librustc/middle/trans/adt.rs:363:1-363:1 -fn- definition:
pub fn ll_inttype(cx: &CrateContext, ity: IntType) -> Type {
match ity {
attr::SignedInt(t) => Type::int_from_ty(cx, t),
references:- 14586: General(ity, _) => {
587: _match::single_result(Result::new(bcx, C_integral(ll_inttype(bcx.ccx(), ity),
588: discr as u64, true)))
--
749: let max_sz = cases.iter().map(|x| x.size).max().unwrap();
750: let lldiscr = C_integral(ll_inttype(ccx, ity), discr as u64, true);
751: let contents = build_const_struct(ccx,
librustc/middle/trans/debuginfo.rs:
1577: None => {
1578: let discriminant_llvm_type = adt::ll_inttype(cx, inttype);
1579: let (discriminant_size, discriminant_align) =
librustc/middle/trans/adt.rs:
612: General(ity, _) => {
613: Store(bcx, C_integral(ll_inttype(bcx.ccx(), ity), discr as u64, true),
614: GEPi(bcx, val, [0, 0]))
librustc/middle/trans/adt.rs:494:4-494:4 -fn- definition:
*/
pub fn trans_switch(bcx: &Block, r: &Repr, scrutinee: ValueRef)
-> (_match::branch_kind, Option<ValueRef>) {
references:- 2librustc/middle/trans/base.rs:
722: match adt::trans_switch(cx, &*repr, av) {
723: (_match::single, None) => {
librustc/middle/trans/_match.rs:
1599: var(_, ref repr) => {
1600: let (the_kind, val_opt) = adt::trans_switch(bcx, &**repr, val);
1601: kind = the_kind;
librustc/middle/trans/adt.rs:898:72-898:72 -fn- definition:
/// Extract field of struct-like const, skipping our alignment padding.
fn const_struct_field(ccx: &CrateContext, val: ValueRef, ix: uint)
-> ValueRef {
references:- 4893: General(..) => const_struct_field(ccx, val, ix + 1),
894: NullablePointer{ .. } => const_struct_field(ccx, val, ix)
895: }
librustc/middle/trans/adt.rs:634:1-634:1 -fn- definition:
fn assert_discr_in_range(ity: IntType, min: Disr, max: Disr, discr: Disr) {
match ity {
attr::UnsignedInt(_) => assert!(min <= discr && discr <= max),
references:- 2743: assert_eq!(vals.len(), 0);
744: assert_discr_in_range(ity, min, max, discr);
745: C_integral(ll_inttype(ccx, ity), discr as u64, true)
librustc/middle/trans/adt.rs:107:60-107:60 -struct- definition:
/// For structs, and struct-like parts of anything fancier.
pub struct Struct {
pub size: u64,
references:- 11300: let llty_rec = Type::struct_(cx, lltys.as_slice(), packed);
301: Struct {
302: size: machine::llsize_of_alloc(cx, llty_rec) /*bad*/as u64,
--
785: */
786: fn compute_struct_field_offsets(ccx: &CrateContext, st: &Struct) -> Vec<u64> {
787: let mut offsets = vec!();
--
812: */
813: fn build_const_struct(ccx: &CrateContext, st: &Struct, vals: &[ValueRef])
814: -> Vec<ValueRef> {
librustc/middle/trans/debuginfo.rs:
1466: fn describe_enum_variant(cx: &CrateContext,
1467: struct_def: &adt::Struct,
1468: variant_info: &ty::VariantInfo,
librustc/middle/trans/adt.rs:
695: fn struct_field_ptr(bcx: &Block, st: &Struct, val: ValueRef, ix: uint,
696: needs_cast: bool) -> ValueRef {
librustc/middle/trans/adt.rs:550:62-550:62 -fn- definition:
/// Helper for cases where the discriminant is simply loaded.
fn load_discr(bcx: &Block, ity: IntType, ptr: ValueRef, min: Disr, max: Disr)
-> ValueRef {
references:- 2523: let ptr = GEPi(bcx, scrutinee, [0, 0]);
524: val = load_discr(bcx, ity, ptr, 0, (cases.len() - 1) as Disr);
525: signed = ity.is_signed();