Skip to content

Commit

Permalink
Use ScalarInt as early as possible...
Browse files Browse the repository at this point in the history
...instead of carrying around ty::Const and erroring later
  • Loading branch information
oli-obk committed Jul 12, 2021
1 parent 987b9fc commit b2a2286
Show file tree
Hide file tree
Showing 5 changed files with 61 additions and 69 deletions.
32 changes: 16 additions & 16 deletions compiler/rustc_middle/src/ty/util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ use rustc_target::abi::{Integer, Size, TargetDataLayout};
use smallvec::SmallVec;
use std::{fmt, iter};

use super::ScalarInt;

#[derive(Copy, Clone, Debug)]
pub struct Discr<'tcx> {
/// Bit representation of the discriminant (e.g., `-128i8` is `0xFF_u128`).
Expand Down Expand Up @@ -616,40 +618,38 @@ impl<'tcx> TypeFolder<'tcx> for OpaqueTypeExpander<'tcx> {
impl<'tcx> ty::TyS<'tcx> {
/// Returns the maximum value for the given numeric type (including `char`s)
/// or returns `None` if the type is not numeric.
pub fn numeric_max_val(&'tcx self, tcx: TyCtxt<'tcx>) -> Option<&'tcx ty::Const<'tcx>> {
let val = match self.kind() {
pub fn numeric_max_val(&'tcx self, tcx: TyCtxt<'tcx>) -> Option<ScalarInt> {
match self.kind() {
ty::Int(_) | ty::Uint(_) => {
let (size, signed) = int_size_and_signed(tcx, self);
let val = if signed { signed_max(size) as u128 } else { unsigned_max(size) };
Some(val)
Some(ScalarInt::from_uint(val, size))
}
ty::Char => Some(std::char::MAX as u128),
ty::Char => Some(ScalarInt::from(std::char::MAX)),
ty::Float(fty) => Some(match fty {
ty::FloatTy::F32 => rustc_apfloat::ieee::Single::INFINITY.to_bits(),
ty::FloatTy::F64 => rustc_apfloat::ieee::Double::INFINITY.to_bits(),
ty::FloatTy::F32 => ScalarInt::from(rustc_apfloat::ieee::Single::INFINITY),
ty::FloatTy::F64 => ScalarInt::from(rustc_apfloat::ieee::Double::INFINITY),
}),
_ => None,
};
val.map(|v| ty::Const::from_bits(tcx, v, ty::ParamEnv::empty().and(self)))
}
}

/// Returns the minimum value for the given numeric type (including `char`s)
/// or returns `None` if the type is not numeric.
pub fn numeric_min_val(&'tcx self, tcx: TyCtxt<'tcx>) -> Option<&'tcx ty::Const<'tcx>> {
let val = match self.kind() {
pub fn numeric_min_val(&'tcx self, tcx: TyCtxt<'tcx>) -> Option<ScalarInt> {
match self.kind() {
ty::Int(_) | ty::Uint(_) => {
let (size, signed) = int_size_and_signed(tcx, self);
let val = if signed { size.truncate(signed_min(size) as u128) } else { 0 };
Some(val)
Some(ScalarInt::from_uint(val, size))
}
ty::Char => Some(0),
ty::Char => Some(ScalarInt::from('\0')),
ty::Float(fty) => Some(match fty {
ty::FloatTy::F32 => (-::rustc_apfloat::ieee::Single::INFINITY).to_bits(),
ty::FloatTy::F64 => (-::rustc_apfloat::ieee::Double::INFINITY).to_bits(),
ty::FloatTy::F32 => ScalarInt::from(-::rustc_apfloat::ieee::Single::INFINITY),
ty::FloatTy::F64 => ScalarInt::from(-::rustc_apfloat::ieee::Double::INFINITY),
}),
_ => None,
};
val.map(|v| ty::Const::from_bits(tcx, v, ty::ParamEnv::empty().and(self)))
}
}

/// Checks whether values of this type `T` are *moved* or *copied*
Expand Down
33 changes: 12 additions & 21 deletions compiler/rustc_mir_build/src/thir/pattern/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ use rustc_middle::mir::UserTypeProjection;
use rustc_middle::mir::{BorrowKind, Field, Mutability};
use rustc_middle::thir::{Ascription, BindingMode, FieldPat, Pat, PatKind, PatRange, PatTyProj};
use rustc_middle::ty::subst::{GenericArg, SubstsRef};
use rustc_middle::ty::{self, AdtDef, DefIdTree, Region, Ty, TyCtxt, UserType};
use rustc_middle::ty::{self, AdtDef, DefIdTree, Region, ScalarInt, Ty, TyCtxt, UserType};
use rustc_span::{Span, Symbol};

use std::cmp::Ordering;
Expand Down Expand Up @@ -122,25 +122,14 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
fn lower_pattern_range(
&mut self,
ty: Ty<'tcx>,
lo: &'tcx ty::Const<'tcx>,
hi: &'tcx ty::Const<'tcx>,
lo: ScalarInt,
hi: ScalarInt,
end: RangeEnd,
span: Span,
) -> PatKind<'tcx> {
assert_eq!(lo.ty, ty);
assert_eq!(hi.ty, ty);
let cmp = compare_const_vals(self.tcx, lo, hi, self.param_env, ty);
let lo_const = lo;
let lo = lo
.val
.eval(self.tcx, self.param_env)
.try_to_scalar_int()
.expect("range patterns must be integral");
let hi = hi
.val
.eval(self.tcx, self.param_env)
.try_to_scalar_int()
.expect("range patterns must be integral");
let lo_const = ty::Const::from_value(self.tcx, ConstValue::Scalar(lo.into()), ty);
let hi_const = ty::Const::from_value(self.tcx, ConstValue::Scalar(hi.into()), ty);
let cmp = compare_const_vals(self.tcx, lo_const, hi_const, self.param_env, ty);
match (end, cmp) {
// `x..y` where `x < y`.
// Non-empty because the range includes at least `x`.
Expand Down Expand Up @@ -193,16 +182,18 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
ty: Ty<'tcx>,
lo: Option<&PatKind<'tcx>>,
hi: Option<&PatKind<'tcx>>,
) -> Option<(&'tcx ty::Const<'tcx>, &'tcx ty::Const<'tcx>)> {
) -> Option<(ScalarInt, ScalarInt)> {
let eval =
|value: &ty::Const<'tcx>| value.val.eval(self.tcx, self.param_env).try_to_scalar_int();
match (lo, hi) {
(Some(PatKind::Constant { value: lo }), Some(PatKind::Constant { value: hi })) => {
Some((lo, hi))
Some((eval(lo)?, eval(hi)?))
}
(Some(PatKind::Constant { value: lo }), None) => {
Some((lo, ty.numeric_max_val(self.tcx)?))
Some((eval(lo)?, ty.numeric_max_val(self.tcx)?))
}
(None, Some(PatKind::Constant { value: hi })) => {
Some((ty.numeric_min_val(self.tcx)?, hi))
Some((ty.numeric_min_val(self.tcx)?, eval(hi)?))
}
_ => None,
}
Expand Down
6 changes: 3 additions & 3 deletions src/tools/clippy/clippy_lints/src/enum_clike.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
//! lint on C-like enums that are `repr(isize/usize)` and have values that
//! don't fit into an `i32`
use clippy_utils::consts::{miri_to_const, Constant};
use clippy_utils::diagnostics::span_lint;
use rustc_hir::{Item, ItemKind};
use rustc_lint::{LateContext, LateLintPass};
Expand Down Expand Up @@ -50,8 +49,9 @@ impl<'tcx> LateLintPass<'tcx> for UnportableVariant {
.tcx
.const_eval_poly(def_id.to_def_id())
.ok()
.map(|val| rustc_middle::ty::Const::from_value(cx.tcx, val, ty));
if let Some(Constant::Int(val)) = constant.and_then(miri_to_const) {
.and_then(|c| c.try_to_scalar_int());
if let Some(scalar) = constant {
let val = scalar.to_bits(cx.tcx.layout_of(cx.param_env.and(ty)).unwrap().size).unwrap();
if let ty::Adt(adt, _) = ty.kind() {
if adt.is_enum() {
ty = adt.repr.discr_type().to_ty(cx.tcx);
Expand Down
11 changes: 9 additions & 2 deletions src/tools/clippy/clippy_lints/src/matches.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ use rustc_hir::{HirIdMap, HirIdSet};
use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_middle::lint::in_external_macro;
use rustc_middle::ty::{self, Ty, TyS, VariantDef};
use rustc_middle::mir::{self, interpret::ConstValue};
use rustc_semver::RustcVersion;
use rustc_session::{declare_tool_lint, impl_lint_pass};
use rustc_span::source_map::{Span, Spanned};
Expand Down Expand Up @@ -1533,11 +1534,17 @@ 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 = match lhs {
Some(lhs) => constant(cx, cx.typeck_results(), lhs)?.0,
None => miri_to_const(ty.numeric_min_val(cx.tcx)?)?,
None => miri_to_const(mir::ConstantKind::Val(
ConstValue::Scalar(ty.numeric_min_val(cx.tcx)?.into()),
ty,
))?,
};
let rhs = match rhs {
Some(rhs) => constant(cx, cx.typeck_results(), rhs)?.0,
None => miri_to_const(ty.numeric_max_val(cx.tcx)?)?,
None => miri_to_const(mir::ConstantKind::Val(
ConstValue::Scalar(ty.numeric_max_val(cx.tcx)?.into()),
ty,
))?,
};
let rhs = match range_end {
RangeEnd::Included => Bound::Included(rhs),
Expand Down
48 changes: 21 additions & 27 deletions src/tools/clippy/clippy_utils/src/consts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use rustc_data_structures::sync::Lrc;
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::mir;
use rustc_middle::ty::subst::{Subst, SubstsRef};
use rustc_middle::ty::{self, FloatTy, ScalarInt, Ty, TyCtxt};
use rustc_middle::{bug, span_bug};
Expand Down Expand Up @@ -354,7 +354,7 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> {
None,
)
.ok()
.map(|val| rustc_middle::ty::Const::from_value(self.lcx.tcx, val, ty))?;
.map(|val| mir::ConstantKind::Val(val, ty))?;
let result = miri_to_const(result);
if result.is_some() {
self.needed_resolution = true;
Expand Down Expand Up @@ -505,44 +505,38 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> {
}
}

pub fn miri_to_const(result: &ty::Const<'_>) -> Option<Constant> {
pub fn miri_to_const(result: mir::ConstantKind<'tcx>) -> Option<Constant> {
use rustc_middle::mir::interpret::ConstValue;
match result.val {
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()))),
match *result.ty().kind() {
ty::Bool => Some(Constant::Bool(result.try_to_scalar_int()? == ScalarInt::TRUE)),
ty::Uint(_) | ty::Int(_) => {
let int = result.try_to_scalar_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"),
result.try_to_scalar_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"),
result.try_to_scalar_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())));
ty::RawPtr(_) => {
let int = result.try_to_scalar_int()?;
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::Str => String::from_utf8(
data.inspect_with_uninit_and_ptr_outside_interpreter(start..end)
.to_owned(),
ty::Str => match result.try_to_value()? {
ConstValue::Slice { data, start, end } => String::from_utf8(
data.inspect_with_uninit_and_ptr_outside_interpreter(start..end).to_owned(),
)
.ok()
.map(Constant::Str),
_ => None,
},
_ => None,
},
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) {
ty::Array(sub_type, len) => match result.try_to_value()? {
ConstValue::ByRef { alloc, offset: _ } => match sub_type.kind() {
ty::Float(FloatTy::F32) => match miri_to_const(len.into()) {
Some(Constant::Int(len)) => alloc
.inspect_with_uninit_and_ptr_outside_interpreter(0..(4 * len as usize))
.to_owned()
Expand All @@ -556,7 +550,7 @@ pub fn miri_to_const(result: &ty::Const<'_>) -> Option<Constant> {
.map(Constant::Vec),
_ => None,
},
ty::Float(FloatTy::F64) => match miri_to_const(len) {
ty::Float(FloatTy::F64) => match miri_to_const(len.into()) {
Some(Constant::Int(len)) => alloc
.inspect_with_uninit_and_ptr_outside_interpreter(0..(8 * len as usize))
.to_owned()
Expand Down

0 comments on commit b2a2286

Please sign in to comment.