From f91ccf9ace393a681922b145e56e7e3fb0041657 Mon Sep 17 00:00:00 2001 From: "Celina G. Val" Date: Wed, 10 Jan 2024 11:46:17 -0800 Subject: [PATCH 1/3] Remove tcx from SMIR run macro and accept closures Simplify the `run` macro to avoid sometimes unnecessary dependency on `TyCtxt`. Instead, users can use the new internal method `tcx()`. Additionally, extend the macro to accept closures that may capture variables. These are non-backward compatible changes, but they only affect internal APIs which are provided today as helper functions until we have a stable API to start the compiler. --- compiler/rustc_smir/src/rustc_internal/mod.rs | 122 +++++++++++++++--- tests/ui-fulldeps/stable-mir/check_abi.rs | 6 +- .../stable-mir/check_allocation.rs | 6 +- tests/ui-fulldeps/stable-mir/check_defs.rs | 6 +- .../ui-fulldeps/stable-mir/check_instance.rs | 6 +- .../ui-fulldeps/stable-mir/check_item_kind.rs | 6 +- tests/ui-fulldeps/stable-mir/check_ty_fold.rs | 6 +- .../stable-mir/compilation-result.rs | 12 +- tests/ui-fulldeps/stable-mir/crate-info.rs | 6 +- tests/ui-fulldeps/stable-mir/projections.rs | 6 +- tests/ui-fulldeps/stable-mir/smir_internal.rs | 6 +- tests/ui-fulldeps/stable-mir/smir_visitor.rs | 6 +- 12 files changed, 134 insertions(+), 60 deletions(-) diff --git a/compiler/rustc_smir/src/rustc_internal/mod.rs b/compiler/rustc_smir/src/rustc_internal/mod.rs index 4bac98909add0..7633739f2890a 100644 --- a/compiler/rustc_smir/src/rustc_internal/mod.rs +++ b/compiler/rustc_smir/src/rustc_internal/mod.rs @@ -24,14 +24,49 @@ use std::ops::Index; mod internal; pub mod pretty; +/// Convert an internal Rust compiler item into its stable counterpart, if one exists. +/// +/// # Warning +/// +/// This function is unstable, and it's behavior may change at any point. +/// E.g.: Items that were previously supported, may no longer be supported, or its translation may +/// change. +/// +/// # Panics +/// +/// This function will panic if StableMIR has not been properly initialized. pub fn stable<'tcx, S: Stable<'tcx>>(item: S) -> S::T { with_tables(|tables| item.stable(tables)) } +/// Convert a stable item into its internal Rust compiler counterpart, if one exists. +/// +/// # Warning +/// +/// This function is unstable, and it's behavior may change at any point. +/// Not every stable item can be converted to an internal one. +/// Furthermore, items that were previously supported, may no longer be supported in newer versions. +/// +/// # Panics +/// +/// This function will panic if StableMIR has not been properly initialized. pub fn internal<'tcx, S: RustcInternal<'tcx>>(item: S) -> S::T { with_tables(|tables| item.internal(tables)) } +/// Retrieve the internal Rust compiler type context. +/// +/// # Warning +/// +/// This function is unstable, and it's behavior may change at any point. +/// +/// # Panics +/// +/// This function will panic if StableMIR has not been properly initialized. +pub fn tcx<'tcx>() -> TyCtxt<'tcx> { + with_tables(|tables| tables.tcx) +} + impl<'tcx> Index for Tables<'tcx> { type Output = DefId; @@ -190,35 +225,83 @@ where stable_mir::compiler_interface::run(&tables, || init(&tables, f)) } +/// Instantiate and run the compiler with the provided arguments and callback. +/// +/// The callback will be invoked after the compiler ran all its analysis, but before code generation. +/// Note that this macro accepts two different formats for the callback: +/// 1. An ident that resolves to a function that accepts no argument and returns `ControlFlow` +/// ```ignore(needs-extern-crate) +/// # extern crate rustc_driver; +/// # extern crate rustc_interface; +/// # #[macro_use] +/// # extern crate rustc_smir; +/// # extern crate stable_mir; +/// # +/// # fn main() { +/// # use std::ops::ControlFlow; +/// # use stable_mir::CompilerError; +/// fn analyze_code() -> ControlFlow<(), ()> { +/// // Your code goes in here. +/// # ControlFlow::Continue(()) +/// } +/// # let args = vec!["--verbose".to_string()]; +/// let result = run!(args, analyze_code); +/// # assert_eq!(result, Err(CompilerError::Skipped)) +/// # } +/// ``` +/// 2. An expression that represents the body of a closure: +/// ```ignore(needs-extern-crate) +/// # extern crate rustc_driver; +/// # extern crate rustc_interface; +/// # #[macro_use] +/// # extern crate rustc_smir; +/// # extern crate stable_mir; +/// # +/// # fn main() { +/// # use std::ops::ControlFlow; +/// # use stable_mir::CompilerError; +/// fn analyze_code(extra_args: Vec) -> ControlFlow<(), ()> { +/// # let _ = extra_args; +/// // Your code goes in here. +/// # ControlFlow::Continue(()) +/// } +/// # let args = vec!["--verbose".to_string()]; +/// # let extra_args = vec![]; +/// let result = run!(args, analyze_code(extra_args)); +/// # assert_eq!(result, Err(CompilerError::Skipped)) +/// # } +/// ``` #[macro_export] macro_rules! run { - ($args:expr, $callback:expr) => { - run!($args, tcx, $callback) + ($args:expr, $callback_fn:ident) => { + run!($args, $callback_fn()) }; - ($args:expr, $tcx:ident, $callback:expr) => {{ + ($args:expr, $callback:expr) => {{ use rustc_driver::{Callbacks, Compilation, RunCompiler}; use rustc_interface::{interface, Queries}; use stable_mir::CompilerError; use std::ops::ControlFlow; - pub struct StableMir + pub struct StableMir ControlFlow> where B: Send, C: Send, + F: FnOnce() -> ControlFlow + Send, { args: Vec, - callback: fn(TyCtxt<'_>) -> ControlFlow, + callback: Option, result: Option>, } - impl StableMir + impl StableMir where B: Send, C: Send, + F: FnOnce() -> ControlFlow + Send, { /// Creates a new `StableMir` instance, with given test_function and arguments. - pub fn new(args: Vec, callback: fn(TyCtxt<'_>) -> ControlFlow) -> Self { - StableMir { args, callback, result: None } + pub fn new(args: Vec, callback: F) -> Self { + StableMir { args, callback: Some(callback), result: None } } /// Runs the compiler against given target and tests it with `test_function` @@ -238,10 +321,11 @@ macro_rules! run { } } - impl Callbacks for StableMir + impl Callbacks for StableMir where B: Send, C: Send, + F: FnOnce() -> ControlFlow + Send, { /// Called after analysis. Return value instructs the compiler whether to /// continue the compilation afterwards (defaults to `Compilation::Continue`) @@ -251,20 +335,24 @@ macro_rules! run { queries: &'tcx Queries<'tcx>, ) -> Compilation { queries.global_ctxt().unwrap().enter(|tcx| { - rustc_internal::run(tcx, || { - self.result = Some((self.callback)(tcx)); - }) - .unwrap(); - if self.result.as_ref().is_some_and(|val| val.is_continue()) { - Compilation::Continue + if let Some(callback) = self.callback.take() { + rustc_internal::run(tcx, || { + self.result = Some((callback)()); + }) + .unwrap(); + if self.result.as_ref().is_some_and(|val| val.is_continue()) { + Compilation::Continue + } else { + Compilation::Stop + } } else { - Compilation::Stop + Compilation::Continue } }) } } - StableMir::new($args, |$tcx| $callback).run() + StableMir::new($args, || $callback).run() }}; } diff --git a/tests/ui-fulldeps/stable-mir/check_abi.rs b/tests/ui-fulldeps/stable-mir/check_abi.rs index 30b42bc3bfafc..7d7469597afc2 100644 --- a/tests/ui-fulldeps/stable-mir/check_abi.rs +++ b/tests/ui-fulldeps/stable-mir/check_abi.rs @@ -12,14 +12,12 @@ #![feature(ascii_char, ascii_char_variants)] extern crate rustc_hir; -extern crate rustc_middle; #[macro_use] extern crate rustc_smir; extern crate rustc_driver; extern crate rustc_interface; extern crate stable_mir; -use rustc_middle::ty::TyCtxt; use rustc_smir::rustc_internal; use stable_mir::abi::{ArgAbi, CallConvention, FieldsShape, PassMode, VariantsShape}; use stable_mir::mir::mono::Instance; @@ -32,7 +30,7 @@ use std::ops::ControlFlow; const CRATE_NAME: &str = "input"; /// This function uses the Stable MIR APIs to get information about the test crate. -fn test_stable_mir(_tcx: TyCtxt<'_>) -> ControlFlow<()> { +fn test_stable_mir() -> ControlFlow<()> { // Find items in the local crate. let items = stable_mir::all_local_items(); @@ -117,7 +115,7 @@ fn main() { CRATE_NAME.to_string(), path.to_string(), ]; - run!(args, tcx, test_stable_mir(tcx)).unwrap(); + run!(args, test_stable_mir).unwrap(); } fn generate_input(path: &str) -> std::io::Result<()> { diff --git a/tests/ui-fulldeps/stable-mir/check_allocation.rs b/tests/ui-fulldeps/stable-mir/check_allocation.rs index 93def93127c88..fb5e13eb13b10 100644 --- a/tests/ui-fulldeps/stable-mir/check_allocation.rs +++ b/tests/ui-fulldeps/stable-mir/check_allocation.rs @@ -14,14 +14,12 @@ #![feature(ascii_char, ascii_char_variants)] extern crate rustc_hir; -extern crate rustc_middle; #[macro_use] extern crate rustc_smir; extern crate rustc_driver; extern crate rustc_interface; extern crate stable_mir; -use rustc_middle::ty::TyCtxt; use rustc_smir::rustc_internal; use stable_mir::crate_def::CrateDef; use stable_mir::mir::alloc::GlobalAlloc; @@ -40,7 +38,7 @@ use std::ops::ControlFlow; const CRATE_NAME: &str = "input"; /// This function uses the Stable MIR APIs to get information about the test crate. -fn test_stable_mir(_tcx: TyCtxt<'_>) -> ControlFlow<()> { +fn test_stable_mir() -> ControlFlow<()> { // Find items in the local crate. let items = stable_mir::all_local_items(); check_foo(*get_item(&items, (ItemKind::Static, "FOO")).unwrap()); @@ -230,7 +228,7 @@ fn main() { CRATE_NAME.to_string(), path.to_string(), ]; - run!(args, tcx, test_stable_mir(tcx)).unwrap(); + run!(args, test_stable_mir).unwrap(); } fn generate_input(path: &str) -> std::io::Result<()> { diff --git a/tests/ui-fulldeps/stable-mir/check_defs.rs b/tests/ui-fulldeps/stable-mir/check_defs.rs index e9a2599d8732c..4a124adb2b605 100644 --- a/tests/ui-fulldeps/stable-mir/check_defs.rs +++ b/tests/ui-fulldeps/stable-mir/check_defs.rs @@ -11,7 +11,6 @@ #![feature(assert_matches)] #![feature(control_flow_enum)] -extern crate rustc_middle; #[macro_use] extern crate rustc_smir; extern crate rustc_driver; @@ -20,7 +19,6 @@ extern crate stable_mir; use std::assert_matches::assert_matches; use mir::{mono::Instance, TerminatorKind::*}; -use rustc_middle::ty::TyCtxt; use rustc_smir::rustc_internal; use stable_mir::ty::{RigidTy, TyKind, Ty, UintTy}; use stable_mir::*; @@ -30,7 +28,7 @@ use std::ops::ControlFlow; const CRATE_NAME: &str = "input"; /// This function uses the Stable MIR APIs to get information about the test crate. -fn test_stable_mir(_tcx: TyCtxt<'_>) -> ControlFlow<()> { +fn test_stable_mir() -> ControlFlow<()> { let entry = stable_mir::entry_fn().unwrap(); let main_fn = Instance::try_from(entry).unwrap(); assert_eq!(main_fn.name(), "main"); @@ -113,7 +111,7 @@ fn main() { CRATE_NAME.to_string(), path.to_string(), ]; - run!(args, tcx, test_stable_mir(tcx)).unwrap(); + run!(args, test_stable_mir).unwrap(); } fn generate_input(path: &str) -> std::io::Result<()> { diff --git a/tests/ui-fulldeps/stable-mir/check_instance.rs b/tests/ui-fulldeps/stable-mir/check_instance.rs index 5cb07eabf41d3..1e039e5ae514c 100644 --- a/tests/ui-fulldeps/stable-mir/check_instance.rs +++ b/tests/ui-fulldeps/stable-mir/check_instance.rs @@ -11,7 +11,6 @@ #![feature(assert_matches)] #![feature(control_flow_enum)] -extern crate rustc_middle; #[macro_use] extern crate rustc_smir; extern crate rustc_driver; @@ -19,7 +18,6 @@ extern crate rustc_interface; extern crate stable_mir; use mir::{mono::Instance, TerminatorKind::*}; -use rustc_middle::ty::TyCtxt; use rustc_smir::rustc_internal; use stable_mir::ty::{RigidTy, TyKind}; use stable_mir::*; @@ -29,7 +27,7 @@ use std::ops::ControlFlow; const CRATE_NAME: &str = "input"; /// This function uses the Stable MIR APIs to get information about the test crate. -fn test_stable_mir(_tcx: TyCtxt<'_>) -> ControlFlow<()> { +fn test_stable_mir() -> ControlFlow<()> { let items = stable_mir::all_local_items(); // Get all items and split generic vs monomorphic items. @@ -96,7 +94,7 @@ fn main() { CRATE_NAME.to_string(), path.to_string(), ]; - run!(args, tcx, test_stable_mir(tcx)).unwrap(); + run!(args, test_stable_mir).unwrap(); } fn generate_input(path: &str) -> std::io::Result<()> { diff --git a/tests/ui-fulldeps/stable-mir/check_item_kind.rs b/tests/ui-fulldeps/stable-mir/check_item_kind.rs index 72e0e09e6e363..0a7f00029f2ac 100644 --- a/tests/ui-fulldeps/stable-mir/check_item_kind.rs +++ b/tests/ui-fulldeps/stable-mir/check_item_kind.rs @@ -11,14 +11,12 @@ #![feature(assert_matches)] #![feature(control_flow_enum)] -extern crate rustc_middle; #[macro_use] extern crate rustc_smir; extern crate rustc_driver; extern crate rustc_interface; extern crate stable_mir; -use rustc_middle::ty::TyCtxt; use rustc_smir::rustc_internal; use stable_mir::*; use std::io::Write; @@ -27,7 +25,7 @@ use std::ops::ControlFlow; const CRATE_NAME: &str = "input"; /// This function uses the Stable MIR APIs to get information about the test crate. -fn test_item_kind(_tcx: TyCtxt<'_>) -> ControlFlow<()> { +fn test_item_kind() -> ControlFlow<()> { let items = stable_mir::all_local_items(); assert_eq!(items.len(), 4); // Constructor item. @@ -59,7 +57,7 @@ fn main() { CRATE_NAME.to_string(), path.to_string(), ]; - run!(args, tcx, test_item_kind(tcx)).unwrap(); + run!(args, test_item_kind).unwrap(); } fn generate_input(path: &str) -> std::io::Result<()> { diff --git a/tests/ui-fulldeps/stable-mir/check_ty_fold.rs b/tests/ui-fulldeps/stable-mir/check_ty_fold.rs index b90d47d4540ba..14cbf9e9f81f1 100644 --- a/tests/ui-fulldeps/stable-mir/check_ty_fold.rs +++ b/tests/ui-fulldeps/stable-mir/check_ty_fold.rs @@ -12,14 +12,12 @@ #![feature(assert_matches)] #![feature(control_flow_enum)] -extern crate rustc_middle; #[macro_use] extern crate rustc_smir; extern crate rustc_driver; extern crate rustc_interface; extern crate stable_mir; -use rustc_middle::ty::TyCtxt; use rustc_smir::rustc_internal; use stable_mir::ty::{RigidTy, TyKind, Ty, }; use stable_mir::mir::{Body, MirVisitor, FieldIdx, Place, ProjectionElem, visit::{Location, @@ -30,7 +28,7 @@ use std::ops::ControlFlow; const CRATE_NAME: &str = "input"; /// This function uses the Stable MIR APIs to get information about the test crate. -fn test_stable_mir(_tcx: TyCtxt<'_>) -> ControlFlow<()> { +fn test_stable_mir() -> ControlFlow<()> { let main_fn = stable_mir::entry_fn(); let body = main_fn.unwrap().body(); let mut visitor = PlaceVisitor{ body: &body, tested: false}; @@ -87,7 +85,7 @@ fn main() { CRATE_NAME.to_string(), path.to_string(), ]; - run!(args, tcx, test_stable_mir(tcx)).unwrap(); + run!(args, test_stable_mir).unwrap(); } fn generate_input(path: &str) -> std::io::Result<()> { diff --git a/tests/ui-fulldeps/stable-mir/compilation-result.rs b/tests/ui-fulldeps/stable-mir/compilation-result.rs index fc56e24814b04..c802316c1d861 100644 --- a/tests/ui-fulldeps/stable-mir/compilation-result.rs +++ b/tests/ui-fulldeps/stable-mir/compilation-result.rs @@ -10,14 +10,12 @@ #![feature(rustc_private)] #![feature(assert_matches)] -extern crate rustc_middle; #[macro_use] extern crate rustc_smir; extern crate rustc_driver; extern crate rustc_interface; extern crate stable_mir; -use rustc_middle::ty::TyCtxt; use rustc_smir::rustc_internal; use std::io::Write; @@ -32,7 +30,8 @@ fn main() { test_continue(args.clone()); test_break(args.clone()); test_failed(args.clone()); - test_skipped(args); + test_skipped(args.clone()); + test_captured(args) } fn test_continue(args: Vec) { @@ -59,6 +58,13 @@ fn test_failed(mut args: Vec) { assert_eq!(result, Err(stable_mir::CompilerError::CompilationFailed)); } +/// Test that we are able to pass a closure and set the return according to the captured value. +fn test_captured(args: Vec) { + let captured = "10".to_string(); + let result = run!(args, ControlFlow::Continue::<(), usize>(captured.len())); + assert_eq!(result, Ok(captured.len())); +} + fn generate_input(path: &str) -> std::io::Result<()> { let mut file = std::fs::File::create(path)?; write!( diff --git a/tests/ui-fulldeps/stable-mir/crate-info.rs b/tests/ui-fulldeps/stable-mir/crate-info.rs index c2035430a33b8..8258883436f2f 100644 --- a/tests/ui-fulldeps/stable-mir/crate-info.rs +++ b/tests/ui-fulldeps/stable-mir/crate-info.rs @@ -12,7 +12,6 @@ #![feature(control_flow_enum)] extern crate rustc_hir; -extern crate rustc_middle; #[macro_use] extern crate rustc_smir; extern crate rustc_driver; @@ -20,7 +19,6 @@ extern crate rustc_interface; extern crate stable_mir; use rustc_hir::def::DefKind; -use rustc_middle::ty::TyCtxt; use rustc_smir::rustc_internal; use stable_mir::ItemKind; use stable_mir::crate_def::CrateDef; @@ -33,7 +31,7 @@ use std::ops::ControlFlow; const CRATE_NAME: &str = "input"; /// This function uses the Stable MIR APIs to get information about the test crate. -fn test_stable_mir(_tcx: TyCtxt<'_>) -> ControlFlow<()> { +fn test_stable_mir() -> ControlFlow<()> { // Get the local crate using stable_mir API. let local = stable_mir::local_crate(); assert_eq!(&local.name, CRATE_NAME); @@ -194,7 +192,7 @@ fn main() { CRATE_NAME.to_string(), path.to_string(), ]; - run!(args, tcx, test_stable_mir(tcx)).unwrap(); + run!(args, test_stable_mir).unwrap(); } fn generate_input(path: &str) -> std::io::Result<()> { diff --git a/tests/ui-fulldeps/stable-mir/projections.rs b/tests/ui-fulldeps/stable-mir/projections.rs index 8c3fda7b6bb1f..40f2d901a2b23 100644 --- a/tests/ui-fulldeps/stable-mir/projections.rs +++ b/tests/ui-fulldeps/stable-mir/projections.rs @@ -12,14 +12,12 @@ #![feature(control_flow_enum)] extern crate rustc_hir; -extern crate rustc_middle; #[macro_use] extern crate rustc_smir; extern crate rustc_driver; extern crate rustc_interface; extern crate stable_mir; -use rustc_middle::ty::TyCtxt; use rustc_smir::rustc_internal; use stable_mir::crate_def::CrateDef; use stable_mir::mir::{ProjectionElem, Rvalue, StatementKind}; @@ -32,7 +30,7 @@ use std::ops::ControlFlow; const CRATE_NAME: &str = "input"; /// Tests projections within Place objects -fn test_place_projections(_tcx: TyCtxt<'_>) -> ControlFlow<()> { +fn test_place_projections() -> ControlFlow<()> { let items = stable_mir::all_local_items(); let body = get_item(&items, (ItemKind::Fn, "projections")).unwrap().body(); assert_eq!(body.blocks.len(), 4); @@ -159,7 +157,7 @@ fn main() { CRATE_NAME.to_string(), path.to_string(), ]; - run!(args, tcx, test_place_projections(tcx)).unwrap(); + run!(args, test_place_projections).unwrap(); } fn generate_input(path: &str) -> std::io::Result<()> { diff --git a/tests/ui-fulldeps/stable-mir/smir_internal.rs b/tests/ui-fulldeps/stable-mir/smir_internal.rs index b0596b1882383..63a6a5e47e8b6 100644 --- a/tests/ui-fulldeps/stable-mir/smir_internal.rs +++ b/tests/ui-fulldeps/stable-mir/smir_internal.rs @@ -16,17 +16,15 @@ extern crate rustc_smir; extern crate rustc_driver; extern crate rustc_interface; -extern crate rustc_middle; extern crate stable_mir; -use rustc_middle::ty::TyCtxt; use rustc_smir::rustc_internal; use std::io::Write; use std::ops::ControlFlow; const CRATE_NAME: &str = "input"; -fn test_translation(_tcx: TyCtxt<'_>) -> ControlFlow<()> { +fn test_translation() -> ControlFlow<()> { let main_fn = stable_mir::entry_fn().unwrap(); let body = main_fn.body(); let orig_ty = body.locals()[0].ty; @@ -48,7 +46,7 @@ fn main() { CRATE_NAME.to_string(), path.to_string(), ]; - run!(args, tcx, test_translation(tcx)).unwrap(); + run!(args, test_translation).unwrap(); } fn generate_input(path: &str) -> std::io::Result<()> { diff --git a/tests/ui-fulldeps/stable-mir/smir_visitor.rs b/tests/ui-fulldeps/stable-mir/smir_visitor.rs index 027b0e7d9e85c..d7739770b706a 100644 --- a/tests/ui-fulldeps/stable-mir/smir_visitor.rs +++ b/tests/ui-fulldeps/stable-mir/smir_visitor.rs @@ -11,7 +11,6 @@ #![feature(assert_matches)] #![feature(control_flow_enum)] -extern crate rustc_middle; #[macro_use] extern crate rustc_smir; extern crate rustc_driver; @@ -19,7 +18,6 @@ extern crate rustc_interface; extern crate stable_mir; use std::collections::HashSet; -use rustc_middle::ty::TyCtxt; use rustc_smir::rustc_internal; use stable_mir::*; use stable_mir::mir::MirVisitor; @@ -28,7 +26,7 @@ use std::ops::ControlFlow; const CRATE_NAME: &str = "input"; -fn test_visitor(_tcx: TyCtxt<'_>) -> ControlFlow<()> { +fn test_visitor() -> ControlFlow<()> { let main_fn = stable_mir::entry_fn(); let main_body = main_fn.unwrap().body(); let main_visitor = TestVisitor::collect(&main_body); @@ -116,7 +114,7 @@ fn main() { CRATE_NAME.to_string(), path.to_string(), ]; - run!(args, tcx, test_visitor(tcx)).unwrap(); + run!(args, test_visitor).unwrap(); } fn generate_input(path: &str) -> std::io::Result<()> { From 2564811e7b7464d4e2ab8cd5a826bf7c2f9f7d8b Mon Sep 17 00:00:00 2001 From: "Celina G. Val" Date: Tue, 16 Jan 2024 14:31:25 -0800 Subject: [PATCH 2/3] Remove tcx function and make `internal` fn safer I added `tcx` argument to `internal` to force 'tcx to be the same lifetime as TyCtxt. The only other solution I could think is to change this function to be `unsafe`. --- compiler/rustc_smir/src/rustc_internal/mod.rs | 78 ++++++++++++------- compiler/rustc_smir/src/rustc_smir/context.rs | 5 +- .../stable-mir/check_trait_queries.rs | 4 +- .../stable-mir/compilation-result.rs | 10 +-- tests/ui-fulldeps/stable-mir/smir_internal.rs | 8 +- 5 files changed, 66 insertions(+), 39 deletions(-) diff --git a/compiler/rustc_smir/src/rustc_internal/mod.rs b/compiler/rustc_smir/src/rustc_internal/mod.rs index 7633739f2890a..873bd94e88fb9 100644 --- a/compiler/rustc_smir/src/rustc_internal/mod.rs +++ b/compiler/rustc_smir/src/rustc_internal/mod.rs @@ -28,7 +28,7 @@ pub mod pretty; /// /// # Warning /// -/// This function is unstable, and it's behavior may change at any point. +/// This function is unstable, and its behavior may change at any point. /// E.g.: Items that were previously supported, may no longer be supported, or its translation may /// change. /// @@ -50,23 +50,12 @@ pub fn stable<'tcx, S: Stable<'tcx>>(item: S) -> S::T { /// # Panics /// /// This function will panic if StableMIR has not been properly initialized. -pub fn internal<'tcx, S: RustcInternal<'tcx>>(item: S) -> S::T { +pub fn internal<'tcx, S: RustcInternal<'tcx>>(tcx: TyCtxt<'tcx>, item: S) -> S::T { + // The tcx argument ensures that the item won't outlive the type context. + let _ = tcx; with_tables(|tables| item.internal(tables)) } -/// Retrieve the internal Rust compiler type context. -/// -/// # Warning -/// -/// This function is unstable, and it's behavior may change at any point. -/// -/// # Panics -/// -/// This function will panic if StableMIR has not been properly initialized. -pub fn tcx<'tcx>() -> TyCtxt<'tcx> { - with_tables(|tables| tables.tcx) -} - impl<'tcx> Index for Tables<'tcx> { type Output = DefId; @@ -227,7 +216,7 @@ where /// Instantiate and run the compiler with the provided arguments and callback. /// -/// The callback will be invoked after the compiler ran all its analysis, but before code generation. +/// The callback will be invoked after the compiler ran all its analyses, but before code generation. /// Note that this macro accepts two different formats for the callback: /// 1. An ident that resolves to a function that accepts no argument and returns `ControlFlow` /// ```ignore(needs-extern-crate) @@ -249,7 +238,7 @@ where /// # assert_eq!(result, Err(CompilerError::Skipped)) /// # } /// ``` -/// 2. An expression that represents the body of a closure: +/// 2. A closure expression: /// ```ignore(needs-extern-crate) /// # extern crate rustc_driver; /// # extern crate rustc_interface; @@ -267,26 +256,63 @@ where /// } /// # let args = vec!["--verbose".to_string()]; /// # let extra_args = vec![]; -/// let result = run!(args, analyze_code(extra_args)); +/// let result = run!(args, || analyze_code(extra_args)); /// # assert_eq!(result, Err(CompilerError::Skipped)) /// # } /// ``` #[macro_export] macro_rules! run { ($args:expr, $callback_fn:ident) => { - run!($args, $callback_fn()) + run_driver!($args, || $callback_fn()) + }; + ($args:expr, $callback:expr) => { + run_driver!($args, $callback) }; - ($args:expr, $callback:expr) => {{ +} + +/// Instantiate and run the compiler with the provided arguments and callback. +/// +/// This is similar to `run` but it invokes the callback with the compiler's `TyCtxt`, +/// which can be used to invoke internal APIs. +#[macro_export] +macro_rules! run_with_tcx { + ($args:expr, $callback_fn:ident) => { + run_driver!($args, |tcx| $callback_fn(tcx), with_tcx) + }; + ($args:expr, $callback:expr) => { + run_driver!($args, $callback, with_tcx) + }; +} + +/// Optionally include an ident. This is needed due to macro hygiene. +#[macro_export] +#[doc(hidden)] +macro_rules! optional { + (with_tcx $ident:ident) => { + $ident + }; +} + +/// Prefer using [run] and [run_with_tcx] instead. +/// +/// This macro implements the instantiation of a StableMIR driver, and it will invoke +/// the given callback after the compiler analyses. +/// +/// The third argument determines whether the callback requires `tcx` as an argument. +#[macro_export] +#[doc(hidden)] +macro_rules! run_driver { + ($args:expr, $callback:expr $(, $with_tcx:ident)?) => {{ use rustc_driver::{Callbacks, Compilation, RunCompiler}; use rustc_interface::{interface, Queries}; use stable_mir::CompilerError; use std::ops::ControlFlow; - pub struct StableMir ControlFlow> + pub struct StableMir ControlFlow> where B: Send, C: Send, - F: FnOnce() -> ControlFlow + Send, + F: FnOnce($(optional!($with_tcx TyCtxt))?) -> ControlFlow + Send, { args: Vec, callback: Option, @@ -297,7 +323,7 @@ macro_rules! run { where B: Send, C: Send, - F: FnOnce() -> ControlFlow + Send, + F: FnOnce($(optional!($with_tcx TyCtxt))?) -> ControlFlow + Send, { /// Creates a new `StableMir` instance, with given test_function and arguments. pub fn new(args: Vec, callback: F) -> Self { @@ -325,7 +351,7 @@ macro_rules! run { where B: Send, C: Send, - F: FnOnce() -> ControlFlow + Send, + F: FnOnce($(optional!($with_tcx TyCtxt))?) -> ControlFlow + Send, { /// Called after analysis. Return value instructs the compiler whether to /// continue the compilation afterwards (defaults to `Compilation::Continue`) @@ -337,7 +363,7 @@ macro_rules! run { queries.global_ctxt().unwrap().enter(|tcx| { if let Some(callback) = self.callback.take() { rustc_internal::run(tcx, || { - self.result = Some((callback)()); + self.result = Some(callback($(optional!($with_tcx tcx))?)); }) .unwrap(); if self.result.as_ref().is_some_and(|val| val.is_continue()) { @@ -352,7 +378,7 @@ macro_rules! run { } } - StableMir::new($args, || $callback).run() + StableMir::new($args, $callback).run() }}; } diff --git a/compiler/rustc_smir/src/rustc_smir/context.rs b/compiler/rustc_smir/src/rustc_smir/context.rs index fffc454804d29..2a2626654a013 100644 --- a/compiler/rustc_smir/src/rustc_smir/context.rs +++ b/compiler/rustc_smir/src/rustc_smir/context.rs @@ -29,7 +29,7 @@ use stable_mir::{Crate, CrateItem, CrateNum, DefId, Error, Filename, ItemKind, S use std::cell::RefCell; use std::iter; -use crate::rustc_internal::{internal, RustcInternal}; +use crate::rustc_internal::RustcInternal; use crate::rustc_smir::builder::BodyBuilder; use crate::rustc_smir::{alloc, new_item_kind, smir_crate, Stable, Tables}; @@ -322,7 +322,8 @@ impl<'tcx> Context for TablesWrapper<'tcx> { } fn const_literal(&self, cnst: &stable_mir::ty::Const) -> String { - internal(cnst).to_string() + let mut tables = self.0.borrow_mut(); + cnst.internal(&mut *tables).to_string() } fn span_of_an_item(&self, def_id: stable_mir::DefId) -> Span { diff --git a/tests/ui-fulldeps/stable-mir/check_trait_queries.rs b/tests/ui-fulldeps/stable-mir/check_trait_queries.rs index fb1197e4ecc40..c9fbe15ffb03f 100644 --- a/tests/ui-fulldeps/stable-mir/check_trait_queries.rs +++ b/tests/ui-fulldeps/stable-mir/check_trait_queries.rs @@ -11,14 +11,12 @@ #![feature(assert_matches)] #![feature(control_flow_enum)] -extern crate rustc_middle; #[macro_use] extern crate rustc_smir; extern crate rustc_driver; extern crate rustc_interface; extern crate stable_mir; -use rustc_middle::ty::TyCtxt; use rustc_smir::rustc_internal; use stable_mir::CrateDef; use std::collections::HashSet; @@ -83,7 +81,7 @@ fn main() { CRATE_NAME.to_string(), path.to_string(), ]; - run!(args, test_traits()).unwrap(); + run!(args, test_traits).unwrap(); } fn generate_input(path: &str) -> std::io::Result<()> { diff --git a/tests/ui-fulldeps/stable-mir/compilation-result.rs b/tests/ui-fulldeps/stable-mir/compilation-result.rs index c802316c1d861..e6dd9fa132d83 100644 --- a/tests/ui-fulldeps/stable-mir/compilation-result.rs +++ b/tests/ui-fulldeps/stable-mir/compilation-result.rs @@ -35,33 +35,33 @@ fn main() { } fn test_continue(args: Vec) { - let result = run!(args, ControlFlow::Continue::<(), bool>(true)); + let result = run!(args, || ControlFlow::Continue::<(), bool>(true)); assert_eq!(result, Ok(true)); } fn test_break(args: Vec) { - let result = run!(args, ControlFlow::Break::(false)); + let result = run!(args, || ControlFlow::Break::(false)); assert_eq!(result, Err(stable_mir::CompilerError::Interrupted(false))); } #[allow(unreachable_code)] fn test_skipped(mut args: Vec) { args.push("--version".to_string()); - let result = run!(args, unreachable!() as ControlFlow<()>); + let result = run!(args, || unreachable!() as ControlFlow<()>); assert_eq!(result, Err(stable_mir::CompilerError::Skipped)); } #[allow(unreachable_code)] fn test_failed(mut args: Vec) { args.push("--cfg=broken".to_string()); - let result = run!(args, unreachable!() as ControlFlow<()>); + let result = run!(args, || unreachable!() as ControlFlow<()>); assert_eq!(result, Err(stable_mir::CompilerError::CompilationFailed)); } /// Test that we are able to pass a closure and set the return according to the captured value. fn test_captured(args: Vec) { let captured = "10".to_string(); - let result = run!(args, ControlFlow::Continue::<(), usize>(captured.len())); + let result = run!(args, || ControlFlow::Continue::<(), usize>(captured.len())); assert_eq!(result, Ok(captured.len())); } diff --git a/tests/ui-fulldeps/stable-mir/smir_internal.rs b/tests/ui-fulldeps/stable-mir/smir_internal.rs index 63a6a5e47e8b6..b0811364c09f4 100644 --- a/tests/ui-fulldeps/stable-mir/smir_internal.rs +++ b/tests/ui-fulldeps/stable-mir/smir_internal.rs @@ -16,19 +16,21 @@ extern crate rustc_smir; extern crate rustc_driver; extern crate rustc_interface; +extern crate rustc_middle; extern crate stable_mir; +use rustc_middle::ty::TyCtxt; use rustc_smir::rustc_internal; use std::io::Write; use std::ops::ControlFlow; const CRATE_NAME: &str = "input"; -fn test_translation() -> ControlFlow<()> { +fn test_translation(tcx: TyCtxt) -> ControlFlow<()> { let main_fn = stable_mir::entry_fn().unwrap(); let body = main_fn.body(); let orig_ty = body.locals()[0].ty; - let rustc_ty = rustc_internal::internal(&orig_ty); + let rustc_ty = rustc_internal::internal(tcx, &orig_ty); assert!(rustc_ty.is_unit()); ControlFlow::Continue(()) } @@ -46,7 +48,7 @@ fn main() { CRATE_NAME.to_string(), path.to_string(), ]; - run!(args, test_translation).unwrap(); + run_with_tcx!(args, test_translation).unwrap(); } fn generate_input(path: &str) -> std::io::Result<()> { From 6a573cbc60af8319e11cf0f0a578f8a12caa932d Mon Sep 17 00:00:00 2001 From: "Celina G. Val" Date: Wed, 17 Jan 2024 19:35:19 -0800 Subject: [PATCH 3/3] Revert changes to internal method for now - Move fix to a separate PR --- compiler/rustc_smir/src/rustc_internal/mod.rs | 28 ++----------------- compiler/rustc_smir/src/rustc_smir/context.rs | 5 ++-- tests/ui-fulldeps/stable-mir/smir_internal.rs | 4 +-- 3 files changed, 6 insertions(+), 31 deletions(-) diff --git a/compiler/rustc_smir/src/rustc_internal/mod.rs b/compiler/rustc_smir/src/rustc_internal/mod.rs index 873bd94e88fb9..b99640d2f2d68 100644 --- a/compiler/rustc_smir/src/rustc_internal/mod.rs +++ b/compiler/rustc_smir/src/rustc_internal/mod.rs @@ -24,35 +24,11 @@ use std::ops::Index; mod internal; pub mod pretty; -/// Convert an internal Rust compiler item into its stable counterpart, if one exists. -/// -/// # Warning -/// -/// This function is unstable, and its behavior may change at any point. -/// E.g.: Items that were previously supported, may no longer be supported, or its translation may -/// change. -/// -/// # Panics -/// -/// This function will panic if StableMIR has not been properly initialized. pub fn stable<'tcx, S: Stable<'tcx>>(item: S) -> S::T { with_tables(|tables| item.stable(tables)) } -/// Convert a stable item into its internal Rust compiler counterpart, if one exists. -/// -/// # Warning -/// -/// This function is unstable, and it's behavior may change at any point. -/// Not every stable item can be converted to an internal one. -/// Furthermore, items that were previously supported, may no longer be supported in newer versions. -/// -/// # Panics -/// -/// This function will panic if StableMIR has not been properly initialized. -pub fn internal<'tcx, S: RustcInternal<'tcx>>(tcx: TyCtxt<'tcx>, item: S) -> S::T { - // The tcx argument ensures that the item won't outlive the type context. - let _ = tcx; +pub fn internal<'tcx, S: RustcInternal<'tcx>>(item: S) -> S::T { with_tables(|tables| item.internal(tables)) } @@ -293,7 +269,7 @@ macro_rules! optional { }; } -/// Prefer using [run] and [run_with_tcx] instead. +/// Prefer using [run!] and [run_with_tcx] instead. /// /// This macro implements the instantiation of a StableMIR driver, and it will invoke /// the given callback after the compiler analyses. diff --git a/compiler/rustc_smir/src/rustc_smir/context.rs b/compiler/rustc_smir/src/rustc_smir/context.rs index 2a2626654a013..fffc454804d29 100644 --- a/compiler/rustc_smir/src/rustc_smir/context.rs +++ b/compiler/rustc_smir/src/rustc_smir/context.rs @@ -29,7 +29,7 @@ use stable_mir::{Crate, CrateItem, CrateNum, DefId, Error, Filename, ItemKind, S use std::cell::RefCell; use std::iter; -use crate::rustc_internal::RustcInternal; +use crate::rustc_internal::{internal, RustcInternal}; use crate::rustc_smir::builder::BodyBuilder; use crate::rustc_smir::{alloc, new_item_kind, smir_crate, Stable, Tables}; @@ -322,8 +322,7 @@ impl<'tcx> Context for TablesWrapper<'tcx> { } fn const_literal(&self, cnst: &stable_mir::ty::Const) -> String { - let mut tables = self.0.borrow_mut(); - cnst.internal(&mut *tables).to_string() + internal(cnst).to_string() } fn span_of_an_item(&self, def_id: stable_mir::DefId) -> Span { diff --git a/tests/ui-fulldeps/stable-mir/smir_internal.rs b/tests/ui-fulldeps/stable-mir/smir_internal.rs index b0811364c09f4..b4faaeb4fc06d 100644 --- a/tests/ui-fulldeps/stable-mir/smir_internal.rs +++ b/tests/ui-fulldeps/stable-mir/smir_internal.rs @@ -26,11 +26,11 @@ use std::ops::ControlFlow; const CRATE_NAME: &str = "input"; -fn test_translation(tcx: TyCtxt) -> ControlFlow<()> { +fn test_translation(_tcx: TyCtxt) -> ControlFlow<()> { let main_fn = stable_mir::entry_fn().unwrap(); let body = main_fn.body(); let orig_ty = body.locals()[0].ty; - let rustc_ty = rustc_internal::internal(tcx, &orig_ty); + let rustc_ty = rustc_internal::internal(&orig_ty); assert!(rustc_ty.is_unit()); ControlFlow::Continue(()) }