use rustc_hir::def::{DefKind, Res};
use rustc_hir::{BinOp, BinOpKind, Block, Expr, ExprKind, HirId, QPath, UnOp};
use rustc_lint::LateContext;
+use rustc_middle::mir::interpret::Scalar;
use rustc_middle::ty::subst::{Subst, SubstsRef};
-use rustc_middle::ty::{self, Ty, TyCtxt};
+use rustc_middle::ty::{self, ScalarInt, Ty, TyCtxt};
use rustc_middle::{bug, span_bug};
use rustc_span::symbol::Symbol;
use std::cmp::Ordering::{self, Equal};
/// A `String` (e.g., "abc").
Str(String),
/// A binary string (e.g., `b"abc"`).
- Binary(Lrc<Vec<u8>>),
+ Binary(Lrc<[u8]>),
/// A single `char` (e.g., `'a'`).
Char(char),
/// An integer's bit representation.
Tuple(Vec<Constant>),
/// A raw pointer.
RawPtr(u128),
+ /// A reference
+ Ref(Box<Constant>),
/// A literal with syntax error.
Err(Symbol),
}
(&Self::Bool(l), &Self::Bool(r)) => l == r,
(&Self::Vec(ref l), &Self::Vec(ref r)) | (&Self::Tuple(ref l), &Self::Tuple(ref r)) => l == r,
(&Self::Repeat(ref lv, ref ls), &Self::Repeat(ref rv, ref rs)) => ls == rs && lv == rv,
+ (&Self::Ref(ref lb), &Self::Ref(ref rb)) => *lb == *rb,
// TODO: are there inter-type equalities?
_ => false,
}
Self::RawPtr(u) => {
u.hash(state);
},
+ Self::Ref(ref r) => {
+ r.hash(state);
+ },
Self::Err(ref s) => {
s.hash(state);
},
(&Self::Str(ref ls), &Self::Str(ref rs)) => Some(ls.cmp(rs)),
(&Self::Char(ref l), &Self::Char(ref r)) => Some(l.cmp(r)),
(&Self::Int(l), &Self::Int(r)) => {
- if let ty::Int(int_ty) = cmp_type.kind {
+ if let ty::Int(int_ty) = *cmp_type.kind() {
Some(sext(tcx, l, int_ty).cmp(&sext(tcx, r, int_ty)))
} else {
Some(l.cmp(&r))
x => x,
}
},
+ (&Self::Ref(ref lb), &Self::Ref(ref rb)) => Self::partial_cmp(tcx, cmp_type, lb, rb),
// TODO: are there any useful inter-type orderings?
_ => None,
}
FloatTy::F32 => Constant::F32(is.as_str().parse().unwrap()),
FloatTy::F64 => Constant::F64(is.as_str().parse().unwrap()),
},
- LitKind::Float(ref is, LitFloatType::Unsuffixed) => match ty.expect("type of float is known").kind {
+ LitKind::Float(ref is, LitFloatType::Unsuffixed) => match ty.expect("type of float is known").kind() {
ty::Float(FloatTy::F32) => Constant::F32(is.as_str().parse().unwrap()),
ty::Float(FloatTy::F64) => Constant::F64(is.as_str().parse().unwrap()),
_ => bug!(),
pub fn constant<'tcx>(
lcx: &LateContext<'tcx>,
- tables: &ty::TypeckTables<'tcx>,
+ typeck_results: &ty::TypeckResults<'tcx>,
e: &Expr<'_>,
) -> Option<(Constant, bool)> {
let mut cx = ConstEvalLateContext {
lcx,
- tables,
+ typeck_results,
param_env: lcx.param_env,
needed_resolution: false,
substs: lcx.tcx.intern_substs(&[]),
pub fn constant_simple<'tcx>(
lcx: &LateContext<'tcx>,
- tables: &ty::TypeckTables<'tcx>,
+ typeck_results: &ty::TypeckResults<'tcx>,
e: &Expr<'_>,
) -> Option<Constant> {
- constant(lcx, tables, e).and_then(|(cst, res)| if res { None } else { Some(cst) })
+ constant(lcx, typeck_results, e).and_then(|(cst, res)| if res { None } else { Some(cst) })
}
-/// Creates a `ConstEvalLateContext` from the given `LateContext` and `TypeckTables`.
+/// Creates a `ConstEvalLateContext` from the given `LateContext` and `TypeckResults`.
pub fn constant_context<'a, 'tcx>(
lcx: &'a LateContext<'tcx>,
- tables: &'a ty::TypeckTables<'tcx>,
+ typeck_results: &'a ty::TypeckResults<'tcx>,
) -> ConstEvalLateContext<'a, 'tcx> {
ConstEvalLateContext {
lcx,
- tables,
+ typeck_results,
param_env: lcx.param_env,
needed_resolution: false,
substs: lcx.tcx.intern_substs(&[]),
pub struct ConstEvalLateContext<'a, 'tcx> {
lcx: &'a LateContext<'tcx>,
- tables: &'a ty::TypeckTables<'tcx>,
+ typeck_results: &'a ty::TypeckResults<'tcx>,
param_env: ty::ParamEnv<'tcx>,
needed_resolution: bool,
substs: SubstsRef<'tcx>,
return self.ifthenelse(cond, then, otherwise);
}
match e.kind {
- ExprKind::Path(ref qpath) => self.fetch_path(qpath, e.hir_id, self.tables.expr_ty(e)),
+ ExprKind::Path(ref qpath) => self.fetch_path(qpath, e.hir_id, self.typeck_results.expr_ty(e)),
ExprKind::Block(ref block, _) => self.block(block),
- ExprKind::Lit(ref lit) => Some(lit_to_constant(&lit.node, self.tables.expr_ty_opt(e))),
+ ExprKind::Lit(ref lit) => Some(lit_to_constant(&lit.node, self.typeck_results.expr_ty_opt(e))),
ExprKind::Array(ref vec) => self.multi(vec).map(Constant::Vec),
ExprKind::Tup(ref tup) => self.multi(tup).map(Constant::Tuple),
ExprKind::Repeat(ref value, _) => {
- let n = match self.tables.expr_ty(e).kind {
+ let n = match self.typeck_results.expr_ty(e).kind() {
ty::Array(_, n) => n.try_eval_usize(self.lcx.tcx, self.lcx.param_env)?,
_ => span_bug!(e.span, "typeck error"),
};
self.expr(value).map(|v| Constant::Repeat(Box::new(v), n))
},
ExprKind::Unary(op, ref operand) => self.expr(operand).and_then(|o| match op {
- UnOp::UnNot => self.constant_not(&o, self.tables.expr_ty(e)),
- UnOp::UnNeg => self.constant_negate(&o, self.tables.expr_ty(e)),
- UnOp::UnDeref => Some(o),
+ UnOp::UnNot => self.constant_not(&o, self.typeck_results.expr_ty(e)),
+ UnOp::UnNeg => self.constant_negate(&o, self.typeck_results.expr_ty(e)),
+ UnOp::UnDeref => Some(if let Constant::Ref(r) = o { *r } else { o }),
}),
ExprKind::Binary(op, ref left, ref right) => self.binop(op, left, right),
ExprKind::Call(ref callee, ref args) => {
if_chain! {
if args.is_empty();
if let ExprKind::Path(qpath) = &callee.kind;
- let res = self.tables.qpath_res(qpath, callee.hir_id);
+ let res = self.typeck_results.qpath_res(qpath, callee.hir_id);
if let Some(def_id) = res.opt_def_id();
let def_path: Vec<_> = self.lcx.get_def_path(def_id).into_iter().map(Symbol::as_str).collect();
let def_path: Vec<&str> = def_path.iter().take(4).map(|s| &**s).collect();
}
},
ExprKind::Index(ref arr, ref index) => self.index(arr, index),
+ ExprKind::AddrOf(_, _, ref inner) => self.expr(inner).map(|r| Constant::Ref(Box::new(r))),
// TODO: add other expressions.
_ => None,
}
Bool(b) => Some(Bool(!b)),
Int(value) => {
let value = !value;
- match ty.kind {
+ match *ty.kind() {
ty::Int(ity) => Some(Int(unsext(self.lcx.tcx, value as i128, ity))),
ty::Uint(ity) => Some(Int(clip(self.lcx.tcx, value, ity))),
_ => None,
use self::Constant::{Int, F32, F64};
match *o {
Int(value) => {
- let ity = match ty.kind {
+ let ity = match *ty.kind() {
ty::Int(ity) => ity,
_ => return None,
};
/// Lookup a possibly constant expression from a `ExprKind::Path`.
fn fetch_path(&mut self, qpath: &QPath<'_>, id: HirId, ty: Ty<'tcx>) -> Option<Constant> {
- let res = self.tables.qpath_res(qpath, id);
+ let res = self.typeck_results.qpath_res(qpath, id);
match res {
Res::Def(DefKind::Const | DefKind::AssocConst, def_id) => {
- let substs = self.tables.node_substs(id);
+ let substs = self.typeck_results.node_substs(id);
let substs = if self.substs.is_empty() {
substs
} else {
let result = self
.lcx
.tcx
- .const_eval_resolve(self.param_env, ty::WithOptConstParam::dummy(def_id), substs, None, None)
+ .const_eval_resolve(
+ self.param_env,
+ ty::WithOptConstParam::unknown(def_id),
+ substs,
+ None,
+ None,
+ )
.ok()
.map(|val| rustc_middle::ty::Const::from_value(self.lcx.tcx, val, ty))?;
let result = miri_to_const(&result);
let l = self.expr(left)?;
let r = self.expr(right);
match (l, r) {
- (Constant::Int(l), Some(Constant::Int(r))) => match self.tables.expr_ty_opt(left)?.kind {
+ (Constant::Int(l), Some(Constant::Int(r))) => match *self.typeck_results.expr_ty_opt(left)?.kind() {
ty::Int(ity) => {
let l = sext(self.lcx.tcx, l, ity);
let r = sext(self.lcx.tcx, r, ity);
}
pub fn miri_to_const(result: &ty::Const<'_>) -> Option<Constant> {
- use rustc_middle::mir::interpret::{ConstValue, Scalar};
+ use rustc_middle::mir::interpret::ConstValue;
match result.val {
- ty::ConstKind::Value(ConstValue::Scalar(Scalar::Raw { data: d, .. })) => match result.ty.kind {
- ty::Bool => Some(Constant::Bool(d == 1)),
- ty::Uint(_) | ty::Int(_) => Some(Constant::Int(d)),
- ty::Float(FloatTy::F32) => Some(Constant::F32(f32::from_bits(
- d.try_into().expect("invalid f32 bit representation"),
- ))),
- ty::Float(FloatTy::F64) => Some(Constant::F64(f64::from_bits(
- d.try_into().expect("invalid f64 bit representation"),
- ))),
- ty::RawPtr(type_and_mut) => {
- if let ty::Uint(_) = type_and_mut.ty.kind {
- return Some(Constant::RawPtr(d));
- }
- None
- },
- // FIXME: implement other conversions.
- _ => None,
+ ty::ConstKind::Value(ConstValue::Scalar(Scalar::Int(int))) => {
+ match result.ty.kind() {
+ ty::Bool => Some(Constant::Bool(int == ScalarInt::TRUE)),
+ ty::Uint(_) | ty::Int(_) => Some(Constant::Int(int.assert_bits(int.size()))),
+ ty::Float(FloatTy::F32) => Some(Constant::F32(f32::from_bits(
+ int.try_into().expect("invalid f32 bit representation"),
+ ))),
+ ty::Float(FloatTy::F64) => Some(Constant::F64(f64::from_bits(
+ int.try_into().expect("invalid f64 bit representation"),
+ ))),
+ ty::RawPtr(type_and_mut) => {
+ if let ty::Uint(_) = type_and_mut.ty.kind() {
+ return Some(Constant::RawPtr(int.assert_bits(int.size())));
+ }
+ None
+ },
+ // FIXME: implement other conversions.
+ _ => None,
+ }
},
- ty::ConstKind::Value(ConstValue::Slice { data, start, end }) => match result.ty.kind {
- ty::Ref(_, tam, _) => match tam.kind {
+ ty::ConstKind::Value(ConstValue::Slice { data, start, end }) => match result.ty.kind() {
+ ty::Ref(_, tam, _) => match tam.kind() {
ty::Str => String::from_utf8(
- data.inspect_with_undef_and_ptr_outside_interpreter(start..end)
+ data.inspect_with_uninit_and_ptr_outside_interpreter(start..end)
.to_owned(),
)
.ok()
},
_ => None,
},
- ty::ConstKind::Value(ConstValue::ByRef { alloc, offset: _ }) => match result.ty.kind {
- ty::Array(sub_type, len) => match sub_type.kind {
+ ty::ConstKind::Value(ConstValue::ByRef { alloc, offset: _ }) => match result.ty.kind() {
+ ty::Array(sub_type, len) => match sub_type.kind() {
ty::Float(FloatTy::F32) => match miri_to_const(len) {
Some(Constant::Int(len)) => alloc
- .inspect_with_undef_and_ptr_outside_interpreter(0..(4 * len as usize))
+ .inspect_with_uninit_and_ptr_outside_interpreter(0..(4 * len as usize))
.to_owned()
.chunks(4)
.map(|chunk| {
},
ty::Float(FloatTy::F64) => match miri_to_const(len) {
Some(Constant::Int(len)) => alloc
- .inspect_with_undef_and_ptr_outside_interpreter(0..(8 * len as usize))
+ .inspect_with_uninit_and_ptr_outside_interpreter(0..(8 * len as usize))
.to_owned()
.chunks(8)
.map(|chunk| {