diff --git a/src/librustc/diagnostics.rs b/src/librustc/diagnostics.rs index eb504d03209f6..c329f2fb012db 100644 --- a/src/librustc/diagnostics.rs +++ b/src/librustc/diagnostics.rs @@ -1237,5 +1237,6 @@ register_diagnostics! { E0314, // closure outlives stack frame E0315, // cannot invoke closure outside of its lifetime E0316, // nested quantification of lifetimes - E0370 // discriminant overflow + E0370, // discriminant overflow + E0400 // overloaded derefs are not allowed in constants } diff --git a/src/librustc/middle/cfg/construct.rs b/src/librustc/middle/cfg/construct.rs index 7d62b6ff90040..d4737f9d604d1 100644 --- a/src/librustc/middle/cfg/construct.rs +++ b/src/librustc/middle/cfg/construct.rs @@ -332,7 +332,7 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> { } ast::ExprIndex(ref l, ref r) | - ast::ExprBinary(_, ref l, ref r) if self.is_method_call(expr) => { + ast::ExprBinary(_, ref l, ref r) if self.tcx.is_method_call(expr.id) => { self.call(expr, pred, &**l, Some(&**r).into_iter()) } @@ -342,7 +342,7 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> { self.straightline(expr, pred, fields) } - ast::ExprUnary(_, ref e) if self.is_method_call(expr) => { + ast::ExprUnary(_, ref e) if self.tcx.is_method_call(expr.id) => { self.call(expr, pred, &**e, None::.iter()) } @@ -631,9 +631,4 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> { } } } - - fn is_method_call(&self, expr: &ast::Expr) -> bool { - let method_call = ty::MethodCall::expr(expr.id); - self.tcx.tables.borrow().method_map.contains_key(&method_call) - } } diff --git a/src/librustc/middle/check_const.rs b/src/librustc/middle/check_const.rs index b5c78340d022d..59f91a50f7421 100644 --- a/src/librustc/middle/check_const.rs +++ b/src/librustc/middle/check_const.rs @@ -405,6 +405,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for CheckCrateVisitor<'a, 'tcx> { let node_ty = self.tcx.node_id_to_type(ex.id); check_expr(self, ex, node_ty); + check_adjustments(self, ex); // Special-case some expressions to avoid certain flags bubbling up. match ex.node { @@ -777,6 +778,25 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, } } +/// Check the adjustments of an expression +fn check_adjustments<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, e: &ast::Expr) { + match v.tcx.tables.borrow().adjustments.get(&e.id) { + None | Some(&ty::AdjustReifyFnPointer) | Some(&ty::AdjustUnsafeFnPointer) => {} + Some(&ty::AdjustDerefRef(ty::AutoDerefRef { autoderefs, .. })) => { + if (0..autoderefs as u32).any(|autoderef| { + v.tcx.is_overloaded_autoderef(e.id, autoderef) + }) { + v.add_qualif(ConstQualif::NOT_CONST); + if v.mode != Mode::Var { + span_err!(v.tcx.sess, e.span, E0400, + "user-defined dereference operators are not allowed in {}s", + v.msg()); + } + } + } + } +} + pub fn check_crate(tcx: &ty::ctxt) { visit::walk_crate(&mut CheckCrateVisitor { tcx: tcx, diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index 715072a12ebd0..b4b8fbf2064ad 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -6631,6 +6631,11 @@ impl<'tcx> ctxt<'tcx> { self.tables.borrow().method_map.contains_key(&MethodCall::expr(expr_id)) } + pub fn is_overloaded_autoderef(&self, expr_id: ast::NodeId, autoderefs: u32) -> bool { + self.tables.borrow().method_map.contains_key(&MethodCall::autoderef(expr_id, + autoderefs)) + } + pub fn upvar_capture(&self, upvar_id: ty::UpvarId) -> Option { Some(self.tables.borrow().upvar_capture_map.get(&upvar_id).unwrap().clone()) } diff --git a/src/librustc_trans/trans/expr.rs b/src/librustc_trans/trans/expr.rs index 7722cb322c9e6..c88c194106e8c 100644 --- a/src/librustc_trans/trans/expr.rs +++ b/src/librustc_trans/trans/expr.rs @@ -367,8 +367,7 @@ fn apply_adjustments<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, match datum.ty.sty { // Don't skip a conversion from Box to &T, etc. ty::TyRef(..) => { - let method_call = MethodCall::autoderef(expr.id, 0); - if bcx.tcx().tables.borrow().method_map.contains_key(&method_call) { + if bcx.tcx().is_overloaded_autoderef(expr.id, 0) { // Don't skip an overloaded deref. 0 } else { @@ -1612,9 +1611,7 @@ fn trans_unary<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, // The only overloaded operator that is translated to a datum // is an overloaded deref, since it is always yields a `&T`. // Otherwise, we should be in the RvalueDpsExpr path. - assert!( - op == ast::UnDeref || - !ccx.tcx().tables.borrow().method_map.contains_key(&method_call)); + assert!(op == ast::UnDeref || !ccx.tcx().is_method_call(expr.id)); let un_ty = expr_ty(bcx, expr); @@ -1907,7 +1904,7 @@ fn trans_binary<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, let ccx = bcx.ccx(); // if overloaded, would be RvalueDpsExpr - assert!(!ccx.tcx().tables.borrow().method_map.contains_key(&MethodCall::expr(expr.id))); + assert!(!ccx.tcx().is_method_call(expr.id)); match op.node { ast::BiAnd => { @@ -2141,7 +2138,7 @@ fn trans_assign_op<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, debug!("trans_assign_op(expr={:?})", expr); // User-defined operator methods cannot be used with `+=` etc right now - assert!(!bcx.tcx().tables.borrow().method_map.contains_key(&MethodCall::expr(expr.id))); + assert!(!bcx.tcx().is_method_call(expr.id)); // Evaluate LHS (destination), which should be an lvalue let dst_datum = unpack_datum!(bcx, trans_to_lvalue(bcx, dst, "assign_op")); @@ -2606,7 +2603,7 @@ enum ExprKind { } fn expr_kind(tcx: &ty::ctxt, expr: &ast::Expr) -> ExprKind { - if tcx.tables.borrow().method_map.contains_key(&MethodCall::expr(expr.id)) { + if tcx.is_method_call(expr.id) { // Overloaded operations are generally calls, and hence they are // generated via DPS, but there are a few exceptions: return match expr.node { diff --git a/src/librustc_typeck/check/regionck.rs b/src/librustc_typeck/check/regionck.rs index bb3c9f9fb5425..1c21813fc63bd 100644 --- a/src/librustc_typeck/check/regionck.rs +++ b/src/librustc_typeck/check/regionck.rs @@ -516,8 +516,7 @@ fn visit_expr(rcx: &mut Rcx, expr: &ast::Expr) { type_must_outlive(rcx, infer::ExprTypeIsNotInScope(expr_ty, expr.span), expr_ty, ty::ReScope(CodeExtent::from_node_id(expr.id))); - let method_call = MethodCall::expr(expr.id); - let has_method_map = rcx.fcx.inh.tables.borrow().method_map.contains_key(&method_call); + let has_method_map = rcx.fcx.infcx().is_method_call(expr.id); // Check any autoderefs or autorefs that appear. let adjustment = rcx.fcx.inh.tables.borrow().adjustments.get(&expr.id).map(|a| a.clone()); diff --git a/src/test/compile-fail/issue-25901.rs b/src/test/compile-fail/issue-25901.rs new file mode 100644 index 0000000000000..3254f0b2aa9bd --- /dev/null +++ b/src/test/compile-fail/issue-25901.rs @@ -0,0 +1,23 @@ +// Copyright 2015 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +struct A; +struct B; + +static S: &'static B = &A; //~ ERROR user-defined dereference operators + +use std::ops::Deref; + +impl Deref for A { + type Target = B; + fn deref(&self)->&B { static B_: B = B; &B_ } +} + +fn main(){}