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

    git branch:    * master           5200215 auto merge of #14035 : alexcrichton/rust/experimental, r=huonw
    modified:    Fri May  9 13:02:28 2014
   1  // Copyright 2012 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  use back::abi;
  13  use lib::llvm::{llvm, ConstFCmp, ConstICmp, SetLinkage, PrivateLinkage, ValueRef, Bool, True,
  14      False};
  15  use lib::llvm::{IntEQ, IntNE, IntUGT, IntUGE, IntULT, IntULE, IntSGT, IntSGE, IntSLT, IntSLE,
  16      RealOEQ, RealOGT, RealOGE, RealOLT, RealOLE, RealONE};
  17  
  18  use metadata::csearch;
  19  use middle::const_eval;
  20  use middle::trans::adt;
  21  use middle::trans::base;
  22  use middle::trans::base::push_ctxt;
  23  use middle::trans::closure;
  24  use middle::trans::common::*;
  25  use middle::trans::consts;
  26  use middle::trans::expr;
  27  use middle::trans::inline;
  28  use middle::trans::machine;
  29  use middle::trans::type_::Type;
  30  use middle::trans::type_of;
  31  use middle::trans::debuginfo;
  32  use middle::ty;
  33  use util::ppaux::{Repr, ty_to_str};
  34  
  35  use std::c_str::ToCStr;
  36  use std::vec;
  37  use std::vec::Vec;
  38  use libc::c_uint;
  39  use syntax::{ast, ast_util};
  40  
  41  pub fn const_lit(cx: &CrateContext, e: &ast::Expr, litast::Lit)
  42      -> ValueRef {
  43      let _icx = push_ctxt("trans_lit");
  44      match lit.node {
  45          ast::LitChar(i) => C_integral(Type::char(cx), i as u64, false),
  46          ast::LitInt(i, t) => C_integral(Type::int_from_ty(cx, t), i as u64, true),
  47          ast::LitUint(u, t) => C_integral(Type::uint_from_ty(cx, t), u, false),
  48          ast::LitIntUnsuffixed(i) => {
  49              let lit_int_ty = ty::node_id_to_type(cx.tcx(), e.id);
  50              match ty::get(lit_int_ty).sty {
  51                  ty::ty_int(t) => {
  52                      C_integral(Type::int_from_ty(cx, t), i as u64, true)
  53                  }
  54                  ty::ty_uint(t) => {
  55                      C_integral(Type::uint_from_ty(cx, t), i as u64, false)
  56                  }
  57                  _ => cx.sess().span_bug(lit.span,
  58                          format!("integer literal has type {} (expected int or uint)",
  59                                  ty_to_str(cx.tcx(), lit_int_ty)))
  60              }
  61          }
  62          ast::LitFloat(ref fs, t) => {
  63              C_floating(fs.get(), Type::float_from_ty(cx, t))
  64          }
  65          ast::LitFloatUnsuffixed(ref fs) => {
  66              let lit_float_ty = ty::node_id_to_type(cx.tcx(), e.id);
  67              match ty::get(lit_float_ty).sty {
  68                  ty::ty_float(t) => {
  69                      C_floating(fs.get(), Type::float_from_ty(cx, t))
  70                  }
  71                  _ => {
  72                      cx.sess().span_bug(lit.span,
  73                          "floating point literal doesn't have the right type");
  74                  }
  75              }
  76          }
  77          ast::LitBool(b) => C_bool(cx, b),
  78          ast::LitNil => C_nil(cx),
  79          ast::LitStr(ref s, _) => C_str_slice(cx, (*s).clone()),
  80          ast::LitBinary(ref data) => C_binary_slice(cx, data.as_slice()),
  81      }
  82  }
  83  
  84  pub fn const_ptrcast(cx: &CrateContext, aValueRef, tType) -> ValueRef {
  85      unsafe {
  86          let b = llvm::LLVMConstPointerCast(a, t.ptr_to().to_ref());
  87          assert!(cx.const_globals.borrow_mut().insert(b as int, a));
  88          b
  89      }
  90  }
  91  
  92  fn const_vec(cx: &CrateContext, e: &ast::Expr,
  93               es: &[@ast::Expr], is_local: bool) -> (ValueRef, Type, bool) {
  94      let vec_ty = ty::expr_ty(cx.tcx(), e);
  95      let unit_ty = ty::sequence_element_type(cx.tcx(), vec_ty);
  96      let llunitty = type_of::type_of(cx, unit_ty);
  97      let (vs, inlineable) = vec::unzip(es.iter().map(|e| const_expr(cx, *e, is_local)));
  98      // If the vector contains enums, an LLVM array won't work.
  99      let v = if vs.iter().any(|vi| val_ty(*vi) != llunitty) {
 100          C_struct(cx, vs.as_slice(), false)
 101      } else {
 102          C_array(llunitty, vs.as_slice())
 103      };
 104      (v, llunitty, inlineable.iter().fold(true, |a, &b| a && b))
 105  }
 106  
 107  fn const_addr_of(cx: &CrateContext, cvValueRef) -> ValueRef {
 108      unsafe {
 109          let gv = "const".with_c_str(|name| {
 110              llvm::LLVMAddGlobal(cx.llmod, val_ty(cv).to_ref(), name)
 111          });
 112          llvm::LLVMSetInitializer(gv, cv);
 113          llvm::LLVMSetGlobalConstant(gv, True);
 114          SetLinkage(gv, PrivateLinkage);
 115          gv
 116      }
 117  }
 118  
 119  fn const_deref_ptr(cx: &CrateContext, vValueRef) -> ValueRef {
 120      let v = match cx.const_globals.borrow().find(&(v as int)) {
 121          Some(&v) => v,
 122          None => v
 123      };
 124      unsafe {
 125          assert_eq!(llvm::LLVMIsGlobalConstant(v), True);
 126          llvm::LLVMGetInitializer(v)
 127      }
 128  }
 129  
 130  fn const_deref_newtype(cx: &CrateContext, vValueRef, tty::t)
 131      -> ValueRef {
 132      let repr = adt::represent_type(cx, t);
 133      adt::const_get_field(cx, &*repr, v, 0, 0)
 134  }
 135  
 136  fn const_deref(cx: &CrateContext, vValueRef, tty::t, explicit: bool)
 137      -> (ValueRef, ty::t) {
 138      match ty::deref(t, explicit) {
 139          Some(ref mt) => {
 140              assert!(mt.mutbl != ast::MutMutable);
 141              let dv = match ty::get(t).sty {
 142                  ty::ty_ptr(mt) | ty::ty_rptr(_, mt) => {
 143                      match ty::get(mt.ty).sty {
 144                          ty::ty_vec(_, None) | ty::ty_str => cx.sess().bug("unexpected slice"),
 145                          _ => const_deref_ptr(cx, v),
 146                      }
 147                  }
 148                  ty::ty_enum(..) | ty::ty_struct(..) => {
 149                      const_deref_newtype(cx, v, t)
 150                  }
 151                  _ => {
 152                      cx.sess().bug(format!("unexpected dereferenceable type {}",
 153                                            ty_to_str(cx.tcx(), t)))
 154                  }
 155              };
 156              (dv, mt.ty)
 157          }
 158          None => {
 159              cx.sess().bug(format!("can't dereference const of type {}",
 160                                    ty_to_str(cx.tcx(), t)))
 161          }
 162      }
 163  }
 164  
 165  pub fn get_const_val(cx: &CrateContext,
 166                       mut def_idast::DefId) -> (ValueRef, bool) {
 167      let contains_key = cx.const_values.borrow().contains_key(&def_id.node);
 168      if !ast_util::is_local(def_id) || !contains_key {
 169          if !ast_util::is_local(def_id) {
 170              def_id = inline::maybe_instantiate_inline(cx, def_id);
 171          }
 172  
 173          match cx.tcx.map.expect_item(def_id.node).node {
 174              ast::ItemStatic(_, ast::MutImmutable, _) => {
 175                  trans_const(cx, ast::MutImmutable, def_id.node);
 176              }
 177              _ => {}
 178          }
 179      }
 180  
 181      (cx.const_values.borrow().get_copy(&def_id.node),
 182       !cx.non_inlineable_statics.borrow().contains(&def_id.node))
 183  }
 184  
 185  pub fn const_expr(cx: &CrateContext, e: &ast::Expr, is_local: bool) -> (ValueRef, bool) {
 186      let (llconst, inlineable) = const_expr_unadjusted(cx, e, is_local);
 187      let mut llconst = llconst;
 188      let mut inlineable = inlineable;
 189      let ety = ty::expr_ty(cx.tcx(), e);
 190      let ety_adjusted = ty::expr_ty_adjusted(cx.tcx(), e);
 191      let opt_adj = cx.tcx.adjustments.borrow().find_copy(&e.id);
 192      match opt_adj {
 193          None => { }
 194          Some(adj) => {
 195              match adj {
 196                  ty::AutoAddEnv(ty::RegionTraitStore(ty::ReStatic, _)) => {
 197                      let def = ty::resolve_expr(cx.tcx(), e);
 198                      let wrapper = closure::get_wrapper_for_bare_fn(cx,
 199                                                                     ety_adjusted,
 200                                                                     def,
 201                                                                     llconst,
 202                                                                     is_local);
 203                      llconst = C_struct(cx, [wrapper, C_null(Type::i8p(cx))], false)
 204                  }
 205                  ty::AutoAddEnv(store) => {
 206                      cx.sess()
 207                        .span_bug(e.span,
 208                                  format!("unexpected static function: {:?}",
 209                                          store))
 210                  }
 211                  ty::AutoObject(..) => {
 212                      cx.sess()
 213                        .span_unimpl(e.span,
 214                                     "unimplemented const coercion to trait \
 215                                      object");
 216                  }
 217                  ty::AutoDerefRef(ref adj) => {
 218                      let mut ty = ety;
 219                      let mut maybe_ptr = None;
 220                      for _ in range(0, adj.autoderefs) {
 221                          let (dv, dt) = const_deref(cx, llconst, ty, false);
 222                          maybe_ptr = Some(llconst);
 223                          llconst = dv;
 224                          ty = dt;
 225                      }
 226  
 227                      match adj.autoref {
 228                          None => { }
 229                          Some(ref autoref) => {
 230                              // Don't copy data to do a deref+ref.
 231                              let llptr = match maybe_ptr {
 232                                  Some(ptr) => ptr,
 233                                  None => {
 234                                      inlineable = false;
 235                                      const_addr_of(cx, llconst)
 236                                  }
 237                              };
 238                              match *autoref {
 239                                  ty::AutoUnsafe(m) |
 240                                  ty::AutoPtr(ty::ReStatic, m) => {
 241                                      assert!(m != ast::MutMutable);
 242                                      llconst = llptr;
 243                                  }
 244                                  ty::AutoBorrowVec(ty::ReStatic, m) => {
 245                                      assert!(m != ast::MutMutable);
 246                                      assert_eq!(abi::slice_elt_base, 0);
 247                                      assert_eq!(abi::slice_elt_len, 1);
 248                                      match ty::get(ty).sty {
 249                                          ty::ty_vec(_, Some(len)) => {
 250                                              llconst = C_struct(cx, [
 251                                                  llptr,
 252                                                  C_uint(cx, len)
 253                                              ], false);
 254                                          }
 255                                          _ => {}
 256                                      }
 257                                  }
 258                                  _ => {
 259                                      cx.sess().span_bug(e.span,
 260                                                         format!("unimplemented \
 261                                                                  const autoref \
 262                                                                  {:?}",
 263                                                                 autoref))
 264                                  }
 265                              }
 266                          }
 267                      }
 268                  }
 269              }
 270          }
 271      }
 272  
 273      let llty = type_of::sizing_type_of(cx, ety_adjusted);
 274      let csize = machine::llsize_of_alloc(cx, val_ty(llconst));
 275      let tsize = machine::llsize_of_alloc(cx, llty);
 276      if csize != tsize {
 277          unsafe {
 278              // FIXME these values could use some context
 279              llvm::LLVMDumpValue(llconst);
 280              llvm::LLVMDumpValue(C_undef(llty));
 281          }
 282          cx.sess().bug(format!("const {} of type {} has size {} instead of {}",
 283                           e.repr(cx.tcx()), ty_to_str(cx.tcx(), ety),
 284                           csize, tsize));
 285      }
 286      (llconst, inlineable)
 287  }
 288  
 289  // the bool returned is whether this expression can be inlined into other crates
 290  // if it's assigned to a static.
 291  fn const_expr_unadjusted(cx: &CrateContext, e: &ast::Expr,
 292                           is_local: bool) -> (ValueRef, bool) {
 293      let map_list = |exprs&[@ast::Expr]{
 294          exprs.iter().map(|&e| const_expr(cx, e, is_local))
 295               .fold((Vec::new(), true),
 296                     |(l, all_inlineable), (val, inlineable)| {
 297                  (l.append_one(val), all_inlineable && inlineable)
 298               })
 299      };
 300      unsafe {
 301          let _icx = push_ctxt("const_expr");
 302          return match e.node {
 303            ast::ExprLit(lit) => {
 304                (consts::const_lit(cx, e, (*lit).clone()), true)
 305            }
 306            ast::ExprBinary(b, e1, e2) => {
 307              let (te1, _) = const_expr(cx, e1, is_local);
 308              let (te2, _) = const_expr(cx, e2, is_local);
 309  
 310              let te2 = base::cast_shift_const_rhs(b, te1, te2);
 311  
 312              /* Neither type is bottom, and we expect them to be unified
 313               * already, so the following is safe. */
 314              let ty = ty::expr_ty(cx.tcx(), e1);
 315              let is_float = ty::type_is_fp(ty);
 316              let signed = ty::type_is_signed(ty);
 317              return (match b {
 318                ast::BiAdd   => {
 319                  if is_float { llvm::LLVMConstFAdd(te1, te2) }
 320                  else        { llvm::LLVMConstAdd(te1, te2) }
 321                }
 322                ast::BiSub => {
 323                  if is_float { llvm::LLVMConstFSub(te1, te2) }
 324                  else        { llvm::LLVMConstSub(te1, te2) }
 325                }
 326                ast::BiMul    => {
 327                  if is_float { llvm::LLVMConstFMul(te1, te2) }
 328                  else        { llvm::LLVMConstMul(te1, te2) }
 329                }
 330                ast::BiDiv    => {
 331                  if is_float    { llvm::LLVMConstFDiv(te1, te2) }
 332                  else if signed { llvm::LLVMConstSDiv(te1, te2) }
 333                  else           { llvm::LLVMConstUDiv(te1, te2) }
 334                }
 335                ast::BiRem    => {
 336                  if is_float    { llvm::LLVMConstFRem(te1, te2) }
 337                  else if signed { llvm::LLVMConstSRem(te1, te2) }
 338                  else           { llvm::LLVMConstURem(te1, te2) }
 339                }
 340                ast::BiAnd    => llvm::LLVMConstAnd(te1, te2),
 341                ast::BiOr     => llvm::LLVMConstOr(te1, te2),
 342                ast::BiBitXor => llvm::LLVMConstXor(te1, te2),
 343                ast::BiBitAnd => llvm::LLVMConstAnd(te1, te2),
 344                ast::BiBitOr  => llvm::LLVMConstOr(te1, te2),
 345                ast::BiShl    => llvm::LLVMConstShl(te1, te2),
 346                ast::BiShr    => {
 347                  if signed { llvm::LLVMConstAShr(te1, te2) }
 348                  else      { llvm::LLVMConstLShr(te1, te2) }
 349                }
 350                ast::BiEq     => {
 351                    if is_float { ConstFCmp(RealOEQ, te1, te2) }
 352                    else        { ConstICmp(IntEQ, te1, te2)   }
 353                },
 354                ast::BiLt     => {
 355                    if is_float { ConstFCmp(RealOLT, te1, te2) }
 356                    else        {
 357                        if signed { ConstICmp(IntSLT, te1, te2) }
 358                        else      { ConstICmp(IntULT, te1, te2) }
 359                    }
 360                },
 361                ast::BiLe     => {
 362                    if is_float { ConstFCmp(RealOLE, te1, te2) }
 363                    else        {
 364                        if signed { ConstICmp(IntSLE, te1, te2) }
 365                        else      { ConstICmp(IntULE, te1, te2) }
 366                    }
 367                },
 368                ast::BiNe     => {
 369                    if is_float { ConstFCmp(RealONE, te1, te2) }
 370                    else        { ConstICmp(IntNE, te1, te2) }
 371                },
 372                ast::BiGe     => {
 373                    if is_float { ConstFCmp(RealOGE, te1, te2) }
 374                    else        {
 375                        if signed { ConstICmp(IntSGE, te1, te2) }
 376                        else      { ConstICmp(IntUGE, te1, te2) }
 377                    }
 378                },
 379                ast::BiGt     => {
 380                    if is_float { ConstFCmp(RealOGT, te1, te2) }
 381                    else        {
 382                        if signed { ConstICmp(IntSGT, te1, te2) }
 383                        else      { ConstICmp(IntUGT, te1, te2) }
 384                    }
 385                },
 386              }, true)
 387            },
 388            ast::ExprUnary(u, e) => {
 389              let (te, _) = const_expr(cx, e, is_local);
 390              let ty = ty::expr_ty(cx.tcx(), e);
 391              let is_float = ty::type_is_fp(ty);
 392              return (match u {
 393                ast::UnBox | ast::UnUniq | ast::UnDeref => {
 394                  let (dv, _dt) = const_deref(cx, te, ty, true);
 395                  dv
 396                }
 397                ast::UnNot    => {
 398                  match ty::get(ty).sty {
 399                      ty::ty_bool => {
 400                          // Somewhat questionable, but I believe this is
 401                          // correct.
 402                          let te = llvm::LLVMConstTrunc(te, Type::i1(cx).to_ref());
 403                          let te = llvm::LLVMConstNot(te);
 404                          llvm::LLVMConstZExt(te, Type::bool(cx).to_ref())
 405                      }
 406                      _ => llvm::LLVMConstNot(te),
 407                  }
 408                }
 409                ast::UnNeg    => {
 410                  if is_float { llvm::LLVMConstFNeg(te) }
 411                  else        { llvm::LLVMConstNeg(te) }
 412                }
 413              }, true)
 414            }
 415            ast::ExprField(base, field, _) => {
 416                let bt = ty::expr_ty_adjusted(cx.tcx(), base);
 417                let brepr = adt::represent_type(cx, bt);
 418                let (bv, inlineable) = const_expr(cx, base, is_local);
 419                expr::with_field_tys(cx.tcx(), bt, None, |discr, field_tys| {
 420                    let ix = ty::field_idx_strict(cx.tcx(), field.name, field_tys);
 421                    (adt::const_get_field(cx, &*brepr, bv, discr, ix), inlineable)
 422                })
 423            }
 424  
 425            ast::ExprIndex(base, index) => {
 426                let bt = ty::expr_ty_adjusted(cx.tcx(), base);
 427                let (bv, inlineable) = const_expr(cx, base, is_local);
 428                let iv = match const_eval::eval_const_expr(cx.tcx(), index) {
 429                    const_eval::const_int(i) => i as u64,
 430                    const_eval::const_uint(u) => u,
 431                    _ => cx.sess().span_bug(index.span,
 432                                            "index is not an integer-constant expression")
 433                };
 434                let (arr, len) = match ty::get(bt).sty {
 435                    ty::ty_vec(_, Some(u)) => (bv, C_uint(cx, u)),
 436                    ty::ty_rptr(_, mt) => match ty::get(mt.ty).sty {
 437                        ty::ty_vec(_, None) | ty::ty_str => {
 438                            let e1 = const_get_elt(cx, bv, [0]);
 439                            (const_deref_ptr(cx, e1), const_get_elt(cx, bv, [1]))
 440                        },
 441                        _ => cx.sess().span_bug(base.span,
 442                                                "index-expr base must be a vector or string type")
 443                    },
 444                    _ => cx.sess().span_bug(base.span,
 445                                            "index-expr base must be a vector or string type")
 446                };
 447  
 448                let len = llvm::LLVMConstIntGetZExtValue(len) as u64;
 449                let len = match ty::get(bt).sty {
 450                    ty::ty_uniq(ty) | ty::ty_rptr(_, ty::mt{ty, ..}) => match ty::get(ty).sty {
 451                        ty::ty_str => {
 452                            assert!(len > 0);
 453                            len - 1
 454                        }
 455                        _ => len
 456                    },
 457                    _ => len
 458                };
 459                if iv >= len {
 460                    // FIXME #3170: report this earlier on in the const-eval
 461                    // pass. Reporting here is a bit late.
 462                    cx.sess().span_err(e.span,
 463                                       "const index-expr is out of bounds");
 464                }
 465                (const_get_elt(cx, arr, [iv as c_uint]), inlineable)
 466            }
 467            ast::ExprCast(base, _) => {
 468              let ety = ty::expr_ty(cx.tcx(), e);
 469              let llty = type_of::type_of(cx, ety);
 470              let basety = ty::expr_ty(cx.tcx(), base);
 471              let (v, inlineable) = const_expr(cx, base, is_local);
 472              return (match (expr::cast_type_kind(basety),
 473                             expr::cast_type_kind(ety)) {
 474  
 475                (expr::cast_integral, expr::cast_integral) => {
 476                  let s = ty::type_is_signed(basety) as Bool;
 477                  llvm::LLVMConstIntCast(v, llty.to_ref(), s)
 478                }
 479                (expr::cast_integral, expr::cast_float) => {
 480                  if ty::type_is_signed(basety) {
 481                      llvm::LLVMConstSIToFP(v, llty.to_ref())
 482                  } else {
 483                      llvm::LLVMConstUIToFP(v, llty.to_ref())
 484                  }
 485                }
 486                (expr::cast_float, expr::cast_float) => {
 487                  llvm::LLVMConstFPCast(v, llty.to_ref())
 488                }
 489                (expr::cast_float, expr::cast_integral) => {
 490                  if ty::type_is_signed(ety) { llvm::LLVMConstFPToSI(v, llty.to_ref()) }
 491                  else { llvm::LLVMConstFPToUI(v, llty.to_ref()) }
 492                }
 493                (expr::cast_enum, expr::cast_integral) |
 494                (expr::cast_enum, expr::cast_float)  => {
 495                  let repr = adt::represent_type(cx, basety);
 496                  let discr = adt::const_get_discrim(cx, &*repr, v);
 497                  let iv = C_integral(cx.int_type, discr, false);
 498                  let ety_cast = expr::cast_type_kind(ety);
 499                  match ety_cast {
 500                      expr::cast_integral => {
 501                          let s = ty::type_is_signed(ety) as Bool;
 502                          llvm::LLVMConstIntCast(iv, llty.to_ref(), s)
 503                      }
 504                      expr::cast_float => llvm::LLVMConstUIToFP(iv, llty.to_ref()),
 505                      _ => cx.sess().bug("enum cast destination is not \
 506                                          integral or float")
 507                  }
 508                }
 509                (expr::cast_pointer, expr::cast_pointer) => {
 510                  llvm::LLVMConstPointerCast(v, llty.to_ref())
 511                }
 512                (expr::cast_integral, expr::cast_pointer) => {
 513                  llvm::LLVMConstIntToPtr(v, llty.to_ref())
 514                }
 515                _ => {
 516                  cx.sess().impossible_case(e.span,
 517                                            "bad combination of types for cast")
 518                }
 519              }, inlineable)
 520            }
 521            ast::ExprAddrOf(ast::MutImmutable, sub) => {
 522                let (e, _) = const_expr(cx, sub, is_local);
 523                (const_addr_of(cx, e), false)
 524            }
 525            ast::ExprTup(ref es) => {
 526                let ety = ty::expr_ty(cx.tcx(), e);
 527                let repr = adt::represent_type(cx, ety);
 528                let (vals, inlineable) = map_list(es.as_slice());
 529                (adt::trans_const(cx, &*repr, 0, vals.as_slice()), inlineable)
 530            }
 531            ast::ExprStruct(_, ref fs, ref base_opt) => {
 532                let ety = ty::expr_ty(cx.tcx(), e);
 533                let repr = adt::represent_type(cx, ety);
 534                let tcx = cx.tcx();
 535  
 536                let base_val = match *base_opt {
 537                  Some(base) => Some(const_expr(cx, base, is_local)),
 538                  None => None
 539                };
 540  
 541                expr::with_field_tys(tcx, ety, Some(e.id), |discr, field_tys| {
 542                    let (cs, inlineable) = vec::unzip(field_tys.iter().enumerate()
 543                        .map(|(ix, &field_ty)| {
 544                        match fs.iter().find(|f| field_ty.ident.name == f.ident.node.name) {
 545                            Some(f) => const_expr(cx, (*f).expr, is_local),
 546                            None => {
 547                                match base_val {
 548                                  Some((bv, inlineable)) => {
 549                                      (adt::const_get_field(cx, &*repr, bv, discr, ix),
 550                                       inlineable)
 551                                  }
 552                                  None => cx.sess().span_bug(e.span, "missing struct field")
 553                                }
 554                            }
 555                        }
 556                    }));
 557                    (adt::trans_const(cx, &*repr, discr, cs.as_slice()),
 558                     inlineable.iter().fold(true, |a, &b| a && b))
 559                })
 560            }
 561            ast::ExprVec(ref es) => {
 562              let (v, _, inlineable) = const_vec(cx,
 563                                                 e,
 564                                                 es.as_slice(),
 565                                                 is_local);
 566              (v, inlineable)
 567            }
 568            ast::ExprVstore(sub, store @ ast::ExprVstoreSlice) |
 569            ast::ExprVstore(sub, store @ ast::ExprVstoreMutSlice) => {
 570              match sub.node {
 571                ast::ExprLit(ref lit) => {
 572                  match lit.node {
 573                      ast::LitStr(..) => { const_expr(cx, sub, is_local) }
 574                      _ => { cx.sess().span_bug(e.span, "bad const-slice lit") }
 575                  }
 576                }
 577                ast::ExprVec(ref es) => {
 578                  let (cv, llunitty, _) = const_vec(cx,
 579                                                    e,
 580                                                    es.as_slice(),
 581                                                    is_local);
 582                  let llty = val_ty(cv);
 583                  let gv = "const".with_c_str(|name| {
 584                      llvm::LLVMAddGlobal(cx.llmod, llty.to_ref(), name)
 585                  });
 586                  llvm::LLVMSetInitializer(gv, cv);
 587                  llvm::LLVMSetGlobalConstant(gv,
 588                        if store == ast::ExprVstoreMutSlice { False } else { True });
 589                  SetLinkage(gv, PrivateLinkage);
 590                  let p = const_ptrcast(cx, gv, llunitty);
 591                  (C_struct(cx, [p, C_uint(cx, es.len())], false), false)
 592                }
 593                _ => cx.sess().span_bug(e.span, "bad const-slice expr")
 594              }
 595            }
 596            ast::ExprRepeat(elem, count) => {
 597              let vec_ty = ty::expr_ty(cx.tcx(), e);
 598              let unit_ty = ty::sequence_element_type(cx.tcx(), vec_ty);
 599              let llunitty = type_of::type_of(cx, unit_ty);
 600              let n = match const_eval::eval_const_expr(cx.tcx(), count) {
 601                  const_eval::const_int(i)  => i as uint,
 602                  const_eval::const_uint(i) => i as uint,
 603                  _ => cx.sess().span_bug(count.span, "count must be integral const expression.")
 604              };
 605              let vs = Vec::from_elem(n, const_expr(cx, elem, is_local).val0());
 606              let v = if vs.iter().any(|vi| val_ty(*vi) != llunitty) {
 607                  C_struct(cx, vs.as_slice(), false)
 608              } else {
 609                  C_array(llunitty, vs.as_slice())
 610              };
 611              (v, true)
 612            }
 613            ast::ExprPath(ref pth) => {
 614              // Assert that there are no type parameters in this path.
 615              assert!(pth.segments.iter().all(|seg| seg.types.is_empty()));
 616  
 617              let opt_def = cx.tcx().def_map.borrow().find_copy(&e.id);
 618              match opt_def {
 619                  Some(ast::DefFn(def_id, _fn_style)) => {
 620                      if !ast_util::is_local(def_id) {
 621                          let ty = csearch::get_type(cx.tcx(), def_id).ty;
 622                          (base::trans_external_path(cx, def_id, ty), true)
 623                      } else {
 624                          assert!(ast_util::is_local(def_id));
 625                          (base::get_item_val(cx, def_id.node), true)
 626                      }
 627                  }
 628                  Some(ast::DefStatic(def_id, false)) => {
 629                      get_const_val(cx, def_id)
 630                  }
 631                  Some(ast::DefVariant(enum_did, variant_did, _)) => {
 632                      let ety = ty::expr_ty(cx.tcx(), e);
 633                      let repr = adt::represent_type(cx, ety);
 634                      let vinfo = ty::enum_variant_with_id(cx.tcx(),
 635                                                           enum_did,
 636                                                           variant_did);
 637                      (adt::trans_const(cx, &*repr, vinfo.disr_val, []), true)
 638                  }
 639                  Some(ast::DefStruct(_)) => {
 640                      let ety = ty::expr_ty(cx.tcx(), e);
 641                      let llty = type_of::type_of(cx, ety);
 642                      (C_null(llty), true)
 643                  }
 644                  _ => {
 645                      cx.sess().span_bug(e.span, "expected a const, fn, struct, or variant def")
 646                  }
 647              }
 648            }
 649            ast::ExprCall(callee, ref args) => {
 650                let opt_def = cx.tcx().def_map.borrow().find_copy(&callee.id);
 651                match opt_def {
 652                    Some(ast::DefStruct(_)) => {
 653                        let ety = ty::expr_ty(cx.tcx(), e);
 654                        let repr = adt::represent_type(cx, ety);
 655                        let (arg_vals, inlineable) = map_list(args.as_slice());
 656                        (adt::trans_const(cx, &*repr, 0, arg_vals.as_slice()),
 657                         inlineable)
 658                    }
 659                    Some(ast::DefVariant(enum_did, variant_did, _)) => {
 660                        let ety = ty::expr_ty(cx.tcx(), e);
 661                        let repr = adt::represent_type(cx, ety);
 662                        let vinfo = ty::enum_variant_with_id(cx.tcx(),
 663                                                             enum_did,
 664                                                             variant_did);
 665                        let (arg_vals, inlineable) = map_list(args.as_slice());
 666                        (adt::trans_const(cx,
 667                                          &*repr,
 668                                          vinfo.disr_val,
 669                                          arg_vals.as_slice()), inlineable)
 670                    }
 671                    _ => cx.sess().span_bug(e.span, "expected a struct or variant def")
 672                }
 673            }
 674            ast::ExprParen(e) => { const_expr(cx, e, is_local) }
 675            _ => cx.sess().span_bug(e.span,
 676                    "bad constant expression type in consts::const_expr")
 677          };
 678      }
 679  }
 680  
 681  pub fn trans_const(ccx: &CrateContext, mast::Mutability, idast::NodeId) {
 682      unsafe {
 683          let _icx = push_ctxt("trans_const");
 684          let g = base::get_item_val(ccx, id);
 685          // At this point, get_item_val has already translated the
 686          // constant's initializer to determine its LLVM type.
 687          let v = ccx.const_values.borrow().get_copy(&id);
 688          llvm::LLVMSetInitializer(g, v);
 689          if m != ast::MutMutable {
 690              llvm::LLVMSetGlobalConstant(g, True);
 691          }
 692          debuginfo::create_global_var_metadata(ccx, id, g);
 693      }
 694  }


