consts.rs 29.5 KB
Newer Older
1 2 3 4 5 6 7 8 9 10
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

11

12
use back::abi;
X
xales 已提交
13 14
use lib::llvm::{llvm, ConstFCmp, ConstICmp, SetLinkage, PrivateLinkage, ValueRef, Bool, True,
    False};
15 16 17
use lib::llvm::{IntEQ, IntNE, IntUGT, IntUGE, IntULT, IntULE, IntSGT, IntSGE, IntSLT, IntSLE,
    RealOEQ, RealOGT, RealOGE, RealOLT, RealOLE, RealONE};

J
Josh Matthews 已提交
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 26
use middle::trans::consts;
use middle::trans::expr;
J
Josh Matthews 已提交
27
use middle::trans::inline;
28
use middle::trans::machine;
29
use middle::trans::type_of;
30
use middle::ty;
31
use util::ppaux::{Repr, ty_to_str};
32

J
James Miller 已提交
33 34
use middle::trans::type_::Type;

35
use std::c_str::ToCStr;
36
use std::libc::c_uint;
37
use std::vec;
38
use syntax::{ast, ast_util};
39

40
pub fn const_lit(cx: &CrateContext, e: &ast::Expr, lit: ast::Lit)
41
    -> ValueRef {
42
    let _icx = push_ctxt("trans_lit");
43
    match lit.node {
44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59
        ast::LitChar(i) => C_integral(Type::char(), i as u64, false),
        ast::LitInt(i, t) => C_integral(Type::int_from_ty(cx, t), i as u64, true),
        ast::LitUint(u, t) => C_integral(Type::uint_from_ty(cx, t), u, false),
        ast::LitIntUnsuffixed(i) => {
            let lit_int_ty = ty::node_id_to_type(cx.tcx, e.id);
            match ty::get(lit_int_ty).sty {
                ty::ty_int(t) => {
                    C_integral(Type::int_from_ty(cx, t), i as u64, true)
                }
                ty::ty_uint(t) => {
                    C_integral(Type::uint_from_ty(cx, t), i as u64, false)
                }
                _ => cx.sess.span_bug(lit.span,
                        format!("integer literal has type {} (expected int or uint)",
                                ty_to_str(cx.tcx, lit_int_ty)))
            }
60
        }
61 62 63 64
        ast::LitFloat(ref fs, t) => {
            C_floating(fs.get(), Type::float_from_ty(t))
        }
        ast::LitFloatUnsuffixed(ref fs) => {
65 66 67
            let lit_float_ty = ty::node_id_to_type(cx.tcx, e.id);
            match ty::get(lit_float_ty).sty {
                ty::ty_float(t) => {
68
                    C_floating(fs.get(), Type::float_from_ty(t))
69 70 71 72 73 74
                }
                _ => {
                    cx.sess.span_bug(lit.span,
                        "floating point literal doesn't have the right type");
                }
            }
75
        }
76 77
        ast::LitBool(b) => C_bool(b),
        ast::LitNil => C_nil(),
78
        ast::LitStr(ref s, _) => C_str_slice(cx, (*s).clone()),
79 80 81
        ast::LitBinary(ref data) => {
            C_binary_slice(cx, data.borrow().as_slice())
        }
82 83 84
    }
}

85
pub fn const_ptrcast(cx: &CrateContext, a: ValueRef, t: Type) -> ValueRef {
86
    unsafe {
J
James Miller 已提交
87
        let b = llvm::LLVMConstPointerCast(a, t.ptr_to().to_ref());
88 89
        let mut const_globals = cx.const_globals.borrow_mut();
        assert!(const_globals.get().insert(b as int, a));
90 91
        b
    }
92 93
}

94 95
fn const_vec(cx: @CrateContext, e: &ast::Expr,
             es: &[@ast::Expr], is_local: bool) -> (ValueRef, Type, bool) {
96 97 98
    let vec_ty = ty::expr_ty(cx.tcx, e);
    let unit_ty = ty::sequence_element_type(cx.tcx, vec_ty);
    let llunitty = type_of::type_of(cx, unit_ty);
99
    let (vs, inlineable) = vec::unzip(es.iter().map(|e| const_expr(cx, *e, is_local)));
100 101 102 103 104 105 106
    // If the vector contains enums, an LLVM array won't work.
    let v = if vs.iter().any(|vi| val_ty(*vi) != llunitty) {
        C_struct(vs, false)
    } else {
        C_array(llunitty, vs)
    };
    (v, llunitty, inlineable.iter().fold(true, |a, &b| a && b))
107 108
}

