From 3c0f3b04b52134b870baf2ca8cedc5067cc5cb7e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jannis=20Christopher=20K=C3=B6hl?= Date: Fri, 7 Oct 2022 01:10:10 +0200 Subject: [PATCH] Only assume Stacked Borrows if -Zunsound-mir-opts is given --- compiler/rustc_middle/src/mir/visit.rs | 9 + .../rustc_mir_dataflow/src/value_analysis.rs | 44 ++++- src/test/mir-opt/dataflow-const-prop/cast.rs | 1 + .../if.main.DataflowConstProp.diff | 164 +++++++++--------- src/test/mir-opt/dataflow-const-prop/if.rs | 2 +- .../ref.main.DataflowConstProp.diff | 2 +- src/test/mir-opt/dataflow-const-prop/ref.rs | 1 + 7 files changed, 137 insertions(+), 86 deletions(-) diff --git a/compiler/rustc_middle/src/mir/visit.rs b/compiler/rustc_middle/src/mir/visit.rs index ddcf3711bfc..d87eb28970e 100644 --- a/compiler/rustc_middle/src/mir/visit.rs +++ b/compiler/rustc_middle/src/mir/visit.rs @@ -1320,6 +1320,15 @@ impl PlaceContext { ) } + /// Returns `true` if this place context represents an address-of. + pub fn is_address_of(&self) -> bool { + matches!( + self, + PlaceContext::NonMutatingUse(NonMutatingUseContext::AddressOf) + | PlaceContext::MutatingUse(MutatingUseContext::AddressOf) + ) + } + /// Returns `true` if this place context represents a storage live or storage dead marker. #[inline] pub fn is_storage_marker(&self) -> bool { diff --git a/compiler/rustc_mir_dataflow/src/value_analysis.rs b/compiler/rustc_mir_dataflow/src/value_analysis.rs index fbaaee48148..9ae87418bc8 100644 --- a/compiler/rustc_mir_dataflow/src/value_analysis.rs +++ b/compiler/rustc_mir_dataflow/src/value_analysis.rs @@ -70,6 +70,7 @@ use std::fmt::{Debug, Formatter}; use rustc_data_structures::fx::FxHashMap; use rustc_index::vec::IndexVec; use rustc_middle::mir::tcx::PlaceTy; +use rustc_middle::mir::visit::{PlaceContext, Visitor}; use rustc_middle::mir::*; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_span::DUMMY_SP; @@ -567,7 +568,17 @@ impl Map { filter: impl FnMut(Ty<'tcx>) -> bool, ) -> Self { let mut map = Self::new(); - map.register_with_filter(tcx, body, 3, filter); + + // If `-Zunsound-mir-opts` is given, tracking through references, and tracking of places + // that have their reference taken is allowed. This would be "unsound" in the sense that + // the correctness relies on an aliasing model similar to Stacked Borrows (which is + // not yet guaranteed). + if tcx.sess.opts.unstable_opts.unsound_mir_opts { + map.register_with_filter(tcx, body, 3, filter, &[]); + } else { + map.register_with_filter(tcx, body, 0, filter, &escaped_places(body)); + } + map } @@ -577,6 +588,7 @@ impl Map { body: &Body<'tcx>, max_derefs: u32, mut filter: impl FnMut(Ty<'tcx>) -> bool, + exclude: &[Place<'tcx>], ) { let param_env = tcx.param_env_reveal_all_normalized(body.source.def_id()); let mut projection = Vec::new(); @@ -589,6 +601,7 @@ impl Map { decl.ty, &mut filter, param_env, + exclude, ); } } @@ -602,11 +615,18 @@ impl Map { ty: Ty<'tcx>, filter: &mut impl FnMut(Ty<'tcx>) -> bool, param_env: ty::ParamEnv<'tcx>, + exclude: &[Place<'tcx>], ) { + // This check could be improved. + if exclude.contains(&Place { local, projection: tcx.intern_place_elems(projection) }) { + return; + } + if filter(ty) { // This might fail if `ty` is not scalar. let _ = self.register_with_ty(local, projection, ty); } + if max_derefs > 0 { if let Some(ty::TypeAndMut { ty: deref_ty, .. }) = ty.builtin_deref(false) { // References can only be tracked if the target is `!Freeze`. @@ -620,6 +640,7 @@ impl Map { deref_ty, filter, param_env, + exclude, ); projection.pop(); } @@ -632,7 +653,7 @@ impl Map { } projection.push(PlaceElem::Field(field, ty)); self.register_with_filter_rec( - tcx, max_derefs, local, projection, ty, filter, param_env, + tcx, max_derefs, local, projection, ty, filter, param_env, exclude, ); projection.pop(); }); @@ -751,6 +772,25 @@ impl PlaceInfo { } } +/// Returns all places, that have their reference or address taken. +fn escaped_places<'tcx>(body: &Body<'tcx>) -> Vec> { + struct Collector<'tcx> { + result: Vec>, + } + + impl<'tcx> Visitor<'tcx> for Collector<'tcx> { + fn visit_place(&mut self, place: &Place<'tcx>, context: PlaceContext, _location: Location) { + if context.is_borrow() || context.is_address_of() { + self.result.push(*place); + } + } + } + + let mut collector = Collector { result: Vec::new() }; + collector.visit_body(body); + collector.result +} + struct Children<'a> { map: &'a Map, next: Option, diff --git a/src/test/mir-opt/dataflow-const-prop/cast.rs b/src/test/mir-opt/dataflow-const-prop/cast.rs index bf5838cb89d..23c360ed874 100644 --- a/src/test/mir-opt/dataflow-const-prop/cast.rs +++ b/src/test/mir-opt/dataflow-const-prop/cast.rs @@ -1,4 +1,5 @@ // unit-test: DataflowConstProp +// compile-flags: -Zunsound-mir-opts // EMIT_MIR cast.main.DataflowConstProp.diff fn main() { diff --git a/src/test/mir-opt/dataflow-const-prop/if.main.DataflowConstProp.diff b/src/test/mir-opt/dataflow-const-prop/if.main.DataflowConstProp.diff index b2c2ba6fa5c..1a5ded8cc0d 100644 --- a/src/test/mir-opt/dataflow-const-prop/if.main.DataflowConstProp.diff +++ b/src/test/mir-opt/dataflow-const-prop/if.main.DataflowConstProp.diff @@ -3,30 +3,30 @@ fn main() -> () { let mut _0: (); // return place in scope 0 at $DIR/if.rs:+0:11: +0:11 - let _1: i32; // in scope 0 at $DIR/if.rs:+2:9: +2:10 - let mut _3: bool; // in scope 0 at $DIR/if.rs:+3:16: +3:24 - let mut _4: i32; // in scope 0 at $DIR/if.rs:+3:16: +3:19 - let mut _5: &i32; // in scope 0 at $DIR/if.rs:+3:17: +3:19 - let mut _7: i32; // in scope 0 at $DIR/if.rs:+4:13: +4:14 - let mut _9: bool; // in scope 0 at $DIR/if.rs:+6:16: +6:24 - let mut _10: i32; // in scope 0 at $DIR/if.rs:+6:16: +6:19 - let mut _11: &i32; // in scope 0 at $DIR/if.rs:+6:17: +6:19 - let mut _12: i32; // in scope 0 at $DIR/if.rs:+6:38: +6:39 - let mut _14: i32; // in scope 0 at $DIR/if.rs:+7:13: +7:14 + let _1: i32; // in scope 0 at $DIR/if.rs:+1:9: +1:10 + let mut _3: bool; // in scope 0 at $DIR/if.rs:+2:16: +2:24 + let mut _4: i32; // in scope 0 at $DIR/if.rs:+2:16: +2:19 + let mut _5: &i32; // in scope 0 at $DIR/if.rs:+2:17: +2:19 + let mut _7: i32; // in scope 0 at $DIR/if.rs:+3:13: +3:14 + let mut _9: bool; // in scope 0 at $DIR/if.rs:+5:16: +5:24 + let mut _10: i32; // in scope 0 at $DIR/if.rs:+5:16: +5:19 + let mut _11: &i32; // in scope 0 at $DIR/if.rs:+5:17: +5:19 + let mut _12: i32; // in scope 0 at $DIR/if.rs:+5:38: +5:39 + let mut _14: i32; // in scope 0 at $DIR/if.rs:+6:13: +6:14 scope 1 { - debug a => _1; // in scope 1 at $DIR/if.rs:+2:9: +2:10 - let _2: i32; // in scope 1 at $DIR/if.rs:+3:9: +3:10 + debug a => _1; // in scope 1 at $DIR/if.rs:+1:9: +1:10 + let _2: i32; // in scope 1 at $DIR/if.rs:+2:9: +2:10 scope 2 { - debug b => _2; // in scope 2 at $DIR/if.rs:+3:9: +3:10 - let _6: i32; // in scope 2 at $DIR/if.rs:+4:9: +4:10 + debug b => _2; // in scope 2 at $DIR/if.rs:+2:9: +2:10 + let _6: i32; // in scope 2 at $DIR/if.rs:+3:9: +3:10 scope 3 { - debug c => _6; // in scope 3 at $DIR/if.rs:+4:9: +4:10 - let _8: i32; // in scope 3 at $DIR/if.rs:+6:9: +6:10 + debug c => _6; // in scope 3 at $DIR/if.rs:+3:9: +3:10 + let _8: i32; // in scope 3 at $DIR/if.rs:+5:9: +5:10 scope 4 { - debug d => _8; // in scope 4 at $DIR/if.rs:+6:9: +6:10 - let _13: i32; // in scope 4 at $DIR/if.rs:+7:9: +7:10 + debug d => _8; // in scope 4 at $DIR/if.rs:+5:9: +5:10 + let _13: i32; // in scope 4 at $DIR/if.rs:+6:9: +6:10 scope 5 { - debug e => _13; // in scope 5 at $DIR/if.rs:+7:9: +7:10 + debug e => _13; // in scope 5 at $DIR/if.rs:+6:9: +6:10 } } } @@ -34,87 +34,87 @@ } bb0: { - StorageLive(_1); // scope 0 at $DIR/if.rs:+2:9: +2:10 - _1 = const 1_i32; // scope 0 at $DIR/if.rs:+2:13: +2:14 - StorageLive(_2); // scope 1 at $DIR/if.rs:+3:9: +3:10 - StorageLive(_3); // scope 1 at $DIR/if.rs:+3:16: +3:24 - StorageLive(_4); // scope 1 at $DIR/if.rs:+3:16: +3:19 - StorageLive(_5); // scope 1 at $DIR/if.rs:+3:17: +3:19 - _5 = &_1; // scope 1 at $DIR/if.rs:+3:17: +3:19 -- _4 = (*_5); // scope 1 at $DIR/if.rs:+3:16: +3:19 -- _3 = Eq(move _4, const 1_i32); // scope 1 at $DIR/if.rs:+3:16: +3:24 -+ _4 = const 1_i32; // scope 1 at $DIR/if.rs:+3:16: +3:19 -+ _3 = const true; // scope 1 at $DIR/if.rs:+3:16: +3:24 - StorageDead(_5); // scope 1 at $DIR/if.rs:+3:23: +3:24 - StorageDead(_4); // scope 1 at $DIR/if.rs:+3:23: +3:24 -- switchInt(move _3) -> [false: bb2, otherwise: bb1]; // scope 1 at $DIR/if.rs:+3:16: +3:24 -+ switchInt(const true) -> [false: bb2, otherwise: bb1]; // scope 1 at $DIR/if.rs:+3:16: +3:24 + StorageLive(_1); // scope 0 at $DIR/if.rs:+1:9: +1:10 + _1 = const 1_i32; // scope 0 at $DIR/if.rs:+1:13: +1:14 + StorageLive(_2); // scope 1 at $DIR/if.rs:+2:9: +2:10 + StorageLive(_3); // scope 1 at $DIR/if.rs:+2:16: +2:24 + StorageLive(_4); // scope 1 at $DIR/if.rs:+2:16: +2:19 + StorageLive(_5); // scope 1 at $DIR/if.rs:+2:17: +2:19 + _5 = &_1; // scope 1 at $DIR/if.rs:+2:17: +2:19 +- _4 = (*_5); // scope 1 at $DIR/if.rs:+2:16: +2:19 +- _3 = Eq(move _4, const 1_i32); // scope 1 at $DIR/if.rs:+2:16: +2:24 ++ _4 = const 1_i32; // scope 1 at $DIR/if.rs:+2:16: +2:19 ++ _3 = const true; // scope 1 at $DIR/if.rs:+2:16: +2:24 + StorageDead(_5); // scope 1 at $DIR/if.rs:+2:23: +2:24 + StorageDead(_4); // scope 1 at $DIR/if.rs:+2:23: +2:24 +- switchInt(move _3) -> [false: bb2, otherwise: bb1]; // scope 1 at $DIR/if.rs:+2:16: +2:24 ++ switchInt(const true) -> [false: bb2, otherwise: bb1]; // scope 1 at $DIR/if.rs:+2:16: +2:24 } bb1: { - _2 = const 2_i32; // scope 1 at $DIR/if.rs:+3:27: +3:28 - goto -> bb3; // scope 1 at $DIR/if.rs:+3:13: +3:41 + _2 = const 2_i32; // scope 1 at $DIR/if.rs:+2:27: +2:28 + goto -> bb3; // scope 1 at $DIR/if.rs:+2:13: +2:41 } bb2: { - _2 = const 3_i32; // scope 1 at $DIR/if.rs:+3:38: +3:39 - goto -> bb3; // scope 1 at $DIR/if.rs:+3:13: +3:41 + _2 = const 3_i32; // scope 1 at $DIR/if.rs:+2:38: +2:39 + goto -> bb3; // scope 1 at $DIR/if.rs:+2:13: +2:41 } bb3: { - StorageDead(_3); // scope 1 at $DIR/if.rs:+3:40: +3:41 - StorageLive(_6); // scope 2 at $DIR/if.rs:+4:9: +4:10 - StorageLive(_7); // scope 2 at $DIR/if.rs:+4:13: +4:14 -- _7 = _2; // scope 2 at $DIR/if.rs:+4:13: +4:14 -- _6 = Add(move _7, const 1_i32); // scope 2 at $DIR/if.rs:+4:13: +4:18 -+ _7 = const 2_i32; // scope 2 at $DIR/if.rs:+4:13: +4:14 -+ _6 = const 3_i32; // scope 2 at $DIR/if.rs:+4:13: +4:18 - StorageDead(_7); // scope 2 at $DIR/if.rs:+4:17: +4:18 - StorageLive(_8); // scope 3 at $DIR/if.rs:+6:9: +6:10 - StorageLive(_9); // scope 3 at $DIR/if.rs:+6:16: +6:24 - StorageLive(_10); // scope 3 at $DIR/if.rs:+6:16: +6:19 - StorageLive(_11); // scope 3 at $DIR/if.rs:+6:17: +6:19 - _11 = &_1; // scope 3 at $DIR/if.rs:+6:17: +6:19 -- _10 = (*_11); // scope 3 at $DIR/if.rs:+6:16: +6:19 -- _9 = Eq(move _10, const 1_i32); // scope 3 at $DIR/if.rs:+6:16: +6:24 -+ _10 = const 1_i32; // scope 3 at $DIR/if.rs:+6:16: +6:19 -+ _9 = const true; // scope 3 at $DIR/if.rs:+6:16: +6:24 - StorageDead(_11); // scope 3 at $DIR/if.rs:+6:23: +6:24 - StorageDead(_10); // scope 3 at $DIR/if.rs:+6:23: +6:24 -- switchInt(move _9) -> [false: bb5, otherwise: bb4]; // scope 3 at $DIR/if.rs:+6:16: +6:24 -+ switchInt(const true) -> [false: bb5, otherwise: bb4]; // scope 3 at $DIR/if.rs:+6:16: +6:24 + StorageDead(_3); // scope 1 at $DIR/if.rs:+2:40: +2:41 + StorageLive(_6); // scope 2 at $DIR/if.rs:+3:9: +3:10 + StorageLive(_7); // scope 2 at $DIR/if.rs:+3:13: +3:14 +- _7 = _2; // scope 2 at $DIR/if.rs:+3:13: +3:14 +- _6 = Add(move _7, const 1_i32); // scope 2 at $DIR/if.rs:+3:13: +3:18 ++ _7 = const 2_i32; // scope 2 at $DIR/if.rs:+3:13: +3:14 ++ _6 = const 3_i32; // scope 2 at $DIR/if.rs:+3:13: +3:18 + StorageDead(_7); // scope 2 at $DIR/if.rs:+3:17: +3:18 + StorageLive(_8); // scope 3 at $DIR/if.rs:+5:9: +5:10 + StorageLive(_9); // scope 3 at $DIR/if.rs:+5:16: +5:24 + StorageLive(_10); // scope 3 at $DIR/if.rs:+5:16: +5:19 + StorageLive(_11); // scope 3 at $DIR/if.rs:+5:17: +5:19 + _11 = &_1; // scope 3 at $DIR/if.rs:+5:17: +5:19 +- _10 = (*_11); // scope 3 at $DIR/if.rs:+5:16: +5:19 +- _9 = Eq(move _10, const 1_i32); // scope 3 at $DIR/if.rs:+5:16: +5:24 ++ _10 = const 1_i32; // scope 3 at $DIR/if.rs:+5:16: +5:19 ++ _9 = const true; // scope 3 at $DIR/if.rs:+5:16: +5:24 + StorageDead(_11); // scope 3 at $DIR/if.rs:+5:23: +5:24 + StorageDead(_10); // scope 3 at $DIR/if.rs:+5:23: +5:24 +- switchInt(move _9) -> [false: bb5, otherwise: bb4]; // scope 3 at $DIR/if.rs:+5:16: +5:24 ++ switchInt(const true) -> [false: bb5, otherwise: bb4]; // scope 3 at $DIR/if.rs:+5:16: +5:24 } bb4: { -- _8 = _1; // scope 3 at $DIR/if.rs:+6:27: +6:28 -+ _8 = const 1_i32; // scope 3 at $DIR/if.rs:+6:27: +6:28 - goto -> bb6; // scope 3 at $DIR/if.rs:+6:13: +6:45 +- _8 = _1; // scope 3 at $DIR/if.rs:+5:27: +5:28 ++ _8 = const 1_i32; // scope 3 at $DIR/if.rs:+5:27: +5:28 + goto -> bb6; // scope 3 at $DIR/if.rs:+5:13: +5:45 } bb5: { - StorageLive(_12); // scope 3 at $DIR/if.rs:+6:38: +6:39 - _12 = _1; // scope 3 at $DIR/if.rs:+6:38: +6:39 - _8 = Add(move _12, const 1_i32); // scope 3 at $DIR/if.rs:+6:38: +6:43 - StorageDead(_12); // scope 3 at $DIR/if.rs:+6:42: +6:43 - goto -> bb6; // scope 3 at $DIR/if.rs:+6:13: +6:45 + StorageLive(_12); // scope 3 at $DIR/if.rs:+5:38: +5:39 + _12 = _1; // scope 3 at $DIR/if.rs:+5:38: +5:39 + _8 = Add(move _12, const 1_i32); // scope 3 at $DIR/if.rs:+5:38: +5:43 + StorageDead(_12); // scope 3 at $DIR/if.rs:+5:42: +5:43 + goto -> bb6; // scope 3 at $DIR/if.rs:+5:13: +5:45 } bb6: { - StorageDead(_9); // scope 3 at $DIR/if.rs:+6:44: +6:45 - StorageLive(_13); // scope 4 at $DIR/if.rs:+7:9: +7:10 - StorageLive(_14); // scope 4 at $DIR/if.rs:+7:13: +7:14 -- _14 = _8; // scope 4 at $DIR/if.rs:+7:13: +7:14 -- _13 = Add(move _14, const 1_i32); // scope 4 at $DIR/if.rs:+7:13: +7:18 -+ _14 = const 1_i32; // scope 4 at $DIR/if.rs:+7:13: +7:14 -+ _13 = const 2_i32; // scope 4 at $DIR/if.rs:+7:13: +7:18 - StorageDead(_14); // scope 4 at $DIR/if.rs:+7:17: +7:18 - _0 = const (); // scope 0 at $DIR/if.rs:+0:11: +8:2 - StorageDead(_13); // scope 4 at $DIR/if.rs:+8:1: +8:2 - StorageDead(_8); // scope 3 at $DIR/if.rs:+8:1: +8:2 - StorageDead(_6); // scope 2 at $DIR/if.rs:+8:1: +8:2 - StorageDead(_2); // scope 1 at $DIR/if.rs:+8:1: +8:2 - StorageDead(_1); // scope 0 at $DIR/if.rs:+8:1: +8:2 - return; // scope 0 at $DIR/if.rs:+8:2: +8:2 + StorageDead(_9); // scope 3 at $DIR/if.rs:+5:44: +5:45 + StorageLive(_13); // scope 4 at $DIR/if.rs:+6:9: +6:10 + StorageLive(_14); // scope 4 at $DIR/if.rs:+6:13: +6:14 +- _14 = _8; // scope 4 at $DIR/if.rs:+6:13: +6:14 +- _13 = Add(move _14, const 1_i32); // scope 4 at $DIR/if.rs:+6:13: +6:18 ++ _14 = const 1_i32; // scope 4 at $DIR/if.rs:+6:13: +6:14 ++ _13 = const 2_i32; // scope 4 at $DIR/if.rs:+6:13: +6:18 + StorageDead(_14); // scope 4 at $DIR/if.rs:+6:17: +6:18 + _0 = const (); // scope 0 at $DIR/if.rs:+0:11: +7:2 + StorageDead(_13); // scope 4 at $DIR/if.rs:+7:1: +7:2 + StorageDead(_8); // scope 3 at $DIR/if.rs:+7:1: +7:2 + StorageDead(_6); // scope 2 at $DIR/if.rs:+7:1: +7:2 + StorageDead(_2); // scope 1 at $DIR/if.rs:+7:1: +7:2 + StorageDead(_1); // scope 0 at $DIR/if.rs:+7:1: +7:2 + return; // scope 0 at $DIR/if.rs:+7:2: +7:2 } } diff --git a/src/test/mir-opt/dataflow-const-prop/if.rs b/src/test/mir-opt/dataflow-const-prop/if.rs index 8df89080477..cc41da2dc9a 100644 --- a/src/test/mir-opt/dataflow-const-prop/if.rs +++ b/src/test/mir-opt/dataflow-const-prop/if.rs @@ -1,8 +1,8 @@ // unit-test: DataflowConstProp +// compile-flags: -Zunsound-mir-opts // EMIT_MIR if.main.DataflowConstProp.diff fn main() { - // This does not work (yet). Needs perhaps additional state to track unreachability. let a = 1; let b = if *&a == 1 { 2 } else { 3 }; let c = b + 1; diff --git a/src/test/mir-opt/dataflow-const-prop/ref.main.DataflowConstProp.diff b/src/test/mir-opt/dataflow-const-prop/ref.main.DataflowConstProp.diff index 6af381617f9..f500c827786 100644 --- a/src/test/mir-opt/dataflow-const-prop/ref.main.DataflowConstProp.diff +++ b/src/test/mir-opt/dataflow-const-prop/ref.main.DataflowConstProp.diff @@ -37,7 +37,7 @@ StorageLive(_6); // scope 2 at $DIR/ref.rs:+3:16: +3:34 _6 = id() -> bb1; // scope 2 at $DIR/ref.rs:+3:16: +3:34 // mir::Constant - // + span: $DIR/ref.rs:7:16: 7:32 + // + span: $DIR/ref.rs:8:16: 8:32 // + literal: Const { ty: fn() -> u32 {id}, val: Value() } } diff --git a/src/test/mir-opt/dataflow-const-prop/ref.rs b/src/test/mir-opt/dataflow-const-prop/ref.rs index 6da613fc516..6c0e3063b0a 100644 --- a/src/test/mir-opt/dataflow-const-prop/ref.rs +++ b/src/test/mir-opt/dataflow-const-prop/ref.rs @@ -1,4 +1,5 @@ // unit-test: DataflowConstProp +// compile-flags: -Zunsound-mir-opts // EMIT_MIR ref.main.DataflowConstProp.diff fn main() {