@@ -32,7 +32,7 @@ use rustc::middle::lang_items;
3232use rustc_target:: spec:: abi:: Abi ;
3333use syntax:: attr;
3434use syntax:: ast:: LitKind ;
35- use syntax:: feature_gate:: UnstableFeatures ;
35+ use syntax:: feature_gate:: { UnstableFeatures , feature_err , emit_feature_err , GateIssue } ;
3636use syntax_pos:: { Span , DUMMY_SP } ;
3737
3838use std:: fmt;
@@ -120,8 +120,7 @@ struct Qualifier<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
120120 rpo : ReversePostorder < ' a , ' tcx > ,
121121 tcx : TyCtxt < ' a , ' gcx , ' tcx > ,
122122 param_env : ty:: ParamEnv < ' tcx > ,
123- temp_qualif : IndexVec < Local , Option < Qualif > > ,
124- return_qualif : Option < Qualif > ,
123+ local_qualif : IndexVec < Local , Option < Qualif > > ,
125124 qualif : Qualif ,
126125 const_fn_arg_vars : BitVector ,
127126 temp_promotion_state : IndexVec < Local , TempState > ,
@@ -140,11 +139,11 @@ impl<'a, 'tcx> Qualifier<'a, 'tcx, 'tcx> {
140139
141140 let param_env = tcx. param_env ( def_id) ;
142141
143- let mut temp_qualif = IndexVec :: from_elem ( None , & mir. local_decls ) ;
142+ let mut local_qualif = IndexVec :: from_elem ( None , & mir. local_decls ) ;
144143 for arg in mir. args_iter ( ) {
145144 let mut qualif = Qualif :: NEEDS_DROP ;
146145 qualif. restrict ( mir. local_decls [ arg] . ty , tcx, param_env) ;
147- temp_qualif [ arg] = Some ( qualif) ;
146+ local_qualif [ arg] = Some ( qualif) ;
148147 }
149148
150149 Qualifier {
@@ -155,8 +154,7 @@ impl<'a, 'tcx> Qualifier<'a, 'tcx, 'tcx> {
155154 rpo,
156155 tcx,
157156 param_env,
158- temp_qualif,
159- return_qualif : None ,
157+ local_qualif,
160158 qualif : Qualif :: empty ( ) ,
161159 const_fn_arg_vars : BitVector :: new ( mir. local_decls . len ( ) ) ,
162160 temp_promotion_state : temps,
@@ -191,12 +189,12 @@ impl<'a, 'tcx> Qualifier<'a, 'tcx, 'tcx> {
191189 fn statement_like ( & mut self ) {
192190 self . add ( Qualif :: NOT_CONST ) ;
193191 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" ,
196195 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) ,
200198 ) ;
201199 if self . tcx . sess . teach ( & err. get_code ( ) . unwrap ( ) ) {
202200 err. note ( "Blocks in constants may only contain items (such as constant, function \
@@ -266,6 +264,7 @@ impl<'a, 'tcx> Qualifier<'a, 'tcx, 'tcx> {
266264
267265 /// Assign the current qualification to the given destination.
268266 fn assign ( & mut self , dest : & Place < ' tcx > , location : Location ) {
267+ trace ! ( "assign: {:?}" , dest) ;
269268 let qualif = self . qualif ;
270269 let span = self . span ;
271270 let store = |slot : & mut Option < Qualif > | {
@@ -281,28 +280,31 @@ impl<'a, 'tcx> Qualifier<'a, 'tcx, 'tcx> {
281280 if self . mir . local_kind ( index) == LocalKind :: Temp
282281 && self . temp_promotion_state [ index] . is_promotable ( ) {
283282 debug ! ( "store to promotable temp {:?}" , index) ;
284- store ( & mut self . temp_qualif [ index] ) ;
283+ store ( & mut self . local_qualif [ index] ) ;
285284 }
286285 }
287286 return ;
288287 }
289288
290289 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 ) ;
294295 }
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] )
298300 }
299301
300302 Place :: Projection ( box Projection {
301303 base : Place :: Local ( index) ,
302304 elem : ProjectionElem :: Deref
303305 } ) if self . mir . local_kind ( index) == LocalKind :: Temp
304306 && 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| {
306308 qualif. intersects ( Qualif :: NOT_CONST )
307309 } ) => {
308310 // Part of `box expr`, we should've errored
@@ -355,40 +357,42 @@ impl<'a, 'tcx> Qualifier<'a, 'tcx, 'tcx> {
355357 TerminatorKind :: FalseUnwind { .. } => None ,
356358
357359 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+ }
377367
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+ }
380384 }
381- }
382385
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+ }
392396 }
393397 }
394398
@@ -408,7 +412,7 @@ impl<'a, 'tcx> Qualifier<'a, 'tcx, 'tcx> {
408412 }
409413 }
410414
411- self . qualif = self . return_qualif . unwrap_or ( Qualif :: NOT_CONST ) ;
415+ self . qualif = self . local_qualif [ RETURN_PLACE ] . unwrap_or ( Qualif :: NOT_CONST ) ;
412416
413417 // Account for errors in consts by using the
414418 // conservative type qualification instead.
@@ -453,9 +457,15 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
453457 LocalKind :: ReturnPointer => {
454458 self . not_const ( ) ;
455459 }
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+ }
457466 self . add ( Qualif :: NOT_CONST ) ;
458467 }
468+ LocalKind :: Var |
459469 LocalKind :: Arg |
460470 LocalKind :: Temp => {
461471 if let LocalKind :: Arg = kind {
@@ -466,7 +476,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
466476 self . add ( Qualif :: NOT_PROMOTABLE ) ;
467477 }
468478
469- if let Some ( qualif) = self . temp_qualif [ local] {
479+ if let Some ( qualif) = self . local_qualif [ local] {
470480 self . add ( qualif) ;
471481 } else {
472482 self . not_const ( ) ;
@@ -588,7 +598,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
588598
589599 // Mark the consumed locals to indicate later drops are noops.
590600 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|
592602 q - Qualif :: NEEDS_DROP
593603 ) ;
594604 }
@@ -759,7 +769,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
759769 }
760770 if let Place :: Local ( local) = * place {
761771 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] {
763773 // `forbidden_mut` is false, so we can safely ignore
764774 // `MUTABLE_INTERIOR` from the local's qualifications.
765775 // 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."
10331043 // HACK(eddyb) Emulate a bit of dataflow analysis,
10341044 // conservatively, that drop elaboration will do.
10351045 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 ) ) {
10371047 Some ( self . mir . local_decls [ local] . source_info . span )
10381048 } else {
10391049 None
@@ -1070,7 +1080,8 @@ This does not pose a problem by itself because they can't be accessed directly."
10701080 // Check the allowed const fn argument forms.
10711081 if let ( Mode :: ConstFn , & Place :: Local ( index) ) = ( self . mode , dest) {
10721082 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 {
10741085
10751086 // Direct use of an argument is permitted.
10761087 match * rvalue {
@@ -1086,10 +1097,11 @@ This does not pose a problem by itself because they can't be accessed directly."
10861097 // Avoid a generic error for other uses of arguments.
10871098 if self . qualif . intersects ( Qualif :: FN_ARGUMENT ) {
10881099 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" ,
10911103 decl. source_info . span ,
1092- E0022 ,
1104+ GateIssue :: Language ,
10931105 "arguments of constant functions can only be immutable by-value bindings"
10941106 ) ;
10951107 if self . tcx . sess . teach ( & err. get_code ( ) . unwrap ( ) ) {
0 commit comments