2 use rustc_hir
::def
::DefKind
;
3 use rustc_hir
::def_id
::{DefId, LocalDefId}
;
4 use rustc_middle
::ty
::query
::Providers
;
5 use rustc_middle
::ty
::{DefIdTree, TyCtxt}
;
6 use rustc_span
::symbol
::Symbol
;
8 /// Whether the `def_id` is an unstable const fn and what feature gate is necessary to enable it
9 pub fn is_unstable_const_fn(tcx
: TyCtxt
<'_
>, def_id
: DefId
) -> Option
<Symbol
> {
10 if tcx
.is_const_fn_raw(def_id
) {
11 let const_stab
= tcx
.lookup_const_stability(def_id
)?
;
12 if const_stab
.is_const_unstable() { Some(const_stab.feature) }
else { None }
18 pub fn is_parent_const_impl_raw(tcx
: TyCtxt
<'_
>, def_id
: LocalDefId
) -> bool
{
19 let parent_id
= tcx
.local_parent(def_id
);
20 matches
!(tcx
.def_kind(parent_id
), DefKind
::Impl { .. }
)
21 && tcx
.constness(parent_id
) == hir
::Constness
::Const
24 /// Checks whether an item is considered to be `const`. If it is a constructor, it is const. If
25 /// it is a trait impl/function, return if it has a `const` modifier. If it is an intrinsic,
26 /// report whether said intrinsic has a `rustc_const_{un,}stable` attribute. Otherwise, return
27 /// `Constness::NotConst`.
28 fn constness(tcx
: TyCtxt
<'_
>, def_id
: DefId
) -> hir
::Constness
{
29 let def_id
= def_id
.expect_local();
30 let node
= tcx
.hir().get_by_def_id(def_id
);
33 hir
::Node
::Ctor(_
) => hir
::Constness
::Const
,
34 hir
::Node
::Item(hir
::Item { kind: hir::ItemKind::Impl(impl_), .. }
) => impl_
.constness
,
35 hir
::Node
::ForeignItem(hir
::ForeignItem { kind: hir::ForeignItemKind::Fn(..), .. }
) => {
36 // Intrinsics use `rustc_const_{un,}stable` attributes to indicate constness. All other
37 // foreign items cannot be evaluated at compile-time.
38 let is_const
= if tcx
.is_intrinsic(def_id
) {
39 tcx
.lookup_const_stability(def_id
).is_some()
43 if is_const { hir::Constness::Const }
else { hir::Constness::NotConst }
45 hir
::Node
::Expr(e
) if let hir
::ExprKind
::Closure(c
) = e
.kind
=> c
.constness
,
47 if let Some(fn_kind
) = node
.fn_kind() {
48 if fn_kind
.constness() == hir
::Constness
::Const
{
49 return hir
::Constness
::Const
;
52 // If the function itself is not annotated with `const`, it may still be a `const fn`
53 // if it resides in a const trait impl.
54 let is_const
= is_parent_const_impl_raw(tcx
, def_id
);
55 if is_const { hir::Constness::Const }
else { hir::Constness::NotConst }
57 hir
::Constness
::NotConst
63 fn is_promotable_const_fn(tcx
: TyCtxt
<'_
>, def_id
: DefId
) -> bool
{
64 tcx
.is_const_fn(def_id
)
65 && match tcx
.lookup_const_stability(def_id
) {
67 if cfg
!(debug_assertions
) && stab
.promotable
{
68 let sig
= tcx
.fn_sig(def_id
);
70 sig
.skip_binder().unsafety(),
71 hir
::Unsafety
::Normal
,
72 "don't mark const unsafe fns as promotable",
73 // https://github.com/rust-lang/rust/pull/53851#issuecomment-418760682
82 pub fn provide(providers
: &mut Providers
) {
83 *providers
= Providers { constness, is_promotable_const_fn, ..*providers }
;