109
fn const_addr_of(cx: &CrateContext, cv: ValueRef) -> ValueRef {
J
Jed Davis 已提交
110
    unsafe {
111
        let gv = "const".with_c_str(|name| {
J
James Miller 已提交
112
            llvm::LLVMAddGlobal(cx.llmod, val_ty(cv).to_ref(), name)
113
        });
J
Jed Davis 已提交
114 115
        llvm::LLVMSetInitializer(gv, cv);
        llvm::LLVMSetGlobalConstant(gv, True);
116
        SetLinkage(gv, PrivateLinkage);
J
Jed Davis 已提交
117 118 119 120
        gv
    }
}

121
fn const_deref_ptr(cx: &CrateContext, v: ValueRef) -> ValueRef {
122 123
    let const_globals = cx.const_globals.borrow();
    let v = match const_globals.get().find(&(v as int)) {
124
        Some(&v) => v,
125 126
        None => v
    };
127
    unsafe {
128
        assert_eq!(llvm::LLVMIsGlobalConstant(v), True);
129 130 131 132
        llvm::LLVMGetInitializer(v)
    }
}

133
fn const_deref_newtype(cx: &CrateContext, v: ValueRef, t: ty::t)
134 135 136 137 138
    -> ValueRef {
    let repr = adt::represent_type(cx, t);
    adt::const_get_field(cx, repr, v, 0, 0)
}

139
fn const_deref(cx: &CrateContext, v: ValueRef, t: ty::t, explicit: bool)
140
    -> (ValueRef, ty::t) {
141
    match ty::deref(t, explicit) {
142
        Some(ref mt) => {
143
            assert!(mt.mutbl != ast::MutMutable);
144
            let dv = match ty::get(t).sty {
A
Alex Crichton 已提交
145
                ty::ty_ptr(..) | ty::ty_rptr(..) => {
146 147
                     const_deref_ptr(cx, v)
                }
A
Alex Crichton 已提交
148
                ty::ty_enum(..) | ty::ty_struct(..) => {
149 150 151
                    const_deref_newtype(cx, v, t)
                }
                _ => {
M
mr.Shu 已提交
152
                    cx.sess.bug(format!("unexpected dereferenceable type {}",
153 154 155 156 157 158
                                     ty_to_str(cx.tcx, t)))
                }
            };
            (dv, mt.ty)
        }
        None => {
M
mr.Shu 已提交
159
            cx.sess.bug(format!("can't dereference const of type {}",
160 161
                             ty_to_str(cx.tcx, t)))
        }
162
    }
163 164
}

165
pub fn get_const_val(cx: @CrateContext,
166
                     mut def_id: ast::DefId) -> (ValueRef, bool) {
167 168 169 170
    let contains_key = {
        let const_values = cx.const_values.borrow();
        const_values.get().contains_key(&def_id.node)
    };
J
James Miller 已提交
171
    if !ast_util::is_local(def_id) || !contains_key {
J
Josh Matthews 已提交
172
        if !ast_util::is_local(def_id) {
173
            def_id = inline::maybe_instantiate_inline(cx, def_id);
J
Josh Matthews 已提交
174
        }
P
Patrick Walton 已提交
175

176 177 178
        match cx.tcx.map.expect_item(def_id.node).node {
            ast::ItemStatic(_, ast::MutImmutable, _) => {
                trans_const(cx, ast::MutImmutable, def_id.node);
179
            }
180
            _ => {}
181 182
        }
    }
183 184

    let const_values = cx.const_values.borrow();
185
    let non_inlineable_statics = cx.non_inlineable_statics.borrow();
186
    (const_values.get().get_copy(&def_id.node),
187
     !non_inlineable_statics.get().contains(&def_id.node))
188
}
189

