Skip to content

Commit c008919

Browse files
author
Jorge Aparicio
committed
add lang items, feature gate, tests; update typeck/trans
1 parent 8251771 commit c008919

File tree

12 files changed

+299
-28
lines changed

12 files changed

+299
-28
lines changed

src/librustc/middle/expr_use_visitor.rs

+8-3
Original file line numberDiff line numberDiff line change
@@ -584,10 +584,15 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,'tcx,TYPER> {
584584
}
585585

586586
ast::ExprAssignOp(_, ref lhs, ref rhs) => {
587-
// This will have to change if/when we support
588-
// overloaded operators for `+=` and so forth.
589587
self.mutate_expr(expr, &**lhs, WriteAndRead);
590-
self.consume_expr(&**rhs);
588+
589+
if self.typer.is_method_call(expr.id) {
590+
let r = ty::ReScope(region::CodeExtent::from_node_id(expr.id));
591+
self.borrow_expr(rhs, r, ty::ImmBorrow, OverloadedOperator);
592+
} else {
593+
// built-in assignment operations consume the RHS
594+
self.consume_expr(&**rhs);
595+
}
591596
}
592597

593598
ast::ExprRepeat(ref base, ref count) => {

src/librustc/middle/lang_items.rs

+11
Original file line numberDiff line numberDiff line change
@@ -283,6 +283,17 @@ lets_do_this! {
283283
RangeToStructLangItem, "range_to", range_to_struct;
284284
RangeFullStructLangItem, "range_full", range_full_struct;
285285

286+
AddAssignTraitLangItem, "add_assign", add_assign_trait;
287+
BitAndAssignTraitLangItem, "bitand_assign", bitand_assign_trait;
288+
BitOrAssignTraitLangItem, "bitor_assign", bitor_assign_trait;
289+
BitXorAssignTraitLangItem, "bitxor_assign", bitxor_assign_trait;
290+
DivAssignTraitLangItem, "div_assign", div_assign_trait;
291+
MulAssignTraitLangItem, "mul_assign", mul_assign_trait;
292+
RemAssignTraitLangItem, "rem_assign", rem_assign_trait;
293+
ShlAssignTraitLangItem, "shl_assign", shl_assign_trait;
294+
ShrAssignTraitLangItem, "shr_assign", shr_assign_trait;
295+
SubAssignTraitLangItem, "sub_assign", sub_assign_trait;
296+
286297
UnsafeCellTypeLangItem, "unsafe_cell", unsafe_cell_type;
287298

288299
DerefTraitLangItem, "deref", deref_trait;

src/librustc_trans/trans/expr.rs

+12-3
Original file line numberDiff line numberDiff line change
@@ -1041,7 +1041,15 @@ fn trans_rvalue_stmt_unadjusted<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
10411041
}
10421042
}
10431043
ast::ExprAssignOp(op, ref dst, ref src) => {
1044-
trans_assign_op(bcx, expr, op, &**dst, &**src)
1044+
if ty::is_binopable(bcx.tcx(), node_id_type(bcx, dst.id), op) {
1045+
trans_assign_op(bcx, expr, op, &**dst, &**src)
1046+
} else {
1047+
let dst = unpack_datum!(bcx, trans(bcx, &**dst));
1048+
let src_datum = unpack_datum!(bcx, trans(bcx, &**src));
1049+
trans_overloaded_op(bcx, expr, MethodCall::expr(expr.id), dst,
1050+
vec![(src_datum, src.id)], None,
1051+
true).bcx
1052+
}
10451053
}
10461054
ast::ExprInlineAsm(ref a) => {
10471055
asm::trans_inline_asm(bcx, a)
@@ -1239,8 +1247,9 @@ fn trans_rvalue_dps_unadjusted<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
12391247
"expr_cast of non-trait");
12401248
}
12411249
}
1242-
ast::ExprAssignOp(op, ref dst, ref src) => {
1243-
trans_assign_op(bcx, expr, op, &**dst, &**src)
1250+
ast::ExprAssignOp(..) => {
1251+
bcx.tcx().sess.span_bug(expr.span,
1252+
"operator assignment (`+=`) should always be an rvalue_stmt");
12441253
}
12451254
_ => {
12461255
bcx.tcx().sess.span_bug(

src/librustc_typeck/check/mod.rs

+51-18
Original file line numberDiff line numberDiff line change
@@ -2992,19 +2992,20 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>,
29922992
let result_t = if is_binop_assignment == SimpleBinop {
29932993
check_user_binop(fcx, expr, lhs, lhs_t, op, rhs)
29942994
} else {
2995-
fcx.type_error_message(expr.span,
2996-
|actual| {
2997-
format!("binary assignment \
2998-
operation `{}=` \
2999-
cannot be applied to \
3000-
type `{}`",
3001-
ast_util::binop_to_string(op.node),
3002-
actual)
3003-
},
3004-
lhs_t,
3005-
None);
3006-
check_expr(fcx, &**rhs);
3007-
fcx.tcx().types.err
2995+
if fcx.tcx().sess.features.borrow().op_assign {
2996+
check_user_binop_assign(fcx, expr, lhs, lhs_t, op, rhs)
2997+
} else {
2998+
fcx.tcx().sess.span_err(
2999+
expr.span,
3000+
"overloaded augmented assignment is not stable",
3001+
);
3002+
fileline_help!(
3003+
fcx.tcx().sess,
3004+
expr.span,
3005+
"add `#![feature(op_assign)]` to the crate attributes to enable");
3006+
3007+
fcx.tcx().types.err
3008+
}
30083009
};
30093010

30103011
fcx.write_ty(expr.id, result_t);
@@ -3053,6 +3054,42 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>,
30533054
}, if ast_util::is_by_value_binop(op.node) { AutorefArgs::No } else { AutorefArgs::Yes })
30543055
}
30553056

