]> git.proxmox.com Git - rustc.git/blob - compiler/rustc_mir_build/src/thir/constant.rs
New upstream version 1.76.0+dfsg1
[rustc.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 use crate::build::parse_float_into_scalar;
7
8 pub(crate) fn lit_to_const<'tcx>(
9 tcx: TyCtxt<'tcx>,
10 lit_input: LitToConstInput<'tcx>,
11 ) -> Result<ty::Const<'tcx>, LitToConstError> {
12 let LitToConstInput { lit, ty, neg } = lit_input;
13
14 let trunc = |n| {
15 let param_ty = ParamEnv::reveal_all().and(ty);
16 let width = tcx
17 .layout_of(param_ty)
18 .map_err(|_| {
19 LitToConstError::Reported(tcx.sess.span_delayed_bug(
20 DUMMY_SP,
21 format!("couldn't compute width of literal: {:?}", lit_input.lit),
22 ))
23 })?
24 .size;
25 trace!("trunc {} with size {} and shift {}", n, width.bits(), 128 - width.bits());
26 let result = width.truncate(n);
27 trace!("trunc result: {}", result);
28
29 Ok(ScalarInt::try_from_uint(result, width)
30 .unwrap_or_else(|| bug!("expected to create ScalarInt from uint {:?}", result)))
31 };
32
33 let valtree = match (lit, &ty.kind()) {
34 (ast::LitKind::Str(s, _), ty::Ref(_, inner_ty, _)) if inner_ty.is_str() => {
35 let str_bytes = s.as_str().as_bytes();
36 ty::ValTree::from_raw_bytes(tcx, str_bytes)
37 }
38 (ast::LitKind::ByteStr(data, _), ty::Ref(_, inner_ty, _))
39 if matches!(inner_ty.kind(), ty::Slice(_)) =>
40 {
41 let bytes = data as &[u8];
42 ty::ValTree::from_raw_bytes(tcx, bytes)
43 }
44 (ast::LitKind::ByteStr(data, _), ty::Ref(_, inner_ty, _)) if inner_ty.is_array() => {
45 let bytes = data as &[u8];
46 ty::ValTree::from_raw_bytes(tcx, bytes)
47 }
48 (ast::LitKind::Byte(n), ty::Uint(ty::UintTy::U8)) => {
49 ty::ValTree::from_scalar_int((*n).into())
50 }
51 (ast::LitKind::CStr(data, _), ty::Ref(_, inner_ty, _)) if matches!(inner_ty.kind(), ty::Adt(def, _) if Some(def.did()) == tcx.lang_items().c_str()) =>
52 {
53 let bytes = data as &[u8];
54 ty::ValTree::from_raw_bytes(tcx, bytes)
55 }
56 (ast::LitKind::Int(n, _), ty::Uint(_)) | (ast::LitKind::Int(n, _), ty::Int(_)) => {
57 let scalar_int =
58 trunc(if neg { (*n as i128).overflowing_neg().0 as u128 } else { *n })?;
59 ty::ValTree::from_scalar_int(scalar_int)
60 }
61 (ast::LitKind::Bool(b), ty::Bool) => ty::ValTree::from_scalar_int((*b).into()),
62 (ast::LitKind::Float(n, _), ty::Float(fty)) => {
63 let bits = parse_float_into_scalar(*n, *fty, neg)
64 .ok_or_else(|| {
65 LitToConstError::Reported(tcx.sess.span_delayed_bug(
66 DUMMY_SP,
67 format!("couldn't parse float literal: {:?}", lit_input.lit),
68 ))
69 })?
70 .assert_int();
71 ty::ValTree::from_scalar_int(bits)
72 }
73 (ast::LitKind::Char(c), ty::Char) => ty::ValTree::from_scalar_int((*c).into()),
74 (ast::LitKind::Err, _) => {
75 return Err(LitToConstError::Reported(
76 tcx.sess.span_delayed_bug(DUMMY_SP, "encountered LitKind::Err during mir build"),
77 ));
78 }
79 _ => return Err(LitToConstError::TypeError),
80 };
81
82 Ok(ty::Const::new_value(tcx, valtree, ty))
83 }