diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs index b896e6ca85343..9c7df7e672b9f 100644 --- a/src/librustc_mir/transform/qualify_consts.rs +++ b/src/librustc_mir/transform/qualify_consts.rs @@ -491,9 +491,10 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> { this.add(Qualif::STATIC); } + this.add(Qualif::NOT_CONST); + let base_ty = proj.base.ty(this.mir, this.tcx).to_ty(this.tcx); if let ty::TyRawPtr(_) = base_ty.sty { - this.add(Qualif::NOT_CONST); if this.mode != Mode::Fn { struct_span_err!(this.tcx.sess, this.span, E0396, @@ -570,7 +571,38 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> { fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) { // Recurse through operands and places. - self.super_rvalue(rvalue, location); + if let Rvalue::Ref(region, kind, ref place) = *rvalue { + let mut is_reborrow = false; + if let Place::Projection(ref proj) = *place { + if let ProjectionElem::Deref = proj.elem { + let base_ty = proj.base.ty(self.mir, self.tcx).to_ty(self.tcx); + if let ty::TyRef(..) = base_ty.sty { + is_reborrow = true; + } + } + } + + if is_reborrow { + self.nest(|this| { + this.super_place(place, PlaceContext::Borrow { + region, + kind + }, location); + if !this.try_consume() { + return; + } + + if this.qualif.intersects(Qualif::STATIC_REF) { + this.qualif = this.qualif - Qualif::STATIC_REF; + this.add(Qualif::STATIC); + } + }); + } else { + self.super_rvalue(rvalue, location); + } + } else { + self.super_rvalue(rvalue, location); + } match *rvalue { Rvalue::Use(_) | diff --git a/src/librustc_passes/consts.rs b/src/librustc_passes/consts.rs index 6df860492f05a..3efed7f1f5de1 100644 --- a/src/librustc_passes/consts.rs +++ b/src/librustc_passes/consts.rs @@ -352,14 +352,9 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, e: &hir::Expr, node hir::ExprBox(_) => { v.promotable = false; } - hir::ExprUnary(op, ref inner) => { - match v.tables.node_id_to_type(inner.hir_id).sty { - ty::TyRawPtr(_) => { - assert!(op == hir::UnDeref); - - v.promotable = false; - } - _ => {} + hir::ExprUnary(op, _) => { + if op == hir::UnDeref { + v.promotable = false; } } hir::ExprBinary(op, ref lhs, _) => { @@ -548,7 +543,8 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, e: &hir::Expr, node fn check_adjustments<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, e: &hir::Expr) { use rustc::ty::adjustment::*; - for adjustment in v.tables.expr_adjustments(e) { + let mut adjustments = v.tables.expr_adjustments(e).iter().peekable(); + while let Some(adjustment) = adjustments.next() { match adjustment.kind { Adjust::NeverToAny | Adjust::ReifyFnPointer | @@ -558,11 +554,14 @@ fn check_adjustments<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, e: &hir::Exp Adjust::Borrow(_) | Adjust::Unsize => {} - Adjust::Deref(ref overloaded) => { - if overloaded.is_some() { - v.promotable = false; - break; + Adjust::Deref(_) => { + if let Some(next_adjustment) = adjustments.peek() { + if let Adjust::Borrow(_) = next_adjustment.kind { + continue; + } } + v.promotable = false; + break; } } }