From d2cb227eb4582c961ad0a9b7bfce41b1e08001f0 Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Wed, 31 Jul 2024 17:51:09 -0400 Subject: [PATCH] Don't store `LateContext` in `ConstEvalLateContext` --- clippy_lints/src/enum_clike.rs | 2 +- clippy_lints/src/matches/overlapping_arms.rs | 4 +- .../src/operators/const_comparisons.rs | 2 +- clippy_lints/src/operators/erasing_op.rs | 2 +- clippy_utils/src/consts.rs | 139 +++++++++--------- clippy_utils/src/lib.rs | 4 +- 6 files changed, 75 insertions(+), 78 deletions(-) diff --git a/clippy_lints/src/enum_clike.rs b/clippy_lints/src/enum_clike.rs index 30eb643c42e..e54cd248ead 100644 --- a/clippy_lints/src/enum_clike.rs +++ b/clippy_lints/src/enum_clike.rs @@ -51,7 +51,7 @@ fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) { .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); diff --git a/clippy_lints/src/matches/overlapping_arms.rs b/clippy_lints/src/matches/overlapping_arms.rs index 7ad66360d8a..4a6741da45f 100644 --- a/clippy_lints/src/matches/overlapping_arms.rs +++ b/clippy_lints/src/matches/overlapping_arms.rs @@ -37,13 +37,13 @@ fn all_ranges<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'_>], ty: Ty<'tcx>) constant(cx, cx.typeck_results(), lhs)? } else { let min_val_const = ty.numeric_min_val(cx.tcx)?; - mir_to_const(cx, mir::Const::from_ty_const(min_val_const, ty, 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)? } else { let max_val_const = ty.numeric_max_val(cx.tcx)?; - mir_to_const(cx, mir::Const::from_ty_const(max_val_const, ty, 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)?; diff --git a/clippy_lints/src/operators/const_comparisons.rs b/clippy_lints/src/operators/const_comparisons.rs index 7bf9b8ef866..1f9f3b3c473 100644 --- a/clippy_lints/src/operators/const_comparisons.rs +++ b/clippy_lints/src/operators/const_comparisons.rs @@ -20,7 +20,7 @@ // Flip yoda conditionals, turnings expressions like `42 < x` into `x > 42` fn comparison_to_const<'tcx>( cx: &LateContext<'tcx>, - typeck: &TypeckResults<'tcx>, + typeck: &'tcx TypeckResults<'tcx>, expr: &'tcx Expr<'tcx>, ) -> Option<(CmpOp, &'tcx Expr<'tcx>, &'tcx Expr<'tcx>, Constant<'tcx>, Ty<'tcx>)> { if let ExprKind::Binary(operator, left, right) = expr.kind diff --git a/clippy_lints/src/operators/erasing_op.rs b/clippy_lints/src/operators/erasing_op.rs index 066e08f3bd4..fc2129b9103 100644 --- a/clippy_lints/src/operators/erasing_op.rs +++ b/clippy_lints/src/operators/erasing_op.rs @@ -34,7 +34,7 @@ fn different_types(tck: &TypeckResults<'_>, input: &Expr<'_>, output: &Expr<'_>) fn check_op<'tcx>( cx: &LateContext<'tcx>, - tck: &TypeckResults<'tcx>, + tck: &'tcx TypeckResults<'tcx>, op: &Expr<'tcx>, other: &Expr<'tcx>, parent: &Expr<'tcx>, diff --git a/clippy_utils/src/consts.rs b/clippy_utils/src/consts.rs index de6ccfe476f..d465daa06e2 100644 --- a/clippy_utils/src/consts.rs +++ b/clippy_utils/src/consts.rs @@ -14,10 +14,12 @@ 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, ScalarInt, Ty, TyCtxt, UintTy}; +use rustc_middle::ty::{ + self, EarlyBinder, FloatTy, GenericArgsRef, IntTy, List, ParamEnv, ScalarInt, Ty, TyCtxt, TypeckResults, UintTy, +}; use rustc_middle::{bug, mir, span_bug}; use rustc_span::def_id::DefId; -use rustc_span::symbol::{Ident, Symbol}; +use rustc_span::symbol::Ident; use rustc_span::{sym, SyntaxContext}; use rustc_target::abi::Size; use std::cmp::Ordering; @@ -339,25 +341,25 @@ pub fn is_local(&self) -> bool { /// 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 { - ConstEvalLateContext::new(lcx, lcx.typeck_results()).expr_is_empty(e) + 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: &ty::TypeckResults<'tcx>, + typeck_results: &'tcx TypeckResults<'tcx>, e: &Expr<'_>, ) -> Option> { - ConstEvalLateContext::new(lcx, typeck_results).expr(e) + 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: &ty::TypeckResults<'tcx>, + typeck_results: &'tcx TypeckResults<'tcx>, e: &Expr<'_>, ) -> Option<(Constant<'tcx>, ConstantSource)> { - let mut ctxt = ConstEvalLateContext::new(lcx, typeck_results); + let mut ctxt = ConstEvalLateContext::new(lcx.tcx, lcx.param_env, typeck_results); let res = ctxt.expr(e); res.map(|x| (x, ctxt.source)) } @@ -365,7 +367,7 @@ pub fn constant_with_source<'tcx>( /// 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: &ty::TypeckResults<'tcx>, + typeck_results: &'tcx TypeckResults<'tcx>, e: &Expr<'_>, ) -> Option> { constant_with_source(lcx, typeck_results, e).and_then(|(c, s)| s.is_local().then_some(c)) @@ -373,7 +375,7 @@ pub fn constant_simple<'tcx>( pub fn constant_full_int<'tcx>( lcx: &LateContext<'tcx>, - typeck_results: &ty::TypeckResults<'tcx>, + typeck_results: &'tcx TypeckResults<'tcx>, e: &Expr<'_>, ) -> Option { constant_simple(lcx, typeck_results, e)?.int_value(lcx, typeck_results.expr_ty(e)) @@ -417,20 +419,20 @@ fn cmp_s_u(s: i128, u: u128) -> Ordering { } } -pub struct ConstEvalLateContext<'a, 'tcx> { - lcx: &'a LateContext<'tcx>, - typeck_results: &'a ty::TypeckResults<'tcx>, - param_env: ty::ParamEnv<'tcx>, +pub struct ConstEvalLateContext<'tcx> { + tcx: TyCtxt<'tcx>, + typeck_results: &'tcx TypeckResults<'tcx>, + param_env: ParamEnv<'tcx>, source: ConstantSource, args: GenericArgsRef<'tcx>, } -impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> { - pub fn new(lcx: &'a LateContext<'tcx>, typeck_results: &'a ty::TypeckResults<'tcx>) -> Self { +impl<'tcx> ConstEvalLateContext<'tcx> { + pub fn new(tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>, typeck_results: &'tcx TypeckResults<'tcx>) -> Self { Self { - lcx, + tcx, typeck_results, - param_env: lcx.param_env, + param_env, source: ConstantSource::Local, args: List::empty(), } @@ -439,18 +441,19 @@ pub fn new(lcx: &'a LateContext<'tcx>, typeck_results: &'a ty::TypeckResults<'tc /// Simple constant folding: Insert an expression, get a constant or none. pub fn expr(&mut self, e: &Expr<'_>) -> Option> { match e.kind { - ExprKind::ConstBlock(ConstBlock { body, .. }) => self.expr(self.lcx.tcx.hir().body(body).value), + 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.lcx.qpath_res(qpath, e.hir_id()).opt_def_id() { - self.lcx.tcx.crate_name(def_id.krate) == sym::core + let is_core_crate = if let Some(def_id) = self.typeck_results.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), |this, result| { - let result = mir_to_const(this.lcx, result)?; + self.fetch_path_and_apply(qpath, e.hir_id, self.typeck_results.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 - this.source = if is_core_crate && !matches!(this.source, ConstantSource::Constant) { + self_.source = if is_core_crate && !matches!(self_.source, ConstantSource::Constant) { ConstantSource::CoreConstant } else { ConstantSource::Constant @@ -470,7 +473,7 @@ pub fn expr(&mut self, e: &Expr<'_>) -> Option> { ExprKind::Tup(tup) => self.multi(tup).map(Constant::Tuple), ExprKind::Repeat(value, _) => { let n = match self.typeck_results.expr_ty(e).kind() { - ty::Array(_, n) => n.try_eval_target_usize(self.lcx.tcx, self.lcx.param_env)?, + 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)) @@ -486,21 +489,16 @@ pub fn expr(&mut self, e: &Expr<'_>) -> Option> { // We only handle a few const functions for now. if args.is_empty() && let ExprKind::Path(qpath) = &callee.kind - && let res = self.typeck_results.qpath_res(qpath, callee.hir_id) - && let Some(def_id) = res.opt_def_id() - && let def_path = self.lcx.get_def_path(def_id) - && let def_path = def_path.iter().take(4).map(Symbol::as_str).collect::>() - && let ["core", "num", int_impl, "max_value"] = *def_path + && let Some(did) = self.typeck_results.qpath_res(qpath, callee.hir_id).opt_def_id() { - let value = match int_impl { - "" => i8::MAX as u128, - "" => i16::MAX as u128, - "" => i32::MAX as u128, - "" => i64::MAX as u128, - "" => i128::MAX as u128, - _ => return None, - }; - Some(Constant::Int(value)) + match self.tcx.get_diagnostic_name(did) { + Some(sym::i8_legacy_fn_max_value) => Some(Constant::Int(i8::MAX as u128)), + Some(sym::i16_legacy_fn_max_value) => Some(Constant::Int(i16::MAX as u128)), + Some(sym::i32_legacy_fn_max_value) => Some(Constant::Int(i32::MAX as u128)), + Some(sym::i64_legacy_fn_max_value) => Some(Constant::Int(i64::MAX as u128)), + Some(sym::i128_legacy_fn_max_value) => Some(Constant::Int(i128::MAX as u128)), + _ => None, + } } else { None } @@ -512,9 +510,9 @@ pub fn expr(&mut self, e: &Expr<'_>) -> Option> { if let Some(Constant::Adt(constant)) = &self.expr(local_expr) && let ty::Adt(adt_def, _) = constant.ty().kind() && adt_def.is_struct() - && let Some(desired_field) = field_of_struct(*adt_def, self.lcx, *constant, field) + && let Some(desired_field) = field_of_struct(*adt_def, self.tcx, *constant, field) { - mir_to_const(self.lcx, desired_field) + mir_to_const(self.tcx, desired_field) } else { result } @@ -528,7 +526,7 @@ pub fn expr(&mut self, e: &Expr<'_>) -> Option> { /// leaves the local crate. pub fn expr_is_empty(&mut self, e: &Expr<'_>) -> Option { match e.kind { - ExprKind::ConstBlock(ConstBlock { body, .. }) => self.expr_is_empty(self.lcx.tcx.hir().body(body).value), + ExprKind::ConstBlock(ConstBlock { body, .. }) => self.expr_is_empty(self.tcx.hir().body(body).value), ExprKind::DropTemps(e) => self.expr_is_empty(e), ExprKind::Path(ref qpath) => { if !self @@ -539,8 +537,8 @@ pub fn expr_is_empty(&mut self, e: &Expr<'_>) -> Option { { return None; } - self.fetch_path_and_apply(qpath, e.hir_id, self.typeck_results.expr_ty(e), |this, result| { - mir_is_empty(this.lcx, result) + self.fetch_path_and_apply(qpath, e.hir_id, self.typeck_results.expr_ty(e), |self_, result| { + mir_is_empty(self_.tcx, result) }) }, ExprKind::Lit(lit) => { @@ -557,7 +555,7 @@ pub fn expr_is_empty(&mut self, e: &Expr<'_>) -> Option { 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() { - Some(n.try_eval_target_usize(self.lcx.tcx, self.lcx.param_env)? == 0) + Some(n.try_eval_target_usize(self.tcx, self.param_env)? == 0) } else { span_bug!(e.span, "typeck error"); } @@ -574,8 +572,8 @@ fn constant_not(&self, o: &Constant<'tcx>, ty: Ty<'_>) -> Option> Int(value) => { let value = !value; match *ty.kind() { - ty::Int(ity) => Some(Int(unsext(self.lcx.tcx, value as i128, ity))), - ty::Uint(ity) => Some(Int(clip(self.lcx.tcx, value, ity))), + ty::Int(ity) => Some(Int(unsext(self.tcx, value as i128, ity))), + ty::Uint(ity) => Some(Int(clip(self.tcx, value, ity))), _ => None, } }, @@ -590,7 +588,7 @@ fn constant_negate(&self, o: &Constant<'tcx>, ty: Ty<'_>) -> Option, ty: Ty<'_>) -> Option Some(F32(-f)), F64(f) => Some(F64(-f)), @@ -623,7 +621,7 @@ fn fetch_path_and_apply(&mut self, qpath: &QPath<'_>, id: HirId, ty: Ty<'t Res::Def(DefKind::Const | DefKind::AssocConst, def_id) => { // Check if this constant is based on `cfg!(..)`, // which is NOT constant for our purposes. - if let Some(node) = self.lcx.tcx.hir().get_if_local(def_id) + if let Some(node) = self.tcx.hir().get_if_local(def_id) && let Node::Item(Item { kind: ItemKind::Const(.., body_id), .. @@ -632,7 +630,7 @@ fn fetch_path_and_apply(&mut self, qpath: &QPath<'_>, id: HirId, ty: Ty<'t kind: ExprKind::Lit(_), span, .. - }) = self.lcx.tcx.hir_node(body_id.hir_id) + }) = self.tcx.hir_node(body_id.hir_id) && is_direct_expn_of(*span, "cfg").is_some() { return None; @@ -642,10 +640,9 @@ fn fetch_path_and_apply(&mut self, qpath: &QPath<'_>, id: HirId, ty: Ty<'t let args = if self.args.is_empty() { args } else { - EarlyBinder::bind(args).instantiate(self.lcx.tcx, self.args) + EarlyBinder::bind(args).instantiate(self.tcx, self.args) }; let result = self - .lcx .tcx .const_eval_resolve(self.param_env, mir::UnevaluatedConst::new(def_id, args), qpath.span()) .ok() @@ -685,7 +682,7 @@ fn index(&mut self, lhs: &'_ Expr<'_>, index: &'_ Expr<'_>) -> Option) -> Option> { if block.stmts.is_empty() && let Some(expr) = block.expr @@ -696,7 +693,7 @@ fn block(&mut self, block: &Block<'_>) -> Option> { if let Some(expr_span) = walk_span_to_context(expr.span, span.ctxt) && let expr_lo = expr_span.lo() && expr_lo >= span.lo - && let Some(src) = (span.lo..expr_lo).get_source_text(self.lcx) + && let Some(src) = (span.lo..expr_lo).get_source_text(&self.tcx) && let Some(src) = src.as_str() { use rustc_lexer::TokenKind::{BlockComment, LineComment, OpenBrace, Semi, Whitespace}; @@ -739,8 +736,8 @@ fn binop(&mut self, op: BinOp, left: &Expr<'_>, right: &Expr<'_>) -> Option { let (ty_min_value, _) = ity.min_max()?; let bits = ity.bits(); - let l = sext(self.lcx.tcx, l, ity); - let r = sext(self.lcx.tcx, r, ity); + let l = sext(self.tcx, l, ity); + let r = sext(self.tcx, r, ity); // Using / or %, where the left-hand argument is the smallest integer of a signed integer type and // the right-hand argument is -1 always panics, even with overflow-checks disabled @@ -751,7 +748,7 @@ fn binop(&mut self, op: BinOp, left: &Expr<'_>, right: &Expr<'_>) -> Option, right: &Expr<'_>) -> Option(lcx: &LateContext<'tcx>, result: mir::Const<'tcx>) -> Option> { +pub fn mir_to_const<'tcx>(tcx: TyCtxt<'tcx>, result: mir::Const<'tcx>) -> Option> { let mir::Const::Val(val, _) = result else { // We only work on evaluated consts. return None; @@ -863,13 +860,13 @@ pub fn mir_to_const<'tcx>(lcx: &LateContext<'tcx>, result: mir::Const<'tcx>) -> _ => None, }, (_, ty::Ref(_, inner_ty, _)) if matches!(inner_ty.kind(), ty::Str) => { - let data = val.try_get_slice_bytes_for_diagnostics(lcx.tcx)?; + let data = val.try_get_slice_bytes_for_diagnostics(tcx)?; String::from_utf8(data.to_owned()).ok().map(Constant::Str) }, (_, ty::Adt(adt_def, _)) if adt_def.is_struct() => Some(Constant::Adt(result)), (ConstValue::Indirect { alloc_id, offset }, ty::Array(sub_type, len)) => { - let alloc = lcx.tcx.global_alloc(alloc_id).unwrap_memory().inner(); - let len = len.try_to_target_usize(lcx.tcx)?; + let alloc = tcx.global_alloc(alloc_id).unwrap_memory().inner(); + let len = len.try_to_target_usize(tcx)?; let ty::Float(flt) = sub_type.kind() else { return None; }; @@ -877,7 +874,7 @@ pub fn mir_to_const<'tcx>(lcx: &LateContext<'tcx>, result: mir::Const<'tcx>) -> let mut res = Vec::new(); for idx in 0..len { let range = alloc_range(offset + size * idx, size); - let val = alloc.read_scalar(&lcx.tcx, range, /* read_provenance */ false).ok()?; + let val = alloc.read_scalar(&tcx, range, /* read_provenance */ false).ok()?; res.push(match flt { FloatTy::F16 => Constant::F16(f16::from_bits(val.to_u16().ok()?)), FloatTy::F32 => Constant::F32(f32::from_bits(val.to_u32().ok()?)), @@ -891,7 +888,7 @@ pub fn mir_to_const<'tcx>(lcx: &LateContext<'tcx>, result: mir::Const<'tcx>) -> } } -fn mir_is_empty<'tcx>(lcx: &LateContext<'tcx>, result: mir::Const<'tcx>) -> Option { +fn mir_is_empty<'tcx>(tcx: TyCtxt<'tcx>, result: mir::Const<'tcx>) -> Option { let mir::Const::Val(val, _) = result else { // We only work on evaluated consts. return None; @@ -902,26 +899,26 @@ fn mir_is_empty<'tcx>(lcx: &LateContext<'tcx>, result: mir::Const<'tcx>) -> Opti if let ConstValue::Indirect { alloc_id, offset } = val { // Get the length from the slice, using the same formula as // [`ConstValue::try_get_slice_bytes_for_diagnostics`]. - let a = lcx.tcx.global_alloc(alloc_id).unwrap_memory().inner(); - let ptr_size = lcx.tcx.data_layout.pointer_size; + let a = tcx.global_alloc(alloc_id).unwrap_memory().inner(); + let ptr_size = tcx.data_layout.pointer_size; if a.size() < offset + 2 * ptr_size { // (partially) dangling reference return None; } let len = a - .read_scalar(&lcx.tcx, alloc_range(offset + ptr_size, ptr_size), false) + .read_scalar(&tcx, alloc_range(offset + ptr_size, ptr_size), false) .ok()? - .to_target_usize(&lcx.tcx) + .to_target_usize(&tcx) .ok()?; Some(len == 0) } else { None } }, - ty::Array(_, len) => Some(len.try_to_target_usize(lcx.tcx)? == 0), + ty::Array(_, len) => Some(len.try_to_target_usize(tcx)? == 0), _ => None, }, - (ConstValue::Indirect { .. }, ty::Array(_, len)) => Some(len.try_to_target_usize(lcx.tcx)? == 0), + (ConstValue::Indirect { .. }, ty::Array(_, len)) => Some(len.try_to_target_usize(tcx)? == 0), (ConstValue::ZeroSized, _) => Some(true), _ => None, } @@ -929,12 +926,12 @@ fn mir_is_empty<'tcx>(lcx: &LateContext<'tcx>, result: mir::Const<'tcx>) -> Opti fn field_of_struct<'tcx>( adt_def: ty::AdtDef<'tcx>, - lcx: &LateContext<'tcx>, + tcx: TyCtxt<'tcx>, result: mir::Const<'tcx>, field: &Ident, ) -> Option> { if let mir::Const::Val(result, ty) = result - && let Some(dc) = lcx.tcx.try_destructure_mir_constant_for_user_output(result, ty) + && let Some(dc) = tcx.try_destructure_mir_constant_for_user_output(result, ty) && let Some(dc_variant) = dc.variant && let Some(variant) = adt_def.variants().get(dc_variant) && let Some(field_idx) = variant.fields.iter().position(|el| el.name == field.name) diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index 86506d33d9f..d43b15fc58a 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -1577,7 +1577,7 @@ pub fn is_range_full(cx: &LateContext<'_>, expr: &Expr<'_>, container_path: Opti if let rustc_ty::Adt(_, subst) = ty.kind() && 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, Const::from_ty_const(min_val, bnd_ty, 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) { start_const == min_const @@ -1590,7 +1590,7 @@ pub fn is_range_full(cx: &LateContext<'_>, expr: &Expr<'_>, container_path: Opti if let rustc_ty::Adt(_, subst) = ty.kind() && 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, Const::from_ty_const(max_val, bnd_ty, 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) { end_const == max_const