@@ -35,34 +35,14 @@ pub fn is_const_evaluatable<'cx, 'tcx>(
3535 span : Span ,
3636) -> Result < ( ) , NotConstEvaluatable > {
3737 debug ! ( "is_const_evaluatable({:?})" , uv) ;
38- if infcx. tcx . features ( ) . generic_const_exprs {
39- let tcx = infcx. tcx ;
38+ let tcx = infcx. tcx ;
39+
40+ if tcx. features ( ) . generic_const_exprs {
4041 match AbstractConst :: new ( tcx, uv) ? {
4142 // We are looking at a generic abstract constant.
4243 Some ( ct) => {
43- for pred in param_env. caller_bounds ( ) {
44- match pred. kind ( ) . skip_binder ( ) {
45- ty:: PredicateKind :: ConstEvaluatable ( uv) => {
46- if let Some ( b_ct) = AbstractConst :: new ( tcx, uv) ? {
47- // Try to unify with each subtree in the AbstractConst to allow for
48- // `N + 1` being const evaluatable even if theres only a `ConstEvaluatable`
49- // predicate for `(N + 1) * 2`
50- let result =
51- walk_abstract_const ( tcx, b_ct, |b_ct| {
52- match try_unify ( tcx, ct, b_ct) {
53- true => ControlFlow :: BREAK ,
54- false => ControlFlow :: CONTINUE ,
55- }
56- } ) ;
57-
58- if let ControlFlow :: Break ( ( ) ) = result {
59- debug ! ( "is_const_evaluatable: abstract_const ~~> ok" ) ;
60- return Ok ( ( ) ) ;
61- }
62- }
63- }
64- _ => { } // don't care
65- }
44+ if satisfied_from_param_env ( tcx, ct, param_env) ? {
45+ return Ok ( ( ) ) ;
6646 }
6747
6848 // We were unable to unify the abstract constant with
@@ -163,6 +143,33 @@ pub fn is_const_evaluatable<'cx, 'tcx>(
163143 }
164144 }
165145
146+ // If we're evaluating a foreign constant, under a nightly compiler without generic
147+ // const exprs, AND it would've passed if that expression had been evaluated with
148+ // generic const exprs, then suggest using generic const exprs.
149+ if concrete. is_err ( )
150+ && tcx. sess . is_nightly_build ( )
151+ && !uv. def . did . is_local ( )
152+ && !tcx. features ( ) . generic_const_exprs
153+ && let Ok ( Some ( ct) ) = AbstractConst :: new ( tcx, uv)
154+ && satisfied_from_param_env ( tcx, ct, param_env) == Ok ( true )
155+ {
156+ tcx. sess
157+ . struct_span_fatal (
158+ // Slightly better span than just using `span` alone
159+ if span == rustc_span:: DUMMY_SP { tcx. def_span ( uv. def . did ) } else { span } ,
160+ "failed to evaluate generic const expression" ,
161+ )
162+ . note ( "the crate this constant originates from uses `#![feature(generic_const_exprs)]`" )
163+ . span_suggestion_verbose (
164+ rustc_span:: DUMMY_SP ,
165+ "consider enabling this feature" ,
166+ "#![feature(generic_const_exprs)]\n " . to_string ( ) ,
167+ rustc_errors:: Applicability :: MaybeIncorrect ,
168+ )
169+ . emit ( ) ;
170+ rustc_errors:: FatalError . raise ( ) ;
171+ }
172+
166173 debug ! ( ?concrete, "is_const_evaluatable" ) ;
167174 match concrete {
168175 Err ( ErrorHandled :: TooGeneric ) => Err ( match uv. has_infer_types_or_consts ( ) {
@@ -178,6 +185,37 @@ pub fn is_const_evaluatable<'cx, 'tcx>(
178185 }
179186}
180187
188+ fn satisfied_from_param_env < ' tcx > (
189+ tcx : TyCtxt < ' tcx > ,
190+ ct : AbstractConst < ' tcx > ,
191+ param_env : ty:: ParamEnv < ' tcx > ,
192+ ) -> Result < bool , NotConstEvaluatable > {
193+ for pred in param_env. caller_bounds ( ) {
194+ match pred. kind ( ) . skip_binder ( ) {
195+ ty:: PredicateKind :: ConstEvaluatable ( uv) => {
196+ if let Some ( b_ct) = AbstractConst :: new ( tcx, uv) ? {
197+ // Try to unify with each subtree in the AbstractConst to allow for
198+ // `N + 1` being const evaluatable even if theres only a `ConstEvaluatable`
199+ // predicate for `(N + 1) * 2`
200+ let result =
201+ walk_abstract_const ( tcx, b_ct, |b_ct| match try_unify ( tcx, ct, b_ct) {
202+ true => ControlFlow :: BREAK ,
203+ false => ControlFlow :: CONTINUE ,
204+ } ) ;
205+
206+ if let ControlFlow :: Break ( ( ) ) = result {
207+ debug ! ( "is_const_evaluatable: abstract_const ~~> ok" ) ;
208+ return Ok ( true ) ;
209+ }
210+ }
211+ }
212+ _ => { } // don't care
213+ }
214+ }
215+
216+ Ok ( false )
217+ }
218+
181219/// A tree representing an anonymous constant.
182220///
183221/// This is only able to represent a subset of `MIR`,
0 commit comments