3057+
fn check_user_binop_assign<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
3058+
ex: &'tcx ast::Expr,
3059+
lhs_expr: &'tcx ast::Expr,
3060+
lhs_resolved_t: Ty<'tcx>,
3061+
op: ast::BinOp,
3062+
rhs: &'tcx P<ast::Expr>) -> Ty<'tcx> {
3063+
let tcx = fcx.ccx.tcx;
3064+
let lang = &tcx.lang_items;
3065+
let (name, trait_did) = match op.node {
3066+
ast::BiAdd => ("add_assign", lang.add_assign_trait()),
3067+
ast::BiSub => ("sub_assign", lang.sub_assign_trait()),
3068+
ast::BiMul => ("mul_assign", lang.mul_assign_trait()),
3069+
ast::BiDiv => ("div_assign", lang.div_assign_trait()),
3070+
ast::BiRem => ("rem_assign", lang.rem_assign_trait()),
3071+
ast::BiBitXor => ("bitxor_assign", lang.bitxor_assign_trait()),
3072+
ast::BiBitAnd => ("bitand_assign", lang.bitand_assign_trait()),
3073+
ast::BiBitOr => ("bitor_assign", lang.bitor_assign_trait()),
3074+
ast::BiShl => ("shl_assign", lang.shl_assign_trait()),
3075+
ast::BiShr => ("shr_assign", lang.shr_assign_trait()),
3076+
ast::BiLt | ast::BiLe | ast::BiGe | ast::BiGt | ast::BiEq | ast::BiNe | ast::BiAnd |
3077+
ast::BiOr =>
3078+
{
3079+
check_expr(fcx, &**rhs);
3080+
return tcx.types.err;
3081+
}
3082+
};
3083+
lookup_op_method(fcx, ex, lhs_resolved_t, token::intern(name),
3084+
trait_did, lhs_expr, Some(rhs), || {
3085+
fcx.type_error_message(ex.span, |actual| {
3086+
format!("binary operation `{}=` cannot be applied to type `{}`",
3087+
ast_util::binop_to_string(op.node),
3088+
actual)
3089+
}, lhs_resolved_t, None)
3090+
}, AutorefArgs::Yes)
3091+
}
3092+
30563093
fn check_user_unop<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
30573094
op_str: &str,
30583095
mname: &str,
@@ -3484,10 +3521,6 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>,
34843521
ast::ExprAssignOp(op, ref lhs, ref rhs) => {
34853522
check_binop(fcx, expr, op, &**lhs, rhs, BinopAssignment);
34863523

3487-
let lhs_t = fcx.expr_ty(&**lhs);
3488-
let result_t = fcx.expr_ty(expr);
3489-
demand::suptype(fcx, expr.span, result_t, lhs_t);
3490-
34913524
let tcx = fcx.tcx();
34923525
if !ty::expr_is_lval(tcx, &**lhs) {
34933526
span_err!(tcx.sess, lhs.span, E0067, "illegal left-hand side expression");
@@ -3498,7 +3531,7 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>,
34983531
// Overwrite result of check_binop...this preserves existing behavior
34993532
// but seems quite dubious with regard to user-defined methods
35003533
// and so forth. - Niko
3501-
if !ty::type_is_error(result_t) {
3534+
if !ty::type_is_error(fcx.expr_ty(expr)) {
35023535
fcx.write_nil(expr.id);
35033536
}
35043537
}

src/libsyntax/feature_gate.rs

+6
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,9 @@ const KNOWN_FEATURES: &'static [(&'static str, &'static str, Status)] = &[
153153
// below (it has to be checked before expansion possibly makes
154154
// macros disappear).
155155
("allow_internal_unstable", "1.0.0", Active),
156+
157+
// Augmented assignment `a += b`; RFC 953
158+
("op_assign", "1.0.0", Active),
156159
];
157160
// (changing above list without updating src/doc/reference.md makes @cmr sad)
158161

@@ -317,6 +320,7 @@ pub enum AttributeType {
317320

318321
/// A set of features to be used by later passes.
319322
pub struct Features {
323+
pub op_assign: bool,
320324
pub unboxed_closures: bool,
321325
pub rustc_diagnostic_macros: bool,
322326
pub visible_private_types: bool,
@@ -339,6 +343,7 @@ pub struct Features {
339343
impl Features {
340344
pub fn new() -> Features {
341345
Features {
346+
op_assign: false,
342347
unboxed_closures: false,
343348
rustc_diagnostic_macros: false,
344349
visible_private_types: false,
@@ -787,6 +792,7 @@ fn check_crate_inner<F>(cm: &CodeMap, span_handler: &SpanHandler, krate: &ast::C
787792
// to a single-pass (instead of N calls to `.has_feature`).
788793

789794
Features {
795+
op_assign: cx.has_feature("op_assign"),
790796
unboxed_closures: cx.has_feature("unboxed_closures"),
791797
rustc_diagnostic_macros: cx.has_feature("rustc_diagnostic_macros"),
792798
visible_private_types: cx.has_feature("visible_private_types"),

src/test/compile-fail/assignment-operator-unimplemented.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,12 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11+
#![feature(op_assign)]
12+
1113
struct Foo;
1214

1315
fn main() {
1416
let mut a = Foo;
1517
let ref b = Foo;
16-
a += *b; //~ Error: binary assignment operation `+=` cannot be applied to type `Foo`
18+
a += *b; //~ Error: binary operation `+=` cannot be applied to type `Foo`
1719
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
use std::ops::AddAssign;
12+
13+
struct MyInt(i32);
14+
15+
impl AddAssign for MyInt {
16+
fn add_assign(&mut self, rhs: &MyInt) {
17+
self.0 += rhs.0
18+
}
19+
}
20+
21+
fn main() {
22+
let mut x = MyInt(1);
23+
x += MyInt(2);
24+
//~^ error: overloaded augmented assignment is not stable
25+
//~^^ help: add `#![feature(op_assign)]` to the crate attributes to enable
26+
x -= MyInt(3);
27+
//~^ error: overloaded augmented assignment is not stable
28+
//~^^ help: add `#![feature(op_assign)]` to the crate attributes to enable
29+
}

src/test/compile-fail/issue-10401.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,10 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11+
#![feature(op_assign)]
12+
1113
fn main() {
1214
let mut a = "a";
1315
a += { "b" };
14-
//~^ ERROR: binary assignment operation `+=` cannot be applied
16+
//~^ ERROR: binary operation `+=` cannot be applied to type `&str`
1517
}

src/test/compile-fail/issue-5239-1.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,9 @@
1010

1111
// Regression test for issue #5239
1212

13+
#![feature(op_assign)]
14+
1315
fn main() {
1416
let x = |ref x: isize| -> isize { x += 1; };
15-
//~^ ERROR binary assignment operation `+=` cannot be applied to type `&isize`
17+
//~^ ERROR binary operation `+=` cannot be applied to type `&isize`
1618
}

src/test/compile-fail/issue-6738.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,15 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11+
#![feature(op_assign)]
12+
1113
struct Foo<T> {
1214
x: T,
1315
}
1416
impl<T> Foo<T> {
1517
fn add(&mut self, v: Foo<T>){
1618
self.x += v.x;
17-
//~^ ERROR: binary assignment operation `+=` cannot be applied
19+
//~^ ERROR: binary operation `+=` cannot be applied to type `T`
1820
}
1921
}
2022
fn main() {}
+33
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
#![feature(op_assign)]
12+
13+
use std::ops::AddAssign;
14+
15+
struct Int(i32);
16+
17+
impl AddAssign for Int {
18+
fn add_assign(&mut self, rhs: &Int) {
19+
self.0 += rhs.0
20+
}
21+
}
22+
23+
fn main() {
24+
let mut x = Int(1);
25+
x //~ error: cannot borrow `x` as mutable because it is also borrowed as immutable
26+
+=
27+
x; //~ note: previous borrow of `x` occurs here
28+
29+
let y = Int(2);
30+
y //~ error: cannot borrow immutable local variable `y` as mutable
31+
+=
32+
Int(1);
33+
}

0 commit comments

Comments
 (0)