2015-10-21 17:42:25 -04:00
|
|
|
// Copyright 2012-2014 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.
|
|
|
|
|
2016-04-21 16:15:56 +03:00
|
|
|
use llvm::{self, ValueRef};
|
2017-04-13 16:40:03 +03:00
|
|
|
use rustc::middle::const_val::{ConstEvalErr, ConstVal, ErrKind};
|
2016-03-15 12:33:13 +01:00
|
|
|
use rustc_const_math::ConstInt::*;
|
2017-10-15 21:37:09 +02:00
|
|
|
use rustc_const_math::{ConstInt, ConstMathErr, MAX_F32_PLUS_HALF_ULP};
|
2016-04-21 16:15:56 +03:00
|
|
|
use rustc::hir::def_id::DefId;
|
2016-05-11 04:14:41 +03:00
|
|
|
use rustc::infer::TransNormalize;
|
2017-09-27 23:23:16 -04:00
|
|
|
use rustc::traits;
|
2016-09-19 23:50:00 +03:00
|
|
|
use rustc::mir;
|
2017-12-01 14:31:47 +02:00
|
|
|
use rustc::mir::tcx::PlaceTy;
|
2017-03-10 06:25:51 +02:00
|
|
|
use rustc::ty::{self, Ty, TyCtxt, TypeFoldable};
|
2017-09-13 00:33:56 +03:00
|
|
|
use rustc::ty::layout::{self, LayoutOf, Size};
|
2016-04-21 16:15:56 +03:00
|
|
|
use rustc::ty::cast::{CastTy, IntTy};
|
2017-12-01 09:26:13 -05:00
|
|
|
use rustc::ty::subst::{Kind, Substs};
|
2017-10-15 22:28:49 +02:00
|
|
|
use rustc_apfloat::{ieee, Float, Status};
|
2016-06-07 17:28:36 +03:00
|
|
|
use rustc_data_structures::indexed_vec::{Idx, IndexVec};
|
2017-09-16 16:39:53 +03:00
|
|
|
use base;
|
2017-06-23 17:48:29 +03:00
|
|
|
use abi::{self, Abi};
|
2017-03-08 18:33:21 +02:00
|
|
|
use callee;
|
2016-12-31 16:00:24 -07:00
|
|
|
use builder::Builder;
|
2018-01-05 07:01:54 +02:00
|
|
|
use common::{self, CodegenCx, const_get_elt, val_ty};
|
2017-09-23 15:04:37 +03:00
|
|
|
use common::{C_array, C_bool, C_bytes, C_int, C_uint, C_uint_big, C_u32, C_u64};
|
2017-06-25 12:42:55 +03:00
|
|
|
use common::{C_null, C_struct, C_str_slice, C_undef, C_usize, C_vector, C_fat_ptr};
|
2016-12-31 16:00:24 -07:00
|
|
|
use common::const_to_opt_u128;
|
2016-08-16 17:41:38 +03:00
|
|
|
use consts;
|
2017-09-21 20:40:50 +03:00
|
|
|
use type_of::LayoutLlvmExt;
|
2016-03-22 19:23:36 +02:00
|
|
|
use type_::Type;
|
2016-04-21 16:15:56 +03:00
|
|
|
use value::Value;
|
2015-11-16 19:57:57 +02:00
|
|
|
|
2016-12-20 23:05:21 +02:00
|
|
|
use syntax_pos::Span;
|
2017-07-30 20:43:53 +03:00
|
|
|
use syntax::ast;
|
2015-10-21 17:42:25 -04:00
|
|
|
|
2016-09-12 01:53:43 +03:00
|
|
|
use std::fmt;
|
2016-04-21 16:15:56 +03:00
|
|
|
use std::ptr;
|
2016-01-08 01:15:59 +02:00
|
|
|
|
2016-04-21 16:15:56 +03:00
|
|
|
use super::operand::{OperandRef, OperandValue};
|
2016-05-03 00:26:41 +03:00
|
|
|
use super::MirContext;
|
2015-11-16 18:41:16 +01:00
|
|
|
|
2016-04-21 16:15:56 +03:00
|
|
|
/// A sized constant rvalue.
|
|
|
|
/// The LLVM type might not be the same for a single Rust type,
|
|
|
|
/// e.g. each enum variant would have its own LLVM struct type.
|
|
|
|
#[derive(Copy, Clone)]
|
2016-04-26 23:54:38 +03:00
|
|
|
pub struct Const<'tcx> {
|
|
|
|
pub llval: ValueRef,
|
|
|
|
pub ty: Ty<'tcx>
|
2016-04-21 16:15:56 +03:00
|
|
|
}
|
2015-11-16 18:41:16 +01:00
|
|
|
|
2017-06-18 16:59:51 +03:00
|
|
|
impl<'a, 'tcx> Const<'tcx> {
|
2016-04-26 23:54:38 +03:00
|
|
|
pub fn new(llval: ValueRef, ty: Ty<'tcx>) -> Const<'tcx> {
|
2016-04-21 16:15:56 +03:00
|
|
|
Const {
|
2017-08-06 22:54:09 -07:00
|
|
|
llval,
|
|
|
|
ty,
|
2015-11-08 19:11:11 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-01-05 07:01:54 +02:00
|
|
|
pub fn from_constint(ccx: &CodegenCx<'a, 'tcx>, ci: &ConstInt) -> Const<'tcx> {
|
2018-01-05 06:58:34 +02:00
|
|
|
let tcx = ccx.tcx;
|
2017-02-02 06:44:30 +02:00
|
|
|
let (llval, ty) = match *ci {
|
2017-08-05 12:27:28 +03:00
|
|
|
I8(v) => (C_int(Type::i8(ccx), v as i64), tcx.types.i8),
|
|
|
|
I16(v) => (C_int(Type::i16(ccx), v as i64), tcx.types.i16),
|
|
|
|
I32(v) => (C_int(Type::i32(ccx), v as i64), tcx.types.i32),
|
|
|
|
I64(v) => (C_int(Type::i64(ccx), v as i64), tcx.types.i64),
|
2017-09-23 15:04:37 +03:00
|
|
|
I128(v) => (C_uint_big(Type::i128(ccx), v as u128), tcx.types.i128),
|
2017-08-05 12:27:28 +03:00
|
|
|
Isize(v) => (C_int(Type::isize(ccx), v.as_i64()), tcx.types.isize),
|
|
|
|
U8(v) => (C_uint(Type::i8(ccx), v as u64), tcx.types.u8),
|
|
|
|
U16(v) => (C_uint(Type::i16(ccx), v as u64), tcx.types.u16),
|
|
|
|
U32(v) => (C_uint(Type::i32(ccx), v as u64), tcx.types.u32),
|
|
|
|
U64(v) => (C_uint(Type::i64(ccx), v), tcx.types.u64),
|
2017-09-23 15:04:37 +03:00
|
|
|
U128(v) => (C_uint_big(Type::i128(ccx), v), tcx.types.u128),
|
2017-08-05 12:27:28 +03:00
|
|
|
Usize(v) => (C_uint(Type::isize(ccx), v.as_u64()), tcx.types.usize),
|
2017-02-02 06:44:30 +02:00
|
|
|
};
|
|
|
|
Const { llval: llval, ty: ty }
|
|
|
|
}
|
|
|
|
|
2016-04-21 16:15:56 +03:00
|
|
|
/// Translate ConstVal into a LLVM constant value.
|
2018-01-05 07:01:54 +02:00
|
|
|
pub fn from_constval(ccx: &CodegenCx<'a, 'tcx>,
|
2017-06-18 16:59:51 +03:00
|
|
|
cv: &ConstVal,
|
|
|
|
ty: Ty<'tcx>)
|
|
|
|
-> Const<'tcx> {
|
2017-09-20 23:07:47 +03:00
|
|
|
let llty = ccx.layout_of(ty).llvm_type(ccx);
|
2017-08-04 00:41:44 +03:00
|
|
|
let val = match *cv {
|
2017-07-30 07:32:11 +03:00
|
|
|
ConstVal::Float(v) => {
|
2017-07-30 20:43:53 +03:00
|
|
|
let bits = match v.ty {
|
|
|
|
ast::FloatTy::F32 => C_u32(ccx, v.bits as u32),
|
|
|
|
ast::FloatTy::F64 => C_u64(ccx, v.bits as u64)
|
2017-07-30 07:32:11 +03:00
|
|
|
};
|
2017-07-30 20:43:53 +03:00
|
|
|
consts::bitcast(bits, llty)
|
2017-07-30 07:32:11 +03:00
|
|
|
}
|
2015-12-28 21:18:24 +02:00
|
|
|
ConstVal::Bool(v) => C_bool(ccx, v),
|
2017-02-02 06:44:30 +02:00
|
|
|
ConstVal::Integral(ref i) => return Const::from_constint(ccx, i),
|
2015-12-28 21:18:24 +02:00
|
|
|
ConstVal::Str(ref v) => C_str_slice(ccx, v.clone()),
|
2017-06-01 21:50:53 +03:00
|
|
|
ConstVal::ByteStr(v) => {
|
|
|
|
consts::addr_of(ccx, C_bytes(ccx, v.data), ccx.align_of(ty), "byte_str")
|
|
|
|
}
|
2017-08-05 12:27:28 +03:00
|
|
|
ConstVal::Char(c) => C_uint(Type::char(ccx), c as u64),
|
2017-06-18 16:59:51 +03:00
|
|
|
ConstVal::Function(..) => C_undef(llty),
|
2017-04-19 15:16:19 +03:00
|
|
|
ConstVal::Variant(_) |
|
2017-08-07 08:08:53 +03:00
|
|
|
ConstVal::Aggregate(..) |
|
|
|
|
ConstVal::Unevaluated(..) => {
|
2017-03-07 16:09:01 +01:00
|
|
|
bug!("MIR must not use `{:?}` (aggregates are expanded to MIR rvalues)", cv)
|
|
|
|
}
|
2016-04-21 16:15:56 +03:00
|
|
|
};
|
|
|
|
|
|
|
|
assert!(!ty.has_erasable_regions());
|
|
|
|
|
|
|
|
Const::new(val, ty)
|
|
|
|
}
|
|
|
|
|
2018-01-05 07:01:54 +02:00
|
|
|
fn get_field(&self, ccx: &CodegenCx<'a, 'tcx>, i: usize) -> ValueRef {
|
2017-10-06 10:25:35 +03:00
|
|
|
let layout = ccx.layout_of(self.ty);
|
2017-10-09 02:31:06 +03:00
|
|
|
let field = layout.field(ccx, i);
|
|
|
|
if field.is_zst() {
|
|
|
|
return C_undef(field.immediate_llvm_type(ccx));
|
|
|
|
}
|
2017-12-13 01:57:56 +02:00
|
|
|
let offset = layout.fields.offset(i);
|
2017-10-09 02:31:06 +03:00
|
|
|
match layout.abi {
|
2017-12-13 01:57:56 +02:00
|
|
|
layout::Abi::Scalar(_) |
|
|
|
|
layout::Abi::ScalarPair(..) |
|
|
|
|
layout::Abi::Vector { .. }
|
|
|
|
if offset.bytes() == 0 && field.size == layout.size => self.llval,
|
|
|
|
|
2017-10-09 02:31:06 +03:00
|
|
|
layout::Abi::ScalarPair(ref a, ref b) => {
|
|
|
|
if offset.bytes() == 0 {
|
2017-12-13 01:57:56 +02:00
|
|
|
assert_eq!(field.size, a.value.size(ccx));
|
|
|
|
const_get_elt(self.llval, 0)
|
2017-10-09 02:31:06 +03:00
|
|
|
} else {
|
|
|
|
assert_eq!(offset, a.value.size(ccx)
|
|
|
|
.abi_align(b.value.align(ccx)));
|
|
|
|
assert_eq!(field.size, b.value.size(ccx));
|
|
|
|
const_get_elt(self.llval, 1)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
_ => {
|
|
|
|
const_get_elt(self.llval, layout.llvm_field_index(i))
|
|
|
|
}
|
2017-10-06 10:25:35 +03:00
|
|
|
}
|
2017-06-18 16:59:51 +03:00
|
|
|
}
|
|
|
|
|
2018-01-05 07:01:54 +02:00
|
|
|
fn get_pair(&self, ccx: &CodegenCx<'a, 'tcx>) -> (ValueRef, ValueRef) {
|
2017-06-18 16:59:51 +03:00
|
|
|
(self.get_field(ccx, 0), self.get_field(ccx, 1))
|
2016-05-25 11:55:44 +03:00
|
|
|
}
|
|
|
|
|
2018-01-05 07:01:54 +02:00
|
|
|
fn get_fat_ptr(&self, ccx: &CodegenCx<'a, 'tcx>) -> (ValueRef, ValueRef) {
|
2016-05-25 11:55:44 +03:00
|
|
|
assert_eq!(abi::FAT_PTR_ADDR, 0);
|
|
|
|
assert_eq!(abi::FAT_PTR_EXTRA, 1);
|
2017-06-18 16:59:51 +03:00
|
|
|
self.get_pair(ccx)
|
2016-04-21 16:15:56 +03:00
|
|
|
}
|
|
|
|
|
2017-12-01 14:39:51 +02:00
|
|
|
fn as_place(&self) -> ConstPlace<'tcx> {
|
2017-12-01 14:31:47 +02:00
|
|
|
ConstPlace {
|
2016-04-21 16:15:56 +03:00
|
|
|
base: Base::Value(self.llval),
|
|
|
|
llextra: ptr::null_mut(),
|
|
|
|
ty: self.ty
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-01-05 07:01:54 +02:00
|
|
|
pub fn to_operand(&self, ccx: &CodegenCx<'a, 'tcx>) -> OperandRef<'tcx> {
|
2017-10-05 04:22:23 +03:00
|
|
|
let layout = ccx.layout_of(self.ty);
|
|
|
|
let llty = layout.immediate_llvm_type(ccx);
|
2016-04-21 16:15:56 +03:00
|
|
|
let llvalty = val_ty(self.llval);
|
|
|
|
|
2017-10-06 10:25:35 +03:00
|
|
|
let val = if llty == llvalty && layout.is_llvm_scalar_pair() {
|
2017-10-09 19:56:41 +03:00
|
|
|
OperandValue::Pair(
|
|
|
|
const_get_elt(self.llval, 0),
|
|
|
|
const_get_elt(self.llval, 1))
|
2017-10-05 04:22:23 +03:00
|
|
|
} else if llty == llvalty && layout.is_llvm_immediate() {
|
2016-04-21 16:15:56 +03:00
|
|
|
// If the types match, we can use the value directly.
|
|
|
|
OperandValue::Immediate(self.llval)
|
|
|
|
} else {
|
|
|
|
// Otherwise, or if the value is not immediate, we create
|
|
|
|
// a constant LLVM global and cast its address if necessary.
|
2017-03-02 05:35:25 +02:00
|
|
|
let align = ccx.align_of(self.ty);
|
2016-04-21 16:15:56 +03:00
|
|
|
let ptr = consts::addr_of(ccx, self.llval, align, "const");
|
2017-10-09 02:31:06 +03:00
|
|
|
OperandValue::Ref(consts::ptrcast(ptr, layout.llvm_type(ccx).ptr_to()),
|
2017-12-01 19:16:39 +02:00
|
|
|
layout.align)
|
2016-04-21 16:15:56 +03:00
|
|
|
};
|
|
|
|
|
|
|
|
OperandRef {
|
2017-08-06 22:54:09 -07:00
|
|
|
val,
|
2017-12-01 19:16:39 +02:00
|
|
|
layout
|
2016-04-21 16:15:56 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-09-12 01:53:43 +03:00
|
|
|
impl<'tcx> fmt::Debug for Const<'tcx> {
|
|
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
|
|
write!(f, "Const({:?}: {:?})", Value(self.llval), self.ty)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-04-21 16:15:56 +03:00
|
|
|
#[derive(Copy, Clone)]
|
|
|
|
enum Base {
|
|
|
|
/// A constant value without an unique address.
|
|
|
|
Value(ValueRef),
|
|
|
|
|
2016-05-08 00:28:52 +03:00
|
|
|
/// String literal base pointer (cast from array).
|
|
|
|
Str(ValueRef),
|
|
|
|
|
2016-04-21 16:15:56 +03:00
|
|
|
/// The address of a static.
|
|
|
|
Static(ValueRef)
|
|
|
|
}
|
|
|
|
|
2017-12-01 14:39:51 +02:00
|
|
|
/// An place as seen from a constant.
|
2016-04-21 16:15:56 +03:00
|
|
|
#[derive(Copy, Clone)]
|
2017-12-01 14:31:47 +02:00
|
|
|
struct ConstPlace<'tcx> {
|
2016-04-21 16:15:56 +03:00
|
|
|
base: Base,
|
|
|
|
llextra: ValueRef,
|
|
|
|
ty: Ty<'tcx>
|
|
|
|
}
|
|
|
|
|
2017-12-01 14:31:47 +02:00
|
|
|
impl<'tcx> ConstPlace<'tcx> {
|
2016-04-21 16:15:56 +03:00
|
|
|
fn to_const(&self, span: Span) -> Const<'tcx> {
|
|
|
|
match self.base {
|
|
|
|
Base::Value(val) => Const::new(val, self.ty),
|
2016-05-08 00:28:52 +03:00
|
|
|
Base::Str(ptr) => {
|
|
|
|
span_bug!(span, "loading from `str` ({:?}) in constant",
|
|
|
|
Value(ptr))
|
|
|
|
}
|
2016-04-21 16:15:56 +03:00
|
|
|
Base::Static(val) => {
|
|
|
|
span_bug!(span, "loading from `static` ({:?}) in constant",
|
|
|
|
Value(val))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-01-05 07:01:54 +02:00
|
|
|
pub fn len<'a>(&self, ccx: &CodegenCx<'a, 'tcx>) -> ValueRef {
|
2016-04-21 16:15:56 +03:00
|
|
|
match self.ty.sty {
|
2017-08-05 16:11:24 +03:00
|
|
|
ty::TyArray(_, n) => {
|
|
|
|
C_usize(ccx, n.val.to_const_int().unwrap().to_u64().unwrap())
|
|
|
|
}
|
2016-04-21 16:15:56 +03:00
|
|
|
ty::TySlice(_) | ty::TyStr => {
|
|
|
|
assert!(self.llextra != ptr::null_mut());
|
|
|
|
self.llextra
|
|
|
|
}
|
2017-12-01 14:31:47 +02:00
|
|
|
_ => bug!("unexpected type `{}` in ConstPlace::len", self.ty)
|
2016-04-21 16:15:56 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Machinery for translating a constant's MIR to LLVM values.
|
|
|
|
/// FIXME(eddyb) use miri and lower its allocations to LLVM.
|
|
|
|
struct MirConstContext<'a, 'tcx: 'a> {
|
2018-01-05 07:01:54 +02:00
|
|
|
ccx: &'a CodegenCx<'a, 'tcx>,
|
2016-05-03 00:26:41 +03:00
|
|
|
mir: &'a mir::Mir<'tcx>,
|
2016-04-21 16:15:56 +03:00
|
|
|
|
|
|
|
/// Type parameters for const fn and associated constants.
|
|
|
|
substs: &'tcx Substs<'tcx>,
|
|
|
|
|
2016-06-20 23:55:14 +03:00
|
|
|
/// Values of locals in a constant or const fn.
|
2017-07-31 17:42:42 +03:00
|
|
|
locals: IndexVec<mir::Local, Option<Result<Const<'tcx>, ConstEvalErr<'tcx>>>>
|
2016-04-21 16:15:56 +03:00
|
|
|
}
|
|
|
|
|
2017-07-31 17:42:42 +03:00
|
|
|
fn add_err<'tcx, U, V>(failure: &mut Result<U, ConstEvalErr<'tcx>>,
|
|
|
|
value: &Result<V, ConstEvalErr<'tcx>>)
|
|
|
|
{
|
|
|
|
if let &Err(ref err) = value {
|
|
|
|
if failure.is_ok() {
|
|
|
|
*failure = Err(err.clone());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2016-04-21 16:15:56 +03:00
|
|
|
|
|
|
|
impl<'a, 'tcx> MirConstContext<'a, 'tcx> {
|
2018-01-05 07:01:54 +02:00
|
|
|
fn new(ccx: &'a CodegenCx<'a, 'tcx>,
|
2016-05-03 00:26:41 +03:00
|
|
|
mir: &'a mir::Mir<'tcx>,
|
|
|
|
substs: &'tcx Substs<'tcx>,
|
2017-07-31 17:42:42 +03:00
|
|
|
args: IndexVec<mir::Local, Result<Const<'tcx>, ConstEvalErr<'tcx>>>)
|
2016-04-21 16:15:56 +03:00
|
|
|
-> MirConstContext<'a, 'tcx> {
|
2016-06-20 23:55:14 +03:00
|
|
|
let mut context = MirConstContext {
|
2017-08-06 22:54:09 -07:00
|
|
|
ccx,
|
|
|
|
mir,
|
|
|
|
substs,
|
2016-09-25 01:38:27 +02:00
|
|
|
locals: (0..mir.local_decls.len()).map(|_| None).collect(),
|
2016-06-20 23:55:14 +03:00
|
|
|
};
|
|
|
|
for (i, arg) in args.into_iter().enumerate() {
|
2016-09-29 01:11:54 +02:00
|
|
|
// Locals after local 0 are the function arguments
|
2016-09-25 01:38:27 +02:00
|
|
|
let index = mir::Local::new(i + 1);
|
2016-06-20 23:55:14 +03:00
|
|
|
context.locals[index] = Some(arg);
|
2016-05-03 00:26:41 +03:00
|
|
|
}
|
2016-06-20 23:55:14 +03:00
|
|
|
context
|
2016-05-03 00:26:41 +03:00
|
|
|
}
|
2016-04-21 16:15:56 +03:00
|
|
|
|
2018-01-05 07:01:54 +02:00
|
|
|
fn trans_def(ccx: &'a CodegenCx<'a, 'tcx>,
|
2017-02-08 18:31:03 +01:00
|
|
|
def_id: DefId,
|
|
|
|
substs: &'tcx Substs<'tcx>,
|
2017-07-31 17:42:42 +03:00
|
|
|
args: IndexVec<mir::Local, Result<Const<'tcx>, ConstEvalErr<'tcx>>>)
|
2017-02-15 15:00:20 +02:00
|
|
|
-> Result<Const<'tcx>, ConstEvalErr<'tcx>> {
|
2018-01-05 06:58:34 +02:00
|
|
|
let instance = ty::Instance::resolve(ccx.tcx,
|
2017-09-28 08:36:34 -04:00
|
|
|
ty::ParamEnv::empty(traits::Reveal::All),
|
|
|
|
def_id,
|
|
|
|
substs).unwrap();
|
2018-01-05 06:58:34 +02:00
|
|
|
let mir = ccx.tcx.instance_mir(instance.def);
|
2016-05-03 00:26:41 +03:00
|
|
|
MirConstContext::new(ccx, &mir, instance.substs, args).trans()
|
2016-04-21 16:15:56 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
fn monomorphize<T>(&self, value: &T) -> T
|
2016-05-11 04:14:41 +03:00
|
|
|
where T: TransNormalize<'tcx>
|
2016-04-21 16:15:56 +03:00
|
|
|
{
|
2018-01-05 06:58:34 +02:00
|
|
|
self.ccx.tcx.trans_apply_param_substs(self.substs, value)
|
2016-04-21 16:15:56 +03:00
|
|
|
}
|
|
|
|
|
2017-02-15 15:00:20 +02:00
|
|
|
fn trans(&mut self) -> Result<Const<'tcx>, ConstEvalErr<'tcx>> {
|
2018-01-05 06:58:34 +02:00
|
|
|
let tcx = self.ccx.tcx;
|
2016-04-21 16:15:56 +03:00
|
|
|
let mut bb = mir::START_BLOCK;
|
2016-06-05 14:38:29 +03:00
|
|
|
|
|
|
|
// Make sure to evaluate all statemenets to
|
|
|
|
// report as many errors as we possibly can.
|
|
|
|
let mut failure = Ok(());
|
|
|
|
|
2016-04-21 16:15:56 +03:00
|
|
|
loop {
|
2016-06-07 21:20:50 +03:00
|
|
|
let data = &self.mir[bb];
|
2016-04-21 16:15:56 +03:00
|
|
|
for statement in &data.statements {
|
2016-06-07 19:21:56 +03:00
|
|
|
let span = statement.source_info.span;
|
2016-04-21 16:15:56 +03:00
|
|
|
match statement.kind {
|
|
|
|
mir::StatementKind::Assign(ref dest, ref rvalue) => {
|
2016-08-05 15:59:51 -07:00
|
|
|
let ty = dest.ty(self.mir, tcx);
|
2016-04-21 16:15:56 +03:00
|
|
|
let ty = self.monomorphize(&ty).to_ty(tcx);
|
2017-07-31 17:42:42 +03:00
|
|
|
let value = self.const_rvalue(rvalue, ty, span);
|
|
|
|
add_err(&mut failure, &value);
|
|
|
|
self.store(dest, value, span);
|
2016-04-21 16:15:56 +03:00
|
|
|
}
|
2016-08-14 06:34:14 +03:00
|
|
|
mir::StatementKind::StorageLive(_) |
|
2016-09-15 18:17:58 -07:00
|
|
|
mir::StatementKind::StorageDead(_) |
|
2017-07-11 14:01:07 -07:00
|
|
|
mir::StatementKind::Validate(..) |
|
Add `EndRegion` statement kind to MIR.
* Emit `EndRegion` for every code-extent for which we observe a
borrow. To do this, we needed to thread source info back through
to `fn in_scope`, which makes this commit a bit more painful than
one might have expected.
* There is `end_region` emission in `Builder::pop_scope` and in
`Builder::exit_scope`; the first handles falling out of a scope
normally, the second handles e.g. `break`.
* Remove `EndRegion` statements during the erase_regions mir
transformation.
* Preallocate the terminator block, and throw an `Unreachable` marker
on it from the outset. Then overwrite that Terminator as necessary
on demand.
* Instead of marking the scope as needs_cleanup after seeing a
borrow, just treat every scope in the chain as being part of the
diverge_block (after any *one* of them has separately signalled
that it needs cleanup, e.g. due to having a destructor to run).
* Allow for resume terminators to be patched when looking up drop flags.
(In particular, `MirPatch::new` has an explicit code path,
presumably previously unreachable, that patches up such resume
terminators.)
* Make `Scope` implement `Debug` trait.
* Expanded a stray comment: we do not emit StorageDead on diverging
paths, but that end behavior might not be desirable.
2017-02-17 13:38:42 +01:00
|
|
|
mir::StatementKind::EndRegion(_) |
|
2016-09-15 18:17:58 -07:00
|
|
|
mir::StatementKind::Nop => {}
|
2017-02-15 21:21:36 +02:00
|
|
|
mir::StatementKind::InlineAsm { .. } |
|
2016-08-04 16:14:33 -07:00
|
|
|
mir::StatementKind::SetDiscriminant{ .. } => {
|
2017-02-15 21:21:36 +02:00
|
|
|
span_bug!(span, "{:?} should not appear in constants?", statement.kind);
|
2016-08-04 16:14:33 -07:00
|
|
|
}
|
2016-04-21 16:15:56 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
let terminator = data.terminator();
|
2016-06-07 19:21:56 +03:00
|
|
|
let span = terminator.source_info.span;
|
2016-04-21 16:15:56 +03:00
|
|
|
bb = match terminator.kind {
|
|
|
|
mir::TerminatorKind::Drop { target, .. } | // No dropping.
|
|
|
|
mir::TerminatorKind::Goto { target } => target,
|
|
|
|
mir::TerminatorKind::Return => {
|
2016-06-05 14:38:29 +03:00
|
|
|
failure?;
|
2017-12-01 14:39:51 +02:00
|
|
|
return self.locals[mir::RETURN_PLACE].clone().unwrap_or_else(|| {
|
2016-04-21 16:15:56 +03:00
|
|
|
span_bug!(span, "no returned value in constant");
|
2017-07-31 17:42:42 +03:00
|
|
|
});
|
2016-04-21 16:15:56 +03:00
|
|
|
}
|
|
|
|
|
2016-05-25 08:39:32 +03:00
|
|
|
mir::TerminatorKind::Assert { ref cond, expected, ref msg, target, .. } => {
|
2016-04-21 16:15:56 +03:00
|
|
|
let cond = self.const_operand(cond, span)?;
|
2016-05-25 08:39:32 +03:00
|
|
|
let cond_bool = common::const_to_uint(cond.llval) != 0;
|
|
|
|
if cond_bool != expected {
|
|
|
|
let err = match *msg {
|
2016-05-26 22:09:48 +03:00
|
|
|
mir::AssertMessage::BoundsCheck { ref len, ref index } => {
|
|
|
|
let len = self.const_operand(len, span)?;
|
|
|
|
let index = self.const_operand(index, span)?;
|
|
|
|
ErrKind::IndexOutOfBounds {
|
|
|
|
len: common::const_to_uint(len.llval),
|
|
|
|
index: common::const_to_uint(index.llval)
|
|
|
|
}
|
2016-05-25 08:39:32 +03:00
|
|
|
}
|
|
|
|
mir::AssertMessage::Math(ref err) => {
|
|
|
|
ErrKind::Math(err.clone())
|
|
|
|
}
|
2016-12-26 14:34:03 +01:00
|
|
|
mir::AssertMessage::GeneratorResumedAfterReturn |
|
2017-07-05 14:57:26 -07:00
|
|
|
mir::AssertMessage::GeneratorResumedAfterPanic =>
|
2016-12-26 14:34:03 +01:00
|
|
|
span_bug!(span, "{:?} should not appear in constants?", msg),
|
2016-05-25 08:39:32 +03:00
|
|
|
};
|
2016-08-16 17:41:38 +03:00
|
|
|
|
2017-04-13 16:40:03 +03:00
|
|
|
let err = ConstEvalErr { span: span, kind: err };
|
|
|
|
err.report(tcx, span, "expression");
|
2016-08-16 17:41:38 +03:00
|
|
|
failure = Err(err);
|
2016-04-21 16:15:56 +03:00
|
|
|
}
|
2016-05-25 08:39:32 +03:00
|
|
|
target
|
2016-04-21 16:15:56 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
mir::TerminatorKind::Call { ref func, ref args, ref destination, .. } => {
|
2016-08-08 13:35:10 -07:00
|
|
|
let fn_ty = func.ty(self.mir, tcx);
|
2016-04-21 16:15:56 +03:00
|
|
|
let fn_ty = self.monomorphize(&fn_ty);
|
2017-02-08 18:31:03 +01:00
|
|
|
let (def_id, substs) = match fn_ty.sty {
|
2017-05-13 17:11:52 +03:00
|
|
|
ty::TyFnDef(def_id, substs) => (def_id, substs),
|
2016-04-21 16:15:56 +03:00
|
|
|
_ => span_bug!(span, "calling {:?} (of type {}) in constant",
|
|
|
|
func, fn_ty)
|
|
|
|
};
|
|
|
|
|
2017-06-23 17:48:29 +03:00
|
|
|
let mut arg_vals = IndexVec::with_capacity(args.len());
|
2016-06-05 14:38:29 +03:00
|
|
|
for arg in args {
|
2017-07-31 17:42:42 +03:00
|
|
|
let arg_val = self.const_operand(arg, span);
|
|
|
|
add_err(&mut failure, &arg_val);
|
|
|
|
arg_vals.push(arg_val);
|
2016-06-05 14:38:29 +03:00
|
|
|
}
|
2016-04-21 16:15:56 +03:00
|
|
|
if let Some((ref dest, target)) = *destination {
|
2017-07-31 17:42:42 +03:00
|
|
|
let result = if fn_ty.fn_sig(tcx).abi() == Abi::RustIntrinsic {
|
2017-09-01 09:24:02 -07:00
|
|
|
match &tcx.item_name(def_id)[..] {
|
2017-06-23 17:48:29 +03:00
|
|
|
"size_of" => {
|
2017-08-05 12:27:28 +03:00
|
|
|
let llval = C_usize(self.ccx,
|
2017-06-01 21:50:53 +03:00
|
|
|
self.ccx.size_of(substs.type_at(0)).bytes());
|
2017-07-31 17:42:42 +03:00
|
|
|
Ok(Const::new(llval, tcx.types.usize))
|
2017-06-23 17:48:29 +03:00
|
|
|
}
|
|
|
|
"min_align_of" => {
|
2017-08-05 12:27:28 +03:00
|
|
|
let llval = C_usize(self.ccx,
|
2017-06-01 21:50:53 +03:00
|
|
|
self.ccx.align_of(substs.type_at(0)).abi());
|
2017-07-31 17:42:42 +03:00
|
|
|
Ok(Const::new(llval, tcx.types.usize))
|
2017-06-23 17:48:29 +03:00
|
|
|
}
|
|
|
|
_ => span_bug!(span, "{:?} in constant", terminator.kind)
|
|
|
|
}
|
2017-12-08 03:00:05 -08:00
|
|
|
} else if let Some((op, is_checked)) = self.is_binop_lang_item(def_id) {
|
|
|
|
(||{
|
|
|
|
assert_eq!(arg_vals.len(), 2);
|
|
|
|
let rhs = arg_vals.pop().unwrap()?;
|
|
|
|
let lhs = arg_vals.pop().unwrap()?;
|
|
|
|
if !is_checked {
|
|
|
|
let binop_ty = op.ty(tcx, lhs.ty, rhs.ty);
|
|
|
|
let (lhs, rhs) = (lhs.llval, rhs.llval);
|
|
|
|
Ok(Const::new(const_scalar_binop(op, lhs, rhs, binop_ty),
|
|
|
|
binop_ty))
|
|
|
|
} else {
|
|
|
|
let ty = lhs.ty;
|
|
|
|
let val_ty = op.ty(tcx, lhs.ty, rhs.ty);
|
|
|
|
let binop_ty = tcx.intern_tup(&[val_ty, tcx.types.bool], false);
|
|
|
|
let (lhs, rhs) = (lhs.llval, rhs.llval);
|
|
|
|
assert!(!ty.is_fp());
|
|
|
|
|
|
|
|
match const_scalar_checked_binop(tcx, op, lhs, rhs, ty) {
|
|
|
|
Some((llval, of)) => {
|
|
|
|
Ok(trans_const_adt(
|
|
|
|
self.ccx,
|
|
|
|
binop_ty,
|
|
|
|
&mir::AggregateKind::Tuple,
|
|
|
|
&[
|
|
|
|
Const::new(llval, val_ty),
|
|
|
|
Const::new(C_bool(self.ccx, of), tcx.types.bool)
|
|
|
|
]))
|
|
|
|
}
|
|
|
|
None => {
|
|
|
|
span_bug!(span,
|
|
|
|
"{:?} got non-integer operands: {:?} and {:?}",
|
|
|
|
op, Value(lhs), Value(rhs));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
})()
|
2017-07-31 17:42:42 +03:00
|
|
|
} else {
|
|
|
|
MirConstContext::trans_def(self.ccx, def_id, substs, arg_vals)
|
|
|
|
};
|
|
|
|
add_err(&mut failure, &result);
|
|
|
|
self.store(dest, result, span);
|
2016-04-21 16:15:56 +03:00
|
|
|
target
|
|
|
|
} else {
|
2016-06-05 14:38:29 +03:00
|
|
|
span_bug!(span, "diverging {:?} in constant", terminator.kind);
|
2016-04-21 16:15:56 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
_ => span_bug!(span, "{:?} in constant", terminator.kind)
|
|
|
|
};
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-12-08 03:00:05 -08:00
|
|
|
fn is_binop_lang_item(&mut self, def_id: DefId) -> Option<(mir::BinOp, bool)> {
|
2018-01-05 06:58:34 +02:00
|
|
|
let tcx = self.ccx.tcx;
|
2017-12-08 03:00:05 -08:00
|
|
|
let items = tcx.lang_items();
|
|
|
|
let def_id = Some(def_id);
|
|
|
|
if items.i128_add_fn() == def_id { Some((mir::BinOp::Add, false)) }
|
|
|
|
else if items.u128_add_fn() == def_id { Some((mir::BinOp::Add, false)) }
|
|
|
|
else if items.i128_sub_fn() == def_id { Some((mir::BinOp::Sub, false)) }
|
|
|
|
else if items.u128_sub_fn() == def_id { Some((mir::BinOp::Sub, false)) }
|
|
|
|
else if items.i128_mul_fn() == def_id { Some((mir::BinOp::Mul, false)) }
|
|
|
|
else if items.u128_mul_fn() == def_id { Some((mir::BinOp::Mul, false)) }
|
|
|
|
else if items.i128_div_fn() == def_id { Some((mir::BinOp::Div, false)) }
|
|
|
|
else if items.u128_div_fn() == def_id { Some((mir::BinOp::Div, false)) }
|
|
|
|
else if items.i128_rem_fn() == def_id { Some((mir::BinOp::Rem, false)) }
|
|
|
|
else if items.u128_rem_fn() == def_id { Some((mir::BinOp::Rem, false)) }
|
|
|
|
else if items.i128_shl_fn() == def_id { Some((mir::BinOp::Shl, false)) }
|
|
|
|
else if items.u128_shl_fn() == def_id { Some((mir::BinOp::Shl, false)) }
|
|
|
|
else if items.i128_shr_fn() == def_id { Some((mir::BinOp::Shr, false)) }
|
|
|
|
else if items.u128_shr_fn() == def_id { Some((mir::BinOp::Shr, false)) }
|
|
|
|
else if items.i128_addo_fn() == def_id { Some((mir::BinOp::Add, true)) }
|
|
|
|
else if items.u128_addo_fn() == def_id { Some((mir::BinOp::Add, true)) }
|
|
|
|
else if items.i128_subo_fn() == def_id { Some((mir::BinOp::Sub, true)) }
|
|
|
|
else if items.u128_subo_fn() == def_id { Some((mir::BinOp::Sub, true)) }
|
|
|
|
else if items.i128_mulo_fn() == def_id { Some((mir::BinOp::Mul, true)) }
|
|
|
|
else if items.u128_mulo_fn() == def_id { Some((mir::BinOp::Mul, true)) }
|
|
|
|
else if items.i128_shlo_fn() == def_id { Some((mir::BinOp::Shl, true)) }
|
|
|
|
else if items.u128_shlo_fn() == def_id { Some((mir::BinOp::Shl, true)) }
|
|
|
|
else if items.i128_shro_fn() == def_id { Some((mir::BinOp::Shr, true)) }
|
|
|
|
else if items.u128_shro_fn() == def_id { Some((mir::BinOp::Shr, true)) }
|
|
|
|
else { None }
|
|
|
|
}
|
|
|
|
|
2017-07-31 17:42:42 +03:00
|
|
|
fn store(&mut self,
|
2017-12-01 14:31:47 +02:00
|
|
|
dest: &mir::Place<'tcx>,
|
2017-07-31 17:42:42 +03:00
|
|
|
value: Result<Const<'tcx>, ConstEvalErr<'tcx>>,
|
|
|
|
span: Span) {
|
2017-12-01 14:31:47 +02:00
|
|
|
if let mir::Place::Local(index) = *dest {
|
2016-06-20 23:55:14 +03:00
|
|
|
self.locals[index] = Some(value);
|
|
|
|
} else {
|
|
|
|
span_bug!(span, "assignment to {:?} in constant", dest);
|
|
|
|
}
|
2016-04-21 16:15:56 +03:00
|
|
|
}
|
|
|
|
|
2017-12-01 14:39:51 +02:00
|
|
|
fn const_place(&self, place: &mir::Place<'tcx>, span: Span)
|
2017-12-01 14:31:47 +02:00
|
|
|
-> Result<ConstPlace<'tcx>, ConstEvalErr<'tcx>> {
|
2018-01-05 06:58:34 +02:00
|
|
|
let tcx = self.ccx.tcx;
|
2016-06-20 23:55:14 +03:00
|
|
|
|
2017-12-01 14:39:51 +02:00
|
|
|
if let mir::Place::Local(index) = *place {
|
2017-07-31 17:42:42 +03:00
|
|
|
return self.locals[index].clone().unwrap_or_else(|| {
|
2017-12-01 14:39:51 +02:00
|
|
|
span_bug!(span, "{:?} not initialized", place)
|
|
|
|
}).map(|v| v.as_place());
|
2016-06-20 23:55:14 +03:00
|
|
|
}
|
|
|
|
|
2017-12-01 14:39:51 +02:00
|
|
|
let place = match *place {
|
2017-12-01 14:31:47 +02:00
|
|
|
mir::Place::Local(_) => bug!(), // handled above
|
|
|
|
mir::Place::Static(box mir::Static { def_id, ty }) => {
|
|
|
|
ConstPlace {
|
2016-08-16 17:41:38 +03:00
|
|
|
base: Base::Static(consts::get_static(self.ccx, def_id)),
|
2016-04-21 16:15:56 +03:00
|
|
|
llextra: ptr::null_mut(),
|
2017-03-01 02:29:57 +02:00
|
|
|
ty: self.monomorphize(&ty),
|
2016-04-21 16:15:56 +03:00
|
|
|
}
|
|
|
|
}
|
2017-12-01 14:31:47 +02:00
|
|
|
mir::Place::Projection(ref projection) => {
|
2017-12-01 14:39:51 +02:00
|
|
|
let tr_base = self.const_place(&projection.base, span)?;
|
2017-12-01 14:31:47 +02:00
|
|
|
let projected_ty = PlaceTy::Ty { ty: tr_base.ty }
|
2016-04-21 16:15:56 +03:00
|
|
|
.projection_ty(tcx, &projection.elem);
|
|
|
|
let base = tr_base.to_const(span);
|
|
|
|
let projected_ty = self.monomorphize(&projected_ty).to_ty(tcx);
|
2018-01-05 06:14:44 +02:00
|
|
|
let has_metadata = self.ccx.type_has_metadata(projected_ty);
|
2016-04-21 16:15:56 +03:00
|
|
|
|
|
|
|
let (projected, llextra) = match projection.elem {
|
|
|
|
mir::ProjectionElem::Deref => {
|
2017-09-03 19:53:58 +01:00
|
|
|
let (base, extra) = if !has_metadata {
|
2016-04-21 16:15:56 +03:00
|
|
|
(base.llval, ptr::null_mut())
|
|
|
|
} else {
|
2017-06-18 16:59:51 +03:00
|
|
|
base.get_fat_ptr(self.ccx)
|
2016-04-21 16:15:56 +03:00
|
|
|
};
|
2018-01-05 06:58:34 +02:00
|
|
|
if self.ccx.statics.borrow().contains_key(&base) {
|
2016-04-21 16:15:56 +03:00
|
|
|
(Base::Static(base), extra)
|
2016-05-08 00:28:52 +03:00
|
|
|
} else if let ty::TyStr = projected_ty.sty {
|
|
|
|
(Base::Str(base), extra)
|
2016-04-21 16:15:56 +03:00
|
|
|
} else {
|
2016-08-16 17:41:38 +03:00
|
|
|
let v = base;
|
2018-01-05 06:58:34 +02:00
|
|
|
let v = self.ccx.const_unsized.borrow().get(&v).map_or(v, |&v| v);
|
2016-08-16 17:41:38 +03:00
|
|
|
let mut val = unsafe { llvm::LLVMGetInitializer(v) };
|
2016-04-21 16:15:56 +03:00
|
|
|
if val.is_null() {
|
|
|
|
span_bug!(span, "dereference of non-constant pointer `{:?}`",
|
|
|
|
Value(base));
|
|
|
|
}
|
2017-09-24 12:01:09 +03:00
|
|
|
let layout = self.ccx.layout_of(projected_ty);
|
2017-09-26 14:41:06 +03:00
|
|
|
if let layout::Abi::Scalar(ref scalar) = layout.abi {
|
2017-05-12 00:14:31 +03:00
|
|
|
let i1_type = Type::i1(self.ccx);
|
2017-09-26 14:41:06 +03:00
|
|
|
if scalar.is_bool() && val_ty(val) != i1_type {
|
2017-05-12 00:14:31 +03:00
|
|
|
unsafe {
|
|
|
|
val = llvm::LLVMConstTrunc(val, i1_type.to_ref());
|
|
|
|
}
|
2016-08-16 17:41:38 +03:00
|
|
|
}
|
|
|
|
}
|
2016-04-21 16:15:56 +03:00
|
|
|
(Base::Value(val), extra)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
mir::ProjectionElem::Field(ref field, _) => {
|
2017-06-18 16:59:51 +03:00
|
|
|
let llprojected = base.get_field(self.ccx, field.index());
|
2017-09-03 19:53:58 +01:00
|
|
|
let llextra = if !has_metadata {
|
2016-04-21 16:15:56 +03:00
|
|
|
ptr::null_mut()
|
|
|
|
} else {
|
|
|
|
tr_base.llextra
|
|
|
|
};
|
|
|
|
(Base::Value(llprojected), llextra)
|
|
|
|
}
|
2017-09-03 21:55:41 +03:00
|
|
|
mir::ProjectionElem::Index(index) => {
|
2017-12-01 14:31:47 +02:00
|
|
|
let index = &mir::Operand::Copy(mir::Place::Local(index));
|
2016-04-21 16:15:56 +03:00
|
|
|
let llindex = self.const_operand(index, span)?.llval;
|
|
|
|
|
2016-08-26 01:32:46 +03:00
|
|
|
let iv = if let Some(iv) = common::const_to_opt_u128(llindex, false) {
|
2016-04-21 16:15:56 +03:00
|
|
|
iv
|
|
|
|
} else {
|
|
|
|
span_bug!(span, "index is not an integer-constant expression")
|
|
|
|
};
|
2016-06-05 14:38:29 +03:00
|
|
|
|
|
|
|
// Produce an undef instead of a LLVM assertion on OOB.
|
|
|
|
let len = common::const_to_uint(tr_base.len(self.ccx));
|
2016-08-26 01:32:46 +03:00
|
|
|
let llelem = if iv < len as u128 {
|
2017-06-25 12:41:24 +03:00
|
|
|
const_get_elt(base.llval, iv as u64)
|
2016-06-05 14:38:29 +03:00
|
|
|
} else {
|
2017-09-20 23:07:47 +03:00
|
|
|
C_undef(self.ccx.layout_of(projected_ty).llvm_type(self.ccx))
|
2016-06-05 14:38:29 +03:00
|
|
|
};
|
|
|
|
|
|
|
|
(Base::Value(llelem), ptr::null_mut())
|
2016-04-21 16:15:56 +03:00
|
|
|
}
|
|
|
|
_ => span_bug!(span, "{:?} in constant", projection.elem)
|
|
|
|
};
|
2017-12-01 14:31:47 +02:00
|
|
|
ConstPlace {
|
2016-04-21 16:15:56 +03:00
|
|
|
base: projected,
|
2017-08-06 22:54:09 -07:00
|
|
|
llextra,
|
2016-04-21 16:15:56 +03:00
|
|
|
ty: projected_ty
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
2017-12-01 14:39:51 +02:00
|
|
|
Ok(place)
|
2016-04-21 16:15:56 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
fn const_operand(&self, operand: &mir::Operand<'tcx>, span: Span)
|
2017-02-15 15:00:20 +02:00
|
|
|
-> Result<Const<'tcx>, ConstEvalErr<'tcx>> {
|
2016-09-12 01:53:43 +03:00
|
|
|
debug!("const_operand({:?} @ {:?})", operand, span);
|
|
|
|
let result = match *operand {
|
2017-12-01 14:39:51 +02:00
|
|
|
mir::Operand::Copy(ref place) |
|
|
|
|
mir::Operand::Move(ref place) => {
|
|
|
|
Ok(self.const_place(place, span)?.to_const(span))
|
2016-04-21 16:15:56 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
mir::Operand::Constant(ref constant) => {
|
|
|
|
let ty = self.monomorphize(&constant.ty);
|
|
|
|
match constant.literal.clone() {
|
2016-05-03 00:26:41 +03:00
|
|
|
mir::Literal::Promoted { index } => {
|
|
|
|
let mir = &self.mir.promoted[index];
|
2016-06-07 17:28:36 +03:00
|
|
|
MirConstContext::new(self.ccx, mir, self.substs, IndexVec::new()).trans()
|
2016-04-21 16:15:56 +03:00
|
|
|
}
|
|
|
|
mir::Literal::Value { value } => {
|
2017-09-03 20:34:48 +03:00
|
|
|
if let ConstVal::Unevaluated(def_id, substs) = value.val {
|
|
|
|
let substs = self.monomorphize(&substs);
|
|
|
|
MirConstContext::trans_def(self.ccx, def_id, substs, IndexVec::new())
|
|
|
|
} else {
|
|
|
|
Ok(Const::from_constval(self.ccx, &value.val, ty))
|
|
|
|
}
|
2016-04-21 16:15:56 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2016-09-12 01:53:43 +03:00
|
|
|
};
|
|
|
|
debug!("const_operand({:?} @ {:?}) = {:?}", operand, span,
|
|
|
|
result.as_ref().ok());
|
|
|
|
result
|
|
|
|
}
|
|
|
|
|
|
|
|
fn const_array(&self, array_ty: Ty<'tcx>, fields: &[ValueRef])
|
|
|
|
-> Const<'tcx>
|
|
|
|
{
|
|
|
|
let elem_ty = array_ty.builtin_index().unwrap_or_else(|| {
|
|
|
|
bug!("bad array type {:?}", array_ty)
|
|
|
|
});
|
2017-09-20 23:07:47 +03:00
|
|
|
let llunitty = self.ccx.layout_of(elem_ty).llvm_type(self.ccx);
|
2016-09-12 01:53:43 +03:00
|
|
|
// If the array contains enums, an LLVM array won't work.
|
|
|
|
let val = if fields.iter().all(|&f| val_ty(f) == llunitty) {
|
|
|
|
C_array(llunitty, fields)
|
|
|
|
} else {
|
|
|
|
C_struct(self.ccx, fields, false)
|
|
|
|
};
|
|
|
|
Const::new(val, array_ty)
|
2015-12-28 21:18:24 +02:00
|
|
|
}
|
|
|
|
|
2016-04-21 16:15:56 +03:00
|
|
|
fn const_rvalue(&self, rvalue: &mir::Rvalue<'tcx>,
|
|
|
|
dest_ty: Ty<'tcx>, span: Span)
|
2017-02-15 15:00:20 +02:00
|
|
|
-> Result<Const<'tcx>, ConstEvalErr<'tcx>> {
|
2018-01-05 06:58:34 +02:00
|
|
|
let tcx = self.ccx.tcx;
|
2016-09-12 01:53:43 +03:00
|
|
|
debug!("const_rvalue({:?}: {:?} @ {:?})", rvalue, dest_ty, span);
|
2016-04-21 16:15:56 +03:00
|
|
|
let val = match *rvalue {
|
|
|
|
mir::Rvalue::Use(ref operand) => self.const_operand(operand, span)?,
|
|
|
|
|
2017-08-05 12:27:28 +03:00
|
|
|
mir::Rvalue::Repeat(ref elem, count) => {
|
2016-04-21 16:15:56 +03:00
|
|
|
let elem = self.const_operand(elem, span)?;
|
2017-08-05 12:27:28 +03:00
|
|
|
let size = count.as_u64();
|
|
|
|
assert_eq!(size as usize as u64, size);
|
2016-04-21 16:15:56 +03:00
|
|
|
let fields = vec![elem.llval; size as usize];
|
2016-09-12 01:53:43 +03:00
|
|
|
self.const_array(dest_ty, &fields)
|
2016-04-21 16:15:56 +03:00
|
|
|
}
|
|
|
|
|
2017-06-01 21:50:53 +03:00
|
|
|
mir::Rvalue::Aggregate(box mir::AggregateKind::Array(_), ref operands) => {
|
2016-06-05 14:38:29 +03:00
|
|
|
// Make sure to evaluate all operands to
|
|
|
|
// report as many errors as we possibly can.
|
|
|
|
let mut fields = Vec::with_capacity(operands.len());
|
|
|
|
let mut failure = Ok(());
|
|
|
|
for operand in operands {
|
|
|
|
match self.const_operand(operand, span) {
|
|
|
|
Ok(val) => fields.push(val.llval),
|
|
|
|
Err(err) => if failure.is_ok() { failure = Err(err); }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
failure?;
|
2016-04-21 16:15:56 +03:00
|
|
|
|
2017-06-01 21:50:53 +03:00
|
|
|
self.const_array(dest_ty, &fields)
|
|
|
|
}
|
|
|
|
|
|
|
|
mir::Rvalue::Aggregate(ref kind, ref operands) => {
|
|
|
|
// Make sure to evaluate all operands to
|
|
|
|
// report as many errors as we possibly can.
|
|
|
|
let mut fields = Vec::with_capacity(operands.len());
|
|
|
|
let mut failure = Ok(());
|
|
|
|
for operand in operands {
|
|
|
|
match self.const_operand(operand, span) {
|
|
|
|
Ok(val) => fields.push(val),
|
|
|
|
Err(err) => if failure.is_ok() { failure = Err(err); }
|
2016-09-12 01:53:43 +03:00
|
|
|
}
|
|
|
|
}
|
2017-06-01 21:50:53 +03:00
|
|
|
failure?;
|
|
|
|
|
|
|
|
trans_const_adt(self.ccx, dest_ty, kind, &fields)
|
2016-04-21 16:15:56 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
mir::Rvalue::Cast(ref kind, ref source, cast_ty) => {
|
|
|
|
let operand = self.const_operand(source, span)?;
|
|
|
|
let cast_ty = self.monomorphize(&cast_ty);
|
|
|
|
|
|
|
|
let val = match *kind {
|
|
|
|
mir::CastKind::ReifyFnPointer => {
|
|
|
|
match operand.ty.sty {
|
2017-05-13 17:11:52 +03:00
|
|
|
ty::TyFnDef(def_id, substs) => {
|
2017-03-08 18:33:21 +02:00
|
|
|
callee::resolve_and_get_fn(self.ccx, def_id, substs)
|
2016-04-21 16:15:56 +03:00
|
|
|
}
|
|
|
|
_ => {
|
|
|
|
span_bug!(span, "{} cannot be reified to a fn ptr",
|
|
|
|
operand.ty)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2017-02-22 01:24:16 +01:00
|
|
|
mir::CastKind::ClosureFnPointer => {
|
|
|
|
match operand.ty.sty {
|
|
|
|
ty::TyClosure(def_id, substs) => {
|
|
|
|
// Get the def_id for FnOnce::call_once
|
2017-08-31 08:57:41 -07:00
|
|
|
let fn_once = tcx.lang_items().fn_once_trait().unwrap();
|
2017-02-22 01:24:16 +01:00
|
|
|
let call_once = tcx
|
|
|
|
.global_tcx().associated_items(fn_once)
|
|
|
|
.find(|it| it.kind == ty::AssociatedKind::Method)
|
|
|
|
.unwrap().def_id;
|
|
|
|
// Now create its substs [Closure, Tuple]
|
2017-12-01 09:26:13 -05:00
|
|
|
let input = substs.closure_sig(def_id, tcx).input(0);
|
2017-02-08 18:31:03 +01:00
|
|
|
let input = tcx.erase_late_bound_regions_and_normalize(&input);
|
|
|
|
let substs = tcx.mk_substs([operand.ty, input]
|
2017-02-24 00:32:21 +01:00
|
|
|
.iter().cloned().map(Kind::from));
|
2017-03-08 18:33:21 +02:00
|
|
|
callee::resolve_and_get_fn(self.ccx, call_once, substs)
|
2017-02-22 01:24:16 +01:00
|
|
|
}
|
|
|
|
_ => {
|
|
|
|
bug!("{} cannot be cast to a fn ptr", operand.ty)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2016-04-21 16:15:56 +03:00
|
|
|
mir::CastKind::UnsafeFnPointer => {
|
|
|
|
// this is a no-op at the LLVM level
|
|
|
|
operand.llval
|
|
|
|
}
|
|
|
|
mir::CastKind::Unsize => {
|
|
|
|
let pointee_ty = operand.ty.builtin_deref(true, ty::NoPreference)
|
|
|
|
.expect("consts: unsizing got non-pointer type").ty;
|
2018-01-05 06:14:44 +02:00
|
|
|
let (base, old_info) = if !self.ccx.type_is_sized(pointee_ty) {
|
2016-04-21 16:15:56 +03:00
|
|
|
// Normally, the source is a thin pointer and we are
|
|
|
|
// adding extra info to make a fat pointer. The exception
|
|
|
|
// is when we are upcasting an existing object fat pointer
|
|
|
|
// to use a different vtable. In that case, we want to
|
|
|
|
// load out the original data pointer so we can repackage
|
|
|
|
// it.
|
2017-06-18 16:59:51 +03:00
|
|
|
let (base, extra) = operand.get_fat_ptr(self.ccx);
|
2016-04-21 16:15:56 +03:00
|
|
|
(base, Some(extra))
|
|
|
|
} else {
|
|
|
|
(operand.llval, None)
|
|
|
|
};
|
|
|
|
|
|
|
|
let unsized_ty = cast_ty.builtin_deref(true, ty::NoPreference)
|
|
|
|
.expect("consts: unsizing got non-pointer target type").ty;
|
2017-09-20 23:07:47 +03:00
|
|
|
let ptr_ty = self.ccx.layout_of(unsized_ty).llvm_type(self.ccx).ptr_to();
|
2016-04-21 16:15:56 +03:00
|
|
|
let base = consts::ptrcast(base, ptr_ty);
|
|
|
|
let info = base::unsized_info(self.ccx, pointee_ty,
|
|
|
|
unsized_ty, old_info);
|
|
|
|
|
|
|
|
if old_info.is_none() {
|
2018-01-05 06:58:34 +02:00
|
|
|
let prev_const = self.ccx.const_unsized.borrow_mut()
|
2016-04-21 16:15:56 +03:00
|
|
|
.insert(base, operand.llval);
|
|
|
|
assert!(prev_const.is_none() || prev_const == Some(operand.llval));
|
|
|
|
}
|
2017-06-25 12:42:55 +03:00
|
|
|
C_fat_ptr(self.ccx, base, info)
|
2016-04-21 16:15:56 +03:00
|
|
|
}
|
2017-09-21 20:40:50 +03:00
|
|
|
mir::CastKind::Misc if self.ccx.layout_of(operand.ty).is_llvm_immediate() => {
|
2016-04-21 16:15:56 +03:00
|
|
|
let r_t_in = CastTy::from_ty(operand.ty).expect("bad input type for cast");
|
|
|
|
let r_t_out = CastTy::from_ty(cast_ty).expect("bad output type for cast");
|
2017-09-21 20:40:50 +03:00
|
|
|
let cast_layout = self.ccx.layout_of(cast_ty);
|
|
|
|
assert!(cast_layout.is_llvm_immediate());
|
|
|
|
let ll_t_out = cast_layout.immediate_llvm_type(self.ccx);
|
2016-04-21 16:15:56 +03:00
|
|
|
let llval = operand.llval;
|
2017-09-26 14:41:06 +03:00
|
|
|
|
|
|
|
let mut signed = false;
|
|
|
|
let l = self.ccx.layout_of(operand.ty);
|
|
|
|
if let layout::Abi::Scalar(ref scalar) = l.abi {
|
|
|
|
if let layout::Int(_, true) = scalar.value {
|
|
|
|
signed = true;
|
|
|
|
}
|
|
|
|
}
|
2016-04-21 16:15:56 +03:00
|
|
|
|
|
|
|
unsafe {
|
|
|
|
match (r_t_in, r_t_out) {
|
|
|
|
(CastTy::Int(_), CastTy::Int(_)) => {
|
|
|
|
let s = signed as llvm::Bool;
|
|
|
|
llvm::LLVMConstIntCast(llval, ll_t_out.to_ref(), s)
|
|
|
|
}
|
|
|
|
(CastTy::Int(_), CastTy::Float) => {
|
2017-10-15 22:28:49 +02:00
|
|
|
cast_const_int_to_float(self.ccx, llval, signed, ll_t_out)
|
2016-04-21 16:15:56 +03:00
|
|
|
}
|
|
|
|
(CastTy::Float, CastTy::Float) => {
|
|
|
|
llvm::LLVMConstFPCast(llval, ll_t_out.to_ref())
|
|
|
|
}
|
|
|
|
(CastTy::Float, CastTy::Int(IntTy::I)) => {
|
2017-10-15 22:28:49 +02:00
|
|
|
cast_const_float_to_int(self.ccx, &operand,
|
|
|
|
true, ll_t_out, span)
|
2016-04-21 16:15:56 +03:00
|
|
|
}
|
|
|
|
(CastTy::Float, CastTy::Int(_)) => {
|
2017-10-15 22:28:49 +02:00
|
|
|
cast_const_float_to_int(self.ccx, &operand,
|
|
|
|
false, ll_t_out, span)
|
2016-04-21 16:15:56 +03:00
|
|
|
}
|
|
|
|
(CastTy::Ptr(_), CastTy::Ptr(_)) |
|
|
|
|
(CastTy::FnPtr, CastTy::Ptr(_)) |
|
|
|
|
(CastTy::RPtr(_), CastTy::Ptr(_)) => {
|
|
|
|
consts::ptrcast(llval, ll_t_out)
|
|
|
|
}
|
|
|
|
(CastTy::Int(_), CastTy::Ptr(_)) => {
|
2018-01-02 12:44:54 -08:00
|
|
|
let s = signed as llvm::Bool;
|
|
|
|
let usize_llval = llvm::LLVMConstIntCast(llval,
|
2018-01-05 06:58:34 +02:00
|
|
|
self.ccx.isize_ty.to_ref(), s);
|
2018-01-02 12:44:54 -08:00
|
|
|
llvm::LLVMConstIntToPtr(usize_llval, ll_t_out.to_ref())
|
2016-04-21 16:15:56 +03:00
|
|
|
}
|
|
|
|
(CastTy::Ptr(_), CastTy::Int(_)) |
|
|
|
|
(CastTy::FnPtr, CastTy::Int(_)) => {
|
|
|
|
llvm::LLVMConstPtrToInt(llval, ll_t_out.to_ref())
|
|
|
|
}
|
|
|
|
_ => bug!("unsupported cast: {:?} to {:?}", operand.ty, cast_ty)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
mir::CastKind::Misc => { // Casts from a fat-ptr.
|
2017-10-10 22:04:13 +03:00
|
|
|
let l = self.ccx.layout_of(operand.ty);
|
|
|
|
let cast = self.ccx.layout_of(cast_ty);
|
|
|
|
if l.is_llvm_scalar_pair() {
|
2017-06-18 17:42:03 +03:00
|
|
|
let (data_ptr, meta) = operand.get_fat_ptr(self.ccx);
|
2017-10-10 22:04:13 +03:00
|
|
|
if cast.is_llvm_scalar_pair() {
|
2017-09-21 20:40:50 +03:00
|
|
|
let data_cast = consts::ptrcast(data_ptr,
|
2017-10-10 22:04:13 +03:00
|
|
|
cast.scalar_pair_element_llvm_type(self.ccx, 0));
|
2017-06-25 12:42:55 +03:00
|
|
|
C_fat_ptr(self.ccx, data_cast, meta)
|
2016-04-21 16:15:56 +03:00
|
|
|
} else { // cast to thin-ptr
|
|
|
|
// Cast of fat-ptr to thin-ptr is an extraction of data-ptr and
|
|
|
|
// pointer-cast of that pointer to desired pointer type.
|
2017-10-10 22:04:13 +03:00
|
|
|
let llcast_ty = cast.immediate_llvm_type(self.ccx);
|
2017-06-18 17:42:03 +03:00
|
|
|
consts::ptrcast(data_ptr, llcast_ty)
|
2016-04-21 16:15:56 +03:00
|
|
|
}
|
|
|
|
} else {
|
2016-05-25 11:55:44 +03:00
|
|
|
bug!("Unexpected non-fat-pointer operand")
|
2016-04-21 16:15:56 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
Const::new(val, cast_ty)
|
|
|
|
}
|
|
|
|
|
2017-12-01 14:39:51 +02:00
|
|
|
mir::Rvalue::Ref(_, bk, ref place) => {
|
|
|
|
let tr_place = self.const_place(place, span)?;
|
2016-04-21 16:15:56 +03:00
|
|
|
|
2017-12-01 14:39:51 +02:00
|
|
|
let ty = tr_place.ty;
|
2017-04-20 01:58:12 +03:00
|
|
|
let ref_ty = tcx.mk_ref(tcx.types.re_erased,
|
2016-04-21 16:15:56 +03:00
|
|
|
ty::TypeAndMut { ty: ty, mutbl: bk.to_mutbl_lossy() });
|
|
|
|
|
2017-12-01 14:39:51 +02:00
|
|
|
let base = match tr_place.base {
|
2016-04-21 16:15:56 +03:00
|
|
|
Base::Value(llval) => {
|
2016-09-25 19:55:43 -04:00
|
|
|
// FIXME: may be wrong for &*(&simd_vec as &fmt::Debug)
|
2018-01-05 06:14:44 +02:00
|
|
|
let align = if self.ccx.type_is_sized(ty) {
|
2017-03-02 05:35:25 +02:00
|
|
|
self.ccx.align_of(ty)
|
2016-08-28 20:44:19 -04:00
|
|
|
} else {
|
2018-01-05 06:58:34 +02:00
|
|
|
self.ccx.tcx.data_layout.pointer_align
|
2016-08-28 20:44:19 -04:00
|
|
|
};
|
2016-04-21 16:15:56 +03:00
|
|
|
if bk == mir::BorrowKind::Mut {
|
|
|
|
consts::addr_of_mut(self.ccx, llval, align, "ref_mut")
|
|
|
|
} else {
|
|
|
|
consts::addr_of(self.ccx, llval, align, "ref")
|
|
|
|
}
|
|
|
|
}
|
2016-05-08 00:28:52 +03:00
|
|
|
Base::Str(llval) |
|
2016-04-21 16:15:56 +03:00
|
|
|
Base::Static(llval) => llval
|
|
|
|
};
|
|
|
|
|
2018-01-05 06:14:44 +02:00
|
|
|
let ptr = if self.ccx.type_is_sized(ty) {
|
2016-04-21 16:15:56 +03:00
|
|
|
base
|
|
|
|
} else {
|
2017-12-01 14:39:51 +02:00
|
|
|
C_fat_ptr(self.ccx, base, tr_place.llextra)
|
2016-04-21 16:15:56 +03:00
|
|
|
};
|
|
|
|
Const::new(ptr, ref_ty)
|
|
|
|
}
|
|
|
|
|
2017-12-01 14:39:51 +02:00
|
|
|
mir::Rvalue::Len(ref place) => {
|
|
|
|
let tr_place = self.const_place(place, span)?;
|
|
|
|
Const::new(tr_place.len(self.ccx), tcx.types.usize)
|
2016-04-21 16:15:56 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
mir::Rvalue::BinaryOp(op, ref lhs, ref rhs) => {
|
|
|
|
let lhs = self.const_operand(lhs, span)?;
|
|
|
|
let rhs = self.const_operand(rhs, span)?;
|
|
|
|
let ty = lhs.ty;
|
2016-08-08 13:35:10 -07:00
|
|
|
let binop_ty = op.ty(tcx, lhs.ty, rhs.ty);
|
2016-04-21 16:15:56 +03:00
|
|
|
let (lhs, rhs) = (lhs.llval, rhs.llval);
|
2016-05-27 14:40:05 +03:00
|
|
|
Const::new(const_scalar_binop(op, lhs, rhs, ty), binop_ty)
|
|
|
|
}
|
2016-04-21 16:15:56 +03:00
|
|
|
|
2016-05-27 14:40:05 +03:00
|
|
|
mir::Rvalue::CheckedBinaryOp(op, ref lhs, ref rhs) => {
|
|
|
|
let lhs = self.const_operand(lhs, span)?;
|
|
|
|
let rhs = self.const_operand(rhs, span)?;
|
|
|
|
let ty = lhs.ty;
|
2016-08-08 13:35:10 -07:00
|
|
|
let val_ty = op.ty(tcx, lhs.ty, rhs.ty);
|
2017-01-11 15:58:37 +08:00
|
|
|
let binop_ty = tcx.intern_tup(&[val_ty, tcx.types.bool], false);
|
2016-05-27 14:40:05 +03:00
|
|
|
let (lhs, rhs) = (lhs.llval, rhs.llval);
|
|
|
|
assert!(!ty.is_fp());
|
2016-04-21 16:15:56 +03:00
|
|
|
|
2016-05-27 14:40:05 +03:00
|
|
|
match const_scalar_checked_binop(tcx, op, lhs, rhs, ty) {
|
|
|
|
Some((llval, of)) => {
|
2017-06-18 16:59:51 +03:00
|
|
|
trans_const_adt(self.ccx, binop_ty, &mir::AggregateKind::Tuple, &[
|
|
|
|
Const::new(llval, val_ty),
|
|
|
|
Const::new(C_bool(self.ccx, of), tcx.types.bool)
|
|
|
|
])
|
2016-04-21 16:15:56 +03:00
|
|
|
}
|
2016-05-27 14:40:05 +03:00
|
|
|
None => {
|
|
|
|
span_bug!(span, "{:?} got non-integer operands: {:?} and {:?}",
|
|
|
|
rvalue, Value(lhs), Value(rhs));
|
|
|
|
}
|
|
|
|
}
|
2016-04-21 16:15:56 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
mir::Rvalue::UnaryOp(op, ref operand) => {
|
|
|
|
let operand = self.const_operand(operand, span)?;
|
|
|
|
let lloperand = operand.llval;
|
|
|
|
let llval = match op {
|
|
|
|
mir::UnOp::Not => {
|
|
|
|
unsafe {
|
|
|
|
llvm::LLVMConstNot(lloperand)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
mir::UnOp::Neg => {
|
|
|
|
let is_float = operand.ty.is_fp();
|
|
|
|
unsafe {
|
|
|
|
if is_float {
|
|
|
|
llvm::LLVMConstFNeg(lloperand)
|
|
|
|
} else {
|
|
|
|
llvm::LLVMConstNeg(lloperand)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
Const::new(llval, operand.ty)
|
|
|
|
}
|
|
|
|
|
2017-05-18 18:43:52 +03:00
|
|
|
mir::Rvalue::NullaryOp(mir::NullOp::SizeOf, ty) => {
|
2018-01-05 06:14:44 +02:00
|
|
|
assert!(self.ccx.type_is_sized(ty));
|
2017-06-01 21:50:53 +03:00
|
|
|
let llval = C_usize(self.ccx, self.ccx.size_of(ty).bytes());
|
2017-05-18 18:43:52 +03:00
|
|
|
Const::new(llval, tcx.types.usize)
|
|
|
|
}
|
|
|
|
|
2016-04-21 16:15:56 +03:00
|
|
|
_ => span_bug!(span, "{:?} in constant", rvalue)
|
|
|
|
};
|
|
|
|
|
2016-09-12 01:53:43 +03:00
|
|
|
debug!("const_rvalue({:?}: {:?} @ {:?}) = {:?}", rvalue, dest_ty, span, val);
|
|
|
|
|
2016-04-21 16:15:56 +03:00
|
|
|
Ok(val)
|
|
|
|
}
|
2016-05-27 14:40:05 +03:00
|
|
|
|
|
|
|
}
|
|
|
|
|
2016-08-16 17:41:38 +03:00
|
|
|
fn to_const_int(value: ValueRef, t: Ty, tcx: TyCtxt) -> Option<ConstInt> {
|
|
|
|
match t.sty {
|
2016-08-26 01:32:46 +03:00
|
|
|
ty::TyInt(int_type) => const_to_opt_u128(value, true)
|
|
|
|
.and_then(|input| ConstInt::new_signed(input as i128, int_type,
|
2017-08-05 12:27:28 +03:00
|
|
|
tcx.sess.target.isize_ty)),
|
2016-08-26 01:32:46 +03:00
|
|
|
ty::TyUint(uint_type) => const_to_opt_u128(value, false)
|
|
|
|
.and_then(|input| ConstInt::new_unsigned(input, uint_type,
|
2017-08-05 12:27:28 +03:00
|
|
|
tcx.sess.target.usize_ty)),
|
2016-08-26 01:32:46 +03:00
|
|
|
_ => None
|
|
|
|
|
2016-08-16 17:41:38 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-05-27 14:40:05 +03:00
|
|
|
pub fn const_scalar_binop(op: mir::BinOp,
|
|
|
|
lhs: ValueRef,
|
|
|
|
rhs: ValueRef,
|
|
|
|
input_ty: Ty) -> ValueRef {
|
|
|
|
assert!(!input_ty.is_simd());
|
|
|
|
let is_float = input_ty.is_fp();
|
|
|
|
let signed = input_ty.is_signed();
|
|
|
|
|
|
|
|
unsafe {
|
|
|
|
match op {
|
|
|
|
mir::BinOp::Add if is_float => llvm::LLVMConstFAdd(lhs, rhs),
|
|
|
|
mir::BinOp::Add => llvm::LLVMConstAdd(lhs, rhs),
|
|
|
|
|
|
|
|
mir::BinOp::Sub if is_float => llvm::LLVMConstFSub(lhs, rhs),
|
|
|
|
mir::BinOp::Sub => llvm::LLVMConstSub(lhs, rhs),
|
|
|
|
|
|
|
|
mir::BinOp::Mul if is_float => llvm::LLVMConstFMul(lhs, rhs),
|
|
|
|
mir::BinOp::Mul => llvm::LLVMConstMul(lhs, rhs),
|
|
|
|
|
|
|
|
mir::BinOp::Div if is_float => llvm::LLVMConstFDiv(lhs, rhs),
|
|
|
|
mir::BinOp::Div if signed => llvm::LLVMConstSDiv(lhs, rhs),
|
|
|
|
mir::BinOp::Div => llvm::LLVMConstUDiv(lhs, rhs),
|
|
|
|
|
|
|
|
mir::BinOp::Rem if is_float => llvm::LLVMConstFRem(lhs, rhs),
|
|
|
|
mir::BinOp::Rem if signed => llvm::LLVMConstSRem(lhs, rhs),
|
|
|
|
mir::BinOp::Rem => llvm::LLVMConstURem(lhs, rhs),
|
|
|
|
|
|
|
|
mir::BinOp::BitXor => llvm::LLVMConstXor(lhs, rhs),
|
|
|
|
mir::BinOp::BitAnd => llvm::LLVMConstAnd(lhs, rhs),
|
|
|
|
mir::BinOp::BitOr => llvm::LLVMConstOr(lhs, rhs),
|
|
|
|
mir::BinOp::Shl => {
|
|
|
|
let rhs = base::cast_shift_const_rhs(op.to_hir_binop(), lhs, rhs);
|
|
|
|
llvm::LLVMConstShl(lhs, rhs)
|
|
|
|
}
|
|
|
|
mir::BinOp::Shr => {
|
|
|
|
let rhs = base::cast_shift_const_rhs(op.to_hir_binop(), lhs, rhs);
|
|
|
|
if signed { llvm::LLVMConstAShr(lhs, rhs) }
|
|
|
|
else { llvm::LLVMConstLShr(lhs, rhs) }
|
|
|
|
}
|
|
|
|
mir::BinOp::Eq | mir::BinOp::Ne |
|
|
|
|
mir::BinOp::Lt | mir::BinOp::Le |
|
|
|
|
mir::BinOp::Gt | mir::BinOp::Ge => {
|
|
|
|
if is_float {
|
|
|
|
let cmp = base::bin_op_to_fcmp_predicate(op.to_hir_binop());
|
2016-08-03 00:25:19 +03:00
|
|
|
llvm::LLVMConstFCmp(cmp, lhs, rhs)
|
2016-05-27 14:40:05 +03:00
|
|
|
} else {
|
|
|
|
let cmp = base::bin_op_to_icmp_predicate(op.to_hir_binop(),
|
|
|
|
signed);
|
2016-08-03 00:25:19 +03:00
|
|
|
llvm::LLVMConstICmp(cmp, lhs, rhs)
|
2016-05-27 14:40:05 +03:00
|
|
|
}
|
|
|
|
}
|
2017-05-18 18:43:52 +03:00
|
|
|
mir::BinOp::Offset => unreachable!("BinOp::Offset in const-eval!")
|
2016-05-27 14:40:05 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn const_scalar_checked_binop<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
|
|
|
op: mir::BinOp,
|
|
|
|
lllhs: ValueRef,
|
|
|
|
llrhs: ValueRef,
|
|
|
|
input_ty: Ty<'tcx>)
|
|
|
|
-> Option<(ValueRef, bool)> {
|
|
|
|
if let (Some(lhs), Some(rhs)) = (to_const_int(lllhs, input_ty, tcx),
|
|
|
|
to_const_int(llrhs, input_ty, tcx)) {
|
|
|
|
let result = match op {
|
|
|
|
mir::BinOp::Add => lhs + rhs,
|
|
|
|
mir::BinOp::Sub => lhs - rhs,
|
|
|
|
mir::BinOp::Mul => lhs * rhs,
|
|
|
|
mir::BinOp::Shl => lhs << rhs,
|
|
|
|
mir::BinOp::Shr => lhs >> rhs,
|
|
|
|
_ => {
|
|
|
|
bug!("Operator `{:?}` is not a checkable operator", op)
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
let of = match result {
|
|
|
|
Ok(_) => false,
|
|
|
|
Err(ConstMathErr::Overflow(_)) |
|
|
|
|
Err(ConstMathErr::ShiftNegative) => true,
|
|
|
|
Err(err) => {
|
|
|
|
bug!("Operator `{:?}` on `{:?}` and `{:?}` errored: {}",
|
|
|
|
op, lhs, rhs, err.description());
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
Some((const_scalar_binop(op, lllhs, llrhs, input_ty), of))
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
}
|
2016-04-21 16:15:56 +03:00
|
|
|
}
|
|
|
|
|
2018-01-05 07:01:54 +02:00
|
|
|
unsafe fn cast_const_float_to_int(ccx: &CodegenCx,
|
2017-10-15 22:28:49 +02:00
|
|
|
operand: &Const,
|
|
|
|
signed: bool,
|
|
|
|
int_ty: Type,
|
|
|
|
span: Span) -> ValueRef {
|
2017-10-09 02:14:00 +02:00
|
|
|
let llval = operand.llval;
|
|
|
|
let float_bits = match operand.ty.sty {
|
|
|
|
ty::TyFloat(fty) => fty.bit_width(),
|
2017-10-15 22:28:49 +02:00
|
|
|
_ => bug!("cast_const_float_to_int: operand not a float"),
|
2017-10-09 02:14:00 +02:00
|
|
|
};
|
2017-10-15 22:28:49 +02:00
|
|
|
// Note: this breaks if llval is a complex constant expression rather than a simple constant.
|
|
|
|
// One way that might happen would be if addresses could be turned into integers in constant
|
|
|
|
// expressions, but that doesn't appear to be possible?
|
|
|
|
// In any case, an ICE is better than producing undef.
|
|
|
|
let llval_bits = consts::bitcast(llval, Type::ix(ccx, float_bits as u64));
|
|
|
|
let bits = const_to_opt_u128(llval_bits, false).unwrap_or_else(|| {
|
|
|
|
panic!("could not get bits of constant float {:?}",
|
|
|
|
Value(llval));
|
|
|
|
});
|
|
|
|
let int_width = int_ty.int_width() as usize;
|
|
|
|
// Try to convert, but report an error for overflow and NaN. This matches HIR const eval.
|
2017-10-09 02:14:00 +02:00
|
|
|
let cast_result = match float_bits {
|
2017-10-15 22:28:49 +02:00
|
|
|
32 if signed => ieee::Single::from_bits(bits).to_i128(int_width).map(|v| v as u128),
|
|
|
|
64 if signed => ieee::Double::from_bits(bits).to_i128(int_width).map(|v| v as u128),
|
|
|
|
32 => ieee::Single::from_bits(bits).to_u128(int_width),
|
|
|
|
64 => ieee::Double::from_bits(bits).to_u128(int_width),
|
2017-10-09 02:14:00 +02:00
|
|
|
n => bug!("unsupported float width {}", n),
|
|
|
|
};
|
2017-10-15 22:28:49 +02:00
|
|
|
if cast_result.status.contains(Status::INVALID_OP) {
|
|
|
|
let err = ConstEvalErr { span: span, kind: ErrKind::CannotCast };
|
2018-01-05 06:58:34 +02:00
|
|
|
err.report(ccx.tcx, span, "expression");
|
2017-10-15 22:28:49 +02:00
|
|
|
}
|
2017-09-23 15:04:37 +03:00
|
|
|
C_uint_big(int_ty, cast_result.value)
|
2017-10-09 02:14:00 +02:00
|
|
|
}
|
|
|
|
|
2018-01-05 07:01:54 +02:00
|
|
|
unsafe fn cast_const_int_to_float(ccx: &CodegenCx,
|
2017-10-15 22:28:49 +02:00
|
|
|
llval: ValueRef,
|
|
|
|
signed: bool,
|
|
|
|
float_ty: Type) -> ValueRef {
|
|
|
|
// Note: this breaks if llval is a complex constant expression rather than a simple constant.
|
|
|
|
// One way that might happen would be if addresses could be turned into integers in constant
|
|
|
|
// expressions, but that doesn't appear to be possible?
|
|
|
|
// In any case, an ICE is better than producing undef.
|
2017-10-09 02:14:00 +02:00
|
|
|
let value = const_to_opt_u128(llval, signed).unwrap_or_else(|| {
|
|
|
|
panic!("could not get z128 value of constant integer {:?}",
|
|
|
|
Value(llval));
|
|
|
|
});
|
|
|
|
if signed {
|
|
|
|
llvm::LLVMConstSIToFP(llval, float_ty.to_ref())
|
2017-10-15 21:37:09 +02:00
|
|
|
} else if float_ty.float_width() == 32 && value >= MAX_F32_PLUS_HALF_ULP {
|
|
|
|
// We're casting to f32 and the value is > f32::MAX + 0.5 ULP -> round up to infinity.
|
2017-10-09 02:14:00 +02:00
|
|
|
let infinity_bits = C_u32(ccx, ieee::Single::INFINITY.to_bits() as u32);
|
|
|
|
consts::bitcast(infinity_bits, float_ty)
|
|
|
|
} else {
|
|
|
|
llvm::LLVMConstUIToFP(llval, float_ty.to_ref())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-12-17 19:54:32 -07:00
|
|
|
impl<'a, 'tcx> MirContext<'a, 'tcx> {
|
2015-10-21 17:42:25 -04:00
|
|
|
pub fn trans_constant(&mut self,
|
2016-12-31 16:00:24 -07:00
|
|
|
bcx: &Builder<'a, 'tcx>,
|
2015-10-21 17:42:25 -04:00
|
|
|
constant: &mir::Constant<'tcx>)
|
2016-04-26 23:54:38 +03:00
|
|
|
-> Const<'tcx>
|
2015-10-21 17:42:25 -04:00
|
|
|
{
|
2016-09-12 01:53:43 +03:00
|
|
|
debug!("trans_constant({:?})", constant);
|
2016-12-18 16:05:40 -07:00
|
|
|
let ty = self.monomorphize(&constant.ty);
|
2016-05-03 00:26:41 +03:00
|
|
|
let result = match constant.literal.clone() {
|
|
|
|
mir::Literal::Promoted { index } => {
|
|
|
|
let mir = &self.mir.promoted[index];
|
2016-12-19 16:25:00 -07:00
|
|
|
MirConstContext::new(bcx.ccx, mir, self.param_substs, IndexVec::new()).trans()
|
2016-01-05 12:29:50 -05:00
|
|
|
}
|
2016-04-21 16:15:56 +03:00
|
|
|
mir::Literal::Value { value } => {
|
2017-09-03 20:34:48 +03:00
|
|
|
if let ConstVal::Unevaluated(def_id, substs) = value.val {
|
|
|
|
let substs = self.monomorphize(&substs);
|
|
|
|
MirConstContext::trans_def(bcx.ccx, def_id, substs, IndexVec::new())
|
|
|
|
} else {
|
|
|
|
Ok(Const::from_constval(bcx.ccx, &value.val, ty))
|
|
|
|
}
|
2016-05-03 00:26:41 +03:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2016-09-12 01:53:43 +03:00
|
|
|
let result = result.unwrap_or_else(|_| {
|
2016-08-16 17:41:38 +03:00
|
|
|
// We've errored, so we don't have to produce working code.
|
2017-09-20 23:07:47 +03:00
|
|
|
let llty = bcx.ccx.layout_of(ty).llvm_type(bcx.ccx);
|
2016-08-16 17:41:38 +03:00
|
|
|
Const::new(C_undef(llty), ty)
|
2016-09-12 01:53:43 +03:00
|
|
|
});
|
|
|
|
|
|
|
|
debug!("trans_constant({:?}) = {:?}", constant, result);
|
|
|
|
result
|
2015-10-21 17:42:25 -04:00
|
|
|
}
|
|
|
|
}
|
2016-04-21 16:15:56 +03:00
|
|
|
|
|
|
|
|
2017-02-15 15:00:20 +02:00
|
|
|
pub fn trans_static_initializer<'a, 'tcx>(
|
2018-01-05 07:01:54 +02:00
|
|
|
ccx: &CodegenCx<'a, 'tcx>,
|
2017-02-15 15:00:20 +02:00
|
|
|
def_id: DefId)
|
|
|
|
-> Result<ValueRef, ConstEvalErr<'tcx>>
|
|
|
|
{
|
2017-02-08 18:31:03 +01:00
|
|
|
MirConstContext::trans_def(ccx, def_id, Substs::empty(), IndexVec::new())
|
|
|
|
.map(|c| c.llval)
|
2016-04-21 16:15:56 +03:00
|
|
|
}
|
2017-01-02 11:00:42 -07:00
|
|
|
|
|
|
|
/// Construct a constant value, suitable for initializing a
|
|
|
|
/// GlobalVariable, given a case and constant values for its fields.
|
|
|
|
/// Note that this may have a different LLVM type (and different
|
|
|
|
/// alignment!) from the representation's `type_of`, so it needs a
|
|
|
|
/// pointer cast before use.
|
|
|
|
///
|
|
|
|
/// The LLVM type system does not directly support unions, and only
|
|
|
|
/// pointers can be bitcast, so a constant (and, by extension, the
|
|
|
|
/// GlobalVariable initialized by it) will have a type that can vary
|
|
|
|
/// depending on which case of an enum it is.
|
|
|
|
///
|
|
|
|
/// To understand the alignment situation, consider `enum E { V64(u64),
|
|
|
|
/// V32(u32, u32) }` on Windows. The type has 8-byte alignment to
|
|
|
|
/// accommodate the u64, but `V32(x, y)` would have LLVM type `{i32,
|
|
|
|
/// i32, i32}`, which is 4-byte aligned.
|
|
|
|
///
|
|
|
|
/// Currently the returned value has the same size as the type, but
|
|
|
|
/// this could be changed in the future to avoid allocating unnecessary
|
|
|
|
/// space after values of shorter-than-maximum cases.
|
2017-06-01 21:50:53 +03:00
|
|
|
fn trans_const_adt<'a, 'tcx>(
|
2018-01-05 07:01:54 +02:00
|
|
|
ccx: &CodegenCx<'a, 'tcx>,
|
2017-01-02 11:00:42 -07:00
|
|
|
t: Ty<'tcx>,
|
|
|
|
kind: &mir::AggregateKind,
|
2017-06-01 21:50:53 +03:00
|
|
|
vals: &[Const<'tcx>]
|
|
|
|
) -> Const<'tcx> {
|
2017-01-02 11:00:42 -07:00
|
|
|
let l = ccx.layout_of(t);
|
|
|
|
let variant_index = match *kind {
|
|
|
|
mir::AggregateKind::Adt(_, index, _, _) => index,
|
|
|
|
_ => 0,
|
|
|
|
};
|
2017-09-26 21:34:10 +03:00
|
|
|
|
|
|
|
if let layout::Abi::Uninhabited = l.abi {
|
|
|
|
return Const::new(C_undef(l.llvm_type(ccx)), t);
|
|
|
|
}
|
|
|
|
|
2017-09-23 01:54:45 +03:00
|
|
|
match l.variants {
|
|
|
|
layout::Variants::Single { index } => {
|
|
|
|
assert_eq!(variant_index, index);
|
2017-12-13 01:57:56 +02:00
|
|
|
if let layout::FieldPlacement::Union(_) = l.fields {
|
2017-09-23 01:54:45 +03:00
|
|
|
assert_eq!(variant_index, 0);
|
|
|
|
assert_eq!(vals.len(), 1);
|
2017-12-01 18:29:35 +02:00
|
|
|
let (field_size, field_align) = ccx.size_and_align_of(vals[0].ty);
|
2017-09-23 01:54:45 +03:00
|
|
|
let contents = [
|
|
|
|
vals[0].llval,
|
2017-12-01 18:29:35 +02:00
|
|
|
padding(ccx, l.size - field_size)
|
2017-09-23 01:54:45 +03:00
|
|
|
];
|
|
|
|
|
2017-12-01 18:29:35 +02:00
|
|
|
let packed = l.align.abi() < field_align.abi();
|
|
|
|
Const::new(C_struct(ccx, &contents, packed), t)
|
2017-09-23 01:54:45 +03:00
|
|
|
} else {
|
2017-12-13 01:57:56 +02:00
|
|
|
if let layout::Abi::Vector { .. } = l.abi {
|
|
|
|
if let layout::FieldPlacement::Array { .. } = l.fields {
|
|
|
|
return Const::new(C_vector(&vals.iter().map(|x| x.llval)
|
|
|
|
.collect::<Vec<_>>()), t);
|
|
|
|
}
|
|
|
|
}
|
2017-09-23 01:54:45 +03:00
|
|
|
build_const_struct(ccx, l, vals, None)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
layout::Variants::Tagged { .. } => {
|
2017-01-02 11:00:42 -07:00
|
|
|
let discr = match *kind {
|
|
|
|
mir::AggregateKind::Adt(adt_def, _, _, _) => {
|
2018-01-05 06:58:34 +02:00
|
|
|
adt_def.discriminant_for_variant(ccx.tcx, variant_index)
|
2017-04-15 04:14:44 +03:00
|
|
|
.to_u128_unchecked() as u64
|
2017-01-02 11:00:42 -07:00
|
|
|
},
|
2017-04-15 04:14:44 +03:00
|
|
|
_ => 0,
|
2017-01-02 11:00:42 -07:00
|
|
|
};
|
2017-09-24 12:12:26 +03:00
|
|
|
let discr_field = l.field(ccx, 0);
|
|
|
|
let discr = C_int(discr_field.llvm_type(ccx), discr as i64);
|
2017-09-16 23:12:39 +03:00
|
|
|
if let layout::Abi::Scalar(_) = l.abi {
|
2017-09-20 18:17:23 +03:00
|
|
|
Const::new(discr, t)
|
2017-09-16 23:12:39 +03:00
|
|
|
} else {
|
2017-09-24 12:12:26 +03:00
|
|
|
let discr = Const::new(discr, discr_field.ty);
|
2017-09-26 21:34:10 +03:00
|
|
|
build_const_struct(ccx, l.for_variant(ccx, variant_index), vals, Some(discr))
|
2017-09-16 23:12:39 +03:00
|
|
|
}
|
2017-01-02 11:00:42 -07:00
|
|
|
}
|
2017-10-12 03:55:49 +03:00
|
|
|
layout::Variants::NicheFilling {
|
|
|
|
dataful_variant,
|
|
|
|
ref niche_variants,
|
|
|
|
niche_start,
|
|
|
|
..
|
|
|
|
} => {
|
2017-09-24 12:12:26 +03:00
|
|
|
if variant_index == dataful_variant {
|
2017-09-26 21:34:10 +03:00
|
|
|
build_const_struct(ccx, l.for_variant(ccx, dataful_variant), vals, None)
|
2017-01-02 11:00:42 -07:00
|
|
|
} else {
|
2017-09-24 12:12:26 +03:00
|
|
|
let niche = l.field(ccx, 0);
|
|
|
|
let niche_llty = niche.llvm_type(ccx);
|
2017-10-12 03:55:49 +03:00
|
|
|
let niche_value = ((variant_index - niche_variants.start) as u128)
|
|
|
|
.wrapping_add(niche_start);
|
2017-09-24 12:12:26 +03:00
|
|
|
// FIXME(eddyb) Check the actual primitive type here.
|
|
|
|
let niche_llval = if niche_value == 0 {
|
|
|
|
// HACK(eddyb) Using `C_null` as it works on all types.
|
|
|
|
C_null(niche_llty)
|
|
|
|
} else {
|
|
|
|
C_uint_big(niche_llty, niche_value)
|
|
|
|
};
|
|
|
|
build_const_struct(ccx, l, &[Const::new(niche_llval, niche.ty)], None)
|
2017-01-02 11:00:42 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Building structs is a little complicated, because we might need to
|
|
|
|
/// insert padding if a field's value is less aligned than its type.
|
|
|
|
///
|
2017-06-01 21:50:53 +03:00
|
|
|
/// Continuing the example from `trans_const_adt`, a value of type `(u32,
|
2017-01-02 11:00:42 -07:00
|
|
|
/// E)` should have the `E` at offset 8, but if that field's
|
|
|
|
/// initializer is 4-byte aligned then simply translating the tuple as
|
|
|
|
/// a two-element struct will locate it at offset 4, and accesses to it
|
|
|
|
/// will read the wrong memory.
|
2018-01-05 07:01:54 +02:00
|
|
|
fn build_const_struct<'a, 'tcx>(ccx: &CodegenCx<'a, 'tcx>,
|
2017-09-21 20:40:50 +03:00
|
|
|
layout: layout::TyLayout<'tcx>,
|
2017-09-10 17:15:29 +03:00
|
|
|
vals: &[Const<'tcx>],
|
|
|
|
discr: Option<Const<'tcx>>)
|
2017-06-01 21:50:53 +03:00
|
|
|
-> Const<'tcx> {
|
2017-09-17 19:34:28 +03:00
|
|
|
assert_eq!(vals.len(), layout.fields.count());
|
2017-01-02 11:00:42 -07:00
|
|
|
|
2017-10-09 02:31:06 +03:00
|
|
|
match layout.abi {
|
|
|
|
layout::Abi::Scalar(_) |
|
2017-12-13 01:57:56 +02:00
|
|
|
layout::Abi::ScalarPair(..) |
|
|
|
|
layout::Abi::Vector { .. } if discr.is_none() => {
|
2017-10-09 02:31:06 +03:00
|
|
|
let mut non_zst_fields = vals.iter().enumerate().map(|(i, f)| {
|
|
|
|
(f, layout.fields.offset(i))
|
|
|
|
}).filter(|&(f, _)| !ccx.layout_of(f.ty).is_zst());
|
|
|
|
match (non_zst_fields.next(), non_zst_fields.next()) {
|
|
|
|
(Some((x, offset)), None) if offset.bytes() == 0 => {
|
|
|
|
return Const::new(x.llval, layout.ty);
|
|
|
|
}
|
|
|
|
(Some((a, a_offset)), Some((b, _))) if a_offset.bytes() == 0 => {
|
|
|
|
return Const::new(C_struct(ccx, &[a.llval, b.llval], false), layout.ty);
|
|
|
|
}
|
|
|
|
(Some((a, _)), Some((b, b_offset))) if b_offset.bytes() == 0 => {
|
|
|
|
return Const::new(C_struct(ccx, &[b.llval, a.llval], false), layout.ty);
|
|
|
|
}
|
|
|
|
_ => {}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
_ => {}
|
2017-10-06 10:25:35 +03:00
|
|
|
}
|
|
|
|
|
2017-01-02 11:00:42 -07:00
|
|
|
// offset of current value
|
2017-12-01 18:29:35 +02:00
|
|
|
let mut packed = false;
|
2017-06-01 21:50:53 +03:00
|
|
|
let mut offset = Size::from_bytes(0);
|
2017-01-02 11:00:42 -07:00
|
|
|
let mut cfields = Vec::new();
|
2017-09-17 19:34:28 +03:00
|
|
|
cfields.reserve(discr.is_some() as usize + 1 + layout.fields.count() * 2);
|
2017-09-10 17:15:29 +03:00
|
|
|
|
|
|
|
if let Some(discr) = discr {
|
2017-12-01 18:29:35 +02:00
|
|
|
let (field_size, field_align) = ccx.size_and_align_of(discr.ty);
|
|
|
|
packed |= layout.align.abi() < field_align.abi();
|
2017-09-10 17:15:29 +03:00
|
|
|
cfields.push(discr.llval);
|
2017-12-01 18:29:35 +02:00
|
|
|
offset = field_size;
|
2017-09-10 17:15:29 +03:00
|
|
|
}
|
2017-01-02 11:00:42 -07:00
|
|
|
|
2017-09-19 12:38:20 +03:00
|
|
|
let parts = layout.fields.index_by_increasing_offset().map(|i| {
|
2017-09-17 19:34:28 +03:00
|
|
|
(vals[i], layout.fields.offset(i))
|
2017-01-02 11:00:42 -07:00
|
|
|
});
|
2017-06-01 21:50:53 +03:00
|
|
|
for (val, target_offset) in parts {
|
2017-12-01 18:29:35 +02:00
|
|
|
let (field_size, field_align) = ccx.size_and_align_of(val.ty);
|
|
|
|
packed |= layout.align.abi() < field_align.abi();
|
2017-06-25 12:42:55 +03:00
|
|
|
cfields.push(padding(ccx, target_offset - offset));
|
2017-06-01 21:50:53 +03:00
|
|
|
cfields.push(val.llval);
|
2017-12-01 18:29:35 +02:00
|
|
|
offset = target_offset + field_size;
|
2017-01-02 11:00:42 -07:00
|
|
|
}
|
|
|
|
|
2017-09-17 19:34:28 +03:00
|
|
|
// Pad to the size of the whole type, not e.g. the variant.
|
|
|
|
cfields.push(padding(ccx, ccx.size_of(layout.ty) - offset));
|
2017-01-02 11:00:42 -07:00
|
|
|
|
2017-12-01 18:29:35 +02:00
|
|
|
Const::new(C_struct(ccx, &cfields, packed), layout.ty)
|
2017-01-02 11:00:42 -07:00
|
|
|
}
|
|
|
|
|
2018-01-05 07:01:54 +02:00
|
|
|
fn padding(ccx: &CodegenCx, size: Size) -> ValueRef {
|
2017-06-01 21:50:53 +03:00
|
|
|
C_undef(Type::array(&Type::i8(ccx), size.bytes()))
|
2017-01-02 11:00:42 -07:00
|
|
|
}
|