Skip to content

Commit 91997a4

Browse files
committed
Auto merge of rust-lang#11565 - RalfJung:mir_to_const, r=Jarcho
mir_to_const improvements This simplifies some code and also fixes the float array handling to properly take into account the `offset`, and to work with little-endian targets. Fixes rust-lang/rust-clippy#11488 changelog: none
2 parents d18d01a + 0f19857 commit 91997a4

File tree

4 files changed

+38
-51
lines changed

4 files changed

+38
-51
lines changed

clippy_lints/src/enum_clike.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
//! lint on C-like enums that are `repr(isize/usize)` and have values that
22
//! don't fit into an `i32`
33
4-
use clippy_utils::consts::{miri_to_const, Constant};
4+
use clippy_utils::consts::{mir_to_const, Constant};
55
use clippy_utils::diagnostics::span_lint;
66
use rustc_hir::{Item, ItemKind};
77
use rustc_lint::{LateContext, LateLintPass};
@@ -51,7 +51,7 @@ impl<'tcx> LateLintPass<'tcx> for UnportableVariant {
5151
.const_eval_poly(def_id.to_def_id())
5252
.ok()
5353
.map(|val| rustc_middle::mir::Const::from_value(val, ty));
54-
if let Some(Constant::Int(val)) = constant.and_then(|c| miri_to_const(cx, c)) {
54+
if let Some(Constant::Int(val)) = constant.and_then(|c| mir_to_const(cx, c)) {
5555
if let ty::Adt(adt, _) = ty.kind() {
5656
if adt.is_enum() {
5757
ty = adt.repr().discr_type().to_ty(cx.tcx);

clippy_lints/src/matches/overlapping_arms.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use clippy_utils::consts::{constant, constant_full_int, miri_to_const, FullInt};
1+
use clippy_utils::consts::{constant, constant_full_int, mir_to_const, FullInt};
22
use clippy_utils::diagnostics::span_lint_and_note;
33
use core::cmp::Ordering;
44
use rustc_hir::{Arm, Expr, PatKind, RangeEnd};
@@ -37,14 +37,14 @@ fn all_ranges<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'_>], ty: Ty<'tcx>)
3737
Some(lhs) => constant(cx, cx.typeck_results(), lhs)?,
3838
None => {
3939
let min_val_const = ty.numeric_min_val(cx.tcx)?;
40-
miri_to_const(cx, mir::Const::from_ty_const(min_val_const, cx.tcx))?
40+
mir_to_const(cx, mir::Const::from_ty_const(min_val_const, cx.tcx))?
4141
},
4242
};
4343
let rhs_const = match rhs {
4444
Some(rhs) => constant(cx, cx.typeck_results(), rhs)?,
4545
None => {
4646
let max_val_const = ty.numeric_max_val(cx.tcx)?;
47-
miri_to_const(cx, mir::Const::from_ty_const(max_val_const, cx.tcx))?
47+
mir_to_const(cx, mir::Const::from_ty_const(max_val_const, cx.tcx))?
4848
},
4949
};
5050
let lhs_val = lhs_const.int_value(cx, ty)?;

clippy_utils/src/consts.rs

+30-39
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,12 @@ use rustc_hir::def::{DefKind, Res};
99
use rustc_hir::{BinOp, BinOpKind, Block, ConstBlock, Expr, ExprKind, HirId, Item, ItemKind, Node, QPath, UnOp};
1010
use rustc_lexer::tokenize;
1111
use rustc_lint::LateContext;
12-
use rustc_middle::mir::interpret::Scalar;
12+
use rustc_middle::mir::interpret::{alloc_range, Scalar};
1313
use rustc_middle::ty::{self, EarlyBinder, FloatTy, GenericArgsRef, List, ScalarInt, Ty, TyCtxt};
1414
use rustc_middle::{bug, mir, span_bug};
1515
use rustc_span::symbol::{Ident, Symbol};
1616
use rustc_span::SyntaxContext;
17+
use rustc_target::abi::Size;
1718
use std::cmp::Ordering::{self, Equal};
1819
use std::hash::{Hash, Hasher};
1920
use std::iter;
@@ -403,7 +404,7 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> {
403404
&& adt_def.is_struct()
404405
&& let Some(desired_field) = field_of_struct(*adt_def, self.lcx, *constant, field)
405406
{
406-
miri_to_const(self.lcx, desired_field)
407+
mir_to_const(self.lcx, desired_field)
407408
}
408409
else {
409410
result
@@ -483,7 +484,7 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> {
483484
.const_eval_resolve(self.param_env, mir::UnevaluatedConst::new(def_id, args), None)
484485
.ok()
485486
.map(|val| rustc_middle::mir::Const::from_value(val, ty))?;
486-
let result = miri_to_const(self.lcx, result)?;
487+
let result = mir_to_const(self.lcx, result)?;
487488
self.source = ConstantSource::Constant;
488489
Some(result)
489490
},
@@ -655,10 +656,14 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> {
655656
}
656657
}
657658

658-
pub fn miri_to_const<'tcx>(lcx: &LateContext<'tcx>, result: mir::Const<'tcx>) -> Option<Constant<'tcx>> {
659+
pub fn mir_to_const<'tcx>(lcx: &LateContext<'tcx>, result: mir::Const<'tcx>) -> Option<Constant<'tcx>> {
659660
use rustc_middle::mir::ConstValue;
660-
match result {
661-
mir::Const::Val(ConstValue::Scalar(Scalar::Int(int)), _) => match result.ty().kind() {
661+
let mir::Const::Val(val, _) = result else {
662+
// We only work on evaluated consts.
663+
return None;
664+
};
665+
match (val, result.ty().kind()) {
666+
(ConstValue::Scalar(Scalar::Int(int)), _) => match result.ty().kind() {
662667
ty::Adt(adt_def, _) if adt_def.is_struct() => Some(Constant::Adt(result)),
663668
ty::Bool => Some(Constant::Bool(int == ScalarInt::TRUE)),
664669
ty::Uint(_) | ty::Int(_) => Some(Constant::Int(int.assert_bits(int.size()))),
@@ -671,42 +676,28 @@ pub fn miri_to_const<'tcx>(lcx: &LateContext<'tcx>, result: mir::Const<'tcx>) ->
671676
ty::RawPtr(_) => Some(Constant::RawPtr(int.assert_bits(int.size()))),
672677
_ => None,
673678
},
674-
mir::Const::Val(cv, _) if matches!(result.ty().kind(), ty::Ref(_, inner_ty, _) if matches!(inner_ty.kind(), ty::Str)) =>
675-
{
676-
let data = cv.try_get_slice_bytes_for_diagnostics(lcx.tcx)?;
679+
(_, ty::Ref(_, inner_ty, _)) if matches!(inner_ty.kind(), ty::Str) => {
680+
let data = val.try_get_slice_bytes_for_diagnostics(lcx.tcx)?;
677681
String::from_utf8(data.to_owned()).ok().map(Constant::Str)
678682
},
679-
mir::Const::Val(ConstValue::Indirect { alloc_id, offset: _ }, _) => {
680-
let alloc = lcx.tcx.global_alloc(alloc_id).unwrap_memory();
681-
match result.ty().kind() {
682-
ty::Adt(adt_def, _) if adt_def.is_struct() => Some(Constant::Adt(result)),
683-
ty::Array(sub_type, len) => match sub_type.kind() {
684-
ty::Float(FloatTy::F32) => match len.try_to_target_usize(lcx.tcx) {
685-
Some(len) => alloc
686-
.inner()
687-
.inspect_with_uninit_and_ptr_outside_interpreter(0..(4 * usize::try_from(len).unwrap()))
688-
.to_owned()
689-
.array_chunks::<4>()
690-
.map(|&chunk| Some(Constant::F32(f32::from_le_bytes(chunk))))
691-
.collect::<Option<Vec<Constant<'tcx>>>>()
692-
.map(Constant::Vec),
693-
_ => None,
694-
},
695-
ty::Float(FloatTy::F64) => match len.try_to_target_usize(lcx.tcx) {
696-
Some(len) => alloc
697-
.inner()
698-
.inspect_with_uninit_and_ptr_outside_interpreter(0..(8 * usize::try_from(len).unwrap()))
699-
.to_owned()
700-
.array_chunks::<8>()
701-
.map(|&chunk| Some(Constant::F64(f64::from_le_bytes(chunk))))
702-
.collect::<Option<Vec<Constant<'tcx>>>>()
703-
.map(Constant::Vec),
704-
_ => None,
705-
},
706-
_ => None,
707-
},
708-
_ => None,
683+
(_, ty::Adt(adt_def, _)) if adt_def.is_struct() => Some(Constant::Adt(result)),
684+
(ConstValue::Indirect { alloc_id, offset }, ty::Array(sub_type, len)) => {
685+
let alloc = lcx.tcx.global_alloc(alloc_id).unwrap_memory().inner();
686+
let len = len.try_to_target_usize(lcx.tcx)?;
687+
let ty::Float(flt) = sub_type.kind() else {
688+
return None;
689+
};
690+
let size = Size::from_bits(flt.bit_width());
691+
let mut res = Vec::new();
692+
for idx in 0..len {
693+
let range = alloc_range(offset + size * idx, size);
694+
let val = alloc.read_scalar(&lcx.tcx, range, /* read_provenance */ false).ok()?;
695+
res.push(match flt {
696+
FloatTy::F32 => Constant::F32(f32::from_bits(val.to_u32().ok()?)),
697+
FloatTy::F64 => Constant::F64(f64::from_bits(val.to_u64().ok()?)),
698+
});
709699
}
700+
Some(Constant::Vec(res))
710701
},
711702
_ => None,
712703
}

clippy_utils/src/lib.rs

+3-7
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@ use rustc_span::{sym, Span};
113113
use rustc_target::abi::Integer;
114114
use visitors::Visitable;
115115

116-
use crate::consts::{constant, miri_to_const, Constant};
116+
use crate::consts::{constant, mir_to_const, Constant};
117117
use crate::higher::Range;
118118
use crate::ty::{
119119
adt_and_variant_of_res, can_partially_move_ty, expr_sig, is_copy, is_recursively_primitive_type,
@@ -1509,9 +1509,7 @@ pub fn is_range_full(cx: &LateContext<'_>, expr: &Expr<'_>, container_path: Opti
15091509
if let rustc_ty::Adt(_, subst) = ty.kind()
15101510
&& let bnd_ty = subst.type_at(0)
15111511
&& let Some(min_val) = bnd_ty.numeric_min_val(cx.tcx)
1512-
&& let const_val = cx.tcx.valtree_to_const_val((bnd_ty, min_val.to_valtree()))
1513-
&& let min_const_kind = Const::from_value(const_val, bnd_ty)
1514-
&& let Some(min_const) = miri_to_const(cx, min_const_kind)
1512+
&& let Some(min_const) = mir_to_const(cx, Const::from_ty_const(min_val, cx.tcx))
15151513
&& let Some(start_const) = constant(cx, cx.typeck_results(), start)
15161514
{
15171515
start_const == min_const
@@ -1525,9 +1523,7 @@ pub fn is_range_full(cx: &LateContext<'_>, expr: &Expr<'_>, container_path: Opti
15251523
if let rustc_ty::Adt(_, subst) = ty.kind()
15261524
&& let bnd_ty = subst.type_at(0)
15271525
&& let Some(max_val) = bnd_ty.numeric_max_val(cx.tcx)
1528-
&& let const_val = cx.tcx.valtree_to_const_val((bnd_ty, max_val.to_valtree()))
1529-
&& let max_const_kind = Const::from_value(const_val, bnd_ty)
1530-
&& let Some(max_const) = miri_to_const(cx, max_const_kind)
1526+
&& let Some(max_const) = mir_to_const(cx, Const::from_ty_const(max_val, cx.tcx))
15311527
&& let Some(end_const) = constant(cx, cx.typeck_results(), end)
15321528
{
15331529
end_const == max_const

0 commit comments

Comments
 (0)