2 use rustc_middle
::mir
::interpret
::{
3 truncate
, Allocation
, ConstValue
, LitToConstError
, LitToConstInput
, Scalar
,
5 use rustc_middle
::ty
::{self, ParamEnv, TyCtxt}
;
6 use rustc_span
::symbol
::Symbol
;
7 use rustc_target
::abi
::Size
;
9 crate fn lit_to_const
<'tcx
>(
11 lit_input
: LitToConstInput
<'tcx
>,
12 ) -> Result
<&'tcx ty
::Const
<'tcx
>, LitToConstError
> {
13 let LitToConstInput { lit, ty, neg }
= lit_input
;
16 let param_ty
= ParamEnv
::reveal_all().and(ty
);
17 let width
= tcx
.layout_of(param_ty
).map_err(|_
| LitToConstError
::Reported
)?
.size
;
18 trace
!("trunc {} with size {} and shift {}", n
, width
.bits(), 128 - width
.bits());
19 let result
= truncate(n
, width
);
20 trace
!("trunc result: {}", result
);
21 Ok(ConstValue
::Scalar(Scalar
::from_uint(result
, width
)))
24 let lit
= match (lit
, &ty
.kind()) {
25 (ast
::LitKind
::Str(s
, _
), ty
::Ref(_
, inner_ty
, _
)) if inner_ty
.is_str() => {
27 let allocation
= Allocation
::from_byte_aligned_bytes(s
.as_bytes());
28 let allocation
= tcx
.intern_const_alloc(allocation
);
29 ConstValue
::Slice { data: allocation, start: 0, end: s.len() }
31 (ast
::LitKind
::ByteStr(data
), ty
::Ref(_
, inner_ty
, _
))
32 if matches
!(inner_ty
.kind(), ty
::Slice(_
)) =>
34 let allocation
= Allocation
::from_byte_aligned_bytes(data
as &Vec
<u8>);
35 let allocation
= tcx
.intern_const_alloc(allocation
);
36 ConstValue
::Slice { data: allocation, start: 0, end: data.len() }
38 (ast
::LitKind
::ByteStr(data
), ty
::Ref(_
, inner_ty
, _
)) if inner_ty
.is_array() => {
39 let id
= tcx
.allocate_bytes(data
);
40 ConstValue
::Scalar(Scalar
::Ptr(id
.into()))
42 (ast
::LitKind
::Byte(n
), ty
::Uint(ast
::UintTy
::U8
)) => {
43 ConstValue
::Scalar(Scalar
::from_uint(*n
, Size
::from_bytes(1)))
45 (ast
::LitKind
::Int(n
, _
), ty
::Uint(_
)) | (ast
::LitKind
::Int(n
, _
), ty
::Int(_
)) => {
46 trunc(if neg { (*n as i128).overflowing_neg().0 as u128 }
else { *n }
)?
48 (ast
::LitKind
::Float(n
, _
), ty
::Float(fty
)) => {
49 parse_float(*n
, *fty
, neg
).map_err(|_
| LitToConstError
::UnparseableFloat
)?
51 (ast
::LitKind
::Bool(b
), ty
::Bool
) => ConstValue
::Scalar(Scalar
::from_bool(*b
)),
52 (ast
::LitKind
::Char(c
), ty
::Char
) => ConstValue
::Scalar(Scalar
::from_char(*c
)),
53 (ast
::LitKind
::Err(_
), _
) => return Err(LitToConstError
::Reported
),
54 _
=> return Err(LitToConstError
::TypeError
),
56 Ok(ty
::Const
::from_value(tcx
, lit
, ty
))
59 fn parse_float
<'tcx
>(num
: Symbol
, fty
: ast
::FloatTy
, neg
: bool
) -> Result
<ConstValue
<'tcx
>, ()> {
60 let num
= num
.as_str();
61 use rustc_apfloat
::ieee
::{Double, Single}
;
62 let scalar
= match fty
{
63 ast
::FloatTy
::F32
=> {
64 num
.parse
::<f32>().map_err(|_
| ())?
;
65 let mut f
= num
.parse
::<Single
>().unwrap_or_else(|e
| {
66 panic
!("apfloat::ieee::Single failed to parse `{}`: {:?}", num
, e
)
73 ast
::FloatTy
::F64
=> {
74 num
.parse
::<f64>().map_err(|_
| ())?
;
75 let mut f
= num
.parse
::<Double
>().unwrap_or_else(|e
| {
76 panic
!("apfloat::ieee::Double failed to parse `{}`: {:?}", num
, e
)
85 Ok(ConstValue
::Scalar(scalar
))