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