Skip to main content

rustc_const_eval/const_eval/
fn_queries.rs

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