diff --git a/compiler/rustc_middle/src/ty/consts.rs b/compiler/rustc_middle/src/ty/consts.rs index 47abbb723dc..fe5c5be15f5 100644 --- a/compiler/rustc_middle/src/ty/consts.rs +++ b/compiler/rustc_middle/src/ty/consts.rs @@ -199,6 +199,14 @@ pub fn from_value(tcx: TyCtxt<'tcx>, val: ty::ValTree<'tcx>, ty: Ty<'tcx>) -> Se tcx.mk_const(ConstS { kind: ConstKind::Value(val), ty }) } + /// Panics if self.kind != ty::ConstKind::Value + pub fn to_valtree(self) -> ty::ValTree<'tcx> { + match self.val() { + ty::ConstKind::Value(valtree) => valtree, + _ => bug!("expected ConstKind::Value"), + } + } + pub fn from_scalar_int(tcx: TyCtxt<'tcx>, i: ScalarInt, ty: Ty<'tcx>) -> Self { let valtree = ty::ValTree::from_scalar_int(i); Self::from_value(tcx, valtree, ty) diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs index e28cb67217c..f5d957e30ff 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs @@ -798,7 +798,7 @@ pub(crate) fn compare_const_vals<'tcx>( if let ty::Str = ty.kind() && let ( Some(a_val @ ConstValue::Slice { .. }), Some(b_val @ ConstValue::Slice { .. }), - ) = (a.try_val(tcx), b.try_val(tcx)) + ) = (a.try_to_value(tcx), b.try_to_value(tcx)) { let a_bytes = get_slice_bytes(&tcx, a_val); let b_bytes = get_slice_bytes(&tcx, b_val); diff --git a/src/tools/clippy/clippy_lints/src/enum_clike.rs b/src/tools/clippy/clippy_lints/src/enum_clike.rs index 5d687d06f6f..b326d864d4b 100644 --- a/src/tools/clippy/clippy_lints/src/enum_clike.rs +++ b/src/tools/clippy/clippy_lints/src/enum_clike.rs @@ -48,9 +48,9 @@ fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) { let mut ty = cx.tcx.type_of(def_id.to_def_id()); let constant = cx .tcx - .const_eval_poly_for_typeck(def_id.to_def_id()) + .const_eval_poly(def_id.to_def_id()) .ok() - .and_then(|val| val.map(|valtree| rustc_middle::ty::Const::from_value(cx.tcx, valtree, ty))); + .and_then(|val| Some(rustc_middle::mir::ConstantKind::from_value(val, ty))); if let Some(Constant::Int(val)) = constant.and_then(|c| miri_to_const(cx.tcx, c)) { if let ty::Adt(adt, _) = ty.kind() { if adt.is_enum() { diff --git a/src/tools/clippy/clippy_lints/src/matches/overlapping_arms.rs b/src/tools/clippy/clippy_lints/src/matches/overlapping_arms.rs index afca7530556..ae69ca8a339 100644 --- a/src/tools/clippy/clippy_lints/src/matches/overlapping_arms.rs +++ b/src/tools/clippy/clippy_lints/src/matches/overlapping_arms.rs @@ -3,6 +3,7 @@ use core::cmp::Ordering; use rustc_hir::{Arm, Expr, PatKind, RangeEnd}; use rustc_lint::LateContext; +use rustc_middle::mir; use rustc_middle::ty::Ty; use rustc_span::Span; @@ -34,11 +35,25 @@ fn all_ranges<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'_>], ty: Ty<'tcx>) if let PatKind::Range(ref lhs, ref rhs, range_end) = pat.kind { let lhs_const = match lhs { Some(lhs) => constant(cx, cx.typeck_results(), lhs)?.0, - None => miri_to_const(cx.tcx, ty.numeric_min_val(cx.tcx)?)?, + None => { + let min_val_const = ty.numeric_min_val(cx.tcx)?; + let min_constant = mir::ConstantKind::from_value( + cx.tcx.valtree_to_const_val((ty, min_val_const.to_valtree())), + ty, + ); + miri_to_const(cx.tcx, min_constant)? + }, }; let rhs_const = match rhs { Some(rhs) => constant(cx, cx.typeck_results(), rhs)?.0, - None => miri_to_const(cx.tcx, ty.numeric_max_val(cx.tcx)?)?, + None => { + let max_val_const = ty.numeric_max_val(cx.tcx)?; + let max_constant = mir::ConstantKind::from_value( + cx.tcx.valtree_to_const_val((ty, max_val_const.to_valtree())), + ty, + ); + miri_to_const(cx.tcx, max_constant)? + }, }; let lhs_val = lhs_const.int_value(cx, ty)?; let rhs_val = rhs_const.int_value(cx, ty)?; diff --git a/src/tools/clippy/clippy_lints/src/non_copy_const.rs b/src/tools/clippy/clippy_lints/src/non_copy_const.rs index 9f6fca27b22..7163cfe5e3a 100644 --- a/src/tools/clippy/clippy_lints/src/non_copy_const.rs +++ b/src/tools/clippy/clippy_lints/src/non_copy_const.rs @@ -13,9 +13,10 @@ BodyId, Expr, ExprKind, HirId, Impl, ImplItem, ImplItemKind, Item, ItemKind, Node, TraitItem, TraitItemKind, UnOp, }; use rustc_lint::{LateContext, LateLintPass, Lint}; -use rustc_middle::mir::interpret::ErrorHandled; +use rustc_middle::mir; +use rustc_middle::mir::interpret::{ConstValue, ErrorHandled}; use rustc_middle::ty::adjustment::Adjust; -use rustc_middle::ty::{self, Const, Ty}; +use rustc_middle::ty::{self, Ty}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::{InnerSpan, Span, DUMMY_SP}; use rustc_typeck::hir_ty_to_ty; @@ -133,22 +134,21 @@ fn is_unfrozen<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool { fn is_value_unfrozen_raw<'tcx>( cx: &LateContext<'tcx>, - result: Result>, ErrorHandled>, + result: Result, ErrorHandled>, ty: Ty<'tcx>, ) -> bool { - fn inner<'tcx>(cx: &LateContext<'tcx>, val: Const<'tcx>) -> bool { + fn inner<'tcx>(cx: &LateContext<'tcx>, val: mir::ConstantKind<'tcx>) -> bool { match val.ty().kind() { // the fact that we have to dig into every structs to search enums // leads us to the point checking `UnsafeCell` directly is the only option. ty::Adt(ty_def, ..) if Some(ty_def.did()) == cx.tcx.lang_items().unsafe_cell_type() => true, ty::Array(..) | ty::Adt(..) | ty::Tuple(..) => { - let val = cx.tcx.destructure_const(val); + let val = cx.tcx.destructure_mir_constant(cx.param_env, val); val.fields.iter().any(|field| inner(cx, *field)) }, _ => false, } } - result.map_or_else( |err| { // Consider `TooGeneric` cases as being unfrozen. @@ -174,19 +174,19 @@ fn inner<'tcx>(cx: &LateContext<'tcx>, val: Const<'tcx>) -> bool { // I chose this way because unfrozen enums as assoc consts are rare (or, hopefully, none). err == ErrorHandled::TooGeneric }, - |val| val.map_or(false, |val| inner(cx, Const::from_value(cx.tcx, val, ty))), + |val| inner(cx, mir::ConstantKind::from_value(val, ty)), ) } fn is_value_unfrozen_poly<'tcx>(cx: &LateContext<'tcx>, body_id: BodyId, ty: Ty<'tcx>) -> bool { - let result = cx.tcx.const_eval_poly_for_typeck(body_id.hir_id.owner.to_def_id()); + let result = cx.tcx.const_eval_poly(body_id.hir_id.owner.to_def_id()); is_value_unfrozen_raw(cx, result, ty) } fn is_value_unfrozen_expr<'tcx>(cx: &LateContext<'tcx>, hir_id: HirId, def_id: DefId, ty: Ty<'tcx>) -> bool { let substs = cx.typeck_results().node_substs(hir_id); - let result = cx.tcx.const_eval_resolve_for_typeck( + let result = cx.tcx.const_eval_resolve( cx.param_env, ty::Unevaluated::new(ty::WithOptConstParam::unknown(def_id), substs), None, diff --git a/src/tools/clippy/clippy_utils/src/consts.rs b/src/tools/clippy/clippy_utils/src/consts.rs index c31c560f427..ec323806fbf 100644 --- a/src/tools/clippy/clippy_utils/src/consts.rs +++ b/src/tools/clippy/clippy_utils/src/consts.rs @@ -7,6 +7,8 @@ use rustc_hir::def::{DefKind, Res}; use rustc_hir::{BinOp, BinOpKind, Block, Expr, ExprKind, HirId, Item, ItemKind, Node, QPath, UnOp}; use rustc_lint::LateContext; +use rustc_middle::mir; +use rustc_middle::mir::interpret::Scalar; use rustc_middle::ty::subst::{Subst, SubstsRef}; use rustc_middle::ty::{self, EarlyBinder, FloatTy, ScalarInt, Ty, TyCtxt}; use rustc_middle::{bug, span_bug}; @@ -422,13 +424,13 @@ fn fetch_path(&mut self, qpath: &QPath<'_>, id: HirId, ty: Ty<'tcx>) -> Option, right: &Expr<'_>) -> Option(tcx: TyCtxt<'tcx>, result: ty::Const<'tcx>) -> Option { - match result.kind() { +fn try_const_to_constant<'tcx>(tcx: TyCtxt<'tcx>, c: ty::Const<'tcx>) -> Option { + match c.kind() { ty::ConstKind::Value(valtree) => { - match (valtree, result.ty().kind()) { - (ty::ValTree::Leaf(int), ty::Bool) => Some(Constant::Bool(int == ScalarInt::TRUE)), - (ty::ValTree::Leaf(int), ty::Uint(_) | ty::Int(_)) => Some(Constant::Int(int.assert_bits(int.size()))), - (ty::ValTree::Leaf(int), ty::Float(FloatTy::F32)) => Some(Constant::F32(f32::from_bits( + let const_val = tcx.valtree_to_const_val((c.ty(), valtree)); + miri_to_const(tcx, mir::ConstantKind::from_value(const_val, c.ty())) + }, + _ => None, + } +} + +pub fn miri_to_const<'tcx>(tcx: TyCtxt<'tcx>, result: mir::ConstantKind<'tcx>) -> Option { + use rustc_middle::mir::interpret::ConstValue; + match result { + mir::ConstantKind::Val(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::ValTree::Leaf(int), ty::Float(FloatTy::F64)) => Some(Constant::F64(f64::from_bits( + ty::Float(FloatTy::F64) => Some(Constant::F64(f64::from_bits( int.try_into().expect("invalid f64 bit representation"), ))), - (ty::ValTree::Leaf(int), ty::RawPtr(type_and_mut)) => { + ty::RawPtr(type_and_mut) => { if let ty::Uint(_) = type_and_mut.ty.kind() { return Some(Constant::RawPtr(int.assert_bits(int.size()))); } None }, - (ty::ValTree::Branch(_), ty::Ref(_, inner_ty, _)) if *inner_ty == tcx.types.str_ => valtree - .try_to_raw_bytes(tcx, result.ty()) - .and_then(|bytes| String::from_utf8(bytes.to_owned()).ok().map(Constant::Str)), - (ty::ValTree::Branch(_), ty::Array(arr_ty, len)) => match arr_ty.kind() { - ty::Float(float_ty) => { - let chunk_size = match float_ty { - FloatTy::F32 => 4, - FloatTy::F64 => 8, - }; - - match miri_to_const(tcx, *len) { - Some(Constant::Int(_)) => valtree.try_to_raw_bytes(tcx, result.ty()).and_then(|bytes| { - bytes - .to_owned() - .chunks(chunk_size) - .map(|chunk| match float_ty { - FloatTy::F32 => { - let float = f32::from_le_bytes( - chunk - .try_into() - .expect(&format!("expected to construct f32 from {:?}", chunk)), - ); - Some(Constant::F32(float)) - }, - FloatTy::F64 => { - let float = f64::from_le_bytes( - chunk - .try_into() - .expect(&format!("expected to construct f64 from {:?}", chunk)), - ); - Some(Constant::F64(float)) - }, - }) - .collect::>>() - .map(Constant::Vec) - }), - _ => None, - } - }, - _ => None, - }, // FIXME: implement other conversions. _ => None, } }, + mir::ConstantKind::Val(ConstValue::Slice { data, start, end }, _) => match result.ty().kind() { + ty::Ref(_, tam, _) => match tam.kind() { + ty::Str => String::from_utf8( + data.inner() + .inspect_with_uninit_and_ptr_outside_interpreter(start..end) + .to_owned(), + ) + .ok() + .map(Constant::Str), + _ => None, + }, + _ => None, + }, + mir::ConstantKind::Val(ConstValue::ByRef { alloc, offset: _ }, _) => match result.ty().kind() { + ty::Array(sub_type, len) => match sub_type.kind() { + ty::Float(FloatTy::F32) => match try_const_to_constant(tcx, *len) { + Some(Constant::Int(len)) => alloc + .inner() + .inspect_with_uninit_and_ptr_outside_interpreter(0..(4 * len as usize)) + .to_owned() + .chunks(4) + .map(|chunk| { + Some(Constant::F32(f32::from_le_bytes( + chunk.try_into().expect("this shouldn't happen"), + ))) + }) + .collect::>>() + .map(Constant::Vec), + _ => None, + }, + ty::Float(FloatTy::F64) => match try_const_to_constant(tcx, *len) { + Some(Constant::Int(len)) => alloc + .inner() + .inspect_with_uninit_and_ptr_outside_interpreter(0..(8 * len as usize)) + .to_owned() + .chunks(8) + .map(|chunk| { + Some(Constant::F64(f64::from_le_bytes( + chunk.try_into().expect("this shouldn't happen"), + ))) + }) + .collect::>>() + .map(Constant::Vec), + _ => None, + }, + // FIXME: implement other array type conversions. + _ => None, + }, + _ => None, + }, + // FIXME: implement other conversions. _ => None, } }