mirror of
https://github.com/rust-lang/rust-clippy
synced 2024-11-27 15:11:30 +00:00
Fix #10792
This commit is contained in:
parent
8c8ff5f31d
commit
0e1caa765e
9 changed files with 114 additions and 72 deletions
|
@ -51,7 +51,7 @@ impl<'tcx> LateLintPass<'tcx> for UnportableVariant {
|
||||||
.const_eval_poly(def_id.to_def_id())
|
.const_eval_poly(def_id.to_def_id())
|
||||||
.ok()
|
.ok()
|
||||||
.map(|val| rustc_middle::mir::ConstantKind::from_value(val, ty));
|
.map(|val| 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 Some(Constant::Int(val)) = constant.and_then(|c| miri_to_const(cx, c)) {
|
||||||
if let ty::Adt(adt, _) = ty.kind() {
|
if let ty::Adt(adt, _) = ty.kind() {
|
||||||
if adt.is_enum() {
|
if adt.is_enum() {
|
||||||
ty = adt.repr().discr_type().to_ty(cx.tcx);
|
ty = adt.repr().discr_type().to_ty(cx.tcx);
|
||||||
|
|
|
@ -215,7 +215,7 @@ fn check_ln1p(cx: &LateContext<'_>, expr: &Expr<'_>, receiver: &Expr<'_>) {
|
||||||
// ranges [-16777215, 16777216) for type f32 as whole number floats outside
|
// ranges [-16777215, 16777216) for type f32 as whole number floats outside
|
||||||
// this range are lossy and ambiguous.
|
// this range are lossy and ambiguous.
|
||||||
#[expect(clippy::cast_possible_truncation)]
|
#[expect(clippy::cast_possible_truncation)]
|
||||||
fn get_integer_from_float_constant(value: &Constant) -> Option<i32> {
|
fn get_integer_from_float_constant(value: &Constant<'_>) -> Option<i32> {
|
||||||
match value {
|
match value {
|
||||||
F32(num) if num.fract() == 0.0 => {
|
F32(num) if num.fract() == 0.0 => {
|
||||||
if (-16_777_215.0..16_777_216.0).contains(num) {
|
if (-16_777_215.0..16_777_216.0).contains(num) {
|
||||||
|
|
|
@ -41,7 +41,7 @@ fn all_ranges<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'_>], ty: Ty<'tcx>)
|
||||||
cx.tcx.valtree_to_const_val((ty, min_val_const.to_valtree())),
|
cx.tcx.valtree_to_const_val((ty, min_val_const.to_valtree())),
|
||||||
ty,
|
ty,
|
||||||
);
|
);
|
||||||
miri_to_const(cx.tcx, min_constant)?
|
miri_to_const(cx, min_constant)?
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
let rhs_const = match rhs {
|
let rhs_const = match rhs {
|
||||||
|
@ -52,7 +52,7 @@ fn all_ranges<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'_>], ty: Ty<'tcx>)
|
||||||
cx.tcx.valtree_to_const_val((ty, max_val_const.to_valtree())),
|
cx.tcx.valtree_to_const_val((ty, max_val_const.to_valtree())),
|
||||||
ty,
|
ty,
|
||||||
);
|
);
|
||||||
miri_to_const(cx.tcx, max_constant)?
|
miri_to_const(cx, max_constant)?
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
let lhs_val = lhs_const.int_value(cx, ty)?;
|
let lhs_val = lhs_const.int_value(cx, ty)?;
|
||||||
|
|
|
@ -66,7 +66,7 @@ enum MinMax {
|
||||||
Max,
|
Max,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn min_max<'a>(cx: &LateContext<'_>, expr: &'a Expr<'a>) -> Option<(MinMax, Constant, &'a Expr<'a>)> {
|
fn min_max<'a, 'tcx>(cx: &LateContext<'tcx>, expr: &'a Expr<'a>) -> Option<(MinMax, Constant<'tcx>, &'a Expr<'a>)> {
|
||||||
match expr.kind {
|
match expr.kind {
|
||||||
ExprKind::Call(path, args) => {
|
ExprKind::Call(path, args) => {
|
||||||
if let ExprKind::Path(ref qpath) = path.kind {
|
if let ExprKind::Path(ref qpath) = path.kind {
|
||||||
|
@ -99,12 +99,12 @@ fn min_max<'a>(cx: &LateContext<'_>, expr: &'a Expr<'a>) -> Option<(MinMax, Cons
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fetch_const<'a>(
|
fn fetch_const<'a, 'tcx>(
|
||||||
cx: &LateContext<'_>,
|
cx: &LateContext<'tcx>,
|
||||||
receiver: Option<&'a Expr<'a>>,
|
receiver: Option<&'a Expr<'a>>,
|
||||||
args: &'a [Expr<'a>],
|
args: &'a [Expr<'a>],
|
||||||
m: MinMax,
|
m: MinMax,
|
||||||
) -> Option<(MinMax, Constant, &'a Expr<'a>)> {
|
) -> Option<(MinMax, Constant<'tcx>, &'a Expr<'a>)> {
|
||||||
let mut args = receiver.into_iter().chain(args);
|
let mut args = receiver.into_iter().chain(args);
|
||||||
let first_arg = args.next()?;
|
let first_arg = args.next()?;
|
||||||
let second_arg = args.next()?;
|
let second_arg = args.next()?;
|
||||||
|
|
|
@ -85,7 +85,7 @@ fn get_lint_and_message(is_local: bool, is_comparing_arrays: bool) -> (&'static
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_allowed(val: &Constant) -> bool {
|
fn is_allowed(val: &Constant<'_>) -> bool {
|
||||||
match val {
|
match val {
|
||||||
&Constant::F32(f) => f == 0.0 || f.is_infinite(),
|
&Constant::F32(f) => f == 0.0 || f.is_infinite(),
|
||||||
&Constant::F64(f) => f == 0.0 || f.is_infinite(),
|
&Constant::F64(f) => f == 0.0 || f.is_infinite(),
|
||||||
|
|
|
@ -296,8 +296,8 @@ fn check_possible_range_contains(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct RangeBounds<'a> {
|
struct RangeBounds<'a, 'tcx> {
|
||||||
val: Constant,
|
val: Constant<'tcx>,
|
||||||
expr: &'a Expr<'a>,
|
expr: &'a Expr<'a>,
|
||||||
id: HirId,
|
id: HirId,
|
||||||
name_span: Span,
|
name_span: Span,
|
||||||
|
@ -309,7 +309,7 @@ struct RangeBounds<'a> {
|
||||||
// Takes a binary expression such as x <= 2 as input
|
// Takes a binary expression such as x <= 2 as input
|
||||||
// Breaks apart into various pieces, such as the value of the number,
|
// Breaks apart into various pieces, such as the value of the number,
|
||||||
// hir id of the variable, and direction/inclusiveness of the operator
|
// hir id of the variable, and direction/inclusiveness of the operator
|
||||||
fn check_range_bounds<'a>(cx: &'a LateContext<'_>, ex: &'a Expr<'_>) -> Option<RangeBounds<'a>> {
|
fn check_range_bounds<'a, 'tcx>(cx: &'a LateContext<'tcx>, ex: &'a Expr<'_>) -> Option<RangeBounds<'a, 'tcx>> {
|
||||||
if let ExprKind::Binary(ref op, l, r) = ex.kind {
|
if let ExprKind::Binary(ref op, l, r) = ex.kind {
|
||||||
let (inclusive, ordering) = match op.node {
|
let (inclusive, ordering) = match op.node {
|
||||||
BinOpKind::Gt => (false, Ordering::Greater),
|
BinOpKind::Gt => (false, Ordering::Greater),
|
||||||
|
|
|
@ -14,7 +14,7 @@ use rustc_middle::mir::interpret::Scalar;
|
||||||
use rustc_middle::ty::{self, EarlyBinder, FloatTy, ScalarInt, Ty, TyCtxt};
|
use rustc_middle::ty::{self, EarlyBinder, FloatTy, ScalarInt, Ty, TyCtxt};
|
||||||
use rustc_middle::ty::{List, SubstsRef};
|
use rustc_middle::ty::{List, SubstsRef};
|
||||||
use rustc_middle::{bug, span_bug};
|
use rustc_middle::{bug, span_bug};
|
||||||
use rustc_span::symbol::Symbol;
|
use rustc_span::symbol::{Ident, Symbol};
|
||||||
use rustc_span::SyntaxContext;
|
use rustc_span::SyntaxContext;
|
||||||
use std::cmp::Ordering::{self, Equal};
|
use std::cmp::Ordering::{self, Equal};
|
||||||
use std::hash::{Hash, Hasher};
|
use std::hash::{Hash, Hasher};
|
||||||
|
@ -22,7 +22,8 @@ use std::iter;
|
||||||
|
|
||||||
/// A `LitKind`-like enum to fold constant `Expr`s into.
|
/// A `LitKind`-like enum to fold constant `Expr`s into.
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum Constant {
|
pub enum Constant<'tcx> {
|
||||||
|
Adt(rustc_middle::mir::ConstantKind<'tcx>),
|
||||||
/// A `String` (e.g., "abc").
|
/// A `String` (e.g., "abc").
|
||||||
Str(String),
|
Str(String),
|
||||||
/// A binary string (e.g., `b"abc"`).
|
/// A binary string (e.g., `b"abc"`).
|
||||||
|
@ -38,20 +39,20 @@ pub enum Constant {
|
||||||
/// `true` or `false`.
|
/// `true` or `false`.
|
||||||
Bool(bool),
|
Bool(bool),
|
||||||
/// An array of constants.
|
/// An array of constants.
|
||||||
Vec(Vec<Constant>),
|
Vec(Vec<Constant<'tcx>>),
|
||||||
/// Also an array, but with only one constant, repeated N times.
|
/// Also an array, but with only one constant, repeated N times.
|
||||||
Repeat(Box<Constant>, u64),
|
Repeat(Box<Constant<'tcx>>, u64),
|
||||||
/// A tuple of constants.
|
/// A tuple of constants.
|
||||||
Tuple(Vec<Constant>),
|
Tuple(Vec<Constant<'tcx>>),
|
||||||
/// A raw pointer.
|
/// A raw pointer.
|
||||||
RawPtr(u128),
|
RawPtr(u128),
|
||||||
/// A reference
|
/// A reference
|
||||||
Ref(Box<Constant>),
|
Ref(Box<Constant<'tcx>>),
|
||||||
/// A literal with syntax error.
|
/// A literal with syntax error.
|
||||||
Err,
|
Err,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PartialEq for Constant {
|
impl<'tcx> PartialEq for Constant<'tcx> {
|
||||||
fn eq(&self, other: &Self) -> bool {
|
fn eq(&self, other: &Self) -> bool {
|
||||||
match (self, other) {
|
match (self, other) {
|
||||||
(Self::Str(ls), Self::Str(rs)) => ls == rs,
|
(Self::Str(ls), Self::Str(rs)) => ls == rs,
|
||||||
|
@ -80,13 +81,16 @@ impl PartialEq for Constant {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Hash for Constant {
|
impl<'tcx> Hash for Constant<'tcx> {
|
||||||
fn hash<H>(&self, state: &mut H)
|
fn hash<H>(&self, state: &mut H)
|
||||||
where
|
where
|
||||||
H: Hasher,
|
H: Hasher,
|
||||||
{
|
{
|
||||||
std::mem::discriminant(self).hash(state);
|
std::mem::discriminant(self).hash(state);
|
||||||
match *self {
|
match *self {
|
||||||
|
Self::Adt(ref elem) => {
|
||||||
|
elem.hash(state);
|
||||||
|
},
|
||||||
Self::Str(ref s) => {
|
Self::Str(ref s) => {
|
||||||
s.hash(state);
|
s.hash(state);
|
||||||
},
|
},
|
||||||
|
@ -126,7 +130,7 @@ impl Hash for Constant {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Constant {
|
impl<'tcx> Constant<'tcx> {
|
||||||
pub fn partial_cmp(tcx: TyCtxt<'_>, cmp_type: Ty<'_>, left: &Self, right: &Self) -> Option<Ordering> {
|
pub fn partial_cmp(tcx: TyCtxt<'_>, cmp_type: Ty<'_>, left: &Self, right: &Self) -> Option<Ordering> {
|
||||||
match (left, right) {
|
match (left, right) {
|
||||||
(Self::Str(ls), Self::Str(rs)) => Some(ls.cmp(rs)),
|
(Self::Str(ls), Self::Str(rs)) => Some(ls.cmp(rs)),
|
||||||
|
@ -209,7 +213,7 @@ impl Constant {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parses a `LitKind` to a `Constant`.
|
/// Parses a `LitKind` to a `Constant`.
|
||||||
pub fn lit_to_mir_constant(lit: &LitKind, ty: Option<Ty<'_>>) -> Constant {
|
pub fn lit_to_mir_constant<'tcx>(lit: &LitKind, ty: Option<Ty<'tcx>>) -> Constant<'tcx> {
|
||||||
match *lit {
|
match *lit {
|
||||||
LitKind::Str(ref is, _) => Constant::Str(is.to_string()),
|
LitKind::Str(ref is, _) => Constant::Str(is.to_string()),
|
||||||
LitKind::Byte(b) => Constant::Int(u128::from(b)),
|
LitKind::Byte(b) => Constant::Int(u128::from(b)),
|
||||||
|
@ -248,7 +252,7 @@ pub fn constant<'tcx>(
|
||||||
lcx: &LateContext<'tcx>,
|
lcx: &LateContext<'tcx>,
|
||||||
typeck_results: &ty::TypeckResults<'tcx>,
|
typeck_results: &ty::TypeckResults<'tcx>,
|
||||||
e: &Expr<'_>,
|
e: &Expr<'_>,
|
||||||
) -> Option<Constant> {
|
) -> Option<Constant<'tcx>> {
|
||||||
ConstEvalLateContext::new(lcx, typeck_results).expr(e)
|
ConstEvalLateContext::new(lcx, typeck_results).expr(e)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -257,7 +261,7 @@ pub fn constant_with_source<'tcx>(
|
||||||
lcx: &LateContext<'tcx>,
|
lcx: &LateContext<'tcx>,
|
||||||
typeck_results: &ty::TypeckResults<'tcx>,
|
typeck_results: &ty::TypeckResults<'tcx>,
|
||||||
e: &Expr<'_>,
|
e: &Expr<'_>,
|
||||||
) -> Option<(Constant, ConstantSource)> {
|
) -> Option<(Constant<'tcx>, ConstantSource)> {
|
||||||
let mut ctxt = ConstEvalLateContext::new(lcx, typeck_results);
|
let mut ctxt = ConstEvalLateContext::new(lcx, typeck_results);
|
||||||
let res = ctxt.expr(e);
|
let res = ctxt.expr(e);
|
||||||
res.map(|x| (x, ctxt.source))
|
res.map(|x| (x, ctxt.source))
|
||||||
|
@ -268,7 +272,7 @@ pub fn constant_simple<'tcx>(
|
||||||
lcx: &LateContext<'tcx>,
|
lcx: &LateContext<'tcx>,
|
||||||
typeck_results: &ty::TypeckResults<'tcx>,
|
typeck_results: &ty::TypeckResults<'tcx>,
|
||||||
e: &Expr<'_>,
|
e: &Expr<'_>,
|
||||||
) -> Option<Constant> {
|
) -> Option<Constant<'tcx>> {
|
||||||
constant_with_source(lcx, typeck_results, e).and_then(|(c, s)| s.is_local().then_some(c))
|
constant_with_source(lcx, typeck_results, e).and_then(|(c, s)| s.is_local().then_some(c))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -338,7 +342,7 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Simple constant folding: Insert an expression, get a constant or none.
|
/// Simple constant folding: Insert an expression, get a constant or none.
|
||||||
pub fn expr(&mut self, e: &Expr<'_>) -> Option<Constant> {
|
pub fn expr(&mut self, e: &Expr<'_>) -> Option<Constant<'tcx>> {
|
||||||
match e.kind {
|
match e.kind {
|
||||||
ExprKind::Path(ref qpath) => self.fetch_path(qpath, e.hir_id, self.typeck_results.expr_ty(e)),
|
ExprKind::Path(ref qpath) => self.fetch_path(qpath, e.hir_id, self.typeck_results.expr_ty(e)),
|
||||||
ExprKind::Block(block, _) => self.block(block),
|
ExprKind::Block(block, _) => self.block(block),
|
||||||
|
@ -392,13 +396,25 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> {
|
||||||
},
|
},
|
||||||
ExprKind::Index(arr, index) => self.index(arr, index),
|
ExprKind::Index(arr, index) => self.index(arr, index),
|
||||||
ExprKind::AddrOf(_, _, inner) => self.expr(inner).map(|r| Constant::Ref(Box::new(r))),
|
ExprKind::AddrOf(_, _, inner) => self.expr(inner).map(|r| Constant::Ref(Box::new(r))),
|
||||||
// TODO: add other expressions.
|
ExprKind::Field(ref local_expr, ref field) => {
|
||||||
|
let result = self.expr(local_expr);
|
||||||
|
if let Some(Constant::Adt(constant)) = &self.expr(local_expr)
|
||||||
|
&& let ty::Adt(adt_def, _) = constant.ty().kind()
|
||||||
|
&& adt_def.is_struct()
|
||||||
|
&& let Some(desired_field) = field_of_struct(*adt_def, self.lcx, *constant, field)
|
||||||
|
{
|
||||||
|
miri_to_const(self.lcx, desired_field)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
result
|
||||||
|
}
|
||||||
|
},
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[expect(clippy::cast_possible_wrap)]
|
#[expect(clippy::cast_possible_wrap)]
|
||||||
fn constant_not(&self, o: &Constant, ty: Ty<'_>) -> Option<Constant> {
|
fn constant_not(&self, o: &Constant<'tcx>, ty: Ty<'_>) -> Option<Constant<'tcx>> {
|
||||||
use self::Constant::{Bool, Int};
|
use self::Constant::{Bool, Int};
|
||||||
match *o {
|
match *o {
|
||||||
Bool(b) => Some(Bool(!b)),
|
Bool(b) => Some(Bool(!b)),
|
||||||
|
@ -414,7 +430,7 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn constant_negate(&self, o: &Constant, ty: Ty<'_>) -> Option<Constant> {
|
fn constant_negate(&self, o: &Constant<'tcx>, ty: Ty<'_>) -> Option<Constant<'tcx>> {
|
||||||
use self::Constant::{Int, F32, F64};
|
use self::Constant::{Int, F32, F64};
|
||||||
match *o {
|
match *o {
|
||||||
Int(value) => {
|
Int(value) => {
|
||||||
|
@ -433,28 +449,25 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> {
|
||||||
|
|
||||||
/// Create `Some(Vec![..])` of all constants, unless there is any
|
/// Create `Some(Vec![..])` of all constants, unless there is any
|
||||||
/// non-constant part.
|
/// non-constant part.
|
||||||
fn multi(&mut self, vec: &[Expr<'_>]) -> Option<Vec<Constant>> {
|
fn multi(&mut self, vec: &[Expr<'_>]) -> Option<Vec<Constant<'tcx>>> {
|
||||||
vec.iter().map(|elem| self.expr(elem)).collect::<Option<_>>()
|
vec.iter().map(|elem| self.expr(elem)).collect::<Option<_>>()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Lookup a possibly constant expression from an `ExprKind::Path`.
|
/// Lookup a possibly constant expression from an `ExprKind::Path`.
|
||||||
fn fetch_path(&mut self, qpath: &QPath<'_>, id: HirId, ty: Ty<'tcx>) -> Option<Constant> {
|
fn fetch_path(&mut self, qpath: &QPath<'_>, id: HirId, ty: Ty<'tcx>) -> Option<Constant<'tcx>> {
|
||||||
let res = self.typeck_results.qpath_res(qpath, id);
|
let res = self.typeck_results.qpath_res(qpath, id);
|
||||||
match res {
|
match res {
|
||||||
Res::Def(DefKind::Const | DefKind::AssocConst, def_id) => {
|
Res::Def(DefKind::Const | DefKind::AssocConst, def_id) => {
|
||||||
// Check if this constant is based on `cfg!(..)`,
|
// Check if this constant is based on `cfg!(..)`,
|
||||||
// which is NOT constant for our purposes.
|
// which is NOT constant for our purposes.
|
||||||
if let Some(node) = self.lcx.tcx.hir().get_if_local(def_id) &&
|
if let Some(node) = self.lcx.tcx.hir().get_if_local(def_id)
|
||||||
let Node::Item(&Item {
|
&& let Node::Item(Item { kind: ItemKind::Const(_, body_id), .. }) = node
|
||||||
kind: ItemKind::Const(_, body_id),
|
&& let Node::Expr(Expr { kind: ExprKind::Lit(_), span, .. }) = self.lcx
|
||||||
..
|
.tcx
|
||||||
}) = node &&
|
.hir()
|
||||||
let Node::Expr(&Expr {
|
.get(body_id.hir_id)
|
||||||
kind: ExprKind::Lit(_),
|
&& is_direct_expn_of(*span, "cfg").is_some()
|
||||||
span,
|
{
|
||||||
..
|
|
||||||
}) = self.lcx.tcx.hir().get(body_id.hir_id) &&
|
|
||||||
is_direct_expn_of(span, "cfg").is_some() {
|
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -464,23 +477,21 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> {
|
||||||
} else {
|
} else {
|
||||||
EarlyBinder::bind(substs).subst(self.lcx.tcx, self.substs)
|
EarlyBinder::bind(substs).subst(self.lcx.tcx, self.substs)
|
||||||
};
|
};
|
||||||
|
|
||||||
let result = self
|
let result = self
|
||||||
.lcx
|
.lcx
|
||||||
.tcx
|
.tcx
|
||||||
.const_eval_resolve(self.param_env, mir::UnevaluatedConst::new(def_id, substs), None)
|
.const_eval_resolve(self.param_env, mir::UnevaluatedConst::new(def_id, substs), None)
|
||||||
.ok()
|
.ok()
|
||||||
.map(|val| rustc_middle::mir::ConstantKind::from_value(val, ty))?;
|
.map(|val| rustc_middle::mir::ConstantKind::from_value(val, ty))?;
|
||||||
let result = miri_to_const(self.lcx.tcx, result)?;
|
let result = miri_to_const(self.lcx, result)?;
|
||||||
self.source = ConstantSource::Constant;
|
self.source = ConstantSource::Constant;
|
||||||
Some(result)
|
Some(result)
|
||||||
},
|
},
|
||||||
// FIXME: cover all usable cases.
|
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn index(&mut self, lhs: &'_ Expr<'_>, index: &'_ Expr<'_>) -> Option<Constant> {
|
fn index(&mut self, lhs: &'_ Expr<'_>, index: &'_ Expr<'_>) -> Option<Constant<'tcx>> {
|
||||||
let lhs = self.expr(lhs);
|
let lhs = self.expr(lhs);
|
||||||
let index = self.expr(index);
|
let index = self.expr(index);
|
||||||
|
|
||||||
|
@ -506,7 +517,7 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A block can only yield a constant if it only has one constant expression.
|
/// A block can only yield a constant if it only has one constant expression.
|
||||||
fn block(&mut self, block: &Block<'_>) -> Option<Constant> {
|
fn block(&mut self, block: &Block<'_>) -> Option<Constant<'tcx>> {
|
||||||
if block.stmts.is_empty()
|
if block.stmts.is_empty()
|
||||||
&& let Some(expr) = block.expr
|
&& let Some(expr) = block.expr
|
||||||
{
|
{
|
||||||
|
@ -539,7 +550,7 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn ifthenelse(&mut self, cond: &Expr<'_>, then: &Expr<'_>, otherwise: Option<&Expr<'_>>) -> Option<Constant> {
|
fn ifthenelse(&mut self, cond: &Expr<'_>, then: &Expr<'_>, otherwise: Option<&Expr<'_>>) -> Option<Constant<'tcx>> {
|
||||||
if let Some(Constant::Bool(b)) = self.expr(cond) {
|
if let Some(Constant::Bool(b)) = self.expr(cond) {
|
||||||
if b {
|
if b {
|
||||||
self.expr(then)
|
self.expr(then)
|
||||||
|
@ -551,7 +562,7 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn binop(&mut self, op: BinOp, left: &Expr<'_>, right: &Expr<'_>) -> Option<Constant> {
|
fn binop(&mut self, op: BinOp, left: &Expr<'_>, right: &Expr<'_>) -> Option<Constant<'tcx>> {
|
||||||
let l = self.expr(left)?;
|
let l = self.expr(left)?;
|
||||||
let r = self.expr(right);
|
let r = self.expr(right);
|
||||||
match (l, r) {
|
match (l, r) {
|
||||||
|
@ -644,23 +655,21 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn miri_to_const<'tcx>(tcx: TyCtxt<'tcx>, result: mir::ConstantKind<'tcx>) -> Option<Constant> {
|
pub fn miri_to_const<'tcx>(lcx: &LateContext<'tcx>, result: mir::ConstantKind<'tcx>) -> Option<Constant<'tcx>> {
|
||||||
use rustc_middle::mir::interpret::ConstValue;
|
use rustc_middle::mir::interpret::ConstValue;
|
||||||
match result {
|
match result {
|
||||||
mir::ConstantKind::Val(ConstValue::Scalar(Scalar::Int(int)), _) => {
|
mir::ConstantKind::Val(ConstValue::Scalar(Scalar::Int(int)), _) => match result.ty().kind() {
|
||||||
match result.ty().kind() {
|
ty::Adt(adt_def, _) if adt_def.is_struct() => Some(Constant::Adt(result)),
|
||||||
ty::Bool => Some(Constant::Bool(int == ScalarInt::TRUE)),
|
ty::Bool => Some(Constant::Bool(int == ScalarInt::TRUE)),
|
||||||
ty::Uint(_) | ty::Int(_) => Some(Constant::Int(int.assert_bits(int.size()))),
|
ty::Uint(_) | ty::Int(_) => Some(Constant::Int(int.assert_bits(int.size()))),
|
||||||
ty::Float(FloatTy::F32) => Some(Constant::F32(f32::from_bits(
|
ty::Float(FloatTy::F32) => Some(Constant::F32(f32::from_bits(
|
||||||
int.try_into().expect("invalid f32 bit representation"),
|
int.try_into().expect("invalid f32 bit representation"),
|
||||||
))),
|
))),
|
||||||
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"),
|
int.try_into().expect("invalid f64 bit representation"),
|
||||||
))),
|
))),
|
||||||
ty::RawPtr(_) => Some(Constant::RawPtr(int.assert_bits(int.size()))),
|
ty::RawPtr(_) => Some(Constant::RawPtr(int.assert_bits(int.size()))),
|
||||||
// FIXME: implement other conversions.
|
_ => None,
|
||||||
_ => None,
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
mir::ConstantKind::Val(ConstValue::Slice { data, start, end }, _) => match result.ty().kind() {
|
mir::ConstantKind::Val(ConstValue::Slice { data, start, end }, _) => match result.ty().kind() {
|
||||||
ty::Ref(_, tam, _) => match tam.kind() {
|
ty::Ref(_, tam, _) => match tam.kind() {
|
||||||
|
@ -676,35 +685,53 @@ pub fn miri_to_const<'tcx>(tcx: TyCtxt<'tcx>, result: mir::ConstantKind<'tcx>) -
|
||||||
_ => None,
|
_ => None,
|
||||||
},
|
},
|
||||||
mir::ConstantKind::Val(ConstValue::ByRef { alloc, offset: _ }, _) => match result.ty().kind() {
|
mir::ConstantKind::Val(ConstValue::ByRef { alloc, offset: _ }, _) => match result.ty().kind() {
|
||||||
|
ty::Adt(adt_def, _) if adt_def.is_struct() => Some(Constant::Adt(result)),
|
||||||
ty::Array(sub_type, len) => match sub_type.kind() {
|
ty::Array(sub_type, len) => match sub_type.kind() {
|
||||||
ty::Float(FloatTy::F32) => match len.kind().try_to_target_usize(tcx) {
|
ty::Float(FloatTy::F32) => match len.kind().try_to_target_usize(lcx.tcx) {
|
||||||
Some(len) => alloc
|
Some(len) => alloc
|
||||||
.inner()
|
.inner()
|
||||||
.inspect_with_uninit_and_ptr_outside_interpreter(0..(4 * usize::try_from(len).unwrap()))
|
.inspect_with_uninit_and_ptr_outside_interpreter(0..(4 * usize::try_from(len).unwrap()))
|
||||||
.to_owned()
|
.to_owned()
|
||||||
.array_chunks::<4>()
|
.array_chunks::<4>()
|
||||||
.map(|&chunk| Some(Constant::F32(f32::from_le_bytes(chunk))))
|
.map(|&chunk| Some(Constant::F32(f32::from_le_bytes(chunk))))
|
||||||
.collect::<Option<Vec<Constant>>>()
|
.collect::<Option<Vec<Constant<'tcx>>>>()
|
||||||
.map(Constant::Vec),
|
.map(Constant::Vec),
|
||||||
_ => None,
|
_ => None,
|
||||||
},
|
},
|
||||||
ty::Float(FloatTy::F64) => match len.kind().try_to_target_usize(tcx) {
|
ty::Float(FloatTy::F64) => match len.kind().try_to_target_usize(lcx.tcx) {
|
||||||
Some(len) => alloc
|
Some(len) => alloc
|
||||||
.inner()
|
.inner()
|
||||||
.inspect_with_uninit_and_ptr_outside_interpreter(0..(8 * usize::try_from(len).unwrap()))
|
.inspect_with_uninit_and_ptr_outside_interpreter(0..(8 * usize::try_from(len).unwrap()))
|
||||||
.to_owned()
|
.to_owned()
|
||||||
.array_chunks::<8>()
|
.array_chunks::<8>()
|
||||||
.map(|&chunk| Some(Constant::F64(f64::from_le_bytes(chunk))))
|
.map(|&chunk| Some(Constant::F64(f64::from_le_bytes(chunk))))
|
||||||
.collect::<Option<Vec<Constant>>>()
|
.collect::<Option<Vec<Constant<'tcx>>>>()
|
||||||
.map(Constant::Vec),
|
.map(Constant::Vec),
|
||||||
_ => None,
|
_ => None,
|
||||||
},
|
},
|
||||||
// FIXME: implement other array type conversions.
|
|
||||||
_ => None,
|
_ => None,
|
||||||
},
|
},
|
||||||
_ => None,
|
_ => None,
|
||||||
},
|
},
|
||||||
// FIXME: implement other conversions.
|
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn field_of_struct<'tcx>(
|
||||||
|
adt_def: ty::AdtDef<'tcx>,
|
||||||
|
lcx: &LateContext<'tcx>,
|
||||||
|
result: mir::ConstantKind<'tcx>,
|
||||||
|
field: &Ident,
|
||||||
|
) -> Option<mir::ConstantKind<'tcx>> {
|
||||||
|
let dc = lcx.tcx.destructure_mir_constant(lcx.param_env, result);
|
||||||
|
if let Some(dc_variant) = dc.variant
|
||||||
|
&& let Some(variant) = adt_def.variants().get(dc_variant)
|
||||||
|
&& let Some(field_idx) = variant.fields.iter().position(|el| el.name == field.name)
|
||||||
|
&& let Some(dc_field) = dc.fields.get(field_idx)
|
||||||
|
{
|
||||||
|
Some(*dc_field)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1499,7 +1499,7 @@ pub fn is_range_full(cx: &LateContext<'_>, expr: &Expr<'_>, container_path: Opti
|
||||||
&& let Some(min_val) = bnd_ty.numeric_min_val(cx.tcx)
|
&& let Some(min_val) = bnd_ty.numeric_min_val(cx.tcx)
|
||||||
&& let const_val = cx.tcx.valtree_to_const_val((bnd_ty, min_val.to_valtree()))
|
&& let const_val = cx.tcx.valtree_to_const_val((bnd_ty, min_val.to_valtree()))
|
||||||
&& let min_const_kind = ConstantKind::from_value(const_val, bnd_ty)
|
&& let min_const_kind = ConstantKind::from_value(const_val, bnd_ty)
|
||||||
&& let Some(min_const) = miri_to_const(cx.tcx, min_const_kind)
|
&& let Some(min_const) = miri_to_const(cx, min_const_kind)
|
||||||
&& let Some(start_const) = constant(cx, cx.typeck_results(), start)
|
&& let Some(start_const) = constant(cx, cx.typeck_results(), start)
|
||||||
{
|
{
|
||||||
start_const == min_const
|
start_const == min_const
|
||||||
|
@ -1515,7 +1515,7 @@ pub fn is_range_full(cx: &LateContext<'_>, expr: &Expr<'_>, container_path: Opti
|
||||||
&& let Some(max_val) = bnd_ty.numeric_max_val(cx.tcx)
|
&& let Some(max_val) = bnd_ty.numeric_max_val(cx.tcx)
|
||||||
&& let const_val = cx.tcx.valtree_to_const_val((bnd_ty, max_val.to_valtree()))
|
&& let const_val = cx.tcx.valtree_to_const_val((bnd_ty, max_val.to_valtree()))
|
||||||
&& let max_const_kind = ConstantKind::from_value(const_val, bnd_ty)
|
&& let max_const_kind = ConstantKind::from_value(const_val, bnd_ty)
|
||||||
&& let Some(max_const) = miri_to_const(cx.tcx, max_const_kind)
|
&& let Some(max_const) = miri_to_const(cx, max_const_kind)
|
||||||
&& let Some(end_const) = constant(cx, cx.typeck_results(), end)
|
&& let Some(end_const) = constant(cx, cx.typeck_results(), end)
|
||||||
{
|
{
|
||||||
end_const == max_const
|
end_const == max_const
|
||||||
|
|
|
@ -466,4 +466,19 @@ pub fn issue_10767() {
|
||||||
&3.5_f32 + &1.3_f32;
|
&3.5_f32 + &1.3_f32;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn issue_10792() {
|
||||||
|
struct One {
|
||||||
|
a: u32,
|
||||||
|
}
|
||||||
|
struct Two {
|
||||||
|
b: u32,
|
||||||
|
c: u64,
|
||||||
|
}
|
||||||
|
const ONE: One = One { a: 1 };
|
||||||
|
const TWO: Two = Two { b: 2, c: 3 };
|
||||||
|
let _ = 10 / ONE.a;
|
||||||
|
let _ = 10 / TWO.b;
|
||||||
|
let _ = 10 / TWO.c;
|
||||||
|
}
|
||||||
|
|
||||||
fn main() {}
|
fn main() {}
|
||||||
|
|
Loading…
Reference in a new issue