Skip to main content

rustc_mir_build/thir/
constant.rs

1use rustc_abi::Size;
2use rustc_ast::{self as ast, UintTy};
3use rustc_hir::LangItem;
4use rustc_middle::bug;
5use rustc_middle::ty::{self, LitToConstInput, ScalarInt, Ty, TyCtxt, TypeVisitableExt as _};
6use tracing::trace;
7
8use crate::builder::parse_float_into_scalar;
9
10pub(crate) fn lit_to_const<'tcx>(
11    tcx: TyCtxt<'tcx>,
12    lit_input: LitToConstInput<'tcx>,
13) -> Option<ty::Value<'tcx>> {
14    let LitToConstInput { lit, ty: expected_ty, neg } = lit_input;
15
16    if expected_ty.error_reported().is_err() {
17        return None;
18    }
19
20    let trunc = |n, width: ty::UintTy| {
21        let width = width
22            .normalize(tcx.data_layout.pointer_size().bits().try_into().unwrap())
23            .bit_width()
24            .unwrap();
25        let width = Size::from_bits(width);
26        {
    use ::tracing::__macro_support::Callsite as _;
    static __CALLSITE: ::tracing::callsite::DefaultCallsite =
        {
            static META: ::tracing::Metadata<'static> =
                {
                    ::tracing_core::metadata::Metadata::new("event compiler/rustc_mir_build/src/thir/constant.rs:26",
                        "rustc_mir_build::thir::constant", ::tracing::Level::TRACE,
                        ::tracing_core::__macro_support::Option::Some("compiler/rustc_mir_build/src/thir/constant.rs"),
                        ::tracing_core::__macro_support::Option::Some(26u32),
                        ::tracing_core::__macro_support::Option::Some("rustc_mir_build::thir::constant"),
                        ::tracing_core::field::FieldSet::new(&["message"],
                            ::tracing_core::callsite::Identifier(&__CALLSITE)),
                        ::tracing::metadata::Kind::EVENT)
                };
            ::tracing::callsite::DefaultCallsite::new(&META)
        };
    let enabled =
        ::tracing::Level::TRACE <= ::tracing::level_filters::STATIC_MAX_LEVEL
                &&
                ::tracing::Level::TRACE <=
                    ::tracing::level_filters::LevelFilter::current() &&
            {
                let interest = __CALLSITE.interest();
                !interest.is_never() &&
                    ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                        interest)
            };
    if enabled {
        (|value_set: ::tracing::field::ValueSet|
                    {
                        let meta = __CALLSITE.metadata();
                        ::tracing::Event::dispatch(meta, &value_set);
                        ;
                    })({
                #[allow(unused_imports)]
                use ::tracing::field::{debug, display, Value};
                let mut iter = __CALLSITE.metadata().fields().iter();
                __CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                    ::tracing::__macro_support::Option::Some(&format_args!("trunc {0} with size {1} and shift {2}",
                                                    n, width.bits(), 128 - width.bits()) as &dyn Value))])
            });
    } else { ; }
};trace!("trunc {} with size {} and shift {}", n, width.bits(), 128 - width.bits());
27        let result = width.truncate(n);
28        {
    use ::tracing::__macro_support::Callsite as _;
    static __CALLSITE: ::tracing::callsite::DefaultCallsite =
        {
            static META: ::tracing::Metadata<'static> =
                {
                    ::tracing_core::metadata::Metadata::new("event compiler/rustc_mir_build/src/thir/constant.rs:28",
                        "rustc_mir_build::thir::constant", ::tracing::Level::TRACE,
                        ::tracing_core::__macro_support::Option::Some("compiler/rustc_mir_build/src/thir/constant.rs"),
                        ::tracing_core::__macro_support::Option::Some(28u32),
                        ::tracing_core::__macro_support::Option::Some("rustc_mir_build::thir::constant"),
                        ::tracing_core::field::FieldSet::new(&["message"],
                            ::tracing_core::callsite::Identifier(&__CALLSITE)),
                        ::tracing::metadata::Kind::EVENT)
                };
            ::tracing::callsite::DefaultCallsite::new(&META)
        };
    let enabled =
        ::tracing::Level::TRACE <= ::tracing::level_filters::STATIC_MAX_LEVEL
                &&
                ::tracing::Level::TRACE <=
                    ::tracing::level_filters::LevelFilter::current() &&
            {
                let interest = __CALLSITE.interest();
                !interest.is_never() &&
                    ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                        interest)
            };
    if enabled {
        (|value_set: ::tracing::field::ValueSet|
                    {
                        let meta = __CALLSITE.metadata();
                        ::tracing::Event::dispatch(meta, &value_set);
                        ;
                    })({
                #[allow(unused_imports)]
                use ::tracing::field::{debug, display, Value};
                let mut iter = __CALLSITE.metadata().fields().iter();
                __CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                    ::tracing::__macro_support::Option::Some(&format_args!("trunc result: {0}",
                                                    result) as &dyn Value))])
            });
    } else { ; }
};trace!("trunc result: {}", result);
29
30        ScalarInt::try_from_uint(result, width)
31            .unwrap_or_else(|| ::rustc_middle::util::bug::bug_fmt(format_args!("expected to create ScalarInt from uint {0:?}",
        result))bug!("expected to create ScalarInt from uint {:?}", result))
