Skip to content

Don't use LateContext in the constant evaluator #13200

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Aug 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions clippy_lints/src/assertions_on_constants.rs
Original file line number Diff line number Diff line change
@@ -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};
Expand Down Expand Up @@ -43,7 +43,7 @@ impl<'tcx> LateLintPass<'tcx> for AssertionsOnConstants {
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;
};

Expand Down
4 changes: 2 additions & 2 deletions clippy_lints/src/casts/cast_nan_to_int.rs
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -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(),
Expand Down
4 changes: 2 additions & 2 deletions clippy_lints/src/casts/cast_possible_truncation.rs
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -15,7 +15,7 @@ use rustc_target::abi::IntegerType;
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
Expand Down
6 changes: 3 additions & 3 deletions clippy_lints/src/casts/cast_sign_loss.rs
Original file line number Diff line number Diff line change
@@ -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};
Expand Down Expand Up @@ -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));
Expand All @@ -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);
Expand Down
2 changes: 1 addition & 1 deletion clippy_lints/src/enum_clike.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ impl<'tcx> LateLintPass<'tcx> for UnportableVariant {
.const_eval_poly(def_id.to_def_id())
.ok()
.map(|val| rustc_middle::mir::Const::from_value(val, ty));
if let Some(Constant::Int(val)) = constant.and_then(|c| mir_to_const(cx, c)) {
if let Some(Constant::Int(val)) = constant.and_then(|c| mir_to_const(cx.tcx, c)) {
if let ty::Adt(adt, _) = ty.kind() {
if adt.is_enum() {
ty = adt.repr().discr_type().to_ty(cx.tcx);
Expand Down
30 changes: 15 additions & 15 deletions clippy_lints/src/floating_point_arithmetic.rs
Original file line number Diff line number Diff line change
@@ -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,
Expand Down Expand Up @@ -112,7 +112,7 @@ declare_lint_pass!(FloatingPointArithmetic => [
// 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 {
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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 {
Expand All @@ -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,
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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
{
Expand Down Expand Up @@ -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()
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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)
Expand Down
4 changes: 2 additions & 2 deletions clippy_lints/src/if_not_else.rs
Original file line number Diff line number Diff line change
@@ -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};
Expand Down Expand Up @@ -49,7 +49,7 @@ declare_clippy_lint! {
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
Expand Down
8 changes: 4 additions & 4 deletions clippy_lints/src/implicit_saturating_add.rs
Original file line number Diff line number Diff line change
@@ -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;
Expand Down Expand Up @@ -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));
}
}
Expand Down
4 changes: 2 additions & 2 deletions clippy_lints/src/index_refutable_slice.rs
Original file line number Diff line number Diff line change
@@ -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;
Expand Down Expand Up @@ -246,7 +246,7 @@ impl<'a, 'tcx> Visitor<'tcx> for SliceIndexLintingVisitor<'a, '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

Expand Down
9 changes: 5 additions & 4 deletions clippy_lints/src/indexing_slicing.rs
Original file line number Diff line number Diff line change
@@ -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};
Expand Down Expand Up @@ -177,7 +177,7 @@ impl<'tcx> LateLintPass<'tcx> for IndexingSlicing {
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
Expand Down Expand Up @@ -215,14 +215,15 @@ impl<'tcx> LateLintPass<'tcx> for IndexingSlicing {
/// 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 {
Expand Down
4 changes: 2 additions & 2 deletions clippy_lints/src/invalid_upcast_comparisons.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use rustc_span::Span;

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;

Expand Down Expand Up @@ -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);
Expand Down
4 changes: 2 additions & 2 deletions clippy_lints/src/loops/while_immutable_condition.rs
Original file line number Diff line number Diff line change
@@ -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};
Expand All @@ -10,7 +10,7 @@ use rustc_lint::LateContext;
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;
}
Expand Down
7 changes: 4 additions & 3 deletions clippy_lints/src/manual_clamp.rs
Original file line number Diff line number Diff line change
@@ -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;
Expand Down Expand Up @@ -122,8 +122,9 @@ impl<'tcx> ClampSuggestion<'tcx> {
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
Expand Down
7 changes: 4 additions & 3 deletions clippy_lints/src/manual_float_methods.rs
Original file line number Diff line number Diff line change
@@ -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};
Expand Down Expand Up @@ -95,8 +95,9 @@ impl<'tcx> LateLintPass<'tcx> for ManualFloatMethods {
|| 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
Expand Down
4 changes: 2 additions & 2 deletions clippy_lints/src/manual_rem_euclid.rs
Original file line number Diff line number Diff line change
@@ -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};
Expand Down Expand Up @@ -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),
Expand Down
4 changes: 2 additions & 2 deletions clippy_lints/src/manual_rotate.rs
Original file line number Diff line number Diff line change
@@ -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;
Expand Down Expand Up @@ -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));
}
Expand Down
4 changes: 2 additions & 2 deletions clippy_lints/src/manual_strip.rs
Original file line number Diff line number Diff line change
@@ -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;
Expand Down Expand Up @@ -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),
Expand Down
Loading