This commit is contained in:
Caio 2023-06-17 17:03:31 -03:00
parent 8c8ff5f31d
commit 0e1caa765e
9 changed files with 114 additions and 72 deletions

View file

@ -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::ConstantKind::from_value(val, ty)); .map(|val| rustc_middle::mir::ConstantKind::from_value(val, ty));
if let Some(Constant::Int(val)) = constant.and_then(|c| miri_to_const(cx.tcx, c)) { if let Some(Constant::Int(val)) = constant.and_then(|c| miri_to_const(cx, 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);

View file

@ -215,7 +215,7 @@ fn check_ln1p(cx: &LateContext<'_>, expr: &Expr<'_>, receiver: &Expr<'_>) {
// ranges [-16777215, 16777216) for type f32 as whole number floats outside // ranges [-16777215, 16777216) for type f32 as whole number floats outside
// this range are lossy and ambiguous. // this range are lossy and ambiguous.
#[expect(clippy::cast_possible_truncation)] #[expect(clippy::cast_possible_truncation)]
fn get_integer_from_float_constant(value: &Constant) -> Option<i32> { fn get_integer_from_float_constant(value: &Constant<'_>) -> Option<i32> {
match value { match value {
F32(num) if num.fract() == 0.0 => { F32(num) if num.fract() == 0.0 => {
if (-16_777_215.0..16_777_216.0).contains(num) { if (-16_777_215.0..16_777_216.0).contains(num) {

View file

@ -41,7 +41,7 @@ fn all_ranges<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'_>], ty: Ty<'tcx>)
cx.tcx.valtree_to_const_val((ty, min_val_const.to_valtree())), cx.tcx.valtree_to_const_val((ty, min_val_const.to_valtree())),
ty, ty,
); );
miri_to_const(cx.tcx, min_constant)? miri_to_const(cx, min_constant)?
}, },
}; };
let rhs_const = match rhs { let rhs_const = match rhs {
@ -52,7 +52,7 @@ fn all_ranges<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'_>], ty: Ty<'tcx>)
cx.tcx.valtree_to_const_val((ty, max_val_const.to_valtree())), cx.tcx.valtree_to_const_val((ty, max_val_const.to_valtree())),
ty, ty,
); );
miri_to_const(cx.tcx, max_constant)? miri_to_const(cx, max_constant)?
}, },
}; };
let lhs_val = lhs_const.int_value(cx, ty)?; let lhs_val = lhs_const.int_value(cx, ty)?;

View file

