Skip to content

Commit 3ce4438

Browse files
committed
rustc: adjust the RHS of comparison operators instead of assuming autorefs.
1 parent 194fe69 commit 3ce4438

File tree

6 files changed

+114
-320
lines changed

6 files changed

+114
-320
lines changed

src/librustc/middle/expr_use_visitor.rs

+13-87
Original file line numberDiff line numberDiff line change
@@ -263,12 +263,6 @@ macro_rules! return_if_err {
263263
)
264264
}
265265

266-
/// Whether the elements of an overloaded operation are passed by value or by reference
267-
enum PassArgs {
268-
ByValue,
269-
ByRef,
270-
}
271-
272266
impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> {
273267
pub fn new(delegate: &'a mut (Delegate<'tcx>+'a),
274268
region_maps: &'a RegionMaps,
@@ -382,9 +376,7 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> {
382376
}
383377

384378
hir::ExprUnary(hir::UnDeref, ref base) => { // *base
385-
if !self.walk_overloaded_operator(expr, &base, Vec::new(), PassArgs::ByRef) {
386-
self.select_from_expr(&base);
387-
}
379+
self.select_from_expr(&base);
388380
}
389381

390382
hir::ExprField(ref base, _) => { // base.f
@@ -396,13 +388,8 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> {
396388
}
397389

398390
hir::ExprIndex(ref lhs, ref rhs) => { // lhs[rhs]
399-
if !self.walk_overloaded_operator(expr,
400-
&lhs,
401-
vec![&rhs],
402-
PassArgs::ByValue) {
403-
self.select_from_expr(&lhs);
404-
self.consume_expr(&rhs);
405-
}
391+
self.select_from_expr(&lhs);
392+
self.consume_expr(&rhs);
406393
}
407394

408395
hir::ExprCall(ref callee, ref args) => { // callee(args)
@@ -485,29 +472,13 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> {
485472
self.walk_block(&blk);
486473
}
487474

488-
hir::ExprUnary(op, ref lhs) => {
489-
let pass_args = if op.is_by_value() {
490-
PassArgs::ByValue
491-
} else {
492-
PassArgs::ByRef
493-
};
494-
495-
if !self.walk_overloaded_operator(expr, &lhs, Vec::new(), pass_args) {
496-
self.consume_expr(&lhs);
497-
}
475+
hir::ExprUnary(_, ref lhs) => {
476+
self.consume_expr(&lhs);
498477
}
499478

500-
hir::ExprBinary(op, ref lhs, ref rhs) => {
501-
let pass_args = if op.node.is_by_value() {
502-
PassArgs::ByValue
503-
} else {
504-
PassArgs::ByRef
505-
};
506-
507-
if !self.walk_overloaded_operator(expr, &lhs, vec![&rhs], pass_args) {
508-
self.consume_expr(&lhs);
509-
self.consume_expr(&rhs);
510-
}
479+
hir::ExprBinary(_, ref lhs, ref rhs) => {
480+
self.consume_expr(&lhs);
481+
self.consume_expr(&rhs);
511482
}
512483

513484
hir::ExprBlock(ref blk) => {
@@ -529,14 +500,13 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> {
529500
self.consume_expr(&base);
530501
}
531502

532-
hir::ExprAssignOp(op, ref lhs, ref rhs) => {
533-
// NB All our assignment operations take the RHS by value
534-
assert!(op.node.is_by_value());
535-
536-
if !self.walk_overloaded_operator(expr, lhs, vec![rhs], PassArgs::ByValue) {
503+
hir::ExprAssignOp(_, ref lhs, ref rhs) => {
504+
if self.mc.infcx.tables.borrow().is_method_call(expr) {
505+
self.consume_expr(lhs);
506+
} else {
537507
self.mutate_expr(expr, &lhs, MutateMode::WriteAndRead);
538-
self.consume_expr(&rhs);
539508
}
509+
self.consume_expr(&rhs);
540510
}
541511

542512
hir::ExprRepeat(ref base, _) => {
@@ -784,50 +754,6 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> {
784754
}
785755
}
786756

787-
788-
// When this returns true, it means that the expression *is* a
789-
// method-call (i.e. via the operator-overload). This true result
790-
// also implies that walk_overloaded_operator already took care of
791-
// recursively processing the input arguments, and thus the caller
792-
// should not do so.
793-
fn walk_overloaded_operator(&mut self,
794-
expr: &hir::Expr,
795-
receiver: &hir::Expr,
796-
rhs: Vec<&hir::Expr>,
797-
pass_args: PassArgs)
798-
-> bool
799-
{
800-
if !self.mc.infcx.tables.borrow().is_method_call(expr) {
801-
return false;
802-
}
803-
804-
match pass_args {
805-
PassArgs::ByValue => {
806-
self.consume_expr(receiver);
807-
for &arg in &rhs {
808-
self.consume_expr(arg);
809-
}
810-
811-
return true;
812-
},
813-
PassArgs::ByRef => {},
814-
}
815-
816-
self.walk_expr(receiver);
817-
818-
// Arguments (but not receivers) to overloaded operator
819-
// methods are implicitly autoref'd which sadly does not use
820-
// adjustments, so we must hardcode the borrow here.
821-
822-
let r = self.tcx().node_scope_region(expr.id);
823-
let bk = ty::ImmBorrow;
824-
825-
for &arg in &rhs {
826-
self.borrow_expr(arg, r, bk, OverloadedOperator);
827-
}
828-
return true;
829-
}
830-
831757
fn arm_move_mode(&mut self, discr_cmt: mc::cmt<'tcx>, arm: &hir::Arm) -> TrackMatchMode {
832758
let mut mode = Unknown;
833759
for pat in &arm.pats {

src/librustc_mir/hair/cx/expr.rs

+18-111
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@ use rustc::ty::adjustment::{Adjustment, Adjust, AutoBorrow};
2121
use rustc::ty::cast::CastKind as TyCastKind;
2222
use rustc::ty::subst::Subst;
2323
use rustc::hir;
24-
use syntax::ptr::P;
2524

2625
impl<'tcx> Mirror<'tcx> for &'tcx hir::Expr {
2726
type Output = Expr<'tcx>;
@@ -117,13 +116,7 @@ fn apply_adjustment<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
117116
},
118117
};
119118

120-
overloaded_lvalue(cx,
121-
hir_expr,
122-
adjustment.target,
123-
Some(call),
124-
PassArgs::ByValue,
125-
expr.to_ref(),
126-
vec![])
119+
overloaded_lvalue(cx, hir_expr, adjustment.target, Some(call), vec![expr.to_ref()])
127120
}
128121
Adjust::Borrow(AutoBorrow::Ref(r, m)) => {
129122
ExprKind::Borrow {
@@ -281,17 +274,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
281274

282275
hir::ExprAssignOp(op, ref lhs, ref rhs) => {
283276
if cx.tables().is_method_call(expr) {
284-
let pass_args = if op.node.is_by_value() {
285-
PassArgs::ByValue
286-
} else {
287-
PassArgs::ByRef
288-
};
289-
overloaded_operator(cx,
290-
expr,
291-
None,
292-
pass_args,
293-
lhs.to_ref(),
294-
vec![rhs])
277+
overloaded_operator(cx, expr, vec![lhs.to_ref(), rhs.to_ref()])
295278
} else {
296279
ExprKind::AssignOp {
297280
op: bin_op(op.node),
@@ -305,17 +288,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
305288

306289
hir::ExprBinary(op, ref lhs, ref rhs) => {
307290
if cx.tables().is_method_call(expr) {
308-
let pass_args = if op.node.is_by_value() {
309-
PassArgs::ByValue
310-
} else {
311-
PassArgs::ByRef
312-
};
313-
overloaded_operator(cx,
314-
expr,
315-
None,
316-
pass_args,
317-
lhs.to_ref(),
318-
vec![rhs])
291+
overloaded_operator(cx, expr, vec![lhs.to_ref(), rhs.to_ref()])
319292
} else {
320293
// FIXME overflow
321294
match (op.node, cx.constness) {
@@ -365,13 +338,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
365338

366339
hir::ExprIndex(ref lhs, ref index) => {
367340
if cx.tables().is_method_call(expr) {
368-
overloaded_lvalue(cx,
369-
expr,
370-
expr_ty,
371-
None,
372-
PassArgs::ByValue,
373-
lhs.to_ref(),
374-
vec![index])
341+
overloaded_lvalue(cx, expr, expr_ty, None, vec![lhs.to_ref(), index.to_ref()])
375342
} else {
376343
ExprKind::Index {
377344
lhs: lhs.to_ref(),
@@ -382,26 +349,15 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
382349

383350
hir::ExprUnary(hir::UnOp::UnDeref, ref arg) => {
384351
if cx.tables().is_method_call(expr) {
385-
overloaded_lvalue(cx,
386-
expr,
387-
expr_ty,
388-
None,
389-
PassArgs::ByValue,
390-
arg.to_ref(),
391-
vec![])
352+
overloaded_lvalue(cx, expr, expr_ty, None, vec![arg.to_ref()])
392353
} else {
393354
ExprKind::Deref { arg: arg.to_ref() }
394355
}
395356
}
396357

397358
hir::ExprUnary(hir::UnOp::UnNot, ref arg) => {
398359
if cx.tables().is_method_call(expr) {
399-
overloaded_operator(cx,
400-
expr,
401-
None,
402-
PassArgs::ByValue,
403-
arg.to_ref(),
404-
vec![])
360+
overloaded_operator(cx, expr, vec![arg.to_ref()])
405361
} else {
406362
ExprKind::Unary {
407363
op: UnOp::Not,
@@ -412,12 +368,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
412368

413369
hir::ExprUnary(hir::UnOp::UnNeg, ref arg) => {
414370
if cx.tables().is_method_call(expr) {
415-
overloaded_operator(cx,
416-
expr,
417-
None,
418-
PassArgs::ByValue,
419-
arg.to_ref(),
420-
vec![])
371+
overloaded_operator(cx, expr, vec![arg.to_ref()])
421372
} else {
422373
// FIXME runtime-overflow
423374
if let hir::ExprLit(_) = arg.node {
@@ -873,77 +824,29 @@ fn bin_op(op: hir::BinOp_) -> BinOp {
873824
}
874825
}
875826

876-
enum PassArgs {
877-
ByValue,
878-
ByRef,
879-
}
880-
881827
fn overloaded_operator<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
882828
expr: &'tcx hir::Expr,
883-
custom_callee: Option<(DefId, &'tcx Substs<'tcx>)>,
884-
pass_args: PassArgs,
885-
receiver: ExprRef<'tcx>,
886-
args: Vec<&'tcx P<hir::Expr>>)
829+
args: Vec<ExprRef<'tcx>>)
887830
-> ExprKind<'tcx> {
888-
// the receiver has all the adjustments that are needed, so we can
889-
// just push a reference to it
890-
let mut argrefs = vec![receiver];
891-
892-
// the arguments, unfortunately, do not, so if this is a ByRef
893-
// operator, we have to gin up the autorefs (but by value is easy)
894-
match pass_args {
895-
PassArgs::ByValue => argrefs.extend(args.iter().map(|arg| arg.to_ref())),
896-
897-
PassArgs::ByRef => {
898-
let region = cx.tcx.node_scope_region(expr.id);
899-
let (temp_lifetime, was_shrunk) =
900-
cx.region_maps.temporary_scope2(expr.id);
901-
argrefs.extend(args.iter()
902-
.map(|arg| {
903-
let arg_ty = cx.tables().expr_ty_adjusted(arg);
904-
let adjusted_ty = cx.tcx.mk_ref(region,
905-
ty::TypeAndMut {
906-
ty: arg_ty,
907-
mutbl: hir::MutImmutable,
908-
});
909-
Expr {
910-
temp_lifetime: temp_lifetime,
911-
temp_lifetime_was_shrunk: was_shrunk,
912-
ty: adjusted_ty,
913-
span: expr.span,
914-
kind: ExprKind::Borrow {
915-
region: region,
916-
borrow_kind: BorrowKind::Shared,
917-
arg: arg.to_ref(),
918-
},
919-
}
920-
.to_ref()
921-
}))
922-
}
923-
}
924-
925-
// now create the call itself
926-
let fun = method_callee(cx, expr, custom_callee);
831+
let fun = method_callee(cx, expr, None);
927832
ExprKind::Call {
928833
ty: fun.ty,
929834
fun: fun.to_ref(),
930-
args: argrefs,
835+
args,
931836
}
932837
}
933838

934839
fn overloaded_lvalue<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
935840
expr: &'tcx hir::Expr,
936841
lvalue_ty: Ty<'tcx>,
937842
custom_callee: Option<(DefId, &'tcx Substs<'tcx>)>,
938-
pass_args: PassArgs,
939-
receiver: ExprRef<'tcx>,
940-
args: Vec<&'tcx P<hir::Expr>>)
843+
args: Vec<ExprRef<'tcx>>)
941844
-> ExprKind<'tcx> {
942845
// For an overloaded *x or x[y] expression of type T, the method
943846
// call returns an &T and we must add the deref so that the types
944847
// line up (this is because `*x` and `x[y]` represent lvalues):
945848

946-
let recv_ty = match receiver {
849+
let recv_ty = match args[0] {
947850
ExprRef::Hair(e) => cx.tables().expr_ty_adjusted(e),
948851
ExprRef::Mirror(ref e) => e.ty
949852
};
@@ -963,13 +866,17 @@ fn overloaded_lvalue<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
963866
// construct the complete expression `foo()` for the overloaded call,
964867
// which will yield the &T type
965868
let (temp_lifetime, was_shrunk) = cx.region_maps.temporary_scope2(expr.id);
966-
let ref_kind = overloaded_operator(cx, expr, custom_callee, pass_args, receiver, args);
869+
let fun = method_callee(cx, expr, custom_callee);
967870
let ref_expr = Expr {
968871
temp_lifetime: temp_lifetime,
969872
temp_lifetime_was_shrunk: was_shrunk,
970873
ty: ref_ty,
971874
span: expr.span,
972-
kind: ref_kind,
875+
kind: ExprKind::Call {
876+
ty: fun.ty,
877+
fun: fun.to_ref(),
878+
args,
879+
},
973880
};
974881

975882
// construct and return a deref wrapper `*foo()`

0 commit comments

Comments
 (0)