1 use ty::query::Providers;
2 use hir::def_id::DefId;
5 use syntax_pos::symbol::Symbol;
6 use hir::map::blocks::FnLikeNode;
8 use rustc_target::spec::abi;
10 impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> {
11 /// Whether the `def_id` counts as const fn in your current crate, considering all active
13 pub fn is_const_fn(self, def_id: DefId) -> bool {
14 self.is_const_fn_raw(def_id) && match self.lookup_stability(def_id) {
15 Some(stab) => match stab.const_stability {
16 // has a `rustc_const_unstable` attribute, check whether the user enabled the
17 // corresponding feature gate
18 Some(feature_name) => self.features()
19 .declared_lib_features
21 .any(|&(sym, _)| sym == feature_name),
22 // the function has no stability attribute, it is stable as const fn or the user
23 // needs to use feature gates to use the function at all
26 // functions without stability are either stable user written const fn or the user is
27 // using feature gates and we thus don't care what they do
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_const_fn_raw(def_id) {
35 self.lookup_stability(def_id)?.const_stability
41 /// Returns true if this function must conform to `min_const_fn`
42 pub fn is_min_const_fn(self, def_id: DefId) -> bool {
43 // some intrinsics are waved through if called inside the
44 // standard library. Users never need to call them directly
45 if let abi::Abi::RustIntrinsic = self.fn_sig(def_id).abi() {
46 match &self.item_name(def_id).as_str()[..] {
55 // Bail out if the signature doesn't contain `const`
56 if !self.is_const_fn_raw(def_id) {
60 if self.features().staged_api {
61 // in order for a libstd function to be considered min_const_fn
62 // it needs to be stable and have no `rustc_const_unstable` attribute
63 self.is_const_fn_raw(def_id) && match self.lookup_stability(def_id) {
64 // stable functions with unstable const fn aren't `min_const_fn`
65 Some(&attr::Stability { const_stability: Some(_), .. }) => false,
66 // unstable functions don't need to conform
67 Some(&attr::Stability { ref level, .. }) if level.is_unstable() => false,
68 // everything else needs to conform, because it would be callable from
69 // other `min_const_fn` functions
73 // users enabling the `const_fn` feature gate can do what they want
74 !self.features().const_fn
80 pub fn provide<'tcx>(providers: &mut Providers<'tcx>) {
81 /// only checks whether the function has a `const` modifier
82 fn is_const_fn_raw<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> bool {
83 let node_id = tcx.hir.as_local_node_id(def_id)
84 .expect("Non-local call to local provider is_const_fn");
86 if let Some(fn_like) = FnLikeNode::from_node(tcx.hir.get(node_id)) {
87 fn_like.constness() == hir::Constness::Const
93 fn is_promotable_const_fn<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> bool {
94 tcx.is_const_fn(def_id) && match tcx.lookup_stability(def_id) {
96 if cfg!(debug_assertions) && stab.promotable {
97 let sig = tcx.fn_sig(def_id);
100 hir::Unsafety::Normal,
101 "don't mark const unsafe fns as promotable",
102 // https://github.com/rust-lang/rust/pull/53851#issuecomment-418760682
111 *providers = Providers {
113 is_promotable_const_fn,