Don't store LateContext
in ConstEvalLateContext
This commit is contained in:
parent
3779062955
commit
d2cb227eb4
@ -51,7 +51,7 @@ impl<'tcx> LateLintPass<'tcx> for UnportableVariant {
|
|||||||
.const_eval_poly(def_id.to_def_id())
|
.const_eval_poly(def_id.to_def_id())
|
||||||
.ok()
|
.ok()
|
||||||
.map(|val| rustc_middle::mir::Const::from_value(val, ty));
|
.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 let ty::Adt(adt, _) = ty.kind() {
|
||||||
if adt.is_enum() {
|
if adt.is_enum() {
|
||||||
ty = adt.repr().discr_type().to_ty(cx.tcx);
|
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)?
|
constant(cx, cx.typeck_results(), lhs)?
|
||||||
} else {
|
} else {
|
||||||
let min_val_const = ty.numeric_min_val(cx.tcx)?;
|
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 {
|
let rhs_const = if let Some(rhs) = rhs {
|
||||||
constant(cx, cx.typeck_results(), rhs)?
|
constant(cx, cx.typeck_results(), rhs)?
|
||||||
} else {
|
} else {
|
||||||
let max_val_const = ty.numeric_max_val(cx.tcx)?;
|
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 lhs_val = lhs_const.int_value(cx, ty)?;
|
||||||
let rhs_val = rhs_const.int_value(cx, ty)?;
|
let rhs_val = rhs_const.int_value(cx, ty)?;
|
||||||
|
@ -20,7 +20,7 @@ use super::{IMPOSSIBLE_COMPARISONS, REDUNDANT_COMPARISONS};
|
|||||||
// Flip yoda conditionals, turnings expressions like `42 < x` into `x > 42`
|
// Flip yoda conditionals, turnings expressions like `42 < x` into `x > 42`
|
||||||
fn comparison_to_const<'tcx>(
|
fn comparison_to_const<'tcx>(
|
||||||
cx: &LateContext<'tcx>,
|
cx: &LateContext<'tcx>,
|
||||||
typeck: &TypeckResults<'tcx>,
|
typeck: &'tcx TypeckResults<'tcx>,
|
||||||
expr: &'tcx Expr<'tcx>,
|
expr: &'tcx Expr<'tcx>,
|
||||||
) -> Option<(CmpOp, &'tcx Expr<'tcx>, &'tcx Expr<'tcx>, Constant<'tcx>, Ty<'tcx>)> {
|
) -> Option<(CmpOp, &'tcx Expr<'tcx>, &'tcx Expr<'tcx>, Constant<'tcx>, Ty<'tcx>)> {
|
||||||
if let ExprKind::Binary(operator, left, right) = expr.kind
|
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>(
|
fn check_op<'tcx>(
|
||||||
cx: &LateContext<'tcx>,
|
cx: &LateContext<'tcx>,
|
||||||
tck: &TypeckResults<'tcx>,
|
tck: &'tcx TypeckResults<'tcx>,
|
||||||
op: &Expr<'tcx>,
|
op: &Expr<'tcx>,
|
||||||
other: &Expr<'tcx>,
|
other: &Expr<'tcx>,
|
||||||
parent: &Expr<'tcx>,
|
parent: &Expr<'tcx>,
|
||||||
|
@ -14,10 +14,12 @@ use rustc_lexer::tokenize;
|
|||||||
use rustc_lint::LateContext;
|
use rustc_lint::LateContext;
|
||||||
use rustc_middle::mir::interpret::{alloc_range, Scalar};
|
use rustc_middle::mir::interpret::{alloc_range, Scalar};
|
||||||
use rustc_middle::mir::ConstValue;
|
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_middle::{bug, mir, span_bug};
|
||||||
use rustc_span::def_id::DefId;
|
use rustc_span::def_id::DefId;
|
||||||
use rustc_span::symbol::{Ident, Symbol};
|
use rustc_span::symbol::Ident;
|
||||||
use rustc_span::{sym, SyntaxContext};
|
use rustc_span::{sym, SyntaxContext};
|
||||||
use rustc_target::abi::Size;
|
use rustc_target::abi::Size;
|
||||||
use std::cmp::Ordering;
|
use std::cmp::Ordering;
|
||||||
@ -339,25 +341,25 @@ impl ConstantSource {
|
|||||||
/// Attempts to check whether the expression is a constant representing an empty slice, str, array,
|
/// Attempts to check whether the expression is a constant representing an empty slice, str, array,
|
||||||
/// etc…
|
/// etc…
|
||||||
pub fn constant_is_empty(lcx: &LateContext<'_>, e: &Expr<'_>) -> Option<bool> {
|
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.
|
/// Attempts to evaluate the expression as a constant.
|
||||||
pub fn constant<'tcx>(
|
pub fn constant<'tcx>(
|
||||||
lcx: &LateContext<'tcx>,
|
lcx: &LateContext<'tcx>,
|
||||||
typeck_results: &ty::TypeckResults<'tcx>,
|
typeck_results: &'tcx TypeckResults<'tcx>,
|
||||||
e: &Expr<'_>,
|
e: &Expr<'_>,
|
||||||
) -> Option<Constant<'tcx>> {
|
) -> 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.
|
/// Attempts to evaluate the expression as a constant.
|
||||||
pub fn constant_with_source<'tcx>(
|
pub fn constant_with_source<'tcx>(
|
||||||
lcx: &LateContext<'tcx>,
|
lcx: &LateContext<'tcx>,
|
||||||
typeck_results: &ty::TypeckResults<'tcx>,
|
typeck_results: &'tcx TypeckResults<'tcx>,
|
||||||
e: &Expr<'_>,
|
e: &Expr<'_>,
|
||||||
) -> Option<(Constant<'tcx>, ConstantSource)> {
|
) -> 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);
|
let res = ctxt.expr(e);
|
||||||
res.map(|x| (x, ctxt.source))
|
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.
|
/// Attempts to evaluate an expression only if its value is not dependent on other items.
|
||||||
pub fn constant_simple<'tcx>(
|
pub fn constant_simple<'tcx>(
|
||||||
lcx: &LateContext<'tcx>,
|
lcx: &LateContext<'tcx>,
|
||||||
typeck_results: &ty::TypeckResults<'tcx>,
|
typeck_results: &'tcx TypeckResults<'tcx>,
|
||||||
e: &Expr<'_>,
|
e: &Expr<'_>,
|
||||||
) -> Option<Constant<'tcx>> {
|
) -> Option<Constant<'tcx>> {
|
||||||
constant_with_source(lcx, typeck_results, e).and_then(|(c, s)| s.is_local().then_some(c))
|
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>(
|
pub fn constant_full_int<'tcx>(
|
||||||
lcx: &LateContext<'tcx>,
|
lcx: &LateContext<'tcx>,
|
||||||
typeck_results: &ty::TypeckResults<'tcx>,
|
typeck_results: &'tcx TypeckResults<'tcx>,
|
||||||
e: &Expr<'_>,
|
e: &Expr<'_>,
|
||||||
) -> Option<FullInt> {
|
) -> Option<FullInt> {
|
||||||
constant_simple(lcx, typeck_results, e)?.int_value(lcx, typeck_results.expr_ty(e))
|
constant_simple(lcx, typeck_results, e)?.int_value(lcx, typeck_results.expr_ty(e))
|
||||||
@ -417,20 +419,20 @@ impl Ord for FullInt {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct ConstEvalLateContext<'a, 'tcx> {
|
pub struct ConstEvalLateContext<'tcx> {
|
||||||
lcx: &'a LateContext<'tcx>,
|
tcx: TyCtxt<'tcx>,
|
||||||
typeck_results: &'a ty::TypeckResults<'tcx>,
|
typeck_results: &'tcx TypeckResults<'tcx>,
|
||||||
param_env: ty::ParamEnv<'tcx>,
|
param_env: ParamEnv<'tcx>,
|
||||||
source: ConstantSource,
|
source: ConstantSource,
|
||||||
args: GenericArgsRef<'tcx>,
|
args: GenericArgsRef<'tcx>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> {
|
impl<'tcx> ConstEvalLateContext<'tcx> {
|
||||||
pub fn new(lcx: &'a LateContext<'tcx>, typeck_results: &'a ty::TypeckResults<'tcx>) -> Self {
|
pub fn new(tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>, typeck_results: &'tcx TypeckResults<'tcx>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
lcx,
|
tcx,
|
||||||
typeck_results,
|
typeck_results,
|
||||||
param_env: lcx.param_env,
|
param_env,
|
||||||
source: ConstantSource::Local,
|
source: ConstantSource::Local,
|
||||||
args: List::empty(),
|
args: List::empty(),
|
||||||
}
|
}
|
||||||
@ -439,18 +441,19 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> {
|
|||||||
/// Simple constant folding: Insert an expression, get a constant or none.
|
/// Simple constant folding: Insert an expression, get a constant or none.
|
||||||
pub fn expr(&mut self, e: &Expr<'_>) -> Option<Constant<'tcx>> {
|
pub fn expr(&mut self, e: &Expr<'_>) -> Option<Constant<'tcx>> {
|
||||||
match e.kind {
|
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::DropTemps(e) => self.expr(e),
|
||||||
ExprKind::Path(ref qpath) => {
|
ExprKind::Path(ref qpath) => {
|
||||||
let is_core_crate = if let Some(def_id) = self.lcx.qpath_res(qpath, e.hir_id()).opt_def_id() {
|
let is_core_crate = if let Some(def_id) = self.typeck_results.qpath_res(qpath, e.hir_id()).opt_def_id()
|
||||||
self.lcx.tcx.crate_name(def_id.krate) == sym::core
|
{
|
||||||
|
self.tcx.crate_name(def_id.krate) == sym::core
|
||||||
} else {
|
} else {
|
||||||
false
|
false
|
||||||
};
|
};
|
||||||
self.fetch_path_and_apply(qpath, e.hir_id, self.typeck_results.expr_ty(e), |this, result| {
|
self.fetch_path_and_apply(qpath, e.hir_id, self.typeck_results.expr_ty(e), |self_, result| {
|
||||||
let result = mir_to_const(this.lcx, result)?;
|
let result = mir_to_const(self_.tcx, result)?;
|
||||||
// If source is already Constant we wouldn't want to override it with CoreConstant
|
// 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
|
ConstantSource::CoreConstant
|
||||||
} else {
|
} else {
|
||||||
ConstantSource::Constant
|
ConstantSource::Constant
|
||||||
@ -470,7 +473,7 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> {
|
|||||||
ExprKind::Tup(tup) => self.multi(tup).map(Constant::Tuple),
|
ExprKind::Tup(tup) => self.multi(tup).map(Constant::Tuple),
|
||||||
ExprKind::Repeat(value, _) => {
|
ExprKind::Repeat(value, _) => {
|
||||||
let n = match self.typeck_results.expr_ty(e).kind() {
|
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"),
|
_ => span_bug!(e.span, "typeck error"),
|
||||||
};
|
};
|
||||||
self.expr(value).map(|v| Constant::Repeat(Box::new(v), n))
|
self.expr(value).map(|v| Constant::Repeat(Box::new(v), n))
|
||||||
@ -486,21 +489,16 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> {
|
|||||||
// We only handle a few const functions for now.
|
// We only handle a few const functions for now.
|
||||||
if args.is_empty()
|
if args.is_empty()
|
||||||
&& let ExprKind::Path(qpath) = &callee.kind
|
&& let ExprKind::Path(qpath) = &callee.kind
|
||||||
&& let res = self.typeck_results.qpath_res(qpath, callee.hir_id)
|
&& let Some(did) = self.typeck_results.qpath_res(qpath, callee.hir_id).opt_def_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 value = match int_impl {
|
match self.tcx.get_diagnostic_name(did) {
|
||||||
"<impl i8>" => i8::MAX as u128,
|
Some(sym::i8_legacy_fn_max_value) => Some(Constant::Int(i8::MAX as u128)),
|
||||||
"<impl i16>" => i16::MAX as u128,
|
Some(sym::i16_legacy_fn_max_value) => Some(Constant::Int(i16::MAX as u128)),
|
||||||
"<impl i32>" => i32::MAX as u128,
|
Some(sym::i32_legacy_fn_max_value) => Some(Constant::Int(i32::MAX as u128)),
|
||||||
"<impl i64>" => i64::MAX as u128,
|
Some(sym::i64_legacy_fn_max_value) => Some(Constant::Int(i64::MAX as u128)),
|
||||||
"<impl i128>" => i128::MAX as u128,
|
Some(sym::i128_legacy_fn_max_value) => Some(Constant::Int(i128::MAX as u128)),
|
||||||
_ => return None,
|
_ => None,
|
||||||
};
|
}
|
||||||
Some(Constant::Int(value))
|
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
@ -512,9 +510,9 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> {
|
|||||||
if let Some(Constant::Adt(constant)) = &self.expr(local_expr)
|
if let Some(Constant::Adt(constant)) = &self.expr(local_expr)
|
||||||
&& let ty::Adt(adt_def, _) = constant.ty().kind()
|
&& let ty::Adt(adt_def, _) = constant.ty().kind()
|
||||||
&& adt_def.is_struct()
|
&& 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 {
|
} else {
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
@ -528,7 +526,7 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> {
|
|||||||
/// leaves the local crate.
|
/// leaves the local crate.
|
||||||
pub fn expr_is_empty(&mut self, e: &Expr<'_>) -> Option<bool> {
|
pub fn expr_is_empty(&mut self, e: &Expr<'_>) -> Option<bool> {
|
||||||
match e.kind {
|
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::DropTemps(e) => self.expr_is_empty(e),
|
||||||
ExprKind::Path(ref qpath) => {
|
ExprKind::Path(ref qpath) => {
|
||||||
if !self
|
if !self
|
||||||
@ -539,8 +537,8 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> {
|
|||||||
{
|
{
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
self.fetch_path_and_apply(qpath, e.hir_id, self.typeck_results.expr_ty(e), |this, result| {
|
self.fetch_path_and_apply(qpath, e.hir_id, self.typeck_results.expr_ty(e), |self_, result| {
|
||||||
mir_is_empty(this.lcx, result)
|
mir_is_empty(self_.tcx, result)
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
ExprKind::Lit(lit) => {
|
ExprKind::Lit(lit) => {
|
||||||
@ -557,7 +555,7 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> {
|
|||||||
ExprKind::Array(vec) => self.multi(vec).map(|v| v.is_empty()),
|
ExprKind::Array(vec) => self.multi(vec).map(|v| v.is_empty()),
|
||||||
ExprKind::Repeat(..) => {
|
ExprKind::Repeat(..) => {
|
||||||
if let ty::Array(_, n) = self.typeck_results.expr_ty(e).kind() {
|
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 {
|
} else {
|
||||||
span_bug!(e.span, "typeck error");
|
span_bug!(e.span, "typeck error");
|
||||||
}
|
}
|
||||||
@ -574,8 +572,8 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> {
|
|||||||
Int(value) => {
|
Int(value) => {
|
||||||
let value = !value;
|
let value = !value;
|
||||||
match *ty.kind() {
|
match *ty.kind() {
|
||||||
ty::Int(ity) => Some(Int(unsext(self.lcx.tcx, value as i128, ity))),
|
ty::Int(ity) => Some(Int(unsext(self.tcx, value as i128, ity))),
|
||||||
ty::Uint(ity) => Some(Int(clip(self.lcx.tcx, value, ity))),
|
ty::Uint(ity) => Some(Int(clip(self.tcx, value, ity))),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -590,7 +588,7 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> {
|
|||||||
let ty::Int(ity) = *ty.kind() else { return None };
|
let ty::Int(ity) = *ty.kind() else { return None };
|
||||||
let (min, _) = ity.min_max()?;
|
let (min, _) = ity.min_max()?;
|
||||||
// sign extend
|
// 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.
|
// Applying unary - to the most negative value of any signed integer type panics.
|
||||||
if value == min {
|
if value == min {
|
||||||
@ -599,7 +597,7 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> {
|
|||||||
|
|
||||||
let value = value.checked_neg()?;
|
let value = value.checked_neg()?;
|
||||||
// clear unused bits
|
// clear unused bits
|
||||||
Some(Int(unsext(self.lcx.tcx, value, ity)))
|
Some(Int(unsext(self.tcx, value, ity)))
|
||||||
},
|
},
|
||||||
F32(f) => Some(F32(-f)),
|
F32(f) => Some(F32(-f)),
|
||||||
F64(f) => Some(F64(-f)),
|
F64(f) => Some(F64(-f)),
|
||||||
@ -623,7 +621,7 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> {
|
|||||||
Res::Def(DefKind::Const | DefKind::AssocConst, def_id) => {
|
Res::Def(DefKind::Const | DefKind::AssocConst, def_id) => {
|
||||||
// Check if this constant is based on `cfg!(..)`,
|
// Check if this constant is based on `cfg!(..)`,
|
||||||
// which is NOT constant for our purposes.
|
// 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 {
|
&& let Node::Item(Item {
|
||||||
kind: ItemKind::Const(.., body_id),
|
kind: ItemKind::Const(.., body_id),
|
||||||
..
|
..
|
||||||
@ -632,7 +630,7 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> {
|
|||||||
kind: ExprKind::Lit(_),
|
kind: ExprKind::Lit(_),
|
||||||
span,
|
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()
|
&& is_direct_expn_of(*span, "cfg").is_some()
|
||||||
{
|
{
|
||||||
return None;
|
return None;
|
||||||
@ -642,10 +640,9 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> {
|
|||||||
let args = if self.args.is_empty() {
|
let args = if self.args.is_empty() {
|
||||||
args
|
args
|
||||||
} else {
|
} else {
|
||||||
EarlyBinder::bind(args).instantiate(self.lcx.tcx, self.args)
|
EarlyBinder::bind(args).instantiate(self.tcx, self.args)
|
||||||
};
|
};
|
||||||
let result = self
|
let result = self
|
||||||
.lcx
|
|
||||||
.tcx
|
.tcx
|
||||||
.const_eval_resolve(self.param_env, mir::UnevaluatedConst::new(def_id, args), qpath.span())
|
.const_eval_resolve(self.param_env, mir::UnevaluatedConst::new(def_id, args), qpath.span())
|
||||||
.ok()
|
.ok()
|
||||||
@ -685,7 +682,7 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 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>> {
|
fn block(&mut self, block: &Block<'_>) -> Option<Constant<'tcx>> {
|
||||||
if block.stmts.is_empty()
|
if block.stmts.is_empty()
|
||||||
&& let Some(expr) = block.expr
|
&& let Some(expr) = block.expr
|
||||||
@ -696,7 +693,7 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> {
|
|||||||
if let Some(expr_span) = walk_span_to_context(expr.span, span.ctxt)
|
if let Some(expr_span) = walk_span_to_context(expr.span, span.ctxt)
|
||||||
&& let expr_lo = expr_span.lo()
|
&& let expr_lo = expr_span.lo()
|
||||||
&& expr_lo >= 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()
|
&& let Some(src) = src.as_str()
|
||||||
{
|
{
|
||||||
use rustc_lexer::TokenKind::{BlockComment, LineComment, OpenBrace, Semi, Whitespace};
|
use rustc_lexer::TokenKind::{BlockComment, LineComment, OpenBrace, Semi, Whitespace};
|
||||||
@ -739,8 +736,8 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> {
|
|||||||
ty::Int(ity) => {
|
ty::Int(ity) => {
|
||||||
let (ty_min_value, _) = ity.min_max()?;
|
let (ty_min_value, _) = ity.min_max()?;
|
||||||
let bits = ity.bits();
|
let bits = ity.bits();
|
||||||
let l = sext(self.lcx.tcx, l, ity);
|
let l = sext(self.tcx, l, ity);
|
||||||
let r = sext(self.lcx.tcx, r, 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
|
// 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
|
// the right-hand argument is -1 always panics, even with overflow-checks disabled
|
||||||
@ -751,7 +748,7 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> {
|
|||||||
return None;
|
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 {
|
match op.node {
|
||||||
// When +, * or binary - create a value greater than the maximum value, or less than
|
// When +, * or binary - create a value greater than the maximum value, or less than
|
||||||
// the minimum value that can be stored, it panics.
|
// the minimum value that can be stored, it panics.
|
||||||
@ -845,7 +842,7 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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 {
|
let mir::Const::Val(val, _) = result else {
|
||||||
// We only work on evaluated consts.
|
// We only work on evaluated consts.
|
||||||
return None;
|
return None;
|
||||||
@ -863,13 +860,13 @@ pub fn mir_to_const<'tcx>(lcx: &LateContext<'tcx>, result: mir::Const<'tcx>) ->
|
|||||||
_ => None,
|
_ => None,
|
||||||
},
|
},
|
||||||
(_, ty::Ref(_, inner_ty, _)) if matches!(inner_ty.kind(), ty::Str) => {
|
(_, 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)
|
String::from_utf8(data.to_owned()).ok().map(Constant::Str)
|
||||||
},
|
},
|
||||||
(_, ty::Adt(adt_def, _)) if adt_def.is_struct() => Some(Constant::Adt(result)),
|
(_, ty::Adt(adt_def, _)) if adt_def.is_struct() => Some(Constant::Adt(result)),
|
||||||
(ConstValue::Indirect { alloc_id, offset }, ty::Array(sub_type, len)) => {
|
(ConstValue::Indirect { alloc_id, offset }, ty::Array(sub_type, len)) => {
|
||||||
let alloc = lcx.tcx.global_alloc(alloc_id).unwrap_memory().inner();
|
let alloc = tcx.global_alloc(alloc_id).unwrap_memory().inner();
|
||||||
let len = len.try_to_target_usize(lcx.tcx)?;
|
let len = len.try_to_target_usize(tcx)?;
|
||||||
let ty::Float(flt) = sub_type.kind() else {
|
let ty::Float(flt) = sub_type.kind() else {
|
||||||
return None;
|
return None;
|
||||||
};
|
};
|
||||||
@ -877,7 +874,7 @@ pub fn mir_to_const<'tcx>(lcx: &LateContext<'tcx>, result: mir::Const<'tcx>) ->
|
|||||||
let mut res = Vec::new();
|
let mut res = Vec::new();
|
||||||
for idx in 0..len {
|
for idx in 0..len {
|
||||||
let range = alloc_range(offset + size * idx, size);
|
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 {
|
res.push(match flt {
|
||||||
FloatTy::F16 => Constant::F16(f16::from_bits(val.to_u16().ok()?)),
|
FloatTy::F16 => Constant::F16(f16::from_bits(val.to_u16().ok()?)),
|
||||||
FloatTy::F32 => Constant::F32(f32::from_bits(val.to_u32().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 {
|
let mir::Const::Val(val, _) = result else {
|
||||||
// We only work on evaluated consts.
|
// We only work on evaluated consts.
|
||||||
return None;
|
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 {
|
if let ConstValue::Indirect { alloc_id, offset } = val {
|
||||||
// Get the length from the slice, using the same formula as
|
// Get the length from the slice, using the same formula as
|
||||||
// [`ConstValue::try_get_slice_bytes_for_diagnostics`].
|
// [`ConstValue::try_get_slice_bytes_for_diagnostics`].
|
||||||
let a = lcx.tcx.global_alloc(alloc_id).unwrap_memory().inner();
|
let a = tcx.global_alloc(alloc_id).unwrap_memory().inner();
|
||||||
let ptr_size = lcx.tcx.data_layout.pointer_size;
|
let ptr_size = tcx.data_layout.pointer_size;
|
||||||
if a.size() < offset + 2 * ptr_size {
|
if a.size() < offset + 2 * ptr_size {
|
||||||
// (partially) dangling reference
|
// (partially) dangling reference
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
let len = a
|
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()?
|
.ok()?
|
||||||
.to_target_usize(&lcx.tcx)
|
.to_target_usize(&tcx)
|
||||||
.ok()?;
|
.ok()?;
|
||||||
Some(len == 0)
|
Some(len == 0)
|
||||||
} else {
|
} else {
|
||||||
None
|
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,
|
_ => 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),
|
(ConstValue::ZeroSized, _) => Some(true),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
@ -929,12 +926,12 @@ fn mir_is_empty<'tcx>(lcx: &LateContext<'tcx>, result: mir::Const<'tcx>) -> Opti
|
|||||||
|
|
||||||
fn field_of_struct<'tcx>(
|
fn field_of_struct<'tcx>(
|
||||||
adt_def: ty::AdtDef<'tcx>,
|
adt_def: ty::AdtDef<'tcx>,
|
||||||
lcx: &LateContext<'tcx>,
|
tcx: TyCtxt<'tcx>,
|
||||||
result: mir::Const<'tcx>,
|
result: mir::Const<'tcx>,
|
||||||
field: &Ident,
|
field: &Ident,
|
||||||
) -> Option<mir::Const<'tcx>> {
|
) -> Option<mir::Const<'tcx>> {
|
||||||
if let mir::Const::Val(result, ty) = result
|
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(dc_variant) = dc.variant
|
||||||
&& let Some(variant) = adt_def.variants().get(dc_variant)
|
&& let Some(variant) = adt_def.variants().get(dc_variant)
|
||||||
&& let Some(field_idx) = variant.fields.iter().position(|el| el.name == field.name)
|
&& 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()
|
if let rustc_ty::Adt(_, subst) = ty.kind()
|
||||||
&& let bnd_ty = subst.type_at(0)
|
&& let bnd_ty = subst.type_at(0)
|
||||||
&& let Some(min_val) = bnd_ty.numeric_min_val(cx.tcx)
|
&& 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)
|
&& let Some(start_const) = constant(cx, cx.typeck_results(), start)
|
||||||
{
|
{
|
||||||
start_const == min_const
|
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()
|
if let rustc_ty::Adt(_, subst) = ty.kind()
|
||||||
&& let bnd_ty = subst.type_at(0)
|
&& let bnd_ty = subst.type_at(0)
|
||||||
&& let Some(max_val) = bnd_ty.numeric_max_val(cx.tcx)
|
&& 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)
|
&& let Some(end_const) = constant(cx, cx.typeck_results(), end)
|
||||||
{
|
{
|
||||||
end_const == max_const
|
end_const == max_const
|
||||||
|
Loading…
x
Reference in New Issue
Block a user