190 191
pub fn const_expr(cx: @CrateContext, e: &ast::Expr, is_local: bool) -> (ValueRef, bool) {
    let (llconst, inlineable) = const_expr_unadjusted(cx, e, is_local);
192 193
    let mut llconst = llconst;
    let mut inlineable = inlineable;
194
    let ety = ty::expr_ty(cx.tcx, e);
195
    let ety_adjusted = ty::expr_ty_adjusted(cx.tcx, e);
196 197 198 199
    let adjustment = {
        let adjustments = cx.tcx.adjustments.borrow();
        adjustments.get().find_copy(&e.id)
    };
J
James Miller 已提交
200
    match adjustment {
201
        None => { }
202 203 204
        Some(adj) => {
            match *adj {
                ty::AutoAddEnv(ty::ReStatic, ast::BorrowedSigil) => {
205 206 207 208 209 210 211
                    let def = ty::resolve_expr(cx.tcx, e);
                    let wrapper = closure::get_wrapper_for_bare_fn(cx,
                                                                   ety_adjusted,
                                                                   def,
                                                                   llconst,
                                                                   is_local);
                    llconst = C_struct([wrapper, C_null(Type::i8p())], false)
212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229
                }
                ty::AutoAddEnv(ref r, ref s) => {
                    cx.sess
                      .span_bug(e.span,
                                format!("unexpected static function: region \
                                         {:?} sigil {:?}",
                                        *r,
                                        *s))
                }
                ty::AutoObject(..) => {
                    cx.sess
                      .span_unimpl(e.span,
                                   "unimplemented const coercion to trait \
                                    object");
                }
                ty::AutoDerefRef(ref adj) => {
                    let mut ty = ety;
                    let mut maybe_ptr = None;
B
Brendan Zabarauskas 已提交
230
                    for _ in range(0, adj.autoderefs) {
231 232 233 234
                        let (dv, dt) = const_deref(cx, llconst, ty, false);
                        maybe_ptr = Some(llconst);
                        llconst = dv;
                        ty = dt;
B
Brendan Zabarauskas 已提交
235
                    }
236

237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274
                    match adj.autoref {
                        None => { }
                        Some(ref autoref) => {
                            // Don't copy data to do a deref+ref.
                            let llptr = match maybe_ptr {
                                Some(ptr) => ptr,
                                None => {
                                    inlineable = false;
                                    const_addr_of(cx, llconst)
                                }
                            };
                            match *autoref {
                                ty::AutoUnsafe(m) |
                                ty::AutoPtr(ty::ReStatic, m) => {
                                    assert!(m != ast::MutMutable);
                                    llconst = llptr;
                                }
                                ty::AutoBorrowVec(ty::ReStatic, m) => {
                                    assert!(m != ast::MutMutable);
                                    assert_eq!(abi::slice_elt_base, 0);
                                    assert_eq!(abi::slice_elt_len, 1);
                                    match ty::get(ty).sty {
                                        ty::ty_vec(_,
                                                   ty::vstore_fixed(len)) => {
                                            llconst = C_struct([
                                                llptr,
                                                C_uint(cx, len)
                                            ], false);
                                        }
                                        _ => {}
                                    }
                                }
                                _ => {
                                    cx.sess.span_bug(e.span,
                                                     format!("unimplemented \
                                                              const autoref \
                                                              {:?}",
                                                             autoref))
275 276
                                }
                            }
277 278 279 280 281 282 283 284
                        }
                    }
                }
            }
        }
    }

    let llty = type_of::sizing_type_of(cx, ety_adjusted);
285 286 287 288
    let csize = machine::llsize_of_alloc(cx, val_ty(llconst));
    let tsize = machine::llsize_of_alloc(cx, llty);
    if csize != tsize {
        unsafe {
289
            // FIXME these values could use some context
290
            llvm::LLVMDumpValue(llconst);
291
            llvm::LLVMDumpValue(C_undef(llty));
292
        }
A
Alex Crichton 已提交
293
        cx.sess.bug(format!("const {} of type {} has size {} instead of {}",
294
                         e.repr(cx.tcx), ty_to_str(cx.tcx, ety),
295 296
                         csize, tsize));
    }
297
    (llconst, inlineable)
298 299
}

