1 use crate::mir
::interpret
::ConstValue
;
2 use crate::mir
::interpret
::{LitToConstInput, Scalar}
;
4 self, InlineConstSubsts
, InlineConstSubstsParts
, InternalSubsts
, ParamEnv
, ParamEnvAnd
, Ty
,
7 use rustc_data_structures
::intern
::Interned
;
8 use rustc_errors
::ErrorGuaranteed
;
10 use rustc_hir
::def_id
::{DefId, LocalDefId}
;
11 use rustc_macros
::HashStable
;
22 /// Use this rather than `ConstS`, whenever possible.
23 #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, HashStable)]
24 #[rustc_pass_by_value]
25 pub struct Const
<'tcx
>(pub Interned
<'tcx
, ConstS
<'tcx
>>);
27 impl<'tcx
> fmt
::Debug
for Const
<'tcx
> {
28 fn fmt(&self, f
: &mut fmt
::Formatter
<'_
>) -> fmt
::Result
{
29 // This reflects what `Const` looked liked before `Interned` was
30 // introduced. We print it like this to avoid having to update expected
31 // output in a lot of tests.
32 write
!(f
, "Const {{ ty: {:?}, val: {:?} }}", self.ty(), self.val())
36 /// Typed constant value.
37 #[derive(PartialEq, Eq, PartialOrd, Ord, Hash, HashStable, TyEncodable, TyDecodable)]
38 pub struct ConstS
<'tcx
> {
40 pub val
: ConstKind
<'tcx
>,
43 #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
44 static_assert_size
!(ConstS
<'_
>, 48);
46 impl<'tcx
> Const
<'tcx
> {
47 pub fn ty(self) -> Ty
<'tcx
> {
51 pub fn val(self) -> ConstKind
<'tcx
> {
55 /// Literals and const generic parameters are eagerly converted to a constant, everything else
56 /// becomes `Unevaluated`.
57 pub fn from_anon_const(tcx
: TyCtxt
<'tcx
>, def_id
: LocalDefId
) -> Self {
58 Self::from_opt_const_arg_anon_const(tcx
, ty
::WithOptConstParam
::unknown(def_id
))
61 #[instrument(skip(tcx), level = "debug")]
62 pub fn from_opt_const_arg_anon_const(
64 def
: ty
::WithOptConstParam
<LocalDefId
>,
66 debug
!("Const::from_anon_const(def={:?})", def
);
68 let body_id
= match tcx
.hir().get_by_def_id(def
.did
) {
69 hir
::Node
::AnonConst(ac
) => ac
.body
,
71 tcx
.def_span(def
.did
.to_def_id()),
72 "from_anon_const can only process anonymous constants"
76 let expr
= &tcx
.hir().body(body_id
).value
;
79 let ty
= tcx
.type_of(def
.def_id_for_type_of());
81 match Self::try_eval_lit_or_param(tcx
, ty
, expr
) {
83 None
=> tcx
.mk_const(ty
::ConstS
{
84 val
: ty
::ConstKind
::Unevaluated(ty
::Unevaluated
{
86 substs
: InternalSubsts
::identity_for_item(tcx
, def
.did
.to_def_id()),
94 #[instrument(skip(tcx), level = "debug")]
95 fn try_eval_lit_or_param(
98 expr
: &'tcx hir
::Expr
<'tcx
>,
100 // Unwrap a block, so that e.g. `{ P }` is recognised as a parameter. Const arguments
101 // currently have to be wrapped in curly brackets, so it's necessary to special-case.
102 let expr
= match &expr
.kind
{
103 hir
::ExprKind
::Block(block
, _
) if block
.stmts
.is_empty() && block
.expr
.is_some() => {
104 block
.expr
.as_ref().unwrap()
109 let lit_input
= match expr
.kind
{
110 hir
::ExprKind
::Lit(ref lit
) => Some(LitToConstInput { lit: &lit.node, ty, neg: false }
),
111 hir
::ExprKind
::Unary(hir
::UnOp
::Neg
, ref expr
) => match expr
.kind
{
112 hir
::ExprKind
::Lit(ref lit
) => {
113 Some(LitToConstInput { lit: &lit.node, ty, neg: true }
)
120 if let Some(lit_input
) = lit_input
{
121 // If an error occurred, ignore that it's a literal and leave reporting the error up to
123 match tcx
.at(expr
.span
).lit_to_const(lit_input
) {
124 Ok(c
) => return Some(c
),
126 tcx
.sess
.delay_span_bug(
128 &format
!("Const::from_anon_const: couldn't lit_to_const {:?}", e
),
134 use hir
::{def::DefKind::ConstParam, def::Res, ExprKind, Path, QPath}
;
136 ExprKind
::Path(QPath
::Resolved(_
, &Path { res: Res::Def(ConstParam, def_id), .. }
)) => {
137 // Find the name and index of the const parameter by indexing the generics of
138 // the parent item and construct a `ParamConst`.
139 let hir_id
= tcx
.hir().local_def_id_to_hir_id(def_id
.expect_local());
140 let item_id
= tcx
.hir().get_parent_node(hir_id
);
141 let item_def_id
= tcx
.hir().local_def_id(item_id
);
142 let generics
= tcx
.generics_of(item_def_id
.to_def_id());
143 let index
= generics
.param_def_id_to_index
[&def_id
];
144 let name
= tcx
.hir().name(hir_id
);
145 Some(tcx
.mk_const(ty
::ConstS
{
146 val
: ty
::ConstKind
::Param(ty
::ParamConst
::new(index
, name
)),
154 pub fn from_inline_const(tcx
: TyCtxt
<'tcx
>, def_id
: LocalDefId
) -> Self {
155 debug
!("Const::from_inline_const(def_id={:?})", def_id
);
157 let hir_id
= tcx
.hir().local_def_id_to_hir_id(def_id
);
159 let body_id
= match tcx
.hir().get(hir_id
) {
160 hir
::Node
::AnonConst(ac
) => ac
.body
,
162 tcx
.def_span(def_id
.to_def_id()),
163 "from_inline_const can only process anonymous constants"
167 let expr
= &tcx
.hir().body(body_id
).value
;
169 let ty
= tcx
.typeck(def_id
).node_type(hir_id
);
171 let ret
= match Self::try_eval_lit_or_param(tcx
, ty
, expr
) {
174 let typeck_root_def_id
= tcx
.typeck_root_def_id(def_id
.to_def_id());
176 tcx
.erase_regions(InternalSubsts
::identity_for_item(tcx
, typeck_root_def_id
));
178 InlineConstSubsts
::new(tcx
, InlineConstSubstsParts { parent_substs, ty }
)
180 tcx
.mk_const(ty
::ConstS
{
181 val
: ty
::ConstKind
::Unevaluated(ty
::Unevaluated
{
182 def
: ty
::WithOptConstParam
::unknown(def_id
).to_global(),
190 debug_assert
!(!ret
.has_free_regions());
194 /// Interns the given value as a constant.
196 pub fn from_value(tcx
: TyCtxt
<'tcx
>, val
: ConstValue
<'tcx
>, ty
: Ty
<'tcx
>) -> Self {
197 tcx
.mk_const(ConstS { val: ConstKind::Value(val), ty }
)
201 /// Interns the given scalar as a constant.
202 pub fn from_scalar(tcx
: TyCtxt
<'tcx
>, val
: Scalar
, ty
: Ty
<'tcx
>) -> Self {
203 Self::from_value(tcx
, ConstValue
::Scalar(val
), ty
)
207 /// Creates a constant with the given integer value and interns it.
208 pub fn from_bits(tcx
: TyCtxt
<'tcx
>, bits
: u128
, ty
: ParamEnvAnd
<'tcx
, Ty
<'tcx
>>) -> Self {
211 .unwrap_or_else(|e
| panic
!("could not compute layout for {:?}: {:?}", ty
, e
))
213 Self::from_scalar(tcx
, Scalar
::from_uint(bits
, size
), ty
.value
)
217 /// Creates an interned zst constant.
218 pub fn zero_sized(tcx
: TyCtxt
<'tcx
>, ty
: Ty
<'tcx
>) -> Self {
219 Self::from_scalar(tcx
, Scalar
::ZST
, ty
)
223 /// Creates an interned bool constant.
224 pub fn from_bool(tcx
: TyCtxt
<'tcx
>, v
: bool
) -> Self {
225 Self::from_bits(tcx
, v
as u128
, ParamEnv
::empty().and(tcx
.types
.bool
))
229 /// Creates an interned usize constant.
230 pub fn from_usize(tcx
: TyCtxt
<'tcx
>, n
: u64) -> Self {
231 Self::from_bits(tcx
, n
as u128
, ParamEnv
::empty().and(tcx
.types
.usize))
235 /// Attempts to evaluate the given constant to bits. Can fail to evaluate in the presence of
236 /// generics (or erroneous code) or if the value can't be represented as bits (e.g. because it
237 /// contains const generic parameters or pointers).
238 pub fn try_eval_bits(
241 param_env
: ParamEnv
<'tcx
>,
244 assert_eq
!(self.ty(), ty
);
245 let size
= tcx
.layout_of(param_env
.with_reveal_all_normalized(tcx
).and(ty
)).ok()?
.size
;
246 // if `ty` does not depend on generic parameters, use an empty param_env
247 self.val().eval(tcx
, param_env
).try_to_bits(size
)
251 pub fn try_eval_bool(self, tcx
: TyCtxt
<'tcx
>, param_env
: ParamEnv
<'tcx
>) -> Option
<bool
> {
252 self.val().eval(tcx
, param_env
).try_to_bool()
256 pub fn try_eval_usize(self, tcx
: TyCtxt
<'tcx
>, param_env
: ParamEnv
<'tcx
>) -> Option
<u64> {
257 self.val().eval(tcx
, param_env
).try_to_machine_usize(tcx
)
261 /// Tries to evaluate the constant if it is `Unevaluated`. If that doesn't succeed, return the
262 /// unevaluated constant.
263 pub fn eval(self, tcx
: TyCtxt
<'tcx
>, param_env
: ParamEnv
<'tcx
>) -> Const
<'tcx
> {
264 if let Some(val
) = self.val().try_eval(tcx
, param_env
) {
266 Ok(val
) => Const
::from_value(tcx
, val
, self.ty()),
267 Err(ErrorGuaranteed { .. }
) => tcx
.const_error(self.ty()),
275 /// Panics if the value cannot be evaluated or doesn't contain a valid integer of the given type.
276 pub fn eval_bits(self, tcx
: TyCtxt
<'tcx
>, param_env
: ParamEnv
<'tcx
>, ty
: Ty
<'tcx
>) -> u128
{
277 self.try_eval_bits(tcx
, param_env
, ty
)
278 .unwrap_or_else(|| bug
!("expected bits of {:#?}, got {:#?}", ty
, self))
282 /// Panics if the value cannot be evaluated or doesn't contain a valid `usize`.
283 pub fn eval_usize(self, tcx
: TyCtxt
<'tcx
>, param_env
: ParamEnv
<'tcx
>) -> u64 {
284 self.try_eval_usize(tcx
, param_env
)
285 .unwrap_or_else(|| bug
!("expected usize, got {:#?}", self))
289 pub fn const_param_default
<'tcx
>(tcx
: TyCtxt
<'tcx
>, def_id
: DefId
) -> Const
<'tcx
> {
290 let default_def_id
= match tcx
.hir().get_by_def_id(def_id
.expect_local()) {
291 hir
::Node
::GenericParam(hir
::GenericParam
{
292 kind
: hir
::GenericParamKind
::Const { ty: _, default: Some(ac) }
,
294 }) => tcx
.hir().local_def_id(ac
.hir_id
),
296 tcx
.def_span(def_id
),
297 "`const_param_default` expected a generic parameter with a constant"
300 Const
::from_anon_const(tcx
, default_def_id
)