1 use crate::ty::query::Providers;
2 use crate::hir::def_id::DefId;
5 use syntax_pos::symbol::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.lookup_stability(def_id) {
14 Some(stab) => match stab.const_stability {
15 // has a `rustc_const_unstable` attribute, check whether the user enabled the
16 // corresponding feature gate
17 Some(feature_name) => self.features()
18 .declared_lib_features
20 .any(|&(sym, _)| sym == feature_name),
21 // the function has no stability attribute, it is stable as const fn or the user
22 // needs to use feature gates to use the function at all
25 // functions without stability are either stable user written const fn or the user is
26 // using feature gates and we thus don't care what they do
31 /// Whether the `def_id` is an unstable const fn and what feature gate is necessary to enable it
32 pub fn is_unstable_const_fn(self, def_id: DefId) -> Option<Symbol> {
33 if self.is_const_fn_raw(def_id) {
34 self.lookup_stability(def_id)?.const_stability
40 /// Returns `true` if this function must conform to `min_const_fn`
41 pub fn is_min_const_fn(self, def_id: DefId) -> bool {
42 // Bail out if the signature doesn't contain `const`
43 if !self.is_const_fn_raw(def_id) {
47 if self.features().staged_api {
48 // in order for a libstd function to be considered min_const_fn
49 // it needs to be stable and have no `rustc_const_unstable` attribute
50 match self.lookup_stability(def_id) {
51 // stable functions with unstable const fn aren't `min_const_fn`
52 Some(&attr::Stability { const_stability: Some(_), .. }) => false,
53 // unstable functions don't need to conform
54 Some(&attr::Stability { ref level, .. }) if level.is_unstable() => false,
55 // everything else needs to conform, because it would be callable from
56 // other `min_const_fn` functions
60 // users enabling the `const_fn` feature gate can do what they want
61 !self.features().const_fn
67 pub fn provide<'tcx>(providers: &mut Providers<'tcx>) {
68 /// only checks whether the function has a `const` modifier
69 fn is_const_fn_raw<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> bool {
70 let hir_id = tcx.hir().as_local_hir_id(def_id)
71 .expect("Non-local call to local provider is_const_fn");
73 if let Some(fn_like) = FnLikeNode::from_node(tcx.hir().get_by_hir_id(hir_id)) {
74 fn_like.constness() == hir::Constness::Const
80 fn is_promotable_const_fn<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> bool {
81 tcx.is_const_fn(def_id) && match tcx.lookup_stability(def_id) {
83 if cfg!(debug_assertions) && stab.promotable {
84 let sig = tcx.fn_sig(def_id);
87 hir::Unsafety::Normal,
88 "don't mark const unsafe fns as promotable",
89 // https://github.com/rust-lang/rust/pull/53851#issuecomment-418760682
98 fn const_fn_is_allowed_fn_ptr<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> bool {
99 tcx.is_const_fn(def_id) &&
100 tcx.lookup_stability(def_id)
101 .map(|stab| stab.allow_const_fn_ptr).unwrap_or(false)
104 *providers = Providers {
106 is_promotable_const_fn,
107 const_fn_is_allowed_fn_ptr,