@@ -15,7 +15,7 @@ use std::iter;
15
15
use syntax:: codemap:: { self , DUMMY_SP } ;
16
16
17
17
use error:: { EvalError , EvalResult } ;
18
- use memory:: { Memory , Pointer } ;
18
+ use memory:: { Memory , Pointer , AllocId } ;
19
19
use primval:: { self , PrimVal } ;
20
20
21
21
use std:: collections:: HashMap ;
@@ -74,7 +74,7 @@ pub struct Frame<'a, 'tcx: 'a> {
74
74
pub return_ptr : Option < Pointer > ,
75
75
76
76
/// The block to return to when returning from the current stack frame
77
- pub return_to_block : Option < mir :: BasicBlock > ,
77
+ pub return_to_block : StackPopCleanup ,
78
78
79
79
/// The list of locals for the current function, stored in order as
80
80
/// `[arguments..., variables..., temporaries...]`. The variables begin at `self.var_offset`
@@ -139,6 +139,18 @@ enum ConstantKind {
139
139
Global ,
140
140
}
141
141
142
+ #[ derive( Clone , Debug , Eq , PartialEq , Hash ) ]
143
+ pub enum StackPopCleanup {
144
+ /// The stackframe existed to compute the initial value of a static/constant, make sure the
145
+ /// static isn't modifyable afterwards
146
+ Freeze ( AllocId ) ,
147
+ /// A regular stackframe added due to a function call will need to get forwarded to the next
148
+ /// block
149
+ Goto ( mir:: BasicBlock ) ,
150
+ /// The main function and diverging functions have nowhere to return to
151
+ None ,
152
+ }
153
+
142
154
impl < ' a , ' tcx > EvalContext < ' a , ' tcx > {
143
155
pub fn new ( tcx : TyCtxt < ' a , ' tcx , ' tcx > , mir_map : & ' a MirMap < ' tcx > , memory_size : usize , stack_limit : usize ) -> Self {
144
156
EvalContext {
@@ -313,7 +325,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
313
325
mir : CachedMir < ' a , ' tcx > ,
314
326
substs : & ' tcx Substs < ' tcx > ,
315
327
return_ptr : Option < Pointer > ,
316
- return_to_block : Option < mir :: BasicBlock > ,
328
+ return_to_block : StackPopCleanup ,
317
329
) -> EvalResult < ' tcx , ( ) > {
318
330
let arg_tys = mir. arg_decls . iter ( ) . map ( |a| a. ty ) ;
319
331
let var_tys = mir. var_decls . iter ( ) . map ( |v| v. ty ) ;
@@ -350,13 +362,16 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
350
362
}
351
363
}
352
364
353
- fn pop_stack_frame ( & mut self ) {
365
+ fn pop_stack_frame ( & mut self ) -> EvalResult < ' tcx , ( ) > {
354
366
:: log_settings:: settings ( ) . indentation -= 1 ;
355
367
let frame = self . stack . pop ( ) . expect ( "tried to pop a stack frame, but there were none" ) ;
356
- if let Some ( target) = frame. return_to_block {
357
- self . goto_block ( target) ;
368
+ match frame. return_to_block {
369
+ StackPopCleanup :: Freeze ( alloc_id) => self . memory . freeze ( alloc_id) ?,
370
+ StackPopCleanup :: Goto ( target) => self . goto_block ( target) ,
371
+ StackPopCleanup :: None => { } ,
358
372
}
359
373
// TODO(solson): Deallocate local variables.
374
+ Ok ( ( ) )
360
375
}
361
376
362
377
/// Applies the binary operation `op` to the two operands and writes a tuple of the result
@@ -1036,7 +1051,7 @@ pub fn eval_main<'a, 'tcx: 'a>(
1036
1051
let return_ptr = ecx. alloc_ret_ptr ( mir. return_ty , substs)
1037
1052
. expect ( "should at least be able to allocate space for the main function's return value" ) ;
1038
1053
1039
- ecx. push_stack_frame ( def_id, mir. span , CachedMir :: Ref ( mir) , substs, Some ( return_ptr) , None )
1054
+ ecx. push_stack_frame ( def_id, mir. span , CachedMir :: Ref ( mir) , substs, Some ( return_ptr) , StackPopCleanup :: None )
1040
1055
. expect ( "could not allocate first stack frame" ) ;
1041
1056
1042
1057
if mir. arg_decls . len ( ) == 2 {
0 commit comments