(index<- )        ./librustc/middle/trans/adt.rs

    git branch:    * master           5200215 auto merge of #14035 : alexcrichton/rust/experimental, r=huonw
    modified:    Fri May  9 13:02:28 2014
   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, nodeast::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, tty::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, tty::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 discrsVec<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_idast::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_idast::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, hintHint, 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, hintHint, 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, ityIntType) -> 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, ityIntType, 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(ityIntType) -> 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, nameOption<&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, scrutineeValueRef)
 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, scrutineeValueRef, cast_toOption<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, nndiscrDisr, ptrfield: uint,
 543                       scrutineeValueRef) -> 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, ityIntType, ptrValueRef, minDisr, maxDisr)
 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, discrDisr)
 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, valValueRef, discrDisr) {
 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(ityIntType, minDisr, maxDisr, discrDisr) {
 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, discrDisr) -> 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, valValueRef, discrDisr,
 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, valValueRef, 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, valValueRef) -> 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, discrDisr,
 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, valValueRef)
 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, valValueRef,
 889                         _discrDisr, 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, valValueRef, 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:- 5
167:                 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:- 2
356:     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:- 5
librustc/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:- 2
librustc/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:- 3
librustc/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:- 2
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| {
--
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:- 25
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 {
--
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:- 4
750:             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:- 2
793:             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:- 3
411: 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:- 2
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)
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:- 2
324: 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:- 2
librustc/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:- 2
librustc/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:- 3
292:         }).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:- 4
librustc/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:- 2
428:                 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:- 34
librustc/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:- 3
498:         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:- 18
librustc/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:- 5
librustc/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:- 3
753:                                               (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:- 7
152:             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:- 2
501:         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:- 3
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:         }
--
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:- 14
586:         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:- 2
librustc/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:- 4
893:         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:- 2
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)


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:- 11
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,
--
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:- 2
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();