@@ -70,24 +70,26 @@ pub struct Mir<'tcx> {
70
70
71
71
/// Rvalues promoted from this function, such as borrows of constants.
72
72
/// Each of them is the Mir of a constant with the fn's type parameters
73
- /// in scope, but no vars or args and a separate set of temps .
73
+ /// in scope, but a separate set of locals .
74
74
pub promoted : IndexVec < Promoted , Mir < ' tcx > > ,
75
75
76
76
/// Return type of the function.
77
77
pub return_ty : Ty < ' tcx > ,
78
78
79
- /// Variables: these are stack slots corresponding to user variables. They may be
80
- /// assigned many times.
81
- pub var_decls : IndexVec < Var , VarDecl < ' tcx > > ,
82
-
83
- /// Args: these are stack slots corresponding to the input arguments .
84
- pub arg_decls : IndexVec < Arg , ArgDecl < ' tcx > > ,
79
+ /// Declarations of locals.
80
+ ///
81
+ /// The first local is the return value pointer, followed by `arg_count`
82
+ /// locals for the function arguments, followed by any user-declared
83
+ /// variables and temporaries .
84
+ pub local_decls : IndexVec < Local , LocalDecl < ' tcx > > ,
85
85
86
- /// Temp declarations: stack slots that for temporaries created by
87
- /// the compiler. These are assigned once, but they are not SSA
88
- /// values in that it is possible to borrow them and mutate them
89
- /// through the resulting reference.
90
- pub temp_decls : IndexVec < Temp , TempDecl < ' tcx > > ,
86
+ /// Number of arguments this function takes.
87
+ ///
88
+ /// Starting at local1, `arg_count` locals will be provided by the caller
89
+ /// and can be assumed to be initialized.
90
+ ///
91
+ /// If this MIR was built for a constant, this will be 0.
92
+ pub arg_count : usize ,
91
93
92
94
/// Names and capture modes of all the closure upvars, assuming
93
95
/// the first argument is either the closure or a reference to it.
@@ -114,20 +116,23 @@ impl<'tcx> Mir<'tcx> {
114
116
visibility_scopes : IndexVec < VisibilityScope , VisibilityScopeData > ,
115
117
promoted : IndexVec < Promoted , Mir < ' tcx > > ,
116
118
return_ty : Ty < ' tcx > ,
117
- var_decls : IndexVec < Var , VarDecl < ' tcx > > ,
118
- arg_decls : IndexVec < Arg , ArgDecl < ' tcx > > ,
119
- temp_decls : IndexVec < Temp , TempDecl < ' tcx > > ,
119
+ local_decls : IndexVec < Local , LocalDecl < ' tcx > > ,
120
+ arg_count : usize ,
120
121
upvar_decls : Vec < UpvarDecl > ,
121
122
span : Span ) -> Self
122
123
{
124
+ // We need `arg_count` locals, and one for the return pointer
125
+ assert ! ( local_decls. len( ) >= arg_count + 1 ,
126
+ "expected at least {} locals, got {}" , arg_count + 1 , local_decls. len( ) ) ;
127
+ assert_eq ! ( local_decls[ RETURN_POINTER ] . ty, return_ty) ;
128
+
123
129
Mir {
124
130
basic_blocks : basic_blocks,
125
131
visibility_scopes : visibility_scopes,
126
132
promoted : promoted,
127
133
return_ty : return_ty,
128
- var_decls : var_decls,
129
- arg_decls : arg_decls,
130
- temp_decls : temp_decls,
134
+ local_decls : local_decls,
135
+ arg_count : arg_count,
131
136
upvar_decls : upvar_decls,
132
137
spread_last_arg : false ,
133
138
span : span,
@@ -161,56 +166,63 @@ impl<'tcx> Mir<'tcx> {
161
166
dominators ( self )
162
167
}
163
168
164
- /// Maps locals (Arg's, Var's, Temp's and ReturnPointer, in that order)
165
- /// to their index in the whole list of locals. This is useful if you
166
- /// want to treat all locals the same instead of repeating yourself.
167
- pub fn local_index ( & self , lvalue : & Lvalue < ' tcx > ) -> Option < Local > {
168
- let idx = match * lvalue {
169
- Lvalue :: Arg ( arg) => arg. index ( ) ,
170
- Lvalue :: Var ( var) => {
171
- self . arg_decls . len ( ) +
172
- var. index ( )
173
- }
174
- Lvalue :: Temp ( temp) => {
175
- self . arg_decls . len ( ) +
176
- self . var_decls . len ( ) +
177
- temp. index ( )
169
+ #[ inline]
170
+ pub fn local_kind ( & self , local : Local ) -> LocalKind {
171
+ let index = local. 0 as usize ;
172
+ if index == 0 {
173
+ debug_assert ! ( self . local_decls[ local] . mutability == Mutability :: Mut ,
174
+ "return pointer should be mutable" ) ;
175
+
176
+ LocalKind :: ReturnPointer
177
+ } else if index < self . arg_count + 1 {
178
+ LocalKind :: Arg
179
+ } else if self . local_decls [ local] . name . is_some ( ) {
180
+ LocalKind :: Var
181
+ } else {
182
+ debug_assert ! ( self . local_decls[ local] . mutability == Mutability :: Mut ,
183
+ "temp should be mutable" ) ;
184
+
185
+ LocalKind :: Temp
186
+ }
187
+ }
188
+
189
+ /// Returns an iterator over all temporaries.
190
+ #[ inline]
191
+ pub fn temp_iter < ' a > ( & ' a self ) -> impl Iterator < Item =Local > + ' a {
192
+ ( self . arg_count +1 ..self . local_decls . len ( ) ) . filter_map ( move |index| {
193
+ let local = Local :: new ( index) ;
194
+ if self . local_decls [ local] . source_info . is_none ( ) {
195
+ Some ( local)
196
+ } else {
197
+ None
178
198
}
179
- Lvalue :: ReturnPointer => {
180
- self . arg_decls . len ( ) +
181
- self . var_decls . len ( ) +
182
- self . temp_decls . len ( )
199
+ } )
200
+ }
201
+
202
+ /// Returns an iterator over all user-declared locals.
203
+ #[ inline]
204
+ pub fn var_iter < ' a > ( & ' a self ) -> impl Iterator < Item =Local > + ' a {
205
+ ( self . arg_count +1 ..self . local_decls . len ( ) ) . filter_map ( move |index| {
206
+ let local = Local :: new ( index) ;
207
+ if self . local_decls [ local] . source_info . is_none ( ) {
208
+ None
209
+ } else {
210
+ Some ( local)
183
211
}
184
- Lvalue :: Static ( _) |
185
- Lvalue :: Projection ( _) => return None
186
- } ;
187
- Some ( Local :: new ( idx) )
212
+ } )
188
213
}
189
214
190
- /// Counts the number of locals, such that local_index
191
- /// will always return an index smaller than this count.
192
- pub fn count_locals ( & self ) -> usize {
193
- self . arg_decls . len ( ) +
194
- self . var_decls . len ( ) +
195
- self . temp_decls . len ( ) + 1
215
+ /// Returns an iterator over all function arguments.
216
+ #[ inline]
217
+ pub fn arg_iter < ' a > ( & ' a self ) -> impl Iterator < Item =Local > + ' a {
218
+ ( 1 ..self . arg_count +1 ) . map ( Local :: new)
196
219
}
197
220
198
- pub fn format_local ( & self , local : Local ) -> String {
199
- let mut index = local. index ( ) ;
200
- index = match index. checked_sub ( self . arg_decls . len ( ) ) {
201
- None => return format ! ( "{:?}" , Arg :: new( index) ) ,
202
- Some ( index) => index,
203
- } ;
204
- index = match index. checked_sub ( self . var_decls . len ( ) ) {
205
- None => return format ! ( "{:?}" , Var :: new( index) ) ,
206
- Some ( index) => index,
207
- } ;
208
- index = match index. checked_sub ( self . temp_decls . len ( ) ) {
209
- None => return format ! ( "{:?}" , Temp :: new( index) ) ,
210
- Some ( index) => index,
211
- } ;
212
- debug_assert ! ( index == 0 ) ;
213
- return "ReturnPointer" . to_string ( )
221
+ /// Returns an iterator over all user-defined variables and compiler-generated temporaries (all
222
+ /// locals that are neither arguments nor the return pointer).
223
+ #[ inline]
224
+ pub fn var_and_temp_iter < ' a > ( & ' a self ) -> impl Iterator < Item =Local > + ' a {
225
+ ( self . arg_count +1 ..self . local_decls . len ( ) ) . map ( Local :: new)
214
226
}
215
227
216
228
/// Changes a statement to a nop. This is both faster than deleting instructions and avoids
@@ -308,49 +320,76 @@ pub enum BorrowKind {
308
320
///////////////////////////////////////////////////////////////////////////
309
321
// Variables and temps
310
322
311
- /// A "variable" is a binding declared by the user as part of the fn
312
- /// decl, a let, etc.
323
+ newtype_index ! ( Local , "local" ) ;
324
+
325
+ pub const RETURN_POINTER : Local = Local ( 0 ) ;
326
+
327
+ /// Classifies locals into categories. See `Mir::local_kind`.
328
+ #[ derive( PartialEq , Eq , Debug ) ]
329
+ pub enum LocalKind {
330
+ /// User-declared variable binding
331
+ Var ,
332
+ /// Compiler-introduced temporary
333
+ Temp ,
334
+ /// Function argument
335
+ Arg ,
336
+ /// Location of function's return value
337
+ ReturnPointer ,
338
+ }
339
+
340
+ /// A MIR local.
341
+ ///
342
+ /// This can be a binding declared by the user, a temporary inserted by the compiler, a function
343
+ /// argument, or the return pointer.
313
344
#[ derive( Clone , Debug , RustcEncodable , RustcDecodable ) ]
314
- pub struct VarDecl < ' tcx > {
315
- /// `let mut x` vs `let x`
345
+ pub struct LocalDecl < ' tcx > {
346
+ /// `let mut x` vs `let x`.
347
+ ///
348
+ /// Temporaries and the return pointer are always mutable.
316
349
pub mutability : Mutability ,
317
350
318
- /// name that user gave the variable; not that, internally,
319
- /// mir references variables by index
320
- pub name : Name ,
321
-
322
- /// type inferred for this variable (`let x: ty = ...`)
351
+ /// Type of this local.
323
352
pub ty : Ty < ' tcx > ,
324
353
325
- /// source information (span, scope, etc.) for the declaration
326
- pub source_info : SourceInfo ,
327
- }
354
+ /// Name of the local, used in debuginfo and pretty-printing.
355
+ ///
356
+ /// Note that function arguments can also have this set to `Some(_)`
357
+ /// to generate better debuginfo.
358
+ pub name : Option < Name > ,
328
359
329
- /// A "temp" is a temporary that we place on the stack. They are
330
- /// anonymous, always mutable, and have only a type.
331
- #[ derive( Clone , Debug , RustcEncodable , RustcDecodable ) ]
332
- pub struct TempDecl < ' tcx > {
333
- pub ty : Ty < ' tcx > ,
360
+ /// For user-declared variables, stores their source information.
361
+ ///
362
+ /// For temporaries, this is `None`.
363
+ ///
364
+ /// This is the primary way to differentiate between user-declared
365
+ /// variables and compiler-generated temporaries.
366
+ pub source_info : Option < SourceInfo > ,
334
367
}
335
368
336
- /// A "arg" is one of the function's formal arguments. These are
337
- /// anonymous and distinct from the bindings that the user declares.
338
- ///
339
- /// For example, in this function:
340
- ///
341
- /// ```
342
- /// fn foo((x, y): (i32, u32)) { ... }
343
- /// ```
344
- ///
345
- /// there is only one argument, of type `(i32, u32)`, but two bindings
346
- /// (`x` and `y`).
347
- #[ derive( Clone , Debug , RustcEncodable , RustcDecodable ) ]
348
- pub struct ArgDecl < ' tcx > {
349
- pub ty : Ty < ' tcx > ,
369
+ impl < ' tcx > LocalDecl < ' tcx > {
370
+ /// Create a new `LocalDecl` for a temporary.
371
+ #[ inline]
372
+ pub fn new_temp ( ty : Ty < ' tcx > ) -> Self {
373
+ LocalDecl {
374
+ mutability : Mutability :: Mut ,
375
+ ty : ty,
376
+ name : None ,
377
+ source_info : None ,
378
+ }
379
+ }
350
380
351
- /// Either keywords::Invalid or the name of a single-binding
352
- /// pattern associated with this argument. Useful for debuginfo.
353
- pub debug_name : Name
381
+ /// Builds a `LocalDecl` for the return pointer.
382
+ ///
383
+ /// This must be inserted into the `local_decls` list as the first local.
384
+ #[ inline]
385
+ pub fn new_return_pointer ( return_ty : Ty ) -> LocalDecl {
386
+ LocalDecl {
387
+ mutability : Mutability :: Mut ,
388
+ ty : return_ty,
389
+ source_info : None ,
390
+ name : None , // FIXME maybe we do want some name here?
391
+ }
392
+ }
354
393
}
355
394
356
395
/// A closure capture, with its name and mode.
@@ -442,7 +481,7 @@ pub enum TerminatorKind<'tcx> {
442
481
/// continue. Emitted by build::scope::diverge_cleanup.
443
482
Resume ,
444
483
445
- /// Indicates a normal return. The ReturnPointer lvalue should
484
+ /// Indicates a normal return. The return pointer lvalue should
446
485
/// have been filled in by now. This should occur at most once.
447
486
Return ,
448
487
@@ -759,31 +798,16 @@ impl<'tcx> Debug for Statement<'tcx> {
759
798
///////////////////////////////////////////////////////////////////////////
760
799
// Lvalues
761
800
762
- newtype_index ! ( Var , "var" ) ;
763
- newtype_index ! ( Temp , "tmp" ) ;
764
- newtype_index ! ( Arg , "arg" ) ;
765
- newtype_index ! ( Local , "local" ) ;
766
-
767
801
/// A path to a value; something that can be evaluated without
768
802
/// changing or disturbing program state.
769
803
#[ derive( Clone , PartialEq , RustcEncodable , RustcDecodable ) ]
770
804
pub enum Lvalue < ' tcx > {
771
- /// local variable declared by the user
772
- Var ( Var ) ,
773
-
774
- /// temporary introduced during lowering into MIR
775
- Temp ( Temp ) ,
776
-
777
- /// formal parameter of the function; note that these are NOT the
778
- /// bindings that the user declares, which are vars
779
- Arg ( Arg ) ,
805
+ /// local variable
806
+ Local ( Local ) ,
780
807
781
808
/// static or static mut variable
782
809
Static ( DefId ) ,
783
810
784
- /// the return pointer of the fn
785
- ReturnPointer ,
786
-
787
811
/// projection out of an lvalue (access a field, deref a pointer, etc)
788
812
Projection ( Box < LvalueProjection < ' tcx > > ) ,
789
813
}
@@ -865,38 +889,16 @@ impl<'tcx> Lvalue<'tcx> {
865
889
elem : elem,
866
890
} ) )
867
891
}
868
-
869
- pub fn from_local ( mir : & Mir < ' tcx > , local : Local ) -> Lvalue < ' tcx > {
870
- let mut index = local. index ( ) ;
871
- index = match index. checked_sub ( mir. arg_decls . len ( ) ) {
872
- None => return Lvalue :: Arg ( Arg ( index as u32 ) ) ,
873
- Some ( index) => index,
874
- } ;
875
- index = match index. checked_sub ( mir. var_decls . len ( ) ) {
876
- None => return Lvalue :: Var ( Var ( index as u32 ) ) ,
877
- Some ( index) => index,
878
- } ;
879
- index = match index. checked_sub ( mir. temp_decls . len ( ) ) {
880
- None => return Lvalue :: Temp ( Temp ( index as u32 ) ) ,
881
- Some ( index) => index,
882
- } ;
883
- debug_assert ! ( index == 0 ) ;
884
- Lvalue :: ReturnPointer
885
- }
886
892
}
887
893
888
894
impl < ' tcx > Debug for Lvalue < ' tcx > {
889
895
fn fmt ( & self , fmt : & mut Formatter ) -> fmt:: Result {
890
896
use self :: Lvalue :: * ;
891
897
892
898
match * self {
893
- Var ( id) => write ! ( fmt, "{:?}" , id) ,
894
- Arg ( id) => write ! ( fmt, "{:?}" , id) ,
895
- Temp ( id) => write ! ( fmt, "{:?}" , id) ,
899
+ Local ( id) => write ! ( fmt, "{:?}" , id) ,
896
900
Static ( def_id) =>
897
901
write ! ( fmt, "{}" , ty:: tls:: with( |tcx| tcx. item_path_str( def_id) ) ) ,
898
- ReturnPointer =>
899
- write ! ( fmt, "return" ) ,
900
902
Projection ( ref data) =>
901
903
match data. elem {
902
904
ProjectionElem :: Downcast ( ref adt_def, index) =>
0 commit comments