Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make tcx optional from StableMIR run macro and extend it to accept closures #119833

Merged
merged 3 commits into from
Jan 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
122 changes: 106 additions & 16 deletions compiler/rustc_smir/src/rustc_internal/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -190,35 +190,120 @@ 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 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<B, C>`
/// ```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. A closure expression:
/// ```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<String>) -> 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_fn:ident) => {
run_driver!($args, || $callback_fn())
};
($args:expr, $callback:expr) => {
run_driver!($args, $callback)
};
}

/// 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!($args, tcx, $callback)
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
};
($args:expr, $tcx:ident, $callback:expr) => {{
}

/// 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<B = (), C = ()>
pub struct StableMir<B = (), C = (), F = fn($(optional!($with_tcx TyCtxt))?) -> ControlFlow<B, C>>
where
B: Send,
C: Send,
F: FnOnce($(optional!($with_tcx TyCtxt))?) -> ControlFlow<B, C> + Send,
{
args: Vec<String>,
callback: fn(TyCtxt<'_>) -> ControlFlow<B, C>,
callback: Option<F>,
result: Option<ControlFlow<B, C>>,
}

impl<B, C> StableMir<B, C>
impl<B, C, F> StableMir<B, C, F>
where
B: Send,
C: Send,
F: FnOnce($(optional!($with_tcx TyCtxt))?) -> ControlFlow<B, C> + Send,
{
/// Creates a new `StableMir` instance, with given test_function and arguments.
pub fn new(args: Vec<String>, callback: fn(TyCtxt<'_>) -> ControlFlow<B, C>) -> Self {
StableMir { args, callback, result: None }
pub fn new(args: Vec<String>, callback: F) -> Self {
StableMir { args, callback: Some(callback), result: None }
}

/// Runs the compiler against given target and tests it with `test_function`
Expand All @@ -238,10 +323,11 @@ macro_rules! run {
}
}

impl<B, C> Callbacks for StableMir<B, C>
impl<B, C, F> Callbacks for StableMir<B, C, F>
where
B: Send,
C: Send,
F: FnOnce($(optional!($with_tcx TyCtxt))?) -> ControlFlow<B, C> + Send,
{
/// Called after analysis. Return value instructs the compiler whether to
/// continue the compilation afterwards (defaults to `Compilation::Continue`)
Expand All @@ -251,20 +337,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($(optional!($with_tcx tcx))?));
})
.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()
}};
}

Expand Down
6 changes: 2 additions & 4 deletions tests/ui-fulldeps/stable-mir/check_abi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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();

Expand Down Expand Up @@ -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<()> {
Expand Down
6 changes: 2 additions & 4 deletions tests/ui-fulldeps/stable-mir/check_allocation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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());
Expand Down Expand Up @@ -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<()> {
Expand Down
6 changes: 2 additions & 4 deletions tests/ui-fulldeps/stable-mir/check_defs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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::*;
Expand All @@ -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");
Expand Down Expand Up @@ -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<()> {
Expand Down
6 changes: 2 additions & 4 deletions tests/ui-fulldeps/stable-mir/check_instance.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,13 @@
#![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 mir::{mono::Instance, TerminatorKind::*};
use rustc_middle::ty::TyCtxt;
use rustc_smir::rustc_internal;
use stable_mir::ty::{RigidTy, TyKind};
use stable_mir::*;
Expand All @@ -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.
Expand Down Expand Up @@ -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<()> {
Expand Down
6 changes: 2 additions & 4 deletions tests/ui-fulldeps/stable-mir/check_item_kind.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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.
Expand Down Expand Up @@ -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<()> {
Expand Down
4 changes: 1 addition & 3 deletions tests/ui-fulldeps/stable-mir/check_trait_queries.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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<()> {
Expand Down
6 changes: 2 additions & 4 deletions tests/ui-fulldeps/stable-mir/check_ty_fold.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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};
Expand Down Expand Up @@ -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<()> {
Expand Down
Loading
Loading