Don't store LateContext
in ConstEvalLateContext
This commit is contained in:
parent
3779062955
commit
d2cb227eb4
@ -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);
|
||||
|
@ -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)?;
|
||||
|
@ -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
|
||||
|
@ -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>,
|
||||
|
@ -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<bool> {
|
||||
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<Constant<'tcx>> {
|
||||
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<'tcx>> {
|
||||
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<FullInt> {
|
||||
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<Constant<'tcx>> {
|
||||
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<Constant<'tcx>> {
|
||||
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<Constant<'tcx>> {
|
||||
// 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::<Vec<_>>()
|
||||
&& 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 {
|
||||
"<impl i8>" => i8::MAX as u128,
|
||||
"<impl i16>" => i16::MAX as u128,
|
||||
"<impl i32>" => i32::MAX as u128,
|
||||
"<impl i64>" => i64::MAX as u128,
|
||||
"<impl i128>" => 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<Constant<'tcx>> {
|
||||
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<Constant<'tcx>> {
|
||||
/// leaves the local crate.
|
||||
pub fn expr_is_empty(&mut self, e: &Expr<'_>) -> Option<bool> {
|
||||
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<bool> {
|
||||
{
|
||||
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<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() {
|
||||
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<Constant<'tcx>>
|
||||
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<Constant<'tc
|
||||
let ty::Int(ity) = *ty.kind() else { return None };
|
||||
let (min, _) = ity.min_max()?;
|
||||
// sign extend
|
||||
let value = sext(self.lcx.tcx, value, ity);
|
||||
let value = sext(self.tcx, value, ity);
|
||||
|
||||
// Applying unary - to the most negative value of any signed integer type panics.
|
||||
if value == min {
|
||||
@ -599,7 +597,7 @@ fn constant_negate(&self, o: &Constant<'tcx>, ty: Ty<'_>) -> Option<Constant<'tc
|
||||
|
||||
let value = value.checked_neg()?;
|
||||
// clear unused bits
|
||||
Some(Int(unsext(self.lcx.tcx, value, ity)))
|
||||
Some(Int(unsext(self.tcx, value, ity)))
|
||||
},
|
||||
F32(f) => Some(F32(-f)),
|
||||
F64(f) => Some(F64(-f)),
|
||||
@ -623,7 +621,7 @@ fn fetch_path_and_apply<T, F>(&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<T, F>(&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<T, F>(&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<Constant<'
|
||||
}
|
||||
}
|
||||
|
||||
/// A block can only yield a constant if it only has one constant expression.
|
||||
/// A block can only yield a constant if it has exactly one constant expression.
|
||||
fn block(&mut self, block: &Block<'_>) -> Option<Constant<'tcx>> {
|
||||
if block.stmts.is_empty()
|
||||
&& let Some(expr) = block.expr
|
||||
@ -696,7 +693,7 @@ fn block(&mut self, block: &Block<'_>) -> Option<Constant<'tcx>> {
|
||||
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<Cons
|
||||
ty::Int(ity) => {
|
||||
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<Cons
|
||||
return None;
|
||||
}
|
||||
|
||||
let zext = |n: i128| Constant::Int(unsext(self.lcx.tcx, n, ity));
|
||||
let zext = |n: i128| Constant::Int(unsext(self.tcx, n, ity));
|
||||
match op.node {
|
||||
// When +, * or binary - create a value greater than the maximum value, or less than
|
||||
// the minimum value that can be stored, it panics.
|
||||
@ -845,7 +842,7 @@ fn binop(&mut self, op: BinOp, left: &Expr<'_>, right: &Expr<'_>) -> Option<Cons
|
||||
}
|
||||
}
|
||||
|
||||
pub fn mir_to_const<'tcx>(lcx: &LateContext<'tcx>, result: mir::Const<'tcx>) -> Option<Constant<'tcx>> {
|
||||
pub fn mir_to_const<'tcx>(tcx: TyCtxt<'tcx>, result: mir::Const<'tcx>) -> Option<Constant<'tcx>> {
|
||||
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<bool> {
|
||||
fn mir_is_empty<'tcx>(tcx: TyCtxt<'tcx>, result: mir::Const<'tcx>) -> Option<bool> {
|
||||
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<mir::Const<'tcx>> {
|
||||
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)
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user