diff --git a/Cargo.lock b/Cargo.lock index 562f76d80..b2a54dd9e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,6 +1,6 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -version = 3 +version = 4 [[package]] name = "Inflector" @@ -23,6 +23,17 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" +[[package]] +name = "aes" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0" +dependencies = [ + "cfg-if", + "cipher", + "cpufeatures", +] + [[package]] name = "aho-corasick" version = "1.0.5" @@ -120,7 +131,7 @@ dependencies = [ "rustc_utils", "serde", "test-log", - "ts-rs", + "ts-rs 7.1.1", ] [[package]] @@ -138,7 +149,7 @@ dependencies = [ "rustc_utils", "serde", "serde_json", - "ts-rs", + "ts-rs 6.2.1", ] [[package]] @@ -414,6 +425,37 @@ dependencies = [ "windows-targets 0.52.6", ] +[[package]] +name = "chrono-tz" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd6dd8046d00723a59a2f8c5f295c515b9bb9a331ee4f8f3d4dd49e428acd3b6" +dependencies = [ + "chrono", + "chrono-tz-build", + "phf", +] + +[[package]] +name = "chrono-tz-build" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e94fea34d77a245229e7746bd2beb786cd2a896f306ff491fb8cecb3074b10a7" +dependencies = [ + "parse-zoneinfo", + "phf_codegen", +] + +[[package]] +name = "cipher" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" +dependencies = [ + "crypto-common", + "inout", +] + [[package]] name = "clap" version = "3.2.25" @@ -597,16 +639,6 @@ dependencies = [ "typenum", ] -[[package]] -name = "ctrlc" -version = "3.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82e95fbd621905b854affdc67943b043a0fbb6ed7385fd5a25650d19a8a6cfdf" -dependencies = [ - "nix", - "windows-sys 0.48.0", -] - [[package]] name = "darling" version = "0.13.4" @@ -652,6 +684,27 @@ dependencies = [ "crypto-common", ] +[[package]] +name = "directories" +version = "5.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a49173b84e034382284f27f1af4dcbbd231ffa358c0fe316541a7337f376a35" +dependencies = [ + "dirs-sys", +] + +[[package]] +name = "dirs-sys" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "520f05a5cbd335fae5a99ff7a6ab8627577660ee5cfd6a94a6a929b52ff0321c" +dependencies = [ + "libc", + "option-ext", + "redox_users", + "windows-sys 0.48.0", +] + [[package]] name = "doc-comment" version = "0.3.3" @@ -1111,6 +1164,15 @@ dependencies = [ "hashbrown 0.14.0", ] +[[package]] +name = "inout" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0c10553d664a4d0bcff9f4215d0aac67a639cc68ef660840afe309b807bc9f5" +dependencies = [ + "generic-array", +] + [[package]] name = "insta" version = "1.31.0" @@ -1127,15 +1189,6 @@ dependencies = [ "yaml-rust", ] -[[package]] -name = "instant" -version = "0.1.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" -dependencies = [ - "cfg-if", -] - [[package]] name = "intervaltree" version = "0.2.7" @@ -1224,12 +1277,22 @@ dependencies = [ [[package]] name = "libloading" -version = "0.7.4" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b67380fd3b2fbe7527a606e18729d21c6f3951633d0500574c4dc22d2d638b9f" +checksum = "fc2f4eb4bc735547cfed7c0a4922cbd04a4655978c09b54f1f7b228750664c34" dependencies = [ "cfg-if", - "winapi", + "windows-targets 0.48.5", +] + +[[package]] +name = "libredox" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" +dependencies = [ + "bitflags 2.4.0", + "libc", ] [[package]] @@ -1324,7 +1387,7 @@ dependencies = [ "serde", "serde_json", "tempfile", - "ts-rs", + "ts-rs 6.2.1", "wait-timeout", ] @@ -1350,9 +1413,9 @@ dependencies = [ [[package]] name = "measureme" -version = "10.1.1" +version = "11.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1930d162935fecd56fc4e0f6729eb3483bac1264542eb4ea31570b86a434b6bc" +checksum = "dfa4a40f09af7aa6faef38285402a78847d0d72bf8827006cd2a332e1e6e4a8d" dependencies = [ "log", "memmap2", @@ -1421,29 +1484,20 @@ dependencies = [ [[package]] name = "miri" version = "0.1.0" -source = "git+https://github.com/rust-lang/miri.git?rev=63c5542edf907dd797db82c4c2979e3c4df71a8b#63c5542edf907dd797db82c4c2979e3c4df71a8b" dependencies = [ - "ctrlc", - "env_logger 0.9.3", + "aes", + "chrono", + "chrono-tz", + "directories", "getrandom", "libc", "libffi", "libloading", - "log", "measureme", "rand", "smallvec", -] - -[[package]] -name = "nix" -version = "0.27.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2eb04e9c688eff1c89d72b407f168cf79bb9e867a9d3323ed6c01519eb9cc053" -dependencies = [ - "bitflags 2.4.0", - "cfg-if", - "libc", + "tikv-jemalloc-sys", + "windows-sys 0.52.0", ] [[package]] @@ -1511,6 +1565,12 @@ dependencies = [ "winapi", ] +[[package]] +name = "option-ext" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" + [[package]] name = "os_str_bytes" version = "6.5.1" @@ -1519,27 +1579,34 @@ checksum = "4d5d9eb14b174ee9aa2ef96dc2b94637a2d4b6e7cb873c7e171f0c20c6cf3eac" [[package]] name = "parking_lot" -version = "0.11.2" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99" +checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" dependencies = [ - "instant", "lock_api", "parking_lot_core", ] [[package]] name = "parking_lot_core" -version = "0.8.6" +version = "0.9.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60a2cfe6f0ad2bfc16aefa463b497d5c7a5ecd44a23efa72aa342d90177356dc" +checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" dependencies = [ "cfg-if", - "instant", "libc", - "redox_syscall 0.2.16", + "redox_syscall 0.5.7", "smallvec", - "winapi", + "windows-targets 0.52.6", +] + +[[package]] +name = "parse-zoneinfo" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f2a05b18d44e2957b88f96ba460715e295bc1d7510468a2f3d3b44535d26c24" +dependencies = [ + "regex", ] [[package]] @@ -1602,6 +1669,44 @@ dependencies = [ "sha2", ] +[[package]] +name = "phf" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ade2d8b8f33c7333b51bcf0428d37e217e9f32192ae4772156f65063b8ce03dc" +dependencies = [ + "phf_shared", +] + +[[package]] +name = "phf_codegen" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8d39688d359e6b34654d328e262234662d16cc0f60ec8dcbe5e718709342a5a" +dependencies = [ + "phf_generator", + "phf_shared", +] + +[[package]] +name = "phf_generator" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48e4cc64c2ad9ebe670cb8fd69dd50ae301650392e81c05f9bfcb2d5bdbc24b0" +dependencies = [ + "phf_shared", + "rand", +] + +[[package]] +name = "phf_shared" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90fcb95eef784c2ac79119d1dd819e162b5da872ce6f3c3abe1e8ca1c082f72b" +dependencies = [ + "siphasher", +] + [[package]] name = "pin-project" version = "1.1.3" @@ -1747,20 +1852,31 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.2.16" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" +checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29" dependencies = [ "bitflags 1.3.2", ] [[package]] name = "redox_syscall" -version = "0.3.5" +version = "0.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29" +checksum = "9b6dfecf2c74bce2466cabf93f6664d6998a69eb21e39f4207930065b27b771f" dependencies = [ - "bitflags 1.3.2", + "bitflags 2.4.0", +] + +[[package]] +name = "redox_users" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43" +dependencies = [ + "getrandom", + "libredox", + "thiserror", ] [[package]] @@ -1806,8 +1922,7 @@ checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" [[package]] name = "rustc_plugin" -version = "0.7.0-nightly-2023-08-25" -source = "git+https://github.com/cognitive-engineering-lab/rustc_plugin?rev=d4b3c43b0695d42030f9cb3a62fc27cc337019d1#d4b3c43b0695d42030f9cb3a62fc27cc337019d1" +version = "0.11.0-nightly-2024-12-01" dependencies = [ "cargo_metadata", "log", @@ -1825,8 +1940,7 @@ checksum = "b3c5a95edfa0c893236ae4778bb7c4752760e4c0d245e19b5eff33c5aa5eb9dc" [[package]] name = "rustc_utils" -version = "0.7.0-nightly-2023-08-25" -source = "git+https://github.com/cognitive-engineering-lab/rustc_plugin?rev=d4b3c43b0695d42030f9cb3a62fc27cc337019d1#d4b3c43b0695d42030f9cb3a62fc27cc337019d1" +version = "0.11.0-nightly-2024-12-01" dependencies = [ "anyhow", "cfg-if", @@ -1835,7 +1949,7 @@ dependencies = [ "regex", "serde", "textwrap", - "ts-rs", + "ts-rs 7.1.1", ] [[package]] @@ -1992,6 +2106,12 @@ version = "2.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "420acb44afdae038210c99e69aae24109f32f15500aa708e81d46c9f29d55fcf" +[[package]] +name = "siphasher" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d" + [[package]] name = "slab" version = "0.4.9" @@ -2174,6 +2294,16 @@ dependencies = [ "syn 2.0.29", ] +[[package]] +name = "tikv-jemalloc-sys" +version = "0.6.0+5.3.0-1-ge13ca993e8ccb9ba9847cc330696e02839f328f7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd3c60906412afa9c2b5b5a48ca6a5abe5736aec9eb48ad05037a677e52e4e2d" +dependencies = [ + "cc", + "libc", +] + [[package]] name = "tinyvec" version = "1.6.0" @@ -2363,7 +2493,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4added4070a4fdf9df03457206cd2e4b12417c8560a2954d91ffcbe60177a56a" dependencies = [ "thiserror", - "ts-rs-macros", + "ts-rs-macros 6.2.0", +] + +[[package]] +name = "ts-rs" +version = "7.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc2cae1fc5d05d47aa24b64f9a4f7cba24cdc9187a2084dd97ac57bef5eccae6" +dependencies = [ + "thiserror", + "ts-rs-macros 7.1.1", ] [[package]] @@ -2379,6 +2519,19 @@ dependencies = [ "termcolor", ] +[[package]] +name = "ts-rs-macros" +version = "7.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73f7f9b821696963053a89a7bd8b292dc34420aea8294d7b225274d488f3ec92" +dependencies = [ + "Inflector", + "proc-macro2", + "quote", + "syn 2.0.29", + "termcolor", +] + [[package]] name = "typenum" version = "1.16.0" @@ -2598,6 +2751,15 @@ dependencies = [ "windows-targets 0.48.5", ] +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets 0.52.6", +] + [[package]] name = "windows-targets" version = "0.42.2" diff --git a/Cargo.toml b/Cargo.toml index c593e615f..00038e4fd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,6 +5,8 @@ resolver = "2" [workspace.dependencies] serde = { version = "=1.0.149", features = ["derive"] } +rustc_plugin = { path = "../rustc_plugin/crates/rustc_plugin" } +rustc_utils = { path = "../rustc_plugin/crates/rustc_utils" } # Make snapshot testing faster [profile.dev.package.insta] @@ -13,6 +15,6 @@ opt-level = 3 [profile.dev.package.similar] opt-level = 3 -[patch.crates-io] -rustc_plugin = { git = "https://github.com/cognitive-engineering-lab/rustc_plugin", rev = "d4b3c43b0695d42030f9cb3a62fc27cc337019d1" } -rustc_utils = { git = "https://github.com/cognitive-engineering-lab/rustc_plugin", rev = "d4b3c43b0695d42030f9cb3a62fc27cc337019d1" } +# [patch.crates-io] +# rustc_plugin = { git = "https://github.com/cognitive-engineering-lab/rustc_plugin", rev = "d4b3c43b0695d42030f9cb3a62fc27cc337019d1" } +# rustc_utils = { git = "https://github.com/cognitive-engineering-lab/rustc_plugin", rev = "d4b3c43b0695d42030f9cb3a62fc27cc337019d1" } diff --git a/crates/aquascope/Cargo.toml b/crates/aquascope/Cargo.toml index d983ab8ed..bd2dfe8ee 100644 --- a/crates/aquascope/Cargo.toml +++ b/crates/aquascope/Cargo.toml @@ -22,13 +22,14 @@ anyhow = "1.0.0" log = "0.4" itertools = "0.10.5" serde = { workspace = true } -ts-rs = "6.2" +ts-rs = "7" regex = "1" fluid-let = "1.0" -rustc_utils = {version = "0.7.0-nightly-2023-08-25", features = ["graphviz", "ts-rs", "serde", "test"]} +rustc_utils = {workspace = true, features = ["graphviz", "ts-rs", "serde", "test"]} # interpret module -miri = {git = "https://github.com/rust-lang/miri.git", rev = "63c5542edf907dd797db82c4c2979e3c4df71a8b"} +# miri = {git = "https://github.com/rust-lang/rust", rev = "1f3bf231e160b9869e2a85260fd6805304bfcee2"} +miri = { path = "../../../rust/src/tools/miri" } aquascope_workspace_utils = { version = "0.3", path = "../aquascope_workspace_utils" } # testing utils diff --git a/crates/aquascope/src/analysis/boundaries/mod.rs b/crates/aquascope/src/analysis/boundaries/mod.rs index 5bb595837..f1626c836 100644 --- a/crates/aquascope/src/analysis/boundaries/mod.rs +++ b/crates/aquascope/src/analysis/boundaries/mod.rs @@ -404,9 +404,9 @@ fn select_candidate_location<'tcx>( /// Return the constraints that occur nested within a [`HirId`]. /// /// Note, constraints involving regions belonging to the same SCC are removed. -fn flow_constraints_at_hir_id<'a, 'tcx: 'a>( - ctxt: &'a PermissionsCtxt<'a, 'tcx>, - ir_mapper: &'a IRMapper<'a, 'tcx>, +fn flow_constraints_at_hir_id<'tcx>( + ctxt: &PermissionsCtxt<'tcx>, + ir_mapper: &IRMapper<'tcx>, hir_id: HirId, ) -> Option> { let mir_locations = @@ -543,10 +543,10 @@ fn get_flow_permission( /// given HIR node. This builds our set of candidate places /// that we consider for boundary resolution. #[allow(clippy::wildcard_in_or_patterns)] -fn paths_at_hir_id<'a, 'tcx: 'a>( +fn paths_at_hir_id<'tcx>( tcx: TyCtxt<'tcx>, - body: &'a Body<'tcx>, - ir_mapper: &'a IRMapper<'a, 'tcx>, + body: &'tcx Body<'tcx>, + ir_mapper: &IRMapper<'tcx>, hir_id: HirId, ) -> Option)>> { type TempBuff<'tcx> = SmallVec<[(Location, Place<'tcx>); 3]>; @@ -581,7 +581,6 @@ fn paths_at_hir_id<'a, 'tcx: 'a>( // Given place cases. Rvalue::Ref(_, _, place) - | Rvalue::AddressOf(_, place) | Rvalue::Len(place) | Rvalue::Discriminant(place) | Rvalue::CopyForDeref(place) @@ -590,11 +589,10 @@ fn paths_at_hir_id<'a, 'tcx: 'a>( smallvec![(loc, *place)] } - // Two operand cases - Rvalue::BinaryOp(_, box (left_op, right_op)) - | Rvalue::CheckedBinaryOp(_, box (left_op, right_op)) => { - maybe_in_op!(loc, left_op, right_op) - } + // Operand case + Rvalue::BinaryOp(_, box (left_op, right_op)) => { + maybe_in_op!(loc, left_op, right_op) + } // Unimplemented cases, ignore nested information for now. // @@ -651,6 +649,7 @@ fn paths_at_hir_id<'a, 'tcx: 'a>( | StatementKind::Coverage(..) | StatementKind::Intrinsic(..) | StatementKind::ConstEvalCounter + | StatementKind::BackwardIncompatibleDropHint { .. } | StatementKind::Nop => smallvec![], } }; @@ -669,9 +668,9 @@ fn paths_at_hir_id<'a, 'tcx: 'a>( Some(mir_locations) } -fn path_to_perm_boundary<'a, 'tcx: 'a>( +fn path_to_perm_boundary<'tcx>( path_boundary: PathBoundary, - analysis: &'a AquascopeAnalysis<'a, 'tcx>, + analysis: &AquascopeAnalysis<'tcx>, ) -> Option { let ctxt = &analysis.permissions; let ir_mapper = &analysis.ir_mapper; @@ -763,8 +762,8 @@ fn path_to_perm_boundary<'a, 'tcx: 'a>( } #[allow(clippy::module_name_repetitions)] -pub fn compute_permission_boundaries<'a, 'tcx: 'a>( - analysis: &AquascopeAnalysis<'a, 'tcx>, +pub fn compute_permission_boundaries<'tcx>( + analysis: &AquascopeAnalysis<'tcx>, ) -> Result> { let ctxt = &analysis.permissions; diff --git a/crates/aquascope/src/analysis/boundaries/path_visitor.rs b/crates/aquascope/src/analysis/boundaries/path_visitor.rs index bb4181819..231a6e70d 100644 --- a/crates/aquascope/src/analysis/boundaries/path_visitor.rs +++ b/crates/aquascope/src/analysis/boundaries/path_visitor.rs @@ -11,7 +11,7 @@ use rustc_middle::{ hir::nested_filter::OnlyBodies, ty::{ adjustment::{Adjust, AutoBorrow}, - ParamEnv, TyCtxt, TypeckResults, + TyCtxt, TypeckResults, TypingEnv, }, }; use rustc_span::Span; @@ -23,15 +23,15 @@ use crate::analysis::permissions::PermissionsCtxt; // The current region flow context for outer statements and returns. fluid_let!(pub static FLOW_CONTEXT: HirId); -struct HirExprScraper<'a, 'tcx: 'a> { +struct HirExprScraper<'tcx> { tcx: TyCtxt<'tcx>, - typeck_res: &'a TypeckResults<'tcx>, - param_env: ParamEnv<'tcx>, + typeck_res: &'tcx TypeckResults<'tcx>, + typing_env: TypingEnv<'tcx>, data: Vec, unsupported_feature: Option<(Span, String)>, } -impl<'a, 'tcx: 'a> HirExprScraper<'a, 'tcx> { +impl<'tcx> HirExprScraper<'tcx> { fn get_adjusted_permissions(&self, expr: &Expr) -> ExpectedPermissions { let ty_adj = self.typeck_res.expr_ty_adjusted(expr); let adjs = self.typeck_res.expr_adjustments(expr); @@ -39,7 +39,7 @@ impl<'a, 'tcx: 'a> HirExprScraper<'a, 'tcx> { log::debug!("Path TY-ADJ: {:#?} from {:#?}", ty_adj, adjs); let is_auto_borrow = adjs.iter().find_map(|adj| { - if let Adjust::Borrow(AutoBorrow::Ref(_, m)) = adj.kind { + if let Adjust::Borrow(AutoBorrow::Ref(m)) = adj.kind { Some(m) } else { None @@ -53,7 +53,7 @@ impl<'a, 'tcx: 'a> HirExprScraper<'a, 'tcx> { // At this point the usage is either a move or a copy. We // can determine this whether or not the type of the path // is copyable or not. - if ty_adj.is_copyable(self.tcx, self.param_env) { + if ty_adj.is_copyable(self.tcx, self.typing_env) { ExpectedPermissions::from_copy() } else { ExpectedPermissions::from_move() @@ -61,7 +61,7 @@ impl<'a, 'tcx: 'a> HirExprScraper<'a, 'tcx> { } } -impl<'a, 'tcx: 'a> Visitor<'tcx> for HirExprScraper<'a, 'tcx> { +impl<'tcx> Visitor<'tcx> for HirExprScraper<'tcx> { type NestedFilter = OnlyBodies; fn nested_visit_map(&mut self) -> Self::Map { @@ -71,12 +71,12 @@ impl<'a, 'tcx: 'a> Visitor<'tcx> for HirExprScraper<'a, 'tcx> { // Visiting statements / body is only used for specifying a // region flow context. This would not be used for RWO // path boundaries. - fn visit_body(&mut self, body: &'tcx Body) { + fn visit_body(&mut self, body: &Body<'tcx>) { fluid_set!(FLOW_CONTEXT, &body.value.hir_id); intravisit::walk_body(self, body); } - fn visit_stmt(&mut self, stmt: &'tcx Stmt) { + fn visit_stmt(&mut self, stmt: &'tcx Stmt<'tcx>) { fluid_set!(FLOW_CONTEXT, &stmt.hir_id); intravisit::walk_stmt(self, stmt); } @@ -255,16 +255,16 @@ impl<'a, 'tcx: 'a> Visitor<'tcx> for HirExprScraper<'a, 'tcx> { } } -pub(super) fn get_path_boundaries<'a, 'tcx: 'a>( - ctxt: &'a PermissionsCtxt<'a, 'tcx>, +pub(super) fn get_path_boundaries<'tcx>( + ctxt: &PermissionsCtxt<'tcx>, ) -> Result> { let tcx = ctxt.tcx; let body_id = ctxt.body_id; let typeck_res = tcx.typeck_body(ctxt.body_id); - let param_env = ctxt.param_env; + let typing_env = ctxt.typing_env; let mut finder = HirExprScraper { tcx, - param_env, + typing_env, typeck_res, unsupported_feature: None, data: Vec::default(), diff --git a/crates/aquascope/src/analysis/find_bindings.rs b/crates/aquascope/src/analysis/find_bindings.rs index f6f47eed6..56ff4390f 100644 --- a/crates/aquascope/src/analysis/find_bindings.rs +++ b/crates/aquascope/src/analysis/find_bindings.rs @@ -1,7 +1,7 @@ use rustc_data_structures::fx::FxHashMap as HashMap; use rustc_hir::{ intravisit::{self, Visitor}, - BindingAnnotation, HirId, Pat, PatKind, + BindingMode, HirId, Pat, PatKind, }; // use rustc_hir_analysis; use rustc_middle::{hir::nested_filter::OnlyBodies, ty::TyCtxt}; @@ -9,7 +9,7 @@ use rustc_middle::{hir::nested_filter::OnlyBodies, ty::TyCtxt}; struct BindingFinder<'tcx> { tcx: TyCtxt<'tcx>, // Mapping a HirId (identifier) with it's binding annotations. - bindings: HashMap, + bindings: HashMap, } impl<'tcx> Visitor<'tcx> for BindingFinder<'tcx> { @@ -29,7 +29,7 @@ impl<'tcx> Visitor<'tcx> for BindingFinder<'tcx> { } } -pub fn find_bindings(tcx: TyCtxt) -> HashMap { +pub fn find_bindings(tcx: TyCtxt) -> HashMap { let mut finder = BindingFinder { tcx, bindings: HashMap::default(), diff --git a/crates/aquascope/src/analysis/ir_mapper/body_graph.rs b/crates/aquascope/src/analysis/ir_mapper/body_graph.rs index dab2403bd..1999253c9 100644 --- a/crates/aquascope/src/analysis/ir_mapper/body_graph.rs +++ b/crates/aquascope/src/analysis/ir_mapper/body_graph.rs @@ -11,11 +11,11 @@ use smallvec::SmallVec; /// regular control-flow. This removes cleanup blocks or those which /// fall in unwind paths. When mapping back to source-level constructs /// this is almost certainly what you want to use. -pub(crate) struct CleanedBody<'a, 'tcx: 'a>(pub &'a Body<'tcx>); +pub(crate) struct CleanedBody<'tcx>(pub &'tcx Body<'tcx>); #[allow(dead_code)] -impl<'a, 'tcx: 'a> CleanedBody<'a, 'tcx> { - pub fn body(&self) -> &'a Body<'tcx> { +impl<'tcx> CleanedBody<'tcx> { + pub fn body(&self) -> &'tcx Body<'tcx> { self.0 } @@ -57,9 +57,7 @@ impl<'a, 'tcx: 'a> CleanedBody<'a, 'tcx> { self.body().basic_blocks[block].terminator() } - pub fn blocks( - &self, - ) -> impl Iterator + Captures<'a> + Captures<'tcx> + '_ { + pub fn blocks(&self) -> impl Iterator + use<'tcx, '_> { self .0 .basic_blocks @@ -99,33 +97,23 @@ impl<'a, 'tcx: 'a> CleanedBody<'a, 'tcx> { // ----------- // Graph impls -impl DirectedGraph for CleanedBody<'_, '_> { +impl DirectedGraph for CleanedBody<'_> { type Node = BasicBlock; -} - -impl WithStartNode for CleanedBody<'_, '_> { - fn start_node(&self) -> Self::Node { - self.0.basic_blocks.start_node() - } -} -impl<'tcx> WithNumNodes for CleanedBody<'_, 'tcx> { fn num_nodes(&self) -> usize { self.0.basic_blocks.len() } } -impl<'tcx> GraphSuccessors<'_> for CleanedBody<'_, 'tcx> { - type Item = BasicBlock; - type Iter = smallvec::IntoIter<[BasicBlock; 4]>; +impl StartNode for CleanedBody<'_> { + fn start_node(&self) -> Self::Node { + self.0.basic_blocks.start_node() + } } -impl<'tcx> WithSuccessors for CleanedBody<'_, 'tcx> { - fn successors( - &self, - node: Self::Node, - ) -> >::Iter { - ::successors(&self.0.basic_blocks, node) +impl<'tcx> Successors for CleanedBody<'tcx> { + fn successors(&self, node: Self::Node) -> impl Iterator { + ::successors(&self.0.basic_blocks, node) .filter(|bb| { let from_data = &self.0.basic_blocks[*bb]; CleanedBody::keep_block(from_data) @@ -136,17 +124,9 @@ impl<'tcx> WithSuccessors for CleanedBody<'_, 'tcx> { } } -impl<'tcx> GraphPredecessors<'_> for CleanedBody<'_, 'tcx> { - type Item = BasicBlock; - type Iter = smallvec::IntoIter<[BasicBlock; 4]>; -} - -impl<'tcx> WithPredecessors for CleanedBody<'_, 'tcx> { - fn predecessors( - &self, - node: Self::Node, - ) -> >::Iter { - ::predecessors(&self.0.basic_blocks, node) +impl<'tcx> Predecessors for CleanedBody<'tcx> { + fn predecessors(&self, node: Self::Node) -> impl Iterator { + ::predecessors(&self.0.basic_blocks, node) .filter(|bb| CleanedBody::keep_block(&self.0.basic_blocks[*bb])) .collect::>() .into_iter() diff --git a/crates/aquascope/src/analysis/ir_mapper/mod.rs b/crates/aquascope/src/analysis/ir_mapper/mod.rs index a4c222a02..e6ea9abb1 100644 --- a/crates/aquascope/src/analysis/ir_mapper/mod.rs +++ b/crates/aquascope/src/analysis/ir_mapper/mod.rs @@ -5,26 +5,26 @@ pub(crate) mod mir_locations; pub(crate) mod post_dominators; // pub(crate) mod region_name; -pub(crate) use body_graph::CleanedBody; -pub(crate) use mir_locations::MirOrderedLocations; -use post_dominators::AllPostDominators; use rustc_data_structures::{ fx::{FxHashMap as HashMap, FxHashSet as HashSet}, graph::{dominators::Dominators, *}, }; -use rustc_hir::{self as hir, HirId}; +use rustc_hir::HirId; use rustc_middle::{ - mir::{ - self, visit::Visitor as MirVisitor, BasicBlock, Body, Location, Place, - }, + mir::{self, visit::Visitor as MirVisitor, BasicBlock, Body, Location}, ty::TyCtxt, }; use rustc_utils::BodyExt; -pub struct IRMapper<'a, 'tcx> { - pub(crate) cleaned_graph: CleanedBody<'a, 'tcx>, +use self::post_dominators::AllPostDominators; +pub(crate) use self::{ + body_graph::CleanedBody, mir_locations::MirOrderedLocations, +}; + +pub struct IRMapper<'tcx> { + pub(crate) cleaned_graph: CleanedBody<'tcx>, tcx: TyCtxt<'tcx>, - body: &'a Body<'tcx>, + body: &'tcx Body<'tcx>, hir_to_mir: HashMap>, gather_mode: GatherMode, pub(crate) dominators: Dominators, @@ -67,13 +67,10 @@ pub enum GatherDepth { Nested, } -impl<'a, 'tcx> IRMapper<'a, 'tcx> -where - 'tcx: 'a, -{ +impl<'tcx> IRMapper<'tcx> { pub fn new( tcx: TyCtxt<'tcx>, - body: &'a Body<'tcx>, + body: &'tcx Body<'tcx>, gather_mode: GatherMode, ) -> Self { let cleaned_graph = CleanedBody(body); @@ -137,26 +134,27 @@ where ) } - pub fn local_assigned_place(&self, local: &hir::Local) -> Vec> { - use either::Either; - use mir::{FakeReadCause as FRC, StatementKind as SK}; - let id = local.hir_id; - self.get_mir_locations(id, GatherDepth::Outer).map_or_else( - Vec::default, - |mol| { - mol - .values() - .filter_map(|loc| match self.body.stmt_at(loc) { - Either::Left(mir::Statement { - kind: SK::FakeRead(box (FRC::ForLet(_), place)), - .. - }) => Some(*place), - _ => None, - }) - .collect::>() - }, - ) - } + // TODO(gavin): fixme or deleteme + // pub fn local_assigned_place(&self, local: &hir::Local) -> Vec> { + // use either::Either; + // use mir::{FakeReadCause as FRC, StatementKind as SK}; + // let id = local.hir_id; + // self.get_mir_locations(id, GatherDepth::Outer).map_or_else( + // Vec::default, + // |mol| { + // mol + // .values() + // .filter_map(|loc| match self.body.stmt_at(loc) { + // Either::Left(mir::Statement { + // kind: SK::FakeRead(box (FRC::ForLet(_), place)), + // .. + // }) => Some(*place), + // _ => None, + // }) + // .collect::>() + // }, + // ) + // } // Determines whether or not a block was inserted solely as a // `FalseEdge` or `FalseUnwind`. These were making the post-dominator @@ -296,7 +294,7 @@ where // ------------------------------------------------------------------- // Gather the HIR -> MIR relationships for statements and terminators. -impl<'tcx> MirVisitor<'tcx> for IRMapper<'_, 'tcx> { +impl<'tcx> MirVisitor<'tcx> for IRMapper<'tcx> { fn visit_basic_block_data( &mut self, block: mir::BasicBlock, diff --git a/crates/aquascope/src/analysis/ir_mapper/post_dominators.rs b/crates/aquascope/src/analysis/ir_mapper/post_dominators.rs index 43c2ec60d..2313593e0 100644 --- a/crates/aquascope/src/analysis/ir_mapper/post_dominators.rs +++ b/crates/aquascope/src/analysis/ir_mapper/post_dominators.rs @@ -1,6 +1,6 @@ use rustc_data_structures::graph::*; use rustc_index::{ - bit_set::{HybridBitSet, SparseBitMatrix}, + bit_set::{ChunkedBitSet, SparseBitMatrix}, Idx, }; use rustc_utils::mir::control_dependencies::PostDominators; @@ -21,7 +21,7 @@ impl AllPostDominators { for exit in exits { let exit_pdom = PostDominators::build(graph, exit); for node in all_nodes.clone() { - let mut is_pdom = HybridBitSet::new_empty(graph.num_nodes()); + let mut is_pdom = ChunkedBitSet::new_empty(graph.num_nodes()); if let Some(iter) = exit_pdom.post_dominators(node) { for other in iter { is_pdom.insert(other); diff --git a/crates/aquascope/src/analysis/mod.rs b/crates/aquascope/src/analysis/mod.rs index b94ebc9d3..7625b6c16 100644 --- a/crates/aquascope/src/analysis/mod.rs +++ b/crates/aquascope/src/analysis/mod.rs @@ -218,11 +218,11 @@ where smoothed_elements } -pub fn compute_permissions<'a, 'tcx>( +pub fn compute_permissions<'tcx>( tcx: TyCtxt<'tcx>, body_id: BodyId, - body_with_facts: &'a BodyWithBorrowckFacts<'tcx>, -) -> PermissionsCtxt<'a, 'tcx> { + body_with_facts: &'tcx BodyWithBorrowckFacts<'tcx>, +) -> PermissionsCtxt<'tcx> { BODY_ID_STACK.with(|stack| { stack.borrow_mut().push(body_id); @@ -247,9 +247,9 @@ pub enum AquascopeError { pub type AquascopeResult = ::std::result::Result; -pub struct AquascopeAnalysis<'a, 'tcx: 'a> { - pub(crate) permissions: PermissionsCtxt<'a, 'tcx>, - pub(crate) ir_mapper: IRMapper<'a, 'tcx>, +pub struct AquascopeAnalysis<'tcx> { + pub(crate) permissions: PermissionsCtxt<'tcx>, + pub(crate) ir_mapper: IRMapper<'tcx>, } impl From for AquascopeError { @@ -270,7 +270,7 @@ pub struct AnalysisOutput { pub move_regions: MoveRegions, } -impl<'a, 'tcx: 'a> AquascopeAnalysis<'a, 'tcx> { +impl<'tcx> AquascopeAnalysis<'tcx> { pub fn new(tcx: TyCtxt<'tcx>, body_id: BodyId) -> Self { let def_id = tcx.hir().body_owner_def_id(body_id); let bwf = borrowck_facts::get_body_with_borrowck_facts(tcx, def_id); @@ -389,7 +389,12 @@ impl<'a, 'tcx: 'a> AquascopeAnalysis<'a, 'tcx> { let loan_live_at = &self.permissions.polonius_output.loan_live_at; let active_nodes = self - .key_to_spans(**loan, loan_live_at, start_span, end_span) + .key_to_spans( + **loan, + &loan_live_at.clone().into_iter().collect(), + start_span, + end_span, + ) .into_iter() .map(|s| self.span_to_range(s)) .collect::>(); diff --git a/crates/aquascope/src/analysis/permissions/context.rs b/crates/aquascope/src/analysis/permissions/context.rs index 9f6d5bd29..92ac13f63 100644 --- a/crates/aquascope/src/analysis/permissions/context.rs +++ b/crates/aquascope/src/analysis/permissions/context.rs @@ -20,7 +20,7 @@ use rustc_hir::{def_id::DefId, BodyId, Mutability}; use rustc_index::IndexVec; use rustc_middle::{ mir::{BorrowKind, Local, Location, Place, ProjectionElem}, - ty::{self, ParamEnv, Ty, TyCtxt}, + ty::{self, Ty, TyCtxt, TypingEnv}, }; use rustc_mir_dataflow::move_paths::MoveData; use rustc_span::Span; @@ -36,9 +36,9 @@ use crate::analysis::permissions::{ /// A path as defined in rustc. type MoveablePath = ::Path; -pub struct PermissionsCtxt<'a, 'tcx> { +pub struct PermissionsCtxt<'tcx> { pub tcx: TyCtxt<'tcx>, - pub polonius_input_facts: &'a AllFacts, + pub polonius_input_facts: &'tcx AllFacts, pub polonius_output: PEOutput, /// Program facts unique to Aquascope. @@ -51,18 +51,18 @@ pub struct PermissionsCtxt<'a, 'tcx> { pub permissions_output: Output, pub body_id: BodyId, pub def_id: DefId, - pub body_with_facts: &'a BodyWithBorrowckFacts<'tcx>, + pub body_with_facts: &'tcx BodyWithBorrowckFacts<'tcx>, pub borrow_set: BorrowSet<'tcx>, pub move_data: MoveData<'tcx>, pub loan_regions: Option>, pub locals_are_invalidated_at_exit: bool, - pub(crate) param_env: ParamEnv<'tcx>, + pub(crate) typing_env: TypingEnv<'tcx>, pub(crate) place_data: IndexVec>, pub(crate) rev_lookup: HashMap>, pub(crate) region_flows: Option, } -impl<'a, 'tcx> PermissionsCtxt<'a, 'tcx> { +impl<'tcx> PermissionsCtxt<'tcx> { pub fn new_path(&mut self, place: Place<'tcx>) -> Path { let place = place.normalize(self.tcx, self.def_id); let new_path = self.place_data.push(place); @@ -125,7 +125,11 @@ impl<'a, 'tcx> PermissionsCtxt<'a, 'tcx> { pub fn path_to_moveable_path(&self, p: Path) -> MoveablePath { let place = self.path_to_place(p); - self.move_data.rev_lookup.find_local(place.local) + self + .move_data + .rev_lookup + .find_local(place.local) + .unwrap_or_else(|| panic!("Missing local: {:?}", place.local)) } pub fn moveable_path_to_path(&self, mp: MoveablePath) -> Path { @@ -218,7 +222,7 @@ impl<'a, 'tcx> PermissionsCtxt<'a, 'tcx> { let body = &self.body_with_facts.body; let place = self.path_to_place(path); let ty = place.ty(&body.local_decls, self.tcx).ty; - ty.is_copyable(self.tcx, self.param_env) + ty.is_copyable(self.tcx, self.typing_env) } /// Can this path be written to? @@ -290,7 +294,7 @@ impl<'a, 'tcx> PermissionsCtxt<'a, 'tcx> { is_live: true, type_droppable: true, type_writeable: true, - type_copyable: ty.is_copyable(self.tcx, self.param_env), + type_copyable: ty.is_copyable(self.tcx, self.typing_env), path_moved: None, path_uninitialized: false, loan_read_refined: None, diff --git a/crates/aquascope/src/analysis/permissions/flow.rs b/crates/aquascope/src/analysis/permissions/flow.rs index d67fe37f3..b4e14980a 100644 --- a/crates/aquascope/src/analysis/permissions/flow.rs +++ b/crates/aquascope/src/analysis/permissions/flow.rs @@ -76,22 +76,28 @@ use std::time::Instant; use itertools::Itertools; -use rustc_borrowck::borrow_set::BorrowData; +use rustc_borrowck::{ + borrow_set::BorrowData, + consumers::{places_conflict, PlaceConflictBias}, + facts::PoloniusRegionVid, +}; use rustc_data_structures::{ fx::FxHashSet as HashSet, graph::{ - scc::Sccs, vec_graph::VecGraph, DirectedGraph, WithNumNodes, WithSuccessors, + depth_first_search, scc::Sccs, vec_graph::VecGraph, DirectedGraph, + Successors, }, transitive_relation::{TransitiveRelation, TransitiveRelationBuilder}, }; -use rustc_index::{bit_set::HybridBitSet, Idx}; -use rustc_utils::{mir::places_conflict, BodyExt}; +use rustc_index::{bit_set::ChunkedBitSet, Idx}; +use rustc_utils::BodyExt; use serde::Serialize; use ts_rs::TS; use super::{Origin, PermissionsCtxt}; rustc_index::newtype_index! { + #[derive(Ord, PartialOrd)] #[debug_format = "scc{}"] pub struct SccIdx {} } @@ -144,10 +150,10 @@ pub struct RegionFlows { specified_flows: TransitiveRelation, /// Local regions that could dangle due to an exit invalidation. - dangling_local_sources: HybridBitSet, + dangling_local_sources: ChunkedBitSet, /// Regions that are equivalent to placeholders. - abstract_sources: HybridBitSet, + abstract_sources: ChunkedBitSet, /// The set of abstract components that a given component could contain. contains_abstract: TransitiveRelation, @@ -276,7 +282,7 @@ fn count_nodes(tups: &[(T, T)]) -> usize { /// The return closure answers queries of the form "for (v, s) did `s` flow to v?" fn flow_from_sources( sources: impl Iterator, - graph: impl DirectedGraph + WithSuccessors + WithNumNodes, + graph: impl DirectedGraph + Successors, ) -> TransitiveRelation where T: Idx, @@ -285,7 +291,7 @@ where // Compute the transitive closure, then assert that they're the same. for s in sources { - for t in graph.depth_first_search(s) { + for t in depth_first_search(&graph, s) { // `t` can point to `s` tcb.add(t, s); } @@ -298,10 +304,9 @@ where /// /// Exit point would refer to a `StorageDead` or `Drop`. fn check_for_invalidation_at_exit<'tcx>( - ctxt: &PermissionsCtxt<'_, 'tcx>, + ctxt: &PermissionsCtxt<'tcx>, borrow: &BorrowData<'tcx>, ) -> bool { - use places_conflict::AccessDepth::{Deep, Shallow}; use rustc_middle::{ mir::{PlaceElem, PlaceRef, ProjectionElem}, ty::TyCtxt, @@ -341,16 +346,12 @@ fn check_for_invalidation_at_exit<'tcx>( return false; } - let sd = if might_be_alive { Deep } else { Shallow(None) }; - - places_conflict::borrow_conflicts_with_place( + places_conflict( tcx, body, place, - borrow.kind, - root_place, - sd, - places_conflict::PlaceConflictBias::Overlap, + root_place.to_place(tcx), + PlaceConflictBias::Overlap, ) } @@ -395,7 +396,11 @@ pub fn compute_flows(ctxt: &mut PermissionsCtxt) { .placeholder .iter() .filter_map(|&(p, _)| vertices.contains(&p).then_some(p)) - .chain(body.regions_in_return().map(|rg| rg.as_var())) + .chain( + body + .regions_in_return() + .map(|rg| PoloniusRegionVid::from(rg.as_var())), + ) .map(|p| scc_constraints.scc(p)) .collect::>(); @@ -427,7 +432,7 @@ pub fn compute_flows(ctxt: &mut PermissionsCtxt) { // Compute local sources: // If `Place::is_indirect` returns false, the caller knows // that the Place refers to the same region of memory as its base. - let mut local_sources = HybridBitSet::new_empty(num_sccs); + let mut local_sources = ChunkedBitSet::new_empty(num_sccs); for (_, bd) in ctxt.borrow_set.location_map.iter() { if !bd.borrowed_place.is_indirect() { let scc = scc_constraints.scc(bd.region); @@ -449,7 +454,7 @@ pub fn compute_flows(ctxt: &mut PermissionsCtxt) { let contains_local = flow_from_sources(local_sources.iter(), &scc_constraints); - let mut dangling_local_sources = HybridBitSet::new_empty(num_sccs); + let mut dangling_local_sources = ChunkedBitSet::new_empty(num_sccs); for (_, loans) in ctxt.polonius_output.errors.iter() { for &loan in loans.iter() { @@ -461,7 +466,7 @@ pub fn compute_flows(ctxt: &mut PermissionsCtxt) { } } - let mut abstract_sources = HybridBitSet::new_empty(num_sccs); + let mut abstract_sources = ChunkedBitSet::new_empty(num_sccs); for scc in placeholders.iter() { abstract_sources.insert(*scc); } diff --git a/crates/aquascope/src/analysis/permissions/mod.rs b/crates/aquascope/src/analysis/permissions/mod.rs index e0fde860f..e9f35d305 100644 --- a/crates/aquascope/src/analysis/permissions/mod.rs +++ b/crates/aquascope/src/analysis/permissions/mod.rs @@ -38,6 +38,7 @@ impl polonius_engine::FactTypes for AquascopeFacts { } rustc_index::newtype_index! { + #[derive(PartialOrd, Ord)] #[debug_format = "path{}"] pub struct PathIndex {} } diff --git a/crates/aquascope/src/analysis/permissions/output.rs b/crates/aquascope/src/analysis/permissions/output.rs index 78555585e..eb666538b 100644 --- a/crates/aquascope/src/analysis/permissions/output.rs +++ b/crates/aquascope/src/analysis/permissions/output.rs @@ -10,19 +10,19 @@ use std::time::Instant; use datafrog::{Iteration, Relation, RelationLeaper, ValueFilter}; use polonius_engine::{Algorithm, FactTypes, Output as PEOutput}; -use rustc_borrowck::{borrow_set::BorrowSet, consumers::BodyWithBorrowckFacts}; +use rustc_borrowck::{ + borrow_set::BorrowSet, + consumers::{places_conflict, BodyWithBorrowckFacts, PlaceConflictBias}, +}; use rustc_data_structures::fx::{FxHashMap as HashMap, FxHashSet as HashSet}; use rustc_hir::{BodyId, Mutability}; use rustc_index::IndexVec; use rustc_middle::{ mir::{Place, ProjectionElem}, - ty::TyCtxt, + ty::{TyCtxt, TypingEnv}, }; use rustc_mir_dataflow::move_paths::MoveData; -use rustc_utils::{ - mir::places_conflict::{self, AccessDepth, PlaceConflictBias}, - BodyExt, PlaceExt, -}; +use rustc_utils::{BodyExt, PlaceExt}; use super::{ context::PermissionsCtxt, flow, AquascopeFacts, Loan, Move, Path, Point, @@ -321,7 +321,7 @@ pub fn derive_permission_facts(ctxt: &mut PermissionsCtxt) { p == point2 && { let mp_assigned_to = ctxt.moveable_path_to_path(assigned_to); let place1 = ctxt.path_to_place(mp_assigned_to); - places_conflict::places_conflict( + places_conflict( tcx, body, place1, @@ -392,13 +392,11 @@ pub fn derive_permission_facts(ctxt: &mut PermissionsCtxt) { |(_origin, loan, _point)| { let borrow = ctxt.loan_to_borrow(*loan); places.iter().filter_map(|place| { - places_conflict::borrow_conflicts_with_place( + places_conflict( tcx, body, borrow.borrowed_place, - borrow.kind, - place.as_ref(), - AccessDepth::Deep, + *place, PlaceConflictBias::Overlap, ) .then_some((*loan, ctxt.place_to_path(place))) @@ -497,11 +495,11 @@ pub fn derive_permission_facts(ctxt: &mut PermissionsCtxt) { // Main entry /// Compute the [`PermissionsCtxt`] for a given body. -pub fn compute<'a, 'tcx>( +pub fn compute<'tcx>( tcx: TyCtxt<'tcx>, body_id: BodyId, - body_with_facts: &'a BodyWithBorrowckFacts<'tcx>, -) -> PermissionsCtxt<'a, 'tcx> { + body_with_facts: &'tcx BodyWithBorrowckFacts<'tcx>, +) -> PermissionsCtxt<'tcx> { let timer = Instant::now(); let def_id = tcx.hir().body_owner_def_id(body_id); let body = &body_with_facts.body; @@ -520,18 +518,11 @@ pub fn compute<'a, 'tcx>( let locals_are_invalidated_at_exit = tcx.hir().body_owner_kind(def_id).is_fn_or_closure(); - let move_data = match MoveData::gather_moves(body, tcx, tcx.param_env(def_id)) - { - Ok(move_data) => move_data, - Err((move_data, _illegal_moves)) => { - log::debug!("illegal moves found {_illegal_moves:?}"); - move_data - } - }; + let move_data = MoveData::gather_moves(body, tcx, |_| true); let borrow_set = BorrowSet::build(tcx, body, locals_are_invalidated_at_exit, &move_data); let def_id = def_id.to_def_id(); - let param_env = tcx.param_env_reveal_all_normalized(def_id); + let typing_env = TypingEnv::post_analysis(tcx, def_id); // This should always be true for the current analysis of aquascope let locals_are_invalidated_at_exit = def_id.as_local().map_or(false, |did| { @@ -549,7 +540,7 @@ pub fn compute<'a, 'tcx>( borrow_set, move_data, locals_are_invalidated_at_exit, - param_env, + typing_env, loan_regions: None, place_data: IndexVec::new(), rev_lookup: HashMap::default(), diff --git a/crates/aquascope/src/analysis/permissions/utils.rs b/crates/aquascope/src/analysis/permissions/utils.rs index ce032d7b6..00ba8a205 100644 --- a/crates/aquascope/src/analysis/permissions/utils.rs +++ b/crates/aquascope/src/analysis/permissions/utils.rs @@ -3,11 +3,10 @@ use std::collections::hash_map::Entry; use rustc_data_structures::fx::FxHashMap as HashMap; -use rustc_middle::mir::{Location, TerminatorEdges}; -use rustc_mir_dataflow::{ - fmt::DebugWithContext, Analysis, AnalysisDomain, JoinSemiLattice, +use rustc_middle::mir::{ + pretty::PrettyPrintMirOptions, Location, TerminatorEdges, }; -use rustc_utils::BodyExt; +use rustc_mir_dataflow::{fmt::DebugWithContext, Analysis, JoinSemiLattice}; use super::{ context::PermissionsCtxt, Permissions, PermissionsData, PermissionsDomain, @@ -30,19 +29,19 @@ pub(crate) fn dump_permissions_with_mir(ctxt: &PermissionsCtxt) { } let analysis = PAnalysis { ctxt }; - let mut results = analysis - .into_engine(ctxt.tcx, &ctxt.body_with_facts.body) - .iterate_to_fixpoint(); + let mut results = + analysis.iterate_to_fixpoint(ctxt.tcx, &ctxt.body_with_facts.body, None); log::debug!("Dumping results for {:?}", name.as_str()); - if let Err(e) = ctxt.body_with_facts.body.write_analysis_results( - &mut results, - def_id.to_def_id(), - ctxt.tcx, - ) { - log::warn!("{:?}", e); - } + // TODO(gavin): fixme or deleteme + // if let Err(e) = ctxt.body_with_facts.body.write_analysis_results( + // &mut results, + // def_id.to_def_id(), + // ctxt.tcx, + // ) { + // log::warn!("{:?}", e); + // } } pub(crate) fn dump_mir_debug(ctxt: &PermissionsCtxt) { @@ -56,6 +55,9 @@ pub(crate) fn dump_mir_debug(ctxt: &PermissionsCtxt) { body, &mut |_, _| Ok(()), &mut stderr, + PrettyPrintMirOptions { + include_extra_comments: false, + }, ) .unwrap(); } @@ -213,7 +215,7 @@ impl DebugWithContext for PermissionsDomain<'_> { // Analysis pub(crate) struct PAnalysis<'a, 'tcx> { - ctxt: &'a PermissionsCtxt<'a, 'tcx>, + ctxt: &'a PermissionsCtxt<'tcx>, } impl<'a, 'tcx> PAnalysis<'a, 'tcx> { @@ -231,7 +233,7 @@ impl<'a, 'tcx> PAnalysis<'a, 'tcx> { } } -impl<'tcx> AnalysisDomain<'tcx> for PAnalysis<'_, 'tcx> { +impl<'tcx> Analysis<'tcx> for PAnalysis<'_, 'tcx> { type Domain = PermissionsDomain<'tcx>; const NAME: &'static str = "PermissionsAnalysisDatalog"; @@ -271,9 +273,7 @@ impl<'tcx> AnalysisDomain<'tcx> for PAnalysis<'_, 'tcx> { _state: &mut Self::Domain, ) { } -} -impl<'tcx> Analysis<'tcx> for PAnalysis<'_, 'tcx> { fn apply_statement_effect( &mut self, state: &mut Self::Domain, diff --git a/crates/aquascope/src/analysis/stepper/hir_steps.rs b/crates/aquascope/src/analysis/stepper/hir_steps.rs index 7d59a226a..ef932182e 100644 --- a/crates/aquascope/src/analysis/stepper/hir_steps.rs +++ b/crates/aquascope/src/analysis/stepper/hir_steps.rs @@ -81,10 +81,10 @@ pub(super) struct HirStepPoints<'a, 'tcx> where 'tcx: 'a, { - tcx: &'a TyCtxt<'tcx>, - body: &'a Body<'tcx>, + tcx: TyCtxt<'tcx>, + body: &'tcx Body<'tcx>, body_id: BodyId, - ir_mapper: &'a IRMapper<'a, 'tcx>, + ir_mapper: &'a IRMapper<'tcx>, // Error reporting counters unsupported_features: Vec, @@ -145,10 +145,10 @@ macro_rules! report_unsupported { impl<'a, 'tcx: 'a> HirStepPoints<'a, 'tcx> { pub(super) fn make( - tcx: &'a TyCtxt<'tcx>, - body: &'a Body<'tcx>, + tcx: TyCtxt<'tcx>, + body: &'tcx Body<'tcx>, body_id: BodyId, - ir_mapper: &'a IRMapper<'a, 'tcx>, + ir_mapper: &'a IRMapper<'tcx>, ) -> Result { let mir_segments = SegmentedMirBuilder::make(ir_mapper); let start_loc = mir::START_BLOCK.start_location(); @@ -191,7 +191,7 @@ impl<'a, 'tcx: 'a> HirStepPoints<'a, 'tcx> { pub(super) fn finalize( self, - analysis: &AquascopeAnalysis<'_, 'tcx>, + analysis: &AquascopeAnalysis<'tcx>, mode: PermIncludeMode, ) -> Result> { let body_hir_id = self.body_value_id(); @@ -225,8 +225,13 @@ impl<'a, 'tcx: 'a> HirStepPoints<'a, 'tcx> { } fn pop_branch_start(&mut self, expecting: Location) { - if let Some(popped) = self.current_branch_start.pop() && popped != expecting { - report_unexpected!(self, "expecting popped location {expecting:?} but got {popped:?}") + if let Some(popped) = self.current_branch_start.pop() + && popped != expecting + { + report_unexpected!( + self, + "expecting popped location {expecting:?} but got {popped:?}" + ) } } @@ -487,12 +492,12 @@ impl<'a, 'tcx: 'a> HirVisitor<'tcx> for HirStepPoints<'a, 'tcx> { self.tcx.hir() } - fn visit_body(&mut self, body: &'tcx hir::Body) { + fn visit_body(&mut self, body: &hir::Body<'tcx>) { intravisit::walk_body(self, body); self.insert_step_at_node_exit(body.value.hir_id); } - fn visit_block(&mut self, block: &'tcx hir::Block) { + fn visit_block(&mut self, block: &hir::Block<'tcx>) { let scope = invoke_internal!(self, open_scope); for stmt in block.stmts.iter() { self.visit_stmt(stmt); @@ -507,7 +512,7 @@ impl<'a, 'tcx: 'a> HirVisitor<'tcx> for HirStepPoints<'a, 'tcx> { invoke_internal!(self, close_scope, scope); } - fn visit_stmt(&mut self, stmt: &'tcx hir::Stmt) { + fn visit_stmt(&mut self, stmt: &'tcx hir::Stmt<'tcx>) { use rustc_hir::StmtKind as SK; log::debug!( @@ -517,14 +522,15 @@ impl<'a, 'tcx: 'a> HirVisitor<'tcx> for HirStepPoints<'a, 'tcx> { let scope = invoke_internal!(self, open_scope); - if let SK::Local(local) = stmt.kind { - let places = self.ir_mapper.local_assigned_place(local); - let locals = places.into_iter().map(|p| p.local).collect::>(); - if !locals.is_empty() { - log::debug!("storing locals at scope {scope:?} {locals:?}"); - self.locals_at_scope.insert(scope, locals); - } - } + // TODO(gavin): fixme or deleteme + // if let SK::Local(local) = stmt.kind { + // let places = self.ir_mapper.local_assigned_place(local); + // let locals = places.into_iter().map(|p| p.local).collect::>(); + // if !locals.is_empty() { + // log::debug!("storing locals at scope {scope:?} {locals:?}"); + // self.locals_at_scope.insert(scope, locals); + // } + // } intravisit::walk_stmt(self, stmt); @@ -549,8 +555,10 @@ impl<'a, 'tcx: 'a> HirVisitor<'tcx> for HirStepPoints<'a, 'tcx> { } // Insert the location and span for the else branch - if let Some(els) = else_opt && let Some(else_entry) = self.get_node_entry(els.hir_id) { - let else_span = self.span_of(els.hir_id).shrink_to_lo(); + if let Some(els) = else_opt + && let Some(else_entry) = self.get_node_entry(els.hir_id) + { + let else_span = self.span_of(els.hir_id).shrink_to_lo(); entry_to_spans.insert(else_entry, else_span); } diff --git a/crates/aquascope/src/analysis/stepper/mod.rs b/crates/aquascope/src/analysis/stepper/mod.rs index 387842295..7d30e6a44 100644 --- a/crates/aquascope/src/analysis/stepper/mod.rs +++ b/crates/aquascope/src/analysis/stepper/mod.rs @@ -324,7 +324,7 @@ impl MirSegment { pub fn into_diff<'tcx>( self, - ctxt: &PermissionsCtxt<'_, 'tcx>, + ctxt: &PermissionsCtxt<'tcx>, ) -> HashMap, PermissionsDataDiff> { let p0 = ctxt.location_to_point(self.from); let p1 = ctxt.location_to_point(self.to); @@ -337,18 +337,15 @@ impl MirSegment { // ---------- // Main entry -pub fn compute_permission_steps<'a, 'tcx>( - analysis: &AquascopeAnalysis<'a, 'tcx>, -) -> Result> -where - 'tcx: 'a, -{ +pub fn compute_permission_steps<'tcx>( + analysis: &AquascopeAnalysis<'tcx>, +) -> Result> { let mode = INCLUDE_MODE.copied().unwrap_or(PermIncludeMode::Changes); let ctxt = &analysis.permissions; let ir_mapper = &analysis.ir_mapper; let body = &ctxt.body_with_facts.body; let mut hir_visitor = - hir_steps::HirStepPoints::make(&ctxt.tcx, body, ctxt.body_id, ir_mapper)?; + hir_steps::HirStepPoints::make(ctxt.tcx, body, ctxt.body_id, ir_mapper)?; hir_visitor.visit_nested_body(ctxt.body_id); diff --git a/crates/aquascope/src/analysis/stepper/segmented_mir.rs b/crates/aquascope/src/analysis/stepper/segmented_mir.rs index 6176de93d..1ad8aa6da 100644 --- a/crates/aquascope/src/analysis/stepper/segmented_mir.rs +++ b/crates/aquascope/src/analysis/stepper/segmented_mir.rs @@ -216,7 +216,7 @@ type BranchSpannerMap<'a> = HashMap Span + 'a>>; pub(super) struct SegmentedMirBuilder<'a, 'tcx: 'a> { - mapper: &'a IRMapper<'a, 'tcx>, + mapper: &'a IRMapper<'tcx>, first_collection: CollectionId, root_mappings: BranchSpannerMap<'a>, collections: IndexVec, @@ -356,7 +356,7 @@ enum GetSpanner<'a> { } impl<'a, 'tcx: 'a> SegmentedMirBuilder<'a, 'tcx> { - pub fn make(mapper: &'a IRMapper<'a, 'tcx>) -> Self { + pub fn make(mapper: &'a IRMapper<'tcx>) -> Self { let from = mapper.cleaned_graph.start_node().start_location(); let mut collections = IndexVec::new(); @@ -471,9 +471,7 @@ impl<'a, 'tcx: 'a> SegmentedMirBuilder<'a, 'tcx> { let mapper = &self.mapper; // Find all basic blocks that are reachable from the root. - let reachable = mapper - .cleaned_graph - .depth_first_search(root) + let reachable = depth_first_search(&mapper.cleaned_graph, root) .filter(|&to| mapper.dominates(root, to)) .collect::>(); diff --git a/crates/aquascope/src/analysis/stepper/table_builder.rs b/crates/aquascope/src/analysis/stepper/table_builder.rs index c65b685d5..00a885501 100644 --- a/crates/aquascope/src/analysis/stepper/table_builder.rs +++ b/crates/aquascope/src/analysis/stepper/table_builder.rs @@ -30,8 +30,8 @@ pub(super) struct Table<'tcx> { pub(super) type Tables<'tcx> = HashMap>>; pub(super) struct TableBuilder<'a, 'tcx: 'a> { - pub(super) analysis: &'a AquascopeAnalysis<'a, 'tcx>, - pub(super) ctxt: &'a PermissionsCtxt<'a, 'tcx>, + pub(super) analysis: &'a AquascopeAnalysis<'tcx>, + pub(super) ctxt: &'a PermissionsCtxt<'tcx>, pub(super) mir: &'a SegmentedMir, pub(super) locals_at_scope: HashMap>, } @@ -209,7 +209,7 @@ impl<'a, 'tcx: 'a> TableBuilder<'a, 'tcx> { // - Convert Spans to Ranges #[allow(clippy::if_not_else)] pub(super) fn prettify_permission_steps<'tcx>( - analysis: &AquascopeAnalysis<'_, 'tcx>, + analysis: &AquascopeAnalysis<'tcx>, perm_steps: Tables<'tcx>, mode: PermIncludeMode, ) -> Vec { @@ -361,7 +361,7 @@ pub(super) fn prettify_permission_steps<'tcx>( .collect::>(); master_table_vec - .sort_by_key(|(place, _)| (place.local.as_usize(), place.projection)); + .sort_by_key(|(place, _)| (place.local.as_usize(), place.projection.len())); let master_table = PermissionsStepTable { from, diff --git a/crates/aquascope/src/errors/mod.rs b/crates/aquascope/src/errors/mod.rs index 068291ee5..0656e7cf8 100644 --- a/crates/aquascope/src/errors/mod.rs +++ b/crates/aquascope/src/errors/mod.rs @@ -2,7 +2,7 @@ pub(crate) mod silent_emitter; use std::cell::RefCell; -use rustc_errors::{Diagnostic, TRACK_DIAGNOSTICS}; +use rustc_errors::{DiagInner, TRACK_DIAGNOSTIC}; use rustc_hir::def_id::LocalDefId; use rustc_span::Span; @@ -17,7 +17,7 @@ struct DiagnosticInfo { is_error: bool, } -fn track_diagnostic(d: &mut Diagnostic, f: &mut dyn FnMut(&mut Diagnostic)) { +fn track_diagnostic(d: DiagInner, f: &mut dyn FnMut(DiagInner) -> R) -> R { BODY_DIAGNOSTICS.with(|diagnostics| { let mut diagnostics = diagnostics.borrow_mut(); let d = DiagnosticInfo { @@ -30,7 +30,7 @@ fn track_diagnostic(d: &mut Diagnostic, f: &mut dyn FnMut(&mut Diagnostic)) { // We need to actually report the diagnostic with the // provided function. Otherwise, a `DelayedBugPanic` // will cause an ICE. - (*f)(d); + (*f)(d) } // ------------------------------------------------ @@ -39,7 +39,7 @@ fn track_diagnostic(d: &mut Diagnostic, f: &mut dyn FnMut(&mut Diagnostic)) { /// This should be called before analysing a new crate. pub fn initialize_error_tracking() { log::debug!("Track diagnostics updated"); - TRACK_DIAGNOSTICS.swap(&(track_diagnostic as _)); + TRACK_DIAGNOSTIC.swap(&(track_diagnostic as _)); } /// Initialize the error tracking for a given routine. It's recommended diff --git a/crates/aquascope/src/errors/silent_emitter.rs b/crates/aquascope/src/errors/silent_emitter.rs index 010708f6f..e7f38de92 100644 --- a/crates/aquascope/src/errors/silent_emitter.rs +++ b/crates/aquascope/src/errors/silent_emitter.rs @@ -3,27 +3,28 @@ //! See: //! https://doc.rust-lang.org/nightly/nightly-rustc/rustfmt_nightly/parse/session/struct.SilentEmitter.html#impl-Translate-for-SilentEmitter -use rustc_data_structures::sync::Lrc; -use rustc_errors::{emitter::Emitter, translation::Translate, Diagnostic}; +use rustc_errors::{ + emitter::Emitter, translation::Translate, DiagInner, FluentBundle, +}; use rustc_span::source_map::SourceMap; /// Emitter which discards every error. pub(crate) struct SilentEmitter; impl Translate for SilentEmitter { - fn fluent_bundle(&self) -> Option<&Lrc> { + fn fluent_bundle(&self) -> Option<&FluentBundle> { None } - fn fallback_fluent_bundle(&self) -> &rustc_errors::FluentBundle { + fn fallback_fluent_bundle(&self) -> &FluentBundle { panic!("silent emitter attempted to translate a diagnostic"); } } impl Emitter for SilentEmitter { - fn source_map(&self) -> Option<&Lrc> { + fn source_map(&self) -> Option<&SourceMap> { None } - fn emit_diagnostic(&mut self, _db: &Diagnostic) {} + fn emit_diagnostic(&mut self, _db: DiagInner) {} } diff --git a/crates/aquascope/src/interpreter/mapper.rs b/crates/aquascope/src/interpreter/mapper.rs index 99b670c99..c414e8b7e 100644 --- a/crates/aquascope/src/interpreter/mapper.rs +++ b/crates/aquascope/src/interpreter/mapper.rs @@ -9,9 +9,10 @@ use either::Either; use itertools::Itertools; use miri::InterpCx; use rustc_hir::{intravisit::Visitor, Body, Expr, ExprKind, HirId, Stmt}; -use rustc_middle::{mir::Location, ty::InstanceDef}; +use rustc_middle::{mir::Location, ty::Instance}; use rustc_span::{BytePos, Span}; use rustc_utils::BodyExt; +use stable_mir::{mir::mono::InstanceDef, CrateDef}; use super::step::{MFrame, MStack, MStep, MTrace, MirLoc}; use crate::analysis::ir_mapper::{GatherDepth, GatherMode, IRMapper}; @@ -45,29 +46,27 @@ struct MapperEntry { body_mapping: HashMap, } -pub struct Mapper<'a, 'mir, 'tcx> { - ecx: &'a InterpCx<'mir, 'tcx, miri::MiriMachine<'mir, 'tcx>>, - mapping: RefCell, MapperEntry>>, +pub struct Mapper<'a, 'tcx> { + ecx: &'a InterpCx<'tcx, miri::MiriMachine<'tcx>>, + mapping: RefCell, MapperEntry>>, } -impl<'a, 'mir, 'tcx> Mapper<'a, 'mir, 'tcx> { - pub fn new( - ecx: &'a InterpCx<'mir, 'tcx, miri::MiriMachine<'mir, 'tcx>>, - ) -> Self { +impl<'a, 'tcx> Mapper<'a, 'tcx> { + pub fn new(ecx: &'a InterpCx<'tcx, miri::MiriMachine<'tcx>>) -> Self { Mapper { ecx, mapping: RefCell::default(), } } - fn build_body_mapping(&self, inst: InstanceDef<'tcx>) -> MapperEntry { + fn build_body_mapping(&self, inst: Instance<'tcx>) -> MapperEntry { let mut finder = FindSteppableNodes::default(); let tcx = *self.ecx.tcx; let hir = tcx.hir(); - let body_id = hir.body_owned_by(inst.def_id().expect_local()); - finder.visit_body(hir.body(body_id)); + let hir_body = hir.body_owned_by(inst.def_id().expect_local()); + finder.visit_body(hir_body); - let body = self.ecx.load_mir(inst, None).unwrap(); + let body = self.ecx.load_mir(inst.def, None).unwrap(); log::debug!("{}", body.to_string(tcx).unwrap()); let mapper = IRMapper::new(tcx, body, GatherMode::All); @@ -88,7 +87,7 @@ impl<'a, 'mir, 'tcx> Mapper<'a, 'mir, 'tcx> { .collect(); MapperEntry { - owner_id: hir.body_owner(body_id), + owner_id: hir.body_owner(hir_body.id()), body_mapping, } } @@ -96,12 +95,12 @@ impl<'a, 'mir, 'tcx> Mapper<'a, 'mir, 'tcx> { fn is_cleanup( &self, owner_id: HirId, - inst: InstanceDef<'tcx>, + inst: Instance<'tcx>, location: Location, ) -> Option { let body_span = self.ecx.tcx.hir().span_with_body(owner_id); let end_brace = body_span.with_lo(body_span.hi() - BytePos(1)); - let body = self.ecx.load_mir(inst, None).unwrap(); + let body = self.ecx.load_mir(inst.def, None).unwrap(); let loc_span = body.source_info(location).span; (loc_span == end_brace).then_some(end_brace) } diff --git a/crates/aquascope/src/interpreter/miri_utils.rs b/crates/aquascope/src/interpreter/miri_utils.rs index f58a18edb..12078dae0 100644 --- a/crates/aquascope/src/interpreter/miri_utils.rs +++ b/crates/aquascope/src/interpreter/miri_utils.rs @@ -1,6 +1,6 @@ use miri::{ - interpret::Provenance, InterpCx, InterpResult, MPlaceTy, Machine, - MemPlaceMeta, OpTy, + interp_ok, InterpCx, InterpResult, MPlaceTy, Machine, MemPlaceMeta, OpTy, + Projectable, }; use rustc_abi::FieldsShape; use rustc_middle::{ @@ -9,24 +9,23 @@ use rustc_middle::{ }; use rustc_target::abi::{FieldIdx, Size}; -pub trait OpTyExt<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>>: Sized { +pub trait OpTyExt<'tcx, M: Machine<'tcx>>: Sized { fn field_by_name( &self, name: &str, - ecx: &InterpCx<'mir, 'tcx, M>, + ecx: &InterpCx<'tcx, M>, ) -> InterpResult<'tcx, (&FieldDef, Self)>; } -impl<'mir, 'tcx, M, Prov: Provenance + 'static> OpTyExt<'mir, 'tcx, M> - for OpTy<'tcx, Prov> +impl<'tcx, M> OpTyExt<'tcx, M> for OpTy<'tcx> where - M: Machine<'mir, 'tcx, Provenance = Prov>, - 'tcx: 'mir, + M: Machine<'tcx>, + Self: Projectable<'tcx, M::Provenance>, { fn field_by_name( &self, name: &str, - ecx: &InterpCx<'mir, 'tcx, M>, + ecx: &InterpCx<'tcx, M>, ) -> InterpResult<'tcx, (&FieldDef, Self)> { let adt_def = self.layout.ty.ty_adt_def().unwrap(); let (i, field) = adt_def @@ -42,17 +41,18 @@ where .collect::>() ) }); - Ok((field, ecx.project_field(self, i)?)) + let field_op = ecx.project_field(self, i)?; + interp_ok((field, field_op)) } } -struct AddressLocator<'a, 'mir, 'tcx> { - ecx: &'a InterpCx<'mir, 'tcx, miri::MiriMachine<'mir, 'tcx>>, +struct AddressLocator<'a, 'tcx> { + ecx: &'a InterpCx<'tcx, miri::MiriMachine<'tcx>>, target: u64, segments: Vec>, } -impl<'tcx> AddressLocator<'_, '_, 'tcx> { +impl<'tcx> AddressLocator<'_, 'tcx> { fn locate(&mut self, layout: TyAndLayout<'tcx>, mut offset: u64) { if offset == self.target { return; @@ -127,11 +127,11 @@ impl<'tcx> AddressLocator<'_, '_, 'tcx> { } } -pub fn locate_address_in_type<'mir, 'tcx>( - ecx: &InterpCx<'mir, 'tcx, miri::MiriMachine<'mir, 'tcx>>, +pub fn locate_address_in_type<'tcx>( + ecx: &InterpCx<'tcx, miri::MiriMachine<'tcx>>, alloc_layout: TyAndLayout<'tcx>, alloc_size: Size, - mplace: MPlaceTy<'tcx, miri::Provenance>, + mplace: MPlaceTy<'tcx>, target: Size, ) -> Vec> { // dbg!((alloc_layout, alloc_size, mplace, target)); @@ -153,7 +153,7 @@ pub fn locate_address_in_type<'mir, 'tcx>( let index = offset / array_elem_size; // dbg!((array_elem_size, offset, index)); - let segment = match mplace.meta { + let segment = match mplace.meta() { MemPlaceMeta::Meta(meta) => { let end_offset = meta.to_u64().unwrap(); let to = index + end_offset / array_elem_size - 1; diff --git a/crates/aquascope/src/interpreter/mod.rs b/crates/aquascope/src/interpreter/mod.rs index 02dad325d..f3fd19b3d 100644 --- a/crates/aquascope/src/interpreter/mod.rs +++ b/crates/aquascope/src/interpreter/mod.rs @@ -3,11 +3,13 @@ use anyhow::Result; use either::Either; use rustc_data_structures::fx::FxIndexMap; +use rustc_errors::DiagCtxt; use rustc_hir::def_id::LocalDefId; use rustc_middle::{ mir::{Body, BorrowCheckResult}, query, ty::TyCtxt, + util::Providers, }; use rustc_utils::{source_map::range::CharRange, SpanExt}; @@ -32,7 +34,7 @@ pub(crate) fn interpret(tcx: TyCtxt) -> Result> { let (inst, mir_body_loc) = step.stack.frames.last().unwrap().location; log::trace!("{}", match mir_body_loc { Either::Left(loc) => { - let body = evaluator.ecx.load_mir(inst, None).unwrap(); + let body = evaluator.ecx.load_mir(inst.def, None).unwrap(); format!("{:?}", body.stmt_at(loc)) } Either::Right(span) => @@ -101,18 +103,17 @@ fn fake_mir_borrowck( // if the MoveData is empty. Thankfully we can reset and ignore that error via // `Handler::reset_err_count` which we do by overriding optimized_mir. fn fake_optimized_mir(tcx: TyCtxt<'_>, did: LocalDefId) -> &'_ Body<'_> { - let mut providers = query::Providers::default(); + let mut providers = Providers::default(); rustc_mir_transform::provide(&mut providers); let body = (providers.optimized_mir)(tcx, did); - tcx.sess.diagnostic().reset_err_count(); + tcx.sess.dcx().reset_err_count(); body } // See `fake_mir_borrowck` pub fn override_queries( _session: &Session, - providers: &mut query::Providers, - _extern_providers: &mut query::ExternProviders, + providers: &mut rustc_middle::util::Providers, ) { providers.mir_borrowck = fake_mir_borrowck; providers.optimized_mir = fake_optimized_mir; diff --git a/crates/aquascope/src/interpreter/mvalue.rs b/crates/aquascope/src/interpreter/mvalue.rs index 9139af949..77e7cbe5b 100644 --- a/crates/aquascope/src/interpreter/mvalue.rs +++ b/crates/aquascope/src/interpreter/mvalue.rs @@ -1,8 +1,9 @@ //! Interpreting memory as Rust data types use miri::{ - AllocKind, AllocMap, Immediate, InterpError, InterpErrorInfo, InterpResult, - MPlaceTy, MemPlaceMeta, MemoryKind, OpTy, Projectable, UndefinedBehaviorInfo, + interp_ok, AllocKind, AllocMap, CheckInAllocMsg, Immediate, InterpErrorInfo, + InterpErrorKind, InterpResult, MPlaceTy, MemPlaceMeta, MemoryKind, OpTy, + Projectable, UndefinedBehaviorInfo, }; use rustc_abi::FieldsShape; use rustc_apfloat::Float; @@ -61,13 +62,13 @@ impl Abbreviated { ) -> InterpResult<'tcx, Self> { if n <= ABBREV_MAX { let elts = (0 .. n).map(mk).collect::>>()?; - Ok(Abbreviated::All(elts)) + interp_ok(Abbreviated::All(elts)) } else { let initial = (0 .. ABBREV_MAX - 1) .map(&mut mk) .collect::>>()?; let last = mk(n - 1)?; - Ok(Abbreviated::Only(initial, Box::new(last))) + interp_ok(Abbreviated::Only(initial, Box::new(last))) } } @@ -121,17 +122,17 @@ pub enum MValue { }, } -struct Reader<'a, 'mir, 'tcx> { - ev: &'a VisEvaluator<'mir, 'tcx>, +struct Reader<'a, 'tcx> { + ev: &'a VisEvaluator<'tcx>, heap_alloc_kinds: Vec, } -impl<'tcx> Reader<'_, '_, 'tcx> { +impl<'tcx> Reader<'_, 'tcx> { fn get_path_segments( &mut self, alloc_size: Size, alloc_layout: TyAndLayout<'tcx>, - mplace: MPlaceTy<'tcx, miri::Provenance>, + mplace: MPlaceTy<'tcx>, target: Size, ) -> Vec { let segments = locate_address_in_type( @@ -149,11 +150,11 @@ impl<'tcx> Reader<'_, '_, 'tcx> { fn read_alloc( &mut self, - base: miri::MPlaceTy<'tcx, miri::Provenance>, + base: miri::MPlaceTy<'tcx>, ) -> InterpResult<'tcx, MValue> { let el_ty = base.layout.ty; let stride = base.layout.size; - Ok(match self.heap_alloc_kinds.last() { + interp_ok(match self.heap_alloc_kinds.last() { Some(MHeapAllocKind::String { len }) => { let array = self.read_array(base, stride, *len, el_ty)?; let MValue::Array(values) = array else { @@ -175,13 +176,16 @@ impl<'tcx> Reader<'_, '_, 'tcx> { /// Reads a pointer, registering the pointed data for later use. fn read_pointer( &mut self, - mplace: miri::MPlaceTy<'tcx, miri::Provenance>, + mplace: miri::MPlaceTy<'tcx>, ) -> InterpResult<'tcx, MValue> { // Determine the base allocation from the mplace's provenance - let (alloc_id, offset, _) = self.ev.ecx.ptr_get_alloc_id(mplace.ptr)?; - let (alloc_size, _, alloc_status) = self.ev.ecx.get_alloc_info(alloc_id); + let (alloc_id, offset, _) = self + .ev + .ecx + .ptr_get_alloc_id(mplace.ptr(), mplace.layout().size.bytes() as i64)?; + let alloc_info = self.ev.ecx.get_alloc_info(alloc_id); - if matches!(alloc_status, AllocKind::Dead) { + if matches!(alloc_info.kind, AllocKind::Dead) { log::warn!("Reading a dead allocation"); } @@ -215,7 +219,7 @@ impl<'tcx> Reader<'_, '_, 'tcx> { Some(t) => t.clone(), None => { drop(memory_map); - return Ok(MValue::Unallocated { + return interp_ok(MValue::Unallocated { alloc_id: Some(self.ev.remap_alloc_id(alloc_id)), }); } @@ -243,9 +247,9 @@ impl<'tcx> Reader<'_, '_, 'tcx> { // The pointer could point anywhere inside the allocation, so we use // `get_path_segments` to reverse-engineer a path from the memory location. - let meta = mplace.meta; + let meta = mplace.meta(); let parts = - self.get_path_segments(alloc_size, alloc_layout, mplace, offset); + self.get_path_segments(alloc_info.size, alloc_layout, mplace, offset); let path = MPath { segment, parts }; let range = match meta { @@ -253,12 +257,12 @@ impl<'tcx> Reader<'_, '_, 'tcx> { MemPlaceMeta::None => None, }; - Ok(MValue::Pointer { path, range }) + interp_ok(MValue::Pointer { path, range }) } fn read_array( &mut self, - base: MPlaceTy<'tcx, miri::Provenance>, + base: MPlaceTy<'tcx>, stride: Size, len: u64, el_ty: Ty<'tcx>, @@ -270,26 +274,23 @@ impl<'tcx> Reader<'_, '_, 'tcx> { self.read(&offset_place.into()) }; let values = Abbreviated::new(len, read)?; - Ok(MValue::Array(values)) + interp_ok(MValue::Array(values)) } fn read_vec_len( &mut self, - op: &OpTy<'tcx, miri::Provenance>, + op: &OpTy<'tcx>, ) -> InterpResult<'tcx, Option> { let (_, len) = op.field_by_name("len", &self.ev.ecx)?; - let len = match self.read(&len) { - Ok(MValue::Unallocated { .. }) => return Ok(None), - Ok(MValue::Uint(len)) => len, + let len = match self.read(&len).unwrap() { + MValue::Unallocated { .. } => return interp_ok(None), + MValue::Uint(len) => len, _ => unreachable!(), }; - Ok(Some(len)) + interp_ok(Some(len)) } - fn read( - &mut self, - op: &OpTy<'tcx, miri::Provenance>, - ) -> InterpResult<'tcx, MValue> { + fn read(&mut self, op: &OpTy<'tcx>) -> InterpResult<'tcx, MValue> { let ty = op.layout.ty; let result = match ty.kind() { @@ -399,7 +400,7 @@ impl<'tcx> Reader<'_, '_, 'tcx> { } _ if ty.is_primitive() => { - let imm = match self.ev.ecx.read_immediate(op) { + let imm = match self.ev.ecx.read_immediate(op).report_err() { Ok(imm) => imm, // It's possible to read uninitialized data if a data structure @@ -407,10 +408,10 @@ impl<'tcx> Reader<'_, '_, 'tcx> { // is initialized. Therefore we have to handle this case by returning // MValue::Unallocated instead of throwing an error. Err(e) => match e.into_kind() { - InterpError::UndefinedBehavior( + InterpErrorKind::UndefinedBehavior( UndefinedBehaviorInfo::InvalidUninitBytes(..), - ) => return Ok(MValue::Unallocated { alloc_id: None }), - e => return Err(InterpErrorInfo::from(e)), + ) => return interp_ok(MValue::Unallocated { alloc_id: None }), + e => return Err(InterpErrorInfo::from(e)).into(), }, }; let Immediate::Scalar(scalar) = &*imm else { @@ -432,6 +433,7 @@ impl<'tcx> Reader<'_, '_, 'tcx> { f32::from_bits(scalar.to_f32()?.to_bits() as u32) as f64 } FloatTy::F64 => f64::from_bits(scalar.to_f64()?.to_bits() as u64), + FloatTy::F16 | FloatTy::F128 => unimplemented!(), }), _ => unreachable!(), } @@ -454,12 +456,29 @@ impl<'tcx> Reader<'_, '_, 'tcx> { _ if ty.is_any_ptr() => { let val = self.ev.ecx.read_immediate(op)?; let mplace = self.ev.ecx.ref_to_mplace(&val)?; - if self.ev.ecx.check_mplace(&mplace).is_err() { - let alloc_id = match self.ev.ecx.ptr_get_alloc_id(mplace.ptr) { + if let Some((size, _)) = + self.ev.ecx.size_and_align_of_mplace(&mplace)? + && self + .ev + .ecx + .check_ptr_access( + mplace.ptr(), + size, + CheckInAllocMsg::MemoryAccessTest, + ) + .report_err() + .is_err() + { + let alloc_id = match self + .ev + .ecx + .ptr_get_alloc_id(mplace.ptr(), mplace.layout().size.bytes() as i64) + .report_err() + { Ok((alloc_id, _, _)) => Some(self.ev.remap_alloc_id(alloc_id)), Err(_) => None, }; - return Ok(MValue::Unallocated { alloc_id }); + return interp_ok(MValue::Unallocated { alloc_id }); } self.read_pointer(mplace)? } @@ -496,18 +515,15 @@ impl<'tcx> Reader<'_, '_, 'tcx> { } } - kind => todo!("{:?} / {:?}", **op, kind), + kind => todo!("{:?} / {:?}", op, kind), }; - Ok(result) + interp_ok(result) } } -impl<'tcx> VisEvaluator<'_, 'tcx> { - pub(super) fn read( - &self, - op: &OpTy<'tcx, miri::Provenance>, - ) -> InterpResult<'tcx, MValue> { +impl<'tcx> VisEvaluator<'tcx> { + pub(super) fn read(&self, op: &OpTy<'tcx>) -> InterpResult<'tcx, MValue> { Reader { ev: self, heap_alloc_kinds: Vec::new(), diff --git a/crates/aquascope/src/interpreter/step.rs b/crates/aquascope/src/interpreter/step.rs index ac3d45a49..4a39421f6 100644 --- a/crates/aquascope/src/interpreter/step.rs +++ b/crates/aquascope/src/interpreter/step.rs @@ -10,12 +10,12 @@ use anyhow::{anyhow, bail, Context, Result}; use either::Either; use itertools::Itertools; use miri::{ - AllocId, AllocMap, AllocRange, Immediate, InterpCx, InterpError, - InterpErrorInfo, InterpResult, LocalState, LocalValue, Machine, MiriConfig, - MiriMachine, OpTy, Operand, UndefinedBehaviorInfo, + interp_ok, AllocId, AllocMap, AllocRange, Immediate, InterpCx, + InterpErrorInfo, InterpErrorKind, InterpResult, LocalState, Machine, + MiriConfig, MiriMachine, OpTy, UndefinedBehaviorInfo, }; use rustc_abi::{FieldsShape, Size}; -use rustc_const_eval::ReportErrorExt; +use rustc_const_eval::{interpret::operand::Operand, ReportErrorExt}; use rustc_hir::def_id::DefId; use rustc_middle::{ mir::{ @@ -24,13 +24,14 @@ use rustc_middle::{ }, ty::{ layout::{HasTyCtxt, TyAndLayout}, - InstanceDef, TyCtxt, + Instance, TyCtxt, }, }; use rustc_session::CtfeBacktrace; use rustc_span::Span; use rustc_utils::{source_map::range::CharRange, PlaceExt}; use serde::Serialize; +use stable_mir::mir::mono::InstanceDef; use ts_rs::TS; use super::mvalue::{MMemorySegment, MPathSegment, MValue}; @@ -94,7 +95,7 @@ pub struct MTrace { pub result: MResult, } -pub(crate) type MirLoc<'tcx> = (InstanceDef<'tcx>, Either); +pub(crate) type MirLoc<'tcx> = (Instance<'tcx>, Either); #[derive(Default)] pub(crate) struct MemoryMap<'tcx> { @@ -132,8 +133,8 @@ impl<'tcx> MovedPlaces<'tcx> { } } -pub struct VisEvaluator<'mir, 'tcx> { - pub(super) ecx: InterpCx<'mir, 'tcx, MiriMachine<'mir, 'tcx>>, +pub struct VisEvaluator<'tcx> { + pub(super) ecx: InterpCx<'tcx, MiriMachine<'tcx>>, pub(super) memory_map: RefCell>, pub(super) moved_places: RefCell>, } @@ -146,26 +147,26 @@ enum BodySpanType { /// Returns the span of a body, either just the header or the entire item fn body_span(tcx: TyCtxt, def_id: DefId, body_span_type: BodySpanType) -> Span { let hir = tcx.hir(); - let fn_node = hir.body_owner(hir.body_owned_by(def_id.expect_local())); + let fn_node = hir.body_owner(hir.body_owned_by(def_id.expect_local()).id()); match body_span_type { BodySpanType::Header => hir.span(fn_node), BodySpanType::Whole => hir.span_with_body(fn_node), } } -type FrameLocals<'tcx> = Vec<(Local, String, OpTy<'tcx, miri::Provenance>)>; -type MiriFrame<'mir, 'tcx> = - miri::Frame<'mir, 'tcx, miri::Provenance, miri::FrameExtra<'tcx>>; +type FrameLocals<'tcx> = Vec<(Local, String, OpTy<'tcx>)>; +type MiriFrame<'tcx> = + miri::Frame<'tcx, miri::Provenance, miri::FrameExtra<'tcx>>; #[derive(Copy, Clone)] -struct LocalFrame<'a, 'mir, 'tcx> { +struct LocalFrame<'a, 'tcx> { current: bool, local_index: usize, global_index: usize, - frame: &'a MiriFrame<'mir, 'tcx>, + frame: &'a MiriFrame<'tcx>, } -impl<'mir, 'tcx> VisEvaluator<'mir, 'tcx> { +impl<'tcx> VisEvaluator<'tcx> { pub fn new(tcx: TyCtxt<'tcx>) -> Result { let (main_id, entry_fn_type) = tcx .entry_fn(()) @@ -173,10 +174,11 @@ impl<'mir, 'tcx> VisEvaluator<'mir, 'tcx> { let ecx = miri::create_ecx(tcx, main_id, entry_fn_type, &MiriConfig { mute_stdout_stderr: true, // have to make sure miri doesn't complain about us poking around memory - validate: false, + validation: miri::ValidationMode::No, borrow_tracker: None, ..Default::default() }) + .report_err() .map_err(|e| { anyhow!("{}", e.into_kind().diagnostic_message().as_str().unwrap()) })?; @@ -222,18 +224,18 @@ impl<'mir, 'tcx> VisEvaluator<'mir, 'tcx> { local_index, global_index, current, - }: LocalFrame<'_, 'mir, 'tcx>, + }: LocalFrame<'_, 'tcx>, loc_override: MirLoc<'tcx>, locals: FrameLocals<'tcx>, ) -> InterpResult<'tcx, MFrame>> { log::trace!("Building frame {local_index}"); - let def_id = frame.instance.def_id(); + let def_id = frame.instance().def_id(); let name = self.fn_name(def_id); let tcx = *self.ecx.tcx; let body_span = CharRange::from_span( - body_span(tcx, frame.instance.def_id(), BodySpanType::Whole), + body_span(tcx, frame.instance().def_id(), BodySpanType::Whole), tcx.sess.source_map(), ) .unwrap(); @@ -241,7 +243,7 @@ impl<'mir, 'tcx> VisEvaluator<'mir, 'tcx> { let current_loc = if current { loc_override } else { - (frame.instance.def, frame.current_loc()) + (frame.instance(), frame.current_loc()) }; let moved_places = self.moved_places.borrow(); @@ -268,7 +270,7 @@ impl<'mir, 'tcx> VisEvaluator<'mir, 'tcx> { .collect::>(), None => Vec::new(), }; - Ok(MLocal { + interp_ok(MLocal { name, value, moved_paths, @@ -276,7 +278,7 @@ impl<'mir, 'tcx> VisEvaluator<'mir, 'tcx> { }) .collect::>>()?; - Ok(MFrame { + interp_ok(MFrame { name, body_span, locals, @@ -287,7 +289,11 @@ impl<'mir, 'tcx> VisEvaluator<'mir, 'tcx> { pub(super) fn mem_is_initialized( &self, layout: TyAndLayout<'tcx>, - allocation: &miri::Allocation, + allocation: &miri::Allocation< + miri::Provenance, + miri::AllocExtra, + miri::MiriAllocBytes, + >, ) -> bool { // TODO: this should be recursive over the type. Only handles one-step right now. let ranges = match &layout.fields { @@ -317,17 +323,17 @@ impl<'mir, 'tcx> VisEvaluator<'mir, 'tcx> { fn test_local( &self, - frame: &MiriFrame<'mir, 'tcx>, + frame: &MiriFrame<'tcx>, frame_index: usize, local: Local, state: &LocalState<'tcx, miri::Provenance>, - ) -> InterpResult<'tcx, Option<(String, OpTy<'tcx, miri::Provenance>)>> { - let decl = &frame.body.local_decls[local]; + ) -> InterpResult<'tcx, Option<(String, OpTy<'tcx>)>> { + let decl = &frame.body().local_decls[local]; let name = if local == RETURN_PLACE { // Don't include unit return types in locals if decl.ty.is_unit() { log::trace!("Ignoring local {local:?} because it's a unit type"); - return Ok(None); + return interp_ok(None); } "(return)".into() @@ -336,7 +342,7 @@ impl<'mir, 'tcx> VisEvaluator<'mir, 'tcx> { // visualize in the case of f(&Some(x)). Need to figure out a good strategy for // deciding when a temp should be included. let has_debug_info = frame - .body + .body() .var_debug_info .iter() .filter_map(|info| match info.value { @@ -354,25 +360,25 @@ impl<'mir, 'tcx> VisEvaluator<'mir, 'tcx> { log::trace!( "Ignoring local {local:?} because it's not a source-level variable" ); - return Ok(None); + return interp_ok(None); } Place::from_local(local, *self.ecx.tcx) - .to_string(*self.ecx.tcx, frame.body) + .to_string(*self.ecx.tcx, frame.body()) .unwrap_or_else(|| String::from("(tmp)")) }; - let layout = state.layout.get(); - // Ignore dead locals - let LocalValue::Live(op) = state.value else { + let Some(op) = state.as_mplace_or_imm() else { log::trace!("Ignoring local {local:?} because it's not live"); - return Ok(None); + return interp_ok(None); }; + let layout = self.ecx.layout_of_local(frame, local, None)?; + match op { // Ignore uninitialized locals - Operand::Immediate(Immediate::Uninit) => { + Either::Right(Immediate::Uninit) => { // Special case: a unit struct is considered uninitialized, but we would still like to // visualize it at the toplevel, so we handle that here. Might need to make this a configurable thing? let not_zst = match layout { @@ -381,22 +387,25 @@ impl<'mir, 'tcx> VisEvaluator<'mir, 'tcx> { }; if not_zst { log::trace!("Ignoring local {local:?} because it's uninitialized and not zero-sized"); - return Ok(None); + return interp_ok(None); } } // If a local is Indirect, meaning there exists a pointer to it, // then save its allocation in `MemoryMap::stack_slots` - Operand::Indirect(mplace) => { + Either::Left((ptr, _)) => { let mut memory_map = self.memory_map.borrow_mut(); - let (alloc_id, _, _) = self.ecx.ptr_get_alloc_id(mplace.ptr).unwrap(); + let (alloc_id, _, _) = self + .ecx + .ptr_get_alloc_id(ptr, layout.size.bytes() as i64) + .unwrap(); // Have to handle the case that a local is uninitialized and indirect let (_, allocation) = self.ecx.memory.alloc_map().get(alloc_id).unwrap(); if !self.mem_is_initialized(layout.unwrap(), allocation) { log::trace!("Ignoring local {local:?} because it's a pointer to uninitialized memory"); - return Ok(None); + return interp_ok(None); } memory_map @@ -406,8 +415,8 @@ impl<'mir, 'tcx> VisEvaluator<'mir, 'tcx> { _ => {} }; - let op_ty = self.ecx.local_to_op(frame, local, layout)?; - Ok(Some((name, op_ty))) + let op_ty = self.ecx.local_to_op(frame, local, Some(layout))?; + interp_ok(Some((name, op_ty))) } fn find_locals(&self) -> InterpResult<'tcx, Vec>> { @@ -423,8 +432,9 @@ impl<'mir, 'tcx> VisEvaluator<'mir, 'tcx> { .filter_map(|(local, state)| { let local_data_res = self .test_local(frame, local_index, local, state) + .report_err() .transpose()?; - Some(local_data_res.map(|(name, op)| (local, name, op))) + Some(local_data_res.map(|(name, op)| (local, name, op)).into()) }) .collect::>>() }, @@ -442,7 +452,7 @@ impl<'mir, 'tcx> VisEvaluator<'mir, 'tcx> { .zip(locals) .map(|(frame, locals)| self.build_frame(frame, current_loc, locals)) .collect::>()?; - Ok(MStack { frames }) + interp_ok(MStack { frames }) } fn build_heap(&self) -> MHeap { @@ -458,24 +468,24 @@ impl<'mir, 'tcx> VisEvaluator<'mir, 'tcx> { log::trace!("Building stack"); let stack = self.build_stack(current_loc)?; if stack.frames.is_empty() { - return Ok(None); + return interp_ok(None); } log::trace!("Building heap"); let heap = self.build_heap(); log::trace!("Step built!"); - Ok(Some(MStep { stack, heap })) + interp_ok(Some(MStep { stack, heap })) } /// Get the stack frames for functions defined in the local crate - fn local_frames(&self) -> impl Iterator> { + fn local_frames(&self) -> impl Iterator> { let stack = Machine::stack(&self.ecx); let n = stack.len(); stack .iter() .enumerate() - .filter(|(_, frame)| frame.instance.def_id().is_local()) + .filter(|(_, frame)| frame.instance().def_id().is_local()) .enumerate() .map(move |(local_index, (global_index, frame))| LocalFrame { current: global_index == n - 1, @@ -488,10 +498,10 @@ impl<'mir, 'tcx> VisEvaluator<'mir, 'tcx> { fn collect_moves(&self) -> InterpResult<'tcx, Vec>> { let stack = Machine::stack(&self.ecx); let Some(frame) = stack.last() else { - return Ok(Vec::new()); + return interp_ok(Vec::new()); }; let Either::Left(loc) = frame.current_loc() else { - return Ok(Vec::new()); + return interp_ok(Vec::new()); }; struct CollectMoves<'tcx> { @@ -511,9 +521,9 @@ impl<'mir, 'tcx> VisEvaluator<'mir, 'tcx> { } let mut collector = CollectMoves { places: Vec::new() }; - collector.visit_location(frame.body, loc); + collector.visit_location(frame.body(), loc); - Ok(collector.places) + interp_ok(collector.places) } fn handle_moves( @@ -533,28 +543,27 @@ impl<'mir, 'tcx> VisEvaluator<'mir, 'tcx> { Either::Left(_mplace) => { // todo!() } - Either::Right((frame, local, _)) => { + Either::Right((local, ..)) => { moved_places - .add_place(frame, Place::from_local(local, self.ecx.tcx())); + .add_place(n_frames, Place::from_local(local, self.ecx.tcx())); } } } } } - Ok(()) + interp_ok(()) } /// Take a single (local) step, internally stepping until we reach a serialization point fn step( &mut self, ) -> InterpResult<'tcx, (Option>>, bool)> { - let get_current_local_loc = - |local_frames: &[LocalFrame<'_, 'mir, 'tcx>]| { - let LocalFrame { frame, .. } = local_frames.last()?; - let loc = frame.current_loc(); - Some((frame.instance.def, loc)) - }; + let get_current_local_loc = |local_frames: &[LocalFrame<'_, 'tcx>]| { + let LocalFrame { frame, .. } = local_frames.last()?; + let loc = frame.current_loc(); + Some((frame.instance(), loc)) + }; loop { let local_frames = self.local_frames().collect::>(); @@ -578,16 +587,16 @@ impl<'mir, 'tcx> VisEvaluator<'mir, 'tcx> { let LocalFrame { frame, .. } = local_frames_after.last().unwrap(); let span = body_span( *self.ecx.tcx, - frame.instance.def_id(), + frame.instance().def_id(), BodySpanType::Header, ); - Some((frame.instance.def, Either::Right(span))) + Some((frame.instance(), Either::Right(span))) } Ordering::Less => { if let Some(caller_frame_loc) = caller_frame_loc { let LocalFrame { frame, .. } = local_frames_after.last().unwrap(); - Some((frame.instance.def, caller_frame_loc)) + Some((frame.instance(), caller_frame_loc)) } else { current_loc_opt } @@ -597,12 +606,12 @@ impl<'mir, 'tcx> VisEvaluator<'mir, 'tcx> { if let Some(current_loc) = current_loc_opt { if let Some(step) = self.build_step(current_loc)? { - return Ok((Some(step), more_work)); + return interp_ok((Some(step), more_work)); } } if !more_work { - return Ok((None, more_work)); + return interp_ok((None, more_work)); } } } @@ -614,7 +623,7 @@ impl<'mir, 'tcx> VisEvaluator<'mir, 'tcx> { use UndefinedBehaviorInfo::PointerUseAfterFree; Ok(match e.into_kind() { - InterpError::UndefinedBehavior(ub) => match ub { + InterpErrorKind::UndefinedBehavior(ub) => match ub { PointerUseAfterFree(alloc_id, _) => { MUndefinedBehavior::PointerUseAfterFree { alloc_id: self.remap_alloc_id(alloc_id), @@ -632,7 +641,7 @@ impl<'mir, 'tcx> VisEvaluator<'mir, 'tcx> { pub fn eval(&mut self) -> Result>> { let mut steps = Vec::new(); let result = loop { - match self.step() { + match self.step().report_err() { Ok((step, more_work)) => { if let Some(step) = step { steps.push(step); diff --git a/crates/aquascope/src/lib.rs b/crates/aquascope/src/lib.rs index 5b7d61cb5..b501d6de9 100644 --- a/crates/aquascope/src/lib.rs +++ b/crates/aquascope/src/lib.rs @@ -80,6 +80,7 @@ extern crate rustc_target; extern crate rustc_trait_selection; extern crate rustc_type_ir; extern crate smallvec; +extern crate stable_mir; pub mod analysis; pub mod errors; diff --git a/crates/aquascope_front/Cargo.toml b/crates/aquascope_front/Cargo.toml index 2ff5328a8..6ac197af4 100644 --- a/crates/aquascope_front/Cargo.toml +++ b/crates/aquascope_front/Cargo.toml @@ -23,8 +23,8 @@ serde_json = "1" ts-rs = "6.2" itertools = "0.10.5" fluid-let = "1.0" -rustc_plugin = "0.7.0-nightly-2023-08-25" -rustc_utils = "0.7.0-nightly-2023-08-25" +rustc_plugin = { workspace = true } +rustc_utils = { workspace = true } # For binaries env_logger = {version = "0.9", default-features = false} diff --git a/rust-toolchain.toml b/rust-toolchain.toml index 220c5ac87..5bfa1b93c 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,3 +1,3 @@ [toolchain] -channel = "nightly-2023-08-25" +channel = "nightly-2024-12-01" components = ["rust-src", "rustc-dev", "llvm-tools-preview", "miri"]