]> git.lizzy.rs Git - rust.git/commitdiff
deref the argument of overloaded MIR autoderef
authorAriel Ben-Yehuda <arielb1@mail.tau.ac.il>
Thu, 11 Feb 2016 16:31:31 +0000 (18:31 +0200)
committerAriel Ben-Yehuda <ariel.byd@gmail.com>
Fri, 19 Feb 2016 23:54:58 +0000 (01:54 +0200)
Fixes #31466

src/librustc_mir/hair/cx/expr.rs
src/test/run-pass/mir_autoderef.rs [new file with mode: 0644]

index 324c1e92efc2ed7ba6caea72501dca6741cedc43..4a91f2b66a1ebd10eba43e078c3213da04982366 100644 (file)
@@ -416,7 +416,7 @@ fn make_mirror<'a>(self, cx: &mut Cx<'a, 'tcx>) -> Expr<'tcx> {
             kind: kind,
         };
 
-        debug!("unadjusted-expr={:?} applying adjustments={:?}",
+        debug!("make_mirror: unadjusted-expr={:?} applying adjustments={:?}",
                expr, cx.tcx.tables.borrow().adjustments.get(&self.id));
 
         // Now apply adjustments, if any.
@@ -459,10 +459,38 @@ fn make_mirror<'a>(self, cx: &mut Cx<'a, 'tcx>) -> Expr<'tcx> {
                             self.span,
                             i,
                             |mc| cx.tcx.tables.borrow().method_map.get(&mc).map(|m| m.ty));
-                    let kind = if cx.tcx.is_overloaded_autoderef(self.id, i) {
-                        overloaded_lvalue(cx, self, ty::MethodCall::autoderef(self.id, i),
-                                          PassArgs::ByValue, expr.to_ref(), vec![])
+                    debug!("make_mirror: autoderef #{}, adjusted_ty={:?}", i, adjusted_ty);
+                    let method_key = ty::MethodCall::autoderef(self.id, i);
+                    let meth_ty =
+                        cx.tcx.tables.borrow().method_map.get(&method_key).map(|m| m.ty);
+                    let kind = if let Some(meth_ty) = meth_ty {
+                        debug!("make_mirror: overloaded autoderef (meth_ty={:?})", meth_ty);
+
+                        let ref_ty = cx.tcx.no_late_bound_regions(&meth_ty.fn_ret());
+                        let (region, mutbl) = match ref_ty {
+                            Some(ty::FnConverging(&ty::TyS {
+                                sty: ty::TyRef(region, mt), ..
+                            })) => (region, mt.mutbl),
+                            _ => cx.tcx.sess.span_bug(
+                                expr.span, "autoderef returned bad type")
+                        };
+
+                        expr = Expr {
+                            temp_lifetime: temp_lifetime,
+                            ty: cx.tcx.mk_ref(
+                                region, ty::TypeAndMut { ty: expr.ty, mutbl: mutbl }),
+                            span: expr.span,
+                            kind: ExprKind::Borrow {
+                                region: *region,
+                                borrow_kind: to_borrow_kind(mutbl),
+                                arg: expr.to_ref()
+                            }
+                        };
+
+                        overloaded_lvalue(cx, self, method_key,
+                                          PassArgs::ByRef, expr.to_ref(), vec![])
                     } else {
+                        debug!("make_mirror: built-in autoderef");
                         ExprKind::Deref { arg: expr.to_ref() }
                     };
                     expr = Expr {
diff --git a/src/test/run-pass/mir_autoderef.rs b/src/test/run-pass/mir_autoderef.rs
new file mode 100644 (file)
index 0000000..81712e4
--- /dev/null
@@ -0,0 +1,41 @@
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(rustc_attrs)]
+
+use std::ops::{Deref, DerefMut};
+
+pub struct MyRef(u32);
+
+impl Deref for MyRef {
+    type Target = u32;
+    fn deref(&self) -> &u32 { &self.0 }
+}
+
+impl DerefMut for MyRef {
+    fn deref_mut(&mut self) -> &mut u32 { &mut self.0 }
+}
+
+
+#[rustc_mir]
+fn deref(x: &MyRef) -> &u32 {
+    x
+}
+
+#[rustc_mir]
+fn deref_mut(x: &mut MyRef) -> &mut u32 {
+    x
+}
+
+fn main() {
+    let mut r = MyRef(2);
+    assert_eq!(deref(&r) as *const _, &r.0 as *const _);
+    assert_eq!(deref_mut(&mut r) as *mut _, &mut r.0 as *mut _);
+}