@@ -32,7 +32,7 @@ use rustc::middle::lang_items;
32
32
use rustc_target:: spec:: abi:: Abi ;
33
33
use syntax:: attr;
34
34
use syntax:: ast:: LitKind ;
35
- use syntax:: feature_gate:: UnstableFeatures ;
35
+ use syntax:: feature_gate:: { UnstableFeatures , feature_err , emit_feature_err , GateIssue } ;
36
36
use syntax_pos:: { Span , DUMMY_SP } ;
37
37
38
38
use std:: fmt;
@@ -120,8 +120,7 @@ struct Qualifier<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
120
120
rpo : ReversePostorder < ' a , ' tcx > ,
121
121
tcx : TyCtxt < ' a , ' gcx , ' tcx > ,
122
122
param_env : ty:: ParamEnv < ' tcx > ,
123
- temp_qualif : IndexVec < Local , Option < Qualif > > ,
124
- return_qualif : Option < Qualif > ,
123
+ local_qualif : IndexVec < Local , Option < Qualif > > ,
125
124
qualif : Qualif ,
126
125
const_fn_arg_vars : BitVector ,
127
126
temp_promotion_state : IndexVec < Local , TempState > ,
@@ -140,11 +139,11 @@ impl<'a, 'tcx> Qualifier<'a, 'tcx, 'tcx> {
140
139
141
140
let param_env = tcx. param_env ( def_id) ;
142
141
143
- let mut temp_qualif = IndexVec :: from_elem ( None , & mir. local_decls ) ;
142
+ let mut local_qualif = IndexVec :: from_elem ( None , & mir. local_decls ) ;
144
143
for arg in mir. args_iter ( ) {
145
144
let mut qualif = Qualif :: NEEDS_DROP ;
146
145
qualif. restrict ( mir. local_decls [ arg] . ty , tcx, param_env) ;
147
- temp_qualif [ arg] = Some ( qualif) ;
146
+ local_qualif [ arg] = Some ( qualif) ;
148
147
}
149
148
150
149
Qualifier {
@@ -155,8 +154,7 @@ impl<'a, 'tcx> Qualifier<'a, 'tcx, 'tcx> {
155
154
rpo,
156
155
tcx,
157
156
param_env,
158
- temp_qualif,
159
- return_qualif : None ,
157
+ local_qualif,
160
158
qualif : Qualif :: empty ( ) ,
161
159
const_fn_arg_vars : BitVector :: new ( mir. local_decls . len ( ) ) ,
162
160
temp_promotion_state : temps,
@@ -191,12 +189,12 @@ impl<'a, 'tcx> Qualifier<'a, 'tcx, 'tcx> {
191
189
fn statement_like ( & mut self ) {
192
190
self . add ( Qualif :: NOT_CONST ) ;
193
191
if self . mode != Mode :: Fn {
194
- let mut err = struct_span_err ! (
195
- self . tcx. sess,
192
+ let mut err = feature_err (
193
+ & self . tcx . sess . parse_sess ,
194
+ "const_let" ,
196
195
self . span ,
197
- E0016 ,
198
- "blocks in {}s are limited to items and tail expressions" ,
199
- self . mode
196
+ GateIssue :: Language ,
197
+ & format ! ( "statements in {}s are unstable" , self . mode) ,
200
198
) ;
201
199
if self . tcx . sess . teach ( & err. get_code ( ) . unwrap ( ) ) {
202
200
err. note ( "Blocks in constants may only contain items (such as constant, function \
@@ -266,6 +264,7 @@ impl<'a, 'tcx> Qualifier<'a, 'tcx, 'tcx> {
266
264
267
265
/// Assign the current qualification to the given destination.
268
266
fn assign ( & mut self , dest : & Place < ' tcx > , location : Location ) {
267
+ trace ! ( "assign: {:?}" , dest) ;
269
268
let qualif = self . qualif ;
270
269
let span = self . span ;
271
270
let store = |slot : & mut Option < Qualif > | {
@@ -281,28 +280,31 @@ impl<'a, 'tcx> Qualifier<'a, 'tcx, 'tcx> {
281
280
if self . mir . local_kind ( index) == LocalKind :: Temp
282
281
&& self . temp_promotion_state [ index] . is_promotable ( ) {
283
282
debug ! ( "store to promotable temp {:?}" , index) ;
284
- store ( & mut self . temp_qualif [ index] ) ;
283
+ store ( & mut self . local_qualif [ index] ) ;
285
284
}
286
285
}
287
286
return ;
288
287
}
289
288
290
289
match * dest {
291
- Place :: Local ( index) if self . mir . local_kind ( index) == LocalKind :: Temp => {
292
- debug ! ( "store to temp {:?}" , index) ;
293
- store ( & mut self . temp_qualif [ index] )
290
+ Place :: Local ( index) if ( self . mir . local_kind ( index) == LocalKind :: Var ||
291
+ self . mir . local_kind ( index) == LocalKind :: Arg ) &&
292
+ self . tcx . sess . features_untracked ( ) . const_let => {
293
+ debug ! ( "store to var {:?}" , index) ;
294
+ self . local_qualif [ index] = Some ( self . qualif ) ;
294
295
}
295
- Place :: Local ( index) if self . mir . local_kind ( index) == LocalKind :: ReturnPointer => {
296
- debug ! ( "store to return place {:?}" , index) ;
297
- store ( & mut self . return_qualif )
296
+ Place :: Local ( index) if self . mir . local_kind ( index) == LocalKind :: Temp ||
297
+ self . mir . local_kind ( index) == LocalKind :: ReturnPointer => {
298
+ debug ! ( "store to {:?} (temp or return pointer)" , index) ;
299
+ store ( & mut self . local_qualif [ index] )
298
300
}
299
301
300
302
Place :: Projection ( box Projection {
301
303
base : Place :: Local ( index) ,
302
304
elem : ProjectionElem :: Deref
303
305
} ) if self . mir . local_kind ( index) == LocalKind :: Temp
304
306
&& self . mir . local_decls [ index] . ty . is_box ( )
305
- && self . temp_qualif [ index] . map_or ( false , |qualif| {
307
+ && self . local_qualif [ index] . map_or ( false , |qualif| {
306
308
qualif. intersects ( Qualif :: NOT_CONST )
307
309
} ) => {
308
310
// Part of `box expr`, we should've errored
@@ -355,40 +357,42 @@ impl<'a, 'tcx> Qualifier<'a, 'tcx, 'tcx> {
355
357
TerminatorKind :: FalseUnwind { .. } => None ,
356
358
357
359
TerminatorKind :: Return => {
358
- // Check for unused values. This usually means
359
- // there are extra statements in the AST.
360
- for temp in mir. temps_iter ( ) {
361
- if self . temp_qualif [ temp] . is_none ( ) {
362
- continue ;
363
- }
364
-
365
- let state = self . temp_promotion_state [ temp] ;
366
- if let TempState :: Defined { location, uses : 0 } = state {
367
- let data = & mir[ location. block ] ;
368
- let stmt_idx = location. statement_index ;
369
-
370
- // Get the span for the initialization.
371
- let source_info = if stmt_idx < data. statements . len ( ) {
372
- data. statements [ stmt_idx] . source_info
373
- } else {
374
- data. terminator ( ) . source_info
375
- } ;
376
- self . span = source_info. span ;
360
+ if !self . tcx . sess . features_untracked ( ) . const_let {
361
+ // Check for unused values. This usually means
362
+ // there are extra statements in the AST.
363
+ for temp in mir. temps_iter ( ) {
364
+ if self . local_qualif [ temp] . is_none ( ) {
365
+ continue ;
366
+ }
377
367
378
- // Treat this as a statement in the AST.
379
- self . statement_like ( ) ;
368
+ let state = self . temp_promotion_state [ temp] ;
369
+ if let TempState :: Defined { location, uses : 0 } = state {
370
+ let data = & mir[ location. block ] ;
371
+ let stmt_idx = location. statement_index ;
372
+
373
+ // Get the span for the initialization.
374
+ let source_info = if stmt_idx < data. statements . len ( ) {
375
+ data. statements [ stmt_idx] . source_info
376
+ } else {
377
+ data. terminator ( ) . source_info
378
+ } ;
379
+ self . span = source_info. span ;
380
+
381
+ // Treat this as a statement in the AST.
382
+ self . statement_like ( ) ;
383
+ }
380
384
}
381
- }
382
385
383
- // Make sure there are no extra unassigned variables.
384
- self . qualif = Qualif :: NOT_CONST ;
385
- for index in mir. vars_iter ( ) {
386
- if !self . const_fn_arg_vars . contains ( index. index ( ) ) {
387
- debug ! ( "unassigned variable {:?}" , index) ;
388
- self . assign ( & Place :: Local ( index) , Location {
389
- block : bb,
390
- statement_index : usize:: MAX ,
391
- } ) ;
386
+ // Make sure there are no extra unassigned variables.
387
+ self . qualif = Qualif :: NOT_CONST ;
388
+ for index in mir. vars_iter ( ) {
389
+ if !self . const_fn_arg_vars . contains ( index. index ( ) ) {
390
+ debug ! ( "unassigned variable {:?}" , index) ;
391
+ self . assign ( & Place :: Local ( index) , Location {
392
+ block : bb,
393
+ statement_index : usize:: MAX ,
394
+ } ) ;
395
+ }
392
396
}
393
397
}
394
398
@@ -408,7 +412,7 @@ impl<'a, 'tcx> Qualifier<'a, 'tcx, 'tcx> {
408
412
}
409
413
}
410
414
411
- self . qualif = self . return_qualif . unwrap_or ( Qualif :: NOT_CONST ) ;
415
+ self . qualif = self . local_qualif [ RETURN_PLACE ] . unwrap_or ( Qualif :: NOT_CONST ) ;
412
416
413
417
// Account for errors in consts by using the
414
418
// conservative type qualification instead.
@@ -453,9 +457,15 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
453
457
LocalKind :: ReturnPointer => {
454
458
self . not_const ( ) ;
455
459
}
456
- LocalKind :: Var => {
460
+ LocalKind :: Var if !self . tcx . sess . features_untracked ( ) . const_let => {
461
+ if self . mode != Mode :: Fn {
462
+ emit_feature_err ( & self . tcx . sess . parse_sess , "const_let" ,
463
+ self . span , GateIssue :: Language ,
464
+ & format ! ( "let bindings in {}s are unstable" , self . mode) ) ;
465
+ }
457
466
self . add ( Qualif :: NOT_CONST ) ;
458
467
}
468
+ LocalKind :: Var |
459
469
LocalKind :: Arg |
460
470
LocalKind :: Temp => {
461
471
if let LocalKind :: Arg = kind {
@@ -466,7 +476,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
466
476
self . add ( Qualif :: NOT_PROMOTABLE ) ;
467
477
}
468
478
469
- if let Some ( qualif) = self . temp_qualif [ local] {
479
+ if let Some ( qualif) = self . local_qualif [ local] {
470
480
self . add ( qualif) ;
471
481
} else {
472
482
self . not_const ( ) ;
@@ -588,7 +598,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
588
598
589
599
// Mark the consumed locals to indicate later drops are noops.
590
600
if let Operand :: Move ( Place :: Local ( local) ) = * operand {
591
- self . temp_qualif [ local] = self . temp_qualif [ local] . map ( |q|
601
+ self . local_qualif [ local] = self . local_qualif [ local] . map ( |q|
592
602
q - Qualif :: NEEDS_DROP
593
603
) ;
594
604
}
@@ -759,7 +769,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
759
769
}
760
770
if let Place :: Local ( local) = * place {
761
771
if self . mir . local_kind ( local) == LocalKind :: Temp {
762
- if let Some ( qualif) = self . temp_qualif [ local] {
772
+ if let Some ( qualif) = self . local_qualif [ local] {
763
773
// `forbidden_mut` is false, so we can safely ignore
764
774
// `MUTABLE_INTERIOR` from the local's qualifications.
765
775
// This allows borrowing fields which don't have
@@ -1033,7 +1043,7 @@ This does not pose a problem by itself because they can't be accessed directly."
1033
1043
// HACK(eddyb) Emulate a bit of dataflow analysis,
1034
1044
// conservatively, that drop elaboration will do.
1035
1045
let needs_drop = if let Place :: Local ( local) = * place {
1036
- if self . temp_qualif [ local] . map_or ( true , |q| q. intersects ( Qualif :: NEEDS_DROP ) ) {
1046
+ if self . local_qualif [ local] . map_or ( true , |q| q. intersects ( Qualif :: NEEDS_DROP ) ) {
1037
1047
Some ( self . mir . local_decls [ local] . source_info . span )
1038
1048
} else {
1039
1049
None
@@ -1070,7 +1080,8 @@ This does not pose a problem by itself because they can't be accessed directly."
1070
1080
// Check the allowed const fn argument forms.
1071
1081
if let ( Mode :: ConstFn , & Place :: Local ( index) ) = ( self . mode , dest) {
1072
1082
if self . mir . local_kind ( index) == LocalKind :: Var &&
1073
- self . const_fn_arg_vars . insert ( index. index ( ) ) {
1083
+ self . const_fn_arg_vars . insert ( index. index ( ) ) &&
1084
+ !self . tcx . sess . features_untracked ( ) . const_let {
1074
1085
1075
1086
// Direct use of an argument is permitted.
1076
1087
match * rvalue {
@@ -1086,10 +1097,11 @@ This does not pose a problem by itself because they can't be accessed directly."
1086
1097
// Avoid a generic error for other uses of arguments.
1087
1098
if self . qualif . intersects ( Qualif :: FN_ARGUMENT ) {
1088
1099
let decl = & self . mir . local_decls [ index] ;
1089
- let mut err = struct_span_err ! (
1090
- self . tcx. sess,
1100
+ let mut err = feature_err (
1101
+ & self . tcx . sess . parse_sess ,
1102
+ "const_let" ,
1091
1103
decl. source_info . span ,
1092
- E0022 ,
1104
+ GateIssue :: Language ,
1093
1105
"arguments of constant functions can only be immutable by-value bindings"
1094
1106
) ;
1095
1107
if self . tcx . sess . teach ( & err. get_code ( ) . unwrap ( ) ) {
0 commit comments