Skip to main content

rustc_mir_build/thir/
constant.rs

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