300 301
// the bool returned is whether this expression can be inlined into other crates
// if it's assigned to a static.
302 303 304 305
fn const_expr_unadjusted(cx: @CrateContext, e: &ast::Expr,
                         is_local: bool) -> (ValueRef, bool) {
    let map_list = |exprs: &[@ast::Expr]| {
        exprs.iter().map(|&e| const_expr(cx, e, is_local))
306 307
             .fold((~[], true), |(l, all_inlineable), (val, inlineable)| {
                (vec::append_one(l, val), all_inlineable && inlineable)
308
             })
309
    };
310
    unsafe {
311
        let _icx = push_ctxt("const_expr");
312
        return match e.node {
313 314 315
          ast::ExprLit(lit) => {
              (consts::const_lit(cx, e, (*lit).clone()), true)
          }
316
          ast::ExprBinary(b, e1, e2) => {
317 318
            let (te1, _) = const_expr(cx, e1, is_local);
            let (te2, _) = const_expr(cx, e2, is_local);
319

320
            let te2 = base::cast_shift_const_rhs(b, te1, te2);
321

322 323 324 325 326
            /* Neither type is bottom, and we expect them to be unified
             * already, so the following is safe. */
            let ty = ty::expr_ty(cx.tcx, e1);
            let is_float = ty::type_is_fp(ty);
            let signed = ty::type_is_signed(ty);
327
            return (match b {
328
              ast::BiAdd   => {
329 330 331
                if is_float { llvm::LLVMConstFAdd(te1, te2) }
                else        { llvm::LLVMConstAdd(te1, te2) }
              }
332
              ast::BiSub => {
333 334 335
                if is_float { llvm::LLVMConstFSub(te1, te2) }
                else        { llvm::LLVMConstSub(te1, te2) }
              }
336
              ast::BiMul    => {
337 338 339
                if is_float { llvm::LLVMConstFMul(te1, te2) }
                else        { llvm::LLVMConstMul(te1, te2) }
              }
340
              ast::BiDiv    => {
341 342 343 344
                if is_float    { llvm::LLVMConstFDiv(te1, te2) }
                else if signed { llvm::LLVMConstSDiv(te1, te2) }
                else           { llvm::LLVMConstUDiv(te1, te2) }
              }
345
              ast::BiRem    => {
346 347 348 349
                if is_float    { llvm::LLVMConstFRem(te1, te2) }
                else if signed { llvm::LLVMConstSRem(te1, te2) }
                else           { llvm::LLVMConstURem(te1, te2) }
              }
350 351 352 353 354 355 356
              ast::BiAnd    => llvm::LLVMConstAnd(te1, te2),
              ast::BiOr     => llvm::LLVMConstOr(te1, te2),
              ast::BiBitXor => llvm::LLVMConstXor(te1, te2),
              ast::BiBitAnd => llvm::LLVMConstAnd(te1, te2),
              ast::BiBitOr  => llvm::LLVMConstOr(te1, te2),
              ast::BiShl    => llvm::LLVMConstShl(te1, te2),
              ast::BiShr    => {
357 358 359
                if signed { llvm::LLVMConstAShr(te1, te2) }
                else      { llvm::LLVMConstLShr(te1, te2) }
              }
360
              ast::BiEq     => {
C
Corey Richardson 已提交
361 362
                  if is_float { ConstFCmp(RealOEQ, te1, te2) }
                  else        { ConstICmp(IntEQ, te1, te2)   }
363
              },
364
              ast::BiLt     => {
C
Corey Richardson 已提交
365
                  if is_float { ConstFCmp(RealOLT, te1, te2) }
366
                  else        {
C
Corey Richardson 已提交
367 368
                      if signed { ConstICmp(IntSLT, te1, te2) }
                      else      { ConstICmp(IntULT, te1, te2) }
369 370
                  }
              },
371
              ast::BiLe     => {
C
Corey Richardson 已提交
372
                  if is_float { ConstFCmp(RealOLE, te1, te2) }
373
                  else        {
C
Corey Richardson 已提交
374 375
                      if signed { ConstICmp(IntSLE, te1, te2) }
                      else      { ConstICmp(IntULE, te1, te2) }
376 377
                  }
              },
378
              ast::BiNe     => {
C
Corey Richardson 已提交
379 380
                  if is_float { ConstFCmp(RealONE, te1, te2) }
                  else        { ConstICmp(IntNE, te1, te2) }
381
              },
382
              ast::BiGe     => {
C
Corey Richardson 已提交
383
                  if is_float { ConstFCmp(RealOGE, te1, te2) }
384
                  else        {
C
Corey Richardson 已提交
385 386
                      if signed { ConstICmp(IntSGE, te1, te2) }
                      else      { ConstICmp(IntUGE, te1, te2) }
387 388
                  }
              },
389
              ast::BiGt     => {
C
Corey Richardson 已提交
390
                  if is_float { ConstFCmp(RealOGT, te1, te2) }
391
                  else        {
C
Corey Richardson 已提交
392 393
                      if signed { ConstICmp(IntSGT, te1, te2) }
                      else      { ConstICmp(IntUGT, te1, te2) }
394 395
                  }
              },
396
            }, true)
397
          },
398
          ast::ExprUnary(u, e) => {
399
            let (te, _) = const_expr(cx, e, is_local);
400 401
            let ty = ty::expr_ty(cx.tcx, e);
            let is_float = ty::type_is_fp(ty);
402
            return (match u {
403
              ast::UnBox | ast::UnUniq | ast::UnDeref => {
404 405 406
                let (dv, _dt) = const_deref(cx, te, ty, true);
                dv
              }
407
              ast::UnNot    => {
408 409 410 411
                match ty::get(ty).sty {
                    ty::ty_bool => {
                        // Somewhat questionable, but I believe this is
                        // correct.
J
James Miller 已提交
412
                        let te = llvm::LLVMConstTrunc(te, Type::i1().to_ref());
413
                        let te = llvm::LLVMConstNot(te);
J
James Miller 已提交
414
                        llvm::LLVMConstZExt(te, Type::bool().to_ref())
415 416 417 418
                    }
                    _ => llvm::LLVMConstNot(te),
                }
              }
419
              ast::UnNeg    => {
420 421 422
                if is_float { llvm::LLVMConstFNeg(te) }
                else        { llvm::LLVMConstNeg(te) }
              }
423
            }, true)
424
          }
425
          ast::ExprField(base, field, _) => {
426
              let bt = ty::expr_ty_adjusted(cx.tcx, base);
427
              let brepr = adt::represent_type(cx, bt);
428
              let (bv, inlineable) = const_expr(cx, base, is_local);
429
              expr::with_field_tys(cx.tcx, bt, None, |discr, field_tys| {
430
                  let ix = ty::field_idx_strict(cx.tcx, field.name, field_tys);
431
                  (adt::const_get_field(cx, brepr, bv, discr, ix), inlineable)
432
              })
433
          }
434

435
          ast::ExprIndex(base, index) => {
436
              let bt = ty::expr_ty_adjusted(cx.tcx, base);
437
              let (bv, inlineable) = const_expr(cx, base, is_local);
438 439 440 441
              let iv = match const_eval::eval_const_expr(cx.tcx, index) {
                  const_eval::const_int(i) => i as u64,
                  const_eval::const_uint(u) => u,
                  _ => cx.sess.span_bug(index.span,
J
Jeong YunWon 已提交
442
                                        "index is not an integer-constant expression")
443
              };
444
              let (arr, len) = match ty::get(bt).sty {
445
                  ty::ty_vec(_, vstore) | ty::ty_str(vstore) =>
446 447 448
                      match vstore {
                      ty::vstore_fixed(u) =>
                          (bv, C_uint(cx, u)),
449

450
                      ty::vstore_slice(_) => {
451
                          let e1 = const_get_elt(cx, bv, [0]);
452
                          (const_deref_ptr(cx, e1), const_get_elt(cx, bv, [1]))
453 454
                      },
                      _ => cx.sess.span_bug(base.span,
J
Jeong YunWon 已提交
455
                                            "index-expr base must be fixed-size or slice")
456
                  },
457
                  _ =>  cx.sess.span_bug(base.span,
J
Jeong YunWon 已提交
458
                                         "index-expr base must be a vector or string type")
459
              };
460

461
              let len = llvm::LLVMConstIntGetZExtValue(len) as u64;
462
              let len = match ty::get(bt).sty {
463
                  ty::ty_str(..) => {assert!(len > 0); len - 1},
464 465 466 467 468 469
                  _ => len
              };
              if iv >= len {
                  // FIXME #3170: report this earlier on in the const-eval
                  // pass. Reporting here is a bit late.
                  cx.sess.span_err(e.span,
J
Jeong YunWon 已提交
470
                                   "const index-expr is out of bounds");
471
              }
472
              (const_get_elt(cx, arr, [iv as c_uint]), inlineable)
473
          }
474
          ast::ExprCast(base, _) => {
475 476 477
            let ety = ty::expr_ty(cx.tcx, e);
            let llty = type_of::type_of(cx, ety);
            let basety = ty::expr_ty(cx.tcx, base);
478
            let (v, inlineable) = const_expr(cx, base, is_local);
479 480
            return (match (expr::cast_type_kind(basety),
                           expr::cast_type_kind(ety)) {
481

482
              (expr::cast_integral, expr::cast_integral) => {
483
                let s = ty::type_is_signed(basety) as Bool;
J
James Miller 已提交
484
                llvm::LLVMConstIntCast(v, llty.to_ref(), s)
485 486 487
              }
              (expr::cast_integral, expr::cast_float) => {
                if ty::type_is_signed(basety) {
J
James Miller 已提交
488
                    llvm::LLVMConstSIToFP(v, llty.to_ref())
489
                } else {
J
James Miller 已提交
490
                    llvm::LLVMConstUIToFP(v, llty.to_ref())
491 492 493
                }
              }
              (expr::cast_float, expr::cast_float) => {
J
James Miller 已提交
494
                llvm::LLVMConstFPCast(v, llty.to_ref())
495 496
              }
              (expr::cast_float, expr::cast_integral) => {
J
James Miller 已提交
497 498
                if ty::type_is_signed(ety) { llvm::LLVMConstFPToSI(v, llty.to_ref()) }
                else { llvm::LLVMConstFPToUI(v, llty.to_ref()) }
499
              }
500 501
              (expr::cast_enum, expr::cast_integral) |
              (expr::cast_enum, expr::cast_float)  => {
502
                let repr = adt::represent_type(cx, basety);
J
James Miller 已提交
503
                let discr = adt::const_get_discrim(cx, repr, v);
504
                let iv = C_integral(cx.int_type, discr, false);
505 506 507 508
                let ety_cast = expr::cast_type_kind(ety);
                match ety_cast {
                    expr::cast_integral => {
                        let s = ty::type_is_signed(ety) as Bool;
J
James Miller 已提交
509
                        llvm::LLVMConstIntCast(iv, llty.to_ref(), s)
510
                    }
J
James Miller 已提交
511
                    expr::cast_float => llvm::LLVMConstUIToFP(iv, llty.to_ref()),
512 513
                    _ => cx.sess.bug("enum cast destination is not \
                                      integral or float")
514 515
                }
              }
516
              (expr::cast_pointer, expr::cast_pointer) => {
J
James Miller 已提交
517
                llvm::LLVMConstPointerCast(v, llty.to_ref())
518
              }
519
              (expr::cast_integral, expr::cast_pointer) => {
J
James Miller 已提交
520
                llvm::LLVMConstIntToPtr(v, llty.to_ref())
521
              }
522 523
              _ => {
                cx.sess.impossible_case(e.span,
524
                                        "bad combination of types for cast")
525
              }
526
            }, inlineable)
527
          }
528
          ast::ExprAddrOf(ast::MutImmutable, sub) => {
529
              let (e, _) = const_expr(cx, sub, is_local);
530
              (const_addr_of(cx, e), false)
531
          }
532
          ast::ExprTup(ref es) => {
533 534
              let ety = ty::expr_ty(cx.tcx, e);
              let repr = adt::represent_type(cx, ety);
535
              let (vals, inlineable) = map_list(es.as_slice());
536
              (adt::trans_const(cx, repr, 0, vals), inlineable)
537
          }
538
          ast::ExprStruct(_, ref fs, ref base_opt) => {
539
              let ety = ty::expr_ty(cx.tcx, e);
540
              let repr = adt::represent_type(cx, ety);
J
James Miller 已提交
541
              let tcx = cx.tcx;
542 543

              let base_val = match *base_opt {
544
                Some(base) => Some(const_expr(cx, base, is_local)),
545 546 547
                None => None
              };

548
              expr::with_field_tys(tcx, ety, Some(e.id), |discr, field_tys| {
549
                  let cs = field_tys.iter().enumerate()
550
                      .map(|(ix, &field_ty)| {
551
                      match fs.iter().find(|f| field_ty.ident.name == f.ident.node.name) {
552
                          Some(f) => const_expr(cx, (*f).expr, is_local),
553
                          None => {
554
                              match base_val {
555 556 557 558
                                Some((bv, inlineable)) => {
                                    (adt::const_get_field(cx, repr, bv, discr, ix),
                                     inlineable)
                                }
559 560
                                None => cx.tcx.sess.span_bug(e.span, "missing struct field")
                              }
561 562
                          }
                      }
563 564 565 566
                  }).to_owned_vec();
                  let (cs, inlineable) = vec::unzip(cs.move_iter());
                  (adt::trans_const(cx, repr, discr, cs),
                   inlineable.iter().fold(true, |a, &b| a && b))
567
              })
568
          }
569
          ast::ExprVec(ref es, ast::MutImmutable) => {
570 571 572 573
            let (v, _, inlineable) = const_vec(cx,
                                               e,
                                               es.as_slice(),
                                               is_local);
574
            (v, inlineable)
575
          }
X
xales 已提交
576 577
          ast::ExprVstore(sub, store @ ast::ExprVstoreSlice) |
              ast::ExprVstore(sub, store @ ast::ExprVstoreMutSlice) => {
578
            match sub.node {
579
              ast::ExprLit(ref lit) => {
580
                match lit.node {
581
                    ast::LitStr(..) => { const_expr(cx, sub, is_local) }
582
                    _ => { cx.sess.span_bug(e.span, "bad const-slice lit") }
583 584
                }
              }
585
              ast::ExprVec(ref es, ast::MutImmutable) => {
586 587 588 589
                let (cv, llunitty, _) = const_vec(cx,
                                                  e,
                                                  es.as_slice(),
                                                  is_local);
590
                let llty = val_ty(cv);
591
                let gv = "const".with_c_str(|name| {
J
James Miller 已提交
592
                    llvm::LLVMAddGlobal(cx.llmod, llty.to_ref(), name)
593
                });
594
                llvm::LLVMSetInitializer(gv, cv);
X
xales 已提交
595 596
                llvm::LLVMSetGlobalConstant(gv,
                      if store == ast::ExprVstoreMutSlice { False } else { True });
597
                SetLinkage(gv, PrivateLinkage);
598
                let p = const_ptrcast(cx, gv, llunitty);
599
                (C_struct([p, C_uint(cx, es.len())], false), false)
600
              }
J
Jeong YunWon 已提交
601
              _ => cx.sess.span_bug(e.span, "bad const-slice expr")
602
            }
603
          }
604
          ast::ExprRepeat(elem, count, _) => {
605 606 607 608 609 610 611 612
            let vec_ty = ty::expr_ty(cx.tcx, e);
            let unit_ty = ty::sequence_element_type(cx.tcx, vec_ty);
            let llunitty = type_of::type_of(cx, unit_ty);
            let n = match const_eval::eval_const_expr(cx.tcx, count) {
                const_eval::const_int(i)  => i as uint,
                const_eval::const_uint(i) => i as uint,
                _ => cx.sess.span_bug(count.span, "count must be integral const expression.")
            };
613
            let vs = vec::from_elem(n, const_expr(cx, elem, is_local).val0());
614
            let v = if vs.iter().any(|vi| val_ty(*vi) != llunitty) {
615
                C_struct(vs, false)
616 617 618
            } else {
                C_array(llunitty, vs)
            };
619
            (v, true)
620
          }
621
          ast::ExprPath(ref pth) => {
622 623 624
            // Assert that there are no type parameters in this path.
            assert!(pth.segments.iter().all(|seg| seg.types.is_empty()));

J
James Miller 已提交
625
            let tcx = cx.tcx;
P
Patrick Walton 已提交
626 627 628 629 630 631
            let opt_def = {
                let def_map = tcx.def_map.borrow();
                def_map.get().find_copy(&e.id)
            };
            match opt_def {
                Some(ast::DefFn(def_id, _purity)) => {
632
                    if !ast_util::is_local(def_id) {
J
Josh Matthews 已提交
633
                        let ty = csearch::get_type(cx.tcx, def_id).ty;
634
                        (base::trans_external_path(cx, def_id, ty), true)
J
Josh Matthews 已提交
635
                    } else {
P
Patrick Walton 已提交
636
                        assert!(ast_util::is_local(def_id));
637
                        (base::get_item_val(cx, def_id.node), true)
638
                    }
639
                }
P
Patrick Walton 已提交
640
                Some(ast::DefStatic(def_id, false)) => {
641
                    get_const_val(cx, def_id)
642
                }
P
Patrick Walton 已提交
643
                Some(ast::DefVariant(enum_did, variant_did, _)) => {
644
                    let ety = ty::expr_ty(cx.tcx, e);
645 646 647 648
                    let repr = adt::represent_type(cx, ety);
                    let vinfo = ty::enum_variant_with_id(cx.tcx,
                                                         enum_did,
                                                         variant_did);
649
                    (adt::trans_const(cx, repr, vinfo.disr_val, []), true)
650
                }
P
Patrick Walton 已提交
651
                Some(ast::DefStruct(_)) => {
652 653
                    let ety = ty::expr_ty(cx.tcx, e);
                    let llty = type_of::type_of(cx, ety);
654
                    (C_null(llty), true)
655 656
                }
                _ => {
J
Jeong YunWon 已提交
657
                    cx.sess.span_bug(e.span, "expected a const, fn, struct, or variant def")
658
                }
659
            }
660
          }
661
          ast::ExprCall(callee, ref args) => {
J
James Miller 已提交
662
              let tcx = cx.tcx;
P
Patrick Walton 已提交
663 664 665 666 667 668
              let opt_def = {
                  let def_map = tcx.def_map.borrow();
                  def_map.get().find_copy(&callee.id)
              };
              match opt_def {
                  Some(ast::DefStruct(_)) => {
669 670
                      let ety = ty::expr_ty(cx.tcx, e);
                      let repr = adt::represent_type(cx, ety);
671
                      let (arg_vals, inlineable) = map_list(args.as_slice());
672
                      (adt::trans_const(cx, repr, 0, arg_vals), inlineable)
673
                  }
P
Patrick Walton 已提交
674
                  Some(ast::DefVariant(enum_did, variant_did, _)) => {
675 676 677 678 679
                      let ety = ty::expr_ty(cx.tcx, e);
                      let repr = adt::represent_type(cx, ety);
                      let vinfo = ty::enum_variant_with_id(cx.tcx,
                                                           enum_did,
                                                           variant_did);
680
                      let (arg_vals, inlineable) = map_list(args.as_slice());
681 682
                      (adt::trans_const(cx, repr, vinfo.disr_val, arg_vals),
                       inlineable)
683
                  }
J
Jeong YunWon 已提交
684
                  _ => cx.sess.span_bug(e.span, "expected a struct or variant def")
685
              }
686
          }
687
          ast::ExprParen(e) => { const_expr(cx, e, is_local) }
688
          _ => cx.sess.span_bug(e.span,
J
Jeong YunWon 已提交
689
                  "bad constant expression type in consts::const_expr")
690 691
        };
    }
692 693
}

694
pub fn trans_const(ccx: @CrateContext, m: ast::Mutability, id: ast::NodeId) {
695
    unsafe {
696
        let _icx = push_ctxt("trans_const");
697
        let g = base::get_item_val(ccx, id);
698 699
        // At this point, get_item_val has already translated the
        // constant's initializer to determine its LLVM type.
700 701
        let const_values = ccx.const_values.borrow();
        let v = const_values.get().get_copy(&id);
702
        llvm::LLVMSetInitializer(g, v);
703
        if m != ast::MutMutable {
704 705
            llvm::LLVMSetGlobalConstant(g, True);
        }
706
    }
707
}