2012-12-03 18:48:01 -06:00
|
|
|
// 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.
|
|
|
|
|
2013-05-17 17:28:44 -05:00
|
|
|
|
2013-03-07 14:34:58 -06:00
|
|
|
use back::abi;
|
2013-06-16 06:11:17 -05:00
|
|
|
use lib::llvm::{llvm, ConstFCmp, ConstICmp, SetLinkage, PrivateLinkage, ValueRef, Bool, True};
|
2013-05-19 15:03:52 -05:00
|
|
|
use lib::llvm::{IntEQ, IntNE, IntUGT, IntUGE, IntULT, IntULE, IntSGT, IntSGE, IntSLT, IntSLE,
|
|
|
|
RealOEQ, RealOGT, RealOGE, RealOLT, RealOLE, RealONE};
|
|
|
|
|
2013-03-07 00:30:20 -06:00
|
|
|
use metadata::csearch;
|
2012-12-23 16:41:37 -06:00
|
|
|
use middle::const_eval;
|
2013-02-24 16:38:59 -06:00
|
|
|
use middle::trans::adt;
|
2013-02-25 13:11:21 -06:00
|
|
|
use middle::trans::base;
|
2013-06-16 23:23:24 -05:00
|
|
|
use middle::trans::base::push_ctxt;
|
2014-01-27 06:18:36 -06:00
|
|
|
use middle::trans::closure;
|
2012-12-13 15:05:22 -06:00
|
|
|
use middle::trans::common::*;
|
2012-12-23 16:41:37 -06:00
|
|
|
use middle::trans::consts;
|
|
|
|
use middle::trans::expr;
|
2013-03-07 00:30:20 -06:00
|
|
|
use middle::trans::inline;
|
2013-01-30 13:46:19 -06:00
|
|
|
use middle::trans::machine;
|
2013-02-25 13:11:21 -06:00
|
|
|
use middle::trans::type_of;
|
2012-12-23 16:41:37 -06:00
|
|
|
use middle::ty;
|
Cleanup substitutions and treatment of generics around traits in a number of ways.
- In a TraitRef, use the self type consistently to refer to the Self type:
- trait ref in `impl Trait<A,B,C> for S` has a self type of `S`.
- trait ref in `A:Trait` has the self type `A`
- trait ref associated with a trait decl has self type `Self`
- trait ref associated with a supertype has self type `Self`
- trait ref in an object type `@Trait` has no self type
- Rewrite `each_bound_traits_and_supertraits` to perform
substitutions as it goes, and thus yield a series of trait refs
that are always in the same 'namespace' as the type parameter
bound given as input. Before, we left this to the caller, but
this doesn't work because the caller lacks adequare information
to perform the type substitutions correctly.
- For provided methods, substitute the generics involved in the provided
method correctly.
- Introduce TypeParameterDef, which tracks the bounds declared on a type
parameter and brings them together with the def_id and (in the future)
other information (maybe even the parameter's name!).
- Introduce Subst trait, which helps to cleanup a lot of the
repetitive code involved with doing type substitution.
- Introduce Repr trait, which makes debug printouts far more convenient.
Fixes #4183. Needed for #5656.
2013-04-09 00:54:49 -05:00
|
|
|
use util::ppaux::{Repr, ty_to_str};
|
2012-12-13 15:05:22 -06:00
|
|
|
|
2013-06-16 05:52:44 -05:00
|
|
|
use middle::trans::type_::Type;
|
|
|
|
|
2013-08-03 19:13:14 -05:00
|
|
|
use std::c_str::ToCStr;
|
2013-06-28 17:32:26 -05:00
|
|
|
use std::libc::c_uint;
|
2013-08-12 20:10:29 -05:00
|
|
|
use std::vec;
|
2014-02-13 23:07:09 -06:00
|
|
|
use syntax::{ast, ast_util};
|
2012-07-31 20:34:36 -05:00
|
|
|
|
2014-01-09 07:05:33 -06:00
|
|
|
pub fn const_lit(cx: &CrateContext, e: &ast::Expr, lit: ast::Lit)
|
2012-07-31 20:34:36 -05:00
|
|
|
-> ValueRef {
|
2013-06-16 23:23:24 -05:00
|
|
|
let _icx = push_ctxt("trans_lit");
|
2012-08-06 14:34:08 -05:00
|
|
|
match lit.node {
|
2014-01-09 07:05:33 -06:00
|
|
|
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)))
|
|
|
|
}
|
2012-07-31 20:34:36 -05:00
|
|
|
}
|
2014-01-15 19:15:39 -06:00
|
|
|
ast::LitFloat(ref fs, t) => {
|
|
|
|
C_floating(fs.get(), Type::float_from_ty(t))
|
|
|
|
}
|
|
|
|
ast::LitFloatUnsuffixed(ref fs) => {
|
2014-01-09 07:05:33 -06:00
|
|
|
let lit_float_ty = ty::node_id_to_type(cx.tcx, e.id);
|
|
|
|
match ty::get(lit_float_ty).sty {
|
|
|
|
ty::ty_float(t) => {
|
2014-01-15 19:15:39 -06:00
|
|
|
C_floating(fs.get(), Type::float_from_ty(t))
|
2014-01-09 07:05:33 -06:00
|
|
|
}
|
|
|
|
_ => {
|
|
|
|
cx.sess.span_bug(lit.span,
|
|
|
|
"floating point literal doesn't have the right type");
|
|
|
|
}
|
|
|
|
}
|
2012-11-07 20:40:34 -06:00
|
|
|
}
|
2014-01-09 07:05:33 -06:00
|
|
|
ast::LitBool(b) => C_bool(b),
|
|
|
|
ast::LitNil => C_nil(),
|
2014-01-10 16:02:36 -06:00
|
|
|
ast::LitStr(ref s, _) => C_str_slice(cx, (*s).clone()),
|
2014-01-31 22:54:41 -06:00
|
|
|
ast::LitBinary(ref data) => C_binary_slice(cx, *data.borrow()),
|
2012-07-31 20:34:36 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-12-19 18:47:15 -06:00
|
|
|
pub fn const_ptrcast(cx: &CrateContext, a: ValueRef, t: Type) -> ValueRef {
|
2013-01-10 23:23:07 -06:00
|
|
|
unsafe {
|
2013-06-16 05:52:44 -05:00
|
|
|
let b = llvm::LLVMConstPointerCast(a, t.ptr_to().to_ref());
|
2013-12-18 19:03:55 -06:00
|
|
|
let mut const_globals = cx.const_globals.borrow_mut();
|
|
|
|
assert!(const_globals.get().insert(b as int, a));
|
2013-01-10 23:23:07 -06:00
|
|
|
b
|
|
|
|
}
|
2012-08-09 18:05:34 -05:00
|
|
|
}
|
|
|
|
|
2014-01-27 06:18:36 -06:00
|
|
|
fn const_vec(cx: @CrateContext, e: &ast::Expr,
|
|
|
|
es: &[@ast::Expr], is_local: bool) -> (ValueRef, Type, bool) {
|
2013-10-14 23:37:32 -05:00
|
|
|
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);
|
2014-01-27 06:18:36 -06:00
|
|
|
let (vs, inlineable) = vec::unzip(es.iter().map(|e| const_expr(cx, *e, is_local)));
|
2013-10-14 23:37:32 -05:00
|
|
|
// 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))
|
2012-08-03 23:44:42 -05:00
|
|
|
}
|
|
|
|
|
2013-12-19 18:47:15 -06:00
|
|
|
fn const_addr_of(cx: &CrateContext, cv: ValueRef) -> ValueRef {
|
2013-03-07 14:34:39 -06:00
|
|
|
unsafe {
|
2013-11-21 17:42:55 -06:00
|
|
|
let gv = "const".with_c_str(|name| {
|
2013-06-16 05:52:44 -05:00
|
|
|
llvm::LLVMAddGlobal(cx.llmod, val_ty(cv).to_ref(), name)
|
2013-11-21 17:42:55 -06:00
|
|
|
});
|
2013-03-07 14:34:39 -06:00
|
|
|
llvm::LLVMSetInitializer(gv, cv);
|
|
|
|
llvm::LLVMSetGlobalConstant(gv, True);
|
2013-03-28 20:15:35 -05:00
|
|
|
SetLinkage(gv, PrivateLinkage);
|
2013-03-07 14:34:39 -06:00
|
|
|
gv
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-12-19 18:47:15 -06:00
|
|
|
fn const_deref_ptr(cx: &CrateContext, v: ValueRef) -> ValueRef {
|
2013-12-18 19:03:55 -06:00
|
|
|
let const_globals = cx.const_globals.borrow();
|
|
|
|
let v = match const_globals.get().find(&(v as int)) {
|
2013-03-22 21:26:41 -05:00
|
|
|
Some(&v) => v,
|
2013-03-08 12:22:48 -06:00
|
|
|
None => v
|
|
|
|
};
|
2013-01-10 23:23:07 -06:00
|
|
|
unsafe {
|
2013-05-18 21:02:45 -05:00
|
|
|
assert_eq!(llvm::LLVMIsGlobalConstant(v), True);
|
2013-03-08 12:22:48 -06:00
|
|
|
llvm::LLVMGetInitializer(v)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-12-19 18:47:15 -06:00
|
|
|
fn const_deref_newtype(cx: &CrateContext, v: ValueRef, t: ty::t)
|
2013-03-08 12:22:48 -06:00
|
|
|
-> ValueRef {
|
|
|
|
let repr = adt::represent_type(cx, t);
|
|
|
|
adt::const_get_field(cx, repr, v, 0, 0)
|
|
|
|
}
|
|
|
|
|
2013-12-19 18:47:15 -06:00
|
|
|
fn const_deref(cx: &CrateContext, v: ValueRef, t: ty::t, explicit: bool)
|
2013-03-08 12:22:48 -06:00
|
|
|
-> (ValueRef, ty::t) {
|
2013-11-01 20:06:31 -05:00
|
|
|
match ty::deref(t, explicit) {
|
2013-03-08 12:22:48 -06:00
|
|
|
Some(ref mt) => {
|
2013-09-01 20:45:37 -05:00
|
|
|
assert!(mt.mutbl != ast::MutMutable);
|
2013-03-08 12:22:48 -06:00
|
|
|
let dv = match ty::get(t).sty {
|
2013-11-28 14:22:53 -06:00
|
|
|
ty::ty_ptr(..) | ty::ty_rptr(..) => {
|
2013-03-08 12:22:48 -06:00
|
|
|
const_deref_ptr(cx, v)
|
|
|
|
}
|
2013-11-28 14:22:53 -06:00
|
|
|
ty::ty_enum(..) | ty::ty_struct(..) => {
|
2013-03-08 12:22:48 -06:00
|
|
|
const_deref_newtype(cx, v, t)
|
|
|
|
}
|
|
|
|
_ => {
|
2014-02-06 03:38:08 -06:00
|
|
|
cx.sess.bug(format!("unexpected dereferenceable type {}",
|
2013-03-08 12:22:48 -06:00
|
|
|
ty_to_str(cx.tcx, t)))
|
|
|
|
}
|
|
|
|
};
|
|
|
|
(dv, mt.ty)
|
|
|
|
}
|
|
|
|
None => {
|
2014-02-06 03:38:08 -06:00
|
|
|
cx.sess.bug(format!("can't dereference const of type {}",
|
2013-03-08 12:22:48 -06:00
|
|
|
ty_to_str(cx.tcx, t)))
|
|
|
|
}
|
2013-01-10 23:23:07 -06:00
|
|
|
}
|
2012-08-08 21:41:50 -05:00
|
|
|
}
|
|
|
|
|
2013-12-19 18:47:15 -06:00
|
|
|
pub fn get_const_val(cx: @CrateContext,
|
2013-09-11 12:06:16 -05:00
|
|
|
mut def_id: ast::DefId) -> (ValueRef, bool) {
|
2013-12-18 19:08:56 -06:00
|
|
|
let contains_key = {
|
|
|
|
let const_values = cx.const_values.borrow();
|
|
|
|
const_values.get().contains_key(&def_id.node)
|
|
|
|
};
|
2013-06-13 02:19:50 -05:00
|
|
|
if !ast_util::is_local(def_id) || !contains_key {
|
2013-03-07 00:30:20 -06:00
|
|
|
if !ast_util::is_local(def_id) {
|
2013-07-11 16:34:10 -05:00
|
|
|
def_id = inline::maybe_instantiate_inline(cx, def_id);
|
2013-03-07 00:30:20 -06:00
|
|
|
}
|
2013-12-27 18:09:29 -06:00
|
|
|
|
2014-02-13 23:07:09 -06:00
|
|
|
match cx.tcx.map.expect_item(def_id.node).node {
|
|
|
|
ast::ItemStatic(_, ast::MutImmutable, _) => {
|
|
|
|
trans_const(cx, ast::MutImmutable, def_id.node);
|
2012-11-13 00:10:15 -06:00
|
|
|
}
|
2014-02-13 23:07:09 -06:00
|
|
|
_ => {}
|
2012-11-13 00:10:15 -06:00
|
|
|
}
|
|
|
|
}
|
2013-12-18 19:08:56 -06:00
|
|
|
|
|
|
|
let const_values = cx.const_values.borrow();
|
2013-12-18 20:11:41 -06:00
|
|
|
let non_inlineable_statics = cx.non_inlineable_statics.borrow();
|
2013-12-18 19:08:56 -06:00
|
|
|
(const_values.get().get_copy(&def_id.node),
|
2013-12-18 20:11:41 -06:00
|
|
|
!non_inlineable_statics.get().contains(&def_id.node))
|
2012-11-13 00:10:15 -06:00
|
|
|
}
|
2012-08-08 21:41:50 -05:00
|
|
|
|
2014-01-27 06:18:36 -06:00
|
|
|
pub fn const_expr(cx: @CrateContext, e: &ast::Expr, is_local: bool) -> (ValueRef, bool) {
|
|
|
|
let (llconst, inlineable) = const_expr_unadjusted(cx, e, is_local);
|
2013-09-11 12:06:16 -05:00
|
|
|
let mut llconst = llconst;
|
|
|
|
let mut inlineable = inlineable;
|
2013-03-07 14:34:58 -06:00
|
|
|
let ety = ty::expr_ty(cx.tcx, e);
|
2014-01-27 06:18:36 -06:00
|
|
|
let ety_adjusted = ty::expr_ty_adjusted(cx.tcx, e);
|
2013-12-19 20:26:45 -06:00
|
|
|
let adjustment = {
|
|
|
|
let adjustments = cx.tcx.adjustments.borrow();
|
|
|
|
adjustments.get().find_copy(&e.id)
|
|
|
|
};
|
2013-06-13 02:19:50 -05:00
|
|
|
match adjustment {
|
2013-03-07 14:34:58 -06:00
|
|
|
None => { }
|
2014-01-03 17:08:48 -06:00
|
|
|
Some(adj) => {
|
|
|
|
match *adj {
|
|
|
|
ty::AutoAddEnv(ty::ReStatic, ast::BorrowedSigil) => {
|
2014-01-27 06:18:36 -06:00
|
|
|
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)
|
2014-01-03 17:08:48 -06:00
|
|
|
}
|
|
|
|
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;
|
2014-01-29 18:20:34 -06:00
|
|
|
for _ in range(0, adj.autoderefs) {
|
2014-01-03 17:08:48 -06:00
|
|
|
let (dv, dt) = const_deref(cx, llconst, ty, false);
|
|
|
|
maybe_ptr = Some(llconst);
|
|
|
|
llconst = dv;
|
|
|
|
ty = dt;
|
2014-01-29 18:20:34 -06:00
|
|
|
}
|
2013-07-27 03:38:55 -05:00
|
|
|
|
2014-01-03 17:08:48 -06:00
|
|
|
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))
|
2013-07-27 03:38:55 -05:00
|
|
|
}
|
|
|
|
}
|
2013-03-07 14:34:58 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
let llty = type_of::sizing_type_of(cx, ety_adjusted);
|
2013-03-03 16:30:06 -06:00
|
|
|
let csize = machine::llsize_of_alloc(cx, val_ty(llconst));
|
|
|
|
let tsize = machine::llsize_of_alloc(cx, llty);
|
|
|
|
if csize != tsize {
|
|
|
|
unsafe {
|
2014-01-26 02:43:42 -06:00
|
|
|
// FIXME these values could use some context
|
2013-03-03 16:30:06 -06:00
|
|
|
llvm::LLVMDumpValue(llconst);
|
2013-03-07 14:34:58 -06:00
|
|
|
llvm::LLVMDumpValue(C_undef(llty));
|
2013-03-03 16:30:06 -06:00
|
|
|
}
|
2013-09-28 00:38:08 -05:00
|
|
|
cx.sess.bug(format!("const {} of type {} has size {} instead of {}",
|
Cleanup substitutions and treatment of generics around traits in a number of ways.
- In a TraitRef, use the self type consistently to refer to the Self type:
- trait ref in `impl Trait<A,B,C> for S` has a self type of `S`.
- trait ref in `A:Trait` has the self type `A`
- trait ref associated with a trait decl has self type `Self`
- trait ref associated with a supertype has self type `Self`
- trait ref in an object type `@Trait` has no self type
- Rewrite `each_bound_traits_and_supertraits` to perform
substitutions as it goes, and thus yield a series of trait refs
that are always in the same 'namespace' as the type parameter
bound given as input. Before, we left this to the caller, but
this doesn't work because the caller lacks adequare information
to perform the type substitutions correctly.
- For provided methods, substitute the generics involved in the provided
method correctly.
- Introduce TypeParameterDef, which tracks the bounds declared on a type
parameter and brings them together with the def_id and (in the future)
other information (maybe even the parameter's name!).
- Introduce Subst trait, which helps to cleanup a lot of the
repetitive code involved with doing type substitution.
- Introduce Repr trait, which makes debug printouts far more convenient.
Fixes #4183. Needed for #5656.
2013-04-09 00:54:49 -05:00
|
|
|
e.repr(cx.tcx), ty_to_str(cx.tcx, ety),
|
2013-03-03 16:30:06 -06:00
|
|
|
csize, tsize));
|
|
|
|
}
|
2013-09-11 12:06:16 -05:00
|
|
|
(llconst, inlineable)
|
2013-03-03 16:30:06 -06:00
|
|
|
}
|
|
|
|
|
2013-09-11 12:06:16 -05:00
|
|
|
// the bool returned is whether this expression can be inlined into other crates
|
|
|
|
// if it's assigned to a static.
|
2014-01-27 06:18:36 -06:00
|
|
|
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))
|
2013-09-11 12:06:16 -05:00
|
|
|
.fold((~[], true), |(L, all_inlineable), (val, inlineable)| {
|
2014-01-27 06:18:36 -06:00
|
|
|
(vec::append_one(L, val), all_inlineable && inlineable)
|
2013-09-11 12:06:16 -05:00
|
|
|
})
|
2014-01-27 06:18:36 -06:00
|
|
|
};
|
2013-01-10 23:23:07 -06:00
|
|
|
unsafe {
|
2013-06-16 23:23:24 -05:00
|
|
|
let _icx = push_ctxt("const_expr");
|
2013-03-20 00:17:42 -05:00
|
|
|
return match e.node {
|
2014-01-10 16:02:36 -06:00
|
|
|
ast::ExprLit(lit) => {
|
|
|
|
(consts::const_lit(cx, e, (*lit).clone()), true)
|
|
|
|
}
|
2013-09-01 20:45:37 -05:00
|
|
|
ast::ExprBinary(_, b, e1, e2) => {
|
2014-01-27 06:18:36 -06:00
|
|
|
let (te1, _) = const_expr(cx, e1, is_local);
|
|
|
|
let (te2, _) = const_expr(cx, e2, is_local);
|
2012-07-31 20:34:36 -05:00
|
|
|
|
2013-01-10 23:23:07 -06:00
|
|
|
let te2 = base::cast_shift_const_rhs(b, te1, te2);
|
2012-07-31 20:34:36 -05:00
|
|
|
|
2013-01-10 23:23:07 -06:00
|
|
|
/* 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);
|
2013-09-11 12:06:16 -05:00
|
|
|
return (match b {
|
2013-09-01 20:45:37 -05:00
|
|
|
ast::BiAdd => {
|
2013-01-10 23:23:07 -06:00
|
|
|
if is_float { llvm::LLVMConstFAdd(te1, te2) }
|
|
|
|
else { llvm::LLVMConstAdd(te1, te2) }
|
|
|
|
}
|
2013-09-01 20:45:37 -05:00
|
|
|
ast::BiSub => {
|
2013-01-10 23:23:07 -06:00
|
|
|
if is_float { llvm::LLVMConstFSub(te1, te2) }
|
|
|
|
else { llvm::LLVMConstSub(te1, te2) }
|
|
|
|
}
|
2013-09-01 20:45:37 -05:00
|
|
|
ast::BiMul => {
|
2013-01-10 23:23:07 -06:00
|
|
|
if is_float { llvm::LLVMConstFMul(te1, te2) }
|
|
|
|
else { llvm::LLVMConstMul(te1, te2) }
|
|
|
|
}
|
2013-09-01 20:45:37 -05:00
|
|
|
ast::BiDiv => {
|
2013-01-10 23:23:07 -06:00
|
|
|
if is_float { llvm::LLVMConstFDiv(te1, te2) }
|
|
|
|
else if signed { llvm::LLVMConstSDiv(te1, te2) }
|
|
|
|
else { llvm::LLVMConstUDiv(te1, te2) }
|
|
|
|
}
|
2013-09-01 20:45:37 -05:00
|
|
|
ast::BiRem => {
|
2013-01-10 23:23:07 -06:00
|
|
|
if is_float { llvm::LLVMConstFRem(te1, te2) }
|
|
|
|
else if signed { llvm::LLVMConstSRem(te1, te2) }
|
|
|
|
else { llvm::LLVMConstURem(te1, te2) }
|
|
|
|
}
|
2013-09-01 20:45:37 -05:00
|
|
|
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 => {
|
2013-01-10 23:23:07 -06:00
|
|
|
if signed { llvm::LLVMConstAShr(te1, te2) }
|
|
|
|
else { llvm::LLVMConstLShr(te1, te2) }
|
|
|
|
}
|
2013-09-01 20:45:37 -05:00
|
|
|
ast::BiEq => {
|
2013-05-19 19:18:56 -05:00
|
|
|
if is_float { ConstFCmp(RealOEQ, te1, te2) }
|
|
|
|
else { ConstICmp(IntEQ, te1, te2) }
|
2013-05-19 15:03:52 -05:00
|
|
|
},
|
2013-09-01 20:45:37 -05:00
|
|
|
ast::BiLt => {
|
2013-05-19 19:18:56 -05:00
|
|
|
if is_float { ConstFCmp(RealOLT, te1, te2) }
|
2013-05-19 15:03:52 -05:00
|
|
|
else {
|
2013-05-19 19:18:56 -05:00
|
|
|
if signed { ConstICmp(IntSLT, te1, te2) }
|
|
|
|
else { ConstICmp(IntULT, te1, te2) }
|
2013-05-19 15:03:52 -05:00
|
|
|
}
|
|
|
|
},
|
2013-09-01 20:45:37 -05:00
|
|
|
ast::BiLe => {
|
2013-05-19 19:18:56 -05:00
|
|
|
if is_float { ConstFCmp(RealOLE, te1, te2) }
|
2013-05-19 15:03:52 -05:00
|
|
|
else {
|
2013-05-19 19:18:56 -05:00
|
|
|
if signed { ConstICmp(IntSLE, te1, te2) }
|
|
|
|
else { ConstICmp(IntULE, te1, te2) }
|
2013-05-19 15:03:52 -05:00
|
|
|
}
|
|
|
|
},
|
2013-09-01 20:45:37 -05:00
|
|
|
ast::BiNe => {
|
2013-05-19 19:18:56 -05:00
|
|
|
if is_float { ConstFCmp(RealONE, te1, te2) }
|
|
|
|
else { ConstICmp(IntNE, te1, te2) }
|
2013-05-19 15:03:52 -05:00
|
|
|
},
|
2013-09-01 20:45:37 -05:00
|
|
|
ast::BiGe => {
|
2013-05-19 19:18:56 -05:00
|
|
|
if is_float { ConstFCmp(RealOGE, te1, te2) }
|
2013-05-19 15:03:52 -05:00
|
|
|
else {
|
2013-05-19 19:18:56 -05:00
|
|
|
if signed { ConstICmp(IntSGE, te1, te2) }
|
|
|
|
else { ConstICmp(IntUGE, te1, te2) }
|
2013-05-19 15:03:52 -05:00
|
|
|
}
|
|
|
|
},
|
2013-09-01 20:45:37 -05:00
|
|
|
ast::BiGt => {
|
2013-05-19 19:18:56 -05:00
|
|
|
if is_float { ConstFCmp(RealOGT, te1, te2) }
|
2013-05-19 15:03:52 -05:00
|
|
|
else {
|
2013-05-19 19:18:56 -05:00
|
|
|
if signed { ConstICmp(IntSGT, te1, te2) }
|
|
|
|
else { ConstICmp(IntUGT, te1, te2) }
|
2013-05-19 15:03:52 -05:00
|
|
|
}
|
|
|
|
},
|
2013-09-11 12:06:16 -05:00
|
|
|
}, true)
|
2013-05-19 15:03:52 -05:00
|
|
|
},
|
2013-09-01 20:45:37 -05:00
|
|
|
ast::ExprUnary(_, u, e) => {
|
2014-01-27 06:18:36 -06:00
|
|
|
let (te, _) = const_expr(cx, e, is_local);
|
2013-01-10 23:23:07 -06:00
|
|
|
let ty = ty::expr_ty(cx.tcx, e);
|
|
|
|
let is_float = ty::type_is_fp(ty);
|
2013-09-11 12:06:16 -05:00
|
|
|
return (match u {
|
2013-12-31 14:55:39 -06:00
|
|
|
ast::UnBox | ast::UnUniq | ast::UnDeref => {
|
2013-03-08 12:22:48 -06:00
|
|
|
let (dv, _dt) = const_deref(cx, te, ty, true);
|
|
|
|
dv
|
|
|
|
}
|
2013-09-01 20:45:37 -05:00
|
|
|
ast::UnNot => {
|
2013-02-06 17:37:34 -06:00
|
|
|
match ty::get(ty).sty {
|
|
|
|
ty::ty_bool => {
|
|
|
|
// Somewhat questionable, but I believe this is
|
|
|
|
// correct.
|
2013-06-16 05:52:44 -05:00
|
|
|
let te = llvm::LLVMConstTrunc(te, Type::i1().to_ref());
|
2013-02-06 17:37:34 -06:00
|
|
|
let te = llvm::LLVMConstNot(te);
|
2013-06-16 05:52:44 -05:00
|
|
|
llvm::LLVMConstZExt(te, Type::bool().to_ref())
|
2013-02-06 17:37:34 -06:00
|
|
|
}
|
|
|
|
_ => llvm::LLVMConstNot(te),
|
|
|
|
}
|
|
|
|
}
|
2013-09-01 20:45:37 -05:00
|
|
|
ast::UnNeg => {
|
2013-01-10 23:23:07 -06:00
|
|
|
if is_float { llvm::LLVMConstFNeg(te) }
|
|
|
|
else { llvm::LLVMConstNeg(te) }
|
|
|
|
}
|
2013-09-11 12:06:16 -05:00
|
|
|
}, true)
|
2012-07-31 20:34:36 -05:00
|
|
|
}
|
2013-09-01 20:45:37 -05:00
|
|
|
ast::ExprField(base, field, _) => {
|
2013-03-07 14:34:58 -06:00
|
|
|
let bt = ty::expr_ty_adjusted(cx.tcx, base);
|
2013-02-24 17:03:47 -06:00
|
|
|
let brepr = adt::represent_type(cx, bt);
|
2014-01-27 06:18:36 -06:00
|
|
|
let (bv, inlineable) = const_expr(cx, base, is_local);
|
2013-11-21 17:42:55 -06:00
|
|
|
expr::with_field_tys(cx.tcx, bt, None, |discr, field_tys| {
|
2013-06-26 17:56:13 -05:00
|
|
|
let ix = ty::field_idx_strict(cx.tcx, field.name, field_tys);
|
2013-09-11 12:06:16 -05:00
|
|
|
(adt::const_get_field(cx, brepr, bv, discr, ix), inlineable)
|
2013-11-21 17:42:55 -06:00
|
|
|
})
|
2012-08-28 17:54:45 -05:00
|
|
|
}
|
2012-08-08 21:41:50 -05:00
|
|
|
|
2013-09-01 20:45:37 -05:00
|
|
|
ast::ExprIndex(_, base, index) => {
|
2013-03-07 14:34:58 -06:00
|
|
|
let bt = ty::expr_ty_adjusted(cx.tcx, base);
|
2014-01-27 06:18:36 -06:00
|
|
|
let (bv, inlineable) = const_expr(cx, base, is_local);
|
2013-01-10 23:23:07 -06:00
|
|
|
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,
|
2013-05-02 11:28:53 -05:00
|
|
|
"index is not an integer-constant expression")
|
2013-01-10 23:23:07 -06:00
|
|
|
};
|
2013-02-08 03:52:55 -06:00
|
|
|
let (arr, len) = match ty::get(bt).sty {
|
2013-12-31 20:09:50 -06:00
|
|
|
ty::ty_vec(_, vstore) | ty::ty_str(vstore) =>
|
2013-01-10 23:23:07 -06:00
|
|
|
match vstore {
|
|
|
|
ty::vstore_fixed(u) =>
|
|
|
|
(bv, C_uint(cx, u)),
|
2012-08-08 21:41:50 -05:00
|
|
|
|
2013-01-10 23:23:07 -06:00
|
|
|
ty::vstore_slice(_) => {
|
2013-06-27 08:04:22 -05:00
|
|
|
let e1 = const_get_elt(cx, bv, [0]);
|
2013-10-14 23:37:32 -05:00
|
|
|
(const_deref_ptr(cx, e1), const_get_elt(cx, bv, [1]))
|
2013-01-10 23:23:07 -06:00
|
|
|
},
|
|
|
|
_ => cx.sess.span_bug(base.span,
|
2013-05-02 11:28:53 -05:00
|
|
|
"index-expr base must be fixed-size or slice")
|
2012-08-08 21:41:50 -05:00
|
|
|
},
|
2013-01-10 23:23:07 -06:00
|
|
|
_ => cx.sess.span_bug(base.span,
|
2013-05-02 11:28:53 -05:00
|
|
|
"index-expr base must be a vector or string type")
|
2013-01-10 23:23:07 -06:00
|
|
|
};
|
2012-08-09 18:05:34 -05:00
|
|
|
|
2013-02-08 03:52:55 -06:00
|
|
|
let len = llvm::LLVMConstIntGetZExtValue(len) as u64;
|
2013-01-10 23:23:07 -06:00
|
|
|
let len = match ty::get(bt).sty {
|
2013-12-31 20:09:50 -06:00
|
|
|
ty::ty_str(..) => {assert!(len > 0); len - 1},
|
2013-01-10 23:23:07 -06:00
|
|
|
_ => 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,
|
2013-05-02 11:28:53 -05:00
|
|
|
"const index-expr is out of bounds");
|
2013-01-10 23:23:07 -06:00
|
|
|
}
|
2013-09-11 12:06:16 -05:00
|
|
|
(const_get_elt(cx, arr, [iv as c_uint]), inlineable)
|
2012-08-08 21:41:50 -05:00
|
|
|
}
|
2013-09-01 20:45:37 -05:00
|
|
|
ast::ExprCast(base, _) => {
|
2013-01-10 23:23:07 -06:00
|
|
|
let ety = ty::expr_ty(cx.tcx, e);
|
|
|
|
let llty = type_of::type_of(cx, ety);
|
|
|
|
let basety = ty::expr_ty(cx.tcx, base);
|
2014-01-27 06:18:36 -06:00
|
|
|
let (v, inlineable) = const_expr(cx, base, is_local);
|
2013-09-11 12:06:16 -05:00
|
|
|
return (match (expr::cast_type_kind(basety),
|
|
|
|
expr::cast_type_kind(ety)) {
|
2012-08-06 14:34:08 -05:00
|
|
|
|
2013-01-10 23:23:07 -06:00
|
|
|
(expr::cast_integral, expr::cast_integral) => {
|
2013-03-01 03:40:23 -06:00
|
|
|
let s = ty::type_is_signed(basety) as Bool;
|
2013-06-16 05:52:44 -05:00
|
|
|
llvm::LLVMConstIntCast(v, llty.to_ref(), s)
|
2013-01-10 23:23:07 -06:00
|
|
|
}
|
|
|
|
(expr::cast_integral, expr::cast_float) => {
|
|
|
|
if ty::type_is_signed(basety) {
|
2013-06-16 05:52:44 -05:00
|
|
|
llvm::LLVMConstSIToFP(v, llty.to_ref())
|
2013-01-10 23:23:07 -06:00
|
|
|
} else {
|
2013-06-16 05:52:44 -05:00
|
|
|
llvm::LLVMConstUIToFP(v, llty.to_ref())
|
2013-01-10 23:23:07 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
(expr::cast_float, expr::cast_float) => {
|
2013-06-16 05:52:44 -05:00
|
|
|
llvm::LLVMConstFPCast(v, llty.to_ref())
|
2013-01-10 23:23:07 -06:00
|
|
|
}
|
|
|
|
(expr::cast_float, expr::cast_integral) => {
|
2013-06-16 05:52:44 -05:00
|
|
|
if ty::type_is_signed(ety) { llvm::LLVMConstFPToSI(v, llty.to_ref()) }
|
|
|
|
else { llvm::LLVMConstFPToUI(v, llty.to_ref()) }
|
2013-01-10 23:23:07 -06:00
|
|
|
}
|
2013-03-01 03:40:23 -06:00
|
|
|
(expr::cast_enum, expr::cast_integral) |
|
|
|
|
(expr::cast_enum, expr::cast_float) => {
|
2013-02-24 16:38:59 -06:00
|
|
|
let repr = adt::represent_type(cx, basety);
|
2013-06-13 02:19:50 -05:00
|
|
|
let discr = adt::const_get_discrim(cx, repr, v);
|
2013-08-02 14:24:21 -05:00
|
|
|
let iv = C_integral(cx.int_type, discr, false);
|
2013-03-01 03:40:23 -06:00
|
|
|
let ety_cast = expr::cast_type_kind(ety);
|
|
|
|
match ety_cast {
|
|
|
|
expr::cast_integral => {
|
|
|
|
let s = ty::type_is_signed(ety) as Bool;
|
2013-06-16 05:52:44 -05:00
|
|
|
llvm::LLVMConstIntCast(iv, llty.to_ref(), s)
|
2013-03-01 03:40:23 -06:00
|
|
|
}
|
2013-06-16 05:52:44 -05:00
|
|
|
expr::cast_float => llvm::LLVMConstUIToFP(iv, llty.to_ref()),
|
2013-05-19 00:07:44 -05:00
|
|
|
_ => cx.sess.bug("enum cast destination is not \
|
|
|
|
integral or float")
|
2013-03-01 03:40:23 -06:00
|
|
|
}
|
|
|
|
}
|
2013-03-04 17:22:03 -06:00
|
|
|
(expr::cast_pointer, expr::cast_pointer) => {
|
2013-06-16 05:52:44 -05:00
|
|
|
llvm::LLVMConstPointerCast(v, llty.to_ref())
|
2013-03-04 17:22:03 -06:00
|
|
|
}
|
2013-03-07 14:35:43 -06:00
|
|
|
(expr::cast_integral, expr::cast_pointer) => {
|
2013-06-16 05:52:44 -05:00
|
|
|
llvm::LLVMConstIntToPtr(v, llty.to_ref())
|
2013-03-07 14:35:43 -06:00
|
|
|
}
|
2013-01-10 23:23:07 -06:00
|
|
|
_ => {
|
|
|
|
cx.sess.impossible_case(e.span,
|
2013-05-19 00:07:44 -05:00
|
|
|
"bad combination of types for cast")
|
2013-01-10 23:23:07 -06:00
|
|
|
}
|
2013-09-11 12:06:16 -05:00
|
|
|
}, inlineable)
|
2012-08-03 23:44:42 -05:00
|
|
|
}
|
2013-09-01 20:45:37 -05:00
|
|
|
ast::ExprAddrOf(ast::MutImmutable, sub) => {
|
2014-01-27 06:18:36 -06:00
|
|
|
let (e, _) = const_expr(cx, sub, is_local);
|
2013-09-11 12:06:16 -05:00
|
|
|
(const_addr_of(cx, e), false)
|
2012-08-03 23:44:42 -05:00
|
|
|
}
|
2013-09-01 20:45:37 -05:00
|
|
|
ast::ExprTup(ref es) => {
|
2013-02-24 16:38:59 -06:00
|
|
|
let ety = ty::expr_ty(cx.tcx, e);
|
|
|
|
let repr = adt::represent_type(cx, ety);
|
2014-01-27 06:18:36 -06:00
|
|
|
let (vals, inlineable) = map_list(*es);
|
2013-09-11 12:06:16 -05:00
|
|
|
(adt::trans_const(cx, repr, 0, vals), inlineable)
|
2013-01-10 23:23:07 -06:00
|
|
|
}
|
2013-09-01 20:45:37 -05:00
|
|
|
ast::ExprStruct(_, ref fs, ref base_opt) => {
|
2013-01-10 23:23:07 -06:00
|
|
|
let ety = ty::expr_ty(cx.tcx, e);
|
2013-02-24 16:38:59 -06:00
|
|
|
let repr = adt::represent_type(cx, ety);
|
2013-06-13 02:19:50 -05:00
|
|
|
let tcx = cx.tcx;
|
2013-07-26 22:49:42 -05:00
|
|
|
|
|
|
|
let base_val = match *base_opt {
|
2014-01-27 06:18:36 -06:00
|
|
|
Some(base) => Some(const_expr(cx, base, is_local)),
|
2013-07-26 22:49:42 -05:00
|
|
|
None => None
|
|
|
|
};
|
|
|
|
|
2013-11-21 17:42:55 -06:00
|
|
|
expr::with_field_tys(tcx, ety, Some(e.id), |discr, field_tys| {
|
2013-09-11 12:06:16 -05:00
|
|
|
let cs = field_tys.iter().enumerate()
|
2013-08-09 22:09:47 -05:00
|
|
|
.map(|(ix, &field_ty)| {
|
2013-10-28 21:22:42 -05:00
|
|
|
match fs.iter().find(|f| field_ty.ident.name == f.ident.node.name) {
|
2014-01-27 06:18:36 -06:00
|
|
|
Some(f) => const_expr(cx, (*f).expr, is_local),
|
2013-01-10 23:23:07 -06:00
|
|
|
None => {
|
2013-07-26 22:49:42 -05:00
|
|
|
match base_val {
|
2013-09-11 12:06:16 -05:00
|
|
|
Some((bv, inlineable)) => {
|
|
|
|
(adt::const_get_field(cx, repr, bv, discr, ix),
|
|
|
|
inlineable)
|
|
|
|
}
|
2013-07-26 22:49:42 -05:00
|
|
|
None => cx.tcx.sess.span_bug(e.span, "missing struct field")
|
|
|
|
}
|
2013-01-10 23:23:07 -06:00
|
|
|
}
|
|
|
|
}
|
2013-09-11 12:06:16 -05:00
|
|
|
}).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))
|
2013-11-21 17:42:55 -06:00
|
|
|
})
|
2013-01-10 23:23:07 -06:00
|
|
|
}
|
2013-09-01 20:45:37 -05:00
|
|
|
ast::ExprVec(ref es, ast::MutImmutable) => {
|
2014-01-27 06:18:36 -06:00
|
|
|
let (v, _, inlineable) = const_vec(cx, e, *es, is_local);
|
2013-09-11 12:06:16 -05:00
|
|
|
(v, inlineable)
|
2013-01-10 23:23:07 -06:00
|
|
|
}
|
2013-09-01 20:45:37 -05:00
|
|
|
ast::ExprVstore(sub, ast::ExprVstoreSlice) => {
|
2013-03-20 00:17:42 -05:00
|
|
|
match sub.node {
|
2013-09-01 20:45:37 -05:00
|
|
|
ast::ExprLit(ref lit) => {
|
2013-01-10 23:23:07 -06:00
|
|
|
match lit.node {
|
2014-01-27 06:18:36 -06:00
|
|
|
ast::LitStr(..) => { const_expr(cx, sub, is_local) }
|
2014-01-09 07:05:33 -06:00
|
|
|
_ => { cx.sess.span_bug(e.span, "bad const-slice lit") }
|
2013-01-10 23:23:07 -06:00
|
|
|
}
|
|
|
|
}
|
2013-09-01 20:45:37 -05:00
|
|
|
ast::ExprVec(ref es, ast::MutImmutable) => {
|
2014-01-27 06:18:36 -06:00
|
|
|
let (cv, llunitty, _) = const_vec(cx, e, *es, is_local);
|
2013-01-10 23:23:07 -06:00
|
|
|
let llty = val_ty(cv);
|
2013-11-21 17:42:55 -06:00
|
|
|
let gv = "const".with_c_str(|name| {
|
2013-06-16 05:52:44 -05:00
|
|
|
llvm::LLVMAddGlobal(cx.llmod, llty.to_ref(), name)
|
2013-11-21 17:42:55 -06:00
|
|
|
});
|
2013-01-10 23:23:07 -06:00
|
|
|
llvm::LLVMSetInitializer(gv, cv);
|
|
|
|
llvm::LLVMSetGlobalConstant(gv, True);
|
2013-03-28 20:15:35 -05:00
|
|
|
SetLinkage(gv, PrivateLinkage);
|
2013-01-10 23:23:07 -06:00
|
|
|
let p = const_ptrcast(cx, gv, llunitty);
|
2013-10-14 23:37:32 -05:00
|
|
|
(C_struct([p, C_uint(cx, es.len())], false), false)
|
2013-01-10 23:23:07 -06:00
|
|
|
}
|
2013-05-02 11:28:53 -05:00
|
|
|
_ => cx.sess.span_bug(e.span, "bad const-slice expr")
|
2012-11-30 15:25:43 -06:00
|
|
|
}
|
2013-01-10 23:23:07 -06:00
|
|
|
}
|
2013-09-01 20:45:37 -05:00
|
|
|
ast::ExprRepeat(elem, count, _) => {
|
2013-08-12 20:10:29 -05:00
|
|
|
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.")
|
|
|
|
};
|
2014-02-16 03:36:43 -06:00
|
|
|
let vs = vec::from_elem(n, const_expr(cx, elem, is_local).val0());
|
2013-08-12 20:10:29 -05:00
|
|
|
let v = if vs.iter().any(|vi| val_ty(*vi) != llunitty) {
|
2013-10-12 22:19:22 -05:00
|
|
|
C_struct(vs, false)
|
2013-08-12 20:10:29 -05:00
|
|
|
} else {
|
|
|
|
C_array(llunitty, vs)
|
|
|
|
};
|
2013-09-11 12:06:16 -05:00
|
|
|
(v, true)
|
2013-08-12 20:10:29 -05:00
|
|
|
}
|
2013-09-01 20:45:37 -05:00
|
|
|
ast::ExprPath(ref pth) => {
|
2013-08-07 11:47:28 -05:00
|
|
|
// Assert that there are no type parameters in this path.
|
|
|
|
assert!(pth.segments.iter().all(|seg| seg.types.is_empty()));
|
|
|
|
|
2013-06-13 02:19:50 -05:00
|
|
|
let tcx = cx.tcx;
|
2013-12-23 13:15:16 -06:00
|
|
|
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)) => {
|
2013-03-07 14:34:58 -06:00
|
|
|
if !ast_util::is_local(def_id) {
|
2013-03-07 00:30:20 -06:00
|
|
|
let ty = csearch::get_type(cx.tcx, def_id).ty;
|
2013-09-11 12:06:16 -05:00
|
|
|
(base::trans_external_path(cx, def_id, ty), true)
|
2013-03-07 00:30:20 -06:00
|
|
|
} else {
|
2013-03-28 20:39:09 -05:00
|
|
|
assert!(ast_util::is_local(def_id));
|
2013-09-11 12:06:16 -05:00
|
|
|
(base::get_item_val(cx, def_id.node), true)
|
2013-01-18 09:12:07 -06:00
|
|
|
}
|
2013-01-10 23:23:07 -06:00
|
|
|
}
|
2013-12-23 13:15:16 -06:00
|
|
|
Some(ast::DefStatic(def_id, false)) => {
|
2013-01-10 23:23:07 -06:00
|
|
|
get_const_val(cx, def_id)
|
2012-11-30 15:25:43 -06:00
|
|
|
}
|
2013-12-23 13:15:16 -06:00
|
|
|
Some(ast::DefVariant(enum_did, variant_did, _)) => {
|
2013-01-30 18:08:39 -06:00
|
|
|
let ety = ty::expr_ty(cx.tcx, e);
|
2013-02-24 16:38:59 -06:00
|
|
|
let repr = adt::represent_type(cx, ety);
|
|
|
|
let vinfo = ty::enum_variant_with_id(cx.tcx,
|
|
|
|
enum_did,
|
|
|
|
variant_did);
|
2013-09-11 12:06:16 -05:00
|
|
|
(adt::trans_const(cx, repr, vinfo.disr_val, []), true)
|
2013-01-07 05:42:49 -06:00
|
|
|
}
|
2013-12-23 13:15:16 -06:00
|
|
|
Some(ast::DefStruct(_)) => {
|
2013-01-10 23:23:07 -06:00
|
|
|
let ety = ty::expr_ty(cx.tcx, e);
|
|
|
|
let llty = type_of::type_of(cx, ety);
|
2013-09-11 12:06:16 -05:00
|
|
|
(C_null(llty), true)
|
2013-01-10 23:23:07 -06:00
|
|
|
}
|
|
|
|
_ => {
|
2013-05-02 11:28:53 -05:00
|
|
|
cx.sess.span_bug(e.span, "expected a const, fn, struct, or variant def")
|
2013-01-10 23:23:07 -06:00
|
|
|
}
|
2012-11-30 15:25:43 -06:00
|
|
|
}
|
2013-01-10 23:23:07 -06:00
|
|
|
}
|
2014-02-14 02:28:32 -06:00
|
|
|
ast::ExprCall(callee, ref args) => {
|
2013-06-13 02:19:50 -05:00
|
|
|
let tcx = cx.tcx;
|
2013-12-23 13:15:16 -06:00
|
|
|
let opt_def = {
|
|
|
|
let def_map = tcx.def_map.borrow();
|
|
|
|
def_map.get().find_copy(&callee.id)
|
|
|
|
};
|
|
|
|
match opt_def {
|
|
|
|
Some(ast::DefStruct(_)) => {
|
2013-02-24 16:38:59 -06:00
|
|
|
let ety = ty::expr_ty(cx.tcx, e);
|
|
|
|
let repr = adt::represent_type(cx, ety);
|
2014-01-27 06:18:36 -06:00
|
|
|
let (arg_vals, inlineable) = map_list(*args);
|
2013-09-11 12:06:16 -05:00
|
|
|
(adt::trans_const(cx, repr, 0, arg_vals), inlineable)
|
2013-02-24 16:38:59 -06:00
|
|
|
}
|
2013-12-23 13:15:16 -06:00
|
|
|
Some(ast::DefVariant(enum_did, variant_did, _)) => {
|
2013-02-24 16:38:59 -06:00
|
|
|
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);
|
2014-01-27 06:18:36 -06:00
|
|
|
let (arg_vals, inlineable) = map_list(*args);
|
2013-09-11 12:06:16 -05:00
|
|
|
(adt::trans_const(cx, repr, vinfo.disr_val, arg_vals),
|
|
|
|
inlineable)
|
2013-02-24 16:38:59 -06:00
|
|
|
}
|
2013-05-02 11:28:53 -05:00
|
|
|
_ => cx.sess.span_bug(e.span, "expected a struct or variant def")
|
2013-02-24 16:38:59 -06:00
|
|
|
}
|
2013-01-10 23:23:07 -06:00
|
|
|
}
|
2014-01-27 06:18:36 -06:00
|
|
|
ast::ExprParen(e) => { const_expr(cx, e, is_local) }
|
2013-01-10 23:23:07 -06:00
|
|
|
_ => cx.sess.span_bug(e.span,
|
2013-05-02 11:28:53 -05:00
|
|
|
"bad constant expression type in consts::const_expr")
|
2013-01-10 23:23:07 -06:00
|
|
|
};
|
|
|
|
}
|
2012-07-31 20:34:36 -05:00
|
|
|
}
|
|
|
|
|
2013-12-19 18:47:15 -06:00
|
|
|
pub fn trans_const(ccx: @CrateContext, m: ast::Mutability, id: ast::NodeId) {
|
2013-01-10 23:23:07 -06:00
|
|
|
unsafe {
|
2013-06-16 23:23:24 -05:00
|
|
|
let _icx = push_ctxt("trans_const");
|
2013-01-10 23:23:07 -06:00
|
|
|
let g = base::get_item_val(ccx, id);
|
2012-12-30 22:30:23 -06:00
|
|
|
// At this point, get_item_val has already translated the
|
|
|
|
// constant's initializer to determine its LLVM type.
|
2013-12-18 19:08:56 -06:00
|
|
|
let const_values = ccx.const_values.borrow();
|
|
|
|
let v = const_values.get().get_copy(&id);
|
2013-01-10 23:23:07 -06:00
|
|
|
llvm::LLVMSetInitializer(g, v);
|
2013-09-01 20:45:37 -05:00
|
|
|
if m != ast::MutMutable {
|
2013-06-21 20:46:34 -05:00
|
|
|
llvm::LLVMSetGlobalConstant(g, True);
|
|
|
|
}
|
2013-01-10 23:23:07 -06:00
|
|
|
}
|
2012-07-31 20:34:36 -05:00
|
|
|
}
|