@@ -35,34 +35,14 @@ pub fn is_const_evaluatable<'cx, 'tcx>(
35
35
span : Span ,
36
36
) -> Result < ( ) , NotConstEvaluatable > {
37
37
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 {
40
41
match AbstractConst :: new ( tcx, uv) ? {
41
42
// We are looking at a generic abstract constant.
42
43
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 ( ( ) ) ;
66
46
}
67
47
68
48
// We were unable to unify the abstract constant with
@@ -163,6 +143,33 @@ pub fn is_const_evaluatable<'cx, 'tcx>(
163
143
}
164
144
}
165
145
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
+
166
173
debug ! ( ?concrete, "is_const_evaluatable" ) ;
167
174
match concrete {
168
175
Err ( ErrorHandled :: TooGeneric ) => Err ( match uv. has_infer_types_or_consts ( ) {
@@ -178,6 +185,37 @@ pub fn is_const_evaluatable<'cx, 'tcx>(
178
185
}
179
186
}
180
187
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
+
181
219
/// A tree representing an anonymous constant.
182
220
///
183
221
/// This is only able to represent a subset of `MIR`,
0 commit comments