Skip to main content

rustc_const_eval/const_eval/
fn_queries.rs

1use rustc_hir::attrs::AttributeKind;
2use rustc_hir::def_id::{DefId, LocalDefId};
3use rustc_hir::{
4    Constness, ExprKind, ForeignItemKind, ImplItem, ImplItemImplKind, ImplItemKind, Item, ItemKind,
5    Node, TraitItem, TraitItemKind, VariantData, find_attr,
6};
7use rustc_middle::query::Providers;
8use rustc_middle::ty::TyCtxt;
9
10/// Checks whether a function-like definition is considered to be `const`. Also stores constness of inherent impls.
11fn constness(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Constness {
12    let node = tcx.hir_node_by_def_id(def_id);
13
14    match node {
15        Node::Ctor(VariantData::Tuple(..)) => Constness::Const,
16        Node::ForeignItem(item) if let ForeignItemKind::Fn(..) = item.kind => {
17            // Foreign functions cannot be evaluated at compile-time.
18            Constness::NotConst
19        }
20        Node::Expr(e) if let ExprKind::Closure(c) = e.kind => c.constness,
21        // FIXME(fee1-dead): extract this one out and rename this query to `fn_constness` so we don't need `is_const_fn` anymore.
22        Node::Item(i) if let ItemKind::Impl(impl_) = i.kind => impl_.constness,
23        Node::Item(Item { kind: ItemKind::Fn { sig, .. }, .. }) => sig.header.constness,
24        Node::ImplItem(ImplItem {
25            impl_kind: ImplItemImplKind::Trait { .. },
26            kind: ImplItemKind::Fn(..),
27            ..
28        }) => tcx.impl_trait_header(tcx.local_parent(def_id)).constness,
29        Node::ImplItem(ImplItem {
30            impl_kind: ImplItemImplKind::Inherent { .. },
31            kind: ImplItemKind::Fn(sig, _),
32            ..
33        }) => {
34            match sig.header.constness {
35                Constness::Const => Constness::Const,
36                // inherent impl could be const
37                Constness::NotConst => tcx.constness(tcx.local_parent(def_id)),
38            }
39        }
40        Node::TraitItem(ti @ TraitItem { kind: TraitItemKind::Fn(..), .. }) => {
41            if {
    {
            'done:
                {
                for i in tcx.hir_attrs(ti.hir_id()) {
                    let i: &rustc_hir::Attribute = i;
                    match i {
                        rustc_hir::Attribute::Parsed(AttributeKind::RustcNonConstTraitMethod)
                            => {
                            break 'done Some(());
                        }
                        _ => {}
                    }
                }
                None
            }
        }.is_some()
}find_attr!(tcx.hir_attrs(ti.hir_id()), AttributeKind::RustcNonConstTraitMethod) {
42                Constness::NotConst
43            } else {
44                tcx.trait_def(tcx.local_parent(def_id)).constness
45            }
46        }
47        _ => {
48            tcx.dcx().span_bug(
49                tcx.def_span(def_id),
50                ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("should not be requesting the constness of items that can\'t be const: {1:#?}: {0:?}",
                tcx.def_kind(def_id), node))
    })format!("should not be requesting the constness of items that can't be const: {node:#?}: {:?}", tcx.def_kind(def_id))
51            )
52        }
53    }
54}
55
56fn is_promotable_const_fn(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
57    tcx.is_const_fn(def_id)
58        && match tcx.lookup_const_stability(def_id) {
59            Some(stab) => {
60                if truecfg!(debug_assertions) && stab.promotable {
61                    let sig = tcx.fn_sig(def_id);
62                    if !sig.skip_binder().safety().is_safe() {
    {
        ::core::panicking::panic_fmt(format_args!("don\'t mark const unsafe fns as promotable"));
    }
};assert!(
63                        sig.skip_binder().safety().is_safe(),
64                        "don't mark const unsafe fns as promotable",
65                        // https://github.com/rust-lang/rust/pull/53851#issuecomment-418760682
66                    );
67                }
68                stab.promotable
69            }
70            None => false,
71        }
72}
73
74pub fn provide(providers: &mut Providers) {
75    *providers = Providers { constness, is_promotable_const_fn, ..*providers };
76}