diff options
| -rw-r--r-- | src/librustc_mir/hair/cx/expr.rs | 36 | ||||
| -rw-r--r-- | src/test/run-pass/mir_autoderef.rs | 41 |
2 files changed, 73 insertions, 4 deletions
diff --git a/src/librustc_mir/hair/cx/expr.rs b/src/librustc_mir/hair/cx/expr.rs index 324c1e92efc..4a91f2b66a1 100644 --- a/src/librustc_mir/hair/cx/expr.rs +++ b/src/librustc_mir/hair/cx/expr.rs @@ -416,7 +416,7 @@ impl<'tcx> Mirror<'tcx> for &'tcx hir::Expr { 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 @@ impl<'tcx> Mirror<'tcx> for &'tcx hir::Expr { 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 index 00000000000..81712e4569f --- /dev/null +++ b/src/test/run-pass/mir_autoderef.rs @@ -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 _); +} |
