1 //! See docs in build/expr/mod.rs
3 use crate::build
::{parse_float_into_constval, Builder}
;
6 use rustc_middle
::mir
::interpret
::{Allocation, LitToConstError, LitToConstInput, Scalar}
;
7 use rustc_middle
::mir
::*;
8 use rustc_middle
::thir
::*;
9 use rustc_middle
::ty
::{
10 self, CanonicalUserType
, CanonicalUserTypeAnnotation
, TyCtxt
, UserTypeAnnotationIndex
,
12 use rustc_span
::DUMMY_SP
;
13 use rustc_target
::abi
::Size
;
15 impl<'a
, 'tcx
> Builder
<'a
, 'tcx
> {
16 /// Compile `expr`, yielding a compile-time constant. Assumes that
17 /// `expr` is a valid compile-time constant!
18 pub(crate) fn as_constant(&mut self, expr
: &Expr
<'tcx
>) -> ConstOperand
<'tcx
> {
21 let Expr { ty, temp_lifetime: _, span, ref kind }
= *expr
;
23 ExprKind
::Scope { region_scope: _, lint_level: _, value }
=> {
24 this
.as_constant(&this
.thir
[*value
])
26 _
=> as_constant_inner(
29 Some(this
.canonical_user_type_annotations
.push(CanonicalUserTypeAnnotation
{
31 user_ty
: user_ty
.clone(),
41 pub fn as_constant_inner
<'tcx
>(
43 push_cuta
: impl FnMut(&Box
<CanonicalUserType
<'tcx
>>) -> Option
<UserTypeAnnotationIndex
>,
45 ) -> ConstOperand
<'tcx
> {
46 let Expr { ty, temp_lifetime: _, span, ref kind }
= *expr
;
48 ExprKind
::Literal { lit, neg }
=> {
49 let const_
= match lit_to_mir_constant(tcx
, LitToConstInput { lit: &lit.node, ty, neg }
)
52 Err(LitToConstError
::Reported(guar
)) => {
53 Const
::Ty(ty
::Const
::new_error(tcx
, guar
, ty
))
55 Err(LitToConstError
::TypeError
) => {
56 bug
!("encountered type error in `lit_to_mir_constant`")
60 ConstOperand { span, user_ty: None, const_ }
62 ExprKind
::NonHirLiteral { lit, ref user_ty }
=> {
63 let user_ty
= user_ty
.as_ref().and_then(push_cuta
);
65 let const_
= Const
::Val(ConstValue
::Scalar(Scalar
::Int(lit
)), ty
);
67 ConstOperand { span, user_ty, const_ }
69 ExprKind
::ZstLiteral { ref user_ty }
=> {
70 let user_ty
= user_ty
.as_ref().and_then(push_cuta
);
72 let const_
= Const
::Val(ConstValue
::ZeroSized
, ty
);
74 ConstOperand { span, user_ty, const_ }
76 ExprKind
::NamedConst { def_id, args, ref user_ty }
=> {
77 let user_ty
= user_ty
.as_ref().and_then(push_cuta
);
79 let uneval
= mir
::UnevaluatedConst
::new(def_id
, args
);
80 let const_
= Const
::Unevaluated(uneval
, ty
);
82 ConstOperand { user_ty, span, const_ }
84 ExprKind
::ConstParam { param, def_id: _ }
=> {
85 let const_param
= ty
::Const
::new_param(tcx
, param
, expr
.ty
);
86 let const_
= Const
::Ty(const_param
);
88 ConstOperand { user_ty: None, span, const_ }
90 ExprKind
::ConstBlock { did: def_id, args }
=> {
91 let uneval
= mir
::UnevaluatedConst
::new(def_id
, args
);
92 let const_
= Const
::Unevaluated(uneval
, ty
);
94 ConstOperand { user_ty: None, span, const_ }
96 ExprKind
::StaticRef { alloc_id, ty, .. }
=> {
97 let const_val
= ConstValue
::Scalar(Scalar
::from_pointer(alloc_id
.into(), &tcx
));
98 let const_
= Const
::Val(const_val
, ty
);
100 ConstOperand { span, user_ty: None, const_ }
102 _
=> span_bug
!(span
, "expression is not a valid constant {:?}", kind
),
106 #[instrument(skip(tcx, lit_input))]
107 fn lit_to_mir_constant
<'tcx
>(
109 lit_input
: LitToConstInput
<'tcx
>,
110 ) -> Result
<Const
<'tcx
>, LitToConstError
> {
111 let LitToConstInput { lit, ty, neg }
= lit_input
;
113 let param_ty
= ty
::ParamEnv
::reveal_all().and(ty
);
117 LitToConstError
::Reported(tcx
.sess
.span_delayed_bug(
119 format
!("couldn't compute width of literal: {:?}", lit_input
.lit
),
123 trace
!("trunc {} with size {} and shift {}", n
, width
.bits(), 128 - width
.bits());
124 let result
= width
.truncate(n
);
125 trace
!("trunc result: {}", result
);
126 Ok(ConstValue
::Scalar(Scalar
::from_uint(result
, width
)))
129 let value
= match (lit
, &ty
.kind()) {
130 (ast
::LitKind
::Str(s
, _
), ty
::Ref(_
, inner_ty
, _
)) if inner_ty
.is_str() => {
132 let allocation
= Allocation
::from_bytes_byte_aligned_immutable(s
.as_bytes());
133 let allocation
= tcx
.mk_const_alloc(allocation
);
134 ConstValue
::Slice { data: allocation, meta: allocation.inner().size().bytes() }
136 (ast
::LitKind
::ByteStr(data
, _
), ty
::Ref(_
, inner_ty
, _
))
137 if matches
!(inner_ty
.kind(), ty
::Slice(_
)) =>
139 let allocation
= Allocation
::from_bytes_byte_aligned_immutable(data
as &[u8]);
140 let allocation
= tcx
.mk_const_alloc(allocation
);
141 ConstValue
::Slice { data: allocation, meta: allocation.inner().size().bytes() }
143 (ast
::LitKind
::ByteStr(data
, _
), ty
::Ref(_
, inner_ty
, _
)) if inner_ty
.is_array() => {
144 let id
= tcx
.allocate_bytes(data
);
145 ConstValue
::Scalar(Scalar
::from_pointer(id
.into(), &tcx
))
147 (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()) =>
149 let allocation
= Allocation
::from_bytes_byte_aligned_immutable(data
as &[u8]);
150 let allocation
= tcx
.mk_const_alloc(allocation
);
151 ConstValue
::Slice { data: allocation, meta: allocation.inner().size().bytes() }
153 (ast
::LitKind
::Byte(n
), ty
::Uint(ty
::UintTy
::U8
)) => {
154 ConstValue
::Scalar(Scalar
::from_uint(*n
, Size
::from_bytes(1)))
156 (ast
::LitKind
::Int(n
, _
), ty
::Uint(_
)) | (ast
::LitKind
::Int(n
, _
), ty
::Int(_
)) => {
157 trunc(if neg { (*n as i128).overflowing_neg().0 as u128 }
else { *n }
)?
159 (ast
::LitKind
::Float(n
, _
), ty
::Float(fty
)) => parse_float_into_constval(*n
, *fty
, neg
)
161 LitToConstError
::Reported(tcx
.sess
.span_delayed_bug(
163 format
!("couldn't parse float literal: {:?}", lit_input
.lit
),
166 (ast
::LitKind
::Bool(b
), ty
::Bool
) => ConstValue
::Scalar(Scalar
::from_bool(*b
)),
167 (ast
::LitKind
::Char(c
), ty
::Char
) => ConstValue
::Scalar(Scalar
::from_char(*c
)),
168 (ast
::LitKind
::Err
, _
) => {
169 return Err(LitToConstError
::Reported(
170 tcx
.sess
.span_delayed_bug(DUMMY_SP
, "encountered LitKind::Err during mir build"),
173 _
=> return Err(LitToConstError
::TypeError
),
176 Ok(Const
::Val(value
, ty
))