1 use crate::ty::query::Providers;
2 use crate::hir::def_id::DefId;
5 use syntax_pos::symbol::{sym, Symbol};
6 use crate::hir::map::blocks::FnLikeNode;
9 impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> {
10 /// Whether the `def_id` counts as const fn in your current crate, considering all active
12 pub fn is_const_fn(self, def_id: DefId) -> bool {
13 self.is_const_fn_raw(def_id) && match self.is_unstable_const_fn(def_id) {
14 Some(feature_name) => {
15 // has a `rustc_const_unstable` attribute, check whether the user enabled the
16 // corresponding feature gate, const_constructor is not a lib feature, so has
17 // to be checked separately.
19 .declared_lib_features
21 .any(|&(sym, _)| sym == feature_name)
22 || (feature_name == sym::const_constructor
23 && self.features().const_constructor)
25 // functions without const stability are either stable user written
26 // const fn or the user is using feature gates and we thus don't
32 /// Whether the `def_id` is an unstable const fn and what feature gate is necessary to enable it
33 pub fn is_unstable_const_fn(self, def_id: DefId) -> Option<Symbol> {
34 if self.is_constructor(def_id) {
35 Some(sym::const_constructor)
36 } else if self.is_const_fn_raw(def_id) {
37 self.lookup_stability(def_id)?.const_stability
43 /// Returns `true` if this function must conform to `min_const_fn`
44 pub fn is_min_const_fn(self, def_id: DefId) -> bool {
45 // Bail out if the signature doesn't contain `const`
46 if !self.is_const_fn_raw(def_id) {
50 if self.features().staged_api {
51 // in order for a libstd function to be considered min_const_fn
52 // it needs to be stable and have no `rustc_const_unstable` attribute
53 match self.lookup_stability(def_id) {
54 // stable functions with unstable const fn aren't `min_const_fn`
55 Some(&attr::Stability { const_stability: Some(_), .. }) => false,
56 // unstable functions don't need to conform
57 Some(&attr::Stability { ref level, .. }) if level.is_unstable() => false,
58 // everything else needs to conform, because it would be callable from
59 // other `min_const_fn` functions
63 // users enabling the `const_fn` feature gate can do what they want
64 !self.features().const_fn
70 pub fn provide<'tcx>(providers: &mut Providers<'tcx>) {
71 /// only checks whether the function has a `const` modifier
72 fn is_const_fn_raw<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> bool {
73 let hir_id = tcx.hir().as_local_hir_id(def_id)
74 .expect("Non-local call to local provider is_const_fn");
76 let node = tcx.hir().get_by_hir_id(hir_id);
77 if let Some(fn_like) = FnLikeNode::from_node(node) {
78 fn_like.constness() == hir::Constness::Const
79 } else if let hir::Node::Ctor(_) = node {
86 fn is_promotable_const_fn<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> bool {
87 tcx.is_const_fn(def_id) && match tcx.lookup_stability(def_id) {
89 if cfg!(debug_assertions) && stab.promotable {
90 let sig = tcx.fn_sig(def_id);
93 hir::Unsafety::Normal,
94 "don't mark const unsafe fns as promotable",
95 // https://github.com/rust-lang/rust/pull/53851#issuecomment-418760682
104 fn const_fn_is_allowed_fn_ptr<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> bool {
105 tcx.is_const_fn(def_id) &&
106 tcx.lookup_stability(def_id)
107 .map(|stab| stab.allow_const_fn_ptr).unwrap_or(false)
110 *providers = Providers {
112 is_promotable_const_fn,
113 const_fn_is_allowed_fn_ptr,