rustc_mir_build/thir/
constant.rs
1use rustc_abi::Size;
2use rustc_ast::{self as ast};
3use rustc_hir::LangItem;
4use rustc_middle::bug;
5use rustc_middle::mir::interpret::LitToConstInput;
6use rustc_middle::ty::{self, ScalarInt, TyCtxt, TypeVisitableExt as _};
7use tracing::trace;
8
9use crate::builder::parse_float_into_scalar;
10
11pub(crate) fn lit_to_const<'tcx>(
12 tcx: TyCtxt<'tcx>,
13 lit_input: LitToConstInput<'tcx>,
14) -> ty::Const<'tcx> {
15 let LitToConstInput { lit, ty, neg } = lit_input;
16
17 if let Err(guar) = ty.error_reported() {
18 return ty::Const::new_error(tcx, guar);
19 }
20
21 let trunc = |n, width: ty::UintTy| {
22 let width = width
23 .normalize(tcx.data_layout.pointer_size.bits().try_into().unwrap())
24 .bit_width()
25 .unwrap();
26 let width = Size::from_bits(width);
27 trace!("trunc {} with size {} and shift {}", n, width.bits(), 128 - width.bits());
28 let result = width.truncate(n);
29 trace!("trunc result: {}", result);
30
31 ScalarInt::try_from_uint(result, width)
32 .unwrap_or_else(|| bug!("expected to create ScalarInt from uint {:?}", result))
33 };
34
35 let valtree = match (lit, ty.kind()) {
36 (ast::LitKind::Str(s, _), ty::Ref(_, inner_ty, _)) if inner_ty.is_str() => {
37 let str_bytes = s.as_str().as_bytes();
38 ty::ValTree::from_raw_bytes(tcx, str_bytes)
39 }
40 (ast::LitKind::ByteStr(data, _), ty::Ref(_, inner_ty, _))
41 if matches!(inner_ty.kind(), ty::Slice(_)) =>
42 {
43 let bytes = data as &[u8];
44 ty::ValTree::from_raw_bytes(tcx, bytes)
45 }
46 (ast::LitKind::ByteStr(data, _), ty::Ref(_, inner_ty, _)) if inner_ty.is_array() => {
47 let bytes = data as &[u8];
48 ty::ValTree::from_raw_bytes(tcx, bytes)
49 }
50 (ast::LitKind::Byte(n), ty::Uint(ty::UintTy::U8)) => {
51 ty::ValTree::from_scalar_int(tcx, (*n).into())
52 }
53 (ast::LitKind::CStr(data, _), ty::Ref(_, inner_ty, _)) if matches!(inner_ty.kind(), ty::Adt(def, _) if tcx.is_lang_item(def.did(), LangItem::CStr)) =>
54 {
55 let bytes = data as &[u8];
56 ty::ValTree::from_raw_bytes(tcx, bytes)
57 }
58 (ast::LitKind::Int(n, _), ty::Uint(ui)) if !neg => {
59 let scalar_int = trunc(n.get(), *ui);
60 ty::ValTree::from_scalar_int(tcx, scalar_int)
61 }
62 (ast::LitKind::Int(n, _), ty::Int(i)) => {
63 let scalar_int = trunc(
64 if neg { (n.get() as i128).overflowing_neg().0 as u128 } else { n.get() },
65 i.to_unsigned(),
66 );
67 ty::ValTree::from_scalar_int(tcx, scalar_int)
68 }
69 (ast::LitKind::Bool(b), ty::Bool) => ty::ValTree::from_scalar_int(tcx, (*b).into()),
70 (ast::LitKind::Float(n, _), ty::Float(fty)) => {
71 let bits = parse_float_into_scalar(*n, *fty, neg).unwrap_or_else(|| {
72 tcx.dcx().bug(format!("couldn't parse float literal: {:?}", lit_input.lit))
73 });
74 ty::ValTree::from_scalar_int(tcx, bits)
75 }
76 (ast::LitKind::Char(c), ty::Char) => ty::ValTree::from_scalar_int(tcx, (*c).into()),
77 (ast::LitKind::Err(guar), _) => return ty::Const::new_error(tcx, *guar),
78 _ => return ty::Const::new_misc_error(tcx),
79 };
80
81 ty::Const::new_value(tcx, valtree, ty)
82}