@ -66,7 +66,7 @@ enum MinMax {
Max, Max,
} }
fn min_max<'a>(cx: &LateContext<'_>, expr: &'a Expr<'a>) -> Option<(MinMax, Constant, &'a Expr<'a>)> { fn min_max<'a, 'tcx>(cx: &LateContext<'tcx>, expr: &'a Expr<'a>) -> Option<(MinMax, Constant<'tcx>, &'a Expr<'a>)> {
match expr.kind { match expr.kind {
ExprKind::Call(path, args) => { ExprKind::Call(path, args) => {
if let ExprKind::Path(ref qpath) = path.kind { if let ExprKind::Path(ref qpath) = path.kind {
@ -99,12 +99,12 @@ fn min_max<'a>(cx: &LateContext<'_>, expr: &'a Expr<'a>) -> Option<(MinMax, Cons
} }
} }
fn fetch_const<'a>( fn fetch_const<'a, 'tcx>(
cx: &LateContext<'_>, cx: &LateContext<'tcx>,
receiver: Option<&'a Expr<'a>>, receiver: Option<&'a Expr<'a>>,
args: &'a [Expr<'a>], args: &'a [Expr<'a>],
m: MinMax, m: MinMax,
) -> Option<(MinMax, Constant, &'a Expr<'a>)> { ) -> Option<(MinMax, Constant<'tcx>, &'a Expr<'a>)> {
let mut args = receiver.into_iter().chain(args); let mut args = receiver.into_iter().chain(args);
let first_arg = args.next()?; let first_arg = args.next()?;
let second_arg = args.next()?; let second_arg = args.next()?;

View file

@ -85,7 +85,7 @@ fn get_lint_and_message(is_local: bool, is_comparing_arrays: bool) -> (&'static
} }
} }
fn is_allowed(val: &Constant) -> bool { fn is_allowed(val: &Constant<'_>) -> bool {
match val { match val {
&Constant::F32(f) => f == 0.0 || f.is_infinite(), &Constant::F32(f) => f == 0.0 || f.is_infinite(),
&Constant::F64(f) => f == 0.0 || f.is_infinite(), &Constant::F64(f) => f == 0.0 || f.is_infinite(),

View file

@ -296,8 +296,8 @@ fn check_possible_range_contains(
} }
} }
struct RangeBounds<'a> { struct RangeBounds<'a, 'tcx> {
val: Constant, val: Constant<'tcx>,
expr: &'a Expr<'a>, expr: &'a Expr<'a>,
id: HirId, id: HirId,
name_span: Span, name_span: Span,
@ -309,7 +309,7 @@ struct RangeBounds<'a> {
// Takes a binary expression such as x <= 2 as input // Takes a binary expression such as x <= 2 as input
// Breaks apart into various pieces, such as the value of the number, // Breaks apart into various pieces, such as the value of the number,
// hir id of the variable, and direction/inclusiveness of the operator // hir id of the variable, and direction/inclusiveness of the operator
fn check_range_bounds<'a>(cx: &'a LateContext<'_>, ex: &'a Expr<'_>) -> Option<RangeBounds<'a>> { fn check_range_bounds<'a, 'tcx>(cx: &'a LateContext<'tcx>, ex: &'a Expr<'_>) -> Option<RangeBounds<'a, 'tcx>> {
if let ExprKind::Binary(ref op, l, r) = ex.kind { if let ExprKind::Binary(ref op, l, r) = ex.kind {
let (inclusive, ordering) = match op.node { let (inclusive, ordering) = match op.node {
BinOpKind::Gt => (false, Ordering::Greater), BinOpKind::Gt => (false, Ordering::Greater),

View file

@ -14,7 +14,7 @@ use rustc_middle::mir::interpret::Scalar;
use rustc_middle::ty::{self, EarlyBinder, FloatTy, ScalarInt, Ty, TyCtxt}; use rustc_middle::ty::{self, EarlyBinder, FloatTy, ScalarInt, Ty, TyCtxt};
use rustc_middle::ty::{List, SubstsRef}; use rustc_middle::ty::{List, SubstsRef};
use rustc_middle::{bug, span_bug}; use rustc_middle::{bug, span_bug};
use rustc_span::symbol::Symbol; use rustc_span::symbol::{Ident, Symbol};
use rustc_span::SyntaxContext; use rustc_span::SyntaxContext;
use std::cmp::Ordering::{self, Equal}; use std::cmp::Ordering::{self, Equal};
use std::hash::{Hash, Hasher}; use std::hash::{Hash, Hasher};
@ -22,7 +22,8 @@ use std::iter;
/// A `LitKind`-like enum to fold constant `Expr`s into. /// A `LitKind`-like enum to fold constant `Expr`s into.
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub enum Constant { pub enum Constant<'tcx> {
Adt(rustc_middle::mir::ConstantKind<'tcx>),
/// A `String` (e.g., "abc"). /// A `String` (e.g., "abc").
Str(String), Str(String),
/// A binary string (e.g., `b"abc"`). /// A binary string (e.g., `b"abc"`).
@ -38,20 +39,20 @@ pub enum Constant {
/// `true` or `false`. /// `true` or `false`.
Bool(bool), Bool(bool),
/// An array of constants. /// An array of constants.
Vec(Vec<Constant>), Vec(Vec<Constant<'tcx>>),
/// Also an array, but with only one constant, repeated N times. /// Also an array, but with only one constant, repeated N times.
Repeat(Box<Constant>, u64), Repeat(Box<Constant<'tcx>>, u64),
/// A tuple of constants. /// A tuple of constants.
Tuple(Vec<Constant>), Tuple(Vec<Constant<'tcx>>),
/// A raw pointer. /// A raw pointer.
RawPtr(u128), RawPtr(u128),
/// A reference /// A reference
Ref(Box<Constant>), Ref(Box<Constant<'tcx>>),
/// A literal with syntax error. /// A literal with syntax error.
Err, Err,
} }
impl PartialEq for Constant { impl<'tcx> PartialEq for Constant<'tcx> {
fn eq(&self, other: &Self) -> bool { fn eq(&self, other: &Self) -> bool {
match (self, other) { match (self, other) {
(Self::Str(ls), Self::Str(rs)) => ls == rs, (Self::Str(ls), Self::Str(rs)) => ls == rs,
@ -80,13 +81,16 @@ impl PartialEq for Constant {
} }
} }
impl Hash for Constant { impl<'tcx> Hash for Constant<'tcx> {
fn hash<H>(&self, state: &mut H) fn hash<H>(&self, state: &mut H)
where where
H: Hasher, H: Hasher,
{ {
std::mem::discriminant(self).hash(state); std::mem::discriminant(self).hash(state);
match *self { match *self {
Self::Adt(ref elem) => {
elem.hash(state);
},
Self::Str(ref s) => { Self::Str(ref s) => {
s.hash(state); s.hash(state);
}, },
@ -126,7 +130,7 @@ impl Hash for Constant {
} }
} }
impl Constant { impl<'tcx> Constant<'tcx> {
pub fn partial_cmp(tcx: TyCtxt<'_>, cmp_type: Ty<'_>, left: &Self, right: &Self) -> Option<Ordering> { pub fn partial_cmp(tcx: TyCtxt<'_>, cmp_type: Ty<'_>, left: &Self, right: &Self) -> Option<Ordering> {
match (left, right) { match (left, right) {
(Self::Str(ls), Self::Str(rs)) => Some(ls.cmp(rs)), (Self::Str(ls), Self::Str(rs)) => Some(ls.cmp(rs)),
@ -209,7 +213,7 @@ impl Constant {
} }
/// Parses a `LitKind` to a `Constant`. /// Parses a `LitKind` to a `Constant`.
pub fn lit_to_mir_constant(lit: &LitKind, ty: Option<Ty<'_>>) -> Constant { pub fn lit_to_mir_constant<'tcx>(lit: &LitKind, ty: Option<Ty<'tcx>>) -> Constant<'tcx> {
match *lit { match *lit {
LitKind::Str(ref is, _) => Constant::Str(is.to_string()), LitKind::Str(ref is, _) => Constant::Str(is.to_string()),
LitKind::Byte(b) => Constant::Int(u128::from(b)), LitKind::Byte(b) => Constant::Int(u128::from(b)),
@ -248,7 +252,7 @@ pub fn constant<'tcx>(
lcx: &LateContext<'tcx>, lcx: &LateContext<'tcx>,
typeck_results: &ty::TypeckResults<'tcx>, typeck_results: &ty::TypeckResults<'tcx>,
e: &Expr<'_>, e: &Expr<'_>,
) -> Option<Constant> { ) -> Option<Constant<'tcx>> {
ConstEvalLateContext::new(lcx, typeck_results).expr(e) ConstEvalLateContext::new(lcx, typeck_results).expr(e)
} }
@ -257,7 +261,7 @@ pub fn constant_with_source<'tcx>(
lcx: &LateContext<'tcx>, lcx: &LateContext<'tcx>,
typeck_results: &ty::TypeckResults<'tcx>, typeck_results: &ty::TypeckResults<'tcx>,
e: &Expr<'_>, e: &Expr<'_>,
) -> Option<(Constant, ConstantSource)> { ) -> Option<(Constant<'tcx>, ConstantSource)> {
let mut ctxt = ConstEvalLateContext::new(lcx, typeck_results); let mut ctxt = ConstEvalLateContext::new(lcx, typeck_results);
let res = ctxt.expr(e); let res = ctxt.expr(e);
res.map(|x| (x, ctxt.source)) res.map(|x| (x, ctxt.source))
@ -268,7 +272,7 @@ pub fn constant_simple<'tcx>(
lcx: &LateContext<'tcx>, lcx: &LateContext<'tcx>,
typeck_results: &ty::TypeckResults<'tcx>, typeck_results: &ty::TypeckResults<'tcx>,
e: &Expr<'_>, e: &Expr<'_>,
) -> Option<Constant> { ) -> 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))
} }
@ -338,7 +342,7 @@ 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> { pub fn expr(&mut self, e: &Expr<'_>) -> Option<Constant<'tcx>> {
match e.kind { match e.kind {
ExprKind::Path(ref qpath) => self.fetch_path(qpath, e.hir_id, self.typeck_results.expr_ty(e)), ExprKind::Path(ref qpath) => self.fetch_path(qpath, e.hir_id, self.typeck_results.expr_ty(e)),
ExprKind::Block(block, _) => self.block(block), ExprKind::Block(block, _) => self.block(block),
@ -392,13 +396,25 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> {
}, },
ExprKind::Index(arr, index) => self.index(arr, index), ExprKind::Index(arr, index) => self.index(arr, index),
ExprKind::AddrOf(_, _, inner) => self.expr(inner).map(|r| Constant::Ref(Box::new(r))), ExprKind::AddrOf(_, _, inner) => self.expr(inner).map(|r| Constant::Ref(Box::new(r))),
// TODO: add other expressions. ExprKind::Field(ref local_expr, ref field) => {
let result = self.expr(local_expr);
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)
{
miri_to_const(self.lcx, desired_field)
}
else {
result
}
},
_ => None, _ => None,
} }
} }
#[expect(clippy::cast_possible_wrap)] #[expect(clippy::cast_possible_wrap)]
fn constant_not(&self, o: &Constant, ty: Ty<'_>) -> Option<Constant> { fn constant_not(&self, o: &Constant<'tcx>, ty: Ty<'_>) -> Option<Constant<'tcx>> {
use self::Constant::{Bool, Int}; use self::Constant::{Bool, Int};
match *o { match *o {
Bool(b) => Some(Bool(!b)), Bool(b) => Some(Bool(!b)),
@ -414,7 +430,7 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> {
} }
} }
fn constant_negate(&self, o: &Constant, ty: Ty<'_>) -> Option<Constant> { fn constant_negate(&self, o: &Constant<'tcx>, ty: Ty<'_>) -> Option<Constant<'tcx>> {
use self::Constant::{Int, F32, F64}; use self::Constant::{Int, F32, F64};
match *o { match *o {
Int(value) => { Int(value) => {
@ -433,28 +449,25 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> {
/// Create `Some(Vec![..])` of all constants, unless there is any /// Create `Some(Vec![..])` of all constants, unless there is any
/// non-constant part. /// non-constant part.
fn multi(&mut self, vec: &[Expr<'_>]) -> Option<Vec<Constant>> { fn multi(&mut self, vec: &[Expr<'_>]) -> Option<Vec<Constant<'tcx>>> {
vec.iter().map(|elem| self.expr(elem)).collect::<Option<_>>() vec.iter().map(|elem| self.expr(elem)).collect::<Option<_>>()
} }
/// Lookup a possibly constant expression from an `ExprKind::Path`. /// Lookup a possibly constant expression from an `ExprKind::Path`.
fn fetch_path(&mut self, qpath: &QPath<'_>, id: HirId, ty: Ty<'tcx>) -> Option<Constant> { fn fetch_path(&mut self, qpath: &QPath<'_>, id: HirId, ty: Ty<'tcx>) -> Option<Constant<'tcx>> {
let res = self.typeck_results.qpath_res(qpath, id); let res = self.typeck_results.qpath_res(qpath, id);
match res { match res {
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.lcx.tcx.hir().get_if_local(def_id)
let Node::Item(&Item { && let Node::Item(Item { kind: ItemKind::Const(_, body_id), .. }) = node
kind: ItemKind::Const(_, body_id), && let Node::Expr(Expr { kind: ExprKind::Lit(_), span, .. }) = self.lcx
.. .tcx
}) = node && .hir()
let Node::Expr(&Expr { .get(body_id.hir_id)
kind: ExprKind::Lit(_), && is_direct_expn_of(*span, "cfg").is_some()
span, {
..
}) = self.lcx.tcx.hir().get(body_id.hir_id) &&
is_direct_expn_of(span, "cfg").is_some() {
return None; return None;
} }
@ -464,23 +477,21 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> {
} else { } else {
EarlyBinder::bind(substs).subst(self.lcx.tcx, self.substs) EarlyBinder::bind(substs).subst(self.lcx.tcx, self.substs)
}; };
let result = self let result = self
.lcx .lcx
.tcx .tcx
.const_eval_resolve(self.param_env, mir::UnevaluatedConst::new(def_id, substs), None) .const_eval_resolve(self.param_env, mir::UnevaluatedConst::new(def_id, substs), None)
.ok() .ok()
.map(|val| rustc_middle::mir::ConstantKind::from_value(val, ty))?; .map(|val| rustc_middle::mir::ConstantKind::from_value(val, ty))?;
let result = miri_to_const(self.lcx.tcx, result)?; let result = miri_to_const(self.lcx, result)?;
self.source = ConstantSource::Constant; self.source = ConstantSource::Constant;
Some(result) Some(result)
}, },
// FIXME: cover all usable cases.
_ => None, _ => None,
} }
} }
fn index(&mut self, lhs: &'_ Expr<'_>, index: &'_ Expr<'_>) -> Option<Constant> { fn index(&mut self, lhs: &'_ Expr<'_>, index: &'_ Expr<'_>) -> Option<Constant<'tcx>> {
let lhs = self.expr(lhs); let lhs = self.expr(lhs);
let index = self.expr(index); let index = self.expr(index);
@ -506,7 +517,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 only has one constant expression.
fn block(&mut self, block: &Block<'_>) -> Option<Constant> { 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
{ {
@ -539,7 +550,7 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> {
} }
} }
fn ifthenelse(&mut self, cond: &Expr<'_>, then: &Expr<'_>, otherwise: Option<&Expr<'_>>) -> Option<Constant> { fn ifthenelse(&mut self, cond: &Expr<'_>, then: &Expr<'_>, otherwise: Option<&Expr<'_>>) -> Option<Constant<'tcx>> {
if let Some(Constant::Bool(b)) = self.expr(cond) { if let Some(Constant::Bool(b)) = self.expr(cond) {
if b { if b {
self.expr(then) self.expr(then)
@ -551,7 +562,7 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> {
} }
} }
fn binop(&mut self, op: BinOp, left: &Expr<'_>, right: &Expr<'_>) -> Option<Constant> { fn binop(&mut self, op: BinOp, left: &Expr<'_>, right: &Expr<'_>) -> Option<Constant<'tcx>> {
let l = self.expr(left)?; let l = self.expr(left)?;
let r = self.expr(right); let r = self.expr(right);
match (l, r) { match (l, r) {
@ -644,11 +655,11 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> {
} }
} }
pub fn miri_to_const<'tcx>(tcx: TyCtxt<'tcx>, result: mir::ConstantKind<'tcx>) -> Option<Constant> { pub fn miri_to_const<'tcx>(lcx: &LateContext<'tcx>, result: mir::ConstantKind<'tcx>) -> Option<Constant<'tcx>> {
use rustc_middle::mir::interpret::ConstValue; use rustc_middle::mir::interpret::ConstValue;
match result { match result {
mir::ConstantKind::Val(ConstValue::Scalar(Scalar::Int(int)), _) => { mir::ConstantKind::Val(ConstValue::Scalar(Scalar::Int(int)), _) => match result.ty().kind() {
match result.ty().kind() { ty::Adt(adt_def, _) if adt_def.is_struct() => Some(Constant::Adt(result)),
ty::Bool => Some(Constant::Bool(int == ScalarInt::TRUE)), ty::Bool => Some(Constant::Bool(int == ScalarInt::TRUE)),
ty::Uint(_) | ty::Int(_) => Some(Constant::Int(int.assert_bits(int.size()))), ty::Uint(_) | ty::Int(_) => Some(Constant::Int(int.assert_bits(int.size()))),
ty::Float(FloatTy::F32) => Some(Constant::F32(f32::from_bits( ty::Float(FloatTy::F32) => Some(Constant::F32(f32::from_bits(
@ -658,9 +669,7 @@ pub fn miri_to_const<'tcx>(tcx: TyCtxt<'tcx>, result: mir::ConstantKind<'tcx>) -
int.try_into().expect("invalid f64 bit representation"), int.try_into().expect("invalid f64 bit representation"),
))), ))),
ty::RawPtr(_) => Some(Constant::RawPtr(int.assert_bits(int.size()))), ty::RawPtr(_) => Some(Constant::RawPtr(int.assert_bits(int.size()))),
// FIXME: implement other conversions.
_ => None, _ => None,
}
}, },
mir::ConstantKind::Val(ConstValue::Slice { data, start, end }, _) => match result.ty().kind() { mir::ConstantKind::Val(ConstValue::Slice { data, start, end }, _) => match result.ty().kind() {
ty::Ref(_, tam, _) => match tam.kind() { ty::Ref(_, tam, _) => match tam.kind() {
@ -676,35 +685,53 @@ pub fn miri_to_const<'tcx>(tcx: TyCtxt<'tcx>, result: mir::ConstantKind<'tcx>) -
_ => None, _ => None,
}, },
mir::ConstantKind::Val(ConstValue::ByRef { alloc, offset: _ }, _) => match result.ty().kind() { mir::ConstantKind::Val(ConstValue::ByRef { alloc, offset: _ }, _) => match result.ty().kind() {
ty::Adt(adt_def, _) if adt_def.is_struct() => Some(Constant::Adt(result)),
ty::Array(sub_type, len) => match sub_type.kind() { ty::Array(sub_type, len) => match sub_type.kind() {
ty::Float(FloatTy::F32) => match len.kind().try_to_target_usize(tcx) { ty::Float(FloatTy::F32) => match len.kind().try_to_target_usize(lcx.tcx) {
Some(len) => alloc Some(len) => alloc
.inner() .inner()
.inspect_with_uninit_and_ptr_outside_interpreter(0..(4 * usize::try_from(len).unwrap())) .inspect_with_uninit_and_ptr_outside_interpreter(0..(4 * usize::try_from(len).unwrap()))
.to_owned() .to_owned()
.array_chunks::<4>() .array_chunks::<4>()
.map(|&chunk| Some(Constant::F32(f32::from_le_bytes(chunk)))) .map(|&chunk| Some(Constant::F32(f32::from_le_bytes(chunk))))
.collect::<Option<Vec<Constant>>>() .collect::<Option<Vec<Constant<'tcx>>>>()
.map(Constant::Vec), .map(Constant::Vec),
_ => None, _ => None,
}, },
ty::Float(FloatTy::F64) => match len.kind().try_to_target_usize(tcx) { ty::Float(FloatTy::F64) => match len.kind().try_to_target_usize(lcx.tcx) {
Some(len) => alloc Some(len) => alloc
.inner() .inner()
.inspect_with_uninit_and_ptr_outside_interpreter(0..(8 * usize::try_from(len).unwrap())) .inspect_with_uninit_and_ptr_outside_interpreter(0..(8 * usize::try_from(len).unwrap()))
.to_owned() .to_owned()
.array_chunks::<8>() .array_chunks::<8>()
.map(|&chunk| Some(Constant::F64(f64::from_le_bytes(chunk)))) .map(|&chunk| Some(Constant::F64(f64::from_le_bytes(chunk))))
.collect::<Option<Vec<Constant>>>() .collect::<Option<Vec<Constant<'tcx>>>>()
.map(Constant::Vec), .map(Constant::Vec),
_ => None, _ => None,
}, },
// FIXME: implement other array type conversions.
_ => None, _ => None,
}, },
_ => None, _ => None,
}, },
// FIXME: implement other conversions.
_ => None, _ => None,
} }
} }
fn field_of_struct<'tcx>(
adt_def: ty::AdtDef<'tcx>,
lcx: &LateContext<'tcx>,
result: mir::ConstantKind<'tcx>,
field: &Ident,
) -> Option<mir::ConstantKind<'tcx>> {
let dc = lcx.tcx.destructure_mir_constant(lcx.param_env, result);
if 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)
&& let Some(dc_field) = dc.fields.get(field_idx)
{
Some(*dc_field)
}
else {
None
}
}

View file

@ -1499,7 +1499,7 @@ pub fn is_range_full(cx: &LateContext<'_>, expr: &Expr<'_>, container_path: Opti
&& let Some(min_val) = bnd_ty.numeric_min_val(cx.tcx) && let Some(min_val) = bnd_ty.numeric_min_val(cx.tcx)
&& let const_val = cx.tcx.valtree_to_const_val((bnd_ty, min_val.to_valtree())) && let const_val = cx.tcx.valtree_to_const_val((bnd_ty, min_val.to_valtree()))
&& let min_const_kind = ConstantKind::from_value(const_val, bnd_ty) && let min_const_kind = ConstantKind::from_value(const_val, bnd_ty)
&& let Some(min_const) = miri_to_const(cx.tcx, min_const_kind) && let Some(min_const) = miri_to_const(cx, min_const_kind)
&& 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
@ -1515,7 +1515,7 @@ pub fn is_range_full(cx: &LateContext<'_>, expr: &Expr<'_>, container_path: Opti
&& let Some(max_val) = bnd_ty.numeric_max_val(cx.tcx) && let Some(max_val) = bnd_ty.numeric_max_val(cx.tcx)
&& let const_val = cx.tcx.valtree_to_const_val((bnd_ty, max_val.to_valtree())) && let const_val = cx.tcx.valtree_to_const_val((bnd_ty, max_val.to_valtree()))
&& let max_const_kind = ConstantKind::from_value(const_val, bnd_ty) && let max_const_kind = ConstantKind::from_value(const_val, bnd_ty)
&& let Some(max_const) = miri_to_const(cx.tcx, max_const_kind) && let Some(max_const) = miri_to_const(cx, max_const_kind)
&& 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

View file

@ -466,4 +466,19 @@ pub fn issue_10767() {
&3.5_f32 + &1.3_f32; &3.5_f32 + &1.3_f32;
} }
pub fn issue_10792() {
struct One {
a: u32,
}
struct Two {
b: u32,
c: u64,
}
const ONE: One = One { a: 1 };
const TWO: Two = Two { b: 2, c: 3 };
let _ = 10 / ONE.a;
let _ = 10 / TWO.b;
let _ = 10 / TWO.c;
}
fn main() {} fn main() {}