]> git.lizzy.rs Git - rust.git/blob - src/librustc/ty/constness.rs
Rollup merge of #61715 - RalfJung:test-ascii-lowercase, r=varkor
[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::{sym, 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.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.
18                 self.features()
19                     .declared_lib_features
20                     .iter()
21                     .any(|&(sym, _)| sym == feature_name)
22                     || (feature_name == sym::const_constructor
23                         && self.features().const_constructor)
24             },
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
27             // care what they do
28             None => true,
29         }
30     }
31
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
38         } else {
39             None
40         }
41     }
42
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) {
47             return false;
48         }
49
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
60                 _ => true,
61             }
62         } else {
63             // users enabling the `const_fn` feature gate can do what they want
64             !self.features().const_fn
65         }
66     }
67 }
68
69
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");
75
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 {
80             true
81         } else {
82             false
83         }
84     }
85
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) {
88             Some(stab) => {
89                 if cfg!(debug_assertions) && stab.promotable {
90                     let sig = tcx.fn_sig(def_id);
91                     assert_eq!(
92                         sig.unsafety(),
93                         hir::Unsafety::Normal,
94                         "don't mark const unsafe fns as promotable",
95                         // https://github.com/rust-lang/rust/pull/53851#issuecomment-418760682
96                     );
97                 }
98                 stab.promotable
99             },
100             None => false,
101         }
102     }
103
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)
108     }
109
110     *providers = Providers {
111         is_const_fn_raw,
112         is_promotable_const_fn,
113         const_fn_is_allowed_fn_ptr,
114         ..*providers
115     };
116 }