]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_mir_build/src/thir/constant.rs
Rollup merge of #103445 - fmease:fix-50291, r=estebank
[rust.git] / compiler / rustc_mir_build / src / thir / constant.rs
1 use rustc_ast as ast;
2 use rustc_middle::mir::interpret::{LitToConstError, LitToConstInput};
3 use rustc_middle::ty::{self, ParamEnv, ScalarInt, TyCtxt};
4 use rustc_span::DUMMY_SP;
5
6 pub(crate) fn lit_to_const<'tcx>(
7     tcx: TyCtxt<'tcx>,
8     lit_input: LitToConstInput<'tcx>,
9 ) -> Result<ty::Const<'tcx>, LitToConstError> {
10     let LitToConstInput { lit, ty, neg } = lit_input;
11
12     let trunc = |n| {
13         let param_ty = ParamEnv::reveal_all().and(ty);
14         let width = tcx
15             .layout_of(param_ty)
16             .map_err(|_| {
17                 LitToConstError::Reported(tcx.sess.delay_span_bug(
18                     DUMMY_SP,
19                     format!("couldn't compute width of literal: {:?}", lit_input.lit),
20                 ))
21             })?
22             .size;
23         trace!("trunc {} with size {} and shift {}", n, width.bits(), 128 - width.bits());
24         let result = width.truncate(n);
25         trace!("trunc result: {}", result);
26
27         Ok(ScalarInt::try_from_uint(result, width)
28             .unwrap_or_else(|| bug!("expected to create ScalarInt from uint {:?}", result)))
29     };
30
31     let valtree = match (lit, &ty.kind()) {
32         (ast::LitKind::Str(s, _), ty::Ref(_, inner_ty, _)) if inner_ty.is_str() => {
33             let str_bytes = s.as_str().as_bytes();
34             ty::ValTree::from_raw_bytes(tcx, str_bytes)
35         }
36         (ast::LitKind::ByteStr(data), ty::Ref(_, inner_ty, _))
37             if matches!(inner_ty.kind(), ty::Slice(_)) =>
38         {
39             let bytes = data as &[u8];
40             ty::ValTree::from_raw_bytes(tcx, bytes)
41         }
42         (ast::LitKind::ByteStr(data), ty::Ref(_, inner_ty, _)) if inner_ty.is_array() => {
43             let bytes = data as &[u8];
44             ty::ValTree::from_raw_bytes(tcx, bytes)
45         }
46         (ast::LitKind::Byte(n), ty::Uint(ty::UintTy::U8)) => {
47             ty::ValTree::from_scalar_int((*n).into())
48         }
49         (ast::LitKind::Int(n, _), ty::Uint(_)) | (ast::LitKind::Int(n, _), ty::Int(_)) => {
50             let scalar_int =
51                 trunc(if neg { (*n as i128).overflowing_neg().0 as u128 } else { *n })?;
52             ty::ValTree::from_scalar_int(scalar_int)
53         }
54         (ast::LitKind::Bool(b), ty::Bool) => ty::ValTree::from_scalar_int((*b).into()),
55         (ast::LitKind::Char(c), ty::Char) => ty::ValTree::from_scalar_int((*c).into()),
56         (ast::LitKind::Err, _) => {
57             return Err(LitToConstError::Reported(
58                 tcx.sess.delay_span_bug(DUMMY_SP, "encountered LitKind::Err during mir build"),
59             ));
60         }
61         _ => return Err(LitToConstError::TypeError),
62     };
63
64     Ok(ty::Const::from_value(tcx, valtree, ty))
65 }