diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index 71026d828a1a..5e059d6f2b0d 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -51,7 +51,10 @@ fn main() { if let Some("miri") = std::env::args().nth(1).as_ref().map(AsRef::as_ref) { // this arm is when `cargo miri` is called - let manifest_path_arg = std::env::args().skip(2).find(|val| val.starts_with("--manifest-path=")); + let test = std::env::args().nth(2).map_or(false, |text| text == "test"); + let skip = if test { 3 } else { 2 }; + + let manifest_path_arg = std::env::args().skip(skip).find(|val| val.starts_with("--manifest-path=")); let mut metadata = if let Ok(metadata) = cargo_metadata::metadata(manifest_path_arg.as_ref().map(AsRef::as_ref)) { metadata @@ -80,14 +83,21 @@ fn main() { .expect("could not find matching package"); let package = metadata.packages.remove(package_index); for target in package.targets { - let args = std::env::args().skip(2); - if let Some("bin") = target.kind.get(0).map(AsRef::as_ref) { - if let Err(code) = process(vec!["--bin".to_string(), target.name].into_iter().chain(args), + let args = std::env::args().skip(skip); + if test && target.kind.get(0).map_or(false, |kind| kind == "test") { + if let Err(code) = process(vec!["--test".to_string(), target.name].into_iter().chain(args), &dep_path) { std::process::exit(code); } - } else { - panic!("badly formatted cargo metadata: target::kind is an empty array"); + } else if !test { + if target.kind.get(0).map_or(false, |kind| kind == "bin") { + if let Err(code) = process(vec!["--bin".to_string(), target.name].into_iter().chain(args), + &dep_path) { + std::process::exit(code); + } + } else { + panic!("badly formatted cargo metadata: target::kind is an empty array"); + } } } } else { diff --git a/src/bin/miri.rs b/src/bin/miri.rs index e36b9baa64bb..0f8bb68549b5 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -14,6 +14,8 @@ use rustc::session::Session; use rustc_driver::{Compilation, CompilerCalls, RustcDefaultCalls}; use rustc_driver::driver::{CompileState, CompileController}; use rustc::session::config::{self, Input, ErrorOutputType}; +use rustc::hir::{self, itemlikevisit}; +use rustc::ty::TyCtxt; use syntax::ast::{MetaItemKind, NestedMetaItemKind, self}; use std::path::PathBuf; @@ -68,19 +70,39 @@ fn after_hir_lowering(state: &mut CompileState) { state.session.plugin_attributes.borrow_mut().push(attr); } -fn after_analysis(state: &mut CompileState) { +fn after_analysis<'a, 'tcx>(state: &mut CompileState<'a, 'tcx>) { state.session.abort_if_errors(); let tcx = state.tcx.unwrap(); - if let Some((entry_node_id, _)) = *state.session.entry_fn.borrow() { - let entry_def_id = tcx.map.local_def_id(entry_node_id); - let limits = resource_limits_from_attributes(state); - miri::run_mir_passes(tcx); - miri::eval_main(tcx, entry_def_id, limits); + miri::run_mir_passes(tcx); + let limits = resource_limits_from_attributes(state); - state.session.abort_if_errors(); + if std::env::args().any(|arg| arg == "--test") { + struct Visitor<'a, 'tcx: 'a>(miri::ResourceLimits, TyCtxt<'a, 'tcx, 'tcx>, &'a CompileState<'a, 'tcx>); + impl<'a, 'tcx: 'a, 'hir> itemlikevisit::ItemLikeVisitor<'hir> for Visitor<'a, 'tcx> { + fn visit_item(&mut self, i: &'hir hir::Item) { + if let hir::Item_::ItemFn(_, _, _, _, _, body_id) = i.node { + if i.attrs.iter().any(|attr| attr.value.name == "test") { + let did = self.1.map.body_owner_def_id(body_id); + println!("running test: {}", self.1.map.def_path(did).to_string(self.1)); + miri::eval_main(self.1, did, self.0); + self.2.session.abort_if_errors(); + } + } + } + fn visit_trait_item(&mut self, _trait_item: &'hir hir::TraitItem) {} + fn visit_impl_item(&mut self, _impl_item: &'hir hir::ImplItem) {} + } + state.hir_crate.unwrap().visit_all_item_likes(&mut Visitor(limits, tcx, state)); } else { - println!("no main function found, assuming auxiliary build"); + if let Some((entry_node_id, _)) = *state.session.entry_fn.borrow() { + let entry_def_id = tcx.map.local_def_id(entry_node_id); + miri::eval_main(tcx, entry_def_id, limits); + + state.session.abort_if_errors(); + } else { + println!("no main function found, assuming auxiliary build"); + } } }