Require ConstEvalCtxt
to be constructed.
This commit is contained in:
parent
d2cb227eb4
commit
e4ad36d6a8
@ -1,4 +1,4 @@
|
||||
use clippy_utils::consts::{constant, Constant};
|
||||
use clippy_utils::consts::{ConstEvalCtxt, Constant};
|
||||
use clippy_utils::diagnostics::span_lint_and_help;
|
||||
use clippy_utils::is_inside_always_const_context;
|
||||
use clippy_utils::macros::{find_assert_args, root_macro_call_first_node, PanicExpn};
|
||||
@ -43,7 +43,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
|
||||
let Some((condition, panic_expn)) = find_assert_args(cx, e, macro_call.expn) else {
|
||||
return;
|
||||
};
|
||||
let Some(Constant::Bool(val)) = constant(cx, cx.typeck_results(), condition) else {
|
||||
let Some(Constant::Bool(val)) = ConstEvalCtxt::new(cx).eval(condition) else {
|
||||
return;
|
||||
};
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
use super::CAST_NAN_TO_INT;
|
||||
|
||||
use clippy_utils::consts::{constant, Constant};
|
||||
use clippy_utils::consts::{ConstEvalCtxt, Constant};
|
||||
use clippy_utils::diagnostics::span_lint_and_note;
|
||||
use rustc_hir::Expr;
|
||||
use rustc_lint::LateContext;
|
||||
@ -20,7 +20,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_expr: &Expr<'_>,
|
||||
}
|
||||
|
||||
fn is_known_nan(cx: &LateContext<'_>, e: &Expr<'_>) -> bool {
|
||||
match constant(cx, cx.typeck_results(), e) {
|
||||
match ConstEvalCtxt::new(cx).eval(e) {
|
||||
// FIXME(f16_f128): add these types when nan checks are available on all platforms
|
||||
Some(Constant::F64(n)) => n.is_nan(),
|
||||
Some(Constant::F32(n)) => n.is_nan(),
|
||||
|
@ -1,4 +1,4 @@
|
||||
use clippy_utils::consts::{constant, Constant};
|
||||
use clippy_utils::consts::{ConstEvalCtxt, Constant};
|
||||
use clippy_utils::diagnostics::{span_lint, span_lint_and_then};
|
||||
use clippy_utils::expr_or_init;
|
||||
use clippy_utils::source::snippet;
|
||||
@ -15,7 +15,7 @@
|
||||
use super::{utils, CAST_ENUM_TRUNCATION, CAST_POSSIBLE_TRUNCATION};
|
||||
|
||||
fn constant_int(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<u128> {
|
||||
if let Some(Constant::Int(c)) = constant(cx, cx.typeck_results(), expr) {
|
||||
if let Some(Constant::Int(c)) = ConstEvalCtxt::new(cx).eval(expr) {
|
||||
Some(c)
|
||||
} else {
|
||||
None
|
||||
|
@ -1,7 +1,7 @@
|
||||
use std::convert::Infallible;
|
||||
use std::ops::ControlFlow;
|
||||
|
||||
use clippy_utils::consts::{constant, Constant};
|
||||
use clippy_utils::consts::{ConstEvalCtxt, Constant};
|
||||
use clippy_utils::diagnostics::span_lint;
|
||||
use clippy_utils::visitors::{for_each_expr_without_closures, Descend};
|
||||
use clippy_utils::{method_chain_args, sext};
|
||||
@ -88,7 +88,7 @@ fn get_const_signed_int_eval<'cx>(
|
||||
) -> Option<i128> {
|
||||
let ty = ty.into().unwrap_or_else(|| cx.typeck_results().expr_ty(expr));
|
||||
|
||||
if let Constant::Int(n) = constant(cx, cx.typeck_results(), expr)?
|
||||
if let Constant::Int(n) = ConstEvalCtxt::new(cx).eval(expr)?
|
||||
&& let ty::Int(ity) = *ty.kind()
|
||||
{
|
||||
return Some(sext(cx.tcx, n, ity));
|
||||
@ -103,7 +103,7 @@ fn get_const_unsigned_int_eval<'cx>(
|
||||
) -> Option<u128> {
|
||||
let ty = ty.into().unwrap_or_else(|| cx.typeck_results().expr_ty(expr));
|
||||
|
||||
if let Constant::Int(n) = constant(cx, cx.typeck_results(), expr)?
|
||||
if let Constant::Int(n) = ConstEvalCtxt::new(cx).eval(expr)?
|
||||
&& let ty::Uint(_ity) = *ty.kind()
|
||||
{
|
||||
return Some(n);
|
||||
|
@ -1,5 +1,5 @@
|
||||
use clippy_utils::consts::Constant::{Int, F32, F64};
|
||||
use clippy_utils::consts::{constant, constant_simple, Constant};
|
||||
use clippy_utils::consts::{ConstEvalCtxt, Constant};
|
||||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use clippy_utils::{
|
||||
eq_expr_value, get_parent_expr, higher, in_constant, is_inherent_method_call, is_no_std_crate, numeric_literal,
|
||||
@ -112,7 +112,7 @@
|
||||
// Returns the specialized log method for a given base if base is constant
|
||||
// and is one of 2, 10 and e
|
||||
fn get_specialized_log_method(cx: &LateContext<'_>, base: &Expr<'_>) -> Option<&'static str> {
|
||||
if let Some(value) = constant(cx, cx.typeck_results(), base) {
|
||||
if let Some(value) = ConstEvalCtxt::new(cx).eval(base) {
|
||||
if F32(2.0) == value || F64(2.0) == value {
|
||||
return Some("log2");
|
||||
} else if F32(10.0) == value || F64(10.0) == value {
|
||||
@ -182,10 +182,8 @@ fn check_ln1p(cx: &LateContext<'_>, expr: &Expr<'_>, receiver: &Expr<'_>) {
|
||||
rhs,
|
||||
) = receiver.kind
|
||||
{
|
||||
let recv = match (
|
||||
constant(cx, cx.typeck_results(), lhs),
|
||||
constant(cx, cx.typeck_results(), rhs),
|
||||
) {
|
||||
let ecx = ConstEvalCtxt::new(cx);
|
||||
let recv = match (ecx.eval(lhs), ecx.eval(rhs)) {
|
||||
(Some(value), _) if F32(1.0) == value || F64(1.0) == value => rhs,
|
||||
(_, Some(value)) if F32(1.0) == value || F64(1.0) == value => lhs,
|
||||
_ => return,
|
||||
@ -230,7 +228,7 @@ fn get_integer_from_float_constant(value: &Constant<'_>) -> Option<i32> {
|
||||
|
||||
fn check_powf(cx: &LateContext<'_>, expr: &Expr<'_>, receiver: &Expr<'_>, args: &[Expr<'_>]) {
|
||||
// Check receiver
|
||||
if let Some(value) = constant(cx, cx.typeck_results(), receiver) {
|
||||
if let Some(value) = ConstEvalCtxt::new(cx).eval(receiver) {
|
||||
if let Some(method) = if F32(f32_consts::E) == value || F64(f64_consts::E) == value {
|
||||
Some("exp")
|
||||
} else if F32(2.0) == value || F64(2.0) == value {
|
||||
@ -251,7 +249,7 @@ fn check_powf(cx: &LateContext<'_>, expr: &Expr<'_>, receiver: &Expr<'_>, args:
|
||||
}
|
||||
|
||||
// Check argument
|
||||
if let Some(value) = constant(cx, cx.typeck_results(), &args[0]) {
|
||||
if let Some(value) = ConstEvalCtxt::new(cx).eval(&args[0]) {
|
||||
let (lint, help, suggestion) = if F32(1.0 / 2.0) == value || F64(1.0 / 2.0) == value {
|
||||
(
|
||||
SUBOPTIMAL_FLOPS,
|
||||
@ -291,7 +289,7 @@ fn check_powf(cx: &LateContext<'_>, expr: &Expr<'_>, receiver: &Expr<'_>, args:
|
||||
}
|
||||
|
||||
fn check_powi(cx: &LateContext<'_>, expr: &Expr<'_>, receiver: &Expr<'_>, args: &[Expr<'_>]) {
|
||||
if let Some(value) = constant(cx, cx.typeck_results(), &args[0]) {
|
||||
if let Some(value) = ConstEvalCtxt::new(cx).eval(&args[0]) {
|
||||
if value == Int(2) {
|
||||
if let Some(parent) = get_parent_expr(cx, expr) {
|
||||
if let Some(grandparent) = get_parent_expr(cx, parent) {
|
||||
@ -397,8 +395,9 @@ fn detect_hypot(cx: &LateContext<'_>, receiver: &Expr<'_>) -> Option<String> {
|
||||
) = &add_rhs.kind
|
||||
&& lmethod_name.as_str() == "powi"
|
||||
&& rmethod_name.as_str() == "powi"
|
||||
&& let Some(lvalue) = constant(cx, cx.typeck_results(), largs_1)
|
||||
&& let Some(rvalue) = constant(cx, cx.typeck_results(), rargs_1)
|
||||
&& let ecx = ConstEvalCtxt::new(cx)
|
||||
&& let Some(lvalue) = ecx.eval(largs_1)
|
||||
&& let Some(rvalue) = ecx.eval(rargs_1)
|
||||
&& Int(2) == lvalue
|
||||
&& Int(2) == rvalue
|
||||
{
|
||||
@ -438,7 +437,7 @@ fn check_expm1(cx: &LateContext<'_>, expr: &Expr<'_>) {
|
||||
rhs,
|
||||
) = expr.kind
|
||||
&& cx.typeck_results().expr_ty(lhs).is_floating_point()
|
||||
&& let Some(value) = constant(cx, cx.typeck_results(), rhs)
|
||||
&& let Some(value) = ConstEvalCtxt::new(cx).eval(rhs)
|
||||
&& (F32(1.0) == value || F64(1.0) == value)
|
||||
&& let ExprKind::MethodCall(path, self_arg, ..) = &lhs.kind
|
||||
&& cx.typeck_results().expr_ty(self_arg).is_floating_point()
|
||||
@ -552,7 +551,7 @@ fn is_testing_negative(cx: &LateContext<'_>, expr: &Expr<'_>, test: &Expr<'_>) -
|
||||
|
||||
/// Returns true iff expr is some zero literal
|
||||
fn is_zero(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
|
||||
match constant_simple(cx, cx.typeck_results(), expr) {
|
||||
match ConstEvalCtxt::new(cx).eval_simple(expr) {
|
||||
Some(Int(i)) => i == 0,
|
||||
Some(F32(f)) => f == 0.0,
|
||||
Some(F64(f)) => f == 0.0,
|
||||
@ -696,8 +695,9 @@ fn check_radians(cx: &LateContext<'_>, expr: &Expr<'_>) {
|
||||
mul_lhs,
|
||||
mul_rhs,
|
||||
) = &div_lhs.kind
|
||||
&& let Some(rvalue) = constant(cx, cx.typeck_results(), div_rhs)
|
||||
&& let Some(lvalue) = constant(cx, cx.typeck_results(), mul_rhs)
|
||||
&& let ecx = ConstEvalCtxt::new(cx)
|
||||
&& let Some(rvalue) = ecx.eval(div_rhs)
|
||||
&& let Some(lvalue) = ecx.eval(mul_rhs)
|
||||
{
|
||||
// TODO: also check for constant values near PI/180 or 180/PI
|
||||
if (F32(f32_consts::PI) == rvalue || F64(f64_consts::PI) == rvalue)
|
||||
|
@ -1,7 +1,7 @@
|
||||
//! lint on if branches that could be swapped so no `!` operation is necessary
|
||||
//! on the condition
|
||||
|
||||
use clippy_utils::consts::{constant_simple, Constant};
|
||||
use clippy_utils::consts::{ConstEvalCtxt, Constant};
|
||||
use clippy_utils::diagnostics::span_lint_and_help;
|
||||
use clippy_utils::is_else_clause;
|
||||
use rustc_hir::{BinOpKind, Expr, ExprKind, UnOp};
|
||||
@ -49,7 +49,7 @@
|
||||
declare_lint_pass!(IfNotElse => [IF_NOT_ELSE]);
|
||||
|
||||
fn is_zero_const(expr: &Expr<'_>, cx: &LateContext<'_>) -> bool {
|
||||
if let Some(value) = constant_simple(cx, cx.typeck_results(), expr) {
|
||||
if let Some(value) = ConstEvalCtxt::new(cx).eval_simple(expr) {
|
||||
return Constant::Int(0) == value;
|
||||
}
|
||||
false
|
||||
|
@ -1,4 +1,4 @@
|
||||
use clippy_utils::consts::{constant, Constant};
|
||||
use clippy_utils::consts::{ConstEvalCtxt, Constant};
|
||||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use clippy_utils::get_parent_expr;
|
||||
use clippy_utils::source::snippet_with_context;
|
||||
@ -117,11 +117,11 @@ fn get_int_max(ty: Ty<'_>) -> Option<u128> {
|
||||
|
||||
fn get_const<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>) -> Option<(u128, BinOpKind, &'tcx Expr<'tcx>)> {
|
||||
if let ExprKind::Binary(op, l, r) = expr.kind {
|
||||
let tr = cx.typeck_results();
|
||||
if let Some(Constant::Int(c)) = constant(cx, tr, r) {
|
||||
let ecx = ConstEvalCtxt::new(cx);
|
||||
if let Some(Constant::Int(c)) = ecx.eval(r) {
|
||||
return Some((c, op.node, l));
|
||||
};
|
||||
if let Some(Constant::Int(c)) = constant(cx, tr, l) {
|
||||
if let Some(Constant::Int(c)) = ecx.eval(l) {
|
||||
return Some((c, invert_op(op.node)?, r));
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
use clippy_config::msrvs::{self, Msrv};
|
||||
use clippy_config::Conf;
|
||||
use clippy_utils::consts::{constant, Constant};
|
||||
use clippy_utils::consts::{ConstEvalCtxt, Constant};
|
||||
use clippy_utils::diagnostics::span_lint_and_then;
|
||||
use clippy_utils::higher::IfLet;
|
||||
use clippy_utils::ty::is_copy;
|
||||
@ -246,7 +246,7 @@ fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) {
|
||||
&& let parent_id = cx.tcx.parent_hir_id(expr.hir_id)
|
||||
&& let hir::Node::Expr(parent_expr) = cx.tcx.hir_node(parent_id)
|
||||
&& let hir::ExprKind::Index(_, index_expr, _) = parent_expr.kind
|
||||
&& let Some(Constant::Int(index_value)) = constant(cx, cx.typeck_results(), index_expr)
|
||||
&& let Some(Constant::Int(index_value)) = ConstEvalCtxt::new(cx).eval(index_expr)
|
||||
&& let Ok(index_value) = index_value.try_into()
|
||||
&& index_value < max_suggested_slice
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
//! lint on indexing and slicing operations
|
||||
|
||||
use clippy_config::Conf;
|
||||
use clippy_utils::consts::{constant, Constant};
|
||||
use clippy_utils::consts::{ConstEvalCtxt, Constant};
|
||||
use clippy_utils::diagnostics::{span_lint, span_lint_and_then};
|
||||
use clippy_utils::ty::{deref_chain, get_adt_inherent_method};
|
||||
use clippy_utils::{higher, is_from_proc_macro};
|
||||
@ -177,7 +177,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
|
||||
return;
|
||||
}
|
||||
// Index is a constant uint.
|
||||
if let Some(constant) = constant(cx, cx.typeck_results(), index) {
|
||||
if let Some(constant) = ConstEvalCtxt::new(cx).eval(index) {
|
||||
// only `usize` index is legal in rust array index
|
||||
// leave other type to rustc
|
||||
if let Constant::Int(off) = constant
|
||||
@ -215,14 +215,15 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
|
||||
/// Returns a tuple of options with the start and end (exclusive) values of
|
||||
/// the range. If the start or end is not constant, None is returned.
|
||||
fn to_const_range(cx: &LateContext<'_>, range: higher::Range<'_>, array_size: u128) -> (Option<u128>, Option<u128>) {
|
||||
let s = range.start.map(|expr| constant(cx, cx.typeck_results(), expr));
|
||||
let ecx = ConstEvalCtxt::new(cx);
|
||||
let s = range.start.map(|expr| ecx.eval(expr));
|
||||
let start = match s {
|
||||
Some(Some(Constant::Int(x))) => Some(x),
|
||||
Some(_) => None,
|
||||
None => Some(0),
|
||||
};
|
||||
|
||||
let e = range.end.map(|expr| constant(cx, cx.typeck_results(), expr));
|
||||
let e = range.end.map(|expr| ecx.eval(expr));
|
||||
let end = match e {
|
||||
Some(Some(Constant::Int(x))) => {
|
||||
if range.limits == RangeLimits::Closed {
|
||||
|
@ -7,7 +7,7 @@
|
||||
|
||||
use clippy_utils::comparisons;
|
||||
use clippy_utils::comparisons::Rel;
|
||||
use clippy_utils::consts::{constant_full_int, FullInt};
|
||||
use clippy_utils::consts::{ConstEvalCtxt, FullInt};
|
||||
use clippy_utils::diagnostics::span_lint;
|
||||
use clippy_utils::source::snippet;
|
||||
|
||||
@ -95,7 +95,7 @@ fn upcast_comparison_bounds_err<'tcx>(
|
||||
invert: bool,
|
||||
) {
|
||||
if let Some((lb, ub)) = lhs_bounds {
|
||||
if let Some(norm_rhs_val) = constant_full_int(cx, cx.typeck_results(), rhs) {
|
||||
if let Some(norm_rhs_val) = ConstEvalCtxt::new(cx).eval_full_int(rhs) {
|
||||
if rel == Rel::Eq || rel == Rel::Ne {
|
||||
if norm_rhs_val < lb || norm_rhs_val > ub {
|
||||
err_upcast_comparison(cx, span, lhs, rel == Rel::Ne);
|
||||
|
@ -1,5 +1,5 @@
|
||||
use super::WHILE_IMMUTABLE_CONDITION;
|
||||
use clippy_utils::consts::constant;
|
||||
use clippy_utils::consts::ConstEvalCtxt;
|
||||
use clippy_utils::diagnostics::span_lint_and_then;
|
||||
use clippy_utils::usage::mutated_variables;
|
||||
use rustc_hir::def::{DefKind, Res};
|
||||
@ -10,7 +10,7 @@
|
||||
use std::ops::ControlFlow;
|
||||
|
||||
pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, cond: &'tcx Expr<'_>, expr: &'tcx Expr<'_>) {
|
||||
if constant(cx, cx.typeck_results(), cond).is_some() {
|
||||
if ConstEvalCtxt::new(cx).eval(cond).is_some() {
|
||||
// A pure constant condition (e.g., `while false`) is not linted.
|
||||
return;
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
use clippy_config::msrvs::{self, Msrv};
|
||||
use clippy_config::Conf;
|
||||
use clippy_utils::consts::{constant, Constant};
|
||||
use clippy_utils::consts::{ConstEvalCtxt, Constant};
|
||||
use clippy_utils::diagnostics::{span_lint_and_then, span_lint_hir_and_then};
|
||||
use clippy_utils::higher::If;
|
||||
use clippy_utils::sugg::Sugg;
|
||||
@ -122,8 +122,9 @@ fn min_less_than_max(&self, cx: &LateContext<'tcx>) -> bool {
|
||||
if max_type != min_type {
|
||||
return false;
|
||||
}
|
||||
if let Some(max) = constant(cx, cx.typeck_results(), self.params.max)
|
||||
&& let Some(min) = constant(cx, cx.typeck_results(), self.params.min)
|
||||
let ecx = ConstEvalCtxt::new(cx);
|
||||
if let Some(max) = ecx.eval(self.params.max)
|
||||
&& let Some(min) = ecx.eval(self.params.min)
|
||||
&& let Some(ord) = Constant::partial_cmp(cx.tcx, max_type, &min, &max)
|
||||
{
|
||||
ord != Ordering::Greater
|
||||
|
@ -1,4 +1,4 @@
|
||||
use clippy_utils::consts::{constant, Constant};
|
||||
use clippy_utils::consts::{ConstEvalCtxt, Constant};
|
||||
use clippy_utils::diagnostics::span_lint_and_then;
|
||||
use clippy_utils::source::snippet_opt;
|
||||
use clippy_utils::{is_from_proc_macro, path_to_local};
|
||||
@ -95,8 +95,9 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
|
||||
|| cx.tcx.features().declared(sym!(const_float_classify))
|
||||
)
|
||||
&& let [first, second, const_1, const_2] = exprs
|
||||
&& let Some(const_1) = constant(cx, cx.typeck_results(), const_1)
|
||||
&& let Some(const_2) = constant(cx, cx.typeck_results(), const_2)
|
||||
&& let ecx = ConstEvalCtxt::new(cx)
|
||||
&& let Some(const_1) = ecx.eval(const_1)
|
||||
&& let Some(const_2) = ecx.eval(const_2)
|
||||
&& path_to_local(first).is_some_and(|f| path_to_local(second).is_some_and(|s| f == s))
|
||||
// The actual infinity check, we also allow `NEG_INFINITY` before` INFINITY` just in
|
||||
// case somebody does that for some reason
|
||||
|
@ -1,6 +1,6 @@
|
||||
use clippy_config::msrvs::{self, Msrv};
|
||||
use clippy_config::Conf;
|
||||
use clippy_utils::consts::{constant_full_int, FullInt};
|
||||
use clippy_utils::consts::{ConstEvalCtxt, FullInt};
|
||||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use clippy_utils::source::snippet_with_context;
|
||||
use clippy_utils::{in_constant, path_to_local};
|
||||
@ -117,7 +117,7 @@ fn check_for_either_unsigned_int_constant<'a>(
|
||||
}
|
||||
|
||||
fn check_for_unsigned_int_constant<'a>(cx: &'a LateContext<'_>, expr: &'a Expr<'_>) -> Option<u128> {
|
||||
let int_const = constant_full_int(cx, cx.typeck_results(), expr)?;
|
||||
let int_const = ConstEvalCtxt::new(cx).eval_full_int(expr)?;
|
||||
match int_const {
|
||||
FullInt::S(s) => s.try_into().ok(),
|
||||
FullInt::U(u) => Some(u),
|
||||
|
@ -1,6 +1,6 @@
|
||||
use std::fmt::Display;
|
||||
|
||||
use clippy_utils::consts::{constant, Constant};
|
||||
use clippy_utils::consts::{ConstEvalCtxt, Constant};
|
||||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use clippy_utils::sugg;
|
||||
use rustc_errors::Applicability;
|
||||
@ -66,7 +66,7 @@ fn parse_shift<'tcx>(
|
||||
BinOpKind::Shr => ShiftDirection::Right,
|
||||
_ => return None,
|
||||
};
|
||||
let const_expr = constant(cx, cx.typeck_results(), r)?;
|
||||
let const_expr = ConstEvalCtxt::new(cx).eval(r)?;
|
||||
if let Constant::Int(shift) = const_expr {
|
||||
return Some((dir, shift, l));
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
use clippy_config::msrvs::{self, Msrv};
|
||||
use clippy_config::Conf;
|
||||
use clippy_utils::consts::{constant, Constant};
|
||||
use clippy_utils::consts::{ConstEvalCtxt, Constant};
|
||||
use clippy_utils::diagnostics::span_lint_and_then;
|
||||
use clippy_utils::source::snippet;
|
||||
use clippy_utils::usage::mutated_variables;
|
||||
@ -147,7 +147,7 @@ fn len_arg<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option<&'tcx E
|
||||
|
||||
// Returns the length of the `expr` if it's a constant string or char.
|
||||
fn constant_length(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<u128> {
|
||||
let value = constant(cx, cx.typeck_results(), expr)?;
|
||||
let value = ConstEvalCtxt::new(cx).eval(expr)?;
|
||||
match value {
|
||||
Constant::Str(value) => Some(value.len() as u128),
|
||||
Constant::Char(value) => Some(value.len_utf8() as u128),
|
||||
|
@ -1,4 +1,4 @@
|
||||
use clippy_utils::consts::constant_simple;
|
||||
use clippy_utils::consts::ConstEvalCtxt;
|
||||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use clippy_utils::source::{indent_of, reindent_multiline, snippet_opt};
|
||||
use clippy_utils::ty::is_type_diagnostic_item;
|
||||
@ -69,7 +69,7 @@ fn check_and_lint<'tcx>(
|
||||
&& let Some(ty_name) = find_type_name(cx, ty)
|
||||
&& let Some(or_body_snippet) = snippet_opt(cx, else_expr.span)
|
||||
&& let Some(indent) = indent_of(cx, expr.span)
|
||||
&& constant_simple(cx, cx.typeck_results(), else_expr).is_some()
|
||||
&& ConstEvalCtxt::new(cx).eval_simple(else_expr).is_some()
|
||||
{
|
||||
lint(cx, expr, let_expr, ty_name, or_body_snippet, indent);
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
use clippy_utils::consts::{constant, constant_full_int, mir_to_const, FullInt};
|
||||
use clippy_utils::consts::{mir_to_const, ConstEvalCtxt, FullInt};
|
||||
use clippy_utils::diagnostics::span_lint_and_note;
|
||||
use core::cmp::Ordering;
|
||||
use rustc_hir::{Arm, Expr, PatKind, RangeEnd};
|
||||
@ -34,19 +34,19 @@ fn all_ranges<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'_>], ty: Ty<'tcx>)
|
||||
if let Arm { pat, guard: None, .. } = *arm {
|
||||
if let PatKind::Range(ref lhs, ref rhs, range_end) = pat.kind {
|
||||
let lhs_const = if let Some(lhs) = lhs {
|
||||
constant(cx, cx.typeck_results(), lhs)?
|
||||
ConstEvalCtxt::new(cx).eval(lhs)?
|
||||
} else {
|
||||
let min_val_const = ty.numeric_min_val(cx.tcx)?;
|
||||
mir_to_const(cx.tcx, mir::Const::from_ty_const(min_val_const, ty, cx.tcx))?
|
||||
};
|
||||
let rhs_const = if let Some(rhs) = rhs {
|
||||
constant(cx, cx.typeck_results(), rhs)?
|
||||
ConstEvalCtxt::new(cx).eval(rhs)?
|
||||
} else {
|
||||
let max_val_const = ty.numeric_max_val(cx.tcx)?;
|
||||
mir_to_const(cx.tcx, mir::Const::from_ty_const(max_val_const, ty, cx.tcx))?
|
||||
};
|
||||
let lhs_val = lhs_const.int_value(cx, ty)?;
|
||||
let rhs_val = rhs_const.int_value(cx, ty)?;
|
||||
let lhs_val = lhs_const.int_value(cx.tcx, ty)?;
|
||||
let rhs_val = rhs_const.int_value(cx.tcx, ty)?;
|
||||
let rhs_bound = match range_end {
|
||||
RangeEnd::Included => EndBound::Included(rhs_val),
|
||||
RangeEnd::Excluded => EndBound::Excluded(rhs_val),
|
||||
@ -58,7 +58,7 @@ fn all_ranges<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'_>], ty: Ty<'tcx>)
|
||||
}
|
||||
|
||||
if let PatKind::Lit(value) = pat.kind {
|
||||
let value = constant_full_int(cx, cx.typeck_results(), value)?;
|
||||
let value = ConstEvalCtxt::new(cx).eval_full_int(value)?;
|
||||
return Some(SpannedRange {
|
||||
span: pat.span,
|
||||
node: (value, EndBound::Included(value)),
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
use super::IS_DIGIT_ASCII_RADIX;
|
||||
use clippy_config::msrvs::{self, Msrv};
|
||||
use clippy_utils::consts::{constant_full_int, FullInt};
|
||||
use clippy_utils::consts::{ConstEvalCtxt, FullInt};
|
||||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use clippy_utils::source::snippet_with_applicability;
|
||||
use rustc_errors::Applicability;
|
||||
@ -24,7 +24,7 @@ pub(super) fn check<'tcx>(
|
||||
return;
|
||||
}
|
||||
|
||||
if let Some(radix_val) = constant_full_int(cx, cx.typeck_results(), radix) {
|
||||
if let Some(radix_val) = ConstEvalCtxt::new(cx).eval_full_int(radix) {
|
||||
let (num, replacement) = match radix_val {
|
||||
FullInt::S(10) | FullInt::U(10) => (10, "is_ascii_digit"),
|
||||
FullInt::S(16) | FullInt::U(16) => (16, "is_ascii_hexdigit"),
|
||||
|
@ -1,4 +1,4 @@
|
||||
use clippy_utils::consts::constant_is_empty;
|
||||
use clippy_utils::consts::ConstEvalCtxt;
|
||||
use clippy_utils::diagnostics::span_lint;
|
||||
use clippy_utils::{find_binding_init, path_to_local};
|
||||
use rustc_hir::{Expr, HirId};
|
||||
@ -18,7 +18,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &'_ Expr<'_>, receiver: &Expr<'_
|
||||
if !receiver.span.eq_ctxt(init_expr.span) {
|
||||
return;
|
||||
}
|
||||
if let Some(init_is_empty) = constant_is_empty(cx, init_expr) {
|
||||
if let Some(init_is_empty) = ConstEvalCtxt::new(cx).eval_is_empty(init_expr) {
|
||||
span_lint(
|
||||
cx,
|
||||
CONST_IS_EMPTY,
|
||||
|
@ -1,4 +1,4 @@
|
||||
use clippy_utils::consts::{constant, Constant};
|
||||
use clippy_utils::consts::{ConstEvalCtxt, Constant};
|
||||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use clippy_utils::source::snippet_with_applicability;
|
||||
use clippy_utils::{is_lang_item_or_ctor, is_trait_method};
|
||||
@ -14,7 +14,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr
|
||||
if let OwnerNode::Item(item) = cx.tcx.hir_owner_node(cx.tcx.hir().get_parent_item(expr.hir_id))
|
||||
&& let def_id = item.owner_id.to_def_id()
|
||||
&& is_trait_method(cx, expr, sym::Iterator)
|
||||
&& let Some(Constant::Int(0)) = constant(cx, cx.typeck_results(), arg)
|
||||
&& let Some(Constant::Int(0)) = ConstEvalCtxt::new(cx).eval(arg)
|
||||
&& !is_lang_item_or_ctor(cx, def_id, LangItem::IteratorNext)
|
||||
{
|
||||
let mut app = Applicability::MachineApplicable;
|
||||
|
@ -1,4 +1,4 @@
|
||||
use clippy_utils::consts::{constant, Constant};
|
||||
use clippy_utils::consts::{ConstEvalCtxt, Constant};
|
||||
use clippy_utils::diagnostics::span_lint_and_then;
|
||||
use clippy_utils::{is_from_proc_macro, is_trait_method};
|
||||
use rustc_errors::Applicability;
|
||||
@ -11,7 +11,7 @@
|
||||
pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, arg_expr: &Expr<'_>) {
|
||||
if !expr.span.from_expansion()
|
||||
&& is_trait_method(cx, expr, sym::Iterator)
|
||||
&& let Some(arg) = constant(cx, cx.typeck_results(), arg_expr).and_then(|constant| {
|
||||
&& let Some(arg) = ConstEvalCtxt::new(cx).eval(arg_expr).and_then(|constant| {
|
||||
if let Constant::Int(arg) = constant {
|
||||
Some(arg)
|
||||
} else {
|
||||
|
@ -1,4 +1,4 @@
|
||||
use clippy_utils::consts::{constant, Constant};
|
||||
use clippy_utils::consts::{ConstEvalCtxt, Constant};
|
||||
use clippy_utils::diagnostics::span_lint;
|
||||
use clippy_utils::is_trait_method;
|
||||
use rustc_hir as hir;
|
||||
@ -9,7 +9,7 @@
|
||||
|
||||
pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &hir::Expr<'_>, arg: &'tcx hir::Expr<'_>) {
|
||||
if is_trait_method(cx, expr, sym::Iterator) {
|
||||
if let Some(Constant::Int(0)) = constant(cx, cx.typeck_results(), arg) {
|
||||
if let Some(Constant::Int(0)) = ConstEvalCtxt::new(cx).eval(arg) {
|
||||
span_lint(
|
||||
cx,
|
||||
ITERATOR_STEP_BY_ZERO,
|
||||
|
@ -133,7 +133,7 @@
|
||||
|
||||
use clippy_config::msrvs::{self, Msrv};
|
||||
use clippy_config::Conf;
|
||||
use clippy_utils::consts::{constant, Constant};
|
||||
use clippy_utils::consts::{ConstEvalCtxt, Constant};
|
||||
use clippy_utils::diagnostics::{span_lint, span_lint_and_help};
|
||||
use clippy_utils::macros::FormatArgsStorage;
|
||||
use clippy_utils::ty::{contains_ty_adt_constructor_opaque, implements_trait, is_copy, is_type_diagnostic_item};
|
||||
@ -4915,13 +4915,13 @@ fn check_methods<'tcx>(&self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
|
||||
str_split::check(cx, expr, recv, arg);
|
||||
},
|
||||
("splitn" | "rsplitn", [count_arg, pat_arg]) => {
|
||||
if let Some(Constant::Int(count)) = constant(cx, cx.typeck_results(), count_arg) {
|
||||
if let Some(Constant::Int(count)) = ConstEvalCtxt::new(cx).eval(count_arg) {
|
||||
suspicious_splitn::check(cx, name, expr, recv, count);
|
||||
str_splitn::check(cx, name, expr, recv, pat_arg, count, &self.msrv);
|
||||
}
|
||||
},
|
||||
("splitn_mut" | "rsplitn_mut", [count_arg, _]) => {
|
||||
if let Some(Constant::Int(count)) = constant(cx, cx.typeck_results(), count_arg) {
|
||||
if let Some(Constant::Int(count)) = ConstEvalCtxt::new(cx).eval(count_arg) {
|
||||
suspicious_splitn::check(cx, name, expr, recv, count);
|
||||
}
|
||||
},
|
||||
|
@ -1,4 +1,4 @@
|
||||
use clippy_utils::consts::{constant, Constant};
|
||||
use clippy_utils::consts::{ConstEvalCtxt, Constant};
|
||||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use clippy_utils::source::snippet;
|
||||
use clippy_utils::ty::is_type_lang_item;
|
||||
@ -14,7 +14,7 @@ pub(super) fn check<'tcx>(
|
||||
recv: &'tcx Expr<'_>,
|
||||
repeat_arg: &'tcx Expr<'_>,
|
||||
) {
|
||||
if constant(cx, cx.typeck_results(), repeat_arg) == Some(Constant::Int(1)) {
|
||||
if ConstEvalCtxt::new(cx).eval(repeat_arg) == Some(Constant::Int(1)) {
|
||||
let ty = cx.typeck_results().expr_ty(recv).peel_refs();
|
||||
if ty.is_str() {
|
||||
span_lint_and_sugg(
|
||||
|
@ -1,5 +1,5 @@
|
||||
use clippy_config::msrvs::{self, Msrv};
|
||||
use clippy_utils::consts::{constant, Constant};
|
||||
use clippy_utils::consts::{ConstEvalCtxt, Constant};
|
||||
use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then};
|
||||
use clippy_utils::source::snippet_with_context;
|
||||
use clippy_utils::usage::local_used_after_expr;
|
||||
@ -301,7 +301,7 @@ fn parse_iter_usage<'tcx>(
|
||||
};
|
||||
},
|
||||
("nth" | "skip", [idx_expr]) if cx.tcx.trait_of_item(did) == Some(iter_id) => {
|
||||
if let Some(Constant::Int(idx)) = constant(cx, cx.typeck_results(), idx_expr) {
|
||||
if let Some(Constant::Int(idx)) = ConstEvalCtxt::new(cx).eval(idx_expr) {
|
||||
let span = if name.ident.as_str() == "nth" {
|
||||
e.span
|
||||
} else if let Some((_, Node::Expr(next_expr))) = iter.next()
|
||||
|
@ -3,7 +3,7 @@
|
||||
use super::UNNECESSARY_MIN_OR_MAX;
|
||||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
|
||||
use clippy_utils::consts::{constant, constant_with_source, Constant, ConstantSource, FullInt};
|
||||
use clippy_utils::consts::{ConstEvalCtxt, Constant, ConstantSource, FullInt};
|
||||
use clippy_utils::source::snippet;
|
||||
|
||||
use rustc_errors::Applicability;
|
||||
@ -20,10 +20,9 @@ pub(super) fn check<'tcx>(
|
||||
arg: &'tcx Expr<'_>,
|
||||
) {
|
||||
let typeck_results = cx.typeck_results();
|
||||
if let Some((left, ConstantSource::Local | ConstantSource::CoreConstant)) =
|
||||
constant_with_source(cx, typeck_results, recv)
|
||||
&& let Some((right, ConstantSource::Local | ConstantSource::CoreConstant)) =
|
||||
constant_with_source(cx, typeck_results, arg)
|
||||
let ecx = ConstEvalCtxt::with_env(cx.tcx, cx.param_env, typeck_results);
|
||||
if let Some((left, ConstantSource::Local | ConstantSource::CoreConstant)) = ecx.eval_with_source(recv)
|
||||
&& let Some((right, ConstantSource::Local | ConstantSource::CoreConstant)) = ecx.eval_with_source(arg)
|
||||
{
|
||||
let Some(ord) = Constant::partial_cmp(cx.tcx, typeck_results.expr_ty(recv), &left, &right) else {
|
||||
return;
|
||||
@ -78,9 +77,9 @@ enum Extrema {
|
||||
fn detect_extrema<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option<Extrema> {
|
||||
let ty = cx.typeck_results().expr_ty(expr);
|
||||
|
||||
let cv = constant(cx, cx.typeck_results(), expr)?;
|
||||
let cv = ConstEvalCtxt::new(cx).eval(expr)?;
|
||||
|
||||
match (cv.int_value(cx, ty)?, ty.kind()) {
|
||||
match (cv.int_value(cx.tcx, ty)?, ty.kind()) {
|
||||
(FullInt::S(i), &ty::Int(ity)) if i == i128::MIN >> (128 - ity.bit_width()?) => Some(Extrema::Minimum),
|
||||
(FullInt::S(i), &ty::Int(ity)) if i == i128::MAX >> (128 - ity.bit_width()?) => Some(Extrema::Maximum),
|
||||
(FullInt::U(i), &ty::Uint(uty)) if i == u128::MAX >> (128 - uty.bit_width()?) => Some(Extrema::Maximum),
|
||||
|
@ -1,4 +1,4 @@
|
||||
use clippy_utils::consts::{constant_simple, Constant};
|
||||
use clippy_utils::consts::{ConstEvalCtxt, Constant};
|
||||
use clippy_utils::diagnostics::span_lint;
|
||||
use clippy_utils::is_trait_method;
|
||||
use rustc_hir::{Expr, ExprKind};
|
||||
@ -106,15 +106,11 @@ fn fetch_const<'a, 'tcx>(
|
||||
if args.next().is_some() {
|
||||
return None;
|
||||
}
|
||||
constant_simple(cx, cx.typeck_results(), first_arg).map_or_else(
|
||||
|| constant_simple(cx, cx.typeck_results(), second_arg).map(|c| (m, c, first_arg)),
|
||||
|c| {
|
||||
if constant_simple(cx, cx.typeck_results(), second_arg).is_none() {
|
||||
// otherwise ignore
|
||||
Some((m, c, second_arg))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
},
|
||||
)
|
||||
let ecx = ConstEvalCtxt::new(cx);
|
||||
match (ecx.eval_simple(first_arg), ecx.eval_simple(second_arg)) {
|
||||
(Some(c), None) => Some((m, c, second_arg)),
|
||||
(None, Some(c)) => Some((m, c, first_arg)),
|
||||
// otherwise ignore
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
@ -3,7 +3,7 @@
|
||||
use rustc_middle::ty;
|
||||
|
||||
use clippy_utils::comparisons::{normalize_comparison, Rel};
|
||||
use clippy_utils::consts::{constant, Constant};
|
||||
use clippy_utils::consts::{ConstEvalCtxt, Constant};
|
||||
use clippy_utils::diagnostics::span_lint_and_help;
|
||||
use clippy_utils::source::snippet;
|
||||
use clippy_utils::ty::is_isize_or_usize;
|
||||
@ -121,7 +121,7 @@ fn detect_absurd_comparison<'tcx>(
|
||||
fn detect_extreme_expr<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option<ExtremeExpr<'tcx>> {
|
||||
let ty = cx.typeck_results().expr_ty(expr);
|
||||
|
||||
let cv = constant(cx, cx.typeck_results(), expr)?;
|
||||
let cv = ConstEvalCtxt::new(cx).eval(expr)?;
|
||||
|
||||
let which = match (ty.kind(), cv) {
|
||||
(&ty::Bool, Constant::Bool(false)) | (&ty::Uint(_), Constant::Int(0)) => ExtremeType::Minimum,
|
||||
|
@ -1,6 +1,6 @@
|
||||
use super::ARITHMETIC_SIDE_EFFECTS;
|
||||
use clippy_config::Conf;
|
||||
use clippy_utils::consts::{constant, constant_simple, Constant};
|
||||
use clippy_utils::consts::{ConstEvalCtxt, Constant};
|
||||
use clippy_utils::diagnostics::span_lint;
|
||||
use clippy_utils::ty::is_type_diagnostic_item;
|
||||
use clippy_utils::{expr_or_init, is_from_proc_macro, is_lint_allowed, peel_hir_expr_refs, peel_hir_expr_unary};
|
||||
@ -162,7 +162,7 @@ fn literal_integer(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> Option<u128> {
|
||||
{
|
||||
return Some(n.get());
|
||||
}
|
||||
if let Some(Constant::Int(n)) = constant(cx, cx.typeck_results(), expr) {
|
||||
if let Some(Constant::Int(n)) = ConstEvalCtxt::new(cx).eval(expr) {
|
||||
return Some(n);
|
||||
}
|
||||
None
|
||||
@ -200,7 +200,7 @@ fn manage_bin_ops<'tcx>(
|
||||
lhs: &'tcx hir::Expr<'_>,
|
||||
rhs: &'tcx hir::Expr<'_>,
|
||||
) {
|
||||
if constant_simple(cx, cx.typeck_results(), expr).is_some() {
|
||||
if ConstEvalCtxt::new(cx).eval_simple(expr).is_some() {
|
||||
return;
|
||||
}
|
||||
if !matches!(
|
||||
@ -280,7 +280,7 @@ fn manage_method_call<'tcx>(
|
||||
let Some(arg) = args.first() else {
|
||||
return;
|
||||
};
|
||||
if constant_simple(cx, cx.typeck_results(), receiver).is_some() {
|
||||
if ConstEvalCtxt::new(cx).eval_simple(receiver).is_some() {
|
||||
return;
|
||||
}
|
||||
let instance_ty = cx.typeck_results().expr_ty(receiver);
|
||||
@ -308,7 +308,7 @@ fn manage_unary_ops<'tcx>(
|
||||
let hir::UnOp::Neg = un_op else {
|
||||
return;
|
||||
};
|
||||
if constant(cx, cx.typeck_results(), un_expr).is_some() {
|
||||
if ConstEvalCtxt::new(cx).eval(un_expr).is_some() {
|
||||
return;
|
||||
}
|
||||
let ty = cx.typeck_results().expr_ty(expr).peel_refs();
|
||||
|
@ -1,4 +1,4 @@
|
||||
use clippy_utils::consts::{constant, Constant};
|
||||
use clippy_utils::consts::{ConstEvalCtxt, Constant};
|
||||
use clippy_utils::diagnostics::span_lint;
|
||||
use rustc_hir::{BinOpKind, Expr, ExprKind};
|
||||
use rustc_lint::LateContext;
|
||||
@ -166,7 +166,7 @@ fn check_ineffective_gt(cx: &LateContext<'_>, span: Span, m: u128, c: u128, op:
|
||||
}
|
||||
|
||||
fn fetch_int_literal(cx: &LateContext<'_>, lit: &Expr<'_>) -> Option<u128> {
|
||||
match constant(cx, cx.typeck_results(), lit)? {
|
||||
match ConstEvalCtxt::new(cx).eval(lit)? {
|
||||
Constant::Int(n) => Some(n),
|
||||
_ => None,
|
||||
}
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
use std::cmp::Ordering;
|
||||
|
||||
use clippy_utils::consts::{constant, Constant};
|
||||
use clippy_utils::consts::{ConstEvalCtxt, Constant};
|
||||
use rustc_hir::{BinOpKind, Expr, ExprKind};
|
||||
use rustc_lint::LateContext;
|
||||
use rustc_middle::ty::layout::HasTyCtxt;
|
||||
@ -26,7 +26,8 @@ fn comparison_to_const<'tcx>(
|
||||
if let ExprKind::Binary(operator, left, right) = expr.kind
|
||||
&& let Ok(cmp_op) = CmpOp::try_from(operator.node)
|
||||
{
|
||||
match (constant(cx, typeck, left), constant(cx, typeck, right)) {
|
||||
let ecx = ConstEvalCtxt::with_env(cx.tcx, cx.param_env, typeck);
|
||||
match (ecx.eval(left), ecx.eval(right)) {
|
||||
(Some(_), Some(_)) => None,
|
||||
(_, Some(con)) => Some((cmp_op, left, right, con, typeck.expr_ty(right))),
|
||||
(Some(con), _) => Some((cmp_op.reverse(), right, left, con, typeck.expr_ty(left))),
|
||||
|
@ -1,4 +1,4 @@
|
||||
use clippy_utils::consts::{constant, Constant};
|
||||
use clippy_utils::consts::{ConstEvalCtxt, Constant};
|
||||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use clippy_utils::source::snippet_with_applicability;
|
||||
use clippy_utils::ty::is_type_diagnostic_item;
|
||||
@ -19,7 +19,7 @@ pub(crate) fn check<'tcx>(
|
||||
if op == BinOpKind::Div
|
||||
&& let ExprKind::MethodCall(method_path, self_arg, [], _) = left.kind
|
||||
&& is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(self_arg).peel_refs(), sym::Duration)
|
||||
&& let Some(Constant::Int(divisor)) = constant(cx, cx.typeck_results(), right)
|
||||
&& let Some(Constant::Int(divisor)) = ConstEvalCtxt::new(cx).eval(right)
|
||||
{
|
||||
let suggested_fn = match (method_path.ident.as_str(), divisor) {
|
||||
("subsec_micros", 1_000) | ("subsec_nanos", 1_000_000) => "subsec_millis",
|
||||
|
@ -1,4 +1,4 @@
|
||||
use clippy_utils::consts::{constant_simple, Constant};
|
||||
use clippy_utils::consts::{ConstEvalCtxt, Constant};
|
||||
use clippy_utils::diagnostics::span_lint;
|
||||
use clippy_utils::ty::same_type_and_consts;
|
||||
|
||||
@ -39,7 +39,7 @@ fn check_op<'tcx>(
|
||||
other: &Expr<'tcx>,
|
||||
parent: &Expr<'tcx>,
|
||||
) {
|
||||
if constant_simple(cx, tck, op) == Some(Constant::Int(0)) {
|
||||
if ConstEvalCtxt::with_env(cx.tcx, cx.param_env, tck).eval_simple(op) == Some(Constant::Int(0)) {
|
||||
if different_types(tck, other, parent) {
|
||||
return;
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
use clippy_utils::consts::{constant_with_source, Constant};
|
||||
use clippy_utils::consts::{ConstEvalCtxt, Constant};
|
||||
use clippy_utils::diagnostics::span_lint_and_then;
|
||||
use clippy_utils::get_item_name;
|
||||
use clippy_utils::sugg::Sugg;
|
||||
@ -17,12 +17,14 @@ pub(crate) fn check<'tcx>(
|
||||
right: &'tcx Expr<'_>,
|
||||
) {
|
||||
if (op == BinOpKind::Eq || op == BinOpKind::Ne) && is_float(cx, left) {
|
||||
let left_is_local = match constant_with_source(cx, cx.typeck_results(), left) {
|
||||
let typeck = cx.typeck_results();
|
||||
let ecx = ConstEvalCtxt::with_env(cx.tcx, cx.param_env, typeck);
|
||||
let left_is_local = match ecx.eval_with_source(left) {
|
||||
Some((c, s)) if !is_allowed(&c) => s.is_local(),
|
||||
Some(_) => return,
|
||||
None => true,
|
||||
};
|
||||
let right_is_local = match constant_with_source(cx, cx.typeck_results(), right) {
|
||||
let right_is_local = match ecx.eval_with_source(right) {
|
||||
Some((c, s)) if !is_allowed(&c) => s.is_local(),
|
||||
Some(_) => return,
|
||||
None => true,
|
||||
|
@ -1,4 +1,4 @@
|
||||
use clippy_utils::consts::{constant_full_int, constant_simple, Constant, FullInt};
|
||||
use clippy_utils::consts::{ConstEvalCtxt, Constant, FullInt};
|
||||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use clippy_utils::source::snippet_with_applicability;
|
||||
use clippy_utils::{clip, peel_hir_expr_refs, unsext};
|
||||
@ -184,14 +184,13 @@ fn is_allowed(cx: &LateContext<'_>, cmp: BinOpKind, left: &Expr<'_>, right: &Exp
|
||||
&& cx.typeck_results().expr_ty(right).peel_refs().is_integral()
|
||||
// `1 << 0` is a common pattern in bit manipulation code
|
||||
&& !(cmp == BinOpKind::Shl
|
||||
&& constant_simple(cx, cx.typeck_results(), right) == Some(Constant::Int(0))
|
||||
&& constant_simple(cx, cx.typeck_results(), left) == Some(Constant::Int(1)))
|
||||
&& ConstEvalCtxt::new(cx).eval_simple(right) == Some(Constant::Int(0))
|
||||
&& ConstEvalCtxt::new(cx).eval_simple(left) == Some(Constant::Int(1)))
|
||||
}
|
||||
|
||||
fn check_remainder(cx: &LateContext<'_>, left: &Expr<'_>, right: &Expr<'_>, span: Span, arg: Span) {
|
||||
let lhs_const = constant_full_int(cx, cx.typeck_results(), left);
|
||||
let rhs_const = constant_full_int(cx, cx.typeck_results(), right);
|
||||
if match (lhs_const, rhs_const) {
|
||||
let ecx = ConstEvalCtxt::new(cx);
|
||||
if match (ecx.eval_full_int(left), ecx.eval_full_int(right)) {
|
||||
(Some(FullInt::S(lv)), Some(FullInt::S(rv))) => lv.abs() < rv.abs(),
|
||||
(Some(FullInt::U(lv)), Some(FullInt::U(rv))) => lv < rv,
|
||||
_ => return,
|
||||
@ -201,7 +200,7 @@ fn check_remainder(cx: &LateContext<'_>, left: &Expr<'_>, right: &Expr<'_>, span
|
||||
}
|
||||
|
||||
fn check_op(cx: &LateContext<'_>, e: &Expr<'_>, m: i8, span: Span, arg: Span, parens: Parens, is_erased: bool) -> bool {
|
||||
if let Some(Constant::Int(v)) = constant_simple(cx, cx.typeck_results(), e).map(Constant::peel_refs) {
|
||||
if let Some(Constant::Int(v)) = ConstEvalCtxt::new(cx).eval_simple(e).map(Constant::peel_refs) {
|
||||
let check = match *cx.typeck_results().expr_ty(e).peel_refs().kind() {
|
||||
ty::Int(ity) => unsext(cx.tcx, -1_i128, ity),
|
||||
ty::Uint(uty) => clip(cx.tcx, !0, uty),
|
||||
|
@ -1,4 +1,4 @@
|
||||
use clippy_utils::consts::{constant, Constant};
|
||||
use clippy_utils::consts::{ConstEvalCtxt, Constant};
|
||||
use clippy_utils::diagnostics::span_lint_and_then;
|
||||
use clippy_utils::sext;
|
||||
use rustc_hir::{BinOpKind, Expr, ExprKind, Node};
|
||||
@ -42,15 +42,11 @@ fn used_in_comparison_with_zero(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
|
||||
};
|
||||
|
||||
if op.node == BinOpKind::Eq || op.node == BinOpKind::Ne {
|
||||
if let Some(Constant::Int(0)) = constant(cx, cx.typeck_results(), rhs) {
|
||||
return true;
|
||||
}
|
||||
if let Some(Constant::Int(0)) = constant(cx, cx.typeck_results(), lhs) {
|
||||
return true;
|
||||
}
|
||||
let ecx = ConstEvalCtxt::new(cx);
|
||||
matches!(ecx.eval(lhs), Some(Constant::Int(0))) || matches!(ecx.eval(rhs), Some(Constant::Int(0)))
|
||||
} else {
|
||||
false
|
||||
}
|
||||
|
||||
false
|
||||
}
|
||||
|
||||
struct OperandInfo {
|
||||
@ -60,7 +56,7 @@ struct OperandInfo {
|
||||
}
|
||||
|
||||
fn analyze_operand(operand: &Expr<'_>, cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<OperandInfo> {
|
||||
match constant(cx, cx.typeck_results(), operand) {
|
||||
match ConstEvalCtxt::new(cx).eval(operand) {
|
||||
Some(Constant::Int(v)) => match *cx.typeck_results().expr_ty(expr).kind() {
|
||||
ty::Int(ity) => {
|
||||
let value = sext(cx.tcx, v, ity);
|
||||
|
@ -1,5 +1,5 @@
|
||||
use super::FLOAT_ARITHMETIC;
|
||||
use clippy_utils::consts::constant_simple;
|
||||
use clippy_utils::consts::ConstEvalCtxt;
|
||||
use clippy_utils::diagnostics::span_lint;
|
||||
use rustc_hir as hir;
|
||||
use rustc_lint::LateContext;
|
||||
@ -55,7 +55,7 @@ pub fn check_negate<'tcx>(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Ex
|
||||
return;
|
||||
}
|
||||
let ty = cx.typeck_results().expr_ty(arg);
|
||||
if constant_simple(cx, cx.typeck_results(), expr).is_none() && ty.is_floating_point() {
|
||||
if ConstEvalCtxt::new(cx).eval_simple(expr).is_none() && ty.is_floating_point() {
|
||||
span_lint(cx, FLOAT_ARITHMETIC, expr.span, "floating-point arithmetic detected");
|
||||
self.expr_id = Some(expr.hir_id);
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
use clippy_config::msrvs::{self, Msrv};
|
||||
use clippy_config::Conf;
|
||||
use clippy_utils::consts::{constant, Constant};
|
||||
use clippy_utils::consts::{ConstEvalCtxt, Constant};
|
||||
use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg, span_lint_and_then};
|
||||
use clippy_utils::source::{snippet, snippet_with_applicability, SpanRangeExt};
|
||||
use clippy_utils::sugg::Sugg;
|
||||
@ -319,7 +319,7 @@ fn check_range_bounds<'a, 'tcx>(cx: &'a LateContext<'tcx>, ex: &'a Expr<'_>) ->
|
||||
_ => return None,
|
||||
};
|
||||
if let Some(id) = path_to_local(l) {
|
||||
if let Some(c) = constant(cx, cx.typeck_results(), r) {
|
||||
if let Some(c) = ConstEvalCtxt::new(cx).eval(r) {
|
||||
return Some(RangeBounds {
|
||||
val: c,
|
||||
expr: r,
|
||||
@ -331,7 +331,7 @@ fn check_range_bounds<'a, 'tcx>(cx: &'a LateContext<'tcx>, ex: &'a Expr<'_>) ->
|
||||
});
|
||||
}
|
||||
} else if let Some(id) = path_to_local(r) {
|
||||
if let Some(c) = constant(cx, cx.typeck_results(), l) {
|
||||
if let Some(c) = ConstEvalCtxt::new(cx).eval(l) {
|
||||
return Some(RangeBounds {
|
||||
val: c,
|
||||
expr: l,
|
||||
@ -451,8 +451,9 @@ fn is_empty_range(limits: RangeLimits, ordering: Ordering) -> bool {
|
||||
}) = higher::Range::hir(expr)
|
||||
&& let ty = cx.typeck_results().expr_ty(start)
|
||||
&& let ty::Int(_) | ty::Uint(_) = ty.kind()
|
||||
&& let Some(start_idx) = constant(cx, cx.typeck_results(), start)
|
||||
&& let Some(end_idx) = constant(cx, cx.typeck_results(), end)
|
||||
&& let ecx = ConstEvalCtxt::new(cx)
|
||||
&& let Some(start_idx) = ecx.eval(start)
|
||||
&& let Some(end_idx) = ecx.eval(end)
|
||||
&& let Some(ordering) = Constant::partial_cmp(cx.tcx, ty, &start_idx, &end_idx)
|
||||
&& is_empty_range(limits, ordering)
|
||||
{
|
||||
|
@ -1,6 +1,6 @@
|
||||
use std::fmt::Display;
|
||||
|
||||
use clippy_utils::consts::{constant, Constant};
|
||||
use clippy_utils::consts::{ConstEvalCtxt, Constant};
|
||||
use clippy_utils::diagnostics::{span_lint, span_lint_and_help};
|
||||
use clippy_utils::source::snippet_opt;
|
||||
use clippy_utils::{def_path_def_ids, path_def_id, paths};
|
||||
@ -148,7 +148,7 @@ fn lint_syntax_error(cx: &LateContext<'_>, error: ®ex_syntax::Error, unescape
|
||||
}
|
||||
|
||||
fn const_str<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> Option<String> {
|
||||
constant(cx, cx.typeck_results(), e).and_then(|c| match c {
|
||||
ConstEvalCtxt::new(cx).eval(e).and_then(|c| match c {
|
||||
Constant::Str(s) => Some(s),
|
||||
_ => None,
|
||||
})
|
||||
|
@ -1,4 +1,4 @@
|
||||
use clippy_utils::consts::{constant, Constant};
|
||||
use clippy_utils::consts::{ConstEvalCtxt, Constant};
|
||||
use clippy_utils::diagnostics::span_lint_and_then;
|
||||
use clippy_utils::higher::VecArgs;
|
||||
use clippy_utils::macros::matching_root_macro_call;
|
||||
@ -69,7 +69,7 @@ fn check_vec_macro(cx: &LateContext<'_>, expr: &Expr<'_>) {
|
||||
&& let Some(VecArgs::Repeat(repeat_expr, len_expr)) = VecArgs::hir(cx, expr)
|
||||
&& fn_def_id(cx, repeat_expr).is_some_and(|did| match_def_path(cx, did, &paths::VEC_WITH_CAPACITY))
|
||||
&& !len_expr.span.from_expansion()
|
||||
&& let Some(Constant::Int(2..)) = constant(cx, cx.typeck_results(), expr_or_init(cx, len_expr))
|
||||
&& let Some(Constant::Int(2..)) = ConstEvalCtxt::new(cx).eval(expr_or_init(cx, len_expr))
|
||||
{
|
||||
emit_lint(
|
||||
cx,
|
||||
|
@ -1,4 +1,4 @@
|
||||
use clippy_utils::consts::{constant, Constant};
|
||||
use clippy_utils::consts::{ConstEvalCtxt, Constant};
|
||||
use clippy_utils::diagnostics::span_lint_and_then;
|
||||
use clippy_utils::{is_integer_literal, is_path_diagnostic_item};
|
||||
use rustc_hir::{Expr, ExprKind};
|
||||
@ -33,10 +33,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, arg: &'t
|
||||
// Catching:
|
||||
// transmute over constants that resolve to `null`.
|
||||
ExprKind::Path(ref _qpath)
|
||||
if matches!(
|
||||
constant(cx, cx.typeck_results(), casts_peeled),
|
||||
Some(Constant::RawPtr(0))
|
||||
) =>
|
||||
if matches!(ConstEvalCtxt::new(cx).eval(casts_peeled), Some(Constant::RawPtr(0))) =>
|
||||
{
|
||||
lint_expr(cx, expr);
|
||||
true
|
||||
|
@ -1,4 +1,4 @@
|
||||
use clippy_utils::consts::{constant, Constant};
|
||||
use clippy_utils::consts::{ConstEvalCtxt, Constant};
|
||||
use clippy_utils::diagnostics::span_lint;
|
||||
use clippy_utils::{is_integer_literal, is_path_diagnostic_item};
|
||||
use rustc_hir::{Expr, ExprKind};
|
||||
@ -17,7 +17,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, arg: &'t
|
||||
|
||||
// Catching transmute over constants that resolve to `null`.
|
||||
if let ExprKind::Path(ref _qpath) = arg.kind
|
||||
&& let Some(Constant::RawPtr(0)) = constant(cx, cx.typeck_results(), arg)
|
||||
&& let Some(Constant::RawPtr(0)) = ConstEvalCtxt::new(cx).eval(arg)
|
||||
{
|
||||
span_lint(cx, TRANSMUTING_NULL, expr.span, LINT_MSG);
|
||||
return true;
|
||||
|
@ -1,4 +1,4 @@
|
||||
use clippy_utils::consts::{constant_simple, Constant};
|
||||
use clippy_utils::consts::{ConstEvalCtxt, Constant};
|
||||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use clippy_utils::source::snippet;
|
||||
use clippy_utils::ty::match_type;
|
||||
@ -93,7 +93,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
|
||||
if let ExprKind::Call(func, [arg]) = &expr.kind
|
||||
&& let ty::FnDef(def_id, _) = cx.typeck_results().expr_ty(func).kind()
|
||||
&& match_def_path(cx, *def_id, &paths::SYMBOL_INTERN)
|
||||
&& let Some(Constant::Str(arg)) = constant_simple(cx, cx.typeck_results(), arg)
|
||||
&& let Some(Constant::Str(arg)) = ConstEvalCtxt::new(cx).eval_simple(arg)
|
||||
&& let value = Symbol::intern(&arg).as_u32()
|
||||
&& let Some(&def_id) = self.symbol_map.get(&value)
|
||||
{
|
||||
@ -199,7 +199,7 @@ fn symbol_str_expr<'tcx>(&self, expr: &'tcx Expr<'tcx>, cx: &LateContext<'tcx>)
|
||||
});
|
||||
}
|
||||
// is a string constant
|
||||
if let Some(Constant::Str(s)) = constant_simple(cx, cx.typeck_results(), expr) {
|
||||
if let Some(Constant::Str(s)) = ConstEvalCtxt::new(cx).eval_simple(expr) {
|
||||
let value = Symbol::intern(&s).as_u32();
|
||||
// ...which matches a symbol constant
|
||||
if let Some(&def_id) = self.symbol_map.get(&value) {
|
||||
|
@ -1,4 +1,4 @@
|
||||
use clippy_utils::consts::{constant_simple, Constant};
|
||||
use clippy_utils::consts::{ConstEvalCtxt, Constant};
|
||||
use clippy_utils::def_path_res;
|
||||
use clippy_utils::diagnostics::span_lint;
|
||||
use rustc_hir as hir;
|
||||
@ -32,9 +32,9 @@ fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
|
||||
let mod_name = &cx.tcx.item_name(local_def_id.to_def_id());
|
||||
if mod_name.as_str() == "paths"
|
||||
&& let hir::ItemKind::Const(.., body_id) = item.kind
|
||||
&& let body = cx.tcx.hir().body(body_id)
|
||||
&& let typeck_results = cx.tcx.typeck_body(body_id)
|
||||
&& let Some(Constant::Vec(path)) = constant_simple(cx, typeck_results, body.value)
|
||||
&& let Some(Constant::Vec(path)) =
|
||||
ConstEvalCtxt::with_env(cx.tcx, cx.tcx.param_env(item.owner_id), cx.tcx.typeck(item.owner_id))
|
||||
.eval_simple(cx.tcx.hir().body(body_id).value)
|
||||
&& let Some(path) = path
|
||||
.iter()
|
||||
.map(|x| {
|
||||
|
@ -3,7 +3,7 @@
|
||||
|
||||
use clippy_config::msrvs::{self, Msrv};
|
||||
use clippy_config::Conf;
|
||||
use clippy_utils::consts::{constant, Constant};
|
||||
use clippy_utils::consts::{ConstEvalCtxt, Constant};
|
||||
use clippy_utils::diagnostics::span_lint_hir_and_then;
|
||||
use clippy_utils::source::snippet_opt;
|
||||
use clippy_utils::ty::is_copy;
|
||||
@ -159,7 +159,7 @@ fn check_vec_macro<'tcx>(
|
||||
|
||||
let snippet = match *vec_args {
|
||||
higher::VecArgs::Repeat(elem, len) => {
|
||||
if let Some(Constant::Int(len_constant)) = constant(cx, cx.typeck_results(), len) {
|
||||
if let Some(Constant::Int(len_constant)) = ConstEvalCtxt::new(cx).eval(len) {
|
||||
// vec![ty; N] works when ty is Clone, [ty; N] requires it to be Copy also
|
||||
if !is_copy(cx, cx.typeck_results().expr_ty(elem)) {
|
||||
return;
|
||||
|
@ -1,4 +1,4 @@
|
||||
use clippy_utils::consts::{constant_simple, Constant};
|
||||
use clippy_utils::consts::{ConstEvalCtxt, Constant};
|
||||
use clippy_utils::diagnostics::span_lint_and_help;
|
||||
use rustc_hir::{BinOpKind, Expr, ExprKind};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
@ -36,8 +36,9 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
|
||||
// TODO - constant_simple does not fold many operations involving floats.
|
||||
// That's probably fine for this lint - it's pretty unlikely that someone would
|
||||
// do something like 0.0/(2.0 - 2.0), but it would be nice to warn on that case too.
|
||||
&& let Some(lhs_value) = constant_simple(cx, cx.typeck_results(), left)
|
||||
&& let Some(rhs_value) = constant_simple(cx, cx.typeck_results(), right)
|
||||
&& let ecx = ConstEvalCtxt::new(cx)
|
||||
&& let Some(lhs_value) = ecx.eval_simple(left)
|
||||
&& let Some(rhs_value) = ecx.eval_simple(right)
|
||||
// FIXME(f16_f128): add these types when eq is available on all platforms
|
||||
&& (Constant::F32(0.0) == lhs_value || Constant::F64(0.0) == lhs_value)
|
||||
&& (Constant::F32(0.0) == rhs_value || Constant::F64(0.0) == rhs_value)
|
||||
|
@ -14,14 +14,13 @@
|
||||
use rustc_lint::LateContext;
|
||||
use rustc_middle::mir::interpret::{alloc_range, Scalar};
|
||||
use rustc_middle::mir::ConstValue;
|
||||
use rustc_middle::ty::{
|
||||
self, EarlyBinder, FloatTy, GenericArgsRef, IntTy, List, ParamEnv, ScalarInt, Ty, TyCtxt, TypeckResults, UintTy,
|
||||
};
|
||||
use rustc_middle::ty::{self, FloatTy, IntTy, ParamEnv, ScalarInt, Ty, TyCtxt, TypeckResults, UintTy};
|
||||
use rustc_middle::{bug, mir, span_bug};
|
||||
use rustc_span::def_id::DefId;
|
||||
use rustc_span::symbol::Ident;
|
||||
use rustc_span::{sym, SyntaxContext};
|
||||
use rustc_target::abi::Size;
|
||||
use std::cell::Cell;
|
||||
use std::cmp::Ordering;
|
||||
use std::hash::{Hash, Hasher};
|
||||
use std::iter;
|
||||
@ -265,10 +264,10 @@ pub fn partial_cmp(tcx: TyCtxt<'_>, cmp_type: Ty<'_>, left: &Self, right: &Self)
|
||||
}
|
||||
|
||||
/// Returns the integer value or `None` if `self` or `val_type` is not integer type.
|
||||
pub fn int_value(&self, cx: &LateContext<'_>, val_type: Ty<'_>) -> Option<FullInt> {
|
||||
pub fn int_value(&self, tcx: TyCtxt<'_>, val_type: Ty<'_>) -> Option<FullInt> {
|
||||
if let Constant::Int(const_int) = *self {
|
||||
match *val_type.kind() {
|
||||
ty::Int(ity) => Some(FullInt::S(sext(cx.tcx, const_int, ity))),
|
||||
ty::Int(ity) => Some(FullInt::S(sext(tcx, const_int, ity))),
|
||||
ty::Uint(_) => Some(FullInt::U(const_int)),
|
||||
_ => None,
|
||||
}
|
||||
@ -324,6 +323,7 @@ pub fn lit_to_mir_constant<'tcx>(lit: &LitKind, ty: Option<Ty<'tcx>>) -> Constan
|
||||
}
|
||||
|
||||
/// The source of a constant value.
|
||||
#[derive(Clone, Copy)]
|
||||
pub enum ConstantSource {
|
||||
/// The value is determined solely from the expression.
|
||||
Local,
|
||||
@ -333,54 +333,11 @@ pub enum ConstantSource {
|
||||
CoreConstant,
|
||||
}
|
||||
impl ConstantSource {
|
||||
pub fn is_local(&self) -> bool {
|
||||
pub fn is_local(self) -> bool {
|
||||
matches!(self, Self::Local)
|
||||
}
|
||||
}
|
||||
|
||||
/// Attempts to check whether the expression is a constant representing an empty slice, str, array,
|
||||
/// etc…
|
||||
pub fn constant_is_empty(lcx: &LateContext<'_>, e: &Expr<'_>) -> Option<bool> {
|
||||
ConstEvalLateContext::new(lcx.tcx, lcx.param_env, lcx.typeck_results()).expr_is_empty(e)
|
||||
}
|
||||
|
||||
/// Attempts to evaluate the expression as a constant.
|
||||
pub fn constant<'tcx>(
|
||||
lcx: &LateContext<'tcx>,
|
||||
typeck_results: &'tcx TypeckResults<'tcx>,
|
||||
e: &Expr<'_>,
|
||||
) -> Option<Constant<'tcx>> {
|
||||
ConstEvalLateContext::new(lcx.tcx, lcx.param_env, typeck_results).expr(e)
|
||||
}
|
||||
|
||||
/// Attempts to evaluate the expression as a constant.
|
||||
pub fn constant_with_source<'tcx>(
|
||||
lcx: &LateContext<'tcx>,
|
||||
typeck_results: &'tcx TypeckResults<'tcx>,
|
||||
e: &Expr<'_>,
|
||||
) -> Option<(Constant<'tcx>, ConstantSource)> {
|
||||
let mut ctxt = ConstEvalLateContext::new(lcx.tcx, lcx.param_env, typeck_results);
|
||||
let res = ctxt.expr(e);
|
||||
res.map(|x| (x, ctxt.source))
|
||||
}
|
||||
|
||||
/// Attempts to evaluate an expression only if its value is not dependent on other items.
|
||||
pub fn constant_simple<'tcx>(
|
||||
lcx: &LateContext<'tcx>,
|
||||
typeck_results: &'tcx TypeckResults<'tcx>,
|
||||
e: &Expr<'_>,
|
||||
) -> Option<Constant<'tcx>> {
|
||||
constant_with_source(lcx, typeck_results, e).and_then(|(c, s)| s.is_local().then_some(c))
|
||||
}
|
||||
|
||||
pub fn constant_full_int<'tcx>(
|
||||
lcx: &LateContext<'tcx>,
|
||||
typeck_results: &'tcx TypeckResults<'tcx>,
|
||||
e: &Expr<'_>,
|
||||
) -> Option<FullInt> {
|
||||
constant_simple(lcx, typeck_results, e)?.int_value(lcx, typeck_results.expr_ty(e))
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, Eq)]
|
||||
pub enum FullInt {
|
||||
S(i128),
|
||||
@ -419,45 +376,87 @@ fn cmp_s_u(s: i128, u: u128) -> Ordering {
|
||||
}
|
||||
}
|
||||
|
||||
pub struct ConstEvalLateContext<'tcx> {
|
||||
/// The context required to evaluate a constant expression.
|
||||
///
|
||||
/// This is currently limited to constant folding and reading the value of named constants.
|
||||
pub struct ConstEvalCtxt<'tcx> {
|
||||
tcx: TyCtxt<'tcx>,
|
||||
typeck_results: &'tcx TypeckResults<'tcx>,
|
||||
param_env: ParamEnv<'tcx>,
|
||||
source: ConstantSource,
|
||||
args: GenericArgsRef<'tcx>,
|
||||
typeck: &'tcx TypeckResults<'tcx>,
|
||||
source: Cell<ConstantSource>,
|
||||
}
|
||||
|
||||
impl<'tcx> ConstEvalLateContext<'tcx> {
|
||||
pub fn new(tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>, typeck_results: &'tcx TypeckResults<'tcx>) -> Self {
|
||||
impl<'tcx> ConstEvalCtxt<'tcx> {
|
||||
/// Creates the evaluation context from the lint context. This requires the lint context to be
|
||||
/// in a body (i.e. `cx.enclosing_body.is_some()`).
|
||||
pub fn new(cx: &LateContext<'tcx>) -> Self {
|
||||
Self {
|
||||
tcx: cx.tcx,
|
||||
param_env: cx.param_env,
|
||||
typeck: cx.typeck_results(),
|
||||
source: Cell::new(ConstantSource::Local),
|
||||
}
|
||||
}
|
||||
|
||||
/// Creates an evaluation context.
|
||||
pub fn with_env(tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>, typeck: &'tcx TypeckResults<'tcx>) -> Self {
|
||||
Self {
|
||||
tcx,
|
||||
typeck_results,
|
||||
param_env,
|
||||
source: ConstantSource::Local,
|
||||
args: List::empty(),
|
||||
typeck,
|
||||
source: Cell::new(ConstantSource::Local),
|
||||
}
|
||||
}
|
||||
|
||||
/// Attempts to evaluate the expression and returns both the value and whether it's dependant on
|
||||
/// other items.
|
||||
pub fn eval_with_source(&self, e: &Expr<'_>) -> Option<(Constant<'tcx>, ConstantSource)> {
|
||||
self.source.set(ConstantSource::Local);
|
||||
self.expr(e).map(|c| (c, self.source.get()))
|
||||
}
|
||||
|
||||
/// Attempts to evaluate the expression.
|
||||
pub fn eval(&self, e: &Expr<'_>) -> Option<Constant<'tcx>> {
|
||||
self.expr(e)
|
||||
}
|
||||
|
||||
/// Attempts to evaluate the expression without accessing other items.
|
||||
pub fn eval_simple(&self, e: &Expr<'_>) -> Option<Constant<'tcx>> {
|
||||
match self.eval_with_source(e) {
|
||||
Some((x, ConstantSource::Local)) => Some(x),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Attempts to evaluate the expression as an integer without accessing other items.
|
||||
pub fn eval_full_int(&self, e: &Expr<'_>) -> Option<FullInt> {
|
||||
match self.eval_with_source(e) {
|
||||
Some((x, ConstantSource::Local)) => x.int_value(self.tcx, self.typeck.expr_ty(e)),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Simple constant folding: Insert an expression, get a constant or none.
|
||||
pub fn expr(&mut self, e: &Expr<'_>) -> Option<Constant<'tcx>> {
|
||||
fn expr(&self, e: &Expr<'_>) -> Option<Constant<'tcx>> {
|
||||
match e.kind {
|
||||
ExprKind::ConstBlock(ConstBlock { body, .. }) => self.expr(self.tcx.hir().body(body).value),
|
||||
ExprKind::DropTemps(e) => self.expr(e),
|
||||
ExprKind::Path(ref qpath) => {
|
||||
let is_core_crate = if let Some(def_id) = self.typeck_results.qpath_res(qpath, e.hir_id()).opt_def_id()
|
||||
{
|
||||
let is_core_crate = if let Some(def_id) = self.typeck.qpath_res(qpath, e.hir_id()).opt_def_id() {
|
||||
self.tcx.crate_name(def_id.krate) == sym::core
|
||||
} else {
|
||||
false
|
||||
};
|
||||
self.fetch_path_and_apply(qpath, e.hir_id, self.typeck_results.expr_ty(e), |self_, result| {
|
||||
self.fetch_path_and_apply(qpath, e.hir_id, self.typeck.expr_ty(e), |self_, result| {
|
||||
let result = mir_to_const(self_.tcx, result)?;
|
||||
// If source is already Constant we wouldn't want to override it with CoreConstant
|
||||
self_.source = if is_core_crate && !matches!(self_.source, ConstantSource::Constant) {
|
||||
ConstantSource::CoreConstant
|
||||
} else {
|
||||
ConstantSource::Constant
|
||||
};
|
||||
self_.source.set(
|
||||
if is_core_crate && !matches!(self_.source.get(), ConstantSource::Constant) {
|
||||
ConstantSource::CoreConstant
|
||||
} else {
|
||||
ConstantSource::Constant
|
||||
},
|
||||
);
|
||||
Some(result)
|
||||
})
|
||||
},
|
||||
@ -466,21 +465,21 @@ pub fn expr(&mut self, e: &Expr<'_>) -> Option<Constant<'tcx>> {
|
||||
if is_direct_expn_of(e.span, "cfg").is_some() {
|
||||
None
|
||||
} else {
|
||||
Some(lit_to_mir_constant(&lit.node, self.typeck_results.expr_ty_opt(e)))
|
||||
Some(lit_to_mir_constant(&lit.node, self.typeck.expr_ty_opt(e)))
|
||||
}
|
||||
},
|
||||
ExprKind::Array(vec) => self.multi(vec).map(Constant::Vec),
|
||||
ExprKind::Tup(tup) => self.multi(tup).map(Constant::Tuple),
|
||||
ExprKind::Repeat(value, _) => {
|
||||
let n = match self.typeck_results.expr_ty(e).kind() {
|
||||
let n = match self.typeck.expr_ty(e).kind() {
|
||||
ty::Array(_, n) => n.try_eval_target_usize(self.tcx, self.param_env)?,
|
||||
_ => span_bug!(e.span, "typeck error"),
|
||||
};
|
||||
self.expr(value).map(|v| Constant::Repeat(Box::new(v), n))
|
||||
},
|
||||
ExprKind::Unary(op, operand) => self.expr(operand).and_then(|o| match op {
|
||||
UnOp::Not => self.constant_not(&o, self.typeck_results.expr_ty(e)),
|
||||
UnOp::Neg => self.constant_negate(&o, self.typeck_results.expr_ty(e)),
|
||||
UnOp::Not => self.constant_not(&o, self.typeck.expr_ty(e)),
|
||||
UnOp::Neg => self.constant_negate(&o, self.typeck.expr_ty(e)),
|
||||
UnOp::Deref => Some(if let Constant::Ref(r) = o { *r } else { o }),
|
||||
}),
|
||||
ExprKind::If(cond, then, ref otherwise) => self.ifthenelse(cond, then, *otherwise),
|
||||
@ -489,7 +488,7 @@ pub fn expr(&mut self, e: &Expr<'_>) -> Option<Constant<'tcx>> {
|
||||
// We only handle a few const functions for now.
|
||||
if args.is_empty()
|
||||
&& let ExprKind::Path(qpath) = &callee.kind
|
||||
&& let Some(did) = self.typeck_results.qpath_res(qpath, callee.hir_id).opt_def_id()
|
||||
&& let Some(did) = self.typeck.qpath_res(qpath, callee.hir_id).opt_def_id()
|
||||
{
|
||||
match self.tcx.get_diagnostic_name(did) {
|
||||
Some(sym::i8_legacy_fn_max_value) => Some(Constant::Int(i8::MAX as u128)),
|
||||
@ -524,20 +523,20 @@ pub fn expr(&mut self, e: &Expr<'_>) -> Option<Constant<'tcx>> {
|
||||
/// Simple constant folding to determine if an expression is an empty slice, str, array, …
|
||||
/// `None` will be returned if the constness cannot be determined, or if the resolution
|
||||
/// leaves the local crate.
|
||||
pub fn expr_is_empty(&mut self, e: &Expr<'_>) -> Option<bool> {
|
||||
pub fn eval_is_empty(&self, e: &Expr<'_>) -> Option<bool> {
|
||||
match e.kind {
|
||||
ExprKind::ConstBlock(ConstBlock { body, .. }) => self.expr_is_empty(self.tcx.hir().body(body).value),
|
||||
ExprKind::DropTemps(e) => self.expr_is_empty(e),
|
||||
ExprKind::ConstBlock(ConstBlock { body, .. }) => self.eval_is_empty(self.tcx.hir().body(body).value),
|
||||
ExprKind::DropTemps(e) => self.eval_is_empty(e),
|
||||
ExprKind::Path(ref qpath) => {
|
||||
if !self
|
||||
.typeck_results
|
||||
.typeck
|
||||
.qpath_res(qpath, e.hir_id)
|
||||
.opt_def_id()
|
||||
.is_some_and(DefId::is_local)
|
||||
{
|
||||
return None;
|
||||
}
|
||||
self.fetch_path_and_apply(qpath, e.hir_id, self.typeck_results.expr_ty(e), |self_, result| {
|
||||
self.fetch_path_and_apply(qpath, e.hir_id, self.typeck.expr_ty(e), |self_, result| {
|
||||
mir_is_empty(self_.tcx, result)
|
||||
})
|
||||
},
|
||||
@ -554,7 +553,7 @@ pub fn expr_is_empty(&mut self, e: &Expr<'_>) -> Option<bool> {
|
||||
},
|
||||
ExprKind::Array(vec) => self.multi(vec).map(|v| v.is_empty()),
|
||||
ExprKind::Repeat(..) => {
|
||||
if let ty::Array(_, n) = self.typeck_results.expr_ty(e).kind() {
|
||||
if let ty::Array(_, n) = self.typeck.expr_ty(e).kind() {
|
||||
Some(n.try_eval_target_usize(self.tcx, self.param_env)? == 0)
|
||||
} else {
|
||||
span_bug!(e.span, "typeck error");
|
||||
@ -607,16 +606,16 @@ fn constant_negate(&self, o: &Constant<'tcx>, ty: Ty<'_>) -> Option<Constant<'tc
|
||||
|
||||
/// Create `Some(Vec![..])` of all constants, unless there is any
|
||||
/// non-constant part.
|
||||
fn multi(&mut self, vec: &[Expr<'_>]) -> Option<Vec<Constant<'tcx>>> {
|
||||
fn multi(&self, vec: &[Expr<'_>]) -> Option<Vec<Constant<'tcx>>> {
|
||||
vec.iter().map(|elem| self.expr(elem)).collect::<Option<_>>()
|
||||
}
|
||||
|
||||
/// Lookup a possibly constant expression from an `ExprKind::Path` and apply a function on it.
|
||||
fn fetch_path_and_apply<T, F>(&mut self, qpath: &QPath<'_>, id: HirId, ty: Ty<'tcx>, f: F) -> Option<T>
|
||||
fn fetch_path_and_apply<T, F>(&self, qpath: &QPath<'_>, id: HirId, ty: Ty<'tcx>, f: F) -> Option<T>
|
||||
where
|
||||
F: FnOnce(&mut Self, mir::Const<'tcx>) -> Option<T>,
|
||||
F: FnOnce(&Self, mir::Const<'tcx>) -> Option<T>,
|
||||
{
|
||||
let res = self.typeck_results.qpath_res(qpath, id);
|
||||
let res = self.typeck.qpath_res(qpath, id);
|
||||
match res {
|
||||
Res::Def(DefKind::Const | DefKind::AssocConst, def_id) => {
|
||||
// Check if this constant is based on `cfg!(..)`,
|
||||
@ -636,12 +635,7 @@ fn fetch_path_and_apply<T, F>(&mut self, qpath: &QPath<'_>, id: HirId, ty: Ty<'t
|
||||
return None;
|
||||
}
|
||||
|
||||
let args = self.typeck_results.node_args(id);
|
||||
let args = if self.args.is_empty() {
|
||||
args
|
||||
} else {
|
||||
EarlyBinder::bind(args).instantiate(self.tcx, self.args)
|
||||
};
|
||||
let args = self.typeck.node_args(id);
|
||||
let result = self
|
||||
.tcx
|
||||
.const_eval_resolve(self.param_env, mir::UnevaluatedConst::new(def_id, args), qpath.span())
|
||||
@ -653,7 +647,7 @@ fn fetch_path_and_apply<T, F>(&mut self, qpath: &QPath<'_>, id: HirId, ty: Ty<'t
|
||||
}
|
||||
}
|
||||
|
||||
fn index(&mut self, lhs: &'_ Expr<'_>, index: &'_ Expr<'_>) -> Option<Constant<'tcx>> {
|
||||
fn index(&self, lhs: &'_ Expr<'_>, index: &'_ Expr<'_>) -> Option<Constant<'tcx>> {
|
||||
let lhs = self.expr(lhs);
|
||||
let index = self.expr(index);
|
||||
|
||||
@ -683,7 +677,7 @@ fn index(&mut self, lhs: &'_ Expr<'_>, index: &'_ Expr<'_>) -> Option<Constant<'
|
||||
}
|
||||
|
||||
/// A block can only yield a constant if it has exactly one constant expression.
|
||||
fn block(&mut self, block: &Block<'_>) -> Option<Constant<'tcx>> {
|
||||
fn block(&self, block: &Block<'_>) -> Option<Constant<'tcx>> {
|
||||
if block.stmts.is_empty()
|
||||
&& let Some(expr) = block.expr
|
||||
{
|
||||
@ -702,11 +696,11 @@ fn block(&mut self, block: &Block<'_>) -> Option<Constant<'tcx>> {
|
||||
.filter(|t| !matches!(t, Whitespace | LineComment { .. } | BlockComment { .. } | Semi))
|
||||
.eq([OpenBrace])
|
||||
{
|
||||
self.source = ConstantSource::Constant;
|
||||
self.source.set(ConstantSource::Constant);
|
||||
}
|
||||
} else {
|
||||
// Unable to access the source. Assume a non-local dependency.
|
||||
self.source = ConstantSource::Constant;
|
||||
self.source.set(ConstantSource::Constant);
|
||||
}
|
||||
}
|
||||
|
||||
@ -716,7 +710,7 @@ fn block(&mut self, block: &Block<'_>) -> Option<Constant<'tcx>> {
|
||||
}
|
||||
}
|
||||
|
||||
fn ifthenelse(&mut self, cond: &Expr<'_>, then: &Expr<'_>, otherwise: Option<&Expr<'_>>) -> Option<Constant<'tcx>> {
|
||||
fn ifthenelse(&self, cond: &Expr<'_>, then: &Expr<'_>, otherwise: Option<&Expr<'_>>) -> Option<Constant<'tcx>> {
|
||||
if let Some(Constant::Bool(b)) = self.expr(cond) {
|
||||
if b {
|
||||
self.expr(then)
|
||||
@ -728,11 +722,11 @@ fn ifthenelse(&mut self, cond: &Expr<'_>, then: &Expr<'_>, otherwise: Option<&Ex
|
||||
}
|
||||
}
|
||||
|
||||
fn binop(&mut self, op: BinOp, left: &Expr<'_>, right: &Expr<'_>) -> Option<Constant<'tcx>> {
|
||||
fn binop(&self, op: BinOp, left: &Expr<'_>, right: &Expr<'_>) -> Option<Constant<'tcx>> {
|
||||
let l = self.expr(left)?;
|
||||
let r = self.expr(right);
|
||||
match (l, r) {
|
||||
(Constant::Int(l), Some(Constant::Int(r))) => match *self.typeck_results.expr_ty_opt(left)?.kind() {
|
||||
(Constant::Int(l), Some(Constant::Int(r))) => match *self.typeck.expr_ty_opt(left)?.kind() {
|
||||
ty::Int(ity) => {
|
||||
let (ty_min_value, _) = ity.min_max()?;
|
||||
let bits = ity.bits();
|
||||
|
@ -9,7 +9,7 @@
|
||||
//! - or-fun-call
|
||||
//! - option-if-let-else
|
||||
|
||||
use crate::consts::{constant, FullInt};
|
||||
use crate::consts::{ConstEvalCtxt, FullInt};
|
||||
use crate::ty::{all_predicates_of, is_copy};
|
||||
use crate::visitors::is_const_evaluatable;
|
||||
use rustc_hir::def::{DefKind, Res};
|
||||
@ -206,7 +206,7 @@ fn visit_expr(&mut self, e: &'tcx Expr<'_>) {
|
||||
},
|
||||
|
||||
// `-i32::MIN` panics with overflow checks
|
||||
ExprKind::Unary(UnOp::Neg, right) if constant(self.cx, self.cx.typeck_results(), right).is_none() => {
|
||||
ExprKind::Unary(UnOp::Neg, right) if ConstEvalCtxt::new(self.cx).eval(right).is_none() => {
|
||||
self.eagerness |= NoChange;
|
||||
},
|
||||
|
||||
@ -232,7 +232,7 @@ fn visit_expr(&mut self, e: &'tcx Expr<'_>) {
|
||||
// Thus, we would realistically only delay the lint.
|
||||
ExprKind::Binary(op, _, right)
|
||||
if matches!(op.node, BinOpKind::Shl | BinOpKind::Shr)
|
||||
&& constant(self.cx, self.cx.typeck_results(), right).is_none() =>
|
||||
&& ConstEvalCtxt::new(self.cx).eval(right).is_none() =>
|
||||
{
|
||||
self.eagerness |= NoChange;
|
||||
},
|
||||
@ -240,9 +240,9 @@ fn visit_expr(&mut self, e: &'tcx Expr<'_>) {
|
||||
ExprKind::Binary(op, left, right)
|
||||
if matches!(op.node, BinOpKind::Div | BinOpKind::Rem)
|
||||
&& let right_ty = self.cx.typeck_results().expr_ty(right)
|
||||
&& let left = constant(self.cx, self.cx.typeck_results(), left)
|
||||
&& let right = constant(self.cx, self.cx.typeck_results(), right)
|
||||
.and_then(|c| c.int_value(self.cx, right_ty))
|
||||
&& let ecx = ConstEvalCtxt::new(self.cx)
|
||||
&& let left = ecx.eval(left)
|
||||
&& let right = ecx.eval(right).and_then(|c| c.int_value(self.cx.tcx, right_ty))
|
||||
&& matches!(
|
||||
(left, right),
|
||||
// `1 / x`: x might be zero
|
||||
@ -261,8 +261,8 @@ fn visit_expr(&mut self, e: &'tcx Expr<'_>) {
|
||||
ExprKind::Binary(op, left, right)
|
||||
if matches!(op.node, BinOpKind::Add | BinOpKind::Sub | BinOpKind::Mul)
|
||||
&& !self.cx.typeck_results().expr_ty(e).is_floating_point()
|
||||
&& (constant(self.cx, self.cx.typeck_results(), left).is_none()
|
||||
|| constant(self.cx, self.cx.typeck_results(), right).is_none()) =>
|
||||
&& let ecx = ConstEvalCtxt::new(self.cx)
|
||||
&& (ecx.eval(left).is_none() || ecx.eval(right).is_none()) =>
|
||||
{
|
||||
self.eagerness |= NoChange;
|
||||
},
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
#![deny(clippy::missing_docs_in_private_items)]
|
||||
|
||||
use crate::consts::{constant_simple, Constant};
|
||||
use crate::consts::{ConstEvalCtxt, Constant};
|
||||
use crate::ty::is_type_diagnostic_item;
|
||||
use crate::{is_expn_of, match_def_path, paths};
|
||||
|
||||
@ -471,7 +471,7 @@ pub fn get_vec_init_kind<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -
|
||||
return Some(VecInitKind::Default);
|
||||
} else if name.ident.name.as_str() == "with_capacity" {
|
||||
let arg = args.first()?;
|
||||
return match constant_simple(cx, cx.typeck_results(), arg) {
|
||||
return match ConstEvalCtxt::new(cx).eval_simple(arg) {
|
||||
Some(Constant::Int(num)) => Some(VecInitKind::WithConstCapacity(num)),
|
||||
_ => Some(VecInitKind::WithExprCapacity(arg.hir_id)),
|
||||
};
|
||||
|
@ -1,4 +1,4 @@
|
||||
use crate::consts::constant_simple;
|
||||
use crate::consts::ConstEvalCtxt;
|
||||
use crate::macros::macro_backtrace;
|
||||
use crate::source::{snippet_opt, walk_span_to_context, SpanRange, SpanRangeExt};
|
||||
use crate::tokenize_with_text;
|
||||
@ -255,8 +255,8 @@ pub fn eq_expr(&mut self, left: &Expr<'_>, right: &Expr<'_>) -> bool {
|
||||
if let Some((typeck_lhs, typeck_rhs)) = self.inner.maybe_typeck_results
|
||||
&& typeck_lhs.expr_ty(left) == typeck_rhs.expr_ty(right)
|
||||
&& let (Some(l), Some(r)) = (
|
||||
constant_simple(self.inner.cx, typeck_lhs, left),
|
||||
constant_simple(self.inner.cx, typeck_rhs, right),
|
||||
ConstEvalCtxt::with_env(self.inner.cx.tcx, self.inner.cx.param_env, typeck_lhs).eval_simple(left),
|
||||
ConstEvalCtxt::with_env(self.inner.cx.tcx, self.inner.cx.param_env, typeck_rhs).eval_simple(right),
|
||||
)
|
||||
&& l == r
|
||||
{
|
||||
@ -714,9 +714,9 @@ pub fn hash_block(&mut self, b: &Block<'_>) {
|
||||
|
||||
#[expect(clippy::too_many_lines)]
|
||||
pub fn hash_expr(&mut self, e: &Expr<'_>) {
|
||||
let simple_const = self
|
||||
.maybe_typeck_results
|
||||
.and_then(|typeck_results| constant_simple(self.cx, typeck_results, e));
|
||||
let simple_const = self.maybe_typeck_results.and_then(|typeck_results| {
|
||||
ConstEvalCtxt::with_env(self.cx.tcx, self.cx.param_env, typeck_results).eval_simple(e)
|
||||
});
|
||||
|
||||
// const hashing may result in the same hash as some unrelated node, so add a sort of
|
||||
// discriminant depending on which path we're choosing next
|
||||
|
@ -125,7 +125,7 @@
|
||||
use rustc_target::abi::Integer;
|
||||
use visitors::Visitable;
|
||||
|
||||
use crate::consts::{constant, mir_to_const, Constant};
|
||||
use crate::consts::{mir_to_const, ConstEvalCtxt, Constant};
|
||||
use crate::higher::Range;
|
||||
use crate::ty::{adt_and_variant_of_res, can_partially_move_ty, expr_sig, is_copy, is_recursively_primitive_type};
|
||||
use crate::visitors::for_each_expr_without_closures;
|
||||
@ -1578,7 +1578,7 @@ pub fn is_range_full(cx: &LateContext<'_>, expr: &Expr<'_>, container_path: Opti
|
||||
&& let bnd_ty = subst.type_at(0)
|
||||
&& let Some(min_val) = bnd_ty.numeric_min_val(cx.tcx)
|
||||
&& let Some(min_const) = mir_to_const(cx.tcx, Const::from_ty_const(min_val, bnd_ty, cx.tcx))
|
||||
&& let Some(start_const) = constant(cx, cx.typeck_results(), start)
|
||||
&& let Some(start_const) = ConstEvalCtxt::new(cx).eval(start)
|
||||
{
|
||||
start_const == min_const
|
||||
} else {
|
||||
@ -1591,7 +1591,7 @@ pub fn is_range_full(cx: &LateContext<'_>, expr: &Expr<'_>, container_path: Opti
|
||||
&& let bnd_ty = subst.type_at(0)
|
||||
&& let Some(max_val) = bnd_ty.numeric_max_val(cx.tcx)
|
||||
&& let Some(max_const) = mir_to_const(cx.tcx, Const::from_ty_const(max_val, bnd_ty, cx.tcx))
|
||||
&& let Some(end_const) = constant(cx, cx.typeck_results(), end)
|
||||
&& let Some(end_const) = ConstEvalCtxt::new(cx).eval(end)
|
||||
{
|
||||
end_const == max_const
|
||||
} else {
|
||||
@ -1622,7 +1622,9 @@ pub fn is_integer_const(cx: &LateContext<'_>, e: &Expr<'_>, value: u128) -> bool
|
||||
return true;
|
||||
}
|
||||
let enclosing_body = cx.tcx.hir().enclosing_body_owner(e.hir_id);
|
||||
if let Some(Constant::Int(v)) = constant(cx, cx.tcx.typeck(enclosing_body), e) {
|
||||
if let Some(Constant::Int(v)) =
|
||||
ConstEvalCtxt::with_env(cx.tcx, cx.tcx.param_env(enclosing_body), cx.tcx.typeck(enclosing_body)).eval(e)
|
||||
{
|
||||
return value == v;
|
||||
}
|
||||
false
|
||||
|
Loading…
Reference in New Issue
Block a user