]> git.lizzy.rs Git - rust.git/blob - src/librustc/ty/constness.rs
Rollup merge of #61420 - felixrabe:patch-2, r=dtolnay
[rust.git] / src / librustc / ty / constness.rs
1 use crate::ty::query::Providers;
2 use crate::hir::def_id::DefId;
3 use crate::hir;
4 use crate::ty::TyCtxt;
5 use syntax_pos::symbol::Symbol;
6 use crate::hir::map::blocks::FnLikeNode;
7 use syntax::attr;
8
9 impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> {
10     /// Whether the `def_id` counts as const fn in your current crate, considering all active
11     /// feature gates
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
19                     .iter()
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
23                 None => true,
24             },
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
27             None => true,
28         }
29     }
30
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
35         } else {
36             None
37         }
38     }
39
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) {
44             return false;
45         }
46
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
57                 _ => true,
58             }
59         } else {
60             // users enabling the `const_fn` feature gate can do what they want
61             !self.features().const_fn
62         }
63     }
64 }
65
66
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");
72
73         if let Some(fn_like) = FnLikeNode::from_node(tcx.hir().get_by_hir_id(hir_id)) {
74             fn_like.constness() == hir::Constness::Const
75         } else {
76             false
77         }
78     }
79
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) {
82             Some(stab) => {
83                 if cfg!(debug_assertions) && stab.promotable {
84                     let sig = tcx.fn_sig(def_id);
85                     assert_eq!(
86                         sig.unsafety(),
87                         hir::Unsafety::Normal,
88                         "don't mark const unsafe fns as promotable",
89                         // https://github.com/rust-lang/rust/pull/53851#issuecomment-418760682
90                     );
91                 }
92                 stab.promotable
93             },
94             None => false,
95         }
96     }
97
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)
102     }
103
104     *providers = Providers {
105         is_const_fn_raw,
106         is_promotable_const_fn,
107         const_fn_is_allowed_fn_ptr,
108         ..*providers
109     };
110 }