1 #![allow(clippy::float_cmp)]
3 use crate::{clip, is_direct_expn_of, sext, unsext}
;
4 use if_chain
::if_chain
;
5 use rustc_ast
::ast
::{self, LitFloatType, LitKind}
;
6 use rustc_data_structures
::sync
::Lrc
;
7 use rustc_hir
::def
::{DefKind, Res}
;
8 use rustc_hir
::{BinOp, BinOpKind, Block, Expr, ExprKind, HirId, Item, ItemKind, Node, QPath, UnOp}
;
9 use rustc_lint
::LateContext
;
10 use rustc_middle
::mir
;
11 use rustc_middle
::mir
::interpret
::Scalar
;
12 use rustc_middle
::ty
::subst
::{Subst, SubstsRef}
;
13 use rustc_middle
::ty
::{self, EarlyBinder, FloatTy, ScalarInt, Ty, TyCtxt}
;
14 use rustc_middle
::{bug, span_bug}
;
15 use rustc_span
::symbol
::Symbol
;
16 use std
::cmp
::Ordering
::{self, Equal}
;
17 use std
::hash
::{Hash, Hasher}
;
20 /// A `LitKind`-like enum to fold constant `Expr`s into.
21 #[derive(Debug, Clone)]
23 /// A `String` (e.g., "abc").
25 /// A binary string (e.g., `b"abc"`).
27 /// A single `char` (e.g., `'a'`).
29 /// An integer's bit representation.
35 /// `true` or `false`.
37 /// An array of constants.
39 /// Also an array, but with only one constant, repeated N times.
40 Repeat(Box
<Constant
>, u64),
41 /// A tuple of constants.
47 /// A literal with syntax error.
51 impl PartialEq
for Constant
{
52 fn eq(&self, other
: &Self) -> bool
{
54 (&Self::Str(ref ls
), &Self::Str(ref rs
)) => ls
== rs
,
55 (&Self::Binary(ref l
), &Self::Binary(ref r
)) => l
== r
,
56 (&Self::Char(l
), &Self::Char(r
)) => l
== r
,
57 (&Self::Int(l
), &Self::Int(r
)) => l
== r
,
58 (&Self::F64(l
), &Self::F64(r
)) => {
59 // We want `Fw32 == FwAny` and `FwAny == Fw64`, and by transitivity we must have
60 // `Fw32 == Fw64`, so don’t compare them.
61 // `to_bits` is required to catch non-matching 0.0, -0.0, and NaNs.
62 l
.to_bits() == r
.to_bits()
64 (&Self::F32(l
), &Self::F32(r
)) => {
65 // We want `Fw32 == FwAny` and `FwAny == Fw64`, and by transitivity we must have
66 // `Fw32 == Fw64`, so don’t compare them.
67 // `to_bits` is required to catch non-matching 0.0, -0.0, and NaNs.
68 f64::from(l
).to_bits() == f64::from(r
).to_bits()
70 (&Self::Bool(l
), &Self::Bool(r
)) => l
== r
,
71 (&Self::Vec(ref l
), &Self::Vec(ref r
)) | (&Self::Tuple(ref l
), &Self::Tuple(ref r
)) => l
== r
,
72 (&Self::Repeat(ref lv
, ref ls
), &Self::Repeat(ref rv
, ref rs
)) => ls
== rs
&& lv
== rv
,
73 (&Self::Ref(ref lb
), &Self::Ref(ref rb
)) => *lb
== *rb
,
74 // TODO: are there inter-type equalities?
80 impl Hash
for Constant
{
81 fn hash
<H
>(&self, state
: &mut H
)
85 std
::mem
::discriminant(self).hash(state
);
90 Self::Binary(ref b
) => {
100 f64::from(f
).to_bits().hash(state
);
103 f
.to_bits().hash(state
);
108 Self::Vec(ref v
) | Self::Tuple(ref v
) => {
111 Self::Repeat(ref c
, l
) => {
118 Self::Ref(ref r
) => {
121 Self::Err(ref s
) => {
129 pub fn partial_cmp(tcx
: TyCtxt
<'_
>, cmp_type
: Ty
<'_
>, left
: &Self, right
: &Self) -> Option
<Ordering
> {
130 match (left
, right
) {
131 (&Self::Str(ref ls
), &Self::Str(ref rs
)) => Some(ls
.cmp(rs
)),
132 (&Self::Char(ref l
), &Self::Char(ref r
)) => Some(l
.cmp(r
)),
133 (&Self::Int(l
), &Self::Int(r
)) => match *cmp_type
.kind() {
134 ty
::Int(int_ty
) => Some(sext(tcx
, l
, int_ty
).cmp(&sext(tcx
, r
, int_ty
))),
135 ty
::Uint(_
) => Some(l
.cmp(&r
)),
136 _
=> bug
!("Not an int type"),
138 (&Self::F64(l
), &Self::F64(r
)) => l
.partial_cmp(&r
),
139 (&Self::F32(l
), &Self::F32(r
)) => l
.partial_cmp(&r
),
140 (&Self::Bool(ref l
), &Self::Bool(ref r
)) => Some(l
.cmp(r
)),
141 (&Self::Tuple(ref l
), &Self::Tuple(ref r
)) | (&Self::Vec(ref l
), &Self::Vec(ref r
)) => iter
::zip(l
, r
)
142 .map(|(li
, ri
)| Self::partial_cmp(tcx
, cmp_type
, li
, ri
))
143 .find(|r
| r
.map_or(true, |o
| o
!= Ordering
::Equal
))
144 .unwrap_or_else(|| Some(l
.len().cmp(&r
.len()))),
145 (&Self::Repeat(ref lv
, ref ls
), &Self::Repeat(ref rv
, ref rs
)) => {
146 match Self::partial_cmp(tcx
, cmp_type
, lv
, rv
) {
147 Some(Equal
) => Some(ls
.cmp(rs
)),
151 (&Self::Ref(ref lb
), &Self::Ref(ref rb
)) => Self::partial_cmp(tcx
, cmp_type
, lb
, rb
),
152 // TODO: are there any useful inter-type orderings?
157 /// Returns the integer value or `None` if `self` or `val_type` is not integer type.
158 pub fn int_value(&self, cx
: &LateContext
<'_
>, val_type
: Ty
<'_
>) -> Option
<FullInt
> {
159 if let Constant
::Int(const_int
) = *self {
160 match *val_type
.kind() {
161 ty
::Int(ity
) => Some(FullInt
::S(sext(cx
.tcx
, const_int
, ity
))),
162 ty
::Uint(_
) => Some(FullInt
::U(const_int
)),
171 pub fn peel_refs(mut self) -> Self {
172 while let Constant
::Ref(r
) = self {
179 /// Parses a `LitKind` to a `Constant`.
180 pub fn lit_to_mir_constant(lit
: &LitKind
, ty
: Option
<Ty
<'_
>>) -> Constant
{
182 LitKind
::Str(ref is
, _
) => Constant
::Str(is
.to_string()),
183 LitKind
::Byte(b
) => Constant
::Int(u128
::from(b
)),
184 LitKind
::ByteStr(ref s
) => Constant
::Binary(Lrc
::clone(s
)),
185 LitKind
::Char(c
) => Constant
::Char(c
),
186 LitKind
::Int(n
, _
) => Constant
::Int(n
),
187 LitKind
::Float(ref is
, LitFloatType
::Suffixed(fty
)) => match fty
{
188 ast
::FloatTy
::F32
=> Constant
::F32(is
.as_str().parse().unwrap()),
189 ast
::FloatTy
::F64
=> Constant
::F64(is
.as_str().parse().unwrap()),
191 LitKind
::Float(ref is
, LitFloatType
::Unsuffixed
) => match ty
.expect("type of float is known").kind() {
192 ty
::Float(FloatTy
::F32
) => Constant
::F32(is
.as_str().parse().unwrap()),
193 ty
::Float(FloatTy
::F64
) => Constant
::F64(is
.as_str().parse().unwrap()),
196 LitKind
::Bool(b
) => Constant
::Bool(b
),
197 LitKind
::Err(s
) => Constant
::Err(s
),
201 pub fn constant
<'tcx
>(
202 lcx
: &LateContext
<'tcx
>,
203 typeck_results
: &ty
::TypeckResults
<'tcx
>,
205 ) -> Option
<(Constant
, bool
)> {
206 let mut cx
= ConstEvalLateContext
{
209 param_env
: lcx
.param_env
,
210 needed_resolution
: false,
211 substs
: lcx
.tcx
.intern_substs(&[]),
213 cx
.expr(e
).map(|cst
| (cst
, cx
.needed_resolution
))
216 pub fn constant_simple
<'tcx
>(
217 lcx
: &LateContext
<'tcx
>,
218 typeck_results
: &ty
::TypeckResults
<'tcx
>,
220 ) -> Option
<Constant
> {
221 constant(lcx
, typeck_results
, e
).and_then(|(cst
, res
)| if res { None }
else { Some(cst) }
)
224 pub fn constant_full_int
<'tcx
>(
225 lcx
: &LateContext
<'tcx
>,
226 typeck_results
: &ty
::TypeckResults
<'tcx
>,
228 ) -> Option
<FullInt
> {
229 constant_simple(lcx
, typeck_results
, e
)?
.int_value(lcx
, typeck_results
.expr_ty(e
))
232 #[derive(Copy, Clone, Debug, Eq)]
238 impl PartialEq
for FullInt
{
240 fn eq(&self, other
: &Self) -> bool
{
241 self.cmp(other
) == Ordering
::Equal
245 impl PartialOrd
for FullInt
{
247 fn partial_cmp(&self, other
: &Self) -> Option
<Ordering
> {
248 Some(self.cmp(other
))
252 impl Ord
for FullInt
{
254 fn cmp(&self, other
: &Self) -> Ordering
{
257 fn cmp_s_u(s
: i128
, u
: u128
) -> Ordering
{
258 u128
::try_from(s
).map_or(Ordering
::Less
, |x
| x
.cmp(&u
))
261 match (*self, *other
) {
262 (S(s
), S(o
)) => s
.cmp(&o
),
263 (U(s
), U(o
)) => s
.cmp(&o
),
264 (S(s
), U(o
)) => cmp_s_u(s
, o
),
265 (U(s
), S(o
)) => cmp_s_u(o
, s
).reverse(),
270 /// Creates a `ConstEvalLateContext` from the given `LateContext` and `TypeckResults`.
271 pub fn constant_context
<'a
, 'tcx
>(
272 lcx
: &'a LateContext
<'tcx
>,
273 typeck_results
: &'a ty
::TypeckResults
<'tcx
>,
274 ) -> ConstEvalLateContext
<'a
, 'tcx
> {
275 ConstEvalLateContext
{
278 param_env
: lcx
.param_env
,
279 needed_resolution
: false,
280 substs
: lcx
.tcx
.intern_substs(&[]),
284 pub struct ConstEvalLateContext
<'a
, 'tcx
> {
285 lcx
: &'a LateContext
<'tcx
>,
286 typeck_results
: &'a ty
::TypeckResults
<'tcx
>,
287 param_env
: ty
::ParamEnv
<'tcx
>,
288 needed_resolution
: bool
,
289 substs
: SubstsRef
<'tcx
>,
292 impl<'a
, 'tcx
> ConstEvalLateContext
<'a
, 'tcx
> {
293 /// Simple constant folding: Insert an expression, get a constant or none.
294 pub fn expr(&mut self, e
: &Expr
<'_
>) -> Option
<Constant
> {
296 ExprKind
::Path(ref qpath
) => self.fetch_path(qpath
, e
.hir_id
, self.typeck_results
.expr_ty(e
)),
297 ExprKind
::Block(block
, _
) => self.block(block
),
298 ExprKind
::Lit(ref lit
) => {
299 if is_direct_expn_of(e
.span
, "cfg").is_some() {
302 Some(lit_to_mir_constant(&lit
.node
, self.typeck_results
.expr_ty_opt(e
)))
305 ExprKind
::Array(vec
) => self.multi(vec
).map(Constant
::Vec
),
306 ExprKind
::Tup(tup
) => self.multi(tup
).map(Constant
::Tuple
),
307 ExprKind
::Repeat(value
, _
) => {
308 let n
= match self.typeck_results
.expr_ty(e
).kind() {
309 ty
::Array(_
, n
) => n
.try_eval_usize(self.lcx
.tcx
, self.lcx
.param_env
)?
,
310 _
=> span_bug
!(e
.span
, "typeck error"),
312 self.expr(value
).map(|v
| Constant
::Repeat(Box
::new(v
), n
))
314 ExprKind
::Unary(op
, operand
) => self.expr(operand
).and_then(|o
| match op
{
315 UnOp
::Not
=> self.constant_not(&o
, self.typeck_results
.expr_ty(e
)),
316 UnOp
::Neg
=> self.constant_negate(&o
, self.typeck_results
.expr_ty(e
)),
317 UnOp
::Deref
=> Some(if let Constant
::Ref(r
) = o { *r }
else { o }
),
319 ExprKind
::If(cond
, then
, ref otherwise
) => self.ifthenelse(cond
, then
, *otherwise
),
320 ExprKind
::Binary(op
, left
, right
) => self.binop(op
, left
, right
),
321 ExprKind
::Call(callee
, args
) => {
322 // We only handle a few const functions for now.
325 if let ExprKind
::Path(qpath
) = &callee
.kind
;
326 let res
= self.typeck_results
.qpath_res(qpath
, callee
.hir_id
);
327 if let Some(def_id
) = res
.opt_def_id();
328 let def_path
= self.lcx
.get_def_path(def_id
);
329 let def_path
: Vec
<&str> = def_path
.iter().take(4).map(Symbol
::as_str
).collect();
330 if let ["core", "num", int_impl
, "max_value"] = *def_path
;
332 let value
= match int_impl
{
333 "<impl i8>" => i8::MAX
as u128
,
334 "<impl i16>" => i16::MAX
as u128
,
335 "<impl i32>" => i32::MAX
as u128
,
336 "<impl i64>" => i64::MAX
as u128
,
337 "<impl i128>" => i128
::MAX
as u128
,
340 Some(Constant
::Int(value
))
346 ExprKind
::Index(arr
, index
) => self.index(arr
, index
),
347 ExprKind
::AddrOf(_
, _
, inner
) => self.expr(inner
).map(|r
| Constant
::Ref(Box
::new(r
))),
348 // TODO: add other expressions.
353 #[expect(clippy::cast_possible_wrap)]
354 fn constant_not(&self, o
: &Constant
, ty
: Ty
<'_
>) -> Option
<Constant
> {
355 use self::Constant
::{Bool, Int}
;
357 Bool(b
) => Some(Bool(!b
)),
361 ty
::Int(ity
) => Some(Int(unsext(self.lcx
.tcx
, value
as i128
, ity
))),
362 ty
::Uint(ity
) => Some(Int(clip(self.lcx
.tcx
, value
, ity
))),
370 fn constant_negate(&self, o
: &Constant
, ty
: Ty
<'_
>) -> Option
<Constant
> {
371 use self::Constant
::{Int, F32, F64}
;
374 let ity
= match *ty
.kind() {
379 let value
= sext(self.lcx
.tcx
, value
, ity
);
380 let value
= value
.checked_neg()?
;
382 Some(Int(unsext(self.lcx
.tcx
, value
, ity
)))
384 F32(f
) => Some(F32(-f
)),
385 F64(f
) => Some(F64(-f
)),
390 /// Create `Some(Vec![..])` of all constants, unless there is any
391 /// non-constant part.
392 fn multi(&mut self, vec
: &[Expr
<'_
>]) -> Option
<Vec
<Constant
>> {
393 vec
.iter().map(|elem
| self.expr(elem
)).collect
::<Option
<_
>>()
396 /// Lookup a possibly constant expression from an `ExprKind::Path`.
397 fn fetch_path(&mut self, qpath
: &QPath
<'_
>, id
: HirId
, ty
: Ty
<'tcx
>) -> Option
<Constant
> {
398 let res
= self.typeck_results
.qpath_res(qpath
, id
);
400 Res
::Def(DefKind
::Const
| DefKind
::AssocConst
, def_id
) => {
401 // Check if this constant is based on `cfg!(..)`,
402 // which is NOT constant for our purposes.
403 if let Some(node
) = self.lcx
.tcx
.hir().get_if_local(def_id
) &&
404 let Node
::Item(&Item
{
405 kind
: ItemKind
::Const(_
, body_id
),
408 let Node
::Expr(&Expr
{
409 kind
: ExprKind
::Lit(_
),
412 }) = self.lcx
.tcx
.hir().get(body_id
.hir_id
) &&
413 is_direct_expn_of(span
, "cfg").is_some() {
417 let substs
= self.typeck_results
.node_substs(id
);
418 let substs
= if self.substs
.is_empty() {
421 EarlyBinder(substs
).subst(self.lcx
.tcx
, self.substs
)
429 ty
::Unevaluated
::new(ty
::WithOptConstParam
::unknown(def_id
), substs
),
433 .map(|val
| rustc_middle
::mir
::ConstantKind
::from_value(val
, ty
))?
;
434 let result
= miri_to_const(self.lcx
.tcx
, result
);
435 if result
.is_some() {
436 self.needed_resolution
= true;
440 // FIXME: cover all usable cases.
445 fn index(&mut self, lhs
: &'_ Expr
<'_
>, index
: &'_ Expr
<'_
>) -> Option
<Constant
> {
446 let lhs
= self.expr(lhs
);
447 let index
= self.expr(index
);
450 (Some(Constant
::Vec(vec
)), Some(Constant
::Int(index
))) => match vec
.get(index
as usize) {
451 Some(Constant
::F32(x
)) => Some(Constant
::F32(*x
)),
452 Some(Constant
::F64(x
)) => Some(Constant
::F64(*x
)),
455 (Some(Constant
::Vec(vec
)), _
) => {
456 if !vec
.is_empty() && vec
.iter().all(|x
| *x
== vec
[0]) {
458 Some(Constant
::F32(x
)) => Some(Constant
::F32(*x
)),
459 Some(Constant
::F64(x
)) => Some(Constant
::F64(*x
)),
470 /// A block can only yield a constant if it only has one constant expression.
471 fn block(&mut self, block
: &Block
<'_
>) -> Option
<Constant
> {
472 if block
.stmts
.is_empty() {
473 block
.expr
.as_ref().and_then(|b
| self.expr(b
))
479 fn ifthenelse(&mut self, cond
: &Expr
<'_
>, then
: &Expr
<'_
>, otherwise
: Option
<&Expr
<'_
>>) -> Option
<Constant
> {
480 if let Some(Constant
::Bool(b
)) = self.expr(cond
) {
484 otherwise
.as_ref().and_then(|expr
| self.expr(expr
))
491 fn binop(&mut self, op
: BinOp
, left
: &Expr
<'_
>, right
: &Expr
<'_
>) -> Option
<Constant
> {
492 let l
= self.expr(left
)?
;
493 let r
= self.expr(right
);
495 (Constant
::Int(l
), Some(Constant
::Int(r
))) => match *self.typeck_results
.expr_ty_opt(left
)?
.kind() {
497 let l
= sext(self.lcx
.tcx
, l
, ity
);
498 let r
= sext(self.lcx
.tcx
, r
, ity
);
499 let zext
= |n
: i128
| Constant
::Int(unsext(self.lcx
.tcx
, n
, ity
));
501 BinOpKind
::Add
=> l
.checked_add(r
).map(zext
),
502 BinOpKind
::Sub
=> l
.checked_sub(r
).map(zext
),
503 BinOpKind
::Mul
=> l
.checked_mul(r
).map(zext
),
504 BinOpKind
::Div
if r
!= 0 => l
.checked_div(r
).map(zext
),
505 BinOpKind
::Rem
if r
!= 0 => l
.checked_rem(r
).map(zext
),
506 BinOpKind
::Shr
=> l
.checked_shr(r
.try_into().expect("invalid shift")).map(zext
),
507 BinOpKind
::Shl
=> l
.checked_shl(r
.try_into().expect("invalid shift")).map(zext
),
508 BinOpKind
::BitXor
=> Some(zext(l ^ r
)),
509 BinOpKind
::BitOr
=> Some(zext(l
| r
)),
510 BinOpKind
::BitAnd
=> Some(zext(l
& r
)),
511 BinOpKind
::Eq
=> Some(Constant
::Bool(l
== r
)),
512 BinOpKind
::Ne
=> Some(Constant
::Bool(l
!= r
)),
513 BinOpKind
::Lt
=> Some(Constant
::Bool(l
< r
)),
514 BinOpKind
::Le
=> Some(Constant
::Bool(l
<= r
)),
515 BinOpKind
::Ge
=> Some(Constant
::Bool(l
>= r
)),
516 BinOpKind
::Gt
=> Some(Constant
::Bool(l
> r
)),
520 ty
::Uint(_
) => match op
.node
{
521 BinOpKind
::Add
=> l
.checked_add(r
).map(Constant
::Int
),
522 BinOpKind
::Sub
=> l
.checked_sub(r
).map(Constant
::Int
),
523 BinOpKind
::Mul
=> l
.checked_mul(r
).map(Constant
::Int
),
524 BinOpKind
::Div
=> l
.checked_div(r
).map(Constant
::Int
),
525 BinOpKind
::Rem
=> l
.checked_rem(r
).map(Constant
::Int
),
526 BinOpKind
::Shr
=> l
.checked_shr(r
.try_into().expect("shift too large")).map(Constant
::Int
),
527 BinOpKind
::Shl
=> l
.checked_shl(r
.try_into().expect("shift too large")).map(Constant
::Int
),
528 BinOpKind
::BitXor
=> Some(Constant
::Int(l ^ r
)),
529 BinOpKind
::BitOr
=> Some(Constant
::Int(l
| r
)),
530 BinOpKind
::BitAnd
=> Some(Constant
::Int(l
& r
)),
531 BinOpKind
::Eq
=> Some(Constant
::Bool(l
== r
)),
532 BinOpKind
::Ne
=> Some(Constant
::Bool(l
!= r
)),
533 BinOpKind
::Lt
=> Some(Constant
::Bool(l
< r
)),
534 BinOpKind
::Le
=> Some(Constant
::Bool(l
<= r
)),
535 BinOpKind
::Ge
=> Some(Constant
::Bool(l
>= r
)),
536 BinOpKind
::Gt
=> Some(Constant
::Bool(l
> r
)),
541 (Constant
::F32(l
), Some(Constant
::F32(r
))) => match op
.node
{
542 BinOpKind
::Add
=> Some(Constant
::F32(l
+ r
)),
543 BinOpKind
::Sub
=> Some(Constant
::F32(l
- r
)),
544 BinOpKind
::Mul
=> Some(Constant
::F32(l
* r
)),
545 BinOpKind
::Div
=> Some(Constant
::F32(l
/ r
)),
546 BinOpKind
::Rem
=> Some(Constant
::F32(l
% r
)),
547 BinOpKind
::Eq
=> Some(Constant
::Bool(l
== r
)),
548 BinOpKind
::Ne
=> Some(Constant
::Bool(l
!= r
)),
549 BinOpKind
::Lt
=> Some(Constant
::Bool(l
< r
)),
550 BinOpKind
::Le
=> Some(Constant
::Bool(l
<= r
)),
551 BinOpKind
::Ge
=> Some(Constant
::Bool(l
>= r
)),
552 BinOpKind
::Gt
=> Some(Constant
::Bool(l
> r
)),
555 (Constant
::F64(l
), Some(Constant
::F64(r
))) => match op
.node
{
556 BinOpKind
::Add
=> Some(Constant
::F64(l
+ r
)),
557 BinOpKind
::Sub
=> Some(Constant
::F64(l
- r
)),
558 BinOpKind
::Mul
=> Some(Constant
::F64(l
* r
)),
559 BinOpKind
::Div
=> Some(Constant
::F64(l
/ r
)),
560 BinOpKind
::Rem
=> Some(Constant
::F64(l
% r
)),
561 BinOpKind
::Eq
=> Some(Constant
::Bool(l
== r
)),
562 BinOpKind
::Ne
=> Some(Constant
::Bool(l
!= r
)),
563 BinOpKind
::Lt
=> Some(Constant
::Bool(l
< r
)),
564 BinOpKind
::Le
=> Some(Constant
::Bool(l
<= r
)),
565 BinOpKind
::Ge
=> Some(Constant
::Bool(l
>= r
)),
566 BinOpKind
::Gt
=> Some(Constant
::Bool(l
> r
)),
569 (l
, r
) => match (op
.node
, l
, r
) {
570 (BinOpKind
::And
, Constant
::Bool(false), _
) => Some(Constant
::Bool(false)),
571 (BinOpKind
::Or
, Constant
::Bool(true), _
) => Some(Constant
::Bool(true)),
572 (BinOpKind
::And
, Constant
::Bool(true), Some(r
)) | (BinOpKind
::Or
, Constant
::Bool(false), Some(r
)) => {
575 (BinOpKind
::BitXor
, Constant
::Bool(l
), Some(Constant
::Bool(r
))) => Some(Constant
::Bool(l ^ r
)),
576 (BinOpKind
::BitAnd
, Constant
::Bool(l
), Some(Constant
::Bool(r
))) => Some(Constant
::Bool(l
& r
)),
577 (BinOpKind
::BitOr
, Constant
::Bool(l
), Some(Constant
::Bool(r
))) => Some(Constant
::Bool(l
| r
)),
584 pub fn miri_to_const
<'tcx
>(tcx
: TyCtxt
<'tcx
>, result
: mir
::ConstantKind
<'tcx
>) -> Option
<Constant
> {
585 use rustc_middle
::mir
::interpret
::ConstValue
;
587 mir
::ConstantKind
::Val(ConstValue
::Scalar(Scalar
::Int(int
)), _
) => {
588 match result
.ty().kind() {
589 ty
::Bool
=> Some(Constant
::Bool(int
== ScalarInt
::TRUE
)),
590 ty
::Uint(_
) | ty
::Int(_
) => Some(Constant
::Int(int
.assert_bits(int
.size()))),
591 ty
::Float(FloatTy
::F32
) => Some(Constant
::F32(f32::from_bits(
592 int
.try_into().expect("invalid f32 bit representation"),
594 ty
::Float(FloatTy
::F64
) => Some(Constant
::F64(f64::from_bits(
595 int
.try_into().expect("invalid f64 bit representation"),
597 ty
::RawPtr(type_and_mut
) => {
598 if let ty
::Uint(_
) = type_and_mut
.ty
.kind() {
599 return Some(Constant
::RawPtr(int
.assert_bits(int
.size())));
603 // FIXME: implement other conversions.
607 mir
::ConstantKind
::Val(ConstValue
::Slice { data, start, end }
, _
) => match result
.ty().kind() {
608 ty
::Ref(_
, tam
, _
) => match tam
.kind() {
609 ty
::Str
=> String
::from_utf8(
611 .inspect_with_uninit_and_ptr_outside_interpreter(start
..end
)
620 mir
::ConstantKind
::Val(ConstValue
::ByRef { alloc, offset: _ }
, _
) => match result
.ty().kind() {
621 ty
::Array(sub_type
, len
) => match sub_type
.kind() {
622 ty
::Float(FloatTy
::F32
) => match len
.kind().try_to_machine_usize(tcx
) {
625 .inspect_with_uninit_and_ptr_outside_interpreter(0..(4 * usize::try_from(len
).unwrap()))
628 .map(|&chunk
| Some(Constant
::F32(f32::from_le_bytes(chunk
))))
629 .collect
::<Option
<Vec
<Constant
>>>()
633 ty
::Float(FloatTy
::F64
) => match len
.kind().try_to_machine_usize(tcx
) {
636 .inspect_with_uninit_and_ptr_outside_interpreter(0..(8 * usize::try_from(len
).unwrap()))
639 .map(|&chunk
| Some(Constant
::F64(f64::from_le_bytes(chunk
))))
640 .collect
::<Option
<Vec
<Constant
>>>()
644 // FIXME: implement other array type conversions.
649 // FIXME: implement other conversions.