@@ -3,7 +3,7 @@ use rustc::ty::query::Providers;
33use rustc:: ty:: TyCtxt ;
44use rustc_attr as attr;
55use rustc_hir as hir;
6- use rustc_hir:: def_id:: DefId ;
6+ use rustc_hir:: def_id:: { DefId , LocalDefId } ;
77use rustc_span:: symbol:: Symbol ;
88use rustc_target:: spec:: abi:: Abi ;
99
@@ -82,72 +82,96 @@ pub fn is_min_const_fn(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
8282 }
8383}
8484
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+ }
9293
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 ;
98107 }
99- }
100108
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+ }
108118
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+ }
110125
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 ( ) )
119129 }
130+ _ => None ,
120131 }
132+ }
121133
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+ ) ;
136159 }
137- None => false ,
160+ stab . promotable
138161 }
139- }
162+ None => false ,
163+ }
164+ }
140165
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+ }
148170
171+ pub fn provide ( providers : & mut Providers < ' _ > ) {
149172 * providers = Providers {
150173 is_const_fn_raw,
174+ is_const_impl_raw : |tcx, def_id| is_const_impl_raw ( tcx, LocalDefId :: from_def_id ( def_id) ) ,
151175 is_promotable_const_fn,
152176 const_fn_is_allowed_fn_ptr,
153177 ..* providers
0 commit comments