Require ConstEvalCtxt to be constructed.

This commit is contained in:
Jason Newcomb 2024-08-01 00:36:21 -04:00
parent d2cb227eb4
commit e4ad36d6a8
52 changed files with 267 additions and 276 deletions

View File

@ -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;
};

View File

@ -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(),

View File

@ -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

View File

@ -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);

View File

@ -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)

View File

@ -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

View File

@ -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));
}
}

View File

@ -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

View File

@ -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 {

View File

@ -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);

View File

@ -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;
}

View File

@ -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

View File

@ -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

View File

@ -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),

View File

@ -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));
}

View File

@ -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),

View File

@ -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);
}

View File

@ -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)),

View File

@ -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"),

View File

@ -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,

View File

@ -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;

View File

@ -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 {

View File

@ -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,

View File

@ -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);
}
},

View File

@ -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(

View File

@ -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()

View File

@ -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),

View File

@ -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,
}
}

View File

@ -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,

View File

@ -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();

View File

@ -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,
}

View File

@ -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))),

View File

@ -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",

View File

@ -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;
}

View File

@ -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,

View File

@ -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),

View File

@ -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);

View File

@ -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);
}

View File

@ -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)
{

View File

@ -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: &regex_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,
})

View File

@ -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,

View File

@ -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

View File

@ -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;

View File

@ -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) {

View File

@ -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| {

View File

@ -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;

View File

@ -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)

View File

@ -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();

View File

@ -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;
},

View File

@ -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)),
};

View File

@ -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

View File

@ -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