mirror of
https://github.com/rust-lang/rust.git
synced 2025-04-28 02:57:37 +00:00
Auto merge of #44275 - eddyb:deferred-ctfe, r=nikomatsakis
Evaluate fixed-length array length expressions lazily. This is in preparation for polymorphic array lengths (aka `[T; T::A]`) and const generics. We need deferred const-evaluation to break cycles when array types show up in positions which require knowing the array type to typeck the array length, e.g. the array type is in a `where` clause. The final step - actually passing bounds in scope to array length expressions from the parent - is not done because it still produces cycles when *normalizing* `ParamEnv`s, and @nikomatsakis' in-progress lazy normalization work is needed to deal with that uniformly. However, the changes here are still useful to unlock work on const generics, which @EpicatSupercell manifested interest in, and I might be mentoring them for that, but we need this baseline first. r? @nikomatsakis cc @oli-obk
This commit is contained in:
commit
3cb24bd37b
@ -611,7 +611,7 @@ pub enum BindingAnnotation {
|
||||
RefMut,
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
|
||||
#[derive(Copy, Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
|
||||
pub enum RangeEnd {
|
||||
Included,
|
||||
Excluded,
|
||||
|
@ -493,10 +493,6 @@ impl<'a, 'gcx, 'tcx> HashStable<StableHashingContext<'a, 'gcx, 'tcx>> for mir::L
|
||||
hasher: &mut StableHasher<W>) {
|
||||
mem::discriminant(self).hash_stable(hcx, hasher);
|
||||
match *self {
|
||||
mir::Literal::Item { def_id, substs } => {
|
||||
def_id.hash_stable(hcx, hasher);
|
||||
substs.hash_stable(hcx, hasher);
|
||||
}
|
||||
mir::Literal::Value { ref value } => {
|
||||
value.hash_stable(hcx, hasher);
|
||||
}
|
||||
|
@ -16,7 +16,6 @@ use rustc_data_structures::stable_hasher::{HashStable, StableHasher,
|
||||
StableHasherResult};
|
||||
use std::hash as std_hash;
|
||||
use std::mem;
|
||||
use syntax_pos::symbol::InternedString;
|
||||
use middle::region;
|
||||
use ty;
|
||||
|
||||
@ -236,6 +235,10 @@ impl<'a, 'gcx, 'tcx> HashStable<StableHashingContext<'a, 'gcx, 'tcx>> for ty::Pr
|
||||
def_id.hash_stable(hcx, hasher);
|
||||
closure_kind.hash_stable(hcx, hasher);
|
||||
}
|
||||
ty::Predicate::ConstEvaluatable(def_id, substs) => {
|
||||
def_id.hash_stable(hcx, hasher);
|
||||
substs.hash_stable(hcx, hasher);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -272,59 +275,69 @@ for ::middle::const_val::ConstVal<'gcx> {
|
||||
fn hash_stable<W: StableHasherResult>(&self,
|
||||
hcx: &mut StableHashingContext<'a, 'gcx, 'tcx>,
|
||||
hasher: &mut StableHasher<W>) {
|
||||
use middle::const_val::ConstVal;
|
||||
use middle::const_val::ConstVal::*;
|
||||
use middle::const_val::ConstAggregate::*;
|
||||
|
||||
mem::discriminant(self).hash_stable(hcx, hasher);
|
||||
|
||||
match *self {
|
||||
ConstVal::Float(ref value) => {
|
||||
Integral(ref value) => {
|
||||
value.hash_stable(hcx, hasher);
|
||||
}
|
||||
ConstVal::Integral(ref value) => {
|
||||
Float(ref value) => {
|
||||
value.hash_stable(hcx, hasher);
|
||||
}
|
||||
ConstVal::Str(ref value) => {
|
||||
Str(ref value) => {
|
||||
value.hash_stable(hcx, hasher);
|
||||
}
|
||||
ConstVal::ByteStr(ref value) => {
|
||||
ByteStr(ref value) => {
|
||||
value.hash_stable(hcx, hasher);
|
||||
}
|
||||
ConstVal::Bool(value) => {
|
||||
Bool(value) => {
|
||||
value.hash_stable(hcx, hasher);
|
||||
}
|
||||
ConstVal::Char(value) => {
|
||||
Char(value) => {
|
||||
value.hash_stable(hcx, hasher);
|
||||
}
|
||||
ConstVal::Variant(def_id) => {
|
||||
Variant(def_id) => {
|
||||
def_id.hash_stable(hcx, hasher);
|
||||
}
|
||||
ConstVal::Function(def_id, substs) => {
|
||||
Function(def_id, substs) => {
|
||||
def_id.hash_stable(hcx, hasher);
|
||||
substs.hash_stable(hcx, hasher);
|
||||
}
|
||||
ConstVal::Struct(ref name_value_map) => {
|
||||
let mut values: Vec<(InternedString, &ConstVal)> =
|
||||
name_value_map.iter()
|
||||
.map(|(name, val)| (name.as_str(), val))
|
||||
.collect();
|
||||
|
||||
Aggregate(Struct(ref name_values)) => {
|
||||
let mut values = name_values.to_vec();
|
||||
values.sort_unstable_by_key(|&(ref name, _)| name.clone());
|
||||
values.hash_stable(hcx, hasher);
|
||||
}
|
||||
ConstVal::Tuple(ref value) => {
|
||||
Aggregate(Tuple(ref value)) => {
|
||||
value.hash_stable(hcx, hasher);
|
||||
}
|
||||
ConstVal::Array(ref value) => {
|
||||
Aggregate(Array(ref value)) => {
|
||||
value.hash_stable(hcx, hasher);
|
||||
}
|
||||
ConstVal::Repeat(ref value, times) => {
|
||||
Aggregate(Repeat(ref value, times)) => {
|
||||
value.hash_stable(hcx, hasher);
|
||||
times.hash_stable(hcx, hasher);
|
||||
}
|
||||
Unevaluated(def_id, substs) => {
|
||||
def_id.hash_stable(hcx, hasher);
|
||||
substs.hash_stable(hcx, hasher);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl_stable_hash_for!(struct ::middle::const_val::ByteArray<'tcx> {
|
||||
data
|
||||
});
|
||||
|
||||
impl_stable_hash_for!(struct ty::Const<'tcx> {
|
||||
ty,
|
||||
val
|
||||
});
|
||||
|
||||
impl_stable_hash_for!(struct ty::ClosureSubsts<'tcx> { substs });
|
||||
|
||||
impl_stable_hash_for!(struct ty::GeneratorInterior<'tcx> { witness });
|
||||
|
@ -442,6 +442,7 @@ macro_rules! impl_trans_normalize {
|
||||
|
||||
impl_trans_normalize!('gcx,
|
||||
Ty<'gcx>,
|
||||
&'gcx ty::Const<'gcx>,
|
||||
&'gcx Substs<'gcx>,
|
||||
ty::FnSig<'gcx>,
|
||||
ty::PolyFnSig<'gcx>,
|
||||
@ -493,7 +494,7 @@ impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> {
|
||||
let param_env = ty::ParamEnv::empty(Reveal::All);
|
||||
let value = self.erase_regions(value);
|
||||
|
||||
if !value.has_projection_types() {
|
||||
if !value.has_projections() {
|
||||
return value;
|
||||
}
|
||||
|
||||
@ -515,7 +516,7 @@ impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> {
|
||||
|
||||
let value = self.erase_regions(value);
|
||||
|
||||
if !value.has_projection_types() {
|
||||
if !value.has_projections() {
|
||||
return value;
|
||||
}
|
||||
|
||||
|
@ -8,64 +8,66 @@
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use self::ConstVal::*;
|
||||
pub use rustc_const_math::ConstInt;
|
||||
|
||||
use hir;
|
||||
use hir::def::Def;
|
||||
use hir::def_id::DefId;
|
||||
use traits::Reveal;
|
||||
use ty::{self, TyCtxt, layout};
|
||||
use ty::subst::Substs;
|
||||
use util::common::ErrorReported;
|
||||
use rustc_const_math::*;
|
||||
|
||||
use graphviz::IntoCow;
|
||||
use errors::DiagnosticBuilder;
|
||||
use serialize::{self, Encodable, Encoder, Decodable, Decoder};
|
||||
use syntax::symbol::InternedString;
|
||||
use syntax::ast;
|
||||
use syntax_pos::Span;
|
||||
|
||||
use std::borrow::Cow;
|
||||
use std::collections::BTreeMap;
|
||||
use std::rc::Rc;
|
||||
|
||||
pub type EvalResult<'tcx> = Result<ConstVal<'tcx>, ConstEvalErr<'tcx>>;
|
||||
pub type EvalResult<'tcx> = Result<&'tcx ty::Const<'tcx>, ConstEvalErr<'tcx>>;
|
||||
|
||||
#[derive(Clone, Debug, Hash, RustcEncodable, RustcDecodable, Eq, PartialEq)]
|
||||
#[derive(Copy, Clone, Debug, Hash, RustcEncodable, RustcDecodable, Eq, PartialEq)]
|
||||
pub enum ConstVal<'tcx> {
|
||||
Float(ConstFloat),
|
||||
Integral(ConstInt),
|
||||
Float(ConstFloat),
|
||||
Str(InternedString),
|
||||
ByteStr(Rc<Vec<u8>>),
|
||||
ByteStr(ByteArray<'tcx>),
|
||||
Bool(bool),
|
||||
Char(char),
|
||||
Variant(DefId),
|
||||
Function(DefId, &'tcx Substs<'tcx>),
|
||||
Struct(BTreeMap<ast::Name, ConstVal<'tcx>>),
|
||||
Tuple(Vec<ConstVal<'tcx>>),
|
||||
Array(Vec<ConstVal<'tcx>>),
|
||||
Repeat(Box<ConstVal<'tcx>>, u64),
|
||||
Aggregate(ConstAggregate<'tcx>),
|
||||
Unevaluated(DefId, &'tcx Substs<'tcx>),
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, Hash, RustcEncodable, Eq, PartialEq)]
|
||||
pub struct ByteArray<'tcx> {
|
||||
pub data: &'tcx [u8],
|
||||
}
|
||||
|
||||
impl<'tcx> serialize::UseSpecializedDecodable for ByteArray<'tcx> {}
|
||||
|
||||
#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
|
||||
pub enum ConstAggregate<'tcx> {
|
||||
Struct(&'tcx [(ast::Name, &'tcx ty::Const<'tcx>)]),
|
||||
Tuple(&'tcx [&'tcx ty::Const<'tcx>]),
|
||||
Array(&'tcx [&'tcx ty::Const<'tcx>]),
|
||||
Repeat(&'tcx ty::Const<'tcx>, u64),
|
||||
}
|
||||
|
||||
impl<'tcx> Encodable for ConstAggregate<'tcx> {
|
||||
fn encode<S: Encoder>(&self, _: &mut S) -> Result<(), S::Error> {
|
||||
bug!("should never encode ConstAggregate::{:?}", self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Decodable for ConstAggregate<'tcx> {
|
||||
fn decode<D: Decoder>(_: &mut D) -> Result<Self, D::Error> {
|
||||
bug!("should never decode ConstAggregate")
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> ConstVal<'tcx> {
|
||||
pub fn description(&self) -> &'static str {
|
||||
match *self {
|
||||
Float(f) => f.description(),
|
||||
Integral(i) => i.description(),
|
||||
Str(_) => "string literal",
|
||||
ByteStr(_) => "byte string literal",
|
||||
Bool(_) => "boolean",
|
||||
Char(..) => "char",
|
||||
Variant(_) => "enum variant",
|
||||
Struct(_) => "struct",
|
||||
Tuple(_) => "tuple",
|
||||
Function(..) => "function definition",
|
||||
Array(..) => "array",
|
||||
Repeat(..) => "repeat",
|
||||
}
|
||||
}
|
||||
|
||||
pub fn to_const_int(&self) -> Option<ConstInt> {
|
||||
match *self {
|
||||
ConstVal::Integral(i) => Some(i),
|
||||
@ -86,8 +88,6 @@ pub struct ConstEvalErr<'tcx> {
|
||||
pub enum ErrKind<'tcx> {
|
||||
CannotCast,
|
||||
MissingStructField,
|
||||
NegateOn(ConstVal<'tcx>),
|
||||
NotOn(ConstVal<'tcx>),
|
||||
|
||||
NonConstPath,
|
||||
UnimplementedConstVal(&'static str),
|
||||
@ -146,9 +146,6 @@ impl<'a, 'gcx, 'tcx> ConstEvalErr<'tcx> {
|
||||
|
||||
match self.kind {
|
||||
CannotCast => simple!("can't cast this type"),
|
||||
NegateOn(ref const_val) => simple!("negate on {}", const_val.description()),
|
||||
NotOn(ref const_val) => simple!("not on {}", const_val.description()),
|
||||
|
||||
MissingStructField => simple!("nonexistent struct field"),
|
||||
NonConstPath => simple!("non-constant path in constant expression"),
|
||||
UnimplementedConstVal(what) =>
|
||||
@ -221,37 +218,3 @@ impl<'a, 'gcx, 'tcx> ConstEvalErr<'tcx> {
|
||||
self.struct_error(tcx, primary_span, primary_kind).emit();
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the value of the length-valued expression
|
||||
pub fn eval_length(tcx: TyCtxt,
|
||||
count: hir::BodyId,
|
||||
reason: &str)
|
||||
-> Result<usize, ErrorReported>
|
||||
{
|
||||
let count_expr = &tcx.hir.body(count).value;
|
||||
let count_def_id = tcx.hir.body_owner_def_id(count);
|
||||
let param_env = ty::ParamEnv::empty(Reveal::UserFacing);
|
||||
let substs = Substs::identity_for_item(tcx.global_tcx(), count_def_id);
|
||||
match tcx.at(count_expr.span).const_eval(param_env.and((count_def_id, substs))) {
|
||||
Ok(Integral(Usize(count))) => {
|
||||
let val = count.as_u64(tcx.sess.target.uint_type);
|
||||
assert_eq!(val as usize as u64, val);
|
||||
Ok(val as usize)
|
||||
},
|
||||
Ok(_) |
|
||||
Err(ConstEvalErr { kind: ErrKind::TypeckError, .. }) => Err(ErrorReported),
|
||||
Err(err) => {
|
||||
let mut diag = err.struct_error(tcx, count_expr.span, reason);
|
||||
|
||||
if let hir::ExprPath(hir::QPath::Resolved(None, ref path)) = count_expr.node {
|
||||
if let Def::Local(..) = path.def {
|
||||
diag.note(&format!("`{}` is a variable",
|
||||
tcx.hir.node_to_pretty_string(count_expr.id)));
|
||||
}
|
||||
}
|
||||
|
||||
diag.emit();
|
||||
Err(ErrorReported)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -147,7 +147,8 @@ impl<'tcx> FreeRegionMap<'tcx> {
|
||||
ty::Predicate::WellFormed(..) |
|
||||
ty::Predicate::ObjectSafe(..) |
|
||||
ty::Predicate::ClosureKind(..) |
|
||||
ty::Predicate::TypeOutlives(..) => {
|
||||
ty::Predicate::TypeOutlives(..) |
|
||||
ty::Predicate::ConstEvaluatable(..) => {
|
||||
// No region bounds here
|
||||
}
|
||||
ty::Predicate::RegionOutlives(ty::Binder(ty::OutlivesPredicate(r_a, r_b))) => {
|
||||
|
@ -876,7 +876,8 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
|
||||
|
||||
// Always promote `[T; 0]` (even when e.g. borrowed mutably).
|
||||
let promotable = match expr_ty.sty {
|
||||
ty::TyArray(_, 0) => true,
|
||||
ty::TyArray(_, len) if
|
||||
len.val.to_const_int().and_then(|i| i.to_u64()) == Some(0) => true,
|
||||
_ => promotable,
|
||||
};
|
||||
|
||||
|
@ -1187,10 +1187,16 @@ impl<'tcx> Operand<'tcx> {
|
||||
substs: &'tcx Substs<'tcx>,
|
||||
span: Span,
|
||||
) -> Self {
|
||||
let ty = tcx.type_of(def_id).subst(tcx, substs);
|
||||
Operand::Constant(box Constant {
|
||||
span,
|
||||
ty: tcx.type_of(def_id).subst(tcx, substs),
|
||||
literal: Literal::Value { value: ConstVal::Function(def_id, substs) },
|
||||
ty,
|
||||
literal: Literal::Value {
|
||||
value: tcx.mk_const(ty::Const {
|
||||
val: ConstVal::Function(def_id, substs),
|
||||
ty
|
||||
})
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
@ -1473,12 +1479,8 @@ newtype_index!(Promoted, "promoted");
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)]
|
||||
pub enum Literal<'tcx> {
|
||||
Item {
|
||||
def_id: DefId,
|
||||
substs: &'tcx Substs<'tcx>,
|
||||
},
|
||||
Value {
|
||||
value: ConstVal<'tcx>,
|
||||
value: &'tcx ty::Const<'tcx>,
|
||||
},
|
||||
Promoted {
|
||||
// Index into the `promoted` vector of `Mir`.
|
||||
@ -1496,12 +1498,9 @@ impl<'tcx> Debug for Literal<'tcx> {
|
||||
fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
|
||||
use self::Literal::*;
|
||||
match *self {
|
||||
Item { def_id, substs } => {
|
||||
ppaux::parameterized(fmt, substs, def_id, &[])
|
||||
}
|
||||
Value { ref value } => {
|
||||
Value { value } => {
|
||||
write!(fmt, "const ")?;
|
||||
fmt_const_val(fmt, value)
|
||||
fmt_const_val(fmt, &value.val)
|
||||
}
|
||||
Promoted { index } => {
|
||||
write!(fmt, "{:?}", index)
|
||||
@ -1516,9 +1515,9 @@ fn fmt_const_val<W: Write>(fmt: &mut W, const_val: &ConstVal) -> fmt::Result {
|
||||
match *const_val {
|
||||
Float(f) => write!(fmt, "{:?}", f),
|
||||
Integral(n) => write!(fmt, "{}", n),
|
||||
Str(ref s) => write!(fmt, "{:?}", s),
|
||||
ByteStr(ref bytes) => {
|
||||
let escaped: String = bytes
|
||||
Str(s) => write!(fmt, "{:?}", s),
|
||||
ByteStr(bytes) => {
|
||||
let escaped: String = bytes.data
|
||||
.iter()
|
||||
.flat_map(|&ch| ascii::escape_default(ch).map(|c| c as char))
|
||||
.collect();
|
||||
@ -1528,8 +1527,8 @@ fn fmt_const_val<W: Write>(fmt: &mut W, const_val: &ConstVal) -> fmt::Result {
|
||||
Char(c) => write!(fmt, "{:?}", c),
|
||||
Variant(def_id) |
|
||||
Function(def_id, _) => write!(fmt, "{}", item_path_str(def_id)),
|
||||
Struct(_) | Tuple(_) | Array(_) | Repeat(..) =>
|
||||
bug!("ConstVal `{:?}` should not be in MIR", const_val),
|
||||
Aggregate(_) => bug!("`ConstVal::{:?}` should not be in MIR", const_val),
|
||||
Unevaluated(..) => write!(fmt, "{:?}", const_val)
|
||||
}
|
||||
}
|
||||
|
||||
@ -1996,17 +1995,16 @@ impl<'tcx> TypeFoldable<'tcx> for Constant<'tcx> {
|
||||
impl<'tcx> TypeFoldable<'tcx> for Literal<'tcx> {
|
||||
fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
|
||||
match *self {
|
||||
Literal::Item { def_id, substs } => Literal::Item {
|
||||
def_id,
|
||||
substs: substs.fold_with(folder)
|
||||
Literal::Value { value } => Literal::Value {
|
||||
value: value.fold_with(folder)
|
||||
},
|
||||
_ => self.clone()
|
||||
Literal::Promoted { index } => Literal::Promoted { index }
|
||||
}
|
||||
}
|
||||
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
|
||||
match *self {
|
||||
Literal::Item { substs, .. } => substs.visit_with(visitor),
|
||||
_ => false
|
||||
Literal::Value { value } => value.visit_with(visitor),
|
||||
Literal::Promoted { .. } => false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -70,7 +70,9 @@ impl<'a, 'gcx, 'tcx> LvalueTy<'tcx> {
|
||||
LvalueTy::Ty {
|
||||
ty: match ty.sty {
|
||||
ty::TyArray(inner, size) => {
|
||||
tcx.mk_array(inner, size-(from as usize)-(to as usize))
|
||||
let size = size.val.to_const_int().unwrap().to_u64().unwrap();
|
||||
let len = size - (from as u64) - (to as u64);
|
||||
tcx.mk_array(inner, len)
|
||||
}
|
||||
ty::TySlice(..) => ty,
|
||||
_ => {
|
||||
@ -146,11 +148,8 @@ impl<'tcx> Rvalue<'tcx> {
|
||||
{
|
||||
match *self {
|
||||
Rvalue::Use(ref operand) => operand.ty(local_decls, tcx),
|
||||
Rvalue::Repeat(ref operand, ref count) => {
|
||||
let op_ty = operand.ty(local_decls, tcx);
|
||||
let count = count.as_u64(tcx.sess.target.uint_type);
|
||||
assert_eq!(count as usize as u64, count);
|
||||
tcx.mk_array(op_ty, count as usize)
|
||||
Rvalue::Repeat(ref operand, count) => {
|
||||
tcx.mk_array_const_usize(operand.ty(local_decls, tcx), count)
|
||||
}
|
||||
Rvalue::Ref(reg, bk, ref lv) => {
|
||||
let lv_ty = lv.ty(local_decls, tcx).to_ty(tcx);
|
||||
@ -193,7 +192,7 @@ impl<'tcx> Rvalue<'tcx> {
|
||||
Rvalue::Aggregate(ref ak, ref ops) => {
|
||||
match **ak {
|
||||
AggregateKind::Array(ty) => {
|
||||
tcx.mk_array(ty, ops.len())
|
||||
tcx.mk_array(ty, ops.len() as u64)
|
||||
}
|
||||
AggregateKind::Tuple => {
|
||||
tcx.mk_tup(
|
||||
|
@ -8,7 +8,6 @@
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use middle::const_val::ConstVal;
|
||||
use hir::def_id::DefId;
|
||||
use ty::subst::Substs;
|
||||
use ty::{ClosureSubsts, Region, Ty, GeneratorInterior};
|
||||
@ -214,6 +213,18 @@ macro_rules! make_mir_visitor {
|
||||
self.super_ty(ty);
|
||||
}
|
||||
|
||||
fn visit_region(&mut self,
|
||||
region: & $($mutability)* ty::Region<'tcx>,
|
||||
_: Location) {
|
||||
self.super_region(region);
|
||||
}
|
||||
|
||||
fn visit_const(&mut self,
|
||||
constant: & $($mutability)* &'tcx ty::Const<'tcx>,
|
||||
_: Location) {
|
||||
self.super_const(constant);
|
||||
}
|
||||
|
||||
fn visit_substs(&mut self,
|
||||
substs: & $($mutability)* &'tcx Substs<'tcx>,
|
||||
_: Location) {
|
||||
@ -232,12 +243,6 @@ macro_rules! make_mir_visitor {
|
||||
self.super_generator_interior(interior);
|
||||
}
|
||||
|
||||
fn visit_const_val(&mut self,
|
||||
const_val: & $($mutability)* ConstVal,
|
||||
_: Location) {
|
||||
self.super_const_val(const_val);
|
||||
}
|
||||
|
||||
fn visit_const_int(&mut self,
|
||||
const_int: &ConstInt,
|
||||
_: Location) {
|
||||
@ -517,9 +522,10 @@ macro_rules! make_mir_visitor {
|
||||
self.visit_const_usize(length, location);
|
||||
}
|
||||
|
||||
Rvalue::Ref(r, bk, ref $($mutability)* path) => {
|
||||
Rvalue::Ref(ref $($mutability)* r, bk, ref $($mutability)* path) => {
|
||||
self.visit_region(r, location);
|
||||
self.visit_lvalue(path, LvalueContext::Borrow {
|
||||
region: r,
|
||||
region: *r,
|
||||
kind: bk
|
||||
}, location);
|
||||
}
|
||||
@ -718,13 +724,8 @@ macro_rules! make_mir_visitor {
|
||||
literal: & $($mutability)* Literal<'tcx>,
|
||||
location: Location) {
|
||||
match *literal {
|
||||
Literal::Item { ref $($mutability)* def_id,
|
||||
ref $($mutability)* substs } => {
|
||||
self.visit_def_id(def_id, location);
|
||||
self.visit_substs(substs, location);
|
||||
}
|
||||
Literal::Value { ref $($mutability)* value } => {
|
||||
self.visit_const_val(value, location);
|
||||
self.visit_const(value, location);
|
||||
}
|
||||
Literal::Promoted { index: _ } => {}
|
||||
}
|
||||
@ -749,6 +750,12 @@ macro_rules! make_mir_visitor {
|
||||
fn super_ty(&mut self, _ty: & $($mutability)* Ty<'tcx>) {
|
||||
}
|
||||
|
||||
fn super_region(&mut self, _region: & $($mutability)* ty::Region<'tcx>) {
|
||||
}
|
||||
|
||||
fn super_const(&mut self, _const: & $($mutability)* &'tcx ty::Const<'tcx>) {
|
||||
}
|
||||
|
||||
fn super_substs(&mut self, _substs: & $($mutability)* &'tcx Substs<'tcx>) {
|
||||
}
|
||||
|
||||
@ -760,9 +767,6 @@ macro_rules! make_mir_visitor {
|
||||
_substs: & $($mutability)* ClosureSubsts<'tcx>) {
|
||||
}
|
||||
|
||||
fn super_const_val(&mut self, _const_val: & $($mutability)* ConstVal) {
|
||||
}
|
||||
|
||||
fn super_const_int(&mut self, _const_int: &ConstInt) {
|
||||
}
|
||||
|
||||
|
@ -48,8 +48,8 @@ use std::path::PathBuf;
|
||||
|
||||
pub struct Config {
|
||||
pub target: Target,
|
||||
pub int_type: IntTy,
|
||||
pub uint_type: UintTy,
|
||||
pub isize_ty: IntTy,
|
||||
pub usize_ty: UintTy,
|
||||
}
|
||||
|
||||
#[derive(Clone, Hash, Debug)]
|
||||
@ -1149,7 +1149,7 @@ pub fn build_target_config(opts: &Options, sp: &Handler) -> Config {
|
||||
}
|
||||
};
|
||||
|
||||
let (int_type, uint_type) = match &target.target_pointer_width[..] {
|
||||
let (isize_ty, usize_ty) = match &target.target_pointer_width[..] {
|
||||
"16" => (ast::IntTy::I16, ast::UintTy::U16),
|
||||
"32" => (ast::IntTy::I32, ast::UintTy::U32),
|
||||
"64" => (ast::IntTy::I64, ast::UintTy::U64),
|
||||
@ -1159,8 +1159,8 @@ pub fn build_target_config(opts: &Options, sp: &Handler) -> Config {
|
||||
|
||||
Config {
|
||||
target,
|
||||
int_type,
|
||||
uint_type,
|
||||
isize_ty,
|
||||
usize_ty,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -19,6 +19,7 @@ use super::{
|
||||
OnUnimplementedNote,
|
||||
OutputTypeParameterMismatch,
|
||||
TraitNotObjectSafe,
|
||||
ConstEvalFailure,
|
||||
PredicateObligation,
|
||||
Reveal,
|
||||
SelectionContext,
|
||||
@ -31,6 +32,7 @@ use hir;
|
||||
use hir::def_id::DefId;
|
||||
use infer::{self, InferCtxt};
|
||||
use infer::type_variable::TypeVariableOrigin;
|
||||
use middle::const_val;
|
||||
use rustc::lint::builtin::EXTRA_REQUIREMENT_IN_IMPL;
|
||||
use std::fmt;
|
||||
use syntax::ast;
|
||||
@ -698,6 +700,14 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
||||
// (which may fail).
|
||||
span_bug!(span, "WF predicate not satisfied for {:?}", ty);
|
||||
}
|
||||
|
||||
ty::Predicate::ConstEvaluatable(..) => {
|
||||
// Errors for `ConstEvaluatable` predicates show up as
|
||||
// `SelectionError::ConstEvalFailure`,
|
||||
// not `Unimplemented`.
|
||||
span_bug!(span,
|
||||
"const-evaluatable requirement gave wrong error: `{:?}`", obligation)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -762,6 +772,13 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
||||
self.tcx.report_object_safety_error(span, did,
|
||||
violations)
|
||||
}
|
||||
|
||||
ConstEvalFailure(ref err) => {
|
||||
if let const_val::ErrKind::TypeckError = err.kind {
|
||||
return;
|
||||
}
|
||||
err.struct_error(self.tcx, span, "constant expression")
|
||||
}
|
||||
};
|
||||
self.note_obligation_cause(&mut err, obligation);
|
||||
err.emit();
|
||||
|
@ -25,7 +25,7 @@ use super::{FulfillmentError, FulfillmentErrorCode};
|
||||
use super::{ObligationCause, PredicateObligation, Obligation};
|
||||
use super::project;
|
||||
use super::select::SelectionContext;
|
||||
use super::Unimplemented;
|
||||
use super::{Unimplemented, ConstEvalFailure};
|
||||
|
||||
impl<'tcx> ForestObligation for PendingPredicateObligation<'tcx> {
|
||||
type Predicate = ty::Predicate<'tcx>;
|
||||
@ -540,6 +540,29 @@ fn process_predicate<'a, 'gcx, 'tcx>(
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ty::Predicate::ConstEvaluatable(def_id, substs) => {
|
||||
match selcx.tcx().lift_to_global(&obligation.param_env) {
|
||||
None => {
|
||||
Ok(None)
|
||||
}
|
||||
Some(param_env) => {
|
||||
match selcx.tcx().lift_to_global(&substs) {
|
||||
None => {
|
||||
pending_obligation.stalled_on = substs.types().collect();
|
||||
Ok(None)
|
||||
}
|
||||
Some(substs) => {
|
||||
match selcx.tcx().at(obligation.cause.span)
|
||||
.const_eval(param_env.and((def_id, substs))) {
|
||||
Ok(_) => Ok(Some(vec![])),
|
||||
Err(e) => Err(CodeSelectionError(ConstEvalFailure(e)))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -17,6 +17,7 @@ pub use self::ObligationCauseCode::*;
|
||||
|
||||
use hir;
|
||||
use hir::def_id::DefId;
|
||||
use middle::const_val::ConstEvalErr;
|
||||
use middle::region;
|
||||
use middle::free_region::FreeRegionMap;
|
||||
use ty::subst::Substs;
|
||||
@ -218,6 +219,7 @@ pub enum SelectionError<'tcx> {
|
||||
ty::PolyTraitRef<'tcx>,
|
||||
ty::error::TypeError<'tcx>),
|
||||
TraitNotObjectSafe(DefId),
|
||||
ConstEvalFailure(ConstEvalErr<'tcx>),
|
||||
}
|
||||
|
||||
pub struct FulfillmentError<'tcx> {
|
||||
|
@ -169,7 +169,8 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
|
||||
ty::Predicate::RegionOutlives(..) |
|
||||
ty::Predicate::ClosureKind(..) |
|
||||
ty::Predicate::Subtype(..) |
|
||||
ty::Predicate::Equate(..) => {
|
||||
ty::Predicate::Equate(..) |
|
||||
ty::Predicate::ConstEvaluatable(..) => {
|
||||
false
|
||||
}
|
||||
}
|
||||
@ -203,7 +204,8 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
|
||||
ty::Predicate::WellFormed(..) |
|
||||
ty::Predicate::ObjectSafe(..) |
|
||||
ty::Predicate::ClosureKind(..) |
|
||||
ty::Predicate::TypeOutlives(..) => {
|
||||
ty::Predicate::TypeOutlives(..) |
|
||||
ty::Predicate::ConstEvaluatable(..) => {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
@ -27,10 +27,11 @@ use super::util;
|
||||
use hir::def_id::DefId;
|
||||
use infer::{InferCtxt, InferOk};
|
||||
use infer::type_variable::TypeVariableOrigin;
|
||||
use middle::const_val::ConstVal;
|
||||
use rustc_data_structures::snapshot_map::{Snapshot, SnapshotMap};
|
||||
use syntax::ast;
|
||||
use syntax::symbol::Symbol;
|
||||
use ty::subst::Subst;
|
||||
use ty::subst::{Subst, Substs};
|
||||
use ty::{self, ToPredicate, ToPolyTraitRef, Ty, TyCtxt};
|
||||
use ty::fold::{TypeFoldable, TypeFolder};
|
||||
use util::common::FN_OUTPUT_NAME;
|
||||
@ -260,7 +261,7 @@ impl<'a, 'b, 'gcx, 'tcx> AssociatedTypeNormalizer<'a, 'b, 'gcx, 'tcx> {
|
||||
fn fold<T:TypeFoldable<'tcx>>(&mut self, value: &T) -> T {
|
||||
let value = self.selcx.infcx().resolve_type_vars_if_possible(value);
|
||||
|
||||
if !value.has_projection_types() {
|
||||
if !value.has_projections() {
|
||||
value.clone()
|
||||
} else {
|
||||
value.fold_with(self)
|
||||
@ -332,6 +333,39 @@ impl<'a, 'b, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for AssociatedTypeNormalizer<'a,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn fold_const(&mut self, constant: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> {
|
||||
if let ConstVal::Unevaluated(def_id, substs) = constant.val {
|
||||
if substs.needs_infer() {
|
||||
let identity_substs = Substs::identity_for_item(self.tcx(), def_id);
|
||||
let data = self.param_env.and((def_id, identity_substs));
|
||||
match self.tcx().lift_to_global(&data) {
|
||||
Some(data) => {
|
||||
match self.tcx().const_eval(data) {
|
||||
Ok(evaluated) => {
|
||||
let evaluated = evaluated.subst(self.tcx(), substs);
|
||||
return self.fold_const(evaluated);
|
||||
}
|
||||
Err(_) => {}
|
||||
}
|
||||
}
|
||||
None => {}
|
||||
}
|
||||
} else {
|
||||
let data = self.param_env.and((def_id, substs));
|
||||
match self.tcx().lift_to_global(&data) {
|
||||
Some(data) => {
|
||||
match self.tcx().const_eval(data) {
|
||||
Ok(evaluated) => return self.fold_const(evaluated),
|
||||
Err(_) => {}
|
||||
}
|
||||
}
|
||||
None => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
constant
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
@ -520,7 +554,7 @@ fn opt_normalize_projection_type<'a, 'b, 'gcx, 'tcx>(
|
||||
depth,
|
||||
obligations);
|
||||
|
||||
let result = if projected_ty.has_projection_types() {
|
||||
let result = if projected_ty.has_projections() {
|
||||
let mut normalizer = AssociatedTypeNormalizer::new(selcx,
|
||||
param_env,
|
||||
cause,
|
||||
|
@ -732,6 +732,21 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ty::Predicate::ConstEvaluatable(def_id, substs) => {
|
||||
match self.tcx().lift_to_global(&(obligation.param_env, substs)) {
|
||||
Some((param_env, substs)) => {
|
||||
match self.tcx().const_eval(param_env.and((def_id, substs))) {
|
||||
Ok(_) => EvaluatedToOk,
|
||||
Err(_) => EvaluatedToErr
|
||||
}
|
||||
}
|
||||
None => {
|
||||
// Inference variables still left in param_env or substs.
|
||||
EvaluatedToAmbig
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -173,6 +173,9 @@ impl<'a, 'tcx> Lift<'tcx> for traits::SelectionError<'a> {
|
||||
super::TraitNotObjectSafe(def_id) => {
|
||||
Some(super::TraitNotObjectSafe(def_id))
|
||||
}
|
||||
super::ConstEvalFailure(ref err) => {
|
||||
tcx.lift(err).map(super::ConstEvalFailure)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -120,7 +120,7 @@ impl<'a, 'gcx> AssociatedTypeNormalizer<'a, 'gcx> {
|
||||
}
|
||||
|
||||
fn fold<T:TypeFoldable<'gcx>>(&mut self, value: &T) -> T {
|
||||
if !value.has_projection_types() {
|
||||
if !value.has_projections() {
|
||||
value.clone()
|
||||
} else {
|
||||
value.fold_with(self)
|
||||
@ -134,7 +134,7 @@ impl<'a, 'gcx> TypeFolder<'gcx, 'gcx> for AssociatedTypeNormalizer<'a, 'gcx> {
|
||||
}
|
||||
|
||||
fn fold_ty(&mut self, ty: Ty<'gcx>) -> Ty<'gcx> {
|
||||
if !ty.has_projection_types() {
|
||||
if !ty.has_projections() {
|
||||
ty
|
||||
} else {
|
||||
self.tcx.trans_trait_caches.project_cache.memoize(ty, || {
|
||||
|
@ -48,6 +48,9 @@ fn anonymize_predicate<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
|
||||
|
||||
ty::Predicate::Subtype(ref data) =>
|
||||
ty::Predicate::Subtype(tcx.anonymize_late_bound_regions(data)),
|
||||
|
||||
ty::Predicate::ConstEvaluatable(def_id, substs) =>
|
||||
ty::Predicate::ConstEvaluatable(def_id, substs),
|
||||
}
|
||||
}
|
||||
|
||||
@ -175,6 +178,10 @@ impl<'cx, 'gcx, 'tcx> Elaborator<'cx, 'gcx, 'tcx> {
|
||||
ty::Predicate::ClosureKind(..) => {
|
||||
// Nothing to elaborate when waiting for a closure's kind to be inferred.
|
||||
}
|
||||
ty::Predicate::ConstEvaluatable(..) => {
|
||||
// Currently, we do not elaborate const-evaluatable
|
||||
// predicates.
|
||||
}
|
||||
|
||||
ty::Predicate::RegionOutlives(..) => {
|
||||
// Nothing to elaborate from `'a: 'b`.
|
||||
|
@ -21,6 +21,7 @@ use hir::map as hir_map;
|
||||
use hir::map::DefPathHash;
|
||||
use lint::{self, Lint};
|
||||
use ich::{self, StableHashingContext, NodeIdHashingMode};
|
||||
use middle::const_val::ConstVal;
|
||||
use middle::free_region::FreeRegionMap;
|
||||
use middle::lang_items;
|
||||
use middle::resolve_lifetime::{self, ObjectLifetimeDefault};
|
||||
@ -32,7 +33,7 @@ use ty::ReprOptions;
|
||||
use traits;
|
||||
use ty::{self, Ty, TypeAndMut};
|
||||
use ty::{TyS, TypeVariants, Slice};
|
||||
use ty::{AdtKind, AdtDef, ClosureSubsts, GeneratorInterior, Region};
|
||||
use ty::{AdtKind, AdtDef, ClosureSubsts, GeneratorInterior, Region, Const};
|
||||
use ty::{PolyFnSig, InferTy, ParamTy, ProjectionTy, ExistentialPredicate, Predicate};
|
||||
use ty::RegionKind;
|
||||
use ty::{TyVar, TyVid, IntVar, IntVid, FloatVar, FloatVid};
|
||||
@ -49,6 +50,7 @@ use rustc_data_structures::stable_hasher::{HashStable, StableHasher,
|
||||
StableHasherResult};
|
||||
|
||||
use arena::{TypedArena, DroplessArena};
|
||||
use rustc_const_math::{ConstInt, ConstUsize};
|
||||
use rustc_data_structures::indexed_vec::IndexVec;
|
||||
use std::borrow::Borrow;
|
||||
use std::cell::{Cell, RefCell};
|
||||
@ -108,6 +110,7 @@ pub struct CtxtInterners<'tcx> {
|
||||
region: RefCell<FxHashSet<Interned<'tcx, RegionKind>>>,
|
||||
existential_predicates: RefCell<FxHashSet<Interned<'tcx, Slice<ExistentialPredicate<'tcx>>>>>,
|
||||
predicates: RefCell<FxHashSet<Interned<'tcx, Slice<Predicate<'tcx>>>>>,
|
||||
const_: RefCell<FxHashSet<Interned<'tcx, Const<'tcx>>>>,
|
||||
}
|
||||
|
||||
impl<'gcx: 'tcx, 'tcx> CtxtInterners<'tcx> {
|
||||
@ -120,6 +123,7 @@ impl<'gcx: 'tcx, 'tcx> CtxtInterners<'tcx> {
|
||||
region: RefCell::new(FxHashSet()),
|
||||
existential_predicates: RefCell::new(FxHashSet()),
|
||||
predicates: RefCell::new(FxHashSet()),
|
||||
const_: RefCell::new(FxHashSet()),
|
||||
}
|
||||
}
|
||||
|
||||
@ -934,6 +938,32 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
|
||||
self.global_arenas.adt_def.alloc(def)
|
||||
}
|
||||
|
||||
pub fn alloc_byte_array(self, bytes: &[u8]) -> &'gcx [u8] {
|
||||
if bytes.is_empty() {
|
||||
&[]
|
||||
} else {
|
||||
self.global_interners.arena.alloc_slice(bytes)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn alloc_const_slice(self, values: &[&'tcx ty::Const<'tcx>])
|
||||
-> &'tcx [&'tcx ty::Const<'tcx>] {
|
||||
if values.is_empty() {
|
||||
&[]
|
||||
} else {
|
||||
self.interners.arena.alloc_slice(values)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn alloc_name_const_slice(self, values: &[(ast::Name, &'tcx ty::Const<'tcx>)])
|
||||
-> &'tcx [(ast::Name, &'tcx ty::Const<'tcx>)] {
|
||||
if values.is_empty() {
|
||||
&[]
|
||||
} else {
|
||||
self.interners.arena.alloc_slice(values)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn intern_stability(self, stab: attr::Stability) -> &'gcx attr::Stability {
|
||||
if let Some(st) = self.stability_interner.borrow().get(&stab) {
|
||||
return st;
|
||||
@ -1175,18 +1205,6 @@ pub trait Lift<'tcx> {
|
||||
fn lift_to_tcx<'a, 'gcx>(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Option<Self::Lifted>;
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> Lift<'tcx> for ty::ParamEnv<'a> {
|
||||
type Lifted = ty::ParamEnv<'tcx>;
|
||||
fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option<ty::ParamEnv<'tcx>> {
|
||||
self.caller_bounds.lift_to_tcx(tcx).and_then(|caller_bounds| {
|
||||
Some(ty::ParamEnv {
|
||||
reveal: self.reveal,
|
||||
caller_bounds,
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> Lift<'tcx> for Ty<'a> {
|
||||
type Lifted = Ty<'tcx>;
|
||||
fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option<Ty<'tcx>> {
|
||||
@ -1202,6 +1220,36 @@ impl<'a, 'tcx> Lift<'tcx> for Ty<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> Lift<'tcx> for Region<'a> {
|
||||
type Lifted = Region<'tcx>;
|
||||
fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option<Region<'tcx>> {
|
||||
if tcx.interners.arena.in_arena(*self as *const _) {
|
||||
return Some(unsafe { mem::transmute(*self) });
|
||||
}
|
||||
// Also try in the global tcx if we're not that.
|
||||
if !tcx.is_global() {
|
||||
self.lift_to_tcx(tcx.global_tcx())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> Lift<'tcx> for &'a Const<'a> {
|
||||
type Lifted = &'tcx Const<'tcx>;
|
||||
fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option<&'tcx Const<'tcx>> {
|
||||
if tcx.interners.arena.in_arena(*self as *const _) {
|
||||
return Some(unsafe { mem::transmute(*self) });
|
||||
}
|
||||
// Also try in the global tcx if we're not that.
|
||||
if !tcx.is_global() {
|
||||
self.lift_to_tcx(tcx.global_tcx())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> Lift<'tcx> for &'a Substs<'a> {
|
||||
type Lifted = &'tcx Substs<'tcx>;
|
||||
fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option<&'tcx Substs<'tcx>> {
|
||||
@ -1220,21 +1268,6 @@ impl<'a, 'tcx> Lift<'tcx> for &'a Substs<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> Lift<'tcx> for Region<'a> {
|
||||
type Lifted = Region<'tcx>;
|
||||
fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option<Region<'tcx>> {
|
||||
if tcx.interners.arena.in_arena(*self as *const _) {
|
||||
return Some(unsafe { mem::transmute(*self) });
|
||||
}
|
||||
// Also try in the global tcx if we're not that.
|
||||
if !tcx.is_global() {
|
||||
self.lift_to_tcx(tcx.global_tcx())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> Lift<'tcx> for &'a Slice<Ty<'a>> {
|
||||
type Lifted = &'tcx Slice<Ty<'tcx>>;
|
||||
fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>)
|
||||
@ -1522,6 +1555,12 @@ impl<'tcx: 'lcx, 'lcx> Borrow<[Predicate<'lcx>]>
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx: 'lcx, 'lcx> Borrow<Const<'lcx>> for Interned<'tcx, Const<'tcx>> {
|
||||
fn borrow<'a>(&'a self) -> &'a Const<'lcx> {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! intern_method {
|
||||
($lt_tcx:tt, $name:ident: $method:ident($alloc:ty,
|
||||
$alloc_method:ident,
|
||||
@ -1602,7 +1641,8 @@ direct_interners!('tcx,
|
||||
&ty::ReVar(_) | &ty::ReSkolemized(..) => true,
|
||||
_ => false
|
||||
}
|
||||
}) -> RegionKind
|
||||
}) -> RegionKind,
|
||||
const_: mk_const(|c: &Const| keep_local(&c.ty) || keep_local(&c.val)) -> Const<'tcx>
|
||||
);
|
||||
|
||||
macro_rules! slice_interners {
|
||||
@ -1719,8 +1759,16 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
|
||||
self.mk_imm_ptr(self.mk_nil())
|
||||
}
|
||||
|
||||
pub fn mk_array(self, ty: Ty<'tcx>, n: usize) -> Ty<'tcx> {
|
||||
self.mk_ty(TyArray(ty, n))
|
||||
pub fn mk_array(self, ty: Ty<'tcx>, n: u64) -> Ty<'tcx> {
|
||||
let n = ConstUsize::new(n, self.sess.target.usize_ty).unwrap();
|
||||
self.mk_array_const_usize(ty, n)
|
||||
}
|
||||
|
||||
pub fn mk_array_const_usize(self, ty: Ty<'tcx>, n: ConstUsize) -> Ty<'tcx> {
|
||||
self.mk_ty(TyArray(ty, self.mk_const(ty::Const {
|
||||
val: ConstVal::Integral(ConstInt::Usize(n)),
|
||||
ty: self.types.usize
|
||||
})))
|
||||
}
|
||||
|
||||
pub fn mk_slice(self, ty: Ty<'tcx>) -> Ty<'tcx> {
|
||||
|
@ -10,6 +10,7 @@
|
||||
|
||||
use hir::def_id::DefId;
|
||||
use infer::type_variable;
|
||||
use middle::const_val::ConstVal;
|
||||
use ty::{self, BoundRegion, DefIdTree, Region, Ty, TyCtxt};
|
||||
|
||||
use std::fmt;
|
||||
@ -18,6 +19,8 @@ use syntax::ast;
|
||||
use errors::DiagnosticBuilder;
|
||||
use syntax_pos::Span;
|
||||
|
||||
use rustc_const_math::ConstInt;
|
||||
|
||||
use hir;
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
@ -34,7 +37,7 @@ pub enum TypeError<'tcx> {
|
||||
AbiMismatch(ExpectedFound<abi::Abi>),
|
||||
Mutability,
|
||||
TupleSize(ExpectedFound<usize>),
|
||||
FixedArraySize(ExpectedFound<usize>),
|
||||
FixedArraySize(ExpectedFound<u64>),
|
||||
ArgCount,
|
||||
|
||||
RegionsDoesNotOutlive(Region<'tcx>, Region<'tcx>),
|
||||
@ -179,7 +182,13 @@ impl<'a, 'gcx, 'lcx, 'tcx> ty::TyS<'tcx> {
|
||||
ty::TyTuple(ref tys, _) if tys.is_empty() => self.to_string(),
|
||||
|
||||
ty::TyAdt(def, _) => format!("{} `{}`", def.descr(), tcx.item_path_str(def.did)),
|
||||
ty::TyArray(_, n) => format!("array of {} elements", n),
|
||||
ty::TyArray(_, n) => {
|
||||
if let ConstVal::Integral(ConstInt::Usize(n)) = n.val {
|
||||
format!("array of {} elements", n)
|
||||
} else {
|
||||
"array".to_string()
|
||||
}
|
||||
}
|
||||
ty::TySlice(_) => "slice".to_string(),
|
||||
ty::TyRawPtr(_) => "*-ptr".to_string(),
|
||||
ty::TyRef(region, tymut) => {
|
||||
|
@ -8,6 +8,7 @@
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use middle::const_val::{ConstVal, ConstAggregate};
|
||||
use ty::subst::Substs;
|
||||
use ty::{self, Ty, TypeFlags, TypeFoldable};
|
||||
|
||||
@ -145,7 +146,12 @@ impl FlagComputation {
|
||||
self.add_region(r);
|
||||
}
|
||||
|
||||
&ty::TyArray(tt, _) | &ty::TySlice(tt) => {
|
||||
&ty::TyArray(tt, len) => {
|
||||
self.add_ty(tt);
|
||||
self.add_const(len);
|
||||
}
|
||||
|
||||
&ty::TySlice(tt) => {
|
||||
self.add_ty(tt)
|
||||
}
|
||||
|
||||
@ -202,6 +208,40 @@ impl FlagComputation {
|
||||
}
|
||||
}
|
||||
|
||||
fn add_const(&mut self, constant: &ty::Const) {
|
||||
self.add_ty(constant.ty);
|
||||
match constant.val {
|
||||
ConstVal::Integral(_) |
|
||||
ConstVal::Float(_) |
|
||||
ConstVal::Str(_) |
|
||||
ConstVal::ByteStr(_) |
|
||||
ConstVal::Bool(_) |
|
||||
ConstVal::Char(_) |
|
||||
ConstVal::Variant(_) => {}
|
||||
ConstVal::Function(_, substs) => {
|
||||
self.add_substs(substs);
|
||||
}
|
||||
ConstVal::Aggregate(ConstAggregate::Struct(fields)) => {
|
||||
for &(_, v) in fields {
|
||||
self.add_const(v);
|
||||
}
|
||||
}
|
||||
ConstVal::Aggregate(ConstAggregate::Tuple(fields)) |
|
||||
ConstVal::Aggregate(ConstAggregate::Array(fields)) => {
|
||||
for v in fields {
|
||||
self.add_const(v);
|
||||
}
|
||||
}
|
||||
ConstVal::Aggregate(ConstAggregate::Repeat(v, _)) => {
|
||||
self.add_const(v);
|
||||
}
|
||||
ConstVal::Unevaluated(_, substs) => {
|
||||
self.add_flags(TypeFlags::HAS_PROJECTION);
|
||||
self.add_substs(substs);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn add_existential_projection(&mut self, projection: &ty::ExistentialProjection) {
|
||||
self.add_substs(projection.substs);
|
||||
self.add_ty(projection.ty);
|
||||
|
@ -39,6 +39,7 @@
|
||||
//! These methods return true to indicate that the visitor has found what it is looking for
|
||||
//! and does not need to visit anything else.
|
||||
|
||||
use middle::const_val::ConstVal;
|
||||
use ty::{self, Binder, Ty, TyCtxt, TypeFlags};
|
||||
|
||||
use std::fmt;
|
||||
@ -67,7 +68,7 @@ pub trait TypeFoldable<'tcx>: fmt::Debug + Clone {
|
||||
fn has_type_flags(&self, flags: TypeFlags) -> bool {
|
||||
self.visit_with(&mut HasTypeFlagsVisitor { flags: flags })
|
||||
}
|
||||
fn has_projection_types(&self) -> bool {
|
||||
fn has_projections(&self) -> bool {
|
||||
self.has_type_flags(TypeFlags::HAS_PROJECTION)
|
||||
}
|
||||
fn references_error(&self) -> bool {
|
||||
@ -139,6 +140,10 @@ pub trait TypeFolder<'gcx: 'tcx, 'tcx> : Sized {
|
||||
fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
|
||||
r.super_fold_with(self)
|
||||
}
|
||||
|
||||
fn fold_const(&mut self, c: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> {
|
||||
c.super_fold_with(self)
|
||||
}
|
||||
}
|
||||
|
||||
pub trait TypeVisitor<'tcx> : Sized {
|
||||
@ -153,6 +158,10 @@ pub trait TypeVisitor<'tcx> : Sized {
|
||||
fn visit_region(&mut self, r: ty::Region<'tcx>) -> bool {
|
||||
r.super_visit_with(self)
|
||||
}
|
||||
|
||||
fn visit_const(&mut self, c: &'tcx ty::Const<'tcx>) -> bool {
|
||||
c.super_visit_with(self)
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
@ -603,6 +612,17 @@ impl<'tcx> TypeVisitor<'tcx> for HasTypeFlagsVisitor {
|
||||
debug!("HasTypeFlagsVisitor: r={:?} r.flags={:?} self.flags={:?}", r, flags, self.flags);
|
||||
flags.intersects(self.flags)
|
||||
}
|
||||
|
||||
fn visit_const(&mut self, c: &'tcx ty::Const<'tcx>) -> bool {
|
||||
if let ConstVal::Unevaluated(..) = c.val {
|
||||
let projection_flags = TypeFlags::HAS_NORMALIZABLE_PROJECTION |
|
||||
TypeFlags::HAS_PROJECTION;
|
||||
if projection_flags.intersects(self.flags) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
c.super_visit_with(self)
|
||||
}
|
||||
}
|
||||
|
||||
/// Collects all the late-bound regions it finds into a hash set.
|
||||
|
@ -205,7 +205,7 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> {
|
||||
}))
|
||||
},
|
||||
TyArray(ty, len) => {
|
||||
if len == 0 {
|
||||
if len.val.to_const_int().and_then(|i| i.to_u64()) == Some(0) {
|
||||
DefIdForest::empty()
|
||||
} else {
|
||||
ty.uninhabited_from(visited, tcx)
|
||||
|
@ -837,12 +837,22 @@ impl<'a, 'tcx> Struct {
|
||||
|
||||
// Is this a fixed-size array of something non-zero
|
||||
// with at least one element?
|
||||
(_, &ty::TyArray(ety, d)) if d > 0 => {
|
||||
Struct::non_zero_field_paths(
|
||||
tcx,
|
||||
param_env,
|
||||
Some(ety).into_iter(),
|
||||
None)
|
||||
(_, &ty::TyArray(ety, mut count)) => {
|
||||
if count.has_projections() {
|
||||
count = tcx.normalize_associated_type_in_env(&count, param_env);
|
||||
if count.has_projections() {
|
||||
return Err(LayoutError::Unknown(ty));
|
||||
}
|
||||
}
|
||||
if count.val.to_const_int().unwrap().to_u64().unwrap() != 0 {
|
||||
Struct::non_zero_field_paths(
|
||||
tcx,
|
||||
param_env,
|
||||
Some(ety).into_iter(),
|
||||
None)
|
||||
} else {
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
|
||||
(_, &ty::TyProjection(_)) | (_, &ty::TyAnon(..)) => {
|
||||
@ -1174,12 +1184,17 @@ impl<'a, 'tcx> Layout {
|
||||
}
|
||||
|
||||
// Arrays and slices.
|
||||
ty::TyArray(element, count) => {
|
||||
ty::TyArray(element, mut count) => {
|
||||
if count.has_projections() {
|
||||
count = tcx.normalize_associated_type_in_env(&count, param_env);
|
||||
if count.has_projections() {
|
||||
return Err(LayoutError::Unknown(ty));
|
||||
}
|
||||
}
|
||||
|
||||
let element = element.layout(tcx, param_env)?;
|
||||
let element_size = element.size(dl);
|
||||
// FIXME(eddyb) Don't use host `usize` for array lengths.
|
||||
let usize_count: usize = count;
|
||||
let count = usize_count as u64;
|
||||
let count = count.val.to_const_int().unwrap().to_u64().unwrap();
|
||||
if element_size.checked_mul(count, dl).is_none() {
|
||||
return Err(LayoutError::SizeOverflow(ty));
|
||||
}
|
||||
|
@ -159,7 +159,7 @@ impl Key for (MirSuite, MirPassIndex, DefId) {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx, T: Clone + Hash + Eq + Debug> Key for ty::ParamEnvAnd<'tcx, T> {
|
||||
impl<'tcx> Key for Ty<'tcx> {
|
||||
fn map_crate(&self) -> CrateNum {
|
||||
LOCAL_CRATE
|
||||
}
|
||||
@ -168,6 +168,15 @@ impl<'tcx, T: Clone + Hash + Eq + Debug> Key for ty::ParamEnvAnd<'tcx, T> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx, T: Key> Key for ty::ParamEnvAnd<'tcx, T> {
|
||||
fn map_crate(&self) -> CrateNum {
|
||||
self.value.map_crate()
|
||||
}
|
||||
fn default_span(&self, tcx: TyCtxt) -> Span {
|
||||
self.value.default_span(tcx)
|
||||
}
|
||||
}
|
||||
|
||||
trait Value<'tcx>: Sized {
|
||||
fn from_cycle_error<'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Self;
|
||||
}
|
||||
|
@ -64,7 +64,7 @@ pub use self::sty::{InferTy, ParamTy, ProjectionTy, ExistentialPredicate};
|
||||
pub use self::sty::{ClosureSubsts, GeneratorInterior, TypeAndMut};
|
||||
pub use self::sty::{TraitRef, TypeVariants, PolyTraitRef};
|
||||
pub use self::sty::{ExistentialTraitRef, PolyExistentialTraitRef};
|
||||
pub use self::sty::{ExistentialProjection, PolyExistentialProjection};
|
||||
pub use self::sty::{ExistentialProjection, PolyExistentialProjection, Const};
|
||||
pub use self::sty::{BoundRegion, EarlyBoundRegion, FreeRegion, Region};
|
||||
pub use self::sty::RegionKind;
|
||||
pub use self::sty::{TyVid, IntVid, FloatVid, RegionVid, SkolemizedRegionVid};
|
||||
@ -846,6 +846,9 @@ pub enum Predicate<'tcx> {
|
||||
|
||||
/// `T1 <: T2`
|
||||
Subtype(PolySubtypePredicate<'tcx>),
|
||||
|
||||
/// Constant initializer must evaluate successfully.
|
||||
ConstEvaluatable(DefId, &'tcx Substs<'tcx>),
|
||||
}
|
||||
|
||||
impl<'a, 'gcx, 'tcx> Predicate<'tcx> {
|
||||
@ -938,6 +941,8 @@ impl<'a, 'gcx, 'tcx> Predicate<'tcx> {
|
||||
Predicate::ObjectSafe(trait_def_id),
|
||||
Predicate::ClosureKind(closure_def_id, kind) =>
|
||||
Predicate::ClosureKind(closure_def_id, kind),
|
||||
Predicate::ConstEvaluatable(def_id, const_substs) =>
|
||||
Predicate::ConstEvaluatable(def_id, const_substs.subst(tcx, substs)),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1120,6 +1125,9 @@ impl<'tcx> Predicate<'tcx> {
|
||||
ty::Predicate::ClosureKind(_closure_def_id, _kind) => {
|
||||
vec![]
|
||||
}
|
||||
ty::Predicate::ConstEvaluatable(_, substs) => {
|
||||
substs.types().collect()
|
||||
}
|
||||
};
|
||||
|
||||
// The only reason to collect into a vector here is that I was
|
||||
@ -1142,7 +1150,8 @@ impl<'tcx> Predicate<'tcx> {
|
||||
Predicate::WellFormed(..) |
|
||||
Predicate::ObjectSafe(..) |
|
||||
Predicate::ClosureKind(..) |
|
||||
Predicate::TypeOutlives(..) => {
|
||||
Predicate::TypeOutlives(..) |
|
||||
Predicate::ConstEvaluatable(..) => {
|
||||
None
|
||||
}
|
||||
}
|
||||
@ -1601,7 +1610,7 @@ impl<'a, 'gcx, 'tcx> AdtDef {
|
||||
if let VariantDiscr::Explicit(expr_did) = v.discr {
|
||||
let substs = Substs::identity_for_item(tcx.global_tcx(), expr_did);
|
||||
match tcx.const_eval(param_env.and((expr_did, substs))) {
|
||||
Ok(ConstVal::Integral(v)) => {
|
||||
Ok(&ty::Const { val: ConstVal::Integral(v), .. }) => {
|
||||
discr = v;
|
||||
}
|
||||
err => {
|
||||
@ -1641,7 +1650,7 @@ impl<'a, 'gcx, 'tcx> AdtDef {
|
||||
ty::VariantDiscr::Explicit(expr_did) => {
|
||||
let substs = Substs::identity_for_item(tcx.global_tcx(), expr_did);
|
||||
match tcx.const_eval(param_env.and((expr_did, substs))) {
|
||||
Ok(ConstVal::Integral(v)) => {
|
||||
Ok(&ty::Const { val: ConstVal::Integral(v), .. }) => {
|
||||
explicit_value = v;
|
||||
break;
|
||||
}
|
||||
@ -1665,11 +1674,11 @@ impl<'a, 'gcx, 'tcx> AdtDef {
|
||||
match repr_type {
|
||||
attr::UnsignedInt(ty) => {
|
||||
ConstInt::new_unsigned_truncating(discr, ty,
|
||||
tcx.sess.target.uint_type)
|
||||
tcx.sess.target.usize_ty)
|
||||
}
|
||||
attr::SignedInt(ty) => {
|
||||
ConstInt::new_signed_truncating(discr as i128, ty,
|
||||
tcx.sess.target.int_type)
|
||||
tcx.sess.target.isize_ty)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -14,9 +14,12 @@
|
||||
//! type equality, etc.
|
||||
|
||||
use hir::def_id::DefId;
|
||||
use middle::const_val::ConstVal;
|
||||
use traits::Reveal;
|
||||
use ty::subst::{Kind, Substs};
|
||||
use ty::{self, Ty, TyCtxt, TypeFoldable};
|
||||
use ty::error::{ExpectedFound, TypeError};
|
||||
use util::common::ErrorReported;
|
||||
use std::rc::Rc;
|
||||
use std::iter;
|
||||
use syntax::abi;
|
||||
@ -428,10 +431,45 @@ pub fn super_relate_tys<'a, 'gcx, 'tcx, R>(relation: &mut R,
|
||||
(&ty::TyArray(a_t, sz_a), &ty::TyArray(b_t, sz_b)) =>
|
||||
{
|
||||
let t = relation.relate(&a_t, &b_t)?;
|
||||
if sz_a == sz_b {
|
||||
Ok(tcx.mk_array(t, sz_a))
|
||||
} else {
|
||||
Err(TypeError::FixedArraySize(expected_found(relation, &sz_a, &sz_b)))
|
||||
assert_eq!(sz_a.ty, tcx.types.usize);
|
||||
assert_eq!(sz_b.ty, tcx.types.usize);
|
||||
let to_u64 = |x: &'tcx ty::Const<'tcx>| -> Result<u64, ErrorReported> {
|
||||
match x.val {
|
||||
ConstVal::Integral(x) => Ok(x.to_u64().unwrap()),
|
||||
ConstVal::Unevaluated(def_id, substs) => {
|
||||
// FIXME(eddyb) get the right param_env.
|
||||
let param_env = ty::ParamEnv::empty(Reveal::UserFacing);
|
||||
match tcx.lift_to_global(&substs) {
|
||||
Some(substs) => {
|
||||
match tcx.const_eval(param_env.and((def_id, substs))) {
|
||||
Ok(&ty::Const { val: ConstVal::Integral(x), .. }) => {
|
||||
return Ok(x.to_u64().unwrap());
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
None => {}
|
||||
}
|
||||
tcx.sess.delay_span_bug(tcx.def_span(def_id),
|
||||
"array length could not be evaluated");
|
||||
Err(ErrorReported)
|
||||
}
|
||||
_ => bug!("arrays should not have {:?} as length", x)
|
||||
}
|
||||
};
|
||||
match (to_u64(sz_a), to_u64(sz_b)) {
|
||||
(Ok(sz_a_u64), Ok(sz_b_u64)) => {
|
||||
if sz_a_u64 == sz_b_u64 {
|
||||
Ok(tcx.mk_ty(ty::TyArray(t, sz_a)))
|
||||
} else {
|
||||
Err(TypeError::FixedArraySize(
|
||||
expected_found(relation, &sz_a_u64, &sz_b_u64)))
|
||||
}
|
||||
}
|
||||
// We reported an error or will ICE, so we can return TyError.
|
||||
(Err(ErrorReported), _) | (_, Err(ErrorReported)) => {
|
||||
Ok(tcx.types.err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -9,6 +9,7 @@
|
||||
// except according to those terms.
|
||||
|
||||
use infer::type_variable;
|
||||
use middle::const_val::{self, ConstVal, ConstAggregate, ConstEvalErr};
|
||||
use ty::{self, Lift, Ty, TyCtxt};
|
||||
use ty::fold::{TypeFoldable, TypeFolder, TypeVisitor};
|
||||
use rustc_data_structures::accumulate_vec::AccumulateVec;
|
||||
@ -58,6 +59,13 @@ impl<'tcx, T: Lift<'tcx>, E: Lift<'tcx>> Lift<'tcx> for Result<T, E> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx, T: Lift<'tcx>> Lift<'tcx> for Box<T> {
|
||||
type Lifted = Box<T::Lifted>;
|
||||
fn lift_to_tcx<'a, 'gcx>(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Option<Self::Lifted> {
|
||||
tcx.lift(&**self).map(Box::new)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx, T: Lift<'tcx>> Lift<'tcx> for [T] {
|
||||
type Lifted = Vec<T::Lifted>;
|
||||
fn lift_to_tcx<'a, 'gcx>(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Option<Self::Lifted> {
|
||||
@ -209,6 +217,11 @@ impl<'a, 'tcx> Lift<'tcx> for ty::Predicate<'a> {
|
||||
ty::Predicate::ObjectSafe(trait_def_id) => {
|
||||
Some(ty::Predicate::ObjectSafe(trait_def_id))
|
||||
}
|
||||
ty::Predicate::ConstEvaluatable(def_id, substs) => {
|
||||
tcx.lift(&substs).map(|substs| {
|
||||
ty::Predicate::ConstEvaluatable(def_id, substs)
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -220,6 +233,32 @@ impl<'tcx, T: Lift<'tcx>> Lift<'tcx> for ty::Binder<T> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> Lift<'tcx> for ty::ParamEnv<'a> {
|
||||
type Lifted = ty::ParamEnv<'tcx>;
|
||||
fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option<Self::Lifted> {
|
||||
tcx.lift(&self.caller_bounds).map(|caller_bounds| {
|
||||
ty::ParamEnv {
|
||||
reveal: self.reveal,
|
||||
caller_bounds,
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'tcx, T: Lift<'tcx>> Lift<'tcx> for ty::ParamEnvAnd<'a, T> {
|
||||
type Lifted = ty::ParamEnvAnd<'tcx, T::Lifted>;
|
||||
fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option<Self::Lifted> {
|
||||
tcx.lift(&self.param_env).and_then(|param_env| {
|
||||
tcx.lift(&self.value).map(|value| {
|
||||
ty::ParamEnvAnd {
|
||||
param_env,
|
||||
value,
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> Lift<'tcx> for ty::ClosureSubsts<'a> {
|
||||
type Lifted = ty::ClosureSubsts<'tcx>;
|
||||
fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option<Self::Lifted> {
|
||||
@ -394,6 +433,64 @@ impl<'a, 'tcx> Lift<'tcx> for ty::error::TypeError<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> Lift<'tcx> for ConstEvalErr<'a> {
|
||||
type Lifted = ConstEvalErr<'tcx>;
|
||||
fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option<Self::Lifted> {
|
||||
tcx.lift(&self.kind).map(|kind| {
|
||||
ConstEvalErr {
|
||||
span: self.span,
|
||||
kind,
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> Lift<'tcx> for const_val::ErrKind<'a> {
|
||||
type Lifted = const_val::ErrKind<'tcx>;
|
||||
fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option<Self::Lifted> {
|
||||
use middle::const_val::ErrKind::*;
|
||||
|
||||
Some(match *self {
|
||||
CannotCast => CannotCast,
|
||||
MissingStructField => MissingStructField,
|
||||
NonConstPath => NonConstPath,
|
||||
UnimplementedConstVal(s) => UnimplementedConstVal(s),
|
||||
ExpectedConstTuple => ExpectedConstTuple,
|
||||
ExpectedConstStruct => ExpectedConstStruct,
|
||||
IndexedNonVec => IndexedNonVec,
|
||||
IndexNotUsize => IndexNotUsize,
|
||||
IndexOutOfBounds { len, index } => IndexOutOfBounds { len, index },
|
||||
MiscBinaryOp => MiscBinaryOp,
|
||||
MiscCatchAll => MiscCatchAll,
|
||||
IndexOpFeatureGated => IndexOpFeatureGated,
|
||||
Math(ref e) => Math(e.clone()),
|
||||
|
||||
LayoutError(ref e) => {
|
||||
return tcx.lift(e).map(LayoutError)
|
||||
}
|
||||
ErroneousReferencedConstant(ref e) => {
|
||||
return tcx.lift(e).map(ErroneousReferencedConstant)
|
||||
}
|
||||
|
||||
TypeckError => TypeckError,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> Lift<'tcx> for ty::layout::LayoutError<'a> {
|
||||
type Lifted = ty::layout::LayoutError<'tcx>;
|
||||
fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option<Self::Lifted> {
|
||||
match *self {
|
||||
ty::layout::LayoutError::Unknown(ref ty) => {
|
||||
tcx.lift(ty).map(ty::layout::LayoutError::Unknown)
|
||||
}
|
||||
ty::layout::LayoutError::SizeOverflow(ref ty) => {
|
||||
tcx.lift(ty).map(ty::layout::LayoutError::SizeOverflow)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// TypeFoldable implementations.
|
||||
//
|
||||
@ -408,6 +505,13 @@ impl<'a, 'tcx> Lift<'tcx> for ty::error::TypeError<'a> {
|
||||
macro_rules! CopyImpls {
|
||||
($($ty:ty),+) => {
|
||||
$(
|
||||
impl<'tcx> Lift<'tcx> for $ty {
|
||||
type Lifted = Self;
|
||||
fn lift_to_tcx<'a, 'gcx>(&self, _: TyCtxt<'a, 'gcx, 'tcx>) -> Option<Self> {
|
||||
Some(*self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> TypeFoldable<'tcx> for $ty {
|
||||
fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, _: &mut F) -> $ty {
|
||||
*self
|
||||
@ -551,7 +655,7 @@ impl<'tcx> TypeFoldable<'tcx> for Ty<'tcx> {
|
||||
fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
|
||||
let sty = match self.sty {
|
||||
ty::TyRawPtr(tm) => ty::TyRawPtr(tm.fold_with(folder)),
|
||||
ty::TyArray(typ, sz) => ty::TyArray(typ.fold_with(folder), sz),
|
||||
ty::TyArray(typ, sz) => ty::TyArray(typ.fold_with(folder), sz.fold_with(folder)),
|
||||
ty::TySlice(typ) => ty::TySlice(typ.fold_with(folder)),
|
||||
ty::TyAdt(tid, substs) => ty::TyAdt(tid, substs.fold_with(folder)),
|
||||
ty::TyDynamic(ref trait_ty, ref region) =>
|
||||
@ -589,7 +693,7 @@ impl<'tcx> TypeFoldable<'tcx> for Ty<'tcx> {
|
||||
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
|
||||
match self.sty {
|
||||
ty::TyRawPtr(ref tm) => tm.visit_with(visitor),
|
||||
ty::TyArray(typ, _sz) => typ.visit_with(visitor),
|
||||
ty::TyArray(typ, sz) => typ.visit_with(visitor) || sz.visit_with(visitor),
|
||||
ty::TySlice(typ) => typ.visit_with(visitor),
|
||||
ty::TyAdt(_, substs) => substs.visit_with(visitor),
|
||||
ty::TyDynamic(ref trait_ty, ref reg) =>
|
||||
@ -865,6 +969,8 @@ impl<'tcx> TypeFoldable<'tcx> for ty::Predicate<'tcx> {
|
||||
ty::Predicate::ClosureKind(closure_def_id, kind),
|
||||
ty::Predicate::ObjectSafe(trait_def_id) =>
|
||||
ty::Predicate::ObjectSafe(trait_def_id),
|
||||
ty::Predicate::ConstEvaluatable(def_id, substs) =>
|
||||
ty::Predicate::ConstEvaluatable(def_id, substs.fold_with(folder)),
|
||||
}
|
||||
}
|
||||
|
||||
@ -879,6 +985,7 @@ impl<'tcx> TypeFoldable<'tcx> for ty::Predicate<'tcx> {
|
||||
ty::Predicate::WellFormed(data) => data.visit_with(visitor),
|
||||
ty::Predicate::ClosureKind(_closure_def_id, _kind) => false,
|
||||
ty::Predicate::ObjectSafe(_trait_def_id) => false,
|
||||
ty::Predicate::ConstEvaluatable(_def_id, substs) => substs.visit_with(visitor),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1101,3 +1208,107 @@ impl<'tcx> TypeFoldable<'tcx> for ty::error::TypeError<'tcx> {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> TypeFoldable<'tcx> for ConstVal<'tcx> {
|
||||
fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
|
||||
match *self {
|
||||
ConstVal::Integral(i) => ConstVal::Integral(i),
|
||||
ConstVal::Float(f) => ConstVal::Float(f),
|
||||
ConstVal::Str(s) => ConstVal::Str(s),
|
||||
ConstVal::ByteStr(b) => ConstVal::ByteStr(b),
|
||||
ConstVal::Bool(b) => ConstVal::Bool(b),
|
||||
ConstVal::Char(c) => ConstVal::Char(c),
|
||||
ConstVal::Variant(def_id) => ConstVal::Variant(def_id),
|
||||
ConstVal::Function(def_id, substs) => {
|
||||
ConstVal::Function(def_id, substs.fold_with(folder))
|
||||
}
|
||||
ConstVal::Aggregate(ConstAggregate::Struct(fields)) => {
|
||||
let new_fields: Vec<_> = fields.iter().map(|&(name, v)| {
|
||||
(name, v.fold_with(folder))
|
||||
}).collect();
|
||||
let fields = if new_fields == fields {
|
||||
fields
|
||||
} else {
|
||||
folder.tcx().alloc_name_const_slice(&new_fields)
|
||||
};
|
||||
ConstVal::Aggregate(ConstAggregate::Struct(fields))
|
||||
}
|
||||
ConstVal::Aggregate(ConstAggregate::Tuple(fields)) => {
|
||||
let new_fields: Vec<_> = fields.iter().map(|v| {
|
||||
v.fold_with(folder)
|
||||
}).collect();
|
||||
let fields = if new_fields == fields {
|
||||
fields
|
||||
} else {
|
||||
folder.tcx().alloc_const_slice(&new_fields)
|
||||
};
|
||||
ConstVal::Aggregate(ConstAggregate::Tuple(fields))
|
||||
}
|
||||
ConstVal::Aggregate(ConstAggregate::Array(fields)) => {
|
||||
let new_fields: Vec<_> = fields.iter().map(|v| {
|
||||
v.fold_with(folder)
|
||||
}).collect();
|
||||
let fields = if new_fields == fields {
|
||||
fields
|
||||
} else {
|
||||
folder.tcx().alloc_const_slice(&new_fields)
|
||||
};
|
||||
ConstVal::Aggregate(ConstAggregate::Array(fields))
|
||||
}
|
||||
ConstVal::Aggregate(ConstAggregate::Repeat(v, count)) => {
|
||||
let v = v.fold_with(folder);
|
||||
ConstVal::Aggregate(ConstAggregate::Repeat(v, count))
|
||||
}
|
||||
ConstVal::Unevaluated(def_id, substs) => {
|
||||
ConstVal::Unevaluated(def_id, substs.fold_with(folder))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
|
||||
match *self {
|
||||
ConstVal::Integral(_) |
|
||||
ConstVal::Float(_) |
|
||||
ConstVal::Str(_) |
|
||||
ConstVal::ByteStr(_) |
|
||||
ConstVal::Bool(_) |
|
||||
ConstVal::Char(_) |
|
||||
ConstVal::Variant(_) => false,
|
||||
ConstVal::Function(_, substs) => substs.visit_with(visitor),
|
||||
ConstVal::Aggregate(ConstAggregate::Struct(fields)) => {
|
||||
fields.iter().any(|&(_, v)| v.visit_with(visitor))
|
||||
}
|
||||
ConstVal::Aggregate(ConstAggregate::Tuple(fields)) |
|
||||
ConstVal::Aggregate(ConstAggregate::Array(fields)) => {
|
||||
fields.iter().any(|v| v.visit_with(visitor))
|
||||
}
|
||||
ConstVal::Aggregate(ConstAggregate::Repeat(v, _)) => {
|
||||
v.visit_with(visitor)
|
||||
}
|
||||
ConstVal::Unevaluated(_, substs) => substs.visit_with(visitor),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::Const<'tcx> {
|
||||
fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
|
||||
let ty = self.ty.fold_with(folder);
|
||||
let val = self.val.fold_with(folder);
|
||||
folder.tcx().mk_const(ty::Const {
|
||||
ty,
|
||||
val
|
||||
})
|
||||
}
|
||||
|
||||
fn fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
|
||||
folder.fold_const(*self)
|
||||
}
|
||||
|
||||
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
|
||||
self.ty.visit_with(visitor) || self.val.visit_with(visitor)
|
||||
}
|
||||
|
||||
fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
|
||||
visitor.visit_const(self)
|
||||
}
|
||||
}
|
||||
|
@ -12,6 +12,7 @@
|
||||
|
||||
use hir::def_id::DefId;
|
||||
|
||||
use middle::const_val::ConstVal;
|
||||
use middle::region;
|
||||
use ty::subst::{Substs, Subst};
|
||||
use ty::{self, AdtDef, TypeFlags, Ty, TyCtxt, TypeFoldable};
|
||||
@ -109,7 +110,7 @@ pub enum TypeVariants<'tcx> {
|
||||
TyStr,
|
||||
|
||||
/// An array with the given length. Written as `[T; n]`.
|
||||
TyArray(Ty<'tcx>, usize),
|
||||
TyArray(Ty<'tcx>, &'tcx ty::Const<'tcx>),
|
||||
|
||||
/// The pointee of an array slice. Written as `[T]`.
|
||||
TySlice(Ty<'tcx>),
|
||||
@ -1458,3 +1459,14 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Typed constant value.
|
||||
#[derive(Copy, Clone, Debug, Hash, RustcEncodable, RustcDecodable, Eq, PartialEq)]
|
||||
pub struct Const<'tcx> {
|
||||
pub ty: Ty<'tcx>,
|
||||
|
||||
// FIXME(eddyb) Replace this with a miri value.
|
||||
pub val: ConstVal<'tcx>,
|
||||
}
|
||||
|
||||
impl<'tcx> serialize::UseSpecializedDecodable for &'tcx Const<'tcx> {}
|
||||
|
@ -13,6 +13,7 @@
|
||||
use hir::def_id::{DefId, LOCAL_CRATE};
|
||||
use hir::map::DefPathData;
|
||||
use ich::{StableHashingContext, NodeIdHashingMode};
|
||||
use middle::const_val::ConstVal;
|
||||
use traits::{self, Reveal};
|
||||
use ty::{self, Ty, TyCtxt, TypeFoldable};
|
||||
use ty::fold::TypeVisitor;
|
||||
@ -53,7 +54,7 @@ macro_rules! typed_literal {
|
||||
SignedInt(ast::IntTy::I32) => ConstInt::I32($lit),
|
||||
SignedInt(ast::IntTy::I64) => ConstInt::I64($lit),
|
||||
SignedInt(ast::IntTy::I128) => ConstInt::I128($lit),
|
||||
SignedInt(ast::IntTy::Is) => match $tcx.sess.target.int_type {
|
||||
SignedInt(ast::IntTy::Is) => match $tcx.sess.target.isize_ty {
|
||||
ast::IntTy::I16 => ConstInt::Isize(ConstIsize::Is16($lit)),
|
||||
ast::IntTy::I32 => ConstInt::Isize(ConstIsize::Is32($lit)),
|
||||
ast::IntTy::I64 => ConstInt::Isize(ConstIsize::Is64($lit)),
|
||||
@ -64,7 +65,7 @@ macro_rules! typed_literal {
|
||||
UnsignedInt(ast::UintTy::U32) => ConstInt::U32($lit),
|
||||
UnsignedInt(ast::UintTy::U64) => ConstInt::U64($lit),
|
||||
UnsignedInt(ast::UintTy::U128) => ConstInt::U128($lit),
|
||||
UnsignedInt(ast::UintTy::Us) => match $tcx.sess.target.uint_type {
|
||||
UnsignedInt(ast::UintTy::Us) => match $tcx.sess.target.usize_ty {
|
||||
ast::UintTy::U16 => ConstInt::Usize(ConstUsize::Us16($lit)),
|
||||
ast::UintTy::U32 => ConstInt::Usize(ConstUsize::Us32($lit)),
|
||||
ast::UintTy::U64 => ConstInt::Usize(ConstUsize::Us64($lit)),
|
||||
@ -388,7 +389,8 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
|
||||
ty::Predicate::WellFormed(..) |
|
||||
ty::Predicate::ObjectSafe(..) |
|
||||
ty::Predicate::ClosureKind(..) |
|
||||
ty::Predicate::RegionOutlives(..) => {
|
||||
ty::Predicate::RegionOutlives(..) |
|
||||
ty::Predicate::ConstEvaluatable(..) => {
|
||||
None
|
||||
}
|
||||
ty::Predicate::TypeOutlives(ty::Binder(ty::OutlivesPredicate(t, r))) => {
|
||||
@ -638,7 +640,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
|
||||
}
|
||||
|
||||
pub fn const_usize(&self, val: u16) -> ConstInt {
|
||||
match self.sess.target.uint_type {
|
||||
match self.sess.target.usize_ty {
|
||||
ast::UintTy::U16 => ConstInt::Usize(ConstUsize::Us16(val as u16)),
|
||||
ast::UintTy::U32 => ConstInt::Usize(ConstUsize::Us32(val as u32)),
|
||||
ast::UintTy::U64 => ConstInt::Usize(ConstUsize::Us64(val as u64)),
|
||||
@ -697,7 +699,14 @@ impl<'a, 'gcx, 'tcx, W> TypeVisitor<'tcx> for TypeIdHasher<'a, 'gcx, 'tcx, W>
|
||||
TyInt(i) => self.hash(i),
|
||||
TyUint(u) => self.hash(u),
|
||||
TyFloat(f) => self.hash(f),
|
||||
TyArray(_, n) => self.hash(n),
|
||||
TyArray(_, n) => {
|
||||
self.hash_discriminant_u8(&n.val);
|
||||
match n.val {
|
||||
ConstVal::Integral(x) => self.hash(x.to_u64().unwrap()),
|
||||
ConstVal::Unevaluated(def_id, _) => self.def_id(def_id),
|
||||
_ => bug!("arrays should not have {:?} as length", n)
|
||||
}
|
||||
}
|
||||
TyRawPtr(m) |
|
||||
TyRef(_, m) => self.hash(m.mutbl),
|
||||
TyClosure(def_id, _) |
|
||||
|
@ -11,6 +11,7 @@
|
||||
//! An iterator over the type substructure.
|
||||
//! WARNING: this does not keep track of the region depth.
|
||||
|
||||
use middle::const_val::{ConstVal, ConstAggregate};
|
||||
use ty::{self, Ty};
|
||||
use rustc_data_structures::small_vec::SmallVec;
|
||||
use rustc_data_structures::accumulate_vec::IntoIter as AccIntoIter;
|
||||
@ -83,7 +84,11 @@ fn push_subtypes<'tcx>(stack: &mut TypeWalkerStack<'tcx>, parent_ty: Ty<'tcx>) {
|
||||
ty::TyBool | ty::TyChar | ty::TyInt(_) | ty::TyUint(_) | ty::TyFloat(_) |
|
||||
ty::TyStr | ty::TyInfer(_) | ty::TyParam(_) | ty::TyNever | ty::TyError => {
|
||||
}
|
||||
ty::TyArray(ty, _) | ty::TySlice(ty) => {
|
||||
ty::TyArray(ty, len) => {
|
||||
push_const(stack, len);
|
||||
stack.push(ty);
|
||||
}
|
||||
ty::TySlice(ty) => {
|
||||
stack.push(ty);
|
||||
}
|
||||
ty::TyRawPtr(ref mt) | ty::TyRef(_, ref mt) => {
|
||||
@ -122,13 +127,42 @@ fn push_subtypes<'tcx>(stack: &mut TypeWalkerStack<'tcx>, parent_ty: Ty<'tcx>) {
|
||||
ty::TyFnDef(_, substs) => {
|
||||
stack.extend(substs.types().rev());
|
||||
}
|
||||
ty::TyFnPtr(ft) => {
|
||||
push_sig_subtypes(stack, ft);
|
||||
ty::TyFnPtr(sig) => {
|
||||
stack.push(sig.skip_binder().output());
|
||||
stack.extend(sig.skip_binder().inputs().iter().cloned().rev());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn push_sig_subtypes<'tcx>(stack: &mut TypeWalkerStack<'tcx>, sig: ty::PolyFnSig<'tcx>) {
|
||||
stack.push(sig.skip_binder().output());
|
||||
stack.extend(sig.skip_binder().inputs().iter().cloned().rev());
|
||||
fn push_const<'tcx>(stack: &mut TypeWalkerStack<'tcx>, constant: &'tcx ty::Const<'tcx>) {
|
||||
match constant.val {
|
||||
ConstVal::Integral(_) |
|
||||
ConstVal::Float(_) |
|
||||
ConstVal::Str(_) |
|
||||
ConstVal::ByteStr(_) |
|
||||
ConstVal::Bool(_) |
|
||||
ConstVal::Char(_) |
|
||||
ConstVal::Variant(_) => {}
|
||||
ConstVal::Function(_, substs) => {
|
||||
stack.extend(substs.types().rev());
|
||||
}
|
||||
ConstVal::Aggregate(ConstAggregate::Struct(fields)) => {
|
||||
for &(_, v) in fields.iter().rev() {
|
||||
push_const(stack, v);
|
||||
}
|
||||
}
|
||||
ConstVal::Aggregate(ConstAggregate::Tuple(fields)) |
|
||||
ConstVal::Aggregate(ConstAggregate::Array(fields)) => {
|
||||
for v in fields.iter().rev() {
|
||||
push_const(stack, v);
|
||||
}
|
||||
}
|
||||
ConstVal::Aggregate(ConstAggregate::Repeat(v, _)) => {
|
||||
push_const(stack, v);
|
||||
}
|
||||
ConstVal::Unevaluated(_, substs) => {
|
||||
stack.extend(substs.types().rev());
|
||||
}
|
||||
}
|
||||
stack.push(constant.ty);
|
||||
}
|
||||
|
@ -9,6 +9,7 @@
|
||||
// except according to those terms.
|
||||
|
||||
use hir::def_id::DefId;
|
||||
use middle::const_val::{ConstVal, ConstAggregate};
|
||||
use infer::InferCtxt;
|
||||
use ty::subst::Substs;
|
||||
use traits;
|
||||
@ -101,6 +102,14 @@ pub fn predicate_obligations<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>,
|
||||
wf.compute(data.skip_binder().a); // (*)
|
||||
wf.compute(data.skip_binder().b); // (*)
|
||||
}
|
||||
ty::Predicate::ConstEvaluatable(def_id, substs) => {
|
||||
let obligations = wf.nominal_obligations(def_id, substs);
|
||||
wf.out.extend(obligations);
|
||||
|
||||
for ty in substs.types() {
|
||||
wf.compute(ty);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
wf.normalize()
|
||||
@ -207,6 +216,46 @@ impl<'a, 'gcx, 'tcx> WfPredicates<'a, 'gcx, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Pushes the obligations required for a constant value to be WF
|
||||
/// into `self.out`.
|
||||
fn compute_const(&mut self, constant: &'tcx ty::Const<'tcx>) {
|
||||
self.require_sized(constant.ty, traits::ConstSized);
|
||||
match constant.val {
|
||||
ConstVal::Integral(_) |
|
||||
ConstVal::Float(_) |
|
||||
ConstVal::Str(_) |
|
||||
ConstVal::ByteStr(_) |
|
||||
ConstVal::Bool(_) |
|
||||
ConstVal::Char(_) |
|
||||
ConstVal::Variant(_) |
|
||||
ConstVal::Function(..) => {}
|
||||
ConstVal::Aggregate(ConstAggregate::Struct(fields)) => {
|
||||
for &(_, v) in fields {
|
||||
self.compute_const(v);
|
||||
}
|
||||
}
|
||||
ConstVal::Aggregate(ConstAggregate::Tuple(fields)) |
|
||||
ConstVal::Aggregate(ConstAggregate::Array(fields)) => {
|
||||
for v in fields {
|
||||
self.compute_const(v);
|
||||
}
|
||||
}
|
||||
ConstVal::Aggregate(ConstAggregate::Repeat(v, _)) => {
|
||||
self.compute_const(v);
|
||||
}
|
||||
ConstVal::Unevaluated(def_id, substs) => {
|
||||
let obligations = self.nominal_obligations(def_id, substs);
|
||||
self.out.extend(obligations);
|
||||
|
||||
let predicate = ty::Predicate::ConstEvaluatable(def_id, substs);
|
||||
let cause = self.cause(traits::MiscObligation);
|
||||
self.out.push(traits::Obligation::new(cause,
|
||||
self.param_env,
|
||||
predicate));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn require_sized(&mut self, subty: Ty<'tcx>, cause: traits::ObligationCauseCode<'tcx>) {
|
||||
if !subty.has_escaping_regions() {
|
||||
let cause = self.cause(cause);
|
||||
@ -239,11 +288,16 @@ impl<'a, 'gcx, 'tcx> WfPredicates<'a, 'gcx, 'tcx> {
|
||||
// WfScalar, WfParameter, etc
|
||||
}
|
||||
|
||||
ty::TySlice(subty) |
|
||||
ty::TyArray(subty, _) => {
|
||||
ty::TySlice(subty) => {
|
||||
self.require_sized(subty, traits::SliceOrArrayElem);
|
||||
}
|
||||
|
||||
ty::TyArray(subty, len) => {
|
||||
self.require_sized(subty, traits::SliceOrArrayElem);
|
||||
assert_eq!(len.ty, self.infcx.tcx.types.usize);
|
||||
self.compute_const(len);
|
||||
}
|
||||
|
||||
ty::TyTuple(ref tys, _) => {
|
||||
if let Some((_last, rest)) = tys.split_last() {
|
||||
for elem in rest {
|
||||
|
@ -10,6 +10,7 @@
|
||||
|
||||
use hir::def_id::DefId;
|
||||
use hir::map::definitions::DefPathData;
|
||||
use middle::const_val::ConstVal;
|
||||
use middle::region::{self, BlockRemainder};
|
||||
use ty::subst::{self, Subst};
|
||||
use ty::{BrAnon, BrEnv, BrFresh, BrNamed};
|
||||
@ -24,6 +25,7 @@ use std::cell::Cell;
|
||||
use std::fmt;
|
||||
use std::usize;
|
||||
|
||||
use rustc_const_math::ConstInt;
|
||||
use syntax::abi::Abi;
|
||||
use syntax::ast::CRATE_NODE_ID;
|
||||
use syntax::symbol::Symbol;
|
||||
@ -428,6 +430,9 @@ impl<'tcx> fmt::Debug for ty::Predicate<'tcx> {
|
||||
ty::Predicate::ClosureKind(closure_def_id, kind) => {
|
||||
write!(f, "ClosureKind({:?}, {:?})", closure_def_id, kind)
|
||||
}
|
||||
ty::Predicate::ConstEvaluatable(def_id, substs) => {
|
||||
write!(f, "ConstEvaluatable({:?}, {:?})", def_id, substs)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -886,7 +891,21 @@ impl<'tcx> fmt::Display for ty::TypeVariants<'tcx> {
|
||||
|
||||
write!(f, "]")
|
||||
}),
|
||||
TyArray(ty, sz) => write!(f, "[{}; {}]", ty, sz),
|
||||
TyArray(ty, sz) => {
|
||||
write!(f, "[{}; ", ty)?;
|
||||
match sz.val {
|
||||
ConstVal::Integral(ConstInt::Usize(sz)) => {
|
||||
write!(f, "{}", sz)?;
|
||||
}
|
||||
ConstVal::Unevaluated(_def_id, substs) => {
|
||||
write!(f, "<unevaluated{:?}>", &substs[..])?;
|
||||
}
|
||||
_ => {
|
||||
write!(f, "{:?}", sz)?;
|
||||
}
|
||||
}
|
||||
write!(f, "]")
|
||||
}
|
||||
TySlice(ty) => write!(f, "[{}]", ty)
|
||||
}
|
||||
}
|
||||
@ -1035,6 +1054,11 @@ impl<'tcx> fmt::Display for ty::Predicate<'tcx> {
|
||||
write!(f, "the closure `{}` implements the trait `{}`",
|
||||
tcx.item_path_str(closure_def_id), kind)
|
||||
}),
|
||||
ty::Predicate::ConstEvaluatable(def_id, substs) => {
|
||||
write!(f, "the constant `")?;
|
||||
parameterized(f, substs, def_id, &[])?;
|
||||
write!(f, "` can be evaluated")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -182,13 +182,16 @@ impl<'a, 'tcx> MatchCheckCtxt<'a, 'tcx> {
|
||||
self.byte_array_map.entry(pat).or_insert_with(|| {
|
||||
match pat.kind {
|
||||
box PatternKind::Constant {
|
||||
value: ConstVal::ByteStr(ref data)
|
||||
value: &ty::Const { val: ConstVal::ByteStr(b), .. }
|
||||
} => {
|
||||
data.iter().map(|c| &*pattern_arena.alloc(Pattern {
|
||||
b.data.iter().map(|&b| &*pattern_arena.alloc(Pattern {
|
||||
ty: tcx.types.u8,
|
||||
span: pat.span,
|
||||
kind: box PatternKind::Constant {
|
||||
value: ConstVal::Integral(ConstInt::U8(*c))
|
||||
value: tcx.mk_const(ty::Const {
|
||||
val: ConstVal::Integral(ConstInt::U8(b)),
|
||||
ty: tcx.types.u8
|
||||
})
|
||||
}
|
||||
})).collect()
|
||||
}
|
||||
@ -228,11 +231,11 @@ pub enum Constructor<'tcx> {
|
||||
/// Enum variants.
|
||||
Variant(DefId),
|
||||
/// Literal values.
|
||||
ConstantValue(ConstVal<'tcx>),
|
||||
ConstantValue(&'tcx ty::Const<'tcx>),
|
||||
/// Ranges of literal values (`2...5` and `2..5`).
|
||||
ConstantRange(ConstVal<'tcx>, ConstVal<'tcx>, RangeEnd),
|
||||
ConstantRange(&'tcx ty::Const<'tcx>, &'tcx ty::Const<'tcx>, RangeEnd),
|
||||
/// Array patterns of length n.
|
||||
Slice(usize),
|
||||
Slice(u64),
|
||||
}
|
||||
|
||||
impl<'tcx> Constructor<'tcx> {
|
||||
@ -273,7 +276,7 @@ pub enum WitnessPreference {
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
struct PatternContext<'tcx> {
|
||||
ty: Ty<'tcx>,
|
||||
max_slice_length: usize,
|
||||
max_slice_length: u64,
|
||||
}
|
||||
|
||||
/// A stack of patterns in reverse order of construction
|
||||
@ -327,8 +330,8 @@ impl<'tcx> Witness<'tcx> {
|
||||
{
|
||||
let arity = constructor_arity(cx, ctor, ty);
|
||||
let pat = {
|
||||
let len = self.0.len();
|
||||
let mut pats = self.0.drain(len-arity..).rev();
|
||||
let len = self.0.len() as u64;
|
||||
let mut pats = self.0.drain((len-arity) as usize..).rev();
|
||||
|
||||
match ty.sty {
|
||||
ty::TyAdt(..) |
|
||||
@ -370,7 +373,7 @@ impl<'tcx> Witness<'tcx> {
|
||||
|
||||
_ => {
|
||||
match *ctor {
|
||||
ConstantValue(ref v) => PatternKind::Constant { value: v.clone() },
|
||||
ConstantValue(value) => PatternKind::Constant { value },
|
||||
_ => PatternKind::Wild,
|
||||
}
|
||||
}
|
||||
@ -404,8 +407,24 @@ fn all_constructors<'a, 'tcx: 'a>(cx: &mut MatchCheckCtxt<'a, 'tcx>,
|
||||
{
|
||||
debug!("all_constructors({:?})", pcx.ty);
|
||||
match pcx.ty.sty {
|
||||
ty::TyBool =>
|
||||
[true, false].iter().map(|b| ConstantValue(ConstVal::Bool(*b))).collect(),
|
||||
ty::TyBool => {
|
||||
[true, false].iter().map(|&b| {
|
||||
ConstantValue(cx.tcx.mk_const(ty::Const {
|
||||
val: ConstVal::Bool(b),
|
||||
ty: cx.tcx.types.bool
|
||||
}))
|
||||
}).collect()
|
||||
}
|
||||
ty::TyArray(ref sub_ty, len) if len.val.to_const_int().is_some() => {
|
||||
let len = len.val.to_const_int().unwrap().to_u64().unwrap();
|
||||
if len != 0 && cx.is_uninhabited(sub_ty) {
|
||||
vec![]
|
||||
} else {
|
||||
vec![Slice(len)]
|
||||
}
|
||||
}
|
||||
// Treat arrays of a constant but unknown length like slices.
|
||||
ty::TyArray(ref sub_ty, _) |
|
||||
ty::TySlice(ref sub_ty) => {
|
||||
if cx.is_uninhabited(sub_ty) {
|
||||
vec![Slice(0)]
|
||||
@ -413,13 +432,6 @@ fn all_constructors<'a, 'tcx: 'a>(cx: &mut MatchCheckCtxt<'a, 'tcx>,
|
||||
(0..pcx.max_slice_length+1).map(|length| Slice(length)).collect()
|
||||
}
|
||||
}
|
||||
ty::TyArray(ref sub_ty, length) => {
|
||||
if length > 0 && cx.is_uninhabited(sub_ty) {
|
||||
vec![]
|
||||
} else {
|
||||
vec![Slice(length)]
|
||||
}
|
||||
}
|
||||
ty::TyAdt(def, substs) if def.is_enum() && def.variants.len() != 1 => {
|
||||
def.variants.iter()
|
||||
.filter(|v| !cx.is_variant_uninhabited(v, substs))
|
||||
@ -438,7 +450,7 @@ fn all_constructors<'a, 'tcx: 'a>(cx: &mut MatchCheckCtxt<'a, 'tcx>,
|
||||
|
||||
fn max_slice_length<'p, 'a: 'p, 'tcx: 'a, I>(
|
||||
_cx: &mut MatchCheckCtxt<'a, 'tcx>,
|
||||
patterns: I) -> usize
|
||||
patterns: I) -> u64
|
||||
where I: Iterator<Item=&'p Pattern<'tcx>>
|
||||
{
|
||||
// The exhaustiveness-checking paper does not include any details on
|
||||
@ -511,16 +523,16 @@ fn max_slice_length<'p, 'a: 'p, 'tcx: 'a, I>(
|
||||
|
||||
for row in patterns {
|
||||
match *row.kind {
|
||||
PatternKind::Constant { value: ConstVal::ByteStr(ref data) } => {
|
||||
max_fixed_len = cmp::max(max_fixed_len, data.len());
|
||||
PatternKind::Constant { value: &ty::Const { val: ConstVal::ByteStr(b), .. } } => {
|
||||
max_fixed_len = cmp::max(max_fixed_len, b.data.len() as u64);
|
||||
}
|
||||
PatternKind::Slice { ref prefix, slice: None, ref suffix } => {
|
||||
let fixed_len = prefix.len() + suffix.len();
|
||||
let fixed_len = prefix.len() as u64 + suffix.len() as u64;
|
||||
max_fixed_len = cmp::max(max_fixed_len, fixed_len);
|
||||
}
|
||||
PatternKind::Slice { ref prefix, slice: Some(_), ref suffix } => {
|
||||
max_prefix_len = cmp::max(max_prefix_len, prefix.len());
|
||||
max_suffix_len = cmp::max(max_suffix_len, suffix.len());
|
||||
max_prefix_len = cmp::max(max_prefix_len, prefix.len() as u64);
|
||||
max_suffix_len = cmp::max(max_suffix_len, suffix.len() as u64);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
@ -715,16 +727,18 @@ fn pat_constructors<'tcx>(_cx: &mut MatchCheckCtxt,
|
||||
Some(vec![Single]),
|
||||
PatternKind::Variant { adt_def, variant_index, .. } =>
|
||||
Some(vec![Variant(adt_def.variants[variant_index].did)]),
|
||||
PatternKind::Constant { ref value } =>
|
||||
Some(vec![ConstantValue(value.clone())]),
|
||||
PatternKind::Range { ref lo, ref hi, ref end } =>
|
||||
Some(vec![ConstantRange(lo.clone(), hi.clone(), end.clone())]),
|
||||
PatternKind::Constant { value } =>
|
||||
Some(vec![ConstantValue(value)]),
|
||||
PatternKind::Range { lo, hi, end } =>
|
||||
Some(vec![ConstantRange(lo, hi, end)]),
|
||||
PatternKind::Array { .. } => match pcx.ty.sty {
|
||||
ty::TyArray(_, length) => Some(vec![Slice(length)]),
|
||||
ty::TyArray(_, length) => Some(vec![
|
||||
Slice(length.val.to_const_int().unwrap().to_u64().unwrap())
|
||||
]),
|
||||
_ => span_bug!(pat.span, "bad ty {:?} for array pattern", pcx.ty)
|
||||
},
|
||||
PatternKind::Slice { ref prefix, ref slice, ref suffix } => {
|
||||
let pat_len = prefix.len() + suffix.len();
|
||||
let pat_len = prefix.len() as u64 + suffix.len() as u64;
|
||||
if slice.is_some() {
|
||||
Some((pat_len..pcx.max_slice_length+1).map(Slice).collect())
|
||||
} else {
|
||||
@ -739,10 +753,10 @@ fn pat_constructors<'tcx>(_cx: &mut MatchCheckCtxt,
|
||||
///
|
||||
/// For instance, a tuple pattern (_, 42, Some([])) has the arity of 3.
|
||||
/// A struct pattern's arity is the number of fields it contains, etc.
|
||||
fn constructor_arity(_cx: &MatchCheckCtxt, ctor: &Constructor, ty: Ty) -> usize {
|
||||
fn constructor_arity(_cx: &MatchCheckCtxt, ctor: &Constructor, ty: Ty) -> u64 {
|
||||
debug!("constructor_arity({:?}, {:?})", ctor, ty);
|
||||
match ty.sty {
|
||||
ty::TyTuple(ref fs, _) => fs.len(),
|
||||
ty::TyTuple(ref fs, _) => fs.len() as u64,
|
||||
ty::TySlice(..) | ty::TyArray(..) => match *ctor {
|
||||
Slice(length) => length,
|
||||
ConstantValue(_) => 0,
|
||||
@ -750,7 +764,7 @@ fn constructor_arity(_cx: &MatchCheckCtxt, ctor: &Constructor, ty: Ty) -> usize
|
||||
},
|
||||
ty::TyRef(..) => 1,
|
||||
ty::TyAdt(adt, _) => {
|
||||
adt.variants[ctor.variant_index_for_adt(adt)].fields.len()
|
||||
adt.variants[ctor.variant_index_for_adt(adt)].fields.len() as u64
|
||||
}
|
||||
_ => 0
|
||||
}
|
||||
@ -768,7 +782,7 @@ fn constructor_sub_pattern_tys<'a, 'tcx: 'a>(cx: &MatchCheckCtxt<'a, 'tcx>,
|
||||
match ty.sty {
|
||||
ty::TyTuple(ref fs, _) => fs.into_iter().map(|t| *t).collect(),
|
||||
ty::TySlice(ty) | ty::TyArray(ty, _) => match *ctor {
|
||||
Slice(length) => repeat(ty).take(length).collect(),
|
||||
Slice(length) => (0..length).map(|_| ty).collect(),
|
||||
ConstantValue(_) => vec![],
|
||||
_ => bug!("bad slice pattern {:?} {:?}", ctor, ty)
|
||||
},
|
||||
@ -806,7 +820,7 @@ fn slice_pat_covered_by_constructor(_tcx: TyCtxt, _span: Span,
|
||||
suffix: &[Pattern])
|
||||
-> Result<bool, ErrorReported> {
|
||||
let data = match *ctor {
|
||||
ConstantValue(ConstVal::ByteStr(ref data)) => data,
|
||||
ConstantValue(&ty::Const { val: ConstVal::ByteStr(b), .. }) => b.data,
|
||||
_ => bug!()
|
||||
};
|
||||
|
||||
@ -820,7 +834,7 @@ fn slice_pat_covered_by_constructor(_tcx: TyCtxt, _span: Span,
|
||||
data[data.len()-suffix.len()..].iter().zip(suffix))
|
||||
{
|
||||
match pat.kind {
|
||||
box PatternKind::Constant { ref value } => match *value {
|
||||
box PatternKind::Constant { value } => match value.val {
|
||||
ConstVal::Integral(ConstInt::U8(u)) => {
|
||||
if u != *ch {
|
||||
return Ok(false);
|
||||
@ -843,23 +857,23 @@ fn constructor_covered_by_range(tcx: TyCtxt, span: Span,
|
||||
let cmp_from = |c_from| Ok(compare_const_vals(tcx, span, c_from, from)? != Ordering::Less);
|
||||
let cmp_to = |c_to| compare_const_vals(tcx, span, c_to, to);
|
||||
match *ctor {
|
||||
ConstantValue(ref value) => {
|
||||
let to = cmp_to(value)?;
|
||||
ConstantValue(value) => {
|
||||
let to = cmp_to(&value.val)?;
|
||||
let end = (to == Ordering::Less) ||
|
||||
(end == RangeEnd::Included && to == Ordering::Equal);
|
||||
Ok(cmp_from(value)? && end)
|
||||
Ok(cmp_from(&value.val)? && end)
|
||||
},
|
||||
ConstantRange(ref from, ref to, RangeEnd::Included) => {
|
||||
let to = cmp_to(to)?;
|
||||
ConstantRange(from, to, RangeEnd::Included) => {
|
||||
let to = cmp_to(&to.val)?;
|
||||
let end = (to == Ordering::Less) ||
|
||||
(end == RangeEnd::Included && to == Ordering::Equal);
|
||||
Ok(cmp_from(from)? && end)
|
||||
Ok(cmp_from(&from.val)? && end)
|
||||
},
|
||||
ConstantRange(ref from, ref to, RangeEnd::Excluded) => {
|
||||
let to = cmp_to(to)?;
|
||||
ConstantRange(from, to, RangeEnd::Excluded) => {
|
||||
let to = cmp_to(&to.val)?;
|
||||
let end = (to == Ordering::Less) ||
|
||||
(end == RangeEnd::Excluded && to == Ordering::Equal);
|
||||
Ok(cmp_from(from)? && end)
|
||||
Ok(cmp_from(&from.val)? && end)
|
||||
}
|
||||
Single => Ok(true),
|
||||
_ => bug!(),
|
||||
@ -919,11 +933,11 @@ fn specialize<'p, 'a: 'p, 'tcx: 'a>(
|
||||
Some(vec![subpattern])
|
||||
}
|
||||
|
||||
PatternKind::Constant { ref value } => {
|
||||
PatternKind::Constant { value } => {
|
||||
match *constructor {
|
||||
Slice(..) => match *value {
|
||||
ConstVal::ByteStr(ref data) => {
|
||||
if wild_patterns.len() == data.len() {
|
||||
Slice(..) => match value.val {
|
||||
ConstVal::ByteStr(b) => {
|
||||
if wild_patterns.len() == b.data.len() {
|
||||
Some(cx.lower_byte_str_pattern(pat))
|
||||
} else {
|
||||
None
|
||||
@ -934,7 +948,7 @@ fn specialize<'p, 'a: 'p, 'tcx: 'a>(
|
||||
},
|
||||
_ => {
|
||||
match constructor_covered_by_range(
|
||||
cx.tcx, pat.span, constructor, value, value, RangeEnd::Included
|
||||
cx.tcx, pat.span, constructor, &value.val, &value.val, RangeEnd::Included
|
||||
) {
|
||||
Ok(true) => Some(vec![]),
|
||||
Ok(false) => None,
|
||||
@ -944,9 +958,9 @@ fn specialize<'p, 'a: 'p, 'tcx: 'a>(
|
||||
}
|
||||
}
|
||||
|
||||
PatternKind::Range { ref lo, ref hi, ref end } => {
|
||||
PatternKind::Range { lo, hi, ref end } => {
|
||||
match constructor_covered_by_range(
|
||||
cx.tcx, pat.span, constructor, lo, hi, end.clone()
|
||||
cx.tcx, pat.span, constructor, &lo.val, &hi.val, end.clone()
|
||||
) {
|
||||
Ok(true) => Some(vec![]),
|
||||
Ok(false) => None,
|
||||
|
@ -140,7 +140,7 @@ impl<'a, 'tcx> MatchVisitor<'a, 'tcx> {
|
||||
fn check_match(
|
||||
&self,
|
||||
scrut: &hir::Expr,
|
||||
arms: &[hir::Arm],
|
||||
arms: &'tcx [hir::Arm],
|
||||
source: hir::MatchSource)
|
||||
{
|
||||
for arm in arms {
|
||||
@ -231,7 +231,7 @@ impl<'a, 'tcx> MatchVisitor<'a, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
fn check_irrefutable(&self, pat: &Pat, origin: &str) {
|
||||
fn check_irrefutable(&self, pat: &'tcx Pat, origin: &str) {
|
||||
let module = self.tcx.hir.get_module_parent(pat.id);
|
||||
MatchCheckCtxt::create_and_enter(self.tcx, module, |ref mut cx| {
|
||||
let mut patcx = PatternContext::new(self.tcx,
|
||||
|
@ -565,7 +565,7 @@ See also https://github.com/rust-lang/rust/issues/14587
|
||||
|
||||
|
||||
register_diagnostics! {
|
||||
E0298, // cannot compare constants
|
||||
// E0298, // cannot compare constants
|
||||
// E0299, // mismatched types between arms
|
||||
// E0471, // constant evaluation error (in pattern)
|
||||
}
|
||||
|
@ -9,8 +9,9 @@
|
||||
// except according to those terms.
|
||||
|
||||
use rustc::middle::const_val::ConstVal::*;
|
||||
use rustc::middle::const_val::ConstAggregate::*;
|
||||
use rustc::middle::const_val::ErrKind::*;
|
||||
use rustc::middle::const_val::{ConstVal, ConstEvalErr, EvalResult, ErrKind};
|
||||
use rustc::middle::const_val::{ByteArray, ConstVal, ConstEvalErr, EvalResult, ErrKind};
|
||||
|
||||
use rustc::hir::map as hir_map;
|
||||
use rustc::hir::map::blocks::FnLikeNode;
|
||||
@ -88,7 +89,7 @@ pub struct ConstContext<'a, 'tcx: 'a> {
|
||||
tables: &'a ty::TypeckTables<'tcx>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
substs: &'tcx Substs<'tcx>,
|
||||
fn_args: Option<NodeMap<ConstVal<'tcx>>>
|
||||
fn_args: Option<NodeMap<&'tcx ty::Const<'tcx>>>
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> ConstContext<'a, 'tcx> {
|
||||
@ -107,7 +108,7 @@ impl<'a, 'tcx> ConstContext<'a, 'tcx> {
|
||||
|
||||
/// Evaluate a constant expression in a context where the expression isn't
|
||||
/// guaranteed to be evaluable.
|
||||
pub fn eval(&self, e: &Expr) -> EvalResult<'tcx> {
|
||||
pub fn eval(&self, e: &'tcx Expr) -> EvalResult<'tcx> {
|
||||
if self.tables.tainted_by_errors {
|
||||
signal!(e, TypeckError);
|
||||
}
|
||||
@ -118,9 +119,10 @@ impl<'a, 'tcx> ConstContext<'a, 'tcx> {
|
||||
type CastResult<'tcx> = Result<ConstVal<'tcx>, ErrKind<'tcx>>;
|
||||
|
||||
fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>,
|
||||
e: &Expr) -> EvalResult<'tcx> {
|
||||
e: &'tcx Expr) -> EvalResult<'tcx> {
|
||||
let tcx = cx.tcx;
|
||||
let ety = cx.tables.expr_ty(e).subst(tcx, cx.substs);
|
||||
let ty = cx.tables.expr_ty(e).subst(tcx, cx.substs);
|
||||
let mk_const = |val| tcx.mk_const(ty::Const { val, ty });
|
||||
|
||||
let result = match e.node {
|
||||
hir::ExprUnary(hir::UnNeg, ref inner) => {
|
||||
@ -133,57 +135,66 @@ fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>,
|
||||
const I32_OVERFLOW: u128 = i32::min_value() as u32 as u128;
|
||||
const I64_OVERFLOW: u128 = i64::min_value() as u64 as u128;
|
||||
const I128_OVERFLOW: u128 = i128::min_value() as u128;
|
||||
match (&lit.node, &ety.sty) {
|
||||
let negated = match (&lit.node, &ty.sty) {
|
||||
(&LitKind::Int(I8_OVERFLOW, _), &ty::TyInt(IntTy::I8)) |
|
||||
(&LitKind::Int(I8_OVERFLOW, Signed(IntTy::I8)), _) => {
|
||||
return Ok(Integral(I8(i8::min_value())))
|
||||
Some(I8(i8::min_value()))
|
||||
},
|
||||
(&LitKind::Int(I16_OVERFLOW, _), &ty::TyInt(IntTy::I16)) |
|
||||
(&LitKind::Int(I16_OVERFLOW, Signed(IntTy::I16)), _) => {
|
||||
return Ok(Integral(I16(i16::min_value())))
|
||||
Some(I16(i16::min_value()))
|
||||
},
|
||||
(&LitKind::Int(I32_OVERFLOW, _), &ty::TyInt(IntTy::I32)) |
|
||||
(&LitKind::Int(I32_OVERFLOW, Signed(IntTy::I32)), _) => {
|
||||
return Ok(Integral(I32(i32::min_value())))
|
||||
Some(I32(i32::min_value()))
|
||||
},
|
||||
(&LitKind::Int(I64_OVERFLOW, _), &ty::TyInt(IntTy::I64)) |
|
||||
(&LitKind::Int(I64_OVERFLOW, Signed(IntTy::I64)), _) => {
|
||||
return Ok(Integral(I64(i64::min_value())))
|
||||
Some(I64(i64::min_value()))
|
||||
},
|
||||
(&LitKind::Int(I128_OVERFLOW, _), &ty::TyInt(IntTy::I128)) |
|
||||
(&LitKind::Int(I128_OVERFLOW, Signed(IntTy::I128)), _) => {
|
||||
return Ok(Integral(I128(i128::min_value())))
|
||||
Some(I128(i128::min_value()))
|
||||
},
|
||||
(&LitKind::Int(n, _), &ty::TyInt(IntTy::Is)) |
|
||||
(&LitKind::Int(n, Signed(IntTy::Is)), _) => {
|
||||
match tcx.sess.target.int_type {
|
||||
match tcx.sess.target.isize_ty {
|
||||
IntTy::I16 => if n == I16_OVERFLOW {
|
||||
return Ok(Integral(Isize(Is16(i16::min_value()))));
|
||||
Some(Isize(Is16(i16::min_value())))
|
||||
} else {
|
||||
None
|
||||
},
|
||||
IntTy::I32 => if n == I32_OVERFLOW {
|
||||
return Ok(Integral(Isize(Is32(i32::min_value()))));
|
||||
Some(Isize(Is32(i32::min_value())))
|
||||
} else {
|
||||
None
|
||||
},
|
||||
IntTy::I64 => if n == I64_OVERFLOW {
|
||||
return Ok(Integral(Isize(Is64(i64::min_value()))));
|
||||
Some(Isize(Is64(i64::min_value())))
|
||||
} else {
|
||||
None
|
||||
},
|
||||
_ => span_bug!(e.span, "typeck error")
|
||||
}
|
||||
},
|
||||
_ => {},
|
||||
_ => None
|
||||
};
|
||||
if let Some(i) = negated {
|
||||
return Ok(mk_const(Integral(i)));
|
||||
}
|
||||
}
|
||||
match cx.eval(inner)? {
|
||||
mk_const(match cx.eval(inner)?.val {
|
||||
Float(f) => Float(-f),
|
||||
Integral(i) => Integral(math!(e, -i)),
|
||||
const_val => signal!(e, NegateOn(const_val)),
|
||||
}
|
||||
_ => signal!(e, TypeckError)
|
||||
})
|
||||
}
|
||||
hir::ExprUnary(hir::UnNot, ref inner) => {
|
||||
match cx.eval(inner)? {
|
||||
mk_const(match cx.eval(inner)?.val {
|
||||
Integral(i) => Integral(math!(e, !i)),
|
||||
Bool(b) => Bool(!b),
|
||||
const_val => signal!(e, NotOn(const_val)),
|
||||
}
|
||||
_ => signal!(e, TypeckError)
|
||||
})
|
||||
}
|
||||
hir::ExprUnary(hir::UnDeref, _) => signal!(e, UnimplementedConstVal("deref operation")),
|
||||
hir::ExprBinary(op, ref a, ref b) => {
|
||||
@ -191,7 +202,7 @@ fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>,
|
||||
// gives us a type through a type-suffix, cast or const def type
|
||||
// we need to re-eval the other value of the BinOp if it was
|
||||
// not inferred
|
||||
match (cx.eval(a)?, cx.eval(b)?) {
|
||||
mk_const(match (cx.eval(a)?.val, cx.eval(b)?.val) {
|
||||
(Float(a), Float(b)) => {
|
||||
use std::cmp::Ordering::*;
|
||||
match op.node {
|
||||
@ -260,16 +271,16 @@ fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>,
|
||||
}
|
||||
|
||||
_ => signal!(e, MiscBinaryOp),
|
||||
}
|
||||
})
|
||||
}
|
||||
hir::ExprCast(ref base, _) => {
|
||||
let base_val = cx.eval(base)?;
|
||||
let base_ty = cx.tables.expr_ty(base).subst(tcx, cx.substs);
|
||||
if ety == base_ty {
|
||||
if ty == base_ty {
|
||||
base_val
|
||||
} else {
|
||||
match cast_const(tcx, base_val, ety) {
|
||||
Ok(val) => val,
|
||||
match cast_const(tcx, base_val.val, ty) {
|
||||
Ok(val) => mk_const(val),
|
||||
Err(kind) => signal!(e, kind),
|
||||
}
|
||||
}
|
||||
@ -291,52 +302,53 @@ fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>,
|
||||
}
|
||||
},
|
||||
Def::VariantCtor(variant_def, CtorKind::Const) => {
|
||||
Variant(variant_def)
|
||||
mk_const(Variant(variant_def))
|
||||
}
|
||||
Def::VariantCtor(_, CtorKind::Fn) => {
|
||||
signal!(e, UnimplementedConstVal("enum variants"));
|
||||
}
|
||||
Def::StructCtor(_, CtorKind::Const) => {
|
||||
ConstVal::Struct(Default::default())
|
||||
mk_const(Aggregate(Struct(&[])))
|
||||
}
|
||||
Def::StructCtor(_, CtorKind::Fn) => {
|
||||
signal!(e, UnimplementedConstVal("tuple struct constructors"))
|
||||
}
|
||||
Def::Local(id) => {
|
||||
debug!("Def::Local({:?}): {:?}", id, cx.fn_args);
|
||||
if let Some(val) = cx.fn_args.as_ref().and_then(|args| args.get(&id)) {
|
||||
val.clone()
|
||||
if let Some(&val) = cx.fn_args.as_ref().and_then(|args| args.get(&id)) {
|
||||
val
|
||||
} else {
|
||||
signal!(e, NonConstPath);
|
||||
}
|
||||
},
|
||||
Def::Method(id) | Def::Fn(id) => Function(id, substs),
|
||||
Def::Method(id) | Def::Fn(id) => mk_const(Function(id, substs)),
|
||||
Def::Err => span_bug!(e.span, "typeck error"),
|
||||
_ => signal!(e, NonConstPath),
|
||||
}
|
||||
}
|
||||
hir::ExprCall(ref callee, ref args) => {
|
||||
let (def_id, substs) = match cx.eval(callee)? {
|
||||
let (def_id, substs) = match cx.eval(callee)?.val {
|
||||
Function(def_id, substs) => (def_id, substs),
|
||||
_ => signal!(e, TypeckError),
|
||||
};
|
||||
|
||||
if tcx.fn_sig(def_id).abi() == Abi::RustIntrinsic {
|
||||
let layout_of = |ty: Ty<'tcx>| {
|
||||
ty.layout(tcx, cx.param_env).map_err(|err| {
|
||||
let ty = tcx.erase_regions(&ty);
|
||||
tcx.at(e.span).layout_raw(cx.param_env.reveal_all().and(ty)).map_err(|err| {
|
||||
ConstEvalErr { span: e.span, kind: LayoutError(err) }
|
||||
})
|
||||
};
|
||||
match &tcx.item_name(def_id)[..] {
|
||||
"size_of" => {
|
||||
let size = layout_of(substs.type_at(0))?.size(tcx);
|
||||
return Ok(Integral(Usize(ConstUsize::new(size.bytes(),
|
||||
tcx.sess.target.uint_type).unwrap())));
|
||||
let size = layout_of(substs.type_at(0))?.size(tcx).bytes();
|
||||
return Ok(mk_const(Integral(Usize(ConstUsize::new(size,
|
||||
tcx.sess.target.usize_ty).unwrap()))));
|
||||
}
|
||||
"min_align_of" => {
|
||||
let align = layout_of(substs.type_at(0))?.align(tcx);
|
||||
return Ok(Integral(Usize(ConstUsize::new(align.abi(),
|
||||
tcx.sess.target.uint_type).unwrap())));
|
||||
let align = layout_of(substs.type_at(0))?.align(tcx).abi();
|
||||
return Ok(mk_const(Integral(Usize(ConstUsize::new(align,
|
||||
tcx.sess.target.usize_ty).unwrap()))));
|
||||
}
|
||||
_ => signal!(e, TypeckError)
|
||||
}
|
||||
@ -384,84 +396,83 @@ fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>,
|
||||
};
|
||||
callee_cx.eval(&body.value)?
|
||||
},
|
||||
hir::ExprLit(ref lit) => match lit_to_const(&lit.node, tcx, ety) {
|
||||
Ok(val) => val,
|
||||
hir::ExprLit(ref lit) => match lit_to_const(&lit.node, tcx, ty) {
|
||||
Ok(val) => mk_const(val),
|
||||
Err(err) => signal!(e, err),
|
||||
},
|
||||
hir::ExprBlock(ref block) => {
|
||||
match block.expr {
|
||||
Some(ref expr) => cx.eval(expr)?,
|
||||
None => Tuple(vec![]),
|
||||
None => mk_const(Aggregate(Tuple(&[]))),
|
||||
}
|
||||
}
|
||||
hir::ExprType(ref e, _) => cx.eval(e)?,
|
||||
hir::ExprTup(ref fields) => {
|
||||
Tuple(fields.iter().map(|e| cx.eval(e)).collect::<Result<_, _>>()?)
|
||||
let values = fields.iter().map(|e| cx.eval(e)).collect::<Result<Vec<_>, _>>()?;
|
||||
mk_const(Aggregate(Tuple(tcx.alloc_const_slice(&values))))
|
||||
}
|
||||
hir::ExprStruct(_, ref fields, _) => {
|
||||
Struct(fields.iter().map(|f| {
|
||||
mk_const(Aggregate(Struct(tcx.alloc_name_const_slice(&fields.iter().map(|f| {
|
||||
cx.eval(&f.expr).map(|v| (f.name.node, v))
|
||||
}).collect::<Result<_, _>>()?)
|
||||
}).collect::<Result<Vec<_>, _>>()?))))
|
||||
}
|
||||
hir::ExprIndex(ref arr, ref idx) => {
|
||||
if !tcx.sess.features.borrow().const_indexing {
|
||||
signal!(e, IndexOpFeatureGated);
|
||||
}
|
||||
let arr = cx.eval(arr)?;
|
||||
let idx = match cx.eval(idx)? {
|
||||
Integral(Usize(i)) => i.as_u64(tcx.sess.target.uint_type),
|
||||
let idx = match cx.eval(idx)?.val {
|
||||
Integral(Usize(i)) => i.as_u64(),
|
||||
_ => signal!(idx, IndexNotUsize),
|
||||
};
|
||||
assert_eq!(idx as usize as u64, idx);
|
||||
match arr {
|
||||
Array(ref v) => {
|
||||
if let Some(elem) = v.get(idx as usize) {
|
||||
elem.clone()
|
||||
match arr.val {
|
||||
Aggregate(Array(v)) => {
|
||||
if let Some(&elem) = v.get(idx as usize) {
|
||||
elem
|
||||
} else {
|
||||
let n = v.len() as u64;
|
||||
assert_eq!(n as usize as u64, n);
|
||||
signal!(e, IndexOutOfBounds { len: n, index: idx })
|
||||
}
|
||||
}
|
||||
|
||||
Repeat(.., n) if idx >= n => {
|
||||
Aggregate(Repeat(.., n)) if idx >= n => {
|
||||
signal!(e, IndexOutOfBounds { len: n, index: idx })
|
||||
}
|
||||
Repeat(ref elem, _) => (**elem).clone(),
|
||||
Aggregate(Repeat(elem, _)) => elem,
|
||||
|
||||
ByteStr(ref data) if idx >= data.len() as u64 => {
|
||||
signal!(e, IndexOutOfBounds { len: data.len() as u64, index: idx })
|
||||
ByteStr(b) if idx >= b.data.len() as u64 => {
|
||||
signal!(e, IndexOutOfBounds { len: b.data.len() as u64, index: idx })
|
||||
}
|
||||
ByteStr(data) => {
|
||||
Integral(U8(data[idx as usize]))
|
||||
ByteStr(b) => {
|
||||
mk_const(Integral(U8(b.data[idx as usize])))
|
||||
},
|
||||
|
||||
_ => signal!(e, IndexedNonVec),
|
||||
}
|
||||
}
|
||||
hir::ExprArray(ref v) => {
|
||||
Array(v.iter().map(|e| cx.eval(e)).collect::<Result<_, _>>()?)
|
||||
let values = v.iter().map(|e| cx.eval(e)).collect::<Result<Vec<_>, _>>()?;
|
||||
mk_const(Aggregate(Array(tcx.alloc_const_slice(&values))))
|
||||
}
|
||||
hir::ExprRepeat(ref elem, _) => {
|
||||
let n = match ety.sty {
|
||||
ty::TyArray(_, n) => n as u64,
|
||||
let n = match ty.sty {
|
||||
ty::TyArray(_, n) => n.val.to_const_int().unwrap().to_u64().unwrap(),
|
||||
_ => span_bug!(e.span, "typeck error")
|
||||
};
|
||||
Repeat(Box::new(cx.eval(elem)?), n)
|
||||
mk_const(Aggregate(Repeat(cx.eval(elem)?, n)))
|
||||
},
|
||||
hir::ExprTupField(ref base, index) => {
|
||||
let c = cx.eval(base)?;
|
||||
if let Tuple(ref fields) = c {
|
||||
fields[index.node].clone()
|
||||
if let Aggregate(Tuple(fields)) = cx.eval(base)?.val {
|
||||
fields[index.node]
|
||||
} else {
|
||||
signal!(base, ExpectedConstTuple);
|
||||
}
|
||||
}
|
||||
hir::ExprField(ref base, field_name) => {
|
||||
let c = cx.eval(base)?;
|
||||
if let Struct(ref fields) = c {
|
||||
if let Some(f) = fields.get(&field_name.node) {
|
||||
f.clone()
|
||||
if let Aggregate(Struct(fields)) = cx.eval(base)?.val {
|
||||
if let Some(&(_, f)) = fields.iter().find(|&&(name, _)| name == field_name.node) {
|
||||
f
|
||||
} else {
|
||||
signal!(e, MissingStructField);
|
||||
}
|
||||
@ -551,7 +562,7 @@ fn cast_const_int<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
ty::TyInt(ast::IntTy::I64) => Ok(Integral(I64(v as i128 as i64))),
|
||||
ty::TyInt(ast::IntTy::I128) => Ok(Integral(I128(v as i128))),
|
||||
ty::TyInt(ast::IntTy::Is) => {
|
||||
Ok(Integral(Isize(ConstIsize::new_truncating(v as i128, tcx.sess.target.int_type))))
|
||||
Ok(Integral(Isize(ConstIsize::new_truncating(v as i128, tcx.sess.target.isize_ty))))
|
||||
},
|
||||
ty::TyUint(ast::UintTy::U8) => Ok(Integral(U8(v as u8))),
|
||||
ty::TyUint(ast::UintTy::U16) => Ok(Integral(U16(v as u16))),
|
||||
@ -559,7 +570,7 @@ fn cast_const_int<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
ty::TyUint(ast::UintTy::U64) => Ok(Integral(U64(v as u64))),
|
||||
ty::TyUint(ast::UintTy::U128) => Ok(Integral(U128(v as u128))),
|
||||
ty::TyUint(ast::UintTy::Us) => {
|
||||
Ok(Integral(Usize(ConstUsize::new_truncating(v, tcx.sess.target.uint_type))))
|
||||
Ok(Integral(Usize(ConstUsize::new_truncating(v, tcx.sess.target.usize_ty))))
|
||||
},
|
||||
ty::TyFloat(fty) => {
|
||||
if let Some(i) = val.to_u128() {
|
||||
@ -625,7 +636,14 @@ fn cast_const<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
Err(ErrKind::UnimplementedConstVal("casting a bytestr to a raw ptr"))
|
||||
},
|
||||
ty::TyRef(_, ty::TypeAndMut { ref ty, mutbl: hir::MutImmutable }) => match ty.sty {
|
||||
ty::TyArray(ty, n) if ty == tcx.types.u8 && n == b.len() => Ok(ByteStr(b)),
|
||||
ty::TyArray(ty, n) => {
|
||||
let n = n.val.to_const_int().unwrap().to_u64().unwrap();
|
||||
if ty == tcx.types.u8 && n == b.data.len() as u64 {
|
||||
Ok(val)
|
||||
} else {
|
||||
Err(CannotCast)
|
||||
}
|
||||
}
|
||||
ty::TySlice(_) => {
|
||||
Err(ErrKind::UnimplementedConstVal("casting a bytestr to slice"))
|
||||
},
|
||||
@ -645,7 +663,7 @@ fn cast_const<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
}
|
||||
}
|
||||
|
||||
fn lit_to_const<'a, 'tcx>(lit: &ast::LitKind,
|
||||
fn lit_to_const<'a, 'tcx>(lit: &'tcx ast::LitKind,
|
||||
tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
mut ty: Ty<'tcx>)
|
||||
-> Result<ConstVal<'tcx>, ErrKind<'tcx>> {
|
||||
@ -660,19 +678,19 @@ fn lit_to_const<'a, 'tcx>(lit: &ast::LitKind,
|
||||
|
||||
match *lit {
|
||||
LitKind::Str(ref s, _) => Ok(Str(s.as_str())),
|
||||
LitKind::ByteStr(ref data) => Ok(ByteStr(data.clone())),
|
||||
LitKind::ByteStr(ref data) => Ok(ByteStr(ByteArray { data })),
|
||||
LitKind::Byte(n) => Ok(Integral(U8(n))),
|
||||
LitKind::Int(n, hint) => {
|
||||
match (&ty.sty, hint) {
|
||||
(&ty::TyInt(ity), _) |
|
||||
(_, Signed(ity)) => {
|
||||
Ok(Integral(ConstInt::new_signed_truncating(n as i128,
|
||||
ity, tcx.sess.target.int_type)))
|
||||
ity, tcx.sess.target.isize_ty)))
|
||||
}
|
||||
(&ty::TyUint(uty), _) |
|
||||
(_, Unsigned(uty)) => {
|
||||
Ok(Integral(ConstInt::new_unsigned_truncating(n as u128,
|
||||
uty, tcx.sess.target.uint_type)))
|
||||
uty, tcx.sess.target.usize_ty)))
|
||||
}
|
||||
_ => bug!()
|
||||
}
|
||||
@ -708,8 +726,8 @@ pub fn compare_const_vals(tcx: TyCtxt, span: Span, a: &ConstVal, b: &ConstVal)
|
||||
(&Float(a), &Float(b)) => a.try_cmp(b).ok(),
|
||||
(&Str(ref a), &Str(ref b)) => Some(a.cmp(b)),
|
||||
(&Bool(a), &Bool(b)) => Some(a.cmp(&b)),
|
||||
(&ByteStr(ref a), &ByteStr(ref b)) => Some(a.cmp(b)),
|
||||
(&Char(a), &Char(ref b)) => Some(a.cmp(b)),
|
||||
(&ByteStr(a), &ByteStr(b)) => Some(a.data.cmp(b.data)),
|
||||
(&Char(a), &Char(b)) => Some(a.cmp(&b)),
|
||||
_ => None,
|
||||
};
|
||||
|
||||
@ -717,10 +735,8 @@ pub fn compare_const_vals(tcx: TyCtxt, span: Span, a: &ConstVal, b: &ConstVal)
|
||||
Some(result) => Ok(result),
|
||||
None => {
|
||||
// FIXME: can this ever be reached?
|
||||
span_err!(tcx.sess, span, E0298,
|
||||
"type mismatch comparing {} and {}",
|
||||
a.description(),
|
||||
b.description());
|
||||
tcx.sess.delay_span_bug(span,
|
||||
&format!("type mismatch comparing {:?} and {:?}", a, b));
|
||||
Err(ErrorReported)
|
||||
}
|
||||
}
|
||||
@ -729,8 +745,8 @@ pub fn compare_const_vals(tcx: TyCtxt, span: Span, a: &ConstVal, b: &ConstVal)
|
||||
impl<'a, 'tcx> ConstContext<'a, 'tcx> {
|
||||
pub fn compare_lit_exprs(&self,
|
||||
span: Span,
|
||||
a: &Expr,
|
||||
b: &Expr) -> Result<Ordering, ErrorReported> {
|
||||
a: &'tcx Expr,
|
||||
b: &'tcx Expr) -> Result<Ordering, ErrorReported> {
|
||||
let tcx = self.tcx;
|
||||
let a = match self.eval(a) {
|
||||
Ok(a) => a,
|
||||
@ -746,7 +762,7 @@ impl<'a, 'tcx> ConstContext<'a, 'tcx> {
|
||||
return Err(ErrorReported);
|
||||
}
|
||||
};
|
||||
compare_const_vals(tcx, span, &a, &b)
|
||||
compare_const_vals(tcx, span, &a.val, &b.val)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -83,12 +83,12 @@ pub enum PatternKind<'tcx> {
|
||||
},
|
||||
|
||||
Constant {
|
||||
value: ConstVal<'tcx>,
|
||||
value: &'tcx ty::Const<'tcx>,
|
||||
},
|
||||
|
||||
Range {
|
||||
lo: ConstVal<'tcx>,
|
||||
hi: ConstVal<'tcx>,
|
||||
lo: &'tcx ty::Const<'tcx>,
|
||||
hi: &'tcx ty::Const<'tcx>,
|
||||
end: RangeEnd,
|
||||
},
|
||||
|
||||
@ -112,15 +112,13 @@ fn print_const_val(value: &ConstVal, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
ConstVal::Float(ref x) => write!(f, "{}", x),
|
||||
ConstVal::Integral(ref i) => write!(f, "{}", i),
|
||||
ConstVal::Str(ref s) => write!(f, "{:?}", &s[..]),
|
||||
ConstVal::ByteStr(ref b) => write!(f, "{:?}", &b[..]),
|
||||
ConstVal::ByteStr(b) => write!(f, "{:?}", b.data),
|
||||
ConstVal::Bool(b) => write!(f, "{:?}", b),
|
||||
ConstVal::Char(c) => write!(f, "{:?}", c),
|
||||
ConstVal::Variant(_) |
|
||||
ConstVal::Struct(_) |
|
||||
ConstVal::Tuple(_) |
|
||||
ConstVal::Function(..) |
|
||||
ConstVal::Array(..) |
|
||||
ConstVal::Repeat(..) => bug!("{:?} not printable in a pattern", value)
|
||||
ConstVal::Aggregate(_) |
|
||||
ConstVal::Unevaluated(..) => bug!("{:?} not printable in a pattern", value)
|
||||
}
|
||||
}
|
||||
|
||||
@ -230,16 +228,16 @@ impl<'tcx> fmt::Display for Pattern<'tcx> {
|
||||
}
|
||||
write!(f, "{}", subpattern)
|
||||
}
|
||||
PatternKind::Constant { ref value } => {
|
||||
print_const_val(value, f)
|
||||
PatternKind::Constant { value } => {
|
||||
print_const_val(&value.val, f)
|
||||
}
|
||||
PatternKind::Range { ref lo, ref hi, ref end } => {
|
||||
print_const_val(lo, f)?;
|
||||
match *end {
|
||||
PatternKind::Range { lo, hi, end } => {
|
||||
print_const_val(&lo.val, f)?;
|
||||
match end {
|
||||
RangeEnd::Included => write!(f, "...")?,
|
||||
RangeEnd::Excluded => write!(f, "..")?,
|
||||
}
|
||||
print_const_val(hi, f)
|
||||
print_const_val(&hi.val, f)
|
||||
}
|
||||
PatternKind::Slice { ref prefix, ref slice, ref suffix } |
|
||||
PatternKind::Array { ref prefix, ref slice, ref suffix } => {
|
||||
@ -278,7 +276,7 @@ impl<'a, 'tcx> Pattern<'tcx> {
|
||||
pub fn from_hir(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
param_env_and_substs: ty::ParamEnvAnd<'tcx, &'tcx Substs<'tcx>>,
|
||||
tables: &'a ty::TypeckTables<'tcx>,
|
||||
pat: &hir::Pat) -> Self {
|
||||
pat: &'tcx hir::Pat) -> Self {
|
||||
let mut pcx = PatternContext::new(tcx, param_env_and_substs, tables);
|
||||
let result = pcx.lower_pattern(pat);
|
||||
if !pcx.errors.is_empty() {
|
||||
@ -302,7 +300,7 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn lower_pattern(&mut self, pat: &hir::Pat) -> Pattern<'tcx> {
|
||||
pub fn lower_pattern(&mut self, pat: &'tcx hir::Pat) -> Pattern<'tcx> {
|
||||
let mut ty = self.tables.node_id_to_type(pat.hir_id);
|
||||
|
||||
let kind = match pat.node {
|
||||
@ -310,11 +308,11 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> {
|
||||
|
||||
PatKind::Lit(ref value) => self.lower_lit(value),
|
||||
|
||||
PatKind::Range(ref lo, ref hi, ref end) => {
|
||||
PatKind::Range(ref lo, ref hi, end) => {
|
||||
match (self.lower_lit(lo), self.lower_lit(hi)) {
|
||||
(PatternKind::Constant { value: lo },
|
||||
PatternKind::Constant { value: hi }) => {
|
||||
PatternKind::Range { lo: lo, hi: hi, end: end.clone() }
|
||||
PatternKind::Range { lo, hi, end }
|
||||
}
|
||||
_ => PatternKind::Wild
|
||||
}
|
||||
@ -474,11 +472,11 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
fn lower_patterns(&mut self, pats: &[P<hir::Pat>]) -> Vec<Pattern<'tcx>> {
|
||||
fn lower_patterns(&mut self, pats: &'tcx [P<hir::Pat>]) -> Vec<Pattern<'tcx>> {
|
||||
pats.iter().map(|p| self.lower_pattern(p)).collect()
|
||||
}
|
||||
|
||||
fn lower_opt_pattern(&mut self, pat: &Option<P<hir::Pat>>) -> Option<Pattern<'tcx>>
|
||||
fn lower_opt_pattern(&mut self, pat: &'tcx Option<P<hir::Pat>>) -> Option<Pattern<'tcx>>
|
||||
{
|
||||
pat.as_ref().map(|p| self.lower_pattern(p))
|
||||
}
|
||||
@ -521,9 +519,9 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> {
|
||||
&mut self,
|
||||
span: Span,
|
||||
ty: Ty<'tcx>,
|
||||
prefix: &[P<hir::Pat>],
|
||||
slice: &Option<P<hir::Pat>>,
|
||||
suffix: &[P<hir::Pat>])
|
||||
prefix: &'tcx [P<hir::Pat>],
|
||||
slice: &'tcx Option<P<hir::Pat>>,
|
||||
suffix: &'tcx [P<hir::Pat>])
|
||||
-> PatternKind<'tcx>
|
||||
{
|
||||
let prefix = self.lower_patterns(prefix);
|
||||
@ -540,7 +538,8 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> {
|
||||
|
||||
ty::TyArray(_, len) => {
|
||||
// fixed-length array
|
||||
assert!(len >= prefix.len() + suffix.len());
|
||||
let len = len.val.to_const_int().unwrap().to_u64().unwrap();
|
||||
assert!(len >= prefix.len() as u64 + suffix.len() as u64);
|
||||
PatternKind::Array { prefix: prefix, slice: slice, suffix: suffix }
|
||||
}
|
||||
|
||||
@ -631,17 +630,17 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
fn lower_lit(&mut self, expr: &hir::Expr) -> PatternKind<'tcx> {
|
||||
fn lower_lit(&mut self, expr: &'tcx hir::Expr) -> PatternKind<'tcx> {
|
||||
let const_cx = eval::ConstContext::new(self.tcx,
|
||||
self.param_env.and(self.substs),
|
||||
self.tables);
|
||||
match const_cx.eval(expr) {
|
||||
Ok(value) => {
|
||||
if let ConstVal::Variant(def_id) = value {
|
||||
if let ConstVal::Variant(def_id) = value.val {
|
||||
let ty = self.tables.expr_ty(expr);
|
||||
self.lower_variant_or_leaf(Def::Variant(def_id), ty, vec![])
|
||||
} else {
|
||||
PatternKind::Constant { value: value }
|
||||
PatternKind::Constant { value }
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
@ -652,7 +651,7 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> {
|
||||
}
|
||||
|
||||
fn lower_const_expr(&mut self,
|
||||
expr: &hir::Expr,
|
||||
expr: &'tcx hir::Expr,
|
||||
pat_id: ast::NodeId,
|
||||
span: Span)
|
||||
-> Pattern<'tcx> {
|
||||
@ -819,8 +818,8 @@ macro_rules! CloneImpls {
|
||||
}
|
||||
|
||||
CloneImpls!{ <'tcx>
|
||||
Span, Field, Mutability, ast::Name, ast::NodeId, usize, ConstVal<'tcx>, Region<'tcx>,
|
||||
Ty<'tcx>, BindingMode<'tcx>, &'tcx AdtDef,
|
||||
Span, Field, Mutability, ast::Name, ast::NodeId, usize, &'tcx ty::Const<'tcx>,
|
||||
Region<'tcx>, Ty<'tcx>, BindingMode<'tcx>, &'tcx AdtDef,
|
||||
&'tcx Substs<'tcx>, &'tcx Kind<'tcx>
|
||||
}
|
||||
|
||||
@ -892,18 +891,18 @@ impl<'tcx> PatternFoldable<'tcx> for PatternKind<'tcx> {
|
||||
subpattern: subpattern.fold_with(folder),
|
||||
},
|
||||
PatternKind::Constant {
|
||||
ref value
|
||||
value
|
||||
} => PatternKind::Constant {
|
||||
value: value.fold_with(folder)
|
||||
},
|
||||
PatternKind::Range {
|
||||
ref lo,
|
||||
ref hi,
|
||||
ref end,
|
||||
lo,
|
||||
hi,
|
||||
end,
|
||||
} => PatternKind::Range {
|
||||
lo: lo.fold_with(folder),
|
||||
hi: hi.fold_with(folder),
|
||||
end: end.clone(),
|
||||
end,
|
||||
},
|
||||
PatternKind::Slice {
|
||||
ref prefix,
|
||||
|
@ -311,17 +311,13 @@ impl ::std::fmt::Display for ConstInt {
|
||||
I32(i) => write!(fmt, "{}i32", i),
|
||||
I64(i) => write!(fmt, "{}i64", i),
|
||||
I128(i) => write!(fmt, "{}i128", i),
|
||||
Isize(ConstIsize::Is64(i)) => write!(fmt, "{}isize", i),
|
||||
Isize(ConstIsize::Is32(i)) => write!(fmt, "{}isize", i),
|
||||
Isize(ConstIsize::Is16(i)) => write!(fmt, "{}isize", i),
|
||||
Isize(i) => write!(fmt, "{}isize", i),
|
||||
U8(i) => write!(fmt, "{}u8", i),
|
||||
U16(i) => write!(fmt, "{}u16", i),
|
||||
U32(i) => write!(fmt, "{}u32", i),
|
||||
U64(i) => write!(fmt, "{}u64", i),
|
||||
U128(i) => write!(fmt, "{}u128", i),
|
||||
Usize(ConstUsize::Us64(i)) => write!(fmt, "{}usize", i),
|
||||
Usize(ConstUsize::Us32(i)) => write!(fmt, "{}usize", i),
|
||||
Usize(ConstUsize::Us16(i)) => write!(fmt, "{}usize", i),
|
||||
Usize(i) => write!(fmt, "{}usize", i),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -21,18 +21,22 @@ pub enum ConstIsize {
|
||||
}
|
||||
pub use self::ConstIsize::*;
|
||||
|
||||
impl ::std::fmt::Display for ConstIsize {
|
||||
fn fmt(&self, fmt: &mut ::std::fmt::Formatter) -> Result<(), ::std::fmt::Error> {
|
||||
write!(fmt, "{}", self.as_i64())
|
||||
}
|
||||
}
|
||||
|
||||
impl ConstIsize {
|
||||
pub fn as_i64(self, target_int_ty: ast::IntTy) -> i64 {
|
||||
match (self, target_int_ty) {
|
||||
(Is16(i), ast::IntTy::I16) => i as i64,
|
||||
(Is32(i), ast::IntTy::I32) => i as i64,
|
||||
(Is64(i), ast::IntTy::I64) => i,
|
||||
_ => panic!("unable to convert self ({:?}) to target isize ({:?})",
|
||||
self, target_int_ty),
|
||||
pub fn as_i64(self) -> i64 {
|
||||
match self {
|
||||
Is16(i) => i as i64,
|
||||
Is32(i) => i as i64,
|
||||
Is64(i) => i,
|
||||
}
|
||||
}
|
||||
pub fn new(i: i64, target_int_ty: ast::IntTy) -> Result<Self, ConstMathErr> {
|
||||
match target_int_ty {
|
||||
pub fn new(i: i64, isize_ty: ast::IntTy) -> Result<Self, ConstMathErr> {
|
||||
match isize_ty {
|
||||
ast::IntTy::I16 if i as i16 as i64 == i => Ok(Is16(i as i16)),
|
||||
ast::IntTy::I16 => Err(LitOutOfRange(ast::IntTy::Is)),
|
||||
ast::IntTy::I32 if i as i32 as i64 == i => Ok(Is32(i as i32)),
|
||||
@ -41,8 +45,8 @@ impl ConstIsize {
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
pub fn new_truncating(i: i128, target_int_ty: ast::IntTy) -> Self {
|
||||
match target_int_ty {
|
||||
pub fn new_truncating(i: i128, isize_ty: ast::IntTy) -> Self {
|
||||
match isize_ty {
|
||||
ast::IntTy::I16 => Is16(i as i16),
|
||||
ast::IntTy::I32 => Is32(i as i32),
|
||||
ast::IntTy::I64 => Is64(i as i64),
|
||||
|
@ -21,18 +21,22 @@ pub enum ConstUsize {
|
||||
}
|
||||
pub use self::ConstUsize::*;
|
||||
|
||||
impl ::std::fmt::Display for ConstUsize {
|
||||
fn fmt(&self, fmt: &mut ::std::fmt::Formatter) -> Result<(), ::std::fmt::Error> {
|
||||
write!(fmt, "{}", self.as_u64())
|
||||
}
|
||||
}
|
||||
|
||||
impl ConstUsize {
|
||||
pub fn as_u64(self, target_uint_ty: ast::UintTy) -> u64 {
|
||||
match (self, target_uint_ty) {
|
||||
(Us16(i), ast::UintTy::U16) => i as u64,
|
||||
(Us32(i), ast::UintTy::U32) => i as u64,
|
||||
(Us64(i), ast::UintTy::U64) => i,
|
||||
_ => panic!("unable to convert self ({:?}) to target usize ({:?})",
|
||||
self, target_uint_ty),
|
||||
pub fn as_u64(self) -> u64 {
|
||||
match self {
|
||||
Us16(i) => i as u64,
|
||||
Us32(i) => i as u64,
|
||||
Us64(i) => i,
|
||||
}
|
||||
}
|
||||
pub fn new(i: u64, target_uint_ty: ast::UintTy) -> Result<Self, ConstMathErr> {
|
||||
match target_uint_ty {
|
||||
pub fn new(i: u64, usize_ty: ast::UintTy) -> Result<Self, ConstMathErr> {
|
||||
match usize_ty {
|
||||
ast::UintTy::U16 if i as u16 as u64 == i => Ok(Us16(i as u16)),
|
||||
ast::UintTy::U16 => Err(ULitOutOfRange(ast::UintTy::Us)),
|
||||
ast::UintTy::U32 if i as u32 as u64 == i => Ok(Us32(i as u32)),
|
||||
@ -41,8 +45,8 @@ impl ConstUsize {
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
pub fn new_truncating(i: u128, target_uint_ty: ast::UintTy) -> Self {
|
||||
match target_uint_ty {
|
||||
pub fn new_truncating(i: u128, usize_ty: ast::UintTy) -> Self {
|
||||
match usize_ty {
|
||||
ast::UintTy::U16 => Us16(i as u16),
|
||||
ast::UintTy::U32 => Us32(i as u32),
|
||||
ast::UintTy::U64 => Us64(i as u64),
|
||||
|
@ -801,13 +801,13 @@ fn walk_ty() {
|
||||
test_env(EMPTY_SOURCE_STR, errors(&[]), |env| {
|
||||
let tcx = env.infcx.tcx;
|
||||
let int_ty = tcx.types.isize;
|
||||
let uint_ty = tcx.types.usize;
|
||||
let tup1_ty = tcx.intern_tup(&[int_ty, uint_ty, int_ty, uint_ty], false);
|
||||
let tup2_ty = tcx.intern_tup(&[tup1_ty, tup1_ty, uint_ty], false);
|
||||
let usize_ty = tcx.types.usize;
|
||||
let tup1_ty = tcx.intern_tup(&[int_ty, usize_ty, int_ty, usize_ty], false);
|
||||
let tup2_ty = tcx.intern_tup(&[tup1_ty, tup1_ty, usize_ty], false);
|
||||
let walked: Vec<_> = tup2_ty.walk().collect();
|
||||
assert_eq!(walked,
|
||||
[tup2_ty, tup1_ty, int_ty, uint_ty, int_ty, uint_ty, tup1_ty, int_ty,
|
||||
uint_ty, int_ty, uint_ty, uint_ty]);
|
||||
[tup2_ty, tup1_ty, int_ty, usize_ty, int_ty, usize_ty, tup1_ty, int_ty,
|
||||
usize_ty, int_ty, usize_ty, usize_ty]);
|
||||
})
|
||||
}
|
||||
|
||||
@ -816,20 +816,20 @@ fn walk_ty_skip_subtree() {
|
||||
test_env(EMPTY_SOURCE_STR, errors(&[]), |env| {
|
||||
let tcx = env.infcx.tcx;
|
||||
let int_ty = tcx.types.isize;
|
||||
let uint_ty = tcx.types.usize;
|
||||
let tup1_ty = tcx.intern_tup(&[int_ty, uint_ty, int_ty, uint_ty], false);
|
||||
let tup2_ty = tcx.intern_tup(&[tup1_ty, tup1_ty, uint_ty], false);
|
||||
let usize_ty = tcx.types.usize;
|
||||
let tup1_ty = tcx.intern_tup(&[int_ty, usize_ty, int_ty, usize_ty], false);
|
||||
let tup2_ty = tcx.intern_tup(&[tup1_ty, tup1_ty, usize_ty], false);
|
||||
|
||||
// types we expect to see (in order), plus a boolean saying
|
||||
// whether to skip the subtree.
|
||||
let mut expected = vec![(tup2_ty, false),
|
||||
(tup1_ty, false),
|
||||
(int_ty, false),
|
||||
(uint_ty, false),
|
||||
(usize_ty, false),
|
||||
(int_ty, false),
|
||||
(uint_ty, false),
|
||||
(usize_ty, false),
|
||||
(tup1_ty, true), // skip the isize/usize/isize/usize
|
||||
(uint_ty, false)];
|
||||
(usize_ty, false)];
|
||||
expected.reverse();
|
||||
|
||||
let mut walker = tup2_ty.walk();
|
||||
|
@ -76,7 +76,7 @@ impl LintPass for TypeLimits {
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TypeLimits {
|
||||
fn check_expr(&mut self, cx: &LateContext, e: &hir::Expr) {
|
||||
fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, e: &'tcx hir::Expr) {
|
||||
match e.node {
|
||||
hir::ExprUnary(hir::UnNeg, ref expr) => {
|
||||
// propagate negation, if the negation itself isn't negated
|
||||
@ -93,8 +93,8 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TypeLimits {
|
||||
|
||||
if binop.node.is_shift() {
|
||||
let opt_ty_bits = match cx.tables.node_id_to_type(l.hir_id).sty {
|
||||
ty::TyInt(t) => Some(int_ty_bits(t, cx.sess().target.int_type)),
|
||||
ty::TyUint(t) => Some(uint_ty_bits(t, cx.sess().target.uint_type)),
|
||||
ty::TyInt(t) => Some(int_ty_bits(t, cx.sess().target.isize_ty)),
|
||||
ty::TyUint(t) => Some(uint_ty_bits(t, cx.sess().target.usize_ty)),
|
||||
_ => None,
|
||||
};
|
||||
|
||||
@ -117,7 +117,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TypeLimits {
|
||||
cx.param_env.and(substs),
|
||||
cx.tables);
|
||||
match const_cx.eval(&r) {
|
||||
Ok(ConstVal::Integral(i)) => {
|
||||
Ok(&ty::Const { val: ConstVal::Integral(i), .. }) => {
|
||||
i.is_negative() ||
|
||||
i.to_u64()
|
||||
.map(|i| i >= bits)
|
||||
@ -141,7 +141,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TypeLimits {
|
||||
ast::LitKind::Int(v, ast::LitIntType::Signed(_)) |
|
||||
ast::LitKind::Int(v, ast::LitIntType::Unsuffixed) => {
|
||||
let int_type = if let ast::IntTy::Is = t {
|
||||
cx.sess().target.int_type
|
||||
cx.sess().target.isize_ty
|
||||
} else {
|
||||
t
|
||||
};
|
||||
@ -164,7 +164,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TypeLimits {
|
||||
}
|
||||
ty::TyUint(t) => {
|
||||
let uint_type = if let ast::UintTy::Us = t {
|
||||
cx.sess().target.uint_type
|
||||
cx.sess().target.usize_ty
|
||||
} else {
|
||||
t
|
||||
};
|
||||
@ -250,9 +250,9 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TypeLimits {
|
||||
}
|
||||
}
|
||||
|
||||
fn int_ty_bits(int_ty: ast::IntTy, target_int_ty: ast::IntTy) -> u64 {
|
||||
fn int_ty_bits(int_ty: ast::IntTy, isize_ty: ast::IntTy) -> u64 {
|
||||
match int_ty {
|
||||
ast::IntTy::Is => int_ty_bits(target_int_ty, target_int_ty),
|
||||
ast::IntTy::Is => int_ty_bits(isize_ty, isize_ty),
|
||||
ast::IntTy::I8 => 8,
|
||||
ast::IntTy::I16 => 16 as u64,
|
||||
ast::IntTy::I32 => 32,
|
||||
@ -261,9 +261,9 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TypeLimits {
|
||||
}
|
||||
}
|
||||
|
||||
fn uint_ty_bits(uint_ty: ast::UintTy, target_uint_ty: ast::UintTy) -> u64 {
|
||||
fn uint_ty_bits(uint_ty: ast::UintTy, usize_ty: ast::UintTy) -> u64 {
|
||||
match uint_ty {
|
||||
ast::UintTy::Us => uint_ty_bits(target_uint_ty, target_uint_ty),
|
||||
ast::UintTy::Us => uint_ty_bits(usize_ty, usize_ty),
|
||||
ast::UintTy::U8 => 8,
|
||||
ast::UintTy::U16 => 16,
|
||||
ast::UintTy::U32 => 32,
|
||||
|
@ -16,6 +16,7 @@ use schema::*;
|
||||
use rustc::hir::map::{DefKey, DefPath, DefPathData, DefPathHash};
|
||||
use rustc::hir;
|
||||
|
||||
use rustc::middle::const_val::ByteArray;
|
||||
use rustc::middle::cstore::LinkagePreference;
|
||||
use rustc::hir::def::{self, Def, CtorKind};
|
||||
use rustc::hir::def_id::{CrateNum, DefId, DefIndex, CRATE_DEF_INDEX, LOCAL_CRATE};
|
||||
@ -377,6 +378,20 @@ impl<'a, 'tcx> SpecializedDecoder<&'tcx ty::Slice<ty::ExistentialPredicate<'tcx>
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> SpecializedDecoder<ByteArray<'tcx>> for DecodeContext<'a, 'tcx> {
|
||||
fn specialized_decode(&mut self) -> Result<ByteArray<'tcx>, Self::Error> {
|
||||
Ok(ByteArray {
|
||||
data: self.tcx().alloc_byte_array(&Vec::decode(self)?)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> SpecializedDecoder<&'tcx ty::Const<'tcx>> for DecodeContext<'a, 'tcx> {
|
||||
fn specialized_decode(&mut self) -> Result<&'tcx ty::Const<'tcx>, Self::Error> {
|
||||
Ok(self.tcx().mk_const(Decodable::decode(self)?))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> MetadataBlob {
|
||||
pub fn is_compatible(&self) -> bool {
|
||||
self.raw_bytes().starts_with(METADATA_HEADER)
|
||||
|
@ -1520,9 +1520,16 @@ impl<'a, 'b, 'tcx> IndexBuilder<'a, 'b, 'tcx> {
|
||||
}
|
||||
|
||||
fn encode_info_for_ty(&mut self, ty: &hir::Ty) {
|
||||
if let hir::TyImplTrait(_) = ty.node {
|
||||
let def_id = self.tcx.hir.local_def_id(ty.id);
|
||||
self.record(def_id, IsolatedEncoder::encode_info_for_anon_ty, def_id);
|
||||
match ty.node {
|
||||
hir::TyImplTrait(_) => {
|
||||
let def_id = self.tcx.hir.local_def_id(ty.id);
|
||||
self.record(def_id, IsolatedEncoder::encode_info_for_anon_ty, def_id);
|
||||
}
|
||||
hir::TyArray(_, len) => {
|
||||
let def_id = self.tcx.hir.body_owner_def_id(len);
|
||||
self.record(def_id, IsolatedEncoder::encode_info_for_embedded_const, def_id);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -197,7 +197,10 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
||||
span: expr_span,
|
||||
ty: this.hir.tcx().types.u32,
|
||||
literal: Literal::Value {
|
||||
value: ConstVal::Integral(ConstInt::U32(0)),
|
||||
value: this.hir.tcx().mk_const(ty::Const {
|
||||
val: ConstVal::Integral(ConstInt::U32(0)),
|
||||
ty: this.hir.tcx().types.u32
|
||||
}),
|
||||
},
|
||||
}));
|
||||
box AggregateKind::Generator(closure_id, substs, interior)
|
||||
@ -385,13 +388,18 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
||||
ast::IntTy::I64 => ConstInt::I64(-1),
|
||||
ast::IntTy::I128 => ConstInt::I128(-1),
|
||||
ast::IntTy::Is => {
|
||||
let int_ty = self.hir.tcx().sess.target.int_type;
|
||||
let int_ty = self.hir.tcx().sess.target.isize_ty;
|
||||
let val = ConstIsize::new(-1, int_ty).unwrap();
|
||||
ConstInt::Isize(val)
|
||||
}
|
||||
};
|
||||
|
||||
Literal::Value { value: ConstVal::Integral(val) }
|
||||
Literal::Value {
|
||||
value: self.hir.tcx().mk_const(ty::Const {
|
||||
val: ConstVal::Integral(val),
|
||||
ty
|
||||
})
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
span_bug!(span, "Invalid type for neg_1_literal: `{:?}`", ty)
|
||||
@ -412,7 +420,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
||||
ast::IntTy::I64 => ConstInt::I64(i64::min_value()),
|
||||
ast::IntTy::I128 => ConstInt::I128(i128::min_value()),
|
||||
ast::IntTy::Is => {
|
||||
let int_ty = self.hir.tcx().sess.target.int_type;
|
||||
let int_ty = self.hir.tcx().sess.target.isize_ty;
|
||||
let min = match int_ty {
|
||||
ast::IntTy::I16 => std::i16::MIN as i64,
|
||||
ast::IntTy::I32 => std::i32::MIN as i64,
|
||||
@ -424,7 +432,12 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
||||
}
|
||||
};
|
||||
|
||||
Literal::Value { value: ConstVal::Integral(val) }
|
||||
Literal::Value {
|
||||
value: self.hir.tcx().mk_const(ty::Const {
|
||||
val: ConstVal::Integral(val),
|
||||
ty
|
||||
})
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
span_bug!(span, "Invalid type for minval_literal: `{:?}`", ty)
|
||||
|
@ -16,8 +16,7 @@
|
||||
use build::{BlockAnd, BlockAndExtension, Builder};
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_data_structures::bitvec::BitVector;
|
||||
use rustc::middle::const_val::ConstVal;
|
||||
use rustc::ty::{AdtDef, Ty};
|
||||
use rustc::ty::{self, Ty};
|
||||
use rustc::mir::*;
|
||||
use rustc::hir;
|
||||
use hair::*;
|
||||
@ -294,20 +293,20 @@ pub struct MatchPair<'pat, 'tcx:'pat> {
|
||||
enum TestKind<'tcx> {
|
||||
// test the branches of enum
|
||||
Switch {
|
||||
adt_def: &'tcx AdtDef,
|
||||
adt_def: &'tcx ty::AdtDef,
|
||||
variants: BitVector,
|
||||
},
|
||||
|
||||
// test the branches of enum
|
||||
SwitchInt {
|
||||
switch_ty: Ty<'tcx>,
|
||||
options: Vec<ConstVal<'tcx>>,
|
||||
indices: FxHashMap<ConstVal<'tcx>, usize>,
|
||||
options: Vec<&'tcx ty::Const<'tcx>>,
|
||||
indices: FxHashMap<&'tcx ty::Const<'tcx>, usize>,
|
||||
},
|
||||
|
||||
// test for equality
|
||||
Eq {
|
||||
value: ConstVal<'tcx>,
|
||||
value: &'tcx ty::Const<'tcx>,
|
||||
ty: Ty<'tcx>,
|
||||
},
|
||||
|
||||
|
@ -61,24 +61,24 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
PatternKind::Constant { ref value } => {
|
||||
PatternKind::Constant { value } => {
|
||||
Test {
|
||||
span: match_pair.pattern.span,
|
||||
kind: TestKind::Eq {
|
||||
value: value.clone(),
|
||||
value,
|
||||
ty: match_pair.pattern.ty.clone()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PatternKind::Range { ref lo, ref hi, ref end } => {
|
||||
PatternKind::Range { lo, hi, end } => {
|
||||
Test {
|
||||
span: match_pair.pattern.span,
|
||||
kind: TestKind::Range {
|
||||
lo: Literal::Value { value: lo.clone() },
|
||||
hi: Literal::Value { value: hi.clone() },
|
||||
lo: Literal::Value { value: lo },
|
||||
hi: Literal::Value { value: hi },
|
||||
ty: match_pair.pattern.ty.clone(),
|
||||
end: end.clone(),
|
||||
end,
|
||||
},
|
||||
}
|
||||
}
|
||||
@ -112,8 +112,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
||||
test_lvalue: &Lvalue<'tcx>,
|
||||
candidate: &Candidate<'pat, 'tcx>,
|
||||
switch_ty: Ty<'tcx>,
|
||||
options: &mut Vec<ConstVal<'tcx>>,
|
||||
indices: &mut FxHashMap<ConstVal<'tcx>, usize>)
|
||||
options: &mut Vec<&'tcx ty::Const<'tcx>>,
|
||||
indices: &mut FxHashMap<&'tcx ty::Const<'tcx>, usize>)
|
||||
-> bool
|
||||
{
|
||||
let match_pair = match candidate.match_pairs.iter().find(|mp| mp.lvalue == *test_lvalue) {
|
||||
@ -122,13 +122,13 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
||||
};
|
||||
|
||||
match *match_pair.pattern.kind {
|
||||
PatternKind::Constant { ref value } => {
|
||||
PatternKind::Constant { value } => {
|
||||
// if the lvalues match, the type should match
|
||||
assert_eq!(match_pair.pattern.ty, switch_ty);
|
||||
|
||||
indices.entry(value.clone())
|
||||
indices.entry(value)
|
||||
.or_insert_with(|| {
|
||||
options.push(value.clone());
|
||||
options.push(value);
|
||||
options.len() - 1
|
||||
});
|
||||
true
|
||||
@ -228,9 +228,9 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
||||
assert!(options.len() > 0 && options.len() <= 2);
|
||||
let (true_bb, false_bb) = (self.cfg.start_new_block(),
|
||||
self.cfg.start_new_block());
|
||||
let ret = match &options[0] {
|
||||
&ConstVal::Bool(true) => vec![true_bb, false_bb],
|
||||
&ConstVal::Bool(false) => vec![false_bb, true_bb],
|
||||
let ret = match options[0].val {
|
||||
ConstVal::Bool(true) => vec![true_bb, false_bb],
|
||||
ConstVal::Bool(false) => vec![false_bb, true_bb],
|
||||
v => span_bug!(test.span, "expected boolean value but got {:?}", v)
|
||||
};
|
||||
(ret, TerminatorKind::if_(self.hir.tcx(), Operand::Consume(lvalue.clone()),
|
||||
@ -245,7 +245,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
||||
.chain(Some(otherwise))
|
||||
.collect();
|
||||
let values: Vec<_> = options.iter().map(|v|
|
||||
v.to_const_int().expect("switching on integral")
|
||||
v.val.to_const_int().expect("switching on integral")
|
||||
).collect();
|
||||
(targets.clone(), TerminatorKind::SwitchInt {
|
||||
discr: Operand::Consume(lvalue.clone()),
|
||||
@ -258,12 +258,12 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
||||
ret
|
||||
}
|
||||
|
||||
TestKind::Eq { ref value, mut ty } => {
|
||||
TestKind::Eq { value, mut ty } => {
|
||||
let mut val = Operand::Consume(lvalue.clone());
|
||||
|
||||
// If we're using b"..." as a pattern, we need to insert an
|
||||
// unsizing coercion, as the byte string has the type &[u8; N].
|
||||
let expect = if let ConstVal::ByteStr(ref bytes) = *value {
|
||||
let expect = if let ConstVal::ByteStr(bytes) = value.val {
|
||||
let tcx = self.hir.tcx();
|
||||
|
||||
// Unsize the lvalue to &[u8], too, if necessary.
|
||||
@ -279,10 +279,10 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
||||
|
||||
assert!(ty.is_slice());
|
||||
|
||||
let array_ty = tcx.mk_array(tcx.types.u8, bytes.len());
|
||||
let array_ty = tcx.mk_array(tcx.types.u8, bytes.data.len() as u64);
|
||||
let array_ref = tcx.mk_imm_ref(tcx.types.re_static, array_ty);
|
||||
let array = self.literal_operand(test.span, array_ref, Literal::Value {
|
||||
value: value.clone()
|
||||
value
|
||||
});
|
||||
|
||||
let slice = self.temp(ty, test.span);
|
||||
@ -291,7 +291,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
||||
Operand::Consume(slice)
|
||||
} else {
|
||||
self.literal_operand(test.span, ty, Literal::Value {
|
||||
value: value.clone()
|
||||
value
|
||||
})
|
||||
};
|
||||
|
||||
|
@ -59,7 +59,14 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
||||
ty::TyBool => {
|
||||
self.hir.false_literal()
|
||||
}
|
||||
ty::TyChar => Literal::Value { value: ConstVal::Char('\0') },
|
||||
ty::TyChar => {
|
||||
Literal::Value {
|
||||
value: self.hir.tcx().mk_const(ty::Const {
|
||||
val: ConstVal::Char('\0'),
|
||||
ty
|
||||
})
|
||||
}
|
||||
}
|
||||
ty::TyUint(ity) => {
|
||||
let val = match ity {
|
||||
ast::UintTy::U8 => ConstInt::U8(0),
|
||||
@ -68,13 +75,18 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
||||
ast::UintTy::U64 => ConstInt::U64(0),
|
||||
ast::UintTy::U128 => ConstInt::U128(0),
|
||||
ast::UintTy::Us => {
|
||||
let uint_ty = self.hir.tcx().sess.target.uint_type;
|
||||
let uint_ty = self.hir.tcx().sess.target.usize_ty;
|
||||
let val = ConstUsize::new(0, uint_ty).unwrap();
|
||||
ConstInt::Usize(val)
|
||||
}
|
||||
};
|
||||
|
||||
Literal::Value { value: ConstVal::Integral(val) }
|
||||
Literal::Value {
|
||||
value: self.hir.tcx().mk_const(ty::Const {
|
||||
val: ConstVal::Integral(val),
|
||||
ty
|
||||
})
|
||||
}
|
||||
}
|
||||
ty::TyInt(ity) => {
|
||||
let val = match ity {
|
||||
@ -84,13 +96,18 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
||||
ast::IntTy::I64 => ConstInt::I64(0),
|
||||
ast::IntTy::I128 => ConstInt::I128(0),
|
||||
ast::IntTy::Is => {
|
||||
let int_ty = self.hir.tcx().sess.target.int_type;
|
||||
let int_ty = self.hir.tcx().sess.target.isize_ty;
|
||||
let val = ConstIsize::new(0, int_ty).unwrap();
|
||||
ConstInt::Isize(val)
|
||||
}
|
||||
};
|
||||
|
||||
Literal::Value { value: ConstVal::Integral(val) }
|
||||
Literal::Value {
|
||||
value: self.hir.tcx().mk_const(ty::Const {
|
||||
val: ConstVal::Integral(val),
|
||||
ty
|
||||
})
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
span_bug!(span, "Invalid type for zero_literal: `{:?}`", ty)
|
||||
|
@ -11,7 +11,6 @@
|
||||
|
||||
use build;
|
||||
use hair::cx::Cx;
|
||||
use hair::Pattern;
|
||||
use rustc::hir;
|
||||
use rustc::hir::def_id::DefId;
|
||||
use rustc::middle::region;
|
||||
@ -167,6 +166,26 @@ impl<'a, 'gcx: 'tcx, 'tcx> MutVisitor<'tcx> for GlobalizeMir<'a, 'gcx> {
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_region(&mut self, region: &mut ty::Region<'tcx>, _: Location) {
|
||||
if let Some(lifted) = self.tcx.lift(region) {
|
||||
*region = lifted;
|
||||
} else {
|
||||
span_bug!(self.span,
|
||||
"found region `{:?}` with inference types/regions in MIR",
|
||||
region);
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_const(&mut self, constant: &mut &'tcx ty::Const<'tcx>, _: Location) {
|
||||
if let Some(lifted) = self.tcx.lift(constant) {
|
||||
*constant = lifted;
|
||||
} else {
|
||||
span_bug!(self.span,
|
||||
"found constant `{:?}` with inference types/regions in MIR",
|
||||
constant);
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_substs(&mut self, substs: &mut &'tcx Substs<'tcx>, _: Location) {
|
||||
if let Some(lifted) = self.tcx.lift(substs) {
|
||||
*substs = lifted;
|
||||
@ -537,10 +556,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
||||
let lvalue = Lvalue::Local(Local::new(index + 1));
|
||||
|
||||
if let Some(pattern) = pattern {
|
||||
let pattern = Pattern::from_hir(self.hir.tcx().global_tcx(),
|
||||
self.hir.param_env.and(self.hir.identity_substs),
|
||||
self.hir.tables(),
|
||||
pattern);
|
||||
let pattern = self.hir.pattern_from_hir(pattern);
|
||||
scope = self.declare_bindings(scope, ast_body.span, &pattern);
|
||||
unpack!(block = self.lvalue_into_pattern(block, pattern, &lvalue));
|
||||
}
|
||||
|
@ -64,10 +64,7 @@ fn mirror_stmts<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
|
||||
first_statement_index: index as u32,
|
||||
});
|
||||
|
||||
let pattern = Pattern::from_hir(cx.tcx.global_tcx(),
|
||||
cx.param_env.and(cx.identity_substs),
|
||||
cx.tables(),
|
||||
&local.pat);
|
||||
let pattern = cx.pattern_from_hir(&local.pat);
|
||||
result.push(StmtRef::Mirror(Box::new(Stmt {
|
||||
kind: StmtKind::Let {
|
||||
remainder_scope: remainder_scope,
|
||||
|
@ -473,7 +473,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
|
||||
let def_id = cx.tcx.hir.body_owner_def_id(count);
|
||||
let substs = Substs::identity_for_item(cx.tcx.global_tcx(), def_id);
|
||||
let count = match cx.tcx.at(c.span).const_eval(cx.param_env.and((def_id, substs))) {
|
||||
Ok(ConstVal::Integral(ConstInt::Usize(u))) => u,
|
||||
Ok(&ty::Const { val: ConstVal::Integral(ConstInt::Usize(u)), .. }) => u,
|
||||
Ok(other) => bug!("constant evaluation of repeat count yielded {:?}", other),
|
||||
Err(s) => cx.fatal_const_eval_err(&s, c.span, "expression")
|
||||
};
|
||||
@ -591,13 +591,17 @@ fn method_callee<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
|
||||
(cx.tables().type_dependent_defs()[expr.hir_id].def_id(),
|
||||
cx.tables().node_substs(expr.hir_id))
|
||||
});
|
||||
let ty = cx.tcx().mk_fn_def(def_id, substs);
|
||||
Expr {
|
||||
temp_lifetime,
|
||||
ty: cx.tcx().mk_fn_def(def_id, substs),
|
||||
ty,
|
||||
span: expr.span,
|
||||
kind: ExprKind::Literal {
|
||||
literal: Literal::Value {
|
||||
value: ConstVal::Function(def_id, substs),
|
||||
value: cx.tcx.mk_const(ty::Const {
|
||||
val: ConstVal::Function(def_id, substs),
|
||||
ty
|
||||
}),
|
||||
},
|
||||
},
|
||||
}
|
||||
@ -612,12 +616,7 @@ fn to_borrow_kind(m: hir::Mutability) -> BorrowKind {
|
||||
|
||||
fn convert_arm<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, arm: &'tcx hir::Arm) -> Arm<'tcx> {
|
||||
Arm {
|
||||
patterns: arm.pats.iter().map(|p| {
|
||||
Pattern::from_hir(cx.tcx.global_tcx(),
|
||||
cx.param_env.and(cx.identity_substs),
|
||||
cx.tables(),
|
||||
p)
|
||||
}).collect(),
|
||||
patterns: arm.pats.iter().map(|p| cx.pattern_from_hir(p)).collect(),
|
||||
guard: arm.guard.to_ref(),
|
||||
body: arm.body.to_ref(),
|
||||
}
|
||||
@ -635,15 +634,20 @@ fn convert_path_expr<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
|
||||
Def::StructCtor(def_id, CtorKind::Fn) |
|
||||
Def::VariantCtor(def_id, CtorKind::Fn) => ExprKind::Literal {
|
||||
literal: Literal::Value {
|
||||
value: ConstVal::Function(def_id, substs),
|
||||
value: cx.tcx.mk_const(ty::Const {
|
||||
val: ConstVal::Function(def_id, substs),
|
||||
ty: cx.tables().node_id_to_type(expr.hir_id)
|
||||
}),
|
||||
},
|
||||
},
|
||||
|
||||
Def::Const(def_id) |
|
||||
Def::AssociatedConst(def_id) => ExprKind::Literal {
|
||||
literal: Literal::Item {
|
||||
def_id,
|
||||
substs,
|
||||
literal: Literal::Value {
|
||||
value: cx.tcx.mk_const(ty::Const {
|
||||
val: ConstVal::Unevaluated(def_id, substs),
|
||||
ty: cx.tables().node_id_to_type(expr.hir_id)
|
||||
}),
|
||||
},
|
||||
},
|
||||
|
||||
|
@ -112,8 +112,15 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> {
|
||||
}
|
||||
|
||||
pub fn usize_literal(&mut self, value: u64) -> Literal<'tcx> {
|
||||
match ConstUsize::new(value, self.tcx.sess.target.uint_type) {
|
||||
Ok(val) => Literal::Value { value: ConstVal::Integral(ConstInt::Usize(val)) },
|
||||
match ConstUsize::new(value, self.tcx.sess.target.usize_ty) {
|
||||
Ok(val) => {
|
||||
Literal::Value {
|
||||
value: self.tcx.mk_const(ty::Const {
|
||||
val: ConstVal::Integral(ConstInt::Usize(val)),
|
||||
ty: self.tcx.types.usize
|
||||
})
|
||||
}
|
||||
}
|
||||
Err(_) => bug!("usize literal out of range for target"),
|
||||
}
|
||||
}
|
||||
@ -127,11 +134,21 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> {
|
||||
}
|
||||
|
||||
pub fn true_literal(&mut self) -> Literal<'tcx> {
|
||||
Literal::Value { value: ConstVal::Bool(true) }
|
||||
Literal::Value {
|
||||
value: self.tcx.mk_const(ty::Const {
|
||||
val: ConstVal::Bool(true),
|
||||
ty: self.tcx.types.bool
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub fn false_literal(&mut self) -> Literal<'tcx> {
|
||||
Literal::Value { value: ConstVal::Bool(false) }
|
||||
Literal::Value {
|
||||
value: self.tcx.mk_const(ty::Const {
|
||||
val: ConstVal::Bool(false),
|
||||
ty: self.tcx.types.bool
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub fn const_eval_literal(&mut self, e: &hir::Expr) -> Literal<'tcx> {
|
||||
@ -139,12 +156,24 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> {
|
||||
let const_cx = ConstContext::new(tcx,
|
||||
self.param_env.and(self.identity_substs),
|
||||
self.tables());
|
||||
match const_cx.eval(e) {
|
||||
Ok(value) => Literal::Value { value: value },
|
||||
match const_cx.eval(tcx.hir.expect_expr(e.id)) {
|
||||
Ok(value) => Literal::Value { value },
|
||||
Err(s) => self.fatal_const_eval_err(&s, e.span, "expression")
|
||||
}
|
||||
}
|
||||
|
||||
pub fn pattern_from_hir(&mut self, p: &hir::Pat) -> Pattern<'tcx> {
|
||||
let tcx = self.tcx.global_tcx();
|
||||
let p = match tcx.hir.get(p.id) {
|
||||
hir::map::NodePat(p) | hir::map::NodeBinding(p) => p,
|
||||
node => bug!("pattern became {:?}", node)
|
||||
};
|
||||
Pattern::from_hir(tcx,
|
||||
self.param_env.and(self.identity_substs),
|
||||
self.tables(),
|
||||
p)
|
||||
}
|
||||
|
||||
pub fn fatal_const_eval_err(&mut self,
|
||||
err: &ConstEvalErr<'tcx>,
|
||||
primary_span: Span,
|
||||
@ -170,7 +199,10 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> {
|
||||
let method_ty = method_ty.subst(self.tcx, substs);
|
||||
return (method_ty,
|
||||
Literal::Value {
|
||||
value: ConstVal::Function(item.def_id, substs),
|
||||
value: self.tcx.mk_const(ty::Const {
|
||||
val: ConstVal::Function(item.def_id, substs),
|
||||
ty: method_ty
|
||||
}),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -292,7 +292,10 @@ fn build_clone_shim<'a, 'tcx>(tcx: ty::TyCtxt<'a, 'tcx, 'tcx>,
|
||||
|
||||
match self_ty.sty {
|
||||
_ if is_copy => builder.copy_shim(),
|
||||
ty::TyArray(ty, len) => builder.array_shim(ty, len),
|
||||
ty::TyArray(ty, len) => {
|
||||
let len = len.val.to_const_int().unwrap().to_u64().unwrap();
|
||||
builder.array_shim(ty, len)
|
||||
}
|
||||
ty::TyTuple(tys, _) => builder.tuple_shim(tys),
|
||||
_ => {
|
||||
bug!("clone shim for `{:?}` which is not `Copy` and is not an aggregate", self_ty);
|
||||
@ -403,11 +406,15 @@ impl<'a, 'tcx> CloneShimBuilder<'a, 'tcx> {
|
||||
);
|
||||
|
||||
// `func == Clone::clone(&ty) -> ty`
|
||||
let func_ty = tcx.mk_fn_def(self.def_id, substs);
|
||||
let func = Operand::Constant(box Constant {
|
||||
span: self.span,
|
||||
ty: tcx.mk_fn_def(self.def_id, substs),
|
||||
ty: func_ty,
|
||||
literal: Literal::Value {
|
||||
value: ConstVal::Function(self.def_id, substs),
|
||||
value: tcx.mk_const(ty::Const {
|
||||
val: ConstVal::Function(self.def_id, substs),
|
||||
ty: func_ty
|
||||
}),
|
||||
},
|
||||
});
|
||||
|
||||
@ -466,18 +473,21 @@ impl<'a, 'tcx> CloneShimBuilder<'a, 'tcx> {
|
||||
);
|
||||
}
|
||||
|
||||
fn make_usize(&self, value: usize) -> Box<Constant<'tcx>> {
|
||||
let value = ConstUsize::new(value as u64, self.tcx.sess.target.uint_type).unwrap();
|
||||
fn make_usize(&self, value: u64) -> Box<Constant<'tcx>> {
|
||||
let value = ConstUsize::new(value, self.tcx.sess.target.usize_ty).unwrap();
|
||||
box Constant {
|
||||
span: self.span,
|
||||
ty: self.tcx.types.usize,
|
||||
literal: Literal::Value {
|
||||
value: ConstVal::Integral(ConstInt::Usize(value))
|
||||
value: self.tcx.mk_const(ty::Const {
|
||||
val: ConstVal::Integral(ConstInt::Usize(value)),
|
||||
ty: self.tcx.types.usize,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn array_shim(&mut self, ty: ty::Ty<'tcx>, len: usize) {
|
||||
fn array_shim(&mut self, ty: ty::Ty<'tcx>, len: u64) {
|
||||
let tcx = self.tcx;
|
||||
let span = self.span;
|
||||
let rcvr = Lvalue::Local(Local::new(1+0)).deref();
|
||||
@ -706,17 +716,21 @@ fn build_call_shim<'a, 'tcx>(tcx: ty::TyCtxt<'a, 'tcx, 'tcx>,
|
||||
|
||||
let (callee, mut args) = match call_kind {
|
||||
CallKind::Indirect => (rcvr, vec![]),
|
||||
CallKind::Direct(def_id) => (
|
||||
Operand::Constant(box Constant {
|
||||
CallKind::Direct(def_id) => {
|
||||
let ty = tcx.type_of(def_id);
|
||||
(Operand::Constant(box Constant {
|
||||
span,
|
||||
ty: tcx.type_of(def_id),
|
||||
ty,
|
||||
literal: Literal::Value {
|
||||
value: ConstVal::Function(def_id,
|
||||
Substs::identity_for_item(tcx, def_id)),
|
||||
value: tcx.mk_const(ty::Const {
|
||||
val: ConstVal::Function(def_id,
|
||||
Substs::identity_for_item(tcx, def_id)),
|
||||
ty
|
||||
}),
|
||||
},
|
||||
}),
|
||||
vec![rcvr]
|
||||
)
|
||||
}),
|
||||
vec![rcvr])
|
||||
}
|
||||
};
|
||||
|
||||
if let Some(untuple_args) = untuple_args {
|
||||
|
@ -520,7 +520,12 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> {
|
||||
Rvalue::Use(Operand::Constant(Box::new(Constant {
|
||||
span,
|
||||
ty: self.tcx.types.bool,
|
||||
literal: Literal::Value { value: ConstVal::Bool(val) }
|
||||
literal: Literal::Value {
|
||||
value: self.tcx.mk_const(ty::Const {
|
||||
val: ConstVal::Bool(val),
|
||||
ty: self.tcx.types.bool
|
||||
})
|
||||
}
|
||||
})))
|
||||
}
|
||||
|
||||
|
@ -15,7 +15,7 @@
|
||||
//! "types-as-contracts"-validation, namely, AcquireValid, ReleaseValid, and EndRegion.
|
||||
|
||||
use rustc::ty::subst::Substs;
|
||||
use rustc::ty::{Ty, TyCtxt, ClosureSubsts};
|
||||
use rustc::ty::{self, Ty, TyCtxt};
|
||||
use rustc::mir::*;
|
||||
use rustc::mir::visit::{MutVisitor, Lookup};
|
||||
use rustc::mir::transform::{MirPass, MirSource};
|
||||
@ -37,38 +37,25 @@ impl<'a, 'tcx> EraseRegionsVisitor<'a, 'tcx> {
|
||||
impl<'a, 'tcx> MutVisitor<'tcx> for EraseRegionsVisitor<'a, 'tcx> {
|
||||
fn visit_ty(&mut self, ty: &mut Ty<'tcx>, _: Lookup) {
|
||||
if !self.in_validation_statement {
|
||||
*ty = self.tcx.erase_regions(&{*ty});
|
||||
*ty = self.tcx.erase_regions(ty);
|
||||
}
|
||||
self.super_ty(ty);
|
||||
}
|
||||
|
||||
fn visit_substs(&mut self, substs: &mut &'tcx Substs<'tcx>, _: Location) {
|
||||
*substs = self.tcx.erase_regions(&{*substs});
|
||||
fn visit_region(&mut self, region: &mut ty::Region<'tcx>, _: Location) {
|
||||
*region = self.tcx.types.re_erased;
|
||||
}
|
||||
|
||||
fn visit_rvalue(&mut self, rvalue: &mut Rvalue<'tcx>, location: Location) {
|
||||
match *rvalue {
|
||||
Rvalue::Ref(ref mut r, _, _) => {
|
||||
*r = self.tcx.types.re_erased;
|
||||
}
|
||||
Rvalue::Use(..) |
|
||||
Rvalue::Repeat(..) |
|
||||
Rvalue::Len(..) |
|
||||
Rvalue::Cast(..) |
|
||||
Rvalue::BinaryOp(..) |
|
||||
Rvalue::CheckedBinaryOp(..) |
|
||||
Rvalue::UnaryOp(..) |
|
||||
Rvalue::Discriminant(..) |
|
||||
Rvalue::NullaryOp(..) |
|
||||
Rvalue::Aggregate(..) => {
|
||||
// These variants don't contain regions.
|
||||
}
|
||||
}
|
||||
self.super_rvalue(rvalue, location);
|
||||
fn visit_const(&mut self, constant: &mut &'tcx ty::Const<'tcx>, _: Location) {
|
||||
*constant = self.tcx.erase_regions(constant);
|
||||
}
|
||||
|
||||
fn visit_substs(&mut self, substs: &mut &'tcx Substs<'tcx>, _: Location) {
|
||||
*substs = self.tcx.erase_regions(substs);
|
||||
}
|
||||
|
||||
fn visit_closure_substs(&mut self,
|
||||
substs: &mut ClosureSubsts<'tcx>,
|
||||
substs: &mut ty::ClosureSubsts<'tcx>,
|
||||
_: Location) {
|
||||
*substs = self.tcx.erase_regions(substs);
|
||||
}
|
||||
|
@ -175,7 +175,10 @@ impl<'a, 'tcx> TransformVisitor<'a, 'tcx> {
|
||||
span: source_info.span,
|
||||
ty: self.tcx.types.u32,
|
||||
literal: Literal::Value {
|
||||
value: ConstVal::Integral(ConstInt::U32(state_disc)),
|
||||
value: self.tcx.mk_const(ty::Const {
|
||||
val: ConstVal::Integral(ConstInt::U32(state_disc)),
|
||||
ty: self.tcx.types.u32
|
||||
}),
|
||||
},
|
||||
});
|
||||
Statement {
|
||||
@ -553,7 +556,10 @@ fn insert_panic_on_resume_after_return<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
span: mir.span,
|
||||
ty: tcx.types.bool,
|
||||
literal: Literal::Value {
|
||||
value: ConstVal::Bool(false),
|
||||
value: tcx.mk_const(ty::Const {
|
||||
val: ConstVal::Bool(false),
|
||||
ty: tcx.types.bool
|
||||
}),
|
||||
},
|
||||
}),
|
||||
expected: true,
|
||||
@ -603,7 +609,10 @@ fn create_generator_resume_function<'a, 'tcx>(
|
||||
span: mir.span,
|
||||
ty: tcx.types.bool,
|
||||
literal: Literal::Value {
|
||||
value: ConstVal::Bool(false),
|
||||
value: tcx.mk_const(ty::Const {
|
||||
val: ConstVal::Bool(false),
|
||||
ty: tcx.types.bool
|
||||
}),
|
||||
},
|
||||
}),
|
||||
expected: true,
|
||||
|
@ -20,6 +20,7 @@ use rustc_data_structures::indexed_vec::{IndexVec, Idx};
|
||||
use rustc::hir;
|
||||
use rustc::hir::map as hir_map;
|
||||
use rustc::hir::def_id::DefId;
|
||||
use rustc::middle::const_val::ConstVal;
|
||||
use rustc::traits::{self, Reveal};
|
||||
use rustc::ty::{self, TyCtxt, Ty, TypeFoldable};
|
||||
use rustc::ty::cast::CastTy;
|
||||
@ -622,10 +623,12 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
|
||||
}
|
||||
}
|
||||
Operand::Constant(ref constant) => {
|
||||
if let Literal::Item { def_id, substs: _ } = constant.literal {
|
||||
if let Literal::Value {
|
||||
value: &ty::Const { val: ConstVal::Unevaluated(def_id, _), ty }
|
||||
} = constant.literal {
|
||||
// Don't peek inside trait associated constants.
|
||||
if self.tcx.trait_of_item(def_id).is_some() {
|
||||
self.add_type(constant.ty);
|
||||
self.add_type(ty);
|
||||
} else {
|
||||
let (bits, _) = self.tcx.at(constant.span).mir_const_qualif(def_id);
|
||||
|
||||
@ -635,7 +638,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
|
||||
// Just in case the type is more specific than
|
||||
// the definition, e.g. impl associated const
|
||||
// with type parameters, take it into account.
|
||||
self.qualif.restrict(constant.ty, self.tcx, self.param_env);
|
||||
self.qualif.restrict(ty, self.tcx, self.param_env);
|
||||
}
|
||||
|
||||
// Let `const fn` transitively have destructors,
|
||||
@ -695,8 +698,9 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
|
||||
}
|
||||
_ => false
|
||||
}
|
||||
} else if let ty::TyArray(_, 0) = ty.sty {
|
||||
self.mode == Mode::Fn
|
||||
} else if let ty::TyArray(_, len) = ty.sty {
|
||||
len.val.to_const_int().unwrap().to_u64().unwrap() == 0 &&
|
||||
self.mode == Mode::Fn
|
||||
} else {
|
||||
false
|
||||
};
|
||||
|
@ -10,7 +10,7 @@
|
||||
|
||||
//! A pass that simplifies branches when their condition is known.
|
||||
|
||||
use rustc::ty::TyCtxt;
|
||||
use rustc::ty::{self, TyCtxt};
|
||||
use rustc::middle::const_val::ConstVal;
|
||||
use rustc::mir::transform::{MirPass, MirSource};
|
||||
use rustc::mir::*;
|
||||
@ -40,7 +40,7 @@ impl MirPass for SimplifyBranches {
|
||||
TerminatorKind::SwitchInt { discr: Operand::Constant(box Constant {
|
||||
literal: Literal::Value { ref value }, ..
|
||||
}), ref values, ref targets, .. } => {
|
||||
if let Some(ref constint) = value.to_const_int() {
|
||||
if let Some(ref constint) = value.val.to_const_int() {
|
||||
let (otherwise, targets) = targets.split_last().unwrap();
|
||||
let mut ret = TerminatorKind::Goto { target: *otherwise };
|
||||
for (v, t) in values.iter().zip(targets.iter()) {
|
||||
@ -56,7 +56,7 @@ impl MirPass for SimplifyBranches {
|
||||
},
|
||||
TerminatorKind::Assert { target, cond: Operand::Constant(box Constant {
|
||||
literal: Literal::Value {
|
||||
value: ConstVal::Bool(cond)
|
||||
value: &ty::Const { val: ConstVal::Bool(cond), .. }
|
||||
}, ..
|
||||
}), expected, .. } if cond == expected => {
|
||||
TerminatorKind::Goto { target: target }
|
||||
|
@ -209,7 +209,8 @@ impl<'a, 'b, 'gcx, 'tcx> TypeVerifier<'a, 'b, 'gcx, 'tcx> {
|
||||
LvalueTy::Ty {
|
||||
ty: match base_ty.sty {
|
||||
ty::TyArray(inner, size) => {
|
||||
let min_size = (from as usize) + (to as usize);
|
||||
let size = size.val.to_const_int().unwrap().to_u64().unwrap();
|
||||
let min_size = (from as u64) + (to as u64);
|
||||
if let Some(rest_size) = size.checked_sub(min_size) {
|
||||
tcx.mk_array(inner, rest_size)
|
||||
} else {
|
||||
@ -572,7 +573,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
|
||||
match operand {
|
||||
&Operand::Constant(box Constant {
|
||||
literal: Literal::Value {
|
||||
value: ConstVal::Function(def_id, _), ..
|
||||
value: &ty::Const { val: ConstVal::Function(def_id, _), .. }, ..
|
||||
}, ..
|
||||
}) => {
|
||||
Some(def_id) == self.tcx().lang_items().box_free_fn()
|
||||
|
@ -922,7 +922,12 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D>
|
||||
Operand::Constant(box Constant {
|
||||
span: self.source_info.span,
|
||||
ty: self.tcx().types.usize,
|
||||
literal: Literal::Value { value: ConstVal::Integral(self.tcx().const_usize(val)) }
|
||||
literal: Literal::Value {
|
||||
value: self.tcx().mk_const(ty::Const {
|
||||
val: ConstVal::Integral(self.tcx().const_usize(val)),
|
||||
ty: self.tcx().types.usize
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -13,7 +13,6 @@
|
||||
// completely accurate (some things might be counted twice, others missed).
|
||||
|
||||
use rustc_const_math::{ConstUsize};
|
||||
use rustc::middle::const_val::{ConstVal};
|
||||
use rustc::mir::{AggregateKind, AssertMessage, BasicBlock, BasicBlockData};
|
||||
use rustc::mir::{Constant, Literal, Location, LocalDecl};
|
||||
use rustc::mir::{Lvalue, LvalueElem, LvalueProjection};
|
||||
@ -21,7 +20,7 @@ use rustc::mir::{Mir, Operand, ProjectionElem};
|
||||
use rustc::mir::{Rvalue, SourceInfo, Statement, StatementKind};
|
||||
use rustc::mir::{Terminator, TerminatorKind, VisibilityScope, VisibilityScopeData};
|
||||
use rustc::mir::visit as mir_visit;
|
||||
use rustc::ty::{ClosureSubsts, TyCtxt};
|
||||
use rustc::ty::{self, ClosureSubsts, TyCtxt};
|
||||
use rustc::util::nodemap::{FxHashMap};
|
||||
|
||||
struct NodeData {
|
||||
@ -236,7 +235,6 @@ impl<'a, 'tcx> mir_visit::Visitor<'tcx> for StatCollector<'a, 'tcx> {
|
||||
location: Location) {
|
||||
self.record("Literal", literal);
|
||||
self.record(match *literal {
|
||||
Literal::Item { .. } => "Literal::Item",
|
||||
Literal::Value { .. } => "Literal::Value",
|
||||
Literal::Promoted { .. } => "Literal::Promoted",
|
||||
}, literal);
|
||||
@ -256,11 +254,11 @@ impl<'a, 'tcx> mir_visit::Visitor<'tcx> for StatCollector<'a, 'tcx> {
|
||||
self.super_closure_substs(substs);
|
||||
}
|
||||
|
||||
fn visit_const_val(&mut self,
|
||||
const_val: &ConstVal,
|
||||
_: Location) {
|
||||
self.record("ConstVal", const_val);
|
||||
self.super_const_val(const_val);
|
||||
fn visit_const(&mut self,
|
||||
constant: &&'tcx ty::Const<'tcx>,
|
||||
_: Location) {
|
||||
self.record("Const", constant);
|
||||
self.super_const(constant);
|
||||
}
|
||||
|
||||
fn visit_const_usize(&mut self,
|
||||
|
@ -11,7 +11,7 @@
|
||||
use llvm::{self, ValueRef, AttributePlace};
|
||||
use base;
|
||||
use builder::Builder;
|
||||
use common::{instance_ty, ty_fn_sig, type_is_fat_ptr, C_uint};
|
||||
use common::{instance_ty, ty_fn_sig, type_is_fat_ptr, C_usize};
|
||||
use context::CrateContext;
|
||||
use cabi_x86;
|
||||
use cabi_x86_64;
|
||||
@ -527,7 +527,7 @@ impl<'a, 'tcx> ArgType<'tcx> {
|
||||
}
|
||||
let ccx = bcx.ccx;
|
||||
if self.is_indirect() {
|
||||
let llsz = C_uint(ccx, self.layout.size(ccx).bytes());
|
||||
let llsz = C_usize(ccx, self.layout.size(ccx).bytes());
|
||||
let llalign = self.layout.align(ccx).abi();
|
||||
base::call_memcpy(bcx, dst, val, llsz, llalign as u32);
|
||||
} else if let Some(ty) = self.cast {
|
||||
@ -564,7 +564,7 @@ impl<'a, 'tcx> ArgType<'tcx> {
|
||||
base::call_memcpy(bcx,
|
||||
bcx.pointercast(dst, Type::i8p(ccx)),
|
||||
bcx.pointercast(llscratch, Type::i8p(ccx)),
|
||||
C_uint(ccx, self.layout.size(ccx).bytes()),
|
||||
C_usize(ccx, self.layout.size(ccx).bytes()),
|
||||
cmp::min(self.layout.align(ccx).abi() as u32,
|
||||
llalign_of_min(ccx, ty)));
|
||||
|
||||
|
@ -397,11 +397,11 @@ pub fn trans_set_discr<'a, 'tcx>(bcx: &Builder<'a, 'tcx>, t: Ty<'tcx>, val: Valu
|
||||
match *l {
|
||||
layout::CEnum{ discr, min, max, .. } => {
|
||||
assert_discr_in_range(min, max, to);
|
||||
bcx.store(C_integral(Type::from_integer(bcx.ccx, discr), to, true),
|
||||
bcx.store(C_int(Type::from_integer(bcx.ccx, discr), to as i64),
|
||||
val, None);
|
||||
}
|
||||
layout::General{ discr, .. } => {
|
||||
bcx.store(C_integral(Type::from_integer(bcx.ccx, discr), to, true),
|
||||
bcx.store(C_int(Type::from_integer(bcx.ccx, discr), to as i64),
|
||||
bcx.struct_gep(val, 0), None);
|
||||
}
|
||||
layout::Univariant { .. }
|
||||
@ -423,7 +423,7 @@ pub fn trans_set_discr<'a, 'tcx>(bcx: &Builder<'a, 'tcx>, t: Ty<'tcx>, val: Valu
|
||||
// than storing null to single target field.
|
||||
let llptr = bcx.pointercast(val, Type::i8(bcx.ccx).ptr_to());
|
||||
let fill_byte = C_u8(bcx.ccx, 0);
|
||||
let size = C_uint(bcx.ccx, nonnull.stride().bytes());
|
||||
let size = C_usize(bcx.ccx, nonnull.stride().bytes());
|
||||
let align = C_i32(bcx.ccx, nonnull.align.abi() as i32);
|
||||
base::call_memset(bcx, llptr, fill_byte, size, align, false);
|
||||
} else {
|
||||
|
@ -53,7 +53,7 @@ use mir::lvalue::LvalueRef;
|
||||
use attributes;
|
||||
use builder::Builder;
|
||||
use callee;
|
||||
use common::{C_bool, C_bytes_in_context, C_i32, C_uint};
|
||||
use common::{C_bool, C_bytes_in_context, C_i32, C_usize};
|
||||
use collector::{self, TransItemCollectionMode};
|
||||
use common::{C_struct_in_context, C_u64, C_undef, C_array};
|
||||
use common::CrateContext;
|
||||
@ -201,7 +201,9 @@ pub fn unsized_info<'ccx, 'tcx>(ccx: &CrateContext<'ccx, 'tcx>,
|
||||
-> ValueRef {
|
||||
let (source, target) = ccx.tcx().struct_lockstep_tails(source, target);
|
||||
match (&source.sty, &target.sty) {
|
||||
(&ty::TyArray(_, len), &ty::TySlice(_)) => C_uint(ccx, len),
|
||||
(&ty::TyArray(_, len), &ty::TySlice(_)) => {
|
||||
C_usize(ccx, len.val.to_const_int().unwrap().to_u64().unwrap())
|
||||
}
|
||||
(&ty::TyDynamic(..), &ty::TyDynamic(..)) => {
|
||||
// For now, upcasts are limited to changes in marker
|
||||
// traits, and hence never actually require an actual
|
||||
@ -524,7 +526,7 @@ pub fn call_memcpy<'a, 'tcx>(b: &Builder<'a, 'tcx>,
|
||||
let memcpy = ccx.get_intrinsic(&key);
|
||||
let src_ptr = b.pointercast(src, Type::i8p(ccx));
|
||||
let dst_ptr = b.pointercast(dst, Type::i8p(ccx));
|
||||
let size = b.intcast(n_bytes, ccx.int_type(), false);
|
||||
let size = b.intcast(n_bytes, ccx.isize_ty(), false);
|
||||
let align = C_i32(ccx, align as i32);
|
||||
let volatile = C_bool(ccx, false);
|
||||
b.call(memcpy, &[dst_ptr, src_ptr, size, align, volatile], None);
|
||||
@ -545,7 +547,7 @@ pub fn memcpy_ty<'a, 'tcx>(
|
||||
}
|
||||
|
||||
let align = align.unwrap_or_else(|| ccx.align_of(t));
|
||||
call_memcpy(bcx, dst, src, C_uint(ccx, size), align);
|
||||
call_memcpy(bcx, dst, src, C_usize(ccx, size), align);
|
||||
}
|
||||
|
||||
pub fn call_memset<'a, 'tcx>(b: &Builder<'a, 'tcx>,
|
||||
@ -696,7 +698,7 @@ fn maybe_create_entry_wrapper(ccx: &CrateContext) {
|
||||
sp: Span,
|
||||
rust_main: ValueRef,
|
||||
use_start_lang_item: bool) {
|
||||
let llfty = Type::func(&[ccx.int_type(), Type::i8p(ccx).ptr_to()], &ccx.int_type());
|
||||
let llfty = Type::func(&[ccx.isize_ty(), Type::i8p(ccx).ptr_to()], &ccx.isize_ty());
|
||||
|
||||
if declare::get_defined_value(ccx, "main").is_some() {
|
||||
// FIXME: We should be smart and show a better diagnostic here.
|
||||
|
@ -193,6 +193,7 @@ use rustc::hir::itemlikevisit::ItemLikeVisitor;
|
||||
|
||||
use rustc::hir::map as hir_map;
|
||||
use rustc::hir::def_id::DefId;
|
||||
use rustc::middle::const_val::ConstVal;
|
||||
use rustc::middle::lang_items::{ExchangeMallocFnLangItem};
|
||||
use rustc::traits;
|
||||
use rustc::ty::subst::Substs;
|
||||
@ -564,24 +565,17 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> {
|
||||
self.super_rvalue(rvalue, location);
|
||||
}
|
||||
|
||||
fn visit_constant(&mut self, constant: &mir::Constant<'tcx>, location: Location) {
|
||||
debug!("visiting constant {:?} @ {:?}", *constant, location);
|
||||
fn visit_const(&mut self, constant: &&'tcx ty::Const<'tcx>, location: Location) {
|
||||
debug!("visiting const {:?} @ {:?}", *constant, location);
|
||||
|
||||
if let ty::TyFnDef(..) = constant.ty.sty {
|
||||
// function definitions are zero-sized, and only generate
|
||||
// IR when they are called/reified.
|
||||
self.super_constant(constant, location);
|
||||
return
|
||||
}
|
||||
|
||||
if let mir::Literal::Item { def_id, substs } = constant.literal {
|
||||
if let ConstVal::Unevaluated(def_id, substs) = constant.val {
|
||||
let substs = self.scx.tcx().trans_apply_param_substs(self.param_substs,
|
||||
&substs);
|
||||
let instance = monomorphize::resolve(self.scx, def_id, substs);
|
||||
collect_neighbours(self.scx, instance, true, self.output);
|
||||
}
|
||||
|
||||
self.super_constant(constant, location);
|
||||
self.super_const(constant);
|
||||
}
|
||||
|
||||
fn visit_terminator_kind(&mut self,
|
||||
|
@ -221,9 +221,15 @@ pub fn C_undef(t: Type) -> ValueRef {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn C_integral(t: Type, u: u64, sign_extend: bool) -> ValueRef {
|
||||
pub fn C_int(t: Type, i: i64) -> ValueRef {
|
||||
unsafe {
|
||||
llvm::LLVMConstInt(t.to_ref(), u, sign_extend as Bool)
|
||||
llvm::LLVMConstInt(t.to_ref(), i as u64, True)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn C_uint(t: Type, i: u64) -> ValueRef {
|
||||
unsafe {
|
||||
llvm::LLVMConstInt(t.to_ref(), i, False)
|
||||
}
|
||||
}
|
||||
|
||||
@ -239,49 +245,34 @@ pub fn C_nil(ccx: &CrateContext) -> ValueRef {
|
||||
}
|
||||
|
||||
pub fn C_bool(ccx: &CrateContext, val: bool) -> ValueRef {
|
||||
C_integral(Type::i1(ccx), val as u64, false)
|
||||
C_uint(Type::i1(ccx), val as u64)
|
||||
}
|
||||
|
||||
pub fn C_i32(ccx: &CrateContext, i: i32) -> ValueRef {
|
||||
C_integral(Type::i32(ccx), i as u64, true)
|
||||
C_int(Type::i32(ccx), i as i64)
|
||||
}
|
||||
|
||||
pub fn C_u32(ccx: &CrateContext, i: u32) -> ValueRef {
|
||||
C_integral(Type::i32(ccx), i as u64, false)
|
||||
C_uint(Type::i32(ccx), i as u64)
|
||||
}
|
||||
|
||||
pub fn C_u64(ccx: &CrateContext, i: u64) -> ValueRef {
|
||||
C_integral(Type::i64(ccx), i, false)
|
||||
C_uint(Type::i64(ccx), i)
|
||||
}
|
||||
|
||||
pub fn C_uint<I: AsU64>(ccx: &CrateContext, i: I) -> ValueRef {
|
||||
let v = i.as_u64();
|
||||
|
||||
let bit_size = machine::llbitsize_of_real(ccx, ccx.int_type());
|
||||
pub fn C_usize(ccx: &CrateContext, i: u64) -> ValueRef {
|
||||
let bit_size = machine::llbitsize_of_real(ccx, ccx.isize_ty());
|
||||
|
||||
if bit_size < 64 {
|
||||
// make sure it doesn't overflow
|
||||
assert!(v < (1<<bit_size));
|
||||
assert!(i < (1<<bit_size));
|
||||
}
|
||||
|
||||
C_integral(ccx.int_type(), v, false)
|
||||
C_uint(ccx.isize_ty(), i)
|
||||
}
|
||||
|
||||
pub trait AsI64 { fn as_i64(self) -> i64; }
|
||||
pub trait AsU64 { fn as_u64(self) -> u64; }
|
||||
|
||||
// FIXME: remove the intptr conversions, because they
|
||||
// are host-architecture-dependent
|
||||
impl AsI64 for i64 { fn as_i64(self) -> i64 { self as i64 }}
|
||||
impl AsI64 for i32 { fn as_i64(self) -> i64 { self as i64 }}
|
||||
impl AsI64 for isize { fn as_i64(self) -> i64 { self as i64 }}
|
||||
|
||||
impl AsU64 for u64 { fn as_u64(self) -> u64 { self as u64 }}
|
||||
impl AsU64 for u32 { fn as_u64(self) -> u64 { self as u64 }}
|
||||
impl AsU64 for usize { fn as_u64(self) -> u64 { self as u64 }}
|
||||
|
||||
pub fn C_u8(ccx: &CrateContext, i: u8) -> ValueRef {
|
||||
C_integral(Type::i8(ccx), i as u64, false)
|
||||
C_uint(Type::i8(ccx), i as u64)
|
||||
}
|
||||
|
||||
|
||||
@ -315,7 +306,7 @@ pub fn C_cstr(cx: &CrateContext, s: InternedString, null_terminated: bool) -> Va
|
||||
pub fn C_str_slice(cx: &CrateContext, s: InternedString) -> ValueRef {
|
||||
let len = s.len();
|
||||
let cs = consts::ptrcast(C_cstr(cx, s, false), Type::i8p(cx));
|
||||
C_named_struct(cx.str_slice_type(), &[cs, C_uint(cx, len)])
|
||||
C_named_struct(cx.str_slice_type(), &[cs, C_usize(cx, len as u64)])
|
||||
}
|
||||
|
||||
pub fn C_struct(cx: &CrateContext, elts: &[ValueRef], packed: bool) -> ValueRef {
|
||||
@ -482,9 +473,9 @@ pub fn shift_mask_val<'a, 'tcx>(
|
||||
// i8/u8 can shift by at most 7, i16/u16 by at most 15, etc.
|
||||
let val = llty.int_width() - 1;
|
||||
if invert {
|
||||
C_integral(mask_llty, !val, true)
|
||||
C_int(mask_llty, !val as i64)
|
||||
} else {
|
||||
C_integral(mask_llty, val, false)
|
||||
C_uint(mask_llty, val)
|
||||
}
|
||||
},
|
||||
TypeKind::Vector => {
|
||||
|
@ -136,7 +136,7 @@ pub struct LocalCrateContext<'a, 'tcx: 'a> {
|
||||
used_statics: RefCell<Vec<ValueRef>>,
|
||||
|
||||
lltypes: RefCell<FxHashMap<Ty<'tcx>, Type>>,
|
||||
int_type: Type,
|
||||
isize_ty: Type,
|
||||
opaque_vec_type: Type,
|
||||
str_slice_type: Type,
|
||||
|
||||
@ -398,7 +398,7 @@ impl<'a, 'tcx> LocalCrateContext<'a, 'tcx> {
|
||||
statics_to_rauw: RefCell::new(Vec::new()),
|
||||
used_statics: RefCell::new(Vec::new()),
|
||||
lltypes: RefCell::new(FxHashMap()),
|
||||
int_type: Type::from_ref(ptr::null_mut()),
|
||||
isize_ty: Type::from_ref(ptr::null_mut()),
|
||||
opaque_vec_type: Type::from_ref(ptr::null_mut()),
|
||||
str_slice_type: Type::from_ref(ptr::null_mut()),
|
||||
dbg_cx,
|
||||
@ -410,23 +410,23 @@ impl<'a, 'tcx> LocalCrateContext<'a, 'tcx> {
|
||||
placeholder: PhantomData,
|
||||
};
|
||||
|
||||
let (int_type, opaque_vec_type, str_slice_ty, mut local_ccx) = {
|
||||
let (isize_ty, opaque_vec_type, str_slice_ty, mut local_ccx) = {
|
||||
// Do a little dance to create a dummy CrateContext, so we can
|
||||
// create some things in the LLVM module of this codegen unit
|
||||
let mut local_ccxs = vec![local_ccx];
|
||||
let (int_type, opaque_vec_type, str_slice_ty) = {
|
||||
let (isize_ty, opaque_vec_type, str_slice_ty) = {
|
||||
let dummy_ccx = LocalCrateContext::dummy_ccx(shared,
|
||||
local_ccxs.as_mut_slice());
|
||||
let mut str_slice_ty = Type::named_struct(&dummy_ccx, "str_slice");
|
||||
str_slice_ty.set_struct_body(&[Type::i8p(&dummy_ccx),
|
||||
Type::int(&dummy_ccx)],
|
||||
Type::isize(&dummy_ccx)],
|
||||
false);
|
||||
(Type::int(&dummy_ccx), Type::opaque_vec(&dummy_ccx), str_slice_ty)
|
||||
(Type::isize(&dummy_ccx), Type::opaque_vec(&dummy_ccx), str_slice_ty)
|
||||
};
|
||||
(int_type, opaque_vec_type, str_slice_ty, local_ccxs.pop().unwrap())
|
||||
(isize_ty, opaque_vec_type, str_slice_ty, local_ccxs.pop().unwrap())
|
||||
};
|
||||
|
||||
local_ccx.int_type = int_type;
|
||||
local_ccx.isize_ty = isize_ty;
|
||||
local_ccx.opaque_vec_type = opaque_vec_type;
|
||||
local_ccx.str_slice_type = str_slice_ty;
|
||||
|
||||
@ -549,8 +549,8 @@ impl<'b, 'tcx> CrateContext<'b, 'tcx> {
|
||||
&self.local().stats
|
||||
}
|
||||
|
||||
pub fn int_type(&self) -> Type {
|
||||
self.local().int_type
|
||||
pub fn isize_ty(&self) -> Type {
|
||||
self.local().isize_ty
|
||||
}
|
||||
|
||||
pub fn str_slice_type(&self) -> Type {
|
||||
|
@ -366,7 +366,7 @@ fn vec_slice_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
|
||||
-> bool {
|
||||
member_llvm_types.len() == 2 &&
|
||||
member_llvm_types[0] == type_of::type_of(cx, element_type).ptr_to() &&
|
||||
member_llvm_types[1] == cx.int_type()
|
||||
member_llvm_types[1] == cx.isize_ty()
|
||||
}
|
||||
}
|
||||
|
||||
@ -530,7 +530,8 @@ pub fn type_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
|
||||
MetadataCreationResult::new(basic_type_metadata(cx, t), false)
|
||||
}
|
||||
ty::TyArray(typ, len) => {
|
||||
fixed_vec_metadata(cx, unique_type_id, typ, Some(len as u64), usage_site_span)
|
||||
let len = len.val.to_const_int().unwrap().to_u64().unwrap();
|
||||
fixed_vec_metadata(cx, unique_type_id, typ, Some(len), usage_site_span)
|
||||
}
|
||||
ty::TySlice(typ) => {
|
||||
fixed_vec_metadata(cx, unique_type_id, typ, None, usage_site_span)
|
||||
|
@ -96,7 +96,7 @@ pub fn push_debuginfo_type_name<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
|
||||
ty::TyArray(inner_type, len) => {
|
||||
output.push('[');
|
||||
push_debuginfo_type_name(cx, inner_type, true, output);
|
||||
output.push_str(&format!("; {}", len));
|
||||
output.push_str(&format!("; {}", len.val.to_const_int().unwrap().to_u64().unwrap()));
|
||||
output.push(']');
|
||||
},
|
||||
ty::TySlice(inner_type) => {
|
||||
|
@ -70,8 +70,8 @@ pub fn size_and_align_of_dst<'a, 'tcx>(bcx: &Builder<'a, 'tcx>, t: Ty<'tcx>, inf
|
||||
let align = bcx.ccx.align_of(t);
|
||||
debug!("size_and_align_of_dst t={} info={:?} size: {} align: {}",
|
||||
t, Value(info), size, align);
|
||||
let size = C_uint(bcx.ccx, size);
|
||||
let align = C_uint(bcx.ccx, align);
|
||||
let size = C_usize(bcx.ccx, size);
|
||||
let align = C_usize(bcx.ccx, align as u64);
|
||||
return (size, align);
|
||||
}
|
||||
assert!(!info.is_null());
|
||||
@ -96,8 +96,8 @@ pub fn size_and_align_of_dst<'a, 'tcx>(bcx: &Builder<'a, 'tcx>, t: Ty<'tcx>, inf
|
||||
};
|
||||
debug!("DST {} statically sized prefix size: {} align: {}",
|
||||
t, sized_size, sized_align);
|
||||
let sized_size = C_uint(ccx, sized_size);
|
||||
let sized_align = C_uint(ccx, sized_align);
|
||||
let sized_size = C_usize(ccx, sized_size);
|
||||
let sized_align = C_usize(ccx, sized_align);
|
||||
|
||||
// Recurse to get the size of the dynamically sized field (must be
|
||||
// the last field).
|
||||
@ -128,7 +128,7 @@ pub fn size_and_align_of_dst<'a, 'tcx>(bcx: &Builder<'a, 'tcx>, t: Ty<'tcx>, inf
|
||||
(Some(sized_align), Some(unsized_align)) => {
|
||||
// If both alignments are constant, (the sized_align should always be), then
|
||||
// pick the correct alignment statically.
|
||||
C_uint(ccx, std::cmp::max(sized_align, unsized_align) as u64)
|
||||
C_usize(ccx, std::cmp::max(sized_align, unsized_align) as u64)
|
||||
}
|
||||
_ => bcx.select(bcx.icmp(llvm::IntUGT, sized_align, unsized_align),
|
||||
sized_align,
|
||||
@ -146,7 +146,7 @@ pub fn size_and_align_of_dst<'a, 'tcx>(bcx: &Builder<'a, 'tcx>, t: Ty<'tcx>, inf
|
||||
//
|
||||
// `(size + (align-1)) & -align`
|
||||
|
||||
let addend = bcx.sub(align, C_uint(bcx.ccx, 1_u64));
|
||||
let addend = bcx.sub(align, C_usize(bcx.ccx, 1));
|
||||
let size = bcx.and(bcx.add(size, addend), bcx.neg(align));
|
||||
|
||||
(size, align)
|
||||
@ -159,8 +159,8 @@ pub fn size_and_align_of_dst<'a, 'tcx>(bcx: &Builder<'a, 'tcx>, t: Ty<'tcx>, inf
|
||||
let unit = t.sequence_element_type(bcx.tcx());
|
||||
// The info in this case is the length of the str, so the size is that
|
||||
// times the unit size.
|
||||
(bcx.mul(info, C_uint(bcx.ccx, bcx.ccx.size_of(unit))),
|
||||
C_uint(bcx.ccx, bcx.ccx.align_of(unit)))
|
||||
(bcx.mul(info, C_usize(bcx.ccx, bcx.ccx.size_of(unit))),
|
||||
C_usize(bcx.ccx, bcx.ccx.align_of(unit) as u64))
|
||||
}
|
||||
_ => bug!("Unexpected unsized type, found {}", t)
|
||||
}
|
||||
|
@ -135,7 +135,7 @@ pub fn trans_intrinsic_call<'a, 'tcx>(bcx: &Builder<'a, 'tcx>,
|
||||
"size_of" => {
|
||||
let tp_ty = substs.type_at(0);
|
||||
let lltp_ty = type_of::type_of(ccx, tp_ty);
|
||||
C_uint(ccx, machine::llsize_of_alloc(ccx, lltp_ty))
|
||||
C_usize(ccx, machine::llsize_of_alloc(ccx, lltp_ty))
|
||||
}
|
||||
"size_of_val" => {
|
||||
let tp_ty = substs.type_at(0);
|
||||
@ -145,12 +145,12 @@ pub fn trans_intrinsic_call<'a, 'tcx>(bcx: &Builder<'a, 'tcx>,
|
||||
llsize
|
||||
} else {
|
||||
let lltp_ty = type_of::type_of(ccx, tp_ty);
|
||||
C_uint(ccx, machine::llsize_of_alloc(ccx, lltp_ty))
|
||||
C_usize(ccx, machine::llsize_of_alloc(ccx, lltp_ty))
|
||||
}
|
||||
}
|
||||
"min_align_of" => {
|
||||
let tp_ty = substs.type_at(0);
|
||||
C_uint(ccx, ccx.align_of(tp_ty))
|
||||
C_usize(ccx, ccx.align_of(tp_ty) as u64)
|
||||
}
|
||||
"min_align_of_val" => {
|
||||
let tp_ty = substs.type_at(0);
|
||||
@ -159,13 +159,13 @@ pub fn trans_intrinsic_call<'a, 'tcx>(bcx: &Builder<'a, 'tcx>,
|
||||
glue::size_and_align_of_dst(bcx, tp_ty, llargs[1]);
|
||||
llalign
|
||||
} else {
|
||||
C_uint(ccx, ccx.align_of(tp_ty))
|
||||
C_usize(ccx, ccx.align_of(tp_ty) as u64)
|
||||
}
|
||||
}
|
||||
"pref_align_of" => {
|
||||
let tp_ty = substs.type_at(0);
|
||||
let lltp_ty = type_of::type_of(ccx, tp_ty);
|
||||
C_uint(ccx, machine::llalign_of_pref(ccx, lltp_ty))
|
||||
C_usize(ccx, machine::llalign_of_pref(ccx, lltp_ty) as u64)
|
||||
}
|
||||
"type_name" => {
|
||||
let tp_ty = substs.type_at(0);
|
||||
@ -182,7 +182,7 @@ pub fn trans_intrinsic_call<'a, 'tcx>(bcx: &Builder<'a, 'tcx>,
|
||||
// If we store a zero constant, LLVM will drown in vreg allocation for large data
|
||||
// structures, and the generated code will be awful. (A telltale sign of this is
|
||||
// large quantities of `mov [byte ptr foo],0` in the generated code.)
|
||||
memset_intrinsic(bcx, false, ty, llresult, C_u8(ccx, 0), C_uint(ccx, 1usize));
|
||||
memset_intrinsic(bcx, false, ty, llresult, C_u8(ccx, 0), C_usize(ccx, 1));
|
||||
}
|
||||
C_nil(ccx)
|
||||
}
|
||||
@ -386,10 +386,10 @@ pub fn trans_intrinsic_call<'a, 'tcx>(bcx: &Builder<'a, 'tcx>,
|
||||
|
||||
"align_offset" => {
|
||||
// `ptr as usize`
|
||||
let ptr_val = bcx.ptrtoint(llargs[0], bcx.ccx.int_type());
|
||||
let ptr_val = bcx.ptrtoint(llargs[0], bcx.ccx.isize_ty());
|
||||
// `ptr_val % align`
|
||||
let offset = bcx.urem(ptr_val, llargs[1]);
|
||||
let zero = C_null(bcx.ccx.int_type());
|
||||
let zero = C_null(bcx.ccx.isize_ty());
|
||||
// `offset == 0`
|
||||
let is_zero = bcx.icmp(llvm::IntPredicate::IntEQ, offset, zero);
|
||||
// `if offset == 0 { 0 } else { offset - align }`
|
||||
@ -688,7 +688,7 @@ fn copy_intrinsic<'a, 'tcx>(bcx: &Builder<'a, 'tcx>,
|
||||
let lltp_ty = type_of::type_of(ccx, tp_ty);
|
||||
let align = C_i32(ccx, ccx.align_of(tp_ty) as i32);
|
||||
let size = machine::llsize_of(ccx, lltp_ty);
|
||||
let int_size = machine::llbitsize_of_real(ccx, ccx.int_type());
|
||||
let int_size = machine::llbitsize_of_real(ccx, ccx.isize_ty());
|
||||
|
||||
let operation = if allow_overlap {
|
||||
"memmove"
|
||||
|
@ -48,7 +48,7 @@ pub fn llsize_of(cx: &CrateContext, ty: Type) -> ValueRef {
|
||||
// there's no need for that contrivance. The instruction
|
||||
// selection DAG generator would flatten that GEP(1) node into a
|
||||
// constant of the type's alloc size, so let's save it some work.
|
||||
return C_uint(cx, llsize_of_alloc(cx, ty));
|
||||
return C_usize(cx, llsize_of_alloc(cx, ty));
|
||||
}
|
||||
|
||||
// Returns the preferred alignment of the given type for the current target.
|
||||
|
@ -46,7 +46,7 @@ impl<'a, 'tcx> VirtualIndex {
|
||||
// Load the data pointer from the object.
|
||||
debug!("get_int({:?}, {:?})", Value(llvtable), self);
|
||||
|
||||
let llvtable = bcx.pointercast(llvtable, Type::int(bcx.ccx).ptr_to());
|
||||
let llvtable = bcx.pointercast(llvtable, Type::isize(bcx.ccx).ptr_to());
|
||||
let ptr = bcx.load(bcx.gepi(llvtable, &[self.0]), None);
|
||||
// Vtable loads are invariant
|
||||
bcx.set_invariant_load(ptr);
|
||||
@ -81,8 +81,8 @@ pub fn get_vtable<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
|
||||
|
||||
let mut components: Vec<_> = [
|
||||
callee::get_fn(ccx, monomorphize::resolve_drop_in_place(ccx.shared(), ty)),
|
||||
C_uint(ccx, ccx.size_of(ty)),
|
||||
C_uint(ccx, ccx.align_of(ty))
|
||||
C_usize(ccx, ccx.size_of(ty)),
|
||||
C_usize(ccx, ccx.align_of(ty) as u64)
|
||||
].iter().cloned().collect();
|
||||
|
||||
if let Some(trait_ref) = trait_ref {
|
||||
|
@ -17,6 +17,7 @@ use rustc::middle::const_val::ConstVal;
|
||||
use rustc::mir::{self, Location, TerminatorKind, Literal};
|
||||
use rustc::mir::visit::{Visitor, LvalueContext};
|
||||
use rustc::mir::traversal;
|
||||
use rustc::ty;
|
||||
use common;
|
||||
use super::MirContext;
|
||||
|
||||
@ -110,7 +111,7 @@ impl<'mir, 'a, 'tcx> Visitor<'tcx> for LocalAnalyzer<'mir, 'a, 'tcx> {
|
||||
mir::TerminatorKind::Call {
|
||||
func: mir::Operand::Constant(box mir::Constant {
|
||||
literal: Literal::Value {
|
||||
value: ConstVal::Function(def_id, _), ..
|
||||
value: &ty::Const { val: ConstVal::Function(def_id, _), .. }, ..
|
||||
}, ..
|
||||
}),
|
||||
ref args, ..
|
||||
|
@ -26,8 +26,8 @@ use abi::{self, Abi};
|
||||
use callee;
|
||||
use builder::Builder;
|
||||
use common::{self, CrateContext, const_get_elt, val_ty};
|
||||
use common::{C_array, C_bool, C_bytes, C_integral, C_big_integral, C_u32, C_u64};
|
||||
use common::{C_null, C_struct, C_str_slice, C_undef, C_uint, C_vector, is_undef};
|
||||
use common::{C_array, C_bool, C_bytes, C_int, C_uint, C_big_integral, C_u32, C_u64};
|
||||
use common::{C_null, C_struct, C_str_slice, C_undef, C_usize, C_vector, is_undef};
|
||||
use common::const_to_opt_u128;
|
||||
use consts;
|
||||
use monomorphize;
|
||||
@ -66,35 +66,29 @@ impl<'tcx> Const<'tcx> {
|
||||
-> Const<'tcx> {
|
||||
let tcx = ccx.tcx();
|
||||
let (llval, ty) = match *ci {
|
||||
I8(v) => (C_integral(Type::i8(ccx), v as u64, true), tcx.types.i8),
|
||||
I16(v) => (C_integral(Type::i16(ccx), v as u64, true), tcx.types.i16),
|
||||
I32(v) => (C_integral(Type::i32(ccx), v as u64, true), tcx.types.i32),
|
||||
I64(v) => (C_integral(Type::i64(ccx), v as u64, true), tcx.types.i64),
|
||||
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),
|
||||
I128(v) => (C_big_integral(Type::i128(ccx), v as u128), tcx.types.i128),
|
||||
Isize(v) => {
|
||||
let i = v.as_i64(ccx.tcx().sess.target.int_type);
|
||||
(C_integral(Type::int(ccx), i as u64, true), tcx.types.isize)
|
||||
},
|
||||
U8(v) => (C_integral(Type::i8(ccx), v as u64, false), tcx.types.u8),
|
||||
U16(v) => (C_integral(Type::i16(ccx), v as u64, false), tcx.types.u16),
|
||||
U32(v) => (C_integral(Type::i32(ccx), v as u64, false), tcx.types.u32),
|
||||
U64(v) => (C_integral(Type::i64(ccx), v, false), tcx.types.u64),
|
||||
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),
|
||||
U128(v) => (C_big_integral(Type::i128(ccx), v), tcx.types.u128),
|
||||
Usize(v) => {
|
||||
let u = v.as_u64(ccx.tcx().sess.target.uint_type);
|
||||
(C_integral(Type::int(ccx), u, false), tcx.types.usize)
|
||||
},
|
||||
Usize(v) => (C_uint(Type::isize(ccx), v.as_u64()), tcx.types.usize),
|
||||
};
|
||||
Const { llval: llval, ty: ty }
|
||||
}
|
||||
|
||||
/// Translate ConstVal into a LLVM constant value.
|
||||
pub fn from_constval<'a>(ccx: &CrateContext<'a, 'tcx>,
|
||||
cv: ConstVal,
|
||||
cv: &ConstVal,
|
||||
ty: Ty<'tcx>)
|
||||
-> Const<'tcx> {
|
||||
let llty = type_of::type_of(ccx, ty);
|
||||
let val = match cv {
|
||||
let val = match *cv {
|
||||
ConstVal::Float(v) => {
|
||||
let bits = match v.ty {
|
||||
ast::FloatTy::F32 => C_u32(ccx, v.bits as u32),
|
||||
@ -105,12 +99,12 @@ impl<'tcx> Const<'tcx> {
|
||||
ConstVal::Bool(v) => C_bool(ccx, v),
|
||||
ConstVal::Integral(ref i) => return Const::from_constint(ccx, i),
|
||||
ConstVal::Str(ref v) => C_str_slice(ccx, v.clone()),
|
||||
ConstVal::ByteStr(ref v) => consts::addr_of(ccx, C_bytes(ccx, v), 1, "byte_str"),
|
||||
ConstVal::Char(c) => C_integral(Type::char(ccx), c as u64, false),
|
||||
ConstVal::ByteStr(v) => consts::addr_of(ccx, C_bytes(ccx, v.data), 1, "byte_str"),
|
||||
ConstVal::Char(c) => C_uint(Type::char(ccx), c as u64),
|
||||
ConstVal::Function(..) => C_null(type_of::type_of(ccx, ty)),
|
||||
ConstVal::Variant(_) |
|
||||
ConstVal::Struct(_) | ConstVal::Tuple(_) |
|
||||
ConstVal::Array(..) | ConstVal::Repeat(..) => {
|
||||
ConstVal::Aggregate(..) |
|
||||
ConstVal::Unevaluated(..) => {
|
||||
bug!("MIR must not use `{:?}` (aggregates are expanded to MIR rvalues)", cv)
|
||||
}
|
||||
};
|
||||
@ -207,7 +201,9 @@ impl<'tcx> ConstLvalue<'tcx> {
|
||||
|
||||
pub fn len<'a>(&self, ccx: &CrateContext<'a, 'tcx>) -> ValueRef {
|
||||
match self.ty.sty {
|
||||
ty::TyArray(_, n) => C_uint(ccx, n),
|
||||
ty::TyArray(_, n) => {
|
||||
C_usize(ccx, n.val.to_const_int().unwrap().to_u64().unwrap())
|
||||
}
|
||||
ty::TySlice(_) | ty::TyStr => {
|
||||
assert!(self.llextra != ptr::null_mut());
|
||||
self.llextra
|
||||
@ -367,13 +363,13 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> {
|
||||
let result = if fn_ty.fn_sig(tcx).abi() == Abi::RustIntrinsic {
|
||||
match &tcx.item_name(def_id)[..] {
|
||||
"size_of" => {
|
||||
let llval = C_uint(self.ccx,
|
||||
let llval = C_usize(self.ccx,
|
||||
self.ccx.size_of(substs.type_at(0)));
|
||||
Ok(Const::new(llval, tcx.types.usize))
|
||||
}
|
||||
"min_align_of" => {
|
||||
let llval = C_uint(self.ccx,
|
||||
self.ccx.align_of(substs.type_at(0)));
|
||||
let llval = C_usize(self.ccx,
|
||||
self.ccx.align_of(substs.type_at(0)) as u64);
|
||||
Ok(Const::new(llval, tcx.types.usize))
|
||||
}
|
||||
_ => span_bug!(span, "{:?} in constant", terminator.kind)
|
||||
@ -514,16 +510,17 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> {
|
||||
mir::Operand::Constant(ref constant) => {
|
||||
let ty = self.monomorphize(&constant.ty);
|
||||
match constant.literal.clone() {
|
||||
mir::Literal::Item { def_id, substs } => {
|
||||
let substs = self.monomorphize(&substs);
|
||||
MirConstContext::trans_def(self.ccx, def_id, substs, IndexVec::new())
|
||||
}
|
||||
mir::Literal::Promoted { index } => {
|
||||
let mir = &self.mir.promoted[index];
|
||||
MirConstContext::new(self.ccx, mir, self.substs, IndexVec::new()).trans()
|
||||
}
|
||||
mir::Literal::Value { value } => {
|
||||
Ok(Const::from_constval(self.ccx, value, ty))
|
||||
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))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -557,9 +554,10 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> {
|
||||
let val = match *rvalue {
|
||||
mir::Rvalue::Use(ref operand) => self.const_operand(operand, span)?,
|
||||
|
||||
mir::Rvalue::Repeat(ref elem, ref count) => {
|
||||
mir::Rvalue::Repeat(ref elem, count) => {
|
||||
let elem = self.const_operand(elem, span)?;
|
||||
let size = count.as_u64(tcx.sess.target.uint_type);
|
||||
let size = count.as_u64();
|
||||
assert_eq!(size as usize as u64, size);
|
||||
let fields = vec![elem.llval; size as usize];
|
||||
self.const_array(dest_ty, &fields)
|
||||
}
|
||||
@ -836,7 +834,7 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> {
|
||||
|
||||
mir::Rvalue::NullaryOp(mir::NullOp::SizeOf, ty) => {
|
||||
assert!(self.ccx.shared().type_is_sized(ty));
|
||||
let llval = C_uint(self.ccx, self.ccx.size_of(ty));
|
||||
let llval = C_usize(self.ccx, self.ccx.size_of(ty));
|
||||
Const::new(llval, tcx.types.usize)
|
||||
}
|
||||
|
||||
@ -854,10 +852,10 @@ fn to_const_int(value: ValueRef, t: Ty, tcx: TyCtxt) -> Option<ConstInt> {
|
||||
match t.sty {
|
||||
ty::TyInt(int_type) => const_to_opt_u128(value, true)
|
||||
.and_then(|input| ConstInt::new_signed(input as i128, int_type,
|
||||
tcx.sess.target.int_type)),
|
||||
tcx.sess.target.isize_ty)),
|
||||
ty::TyUint(uint_type) => const_to_opt_u128(value, false)
|
||||
.and_then(|input| ConstInt::new_unsigned(input, uint_type,
|
||||
tcx.sess.target.uint_type)),
|
||||
tcx.sess.target.usize_ty)),
|
||||
_ => None
|
||||
|
||||
}
|
||||
@ -963,16 +961,17 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> {
|
||||
debug!("trans_constant({:?})", constant);
|
||||
let ty = self.monomorphize(&constant.ty);
|
||||
let result = match constant.literal.clone() {
|
||||
mir::Literal::Item { def_id, substs } => {
|
||||
let substs = self.monomorphize(&substs);
|
||||
MirConstContext::trans_def(bcx.ccx, def_id, substs, IndexVec::new())
|
||||
}
|
||||
mir::Literal::Promoted { index } => {
|
||||
let mir = &self.mir.promoted[index];
|
||||
MirConstContext::new(bcx.ccx, mir, self.param_substs, IndexVec::new()).trans()
|
||||
}
|
||||
mir::Literal::Value { value } => {
|
||||
Ok(Const::from_constval(bcx.ccx, value, ty))
|
||||
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))
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@ -1038,11 +1037,11 @@ fn trans_const<'a, 'tcx>(
|
||||
};
|
||||
assert_eq!(vals.len(), 0);
|
||||
adt::assert_discr_in_range(min, max, discr);
|
||||
C_integral(Type::from_integer(ccx, d), discr, true)
|
||||
C_int(Type::from_integer(ccx, d), discr as i64)
|
||||
}
|
||||
layout::General { discr: d, ref variants, .. } => {
|
||||
let variant = &variants[variant_index];
|
||||
let lldiscr = C_integral(Type::from_integer(ccx, d), variant_index as u64, true);
|
||||
let lldiscr = C_int(Type::from_integer(ccx, d), variant_index as i64);
|
||||
let mut vals_with_discr = vec![lldiscr];
|
||||
vals_with_discr.extend_from_slice(vals);
|
||||
let mut contents = build_const_struct(ccx, &variant, &vals_with_discr[..]);
|
||||
|
@ -16,7 +16,7 @@ use rustc::mir::tcx::LvalueTy;
|
||||
use rustc_data_structures::indexed_vec::Idx;
|
||||
use adt;
|
||||
use builder::Builder;
|
||||
use common::{self, CrateContext, C_uint};
|
||||
use common::{self, CrateContext, C_usize};
|
||||
use consts;
|
||||
use machine;
|
||||
use type_of;
|
||||
@ -106,7 +106,9 @@ impl<'a, 'tcx> LvalueRef<'tcx> {
|
||||
pub fn len(&self, ccx: &CrateContext<'a, 'tcx>) -> ValueRef {
|
||||
let ty = self.ty.to_ty(ccx.tcx());
|
||||
match ty.sty {
|
||||
ty::TyArray(_, n) => common::C_uint(ccx, n),
|
||||
ty::TyArray(_, n) => {
|
||||
common::C_usize(ccx, n.val.to_const_int().unwrap().to_u64().unwrap())
|
||||
}
|
||||
ty::TySlice(_) | ty::TyStr => {
|
||||
assert!(self.llextra != ptr::null_mut());
|
||||
self.llextra
|
||||
@ -186,7 +188,7 @@ impl<'a, 'tcx> LvalueRef<'tcx> {
|
||||
|
||||
|
||||
let offset = st.offsets[ix].bytes();
|
||||
let unaligned_offset = C_uint(bcx.ccx, offset);
|
||||
let unaligned_offset = C_usize(bcx.ccx, offset);
|
||||
|
||||
// Get the alignment of the field
|
||||
let (_, align) = glue::size_and_align_of_dst(bcx, fty, meta);
|
||||
@ -197,7 +199,7 @@ impl<'a, 'tcx> LvalueRef<'tcx> {
|
||||
// (unaligned offset + (align - 1)) & -align
|
||||
|
||||
// Calculate offset
|
||||
let align_sub_1 = bcx.sub(align, C_uint(bcx.ccx, 1u64));
|
||||
let align_sub_1 = bcx.sub(align, C_usize(bcx.ccx, 1));
|
||||
let offset = bcx.and(bcx.add(unaligned_offset, align_sub_1),
|
||||
bcx.neg(align));
|
||||
|
||||
@ -276,7 +278,7 @@ impl<'a, 'tcx> LvalueRef<'tcx> {
|
||||
// Slices already point to the array element type.
|
||||
bcx.inbounds_gep(self.llval, &[llindex])
|
||||
} else {
|
||||
let zero = common::C_uint(bcx.ccx, 0u64);
|
||||
let zero = common::C_usize(bcx.ccx, 0);
|
||||
bcx.inbounds_gep(self.llval, &[zero, llindex])
|
||||
}
|
||||
}
|
||||
@ -342,19 +344,19 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> {
|
||||
mir::ProjectionElem::ConstantIndex { offset,
|
||||
from_end: false,
|
||||
min_length: _ } => {
|
||||
let lloffset = C_uint(bcx.ccx, offset);
|
||||
let lloffset = C_usize(bcx.ccx, offset as u64);
|
||||
((tr_base.project_index(bcx, lloffset), align), ptr::null_mut())
|
||||
}
|
||||
mir::ProjectionElem::ConstantIndex { offset,
|
||||
from_end: true,
|
||||
min_length: _ } => {
|
||||
let lloffset = C_uint(bcx.ccx, offset);
|
||||
let lloffset = C_usize(bcx.ccx, offset as u64);
|
||||
let lllen = tr_base.len(bcx.ccx);
|
||||
let llindex = bcx.sub(lllen, lloffset);
|
||||
((tr_base.project_index(bcx, llindex), align), ptr::null_mut())
|
||||
}
|
||||
mir::ProjectionElem::Subslice { from, to } => {
|
||||
let llbase = tr_base.project_index(bcx, C_uint(bcx.ccx, from));
|
||||
let llbase = tr_base.project_index(bcx, C_usize(bcx.ccx, from as u64));
|
||||
|
||||
let base_ty = tr_base.ty.to_ty(bcx.tcx());
|
||||
match base_ty.sty {
|
||||
@ -369,7 +371,7 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> {
|
||||
ty::TySlice(..) => {
|
||||
assert!(tr_base.llextra != ptr::null_mut());
|
||||
let lllen = bcx.sub(tr_base.llextra,
|
||||
C_uint(bcx.ccx, from+to));
|
||||
C_usize(bcx.ccx, (from as u64)+(to as u64)));
|
||||
((llbase, align), lllen)
|
||||
}
|
||||
_ => bug!("unexpected type {:?} in Subslice", base_ty)
|
||||
@ -397,11 +399,11 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> {
|
||||
/// nmatsakis: is this still necessary? Not sure.
|
||||
fn prepare_index(&mut self, bcx: &Builder<'a, 'tcx>, llindex: ValueRef) -> ValueRef {
|
||||
let index_size = machine::llbitsize_of_real(bcx.ccx, common::val_ty(llindex));
|
||||
let int_size = machine::llbitsize_of_real(bcx.ccx, bcx.ccx.int_type());
|
||||
let int_size = machine::llbitsize_of_real(bcx.ccx, bcx.ccx.isize_ty());
|
||||
if index_size < int_size {
|
||||
bcx.zext(llindex, bcx.ccx.int_type())
|
||||
bcx.zext(llindex, bcx.ccx.isize_ty())
|
||||
} else if index_size > int_size {
|
||||
bcx.trunc(llindex, bcx.ccx.int_type())
|
||||
bcx.trunc(llindex, bcx.ccx.isize_ty())
|
||||
} else {
|
||||
llindex
|
||||
}
|
||||
|
@ -19,8 +19,7 @@ use rustc::middle::lang_items::ExchangeMallocFnLangItem;
|
||||
use base;
|
||||
use builder::Builder;
|
||||
use callee;
|
||||
use common::{self, val_ty, C_bool, C_null, C_uint};
|
||||
use common::{C_integral, C_i32};
|
||||
use common::{self, val_ty, C_bool, C_i32, C_null, C_usize, C_uint};
|
||||
use adt;
|
||||
use machine;
|
||||
use monomorphize;
|
||||
@ -92,7 +91,7 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> {
|
||||
bcx
|
||||
}
|
||||
|
||||
mir::Rvalue::Repeat(ref elem, ref count) => {
|
||||
mir::Rvalue::Repeat(ref elem, count) => {
|
||||
let dest_ty = dest.ty.to_ty(bcx.tcx());
|
||||
|
||||
// No need to inizialize memory of a zero-sized slice
|
||||
@ -101,8 +100,8 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> {
|
||||
}
|
||||
|
||||
let tr_elem = self.trans_operand(&bcx, elem);
|
||||
let size = count.as_u64(bcx.tcx().sess.target.uint_type);
|
||||
let size = C_uint(bcx.ccx, size);
|
||||
let size = count.as_u64();
|
||||
let size = C_usize(bcx.ccx, size);
|
||||
let base = base::get_dataptr(&bcx, dest.llval);
|
||||
let align = dest.alignment.to_align();
|
||||
|
||||
@ -113,7 +112,7 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> {
|
||||
let align = C_i32(bcx.ccx, align as i32);
|
||||
let ty = type_of::type_of(bcx.ccx, dest_ty);
|
||||
let size = machine::llsize_of(bcx.ccx, ty);
|
||||
let fill = C_integral(Type::i8(bcx.ccx), 0, false);
|
||||
let fill = C_uint(Type::i8(bcx.ccx), 0);
|
||||
base::call_memset(&bcx, base, fill, size, align, false);
|
||||
return bcx;
|
||||
}
|
||||
@ -301,7 +300,7 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> {
|
||||
base::call_assume(&bcx, bcx.icmp(
|
||||
llvm::IntULE,
|
||||
llval,
|
||||
C_integral(common::val_ty(llval), max, false)
|
||||
C_uint(common::val_ty(llval), max)
|
||||
));
|
||||
}
|
||||
|
||||
@ -464,7 +463,7 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> {
|
||||
|
||||
mir::Rvalue::NullaryOp(mir::NullOp::SizeOf, ty) => {
|
||||
assert!(bcx.ccx.shared().type_is_sized(ty));
|
||||
let val = C_uint(bcx.ccx, bcx.ccx.size_of(ty));
|
||||
let val = C_usize(bcx.ccx, bcx.ccx.size_of(ty));
|
||||
let tcx = bcx.tcx();
|
||||
(bcx, OperandRef {
|
||||
val: OperandValue::Immediate(val),
|
||||
@ -477,7 +476,7 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> {
|
||||
let llty = type_of::type_of(bcx.ccx, content_ty);
|
||||
let llsize = machine::llsize_of(bcx.ccx, llty);
|
||||
let align = bcx.ccx.align_of(content_ty);
|
||||
let llalign = C_uint(bcx.ccx, align);
|
||||
let llalign = C_usize(bcx.ccx, align as u64);
|
||||
let llty_ptr = llty.ptr_to();
|
||||
let box_ty = bcx.tcx().mk_box(content_ty);
|
||||
|
||||
@ -522,7 +521,8 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> {
|
||||
if let LocalRef::Operand(Some(op)) = self.locals[index] {
|
||||
if common::type_is_zero_size(bcx.ccx, op.ty) {
|
||||
if let ty::TyArray(_, n) = op.ty.sty {
|
||||
return common::C_uint(bcx.ccx, n);
|
||||
let n = n.val.to_const_int().unwrap().to_u64().unwrap();
|
||||
return common::C_usize(bcx.ccx, n);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -446,7 +446,8 @@ impl<'a, 'tcx> DefPathBasedNames<'a, 'tcx> {
|
||||
ty::TyArray(inner_type, len) => {
|
||||
output.push('[');
|
||||
self.push_type_name(inner_type, output);
|
||||
write!(output, "; {}", len).unwrap();
|
||||
write!(output, "; {}",
|
||||
len.val.to_const_int().unwrap().to_u64().unwrap()).unwrap();
|
||||
output.push(']');
|
||||
},
|
||||
ty::TySlice(inner_type) => {
|
||||
|
@ -34,7 +34,7 @@ pub fn slice_for_each<'a, 'tcx, F>(
|
||||
let next_bcx = bcx.build_sibling_block("slice_loop_next");
|
||||
|
||||
let start = if zst {
|
||||
C_uint(bcx.ccx, 0usize)
|
||||
C_usize(bcx.ccx, 1)
|
||||
} else {
|
||||
data_ptr
|
||||
};
|
||||
@ -46,7 +46,7 @@ pub fn slice_for_each<'a, 'tcx, F>(
|
||||
let keep_going = header_bcx.icmp(llvm::IntNE, current, end);
|
||||
header_bcx.cond_br(keep_going, body_bcx.llbb(), next_bcx.llbb());
|
||||
|
||||
let next = add(&body_bcx, current, C_uint(bcx.ccx, 1usize));
|
||||
let next = add(&body_bcx, current, C_usize(bcx.ccx, 1));
|
||||
f(&body_bcx, if zst { data_ptr } else { current }, header_bcx.llbb());
|
||||
header_bcx.add_incoming_to_phi(current, next, body_bcx.llbb());
|
||||
next_bcx
|
||||
|
@ -131,7 +131,7 @@ impl Type {
|
||||
Type::i8_llcx(llcx).ptr_to()
|
||||
}
|
||||
|
||||
pub fn int(ccx: &CrateContext) -> Type {
|
||||
pub fn isize(ccx: &CrateContext) -> Type {
|
||||
match &ccx.tcx().sess.target.target.target_pointer_width[..] {
|
||||
"16" => Type::i16(ccx),
|
||||
"32" => Type::i32(ccx),
|
||||
@ -142,7 +142,7 @@ impl Type {
|
||||
|
||||
pub fn int_from_ty(ccx: &CrateContext, t: ast::IntTy) -> Type {
|
||||
match t {
|
||||
ast::IntTy::Is => ccx.int_type(),
|
||||
ast::IntTy::Is => ccx.isize_ty(),
|
||||
ast::IntTy::I8 => Type::i8(ccx),
|
||||
ast::IntTy::I16 => Type::i16(ccx),
|
||||
ast::IntTy::I32 => Type::i32(ccx),
|
||||
@ -153,7 +153,7 @@ impl Type {
|
||||
|
||||
pub fn uint_from_ty(ccx: &CrateContext, t: ast::UintTy) -> Type {
|
||||
match t {
|
||||
ast::UintTy::Us => ccx.int_type(),
|
||||
ast::UintTy::Us => ccx.isize_ty(),
|
||||
ast::UintTy::U8 => Type::i8(ccx),
|
||||
ast::UintTy::U16 => Type::i16(ccx),
|
||||
ast::UintTy::U32 => Type::i32(ccx),
|
||||
@ -207,7 +207,7 @@ impl Type {
|
||||
|
||||
pub fn vec(ccx: &CrateContext, ty: &Type) -> Type {
|
||||
Type::struct_(ccx,
|
||||
&[Type::array(ty, 0), Type::int(ccx)],
|
||||
&[Type::array(ty, 0), Type::isize(ccx)],
|
||||
false)
|
||||
}
|
||||
|
||||
|
@ -148,8 +148,8 @@ pub fn in_memory_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) ->
|
||||
}
|
||||
|
||||
ty::TyArray(ty, size) => {
|
||||
let size = size as u64;
|
||||
let llty = in_memory_type_of(cx, ty);
|
||||
let size = size.val.to_const_int().unwrap().to_u64().unwrap();
|
||||
Type::array(&llty, size)
|
||||
}
|
||||
|
||||
|
@ -12,7 +12,7 @@
|
||||
//! representation. The main routine here is `ast_ty_to_ty()`: each use
|
||||
//! is parameterized by an instance of `AstConv`.
|
||||
|
||||
use rustc::middle::const_val::eval_length;
|
||||
use rustc::middle::const_val::ConstVal;
|
||||
use rustc_data_structures::accumulate_vec::AccumulateVec;
|
||||
use hir;
|
||||
use hir::def::Def;
|
||||
@ -1082,11 +1082,14 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
|
||||
self.associated_path_def_to_ty(ast_ty.id, ast_ty.span, ty, def, segment).0
|
||||
}
|
||||
hir::TyArray(ref ty, length) => {
|
||||
if let Ok(length) = eval_length(tcx, length, "array length") {
|
||||
tcx.mk_array(self.ast_ty_to_ty(&ty), length)
|
||||
} else {
|
||||
self.tcx().types.err
|
||||
}
|
||||
let length_def_id = tcx.hir.body_owner_def_id(length);
|
||||
let substs = Substs::identity_for_item(tcx, length_def_id);
|
||||
let length = tcx.mk_const(ty::Const {
|
||||
val: ConstVal::Unevaluated(length_def_id, substs),
|
||||
ty: tcx.types.usize
|
||||
});
|
||||
let array_ty = tcx.mk_ty(ty::TyArray(self.ast_ty_to_ty(&ty), length));
|
||||
self.normalize_ty(ast_ty.span, array_ty)
|
||||
}
|
||||
hir::TyTypeof(ref _e) => {
|
||||
struct_span_err!(tcx.sess, ast_ty.span, E0516,
|
||||
|
@ -264,7 +264,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
let expected_ty = self.structurally_resolved_type(pat.span, expected);
|
||||
let (inner_ty, slice_ty) = match expected_ty.sty {
|
||||
ty::TyArray(inner_ty, size) => {
|
||||
let min_len = before.len() + after.len();
|
||||
let size = size.val.to_const_int().unwrap().to_u64().unwrap();
|
||||
let min_len = before.len() as u64 + after.len() as u64;
|
||||
if slice.is_none() {
|
||||
if min_len != size {
|
||||
struct_span_err!(
|
||||
|
@ -192,6 +192,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
ty::Predicate::TypeOutlives(..) => None,
|
||||
ty::Predicate::WellFormed(..) => None,
|
||||
ty::Predicate::ObjectSafe(..) => None,
|
||||
ty::Predicate::ConstEvaluatable(..) => None,
|
||||
|
||||
// NB: This predicate is created by breaking down a
|
||||
// `ClosureType: FnFoo()` predicate, where
|
||||
|
@ -360,7 +360,7 @@ pub fn check_platform_intrinsic_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
match name["simd_shuffle".len()..].parse() {
|
||||
Ok(n) => {
|
||||
let params = vec![param(0), param(0),
|
||||
tcx.mk_ty(ty::TyArray(tcx.types.u32, n))];
|
||||
tcx.mk_array(tcx.types.u32, n)];
|
||||
(2, params, param(1))
|
||||
}
|
||||
Err(_) => {
|
||||
|
@ -590,7 +590,8 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
|
||||
ty::Predicate::WellFormed(..) |
|
||||
ty::Predicate::ObjectSafe(..) |
|
||||
ty::Predicate::ClosureKind(..) |
|
||||
ty::Predicate::TypeOutlives(..) => None,
|
||||
ty::Predicate::TypeOutlives(..) |
|
||||
ty::Predicate::ConstEvaluatable(..) => None,
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
|
@ -128,7 +128,6 @@ use rustc::hir::map::Node;
|
||||
use rustc::hir::{self, PatKind};
|
||||
use rustc::middle::lang_items;
|
||||
use rustc_back::slice;
|
||||
use rustc::middle::const_val::eval_length;
|
||||
use rustc_const_math::ConstInt;
|
||||
|
||||
mod autoderef;
|
||||
@ -2636,7 +2635,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
ast::LitKind::Str(..) => tcx.mk_static_str(),
|
||||
ast::LitKind::ByteStr(ref v) => {
|
||||
tcx.mk_imm_ref(tcx.types.re_static,
|
||||
tcx.mk_array(tcx.types.u8, v.len()))
|
||||
tcx.mk_array(tcx.types.u8, v.len() as u64))
|
||||
}
|
||||
ast::LitKind::Byte(_) => tcx.types.u8,
|
||||
ast::LitKind::Char(_) => tcx.types.char,
|
||||
@ -3895,11 +3894,17 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
} else {
|
||||
self.next_ty_var(TypeVariableOrigin::TypeInference(expr.span))
|
||||
};
|
||||
tcx.mk_array(element_ty, args.len())
|
||||
tcx.mk_array(element_ty, args.len() as u64)
|
||||
}
|
||||
hir::ExprRepeat(ref element, count) => {
|
||||
let count = eval_length(self.tcx, count, "repeat count")
|
||||
.unwrap_or(0);
|
||||
let count_def_id = tcx.hir.body_owner_def_id(count);
|
||||
let param_env = ty::ParamEnv::empty(traits::Reveal::UserFacing);
|
||||
let substs = Substs::identity_for_item(tcx.global_tcx(), count_def_id);
|
||||
let count = tcx.const_eval(param_env.and((count_def_id, substs)));
|
||||
|
||||
if let Err(ref err) = count {
|
||||
err.report(tcx, tcx.def_span(count_def_id), "constant expression");
|
||||
}
|
||||
|
||||
let uty = match expected {
|
||||
ExpectHasType(uty) => {
|
||||
@ -3923,17 +3928,24 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
}
|
||||
};
|
||||
|
||||
if count > 1 {
|
||||
// For [foo, ..n] where n > 1, `foo` must have
|
||||
// Copy type:
|
||||
let lang_item = self.tcx.require_lang_item(lang_items::CopyTraitLangItem);
|
||||
self.require_type_meets(t, expr.span, traits::RepeatVec, lang_item);
|
||||
if let Ok(count) = count {
|
||||
let zero_or_one = count.val.to_const_int().and_then(|count| {
|
||||
count.to_u64().map(|count| count <= 1)
|
||||
}).unwrap_or(false);
|
||||
if !zero_or_one {
|
||||
// For [foo, ..n] where n > 1, `foo` must have
|
||||
// Copy type:
|
||||
let lang_item = self.tcx.require_lang_item(lang_items::CopyTraitLangItem);
|
||||
self.require_type_meets(t, expr.span, traits::RepeatVec, lang_item);
|
||||
}
|
||||
}
|
||||
|
||||
if element_ty.references_error() {
|
||||
tcx.types.err
|
||||
} else if let Ok(count) = count {
|
||||
tcx.mk_ty(ty::TyArray(t, count))
|
||||
} else {
|
||||
tcx.mk_array(t, count)
|
||||
tcx.types.err
|
||||
}
|
||||
}
|
||||
hir::ExprTup(ref elts) => {
|
||||
|
@ -511,7 +511,8 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> {
|
||||
ty::Predicate::Subtype(..) |
|
||||
ty::Predicate::Projection(..) |
|
||||
ty::Predicate::ClosureKind(..) |
|
||||
ty::Predicate::ObjectSafe(..) =>
|
||||
ty::Predicate::ObjectSafe(..) |
|
||||
ty::Predicate::ConstEvaluatable(..) =>
|
||||
vec![],
|
||||
|
||||
ty::Predicate::WellFormed(subty) => {
|
||||
|
@ -572,7 +572,7 @@ fn convert_enum_variant_types<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
}
|
||||
|
||||
match result {
|
||||
Ok(ConstVal::Integral(x)) => Some(x),
|
||||
Ok(&ty::Const { val: ConstVal::Integral(x), .. }) => Some(x),
|
||||
_ => None
|
||||
}
|
||||
} else if let Some(discr) = repr_type.disr_incr(tcx, prev_discr) {
|
||||
|
@ -27,11 +27,13 @@ use syntax::ptr::P;
|
||||
use syntax::symbol::keywords;
|
||||
use syntax_pos::{self, DUMMY_SP, Pos};
|
||||
|
||||
use rustc::middle::const_val::ConstVal;
|
||||
use rustc::middle::privacy::AccessLevels;
|
||||
use rustc::middle::resolve_lifetime as rl;
|
||||
use rustc::middle::lang_items;
|
||||
use rustc::hir::def::{Def, CtorKind};
|
||||
use rustc::hir::def_id::{CrateNum, DefId, CRATE_DEF_INDEX, LOCAL_CRATE};
|
||||
use rustc::traits::Reveal;
|
||||
use rustc::ty::subst::Substs;
|
||||
use rustc::ty::{self, AdtKind};
|
||||
use rustc::middle::stability;
|
||||
@ -40,6 +42,7 @@ use rustc_typeck::hir_ty_to_ty;
|
||||
|
||||
use rustc::hir;
|
||||
|
||||
use rustc_const_math::ConstInt;
|
||||
use std::{mem, slice, vec};
|
||||
use std::path::PathBuf;
|
||||
use std::rc::Rc;
|
||||
@ -934,6 +937,7 @@ impl<'a> Clean<WherePredicate> for ty::Predicate<'a> {
|
||||
Predicate::WellFormed(_) => panic!("not user writable"),
|
||||
Predicate::ObjectSafe(_) => panic!("not user writable"),
|
||||
Predicate::ClosureKind(..) => panic!("not user writable"),
|
||||
Predicate::ConstEvaluatable(..) => panic!("not user writable"),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1555,7 +1559,7 @@ pub enum Type {
|
||||
BareFunction(Box<BareFunctionDecl>),
|
||||
Tuple(Vec<Type>),
|
||||
Slice(Box<Type>),
|
||||
Array(Box<Type>, usize),
|
||||
Array(Box<Type>, String),
|
||||
Never,
|
||||
Unique(Box<Type>),
|
||||
RawPointer(Mutability, Box<Type>),
|
||||
@ -1782,9 +1786,16 @@ impl Clean<Type> for hir::Ty {
|
||||
type_: box m.ty.clean(cx)}
|
||||
}
|
||||
TySlice(ref ty) => Slice(box ty.clean(cx)),
|
||||
TyArray(ref ty, length) => {
|
||||
use rustc::middle::const_val::eval_length;
|
||||
let n = eval_length(cx.tcx, length, "array length").unwrap();
|
||||
TyArray(ref ty, n) => {
|
||||
let def_id = cx.tcx.hir.body_owner_def_id(n);
|
||||
let param_env = ty::ParamEnv::empty(Reveal::UserFacing);
|
||||
let substs = Substs::identity_for_item(cx.tcx, def_id);
|
||||
let n = cx.tcx.const_eval(param_env.and((def_id, substs))).unwrap();
|
||||
let n = if let ConstVal::Integral(ConstInt::Usize(n)) = n.val {
|
||||
n.to_string()
|
||||
} else {
|
||||
format!("{:?}", n)
|
||||
};
|
||||
Array(box ty.clean(cx), n)
|
||||
},
|
||||
TyTup(ref tys) => Tuple(tys.clean(cx)),
|
||||
@ -1895,7 +1906,14 @@ impl<'tcx> Clean<Type> for ty::Ty<'tcx> {
|
||||
ty::TyFloat(float_ty) => Primitive(float_ty.into()),
|
||||
ty::TyStr => Primitive(PrimitiveType::Str),
|
||||
ty::TySlice(ty) => Slice(box ty.clean(cx)),
|
||||
ty::TyArray(ty, n) => Array(box ty.clean(cx), n),
|
||||
ty::TyArray(ty, n) => {
|
||||
let n = if let ConstVal::Integral(ConstInt::Usize(n)) = n.val {
|
||||
n.to_string()
|
||||
} else {
|
||||
format!("{:?}", n)
|
||||
};
|
||||
Array(box ty.clean(cx), n)
|
||||
}
|
||||
ty::TyRawPtr(mt) => RawPointer(mt.mutbl.clean(cx), box mt.ty.clean(cx)),
|
||||
ty::TyRef(r, mt) => BorrowedRef {
|
||||
lifetime: r.clean(cx),
|
||||
|
@ -633,7 +633,7 @@ fn fmt_type(t: &clean::Type, f: &mut fmt::Formatter, use_absolute: bool) -> fmt:
|
||||
fmt::Display::fmt(t, f)?;
|
||||
primitive_link(f, PrimitiveType::Slice, "]")
|
||||
}
|
||||
clean::Array(ref t, n) => {
|
||||
clean::Array(ref t, ref n) => {
|
||||
primitive_link(f, PrimitiveType::Array, "[")?;
|
||||
fmt::Display::fmt(t, f)?;
|
||||
primitive_link(f, PrimitiveType::Array, &format!("; {}]", n))
|
||||
|
@ -32,6 +32,7 @@ extern crate html_diff;
|
||||
extern crate libc;
|
||||
extern crate rustc;
|
||||
extern crate rustc_data_structures;
|
||||
extern crate rustc_const_math;
|
||||
extern crate rustc_trans;
|
||||
extern crate rustc_driver;
|
||||
extern crate rustc_resolve;
|
||||
|
15
src/test/compile-fail/const-block-non-item-statement-3.rs
Normal file
15
src/test/compile-fail/const-block-non-item-statement-3.rs
Normal file
@ -0,0 +1,15 @@
|
||||
// Copyright 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.
|
||||
|
||||
type Array = [u32; { let x = 2; 5 }];
|
||||
//~^ ERROR: blocks in constants are limited to items and tail expressions
|
||||
//~^^ ERROR: blocks in constants are limited to items and tail expressions
|
||||
|
||||
pub fn main() {}
|
@ -14,8 +14,4 @@ enum Foo {
|
||||
//~^^ ERROR: blocks in constants are limited to items and tail expressions
|
||||
}
|
||||
|
||||
type Array = [u32; { let x = 2; 5 }];
|
||||
//~^ ERROR: blocks in constants are limited to items and tail expressions
|
||||
//~^^ ERROR: blocks in constants are limited to items and tail expressions
|
||||
|
||||
pub fn main() {}
|
||||
|
@ -23,5 +23,5 @@ const fn f(x: usize) -> usize {
|
||||
|
||||
#[allow(unused_variables)]
|
||||
fn main() {
|
||||
let a : [i32; f(X)]; //~ NOTE for array length here
|
||||
let a : [i32; f(X)]; //~ NOTE for constant expression here
|
||||
}
|
||||
|
@ -20,5 +20,5 @@ const LEN: usize = ONE - TWO;
|
||||
|
||||
fn main() {
|
||||
let a: [i8; LEN] = unimplemented!();
|
||||
//~^ NOTE for array length here
|
||||
//~^ NOTE for constant expression here
|
||||
}
|
||||
|
@ -8,11 +8,12 @@
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// error-pattern: unsupported cyclic reference between types/traits detected
|
||||
|
||||
#![feature(const_fn)]
|
||||
|
||||
struct Foo {
|
||||
bytes: [u8; std::mem::size_of::<Foo>()]
|
||||
//~^ ERROR unsupported cyclic reference between types/traits detected
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user