@@ -3,7 +3,7 @@ use rustc::ty::query::Providers;
3
3
use rustc:: ty:: TyCtxt ;
4
4
use rustc_attr as attr;
5
5
use rustc_hir as hir;
6
- use rustc_hir:: def_id:: DefId ;
6
+ use rustc_hir:: def_id:: { DefId , LocalDefId } ;
7
7
use rustc_span:: symbol:: Symbol ;
8
8
use rustc_target:: spec:: abi:: Abi ;
9
9
@@ -82,72 +82,96 @@ pub fn is_min_const_fn(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
82
82
}
83
83
}
84
84
85
- pub fn provide ( providers : & mut Providers < ' _ > ) {
86
- /// Const evaluability whitelist is here to check evaluability at the
87
- /// top level beforehand.
88
- fn is_const_intrinsic ( tcx : TyCtxt < ' _ > , def_id : DefId ) -> Option < bool > {
89
- if tcx. is_closure ( def_id) {
90
- return None ;
91
- }
85
+ pub fn is_parent_const_impl_raw ( tcx : TyCtxt < ' _ > , hir_id : hir:: HirId ) -> bool {
86
+ let parent_id = tcx. hir ( ) . get_parent_did ( hir_id) ;
87
+ if !parent_id. is_top_level_module ( ) {
88
+ is_const_impl_raw ( tcx, LocalDefId :: from_def_id ( parent_id) )
89
+ } else {
90
+ false
91
+ }
92
+ }
92
93
93
- match tcx. fn_sig ( def_id) . abi ( ) {
94
- Abi :: RustIntrinsic | Abi :: PlatformIntrinsic => {
95
- Some ( tcx. lookup_const_stability ( def_id) . is_some ( ) )
96
- }
97
- _ => None ,
94
+ /// Checks whether the function has a `const` modifier or, in case it is an intrinsic, whether
95
+ /// said intrinsic is on the whitelist for being const callable.
96
+ fn is_const_fn_raw ( tcx : TyCtxt < ' _ > , def_id : DefId ) -> bool {
97
+ let hir_id =
98
+ tcx. hir ( ) . as_local_hir_id ( def_id) . expect ( "Non-local call to local provider is_const_fn" ) ;
99
+
100
+ let node = tcx. hir ( ) . get ( hir_id) ;
101
+
102
+ if let Some ( whitelisted) = is_const_intrinsic ( tcx, def_id) {
103
+ whitelisted
104
+ } else if let Some ( fn_like) = FnLikeNode :: from_node ( node) {
105
+ if fn_like. constness ( ) == hir:: Constness :: Const {
106
+ return true ;
98
107
}
99
- }
100
108
101
- /// Checks whether the function has a `const` modifier or, in case it is an intrinsic, whether
102
- /// said intrinsic is on the whitelist for being const callable.
103
- fn is_const_fn_raw ( tcx : TyCtxt < ' _ > , def_id : DefId ) -> bool {
104
- let hir_id = tcx
105
- . hir ( )
106
- . as_local_hir_id ( def_id)
107
- . expect ( "Non-local call to local provider is_const_fn" ) ;
109
+ // If the function itself is not annotated with `const`, it may still be a `const fn`
110
+ // if it resides in a const trait impl.
111
+ is_parent_const_impl_raw ( tcx, hir_id)
112
+ } else if let hir:: Node :: Ctor ( _) = node {
113
+ true
114
+ } else {
115
+ false
116
+ }
117
+ }
108
118
109
- let node = tcx. hir ( ) . get ( hir_id) ;
119
+ /// Const evaluability whitelist is here to check evaluability at the
120
+ /// top level beforehand.
121
+ fn is_const_intrinsic ( tcx : TyCtxt < ' _ > , def_id : DefId ) -> Option < bool > {
122
+ if tcx. is_closure ( def_id) {
123
+ return None ;
124
+ }
110
125
111
- if let Some ( whitelisted) = is_const_intrinsic ( tcx, def_id) {
112
- whitelisted
113
- } else if let Some ( fn_like) = FnLikeNode :: from_node ( node) {
114
- fn_like. constness ( ) == hir:: Constness :: Const
115
- } else if let hir:: Node :: Ctor ( _) = node {
116
- true
117
- } else {
118
- false
126
+ match tcx. fn_sig ( def_id) . abi ( ) {
127
+ Abi :: RustIntrinsic | Abi :: PlatformIntrinsic => {
128
+ Some ( tcx. lookup_const_stability ( def_id) . is_some ( ) )
119
129
}
130
+ _ => None ,
120
131
}
132
+ }
121
133
122
- fn is_promotable_const_fn ( tcx : TyCtxt < ' _ > , def_id : DefId ) -> bool {
123
- is_const_fn ( tcx, def_id)
124
- && match tcx. lookup_const_stability ( def_id) {
125
- Some ( stab) => {
126
- if cfg ! ( debug_assertions) && stab. promotable {
127
- let sig = tcx. fn_sig ( def_id) ;
128
- assert_eq ! (
129
- sig. unsafety( ) ,
130
- hir:: Unsafety :: Normal ,
131
- "don't mark const unsafe fns as promotable" ,
132
- // https://github.com/rust-lang/rust/pull/53851#issuecomment-418760682
133
- ) ;
134
- }
135
- stab. promotable
134
+ /// Checks whether the given item is an `impl` that has a `const` modifier.
135
+ fn is_const_impl_raw ( tcx : TyCtxt < ' _ > , def_id : LocalDefId ) -> bool {
136
+ let hir_id = tcx. hir ( ) . local_def_id_to_hir_id ( def_id) ;
137
+ let node = tcx. hir ( ) . get ( hir_id) ;
138
+ matches ! (
139
+ node,
140
+ hir:: Node :: Item ( hir:: Item {
141
+ kind: hir:: ItemKind :: Impl { constness: hir:: Constness :: Const , .. } ,
142
+ ..
143
+ } )
144
+ )
145
+ }
146
+
147
+ fn is_promotable_const_fn ( tcx : TyCtxt < ' _ > , def_id : DefId ) -> bool {
148
+ is_const_fn ( tcx, def_id)
149
+ && match tcx. lookup_const_stability ( def_id) {
150
+ Some ( stab) => {
151
+ if cfg ! ( debug_assertions) && stab. promotable {
152
+ let sig = tcx. fn_sig ( def_id) ;
153
+ assert_eq ! (
154
+ sig. unsafety( ) ,
155
+ hir:: Unsafety :: Normal ,
156
+ "don't mark const unsafe fns as promotable" ,
157
+ // https://github.com/rust-lang/rust/pull/53851#issuecomment-418760682
158
+ ) ;
136
159
}
137
- None => false ,
160
+ stab . promotable
138
161
}
139
- }
162
+ None => false ,
163
+ }
164
+ }
140
165
141
- fn const_fn_is_allowed_fn_ptr ( tcx : TyCtxt < ' _ > , def_id : DefId ) -> bool {
142
- is_const_fn ( tcx, def_id)
143
- && tcx
144
- . lookup_const_stability ( def_id)
145
- . map ( |stab| stab. allow_const_fn_ptr )
146
- . unwrap_or ( false )
147
- }
166
+ fn const_fn_is_allowed_fn_ptr ( tcx : TyCtxt < ' _ > , def_id : DefId ) -> bool {
167
+ is_const_fn ( tcx, def_id)
168
+ && tcx. lookup_const_stability ( def_id) . map ( |stab| stab. allow_const_fn_ptr ) . unwrap_or ( false )
169
+ }
148
170
171
+ pub fn provide ( providers : & mut Providers < ' _ > ) {
149
172
* providers = Providers {
150
173
is_const_fn_raw,
174
+ is_const_impl_raw : |tcx, def_id| is_const_impl_raw ( tcx, LocalDefId :: from_def_id ( def_id) ) ,
151
175
is_promotable_const_fn,
152
176
const_fn_is_allowed_fn_ptr,
153
177
..* providers
0 commit comments