@@ -20,6 +20,7 @@ pub use self::Variance::*;
20
20
pub use self :: AutoAdjustment :: * ;
21
21
pub use self :: Representability :: * ;
22
22
pub use self :: AutoRef :: * ;
23
+ pub use self :: ExprKind :: * ;
23
24
pub use self :: DtorKind :: * ;
24
25
pub use self :: ExplicitSelfCategory :: * ;
25
26
pub use self :: FnOutput :: * ;
@@ -86,7 +87,7 @@ use syntax::abi;
86
87
use syntax:: ast:: { CrateNum , DefId , ItemImpl , ItemTrait , LOCAL_CRATE } ;
87
88
use syntax:: ast:: { MutImmutable , MutMutable , Name , NamedField , NodeId } ;
88
89
use syntax:: ast:: { StmtExpr , StmtSemi , StructField , UnnamedField , Visibility } ;
89
- use syntax:: ast_util:: { self , is_local, local_def} ;
90
+ use syntax:: ast_util:: { self , is_local, lit_is_str , local_def} ;
90
91
use syntax:: attr:: { self , AttrMetaMethods , SignedInt , UnsignedInt } ;
91
92
use syntax:: codemap:: Span ;
92
93
use syntax:: parse:: token:: { self , InternedString , special_idents} ;
@@ -5105,35 +5106,104 @@ pub fn resolve_expr(tcx: &ctxt, expr: &ast::Expr) -> def::Def {
5105
5106
}
5106
5107
}
5107
5108
5108
- pub fn expr_is_lval ( tcx : & ctxt , expr : & ast:: Expr ) -> bool {
5109
- match expr. node {
5109
+ pub fn expr_is_lval ( tcx : & ctxt , e : & ast:: Expr ) -> bool {
5110
+ match expr_kind ( tcx, e) {
5111
+ LvalueExpr => true ,
5112
+ RvalueDpsExpr | RvalueDatumExpr | RvalueStmtExpr => false
5113
+ }
5114
+ }
5115
+
5116
+ /// We categorize expressions into three kinds. The distinction between
5117
+ /// lvalue/rvalue is fundamental to the language. The distinction between the
5118
+ /// two kinds of rvalues is an artifact of trans which reflects how we will
5119
+ /// generate code for that kind of expression. See trans/expr.rs for more
5120
+ /// information.
5121
+ #[ derive( Copy , Clone ) ]
5122
+ pub enum ExprKind {
5123
+ LvalueExpr ,
5124
+ RvalueDpsExpr ,
5125
+ RvalueDatumExpr ,
5126
+ RvalueStmtExpr
5127
+ }
5128
+
5129
+ pub fn expr_kind ( tcx : & ctxt , expr : & ast:: Expr ) -> ExprKind {
5130
+ if tcx. method_map . borrow ( ) . contains_key ( & MethodCall :: expr ( expr. id ) ) {
5131
+ // Overloaded operations are generally calls, and hence they are
5132
+ // generated via DPS, but there are a few exceptions:
5133
+ return match expr. node {
5134
+ // `a += b` has a unit result.
5135
+ ast:: ExprAssignOp ( ..) => RvalueStmtExpr ,
5136
+
5137
+ // the deref method invoked for `*a` always yields an `&T`
5138
+ ast:: ExprUnary ( ast:: UnDeref , _) => LvalueExpr ,
5139
+
5140
+ // the index method invoked for `a[i]` always yields an `&T`
5141
+ ast:: ExprIndex ( ..) => LvalueExpr ,
5142
+
5143
+ // in the general case, result could be any type, use DPS
5144
+ _ => RvalueDpsExpr
5145
+ } ;
5146
+ }
5147
+
5148
+ match expr. node {
5110
5149
ast:: ExprPath ( ..) => {
5111
- // We can't use resolve_expr here, as this needs to run on broken
5112
- // programs. We don't need to through - associated items are all
5113
- // rvalues.
5114
- match tcx. def_map . borrow ( ) . get ( & expr. id ) {
5115
- Some ( & def:: PathResolution {
5116
- base_def : def:: DefStatic ( ..) , ..
5117
- } ) | Some ( & def:: PathResolution {
5118
- base_def : def:: DefUpvar ( ..) , ..
5119
- } ) | Some ( & def:: PathResolution {
5120
- base_def : def:: DefLocal ( ..) , ..
5121
- } ) => {
5122
- true
5150
+ match resolve_expr ( tcx, expr) {
5151
+ def:: DefVariant ( tid, vid, _) => {
5152
+ let variant_info = enum_variant_with_id ( tcx, tid, vid) ;
5153
+ if !variant_info. args . is_empty ( ) {
5154
+ // N-ary variant.
5155
+ RvalueDatumExpr
5156
+ } else {
5157
+ // Nullary variant.
5158
+ RvalueDpsExpr
5159
+ }
5123
5160
}
5124
5161
5125
- Some ( ..) => false ,
5162
+ def:: DefStruct ( _) => {
5163
+ match tcx. node_types . borrow ( ) . get ( & expr. id ) {
5164
+ Some ( ty) => match ty. sty {
5165
+ TyBareFn ( ..) => RvalueDatumExpr ,
5166
+ _ => RvalueDpsExpr
5167
+ } ,
5168
+ // See ExprCast below for why types might be missing.
5169
+ None => RvalueDatumExpr
5170
+ }
5171
+ }
5126
5172
5127
- None => tcx. sess . span_bug ( expr. span , & format ! (
5128
- "no def for path {}" , expr. id) )
5173
+ // Special case: A unit like struct's constructor must be called without () at the
5174
+ // end (like `UnitStruct`) which means this is an ExprPath to a DefFn. But in case
5175
+ // of unit structs this is should not be interpreted as function pointer but as
5176
+ // call to the constructor.
5177
+ def:: DefFn ( _, true ) => RvalueDpsExpr ,
5178
+
5179
+ // Fn pointers are just scalar values.
5180
+ def:: DefFn ( ..) | def:: DefMethod ( ..) => RvalueDatumExpr ,
5181
+
5182
+ // Note: there is actually a good case to be made that
5183
+ // DefArg's, particularly those of immediate type, ought to
5184
+ // considered rvalues.
5185
+ def:: DefStatic ( ..) |
5186
+ def:: DefUpvar ( ..) |
5187
+ def:: DefLocal ( ..) => LvalueExpr ,
5188
+
5189
+ def:: DefConst ( ..) |
5190
+ def:: DefAssociatedConst ( ..) => RvalueDatumExpr ,
5191
+
5192
+ def => {
5193
+ tcx. sess . span_bug (
5194
+ expr. span ,
5195
+ & format ! ( "uncategorized def for expr {}: {:?}" ,
5196
+ expr. id,
5197
+ def) ) ;
5198
+ }
5129
5199
}
5130
5200
}
5131
5201
5132
5202
ast:: ExprUnary ( ast:: UnDeref , _) |
5133
5203
ast:: ExprField ( ..) |
5134
5204
ast:: ExprTupField ( ..) |
5135
5205
ast:: ExprIndex ( ..) => {
5136
- true
5206
+ LvalueExpr
5137
5207
}
5138
5208
5139
5209
ast:: ExprCall ( ..) |
@@ -5146,29 +5216,60 @@ pub fn expr_is_lval(tcx: &ctxt, expr: &ast::Expr) -> bool {
5146
5216
ast:: ExprClosure ( ..) |
5147
5217
ast:: ExprBlock ( ..) |
5148
5218
ast:: ExprRepeat ( ..) |
5149
- ast:: ExprVec ( ..) |
5219
+ ast:: ExprVec ( ..) => {
5220
+ RvalueDpsExpr
5221
+ }
5222
+
5223
+ ast:: ExprIfLet ( ..) => {
5224
+ tcx. sess . span_bug ( expr. span , "non-desugared ExprIfLet" ) ;
5225
+ }
5226
+ ast:: ExprWhileLet ( ..) => {
5227
+ tcx. sess . span_bug ( expr. span , "non-desugared ExprWhileLet" ) ;
5228
+ }
5229
+
5230
+ ast:: ExprForLoop ( ..) => {
5231
+ tcx. sess . span_bug ( expr. span , "non-desugared ExprForLoop" ) ;
5232
+ }
5233
+
5234
+ ast:: ExprLit ( ref lit) if lit_is_str ( & * * lit) => {
5235
+ RvalueDpsExpr
5236
+ }
5237
+
5150
5238
ast:: ExprBreak ( ..) |
5151
5239
ast:: ExprAgain ( ..) |
5152
5240
ast:: ExprRet ( ..) |
5153
5241
ast:: ExprWhile ( ..) |
5154
5242
ast:: ExprLoop ( ..) |
5155
5243
ast:: ExprAssign ( ..) |
5156
5244
ast:: ExprInlineAsm ( ..) |
5157
- ast:: ExprAssignOp ( ..) |
5158
- ast:: ExprLit ( _) |
5245
+ ast:: ExprAssignOp ( ..) => {
5246
+ RvalueStmtExpr
5247
+ }
5248
+
5249
+ ast:: ExprLit ( _) | // Note: LitStr is carved out above
5159
5250
ast:: ExprUnary ( ..) |
5160
- ast:: ExprBox ( .. ) |
5251
+ ast:: ExprBox ( None , _ ) |
5161
5252
ast:: ExprAddrOf ( ..) |
5162
5253
ast:: ExprBinary ( ..) |
5163
5254
ast:: ExprCast ( ..) => {
5164
- false
5255
+ RvalueDatumExpr
5256
+ }
5257
+
5258
+ ast:: ExprBox ( Some ( ref place) , _) => {
5259
+ // Special case `Box<T>` for now:
5260
+ let def_id = match tcx. def_map . borrow ( ) . get ( & place. id ) {
5261
+ Some ( def) => def. def_id ( ) ,
5262
+ None => panic ! ( "no def for place" ) ,
5263
+ } ;
5264
+ if tcx. lang_items . exchange_heap ( ) == Some ( def_id) {
5265
+ RvalueDatumExpr
5266
+ } else {
5267
+ RvalueDpsExpr
5268
+ }
5165
5269
}
5166
5270
5167
- ast:: ExprParen ( ref e) => expr_is_lval ( tcx, e) ,
5271
+ ast:: ExprParen ( ref e) => expr_kind ( tcx, & * * e) ,
5168
5272
5169
- ast:: ExprIfLet ( ..) |
5170
- ast:: ExprWhileLet ( ..) |
5171
- ast:: ExprForLoop ( ..) |
5172
5273
ast:: ExprMac ( ..) => {
5173
5274
tcx. sess . span_bug (
5174
5275
expr. span ,
0 commit comments