Skip to main content

rustc_const_eval/const_eval/
fn_queries.rs

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