@@ -70,29 +70,37 @@ pub struct Mir<'tcx> {
7070
7171 /// Rvalues promoted from this function, such as borrows of constants.
7272 /// 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 .
7474 pub promoted : IndexVec < Promoted , Mir < ' tcx > > ,
7575
7676 /// Return type of the function.
7777 pub return_ty : Ty < ' tcx > ,
7878
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 > > ,
8585
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 local 1, `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 ,
9193
9294 /// Names and capture modes of all the closure upvars, assuming
9395 /// the first argument is either the closure or a reference to it.
9496 pub upvar_decls : Vec < UpvarDecl > ,
9597
98+ /// Mark an argument local (which must be a tuple) as getting passed as
99+ /// its individual components at the LLVM level.
100+ ///
101+ /// This is used for the "rust-call" ABI.
102+ pub spread_arg : Option < Local > ,
103+
96104 /// A span representing this MIR, for error reporting
97105 pub span : Span ,
98106
@@ -108,21 +116,25 @@ impl<'tcx> Mir<'tcx> {
108116 visibility_scopes : IndexVec < VisibilityScope , VisibilityScopeData > ,
109117 promoted : IndexVec < Promoted , Mir < ' tcx > > ,
110118 return_ty : Ty < ' tcx > ,
111- var_decls : IndexVec < Var , VarDecl < ' tcx > > ,
112- arg_decls : IndexVec < Arg , ArgDecl < ' tcx > > ,
113- temp_decls : IndexVec < Temp , TempDecl < ' tcx > > ,
119+ local_decls : IndexVec < Local , LocalDecl < ' tcx > > ,
120+ arg_count : usize ,
114121 upvar_decls : Vec < UpvarDecl > ,
115122 span : Span ) -> Self
116123 {
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+
117129 Mir {
118130 basic_blocks : basic_blocks,
119131 visibility_scopes : visibility_scopes,
120132 promoted : promoted,
121133 return_ty : return_ty,
122- var_decls : var_decls,
123- arg_decls : arg_decls,
124- temp_decls : temp_decls,
134+ local_decls : local_decls,
135+ arg_count : arg_count,
125136 upvar_decls : upvar_decls,
137+ spread_arg : None ,
126138 span : span,
127139 cache : Cache :: new ( )
128140 }
@@ -154,56 +166,66 @@ impl<'tcx> Mir<'tcx> {
154166 dominators ( self )
155167 }
156168
157- /// Maps locals (Arg's, Var's, Temp's and ReturnPointer, in that order)
158- /// to their index in the whole list of locals. This is useful if you
159- /// want to treat all locals the same instead of repeating yourself.
160- pub fn local_index ( & self , lvalue : & Lvalue < ' tcx > ) -> Option < Local > {
161- let idx = match * lvalue {
162- Lvalue :: Arg ( arg) => arg. index ( ) ,
163- Lvalue :: Var ( var) => {
164- self . arg_decls . len ( ) +
165- var. index ( )
166- }
167- Lvalue :: Temp ( temp) => {
168- self . arg_decls . len ( ) +
169- self . var_decls . len ( ) +
170- 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 temps_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
171198 }
172- Lvalue :: ReturnPointer => {
173- self . arg_decls . len ( ) +
174- self . var_decls . len ( ) +
175- self . temp_decls . len ( )
199+ } )
200+ }
201+
202+ /// Returns an iterator over all user-declared locals.
203+ #[ inline]
204+ pub fn vars_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)
176211 }
177- Lvalue :: Static ( _) |
178- Lvalue :: Projection ( _) => return None
179- } ;
180- Some ( Local :: new ( idx) )
212+ } )
181213 }
182214
183- /// Counts the number of locals, such that local_index
184- /// will always return an index smaller than this count.
185- pub fn count_locals ( & self ) -> usize {
186- self . arg_decls . len ( ) +
187- self . var_decls . len ( ) +
188- self . temp_decls . len ( ) + 1
215+ /// Returns an iterator over all function arguments.
216+ #[ inline]
217+ pub fn args_iter ( & self ) -> impl Iterator < Item =Local > {
218+ let arg_count = self . arg_count ;
219+ ( 1 ..arg_count+1 ) . map ( Local :: new)
189220 }
190221
191- pub fn format_local ( & self , local : Local ) -> String {
192- let mut index = local. index ( ) ;
193- index = match index. checked_sub ( self . arg_decls . len ( ) ) {
194- None => return format ! ( "{:?}" , Arg :: new( index) ) ,
195- Some ( index) => index,
196- } ;
197- index = match index. checked_sub ( self . var_decls . len ( ) ) {
198- None => return format ! ( "{:?}" , Var :: new( index) ) ,
199- Some ( index) => index,
200- } ;
201- index = match index. checked_sub ( self . temp_decls . len ( ) ) {
202- None => return format ! ( "{:?}" , Temp :: new( index) ) ,
203- Some ( index) => index,
204- } ;
205- debug_assert ! ( index == 0 ) ;
206- return "ReturnPointer" . to_string ( )
222+ /// Returns an iterator over all user-defined variables and compiler-generated temporaries (all
223+ /// locals that are neither arguments nor the return pointer).
224+ #[ inline]
225+ pub fn vars_and_temps_iter ( & self ) -> impl Iterator < Item =Local > {
226+ let arg_count = self . arg_count ;
227+ let local_count = self . local_decls . len ( ) ;
228+ ( arg_count+1 ..local_count) . map ( Local :: new)
207229 }
208230
209231 /// Changes a statement to a nop. This is both faster than deleting instructions and avoids
@@ -301,53 +323,76 @@ pub enum BorrowKind {
301323///////////////////////////////////////////////////////////////////////////
302324// Variables and temps
303325
304- /// A "variable" is a binding declared by the user as part of the fn
305- /// decl, a let, etc.
306- #[ derive( Clone , Debug , RustcEncodable , RustcDecodable ) ]
307- pub struct VarDecl < ' tcx > {
308- /// `let mut x` vs `let x`
309- pub mutability : Mutability ,
310-
311- /// name that user gave the variable; not that, internally,
312- /// mir references variables by index
313- pub name : Name ,
326+ newtype_index ! ( Local , "_" ) ;
314327
315- /// type inferred for this variable (`let x: ty = ...`)
316- pub ty : Ty < ' tcx > ,
328+ pub const RETURN_POINTER : Local = Local ( 0 ) ;
317329
318- /// source information (span, scope, etc.) for the declaration
319- pub source_info : SourceInfo ,
320- }
321-
322- /// A "temp" is a temporary that we place on the stack. They are
323- /// anonymous, always mutable, and have only a type.
324- #[ derive( Clone , Debug , RustcEncodable , RustcDecodable ) ]
325- pub struct TempDecl < ' tcx > {
326- pub ty : Ty < ' tcx > ,
330+ /// Classifies locals into categories. See `Mir::local_kind`.
331+ #[ derive( PartialEq , Eq , Debug ) ]
332+ pub enum LocalKind {
333+ /// User-declared variable binding
334+ Var ,
335+ /// Compiler-introduced temporary
336+ Temp ,
337+ /// Function argument
338+ Arg ,
339+ /// Location of function's return value
340+ ReturnPointer ,
327341}
328342
329- /// A "arg" is one of the function's formal arguments. These are
330- /// anonymous and distinct from the bindings that the user declares.
331- ///
332- /// For example, in this function:
333- ///
334- /// ```
335- /// fn foo((x, y): (i32, u32)) { ... }
336- /// ```
343+ /// A MIR local.
337344///
338- /// there is only one argument, of type `(i32, u32)`, but two bindings
339- /// (`x` and `y`) .
345+ /// This can be a binding declared by the user, a temporary inserted by the compiler, a function
346+ /// argument, or the return pointer .
340347#[ derive( Clone , Debug , RustcEncodable , RustcDecodable ) ]
341- pub struct ArgDecl < ' tcx > {
348+ pub struct LocalDecl < ' tcx > {
349+ /// `let mut x` vs `let x`.
350+ ///
351+ /// Temporaries and the return pointer are always mutable.
352+ pub mutability : Mutability ,
353+
354+ /// Type of this local.
342355 pub ty : Ty < ' tcx > ,
343356
344- /// If true, this argument is a tuple after monomorphization,
345- /// and has to be collected from multiple actual arguments.
346- pub spread : bool ,
357+ /// Name of the local, used in debuginfo and pretty-printing.
358+ ///
359+ /// Note that function arguments can also have this set to `Some(_)`
360+ /// to generate better debuginfo.
361+ pub name : Option < Name > ,
347362
348- /// Either keywords::Invalid or the name of a single-binding
349- /// pattern associated with this argument. Useful for debuginfo.
350- pub debug_name : Name
363+ /// For user-declared variables, stores their source information.
364+ ///
365+ /// For temporaries, this is `None`.
366+ ///
367+ /// This is the primary way to differentiate between user-declared
368+ /// variables and compiler-generated temporaries.
369+ pub source_info : Option < SourceInfo > ,
370+ }
371+
372+ impl < ' tcx > LocalDecl < ' tcx > {
373+ /// Create a new `LocalDecl` for a temporary.
374+ #[ inline]
375+ pub fn new_temp ( ty : Ty < ' tcx > ) -> Self {
376+ LocalDecl {
377+ mutability : Mutability :: Mut ,
378+ ty : ty,
379+ name : None ,
380+ source_info : None ,
381+ }
382+ }
383+
384+ /// Builds a `LocalDecl` for the return pointer.
385+ ///
386+ /// This must be inserted into the `local_decls` list as the first local.
387+ #[ inline]
388+ pub fn new_return_pointer ( return_ty : Ty ) -> LocalDecl {
389+ LocalDecl {
390+ mutability : Mutability :: Mut ,
391+ ty : return_ty,
392+ source_info : None ,
393+ name : None , // FIXME maybe we do want some name here?
394+ }
395+ }
351396}
352397
353398/// A closure capture, with its name and mode.
@@ -439,7 +484,7 @@ pub enum TerminatorKind<'tcx> {
439484 /// continue. Emitted by build::scope::diverge_cleanup.
440485 Resume ,
441486
442- /// Indicates a normal return. The ReturnPointer lvalue should
487+ /// Indicates a normal return. The return pointer lvalue should
443488 /// have been filled in by now. This should occur at most once.
444489 Return ,
445490
@@ -756,31 +801,16 @@ impl<'tcx> Debug for Statement<'tcx> {
756801///////////////////////////////////////////////////////////////////////////
757802// Lvalues
758803
759- newtype_index ! ( Var , "var" ) ;
760- newtype_index ! ( Temp , "tmp" ) ;
761- newtype_index ! ( Arg , "arg" ) ;
762- newtype_index ! ( Local , "local" ) ;
763-
764804/// A path to a value; something that can be evaluated without
765805/// changing or disturbing program state.
766806#[ derive( Clone , PartialEq , RustcEncodable , RustcDecodable ) ]
767807pub enum Lvalue < ' tcx > {
768- /// local variable declared by the user
769- Var ( Var ) ,
770-
771- /// temporary introduced during lowering into MIR
772- Temp ( Temp ) ,
773-
774- /// formal parameter of the function; note that these are NOT the
775- /// bindings that the user declares, which are vars
776- Arg ( Arg ) ,
808+ /// local variable
809+ Local ( Local ) ,
777810
778811 /// static or static mut variable
779812 Static ( DefId ) ,
780813
781- /// the return pointer of the fn
782- ReturnPointer ,
783-
784814 /// projection out of an lvalue (access a field, deref a pointer, etc)
785815 Projection ( Box < LvalueProjection < ' tcx > > ) ,
786816}
@@ -862,38 +892,16 @@ impl<'tcx> Lvalue<'tcx> {
862892 elem : elem,
863893 } ) )
864894 }
865-
866- pub fn from_local ( mir : & Mir < ' tcx > , local : Local ) -> Lvalue < ' tcx > {
867- let mut index = local. index ( ) ;
868- index = match index. checked_sub ( mir. arg_decls . len ( ) ) {
869- None => return Lvalue :: Arg ( Arg ( index as u32 ) ) ,
870- Some ( index) => index,
871- } ;
872- index = match index. checked_sub ( mir. var_decls . len ( ) ) {
873- None => return Lvalue :: Var ( Var ( index as u32 ) ) ,
874- Some ( index) => index,
875- } ;
876- index = match index. checked_sub ( mir. temp_decls . len ( ) ) {
877- None => return Lvalue :: Temp ( Temp ( index as u32 ) ) ,
878- Some ( index) => index,
879- } ;
880- debug_assert ! ( index == 0 ) ;
881- Lvalue :: ReturnPointer
882- }
883895}
884896
885897impl < ' tcx > Debug for Lvalue < ' tcx > {
886898 fn fmt ( & self , fmt : & mut Formatter ) -> fmt:: Result {
887899 use self :: Lvalue :: * ;
888900
889901 match * self {
890- Var ( id) => write ! ( fmt, "{:?}" , id) ,
891- Arg ( id) => write ! ( fmt, "{:?}" , id) ,
892- Temp ( id) => write ! ( fmt, "{:?}" , id) ,
902+ Local ( id) => write ! ( fmt, "{:?}" , id) ,
893903 Static ( def_id) =>
894904 write ! ( fmt, "{}" , ty:: tls:: with( |tcx| tcx. item_path_str( def_id) ) ) ,
895- ReturnPointer =>
896- write ! ( fmt, "return" ) ,
897905 Projection ( ref data) =>
898906 match data. elem {
899907 ProjectionElem :: Downcast ( ref adt_def, index) =>
0 commit comments