rustc_const_eval/const_eval/
fn_queries.rs

1use rustc_hir as hir;
2use rustc_hir::def::DefKind;
3use rustc_hir::def_id::{DefId, LocalDefId};
4use rustc_middle::query::Providers;
5use rustc_middle::ty::TyCtxt;
6
7fn parent_impl_or_trait_constness(tcx: TyCtxt<'_>, def_id: LocalDefId) -> hir::Constness {
8    let parent_id = tcx.local_parent(def_id);
9    match tcx.def_kind(parent_id) {
10        DefKind::Impl { of_trait: true } => tcx.impl_trait_header(parent_id).constness,
11        DefKind::Impl { of_trait: false } => tcx.constness(parent_id),
12        DefKind::Trait => {
13            if tcx.is_const_trait(parent_id.into()) {
14                hir::Constness::Const
15            } else {
16                hir::Constness::NotConst
17            }
18        }
19        _ => hir::Constness::NotConst,
20    }
21}
22
23/// Checks whether a function-like definition is considered to be `const`.
24fn constness(tcx: TyCtxt<'_>, def_id: LocalDefId) -> hir::Constness {
25    let node = tcx.hir_node_by_def_id(def_id);
26
27    match node {
28        hir::Node::Ctor(hir::VariantData::Tuple(..)) => hir::Constness::Const,
29        hir::Node::ForeignItem(item) if let hir::ForeignItemKind::Fn(..) = item.kind => {
30            // Foreign functions cannot be evaluated at compile-time.
31            hir::Constness::NotConst
32        }
33        hir::Node::Expr(e) if let hir::ExprKind::Closure(c) = e.kind => c.constness,
34        hir::Node::Item(i) if let hir::ItemKind::Impl(impl_) = i.kind => impl_.constness,
35        _ => {
36            if let Some(fn_kind) = node.fn_kind() {
37                if fn_kind.constness() == hir::Constness::Const {
38                    return hir::Constness::Const;
39                }
40
41                // If the function itself is not annotated with `const`, it may still be a `const fn`
42                // if it resides in a const trait impl.
43                parent_impl_or_trait_constness(tcx, def_id)
44            } else {
45                tcx.dcx().span_bug(
46                    tcx.def_span(def_id),
47                    format!("should not be requesting the constness of items that can't be const: {node:#?}: {:?}", tcx.def_kind(def_id))
48                )
49            }
50        }
51    }
52}
53
54fn is_promotable_const_fn(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
55    tcx.is_const_fn(def_id)
56        && match tcx.lookup_const_stability(def_id) {
57            Some(stab) => {
58                if cfg!(debug_assertions) && stab.promotable {
59                    let sig = tcx.fn_sig(def_id);
60                    assert!(
61                        sig.skip_binder().safety().is_safe(),
62                        "don't mark const unsafe fns as promotable",
63                        // https://github.com/rust-lang/rust/pull/53851#issuecomment-418760682
64                    );
65                }
66                stab.promotable
67            }
68            None => false,
69        }
70}
71
72pub fn provide(providers: &mut Providers) {
73    *providers = Providers { constness, is_promotable_const_fn, ..*providers };
74}