32    };
33
34    let (valtree, valtree_ty) = match (lit, expected_ty.kind()) {
35        (ast::LitKind::Str(s, _), _) => {
36            let str_bytes = s.as_str().as_bytes();
37            let valtree_ty = Ty::new_imm_ref(tcx, tcx.lifetimes.re_static, tcx.types.str_);
38            (ty::ValTree::from_raw_bytes(tcx, str_bytes), valtree_ty)
39        }
40        (ast::LitKind::ByteStr(byte_sym, _), ty::Ref(_, inner_ty, _))
41            if let ty::Slice(ty) | ty::Array(ty, _) = inner_ty.kind()
42                && let ty::Uint(UintTy::U8) = ty.kind() =>
43        {
44            (ty::ValTree::from_raw_bytes(tcx, byte_sym.as_byte_str()), expected_ty)
45        }
46        (ast::LitKind::ByteStr(byte_sym, _), ty::Slice(inner_ty) | ty::Array(inner_ty, _))
47            if tcx.features().deref_patterns()
48                && let ty::Uint(UintTy::U8) = inner_ty.kind() =>
49        {
50            // Byte string literal patterns may have type `[u8]` or `[u8; N]` if `deref_patterns` is
51            // enabled, in order to allow, e.g., `deref!(b"..."): Vec<u8>`.
52            (ty::ValTree::from_raw_bytes(tcx, byte_sym.as_byte_str()), expected_ty)
53        }
54        (ast::LitKind::ByteStr(byte_sym, _), _) => {
55            let valtree = ty::ValTree::from_raw_bytes(tcx, byte_sym.as_byte_str());
56            let valtree_ty = Ty::new_array(tcx, tcx.types.u8, byte_sym.as_byte_str().len() as u64);
57            (valtree, valtree_ty)
58        }
59        (ast::LitKind::Byte(n), _) => (ty::ValTree::from_scalar_int(tcx, n.into()), tcx.types.u8),
60        (ast::LitKind::CStr(byte_sym, _), _)
61            if let Some(cstr_def_id) = tcx.lang_items().get(LangItem::CStr) =>
62        {
63            // A CStr is a newtype around a byte slice, so we create the inner slice here.
64            // We need a branch for each "level" of the data structure.
65            let cstr_ty = tcx.type_of(cstr_def_id).skip_binder();
66            let bytes = ty::ValTree::from_raw_bytes(tcx, byte_sym.as_byte_str());
67            let valtree =
68                ty::ValTree::from_branches(tcx, [ty::Const::new_value(tcx, bytes, cstr_ty)]);
69            let valtree_ty = Ty::new_imm_ref(tcx, tcx.lifetimes.re_static, cstr_ty);
70            (valtree, valtree_ty)
71        }
72        (ast::LitKind::Int(n, ast::LitIntType::Unsigned(ui)), _) if !neg => {
73            let scalar_int = trunc(n.get(), ui);
74            (ty::ValTree::from_scalar_int(tcx, scalar_int), Ty::new_uint(tcx, ui))
75        }
76        (ast::LitKind::Int(_, ast::LitIntType::Unsigned(_)), _) if neg => return None,
77        (ast::LitKind::Int(n, ast::LitIntType::Signed(i)), _) => {
78            let scalar_int =
79                trunc(if neg { u128::wrapping_neg(n.get()) } else { n.get() }, i.to_unsigned());
80            (ty::ValTree::from_scalar_int(tcx, scalar_int), Ty::new_int(tcx, i))
81        }
82        (ast::LitKind::Int(n, ast::LitIntType::Unsuffixed), ty::Uint(ui)) if !neg => {
83            let scalar_int = trunc(n.get(), *ui);
84            (ty::ValTree::from_scalar_int(tcx, scalar_int), Ty::new_uint(tcx, *ui))
85        }
86        (ast::LitKind::Int(n, ast::LitIntType::Unsuffixed), ty::Int(i)) => {
87            // Unsigned "negation" has the same bitwise effect as signed negation,
88            // which gets the result we want without additional casts.
89            let scalar_int =
90                trunc(if neg { u128::wrapping_neg(n.get()) } else { n.get() }, i.to_unsigned());
91            (ty::ValTree::from_scalar_int(tcx, scalar_int), Ty::new_int(tcx, *i))
92        }
93        (ast::LitKind::Bool(b), _) => (ty::ValTree::from_scalar_int(tcx, b.into()), tcx.types.bool),
94        (ast::LitKind::Float(n, ast::LitFloatType::Suffixed(fty)), _) => {
95            let fty = match fty {
96                ast::FloatTy::F16 => ty::FloatTy::F16,
97                ast::FloatTy::F32 => ty::FloatTy::F32,
98                ast::FloatTy::F64 => ty::FloatTy::F64,
99                ast::FloatTy::F128 => ty::FloatTy::F128,
100            };
101            let bits = parse_float_into_scalar(n, fty, neg)?;
102            (ty::ValTree::from_scalar_int(tcx, bits), Ty::new_float(tcx, fty))
103        }
104        (ast::LitKind::Float(n, ast::LitFloatType::Unsuffixed), ty::Float(fty)) => {
105            let bits = parse_float_into_scalar(n, *fty, neg)?;
106            (ty::ValTree::from_scalar_int(tcx, bits), Ty::new_float(tcx, *fty))
107        }
108        (ast::LitKind::Char(c), _) => (ty::ValTree::from_scalar_int(tcx, c.into()), tcx.types.char),
109        (ast::LitKind::Err(_), _) => return None,
110        _ => return None,
111    };
112
113    Some(ty::Value { ty: valtree_ty, valtree })
114}