Skip to content

Commit 5313e87

Browse files
committed
Auto merge of #47408 - eddyb:deref-danger, r=nikomatsakis
Don't promote to 'static the result of dereferences. This is a **breaking change**, removing copies out of dereferences from rvalue-to-`'static` promotion. With miri we won't easily know whether the dereference itself would see the same value at runtime as miri (e.g. after mutating a `static`) or even if it can be interpreted (e.g. integer pointers). One alternative to this ban is defining at least *some* of those situations as UB, i.e. you shouldn't have a reference in the first place, and you should work through raw pointers instead, to avoid promotion. **EDIT**: The other *may seem* to be to add some analysis which whitelists references-to-constant-values and assume any values produced by arbitrary computation to not be safe to promote dereferences thereof - but that means producing a reference from an associated constant or `const fn` would necessarily obscure it, and in the former case, this could still impact code that runs on stable today. What we do today to track "references to statics" only works because we restrict taking a reference to a `static` at all to other `static`s (which, again, are currently limited in that they can't be read at compile-time) and to runtime-only `fn`s (*not* `const fn`s). I'm primarily opening this PR with a conservative first approximation (e.g. `&(*r).a` is not allowed, only reborrows are, and in the old borrow only implicit ones from adjustments, at that) for cratering. r? @nikomatsakis
2 parents f6216b2 + 121499a commit 5313e87

File tree

2 files changed

+46
-15
lines changed

2 files changed

+46
-15
lines changed

src/librustc_mir/transform/qualify_consts.rs

+34-2
Original file line numberDiff line numberDiff line change
@@ -526,9 +526,10 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
526526
this.add(Qualif::STATIC);
527527
}
528528

529+
this.add(Qualif::NOT_CONST);
530+
529531
let base_ty = proj.base.ty(this.mir, this.tcx).to_ty(this.tcx);
530532
if let ty::TyRawPtr(_) = base_ty.sty {
531-
this.add(Qualif::NOT_CONST);
532533
if this.mode != Mode::Fn {
533534
let mut err = struct_span_err!(
534535
this.tcx.sess,
@@ -617,7 +618,38 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
617618

618619
fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) {
619620
// Recurse through operands and places.
620-
self.super_rvalue(rvalue, location);
621+
if let Rvalue::Ref(region, kind, ref place) = *rvalue {
622+
let mut is_reborrow = false;
623+
if let Place::Projection(ref proj) = *place {
624+
if let ProjectionElem::Deref = proj.elem {
625+
let base_ty = proj.base.ty(self.mir, self.tcx).to_ty(self.tcx);
626+
if let ty::TyRef(..) = base_ty.sty {
627+
is_reborrow = true;
628+
}
629+
}
630+
}
631+
632+
if is_reborrow {
633+
self.nest(|this| {
634+
this.super_place(place, PlaceContext::Borrow {
635+
region,
636+
kind
637+
}, location);
638+
if !this.try_consume() {
639+
return;
640+
}
641+
642+
if this.qualif.intersects(Qualif::STATIC_REF) {
643+
this.qualif = this.qualif - Qualif::STATIC_REF;
644+
this.add(Qualif::STATIC);
645+
}
646+
});
647+
} else {
648+
self.super_rvalue(rvalue, location);
649+
}
650+
} else {
651+
self.super_rvalue(rvalue, location);
652+
}
621653

622654
match *rvalue {
623655
Rvalue::Use(_) |

src/librustc_passes/consts.rs

+12-13
Original file line numberDiff line numberDiff line change
@@ -362,14 +362,9 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, e: &hir::Expr, node
362362
hir::ExprBox(_) => {
363363
v.promotable = false;
364364
}
365-
hir::ExprUnary(op, ref inner) => {
366-
match v.tables.node_id_to_type(inner.hir_id).sty {
367-
ty::TyRawPtr(_) => {
368-
assert!(op == hir::UnDeref);
369-
370-
v.promotable = false;
371-
}
372-
_ => {}
365+
hir::ExprUnary(op, _) => {
366+
if op == hir::UnDeref {
367+
v.promotable = false;
373368
}
374369
}
375370
hir::ExprBinary(op, ref lhs, _) => {
@@ -558,7 +553,8 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, e: &hir::Expr, node
558553
fn check_adjustments<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, e: &hir::Expr) {
559554
use rustc::ty::adjustment::*;
560555

561-
for adjustment in v.tables.expr_adjustments(e) {
556+
let mut adjustments = v.tables.expr_adjustments(e).iter().peekable();
557+
while let Some(adjustment) = adjustments.next() {
562558
match adjustment.kind {
563559
Adjust::NeverToAny |
564560
Adjust::ReifyFnPointer |
@@ -568,11 +564,14 @@ fn check_adjustments<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, e: &hir::Exp
568564
Adjust::Borrow(_) |
569565
Adjust::Unsize => {}
570566

571-
Adjust::Deref(ref overloaded) => {
572-
if overloaded.is_some() {
573-
v.promotable = false;
574-
break;
567+
Adjust::Deref(_) => {
568+
if let Some(next_adjustment) = adjustments.peek() {
569+
if let Adjust::Borrow(_) = next_adjustment.kind {
570+
continue;
571+
}
575572
}
573+
v.promotable = false;
574+
break;
576575
}
577576
}
578577
}

0 commit comments

Comments
 (0)