66// their associated scopes. In phase two, checking loans, we will then make
77// sure that all of these loans are honored.
88
9- import categorization:: public_methods;
9+ import categorization :: { public_methods, opt_deref_kind } ;
1010import loan:: public_methods;
1111import preserve:: public_methods;
1212
@@ -30,6 +30,8 @@ fn req_loans_in_expr(ex: @ast::expr,
3030 let bccx = self . bccx ;
3131 let tcx = bccx. tcx ;
3232
33+ #debug[ "req_loans_in_expr(ex=%s)" , pprust:: expr_to_str ( ex) ] ;
34+
3335 // If this expression is borrowed, have to ensure it remains valid:
3436 for tcx. borrowings. find( ex. id) . each { |borrow|
3537 let cmt = self . bccx. cat_borrow_of_expr( ex) ;
@@ -64,7 +66,39 @@ fn req_loans_in_expr(ex: @ast::expr,
6466 let arg_cmt = self . bccx . cat_expr ( arg) ;
6567 self . guarantee_valid ( arg_cmt, m_imm, scope_r) ;
6668 }
67- ast:: by_move | ast:: by_copy | ast:: by_val { }
69+ ast:: by_val {
70+ // Rust's by-val does not actually give ownership to
71+ // the callee. This means that if a pointer type is
72+ // passed, it is effectively a borrow, and so the
73+ // caller must guarantee that the data remains valid.
74+ //
75+ // Subtle: we only guarantee that the pointer is valid
76+ // and const. Technically, we ought to pass in the
77+ // mutability that the caller expects (e.g., if the
78+ // formal argument has type @mut, we should guarantee
79+ // validity and mutability, not validity and const).
80+ // However, the type system already guarantees that
81+ // the caller's mutability is compatible with the
82+ // callee, so this is not necessary. (Note that with
83+ // actual borrows, typeck is more liberal and allows
84+ // the pointer to be borrowed as immutable even if it
85+ // is mutable in the caller's frame, thus effectively
86+ // passing the buck onto us to enforce this)
87+
88+ alt opt_deref_kind( arg_ty. ty ) {
89+ some( deref_ptr( region_ptr) ) {
90+ /* region pointers are (by induction) guaranteed */
91+ }
92+ none {
93+ /* not a pointer, no worries */
94+ }
95+ some( _) {
96+ let arg_cmt = self . bccx . cat_borrow_of_expr ( arg) ;
97+ self . guarantee_valid ( arg_cmt, m_const, scope_r) ;
98+ }
99+ }
100+ }
101+ ast:: by_move | ast:: by_copy { }
68102 }
69103 }
70104 }
@@ -78,6 +112,24 @@ fn req_loans_in_expr(ex: @ast::expr,
78112 }
79113 }
80114
115+ ast:: expr_field( rcvr, _, _) |
116+ ast:: expr_binary( _, rcvr, _) |
117+ ast:: expr_unary( _, rcvr) if self . bccx. method_map. contains_key( ex. id) {
118+ // Receivers in method calls are always passed by ref.
119+ //
120+ // FIXME--this scope is both too large and too small. We make
121+ // the scope the enclosing block, which surely includes any
122+ // immediate call (a.b()) but which is too big. OTOH, in the
123+ // case of a naked field `a.b`, the value is copied
124+ // anyhow. This is probably best fixed if we address the
125+ // syntactic ambiguity.
126+
127+ // let scope_r = ty::re_scope(ex.id);
128+ let scope_r = ty:: re_scope ( self . tcx ( ) . region_map . get ( ex. id ) ) ;
129+ let rcvr_cmt = self . bccx . cat_expr ( rcvr) ;
130+ self . guarantee_valid ( rcvr_cmt, m_imm, scope_r) ;
131+ }
132+
81133 _ { /*ok*/ }
82134 }
83135
0 commit comments