diff --git a/src/librustc/middle/borrowck.rs b/src/librustc/middle/borrowck.rs index 25e184c2c02c3..5745d2e84bff1 100644 --- a/src/librustc/middle/borrowck.rs +++ b/src/librustc/middle/borrowck.rs @@ -513,6 +513,16 @@ impl borrowck_ctxt { cat_expr(self.tcx, self.method_map, expr) } + fn cat_expr_unadjusted(expr: @ast::expr) -> cmt { + cat_expr_unadjusted(self.tcx, self.method_map, expr) + } + + fn cat_expr_autoderefd(expr: @ast::expr, + adj: @ty::AutoAdjustment) + -> cmt { + cat_expr_autoderefd(self.tcx, self.method_map, expr, adj) + } + fn cat_def(id: ast::node_id, span: span, ty: ty::t, diff --git a/src/librustc/middle/borrowck/check_loans.rs b/src/librustc/middle/borrowck/check_loans.rs index 366dd7e7e8504..03bd403bf461d 100644 --- a/src/librustc/middle/borrowck/check_loans.rs +++ b/src/librustc/middle/borrowck/check_loans.rs @@ -362,7 +362,12 @@ impl check_loan_ctxt { } fn check_assignment(at: assignment_type, ex: @ast::expr) { - let cmt = self.bccx.cat_expr(ex); + // We don't use cat_expr() here because we don't want to treat + // auto-ref'd parameters in overloaded operators as rvalues. + let cmt = match self.bccx.tcx.adjustments.find(ex.id) { + None => self.bccx.cat_expr_unadjusted(ex), + Some(adj) => self.bccx.cat_expr_autoderefd(ex, adj) + }; debug!("check_assignment(cmt=%s)", self.bccx.cmt_to_repr(cmt)); diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index ebc06435c64e6..9eafec930f6e4 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -573,6 +573,29 @@ fn cat_expr( return mcx.cat_expr(expr); } +fn cat_expr_unadjusted( + tcx: ty::ctxt, + method_map: typeck::method_map, + expr: @ast::expr) -> cmt { + + let mcx = &mem_categorization_ctxt { + tcx: tcx, method_map: method_map + }; + return mcx.cat_expr_unadjusted(expr); +} + +fn cat_expr_autoderefd( + tcx: ty::ctxt, + method_map: typeck::method_map, + expr: @ast::expr, + adj: @ty::AutoAdjustment) -> cmt { + + let mcx = &mem_categorization_ctxt { + tcx: tcx, method_map: method_map + }; + return mcx.cat_expr_autoderefd(expr, adj); +} + fn cat_def( tcx: ty::ctxt, method_map: typeck::method_map, diff --git a/src/librustc/middle/trans/expr.rs b/src/librustc/middle/trans/expr.rs index 2e4d95acdfbd0..4927d2773c190 100644 --- a/src/librustc/middle/trans/expr.rs +++ b/src/librustc/middle/trans/expr.rs @@ -1572,7 +1572,7 @@ fn trans_assign_op(bcx: block, debug!("trans_assign_op(expr=%s)", bcx.expr_to_str(expr)); // Evaluate LHS (destination), which should be an lvalue - let dst_datum = unpack_datum!(bcx, trans_lvalue(bcx, dst)); + let dst_datum = unpack_datum!(bcx, trans_lvalue_unadjusted(bcx, dst)); // A user-defined operator method if bcx.ccx().maps.method_map.find(expr.id).is_some() { diff --git a/src/test/run-pass/operator-overloading-explicit-self.rs b/src/test/run-pass/operator-overloading-explicit-self.rs new file mode 100644 index 0000000000000..3b198078cf827 --- /dev/null +++ b/src/test/run-pass/operator-overloading-explicit-self.rs @@ -0,0 +1,16 @@ +struct S { + x: int +} + +impl S { + pure fn add(&self, other: &S) -> S { + S { x: self.x + other.x } + } +} + +fn main() { + let mut s = S { x: 1 }; + s += S { x: 2 }; + assert s.x == 3; +} +