1 use rustc_apfloat
::Float
;
3 use rustc_middle
::mir
::interpret
::{
4 Allocation
, ConstValue
, LitToConstError
, LitToConstInput
, Scalar
,
6 use rustc_middle
::ty
::{self, ParamEnv, TyCtxt}
;
7 use rustc_span
::symbol
::Symbol
;
8 use rustc_target
::abi
::Size
;
10 crate fn lit_to_const
<'tcx
>(
12 lit_input
: LitToConstInput
<'tcx
>,
13 ) -> Result
<&'tcx ty
::Const
<'tcx
>, LitToConstError
> {
14 let LitToConstInput { lit, ty, neg }
= lit_input
;
17 let param_ty
= ParamEnv
::reveal_all().and(ty
);
18 let width
= tcx
.layout_of(param_ty
).map_err(|_
| LitToConstError
::Reported
)?
.size
;
19 trace
!("trunc {} with size {} and shift {}", n
, width
.bits(), 128 - width
.bits());
20 let result
= width
.truncate(n
);
21 trace
!("trunc result: {}", result
);
22 Ok(ConstValue
::Scalar(Scalar
::from_uint(result
, width
)))
25 let lit
= match (lit
, &ty
.kind()) {
26 (ast
::LitKind
::Str(s
, _
), ty
::Ref(_
, inner_ty
, _
)) if inner_ty
.is_str() => {
28 let allocation
= Allocation
::from_bytes_byte_aligned_immutable(s
.as_bytes());
29 let allocation
= tcx
.intern_const_alloc(allocation
);
30 ConstValue
::Slice { data: allocation, start: 0, end: s.len() }
32 (ast
::LitKind
::ByteStr(data
), ty
::Ref(_
, inner_ty
, _
))
33 if matches
!(inner_ty
.kind(), ty
::Slice(_
)) =>
35 let allocation
= Allocation
::from_bytes_byte_aligned_immutable(data
as &[u8]);
36 let allocation
= tcx
.intern_const_alloc(allocation
);
37 ConstValue
::Slice { data: allocation, start: 0, end: data.len() }
39 (ast
::LitKind
::ByteStr(data
), ty
::Ref(_
, inner_ty
, _
)) if inner_ty
.is_array() => {
40 let id
= tcx
.allocate_bytes(data
);
41 ConstValue
::Scalar(Scalar
::from_pointer(id
.into(), &tcx
))
43 (ast
::LitKind
::Byte(n
), ty
::Uint(ty
::UintTy
::U8
)) => {
44 ConstValue
::Scalar(Scalar
::from_uint(*n
, Size
::from_bytes(1)))
46 (ast
::LitKind
::Int(n
, _
), ty
::Uint(_
)) | (ast
::LitKind
::Int(n
, _
), ty
::Int(_
)) => {
47 trunc(if neg { (*n as i128).overflowing_neg().0 as u128 }
else { *n }
)?
49 (ast
::LitKind
::Float(n
, _
), ty
::Float(fty
)) => parse_float(*n
, *fty
, neg
),
50 (ast
::LitKind
::Bool(b
), ty
::Bool
) => ConstValue
::Scalar(Scalar
::from_bool(*b
)),
51 (ast
::LitKind
::Char(c
), ty
::Char
) => ConstValue
::Scalar(Scalar
::from_char(*c
)),
52 (ast
::LitKind
::Err(_
), _
) => return Err(LitToConstError
::Reported
),
53 _
=> return Err(LitToConstError
::TypeError
),
55 Ok(ty
::Const
::from_value(tcx
, lit
, ty
))
58 fn parse_float
<'tcx
>(num
: Symbol
, fty
: ty
::FloatTy
, neg
: bool
) -> ConstValue
<'tcx
> {
59 let num
= num
.as_str();
60 use rustc_apfloat
::ieee
::{Double, Single}
;
61 let scalar
= match fty
{
65 .unwrap_or_else(|e
| panic
!("f32 failed to parse `{}`: {:?}", num
, e
));
66 let mut f
= num
.parse
::<Single
>().unwrap_or_else(|e
| {
67 panic
!("apfloat::ieee::Single failed to parse `{}`: {:?}", num
, e
)
70 u128
::from(rust_f
.to_bits()) == f
.to_bits(),
71 "apfloat::ieee::Single gave different result for `{}`: \
72 {}({:#x}) vs Rust's {}({:#x})",
76 Single
::from_bits(rust_f
.to_bits().into()),
87 .unwrap_or_else(|e
| panic
!("f64 failed to parse `{}`: {:?}", num
, e
));
88 let mut f
= num
.parse
::<Double
>().unwrap_or_else(|e
| {
89 panic
!("apfloat::ieee::Double failed to parse `{}`: {:?}", num
, e
)
92 u128
::from(rust_f
.to_bits()) == f
.to_bits(),
93 "apfloat::ieee::Double gave different result for `{}`: \
94 {}({:#x}) vs Rust's {}({:#x})",
98 Double
::from_bits(rust_f
.to_bits().into()),
108 ConstValue
::Scalar(scalar
)