librustc/middle/trans/consts.rs:184:1-184:1 -fn- definition:
pub fn const_expr(cx: &CrateContext, e: &ast::Expr, is_local: bool) -> (ValueRef, bool) {
    let (llconst, inlineable) = const_expr_unadjusted(cx, e, is_local);
    let mut llconst = llconst;
references:- 17
544:                       match fs.iter().find(|f| field_ty.ident.name == f.ident.node.name) {
545:                           Some(f) => const_expr(cx, (*f).expr, is_local),
546:                           None => {
--
604:             };
605:             let vs = Vec::from_elem(n, const_expr(cx, elem, is_local).val0());
606:             let v = if vs.iter().any(|vi| val_ty(*vi) != llunitty) {
--
673:           }
674:           ast::ExprParen(e) => { const_expr(cx, e, is_local) }
675:           _ => cx.sess().span_bug(e.span,
librustc/middle/trans/base.rs:
1880:                     // LLVM type is not fully determined by the Rust type.
1881:                     let (v, inlineable) = consts::const_expr(ccx, expr, is_local);
1882:                     ccx.const_values.borrow_mut().insert(id, v);
librustc/middle/trans/_match.rs:
321:         range(l1, l2) => {
322:             let (l1, _) = consts::const_expr(ccx, l1, true);
323:             let (l2, _) = consts::const_expr(ccx, l2, true);
324:             return range_result(Result::new(bcx, l1), Result::new(bcx, l2));
librustc/middle/trans/consts.rs:
388:           ast::ExprUnary(u, e) => {
389:             let (te, _) = const_expr(cx, e, is_local);
390:             let ty = ty::expr_ty(cx.tcx(), e);


librustc/middle/trans/consts.rs:91:1-91:1 -fn- definition:
fn const_vec(cx: &CrateContext, e: &ast::Expr,
             es: &[@ast::Expr], is_local: bool) -> (ValueRef, Type, bool) {
    let vec_ty = ty::expr_ty(cx.tcx(), e);
references:- 2
577:               ast::ExprVec(ref es) => {
578:                 let (cv, llunitty, _) = const_vec(cx,
579:                                                   e,


librustc/middle/trans/consts.rs:118:1-118:1 -fn- definition:
fn const_deref_ptr(cx: &CrateContext, v: ValueRef) -> ValueRef {
    let v = match cx.const_globals.borrow().find(&(v as int)) {
        Some(&v) => v,
references:- 2
144:                         ty::ty_vec(_, None) | ty::ty_str => cx.sess().bug("unexpected slice"),
145:                         _ => const_deref_ptr(cx, v),
146:                     }
--
438:                           let e1 = const_get_elt(cx, bv, [0]);
439:                           (const_deref_ptr(cx, e1), const_get_elt(cx, bv, [1]))
440:                       },


librustc/middle/trans/consts.rs:680:1-680:1 -fn- definition:
pub fn trans_const(ccx: &CrateContext, m: ast::Mutability, id: ast::NodeId) {
    unsafe {
        let _icx = push_ctxt("trans_const");
references:- 2
174:             ast::ItemStatic(_, ast::MutImmutable, _) => {
175:                 trans_const(cx, ast::MutImmutable, def_id.node);
176:             }
librustc/middle/trans/base.rs:
1629:       ast::ItemStatic(_, m, expr) => {
1630:           consts::trans_const(ccx, m, item.id);
1631:           // Do static_assert checking. It can't really be done much earlier


librustc/middle/trans/consts.rs:106:1-106:1 -fn- definition:
fn const_addr_of(cx: &CrateContext, cv: ValueRef) -> ValueRef {
    unsafe {
        let gv = "const".with_c_str(|name| {
references:- 2
522:               let (e, _) = const_expr(cx, sub, is_local);
523:               (const_addr_of(cx, e), false)
524:           }


librustc/middle/trans/consts.rs:135:1-135:1 -fn- definition:
fn const_deref(cx: &CrateContext, v: ValueRef, t: ty::t, explicit: bool)
    -> (ValueRef, ty::t) {
    match ty::deref(t, explicit) {
references:- 2
220:                     for _ in range(0, adj.autoderefs) {
221:                         let (dv, dt) = const_deref(cx, llconst, ty, false);
222:                         maybe_ptr = Some(llconst);
--
393:               ast::UnBox | ast::UnUniq | ast::UnDeref => {
394:                 let (dv, _dt) = const_deref(cx, te, ty, true);
395:                 dv


librustc/middle/trans/consts.rs:40:1-40:1 -fn- definition:
pub fn const_lit(cx: &CrateContext, e: &ast::Expr, lit: ast::Lit)
    -> ValueRef {
    let _icx = push_ctxt("trans_lit");
references:- 2
303:           ast::ExprLit(lit) => {
304:               (consts::const_lit(cx, e, (*lit).clone()), true)
305:           }
librustc/middle/trans/expr.rs:
1098:     let ty = expr_ty(bcx, expr);
1099:     let v = consts::const_lit(bcx.ccx(), expr, lit);
1100:     immediate_rvalue_bcx(bcx, v, ty).to_expr_datumblock()


librustc/middle/trans/consts.rs:164:1-164:1 -fn- definition:
pub fn get_const_val(cx: &CrateContext,
                     mut def_id: ast::DefId) -> (ValueRef, bool) {
    let contains_key = cx.const_values.borrow().contains_key(&def_id.node);
references:- 2
librustc/middle/trans/_match.rs:
314:         lit(ConstLit(lit_id)) => {
315:             let (llval, _) = consts::get_const_val(bcx.ccx(), lit_id);
316:             return single_result(Result::new(bcx, llval));
librustc/middle/trans/consts.rs:
628:                 Some(ast::DefStatic(def_id, false)) => {
629:                     get_const_val(cx, def_id)
630:                 }