mirror of
https://github.com/rust-lang/rust.git
synced 2025-04-17 06:26:55 +00:00
add support for #[start]
This commit is contained in:
parent
4f1fca7512
commit
84b058ac47
@ -20,11 +20,12 @@ impl rustc_driver::Callbacks for MiriCompilerCalls<'_> {
|
||||
compiler.session().abort_if_errors();
|
||||
|
||||
queries.global_ctxt().unwrap().peek_mut().enter(|tcx| {
|
||||
let (entry_def_id, _) = tcx.entry_fn(()).expect("no main or start function found");
|
||||
let (entry_def_id, entry_type) =
|
||||
tcx.entry_fn(()).expect("no main or start function found");
|
||||
|
||||
self.bencher.iter(|| {
|
||||
let config = miri::MiriConfig::default();
|
||||
miri::eval_main(tcx, entry_def_id, config);
|
||||
miri::eval_entry(tcx, entry_def_id, entry_type, config);
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -58,8 +58,8 @@ impl rustc_driver::Callbacks for MiriCompilerCalls {
|
||||
|
||||
queries.global_ctxt().unwrap().peek_mut().enter(|tcx| {
|
||||
init_late_loggers(tcx);
|
||||
let (entry_def_id, _) = if let Some((entry_def, x)) = tcx.entry_fn(()) {
|
||||
(entry_def, x)
|
||||
let (entry_def_id, entry_type) = if let Some(entry_def) = tcx.entry_fn(()) {
|
||||
entry_def
|
||||
} else {
|
||||
let output_ty = ErrorOutputType::HumanReadable(HumanReadableErrorType::Default(
|
||||
ColorConfig::Auto,
|
||||
@ -79,7 +79,7 @@ impl rustc_driver::Callbacks for MiriCompilerCalls {
|
||||
env::set_current_dir(cwd).unwrap();
|
||||
}
|
||||
|
||||
if let Some(return_code) = miri::eval_main(tcx, entry_def_id, config) {
|
||||
if let Some(return_code) = miri::eval_entry(tcx, entry_def_id, entry_type, config) {
|
||||
std::process::exit(
|
||||
i32::try_from(return_code).expect("Return value was too large!"),
|
||||
);
|
||||
|
90
src/eval.rs
90
src/eval.rs
@ -10,6 +10,8 @@ use rustc_middle::ty::{self, layout::LayoutCx, TyCtxt};
|
||||
use rustc_target::abi::LayoutOf;
|
||||
use rustc_target::spec::abi::Abi;
|
||||
|
||||
use rustc_session::config::EntryFnType;
|
||||
|
||||
use crate::*;
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq)]
|
||||
@ -117,12 +119,13 @@ impl Default for MiriConfig {
|
||||
}
|
||||
|
||||
/// Returns a freshly created `InterpCx`, along with an `MPlaceTy` representing
|
||||
/// the location where the return value of the `start` lang item will be
|
||||
/// the location where the return value of the `start` function will be
|
||||
/// written to.
|
||||
/// Public because this is also used by `priroda`.
|
||||
pub fn create_ecx<'mir, 'tcx: 'mir>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
main_id: DefId,
|
||||
entry_id: DefId,
|
||||
entry_type: EntryFnType,
|
||||
config: MiriConfig,
|
||||
) -> InterpResult<'tcx, (InterpCx<'mir, 'tcx, Evaluator<'mir, 'tcx>>, MPlaceTy<'tcx, Tag>)> {
|
||||
let param_env = ty::ParamEnv::reveal_all();
|
||||
@ -145,26 +148,14 @@ pub fn create_ecx<'mir, 'tcx: 'mir>(
|
||||
}
|
||||
|
||||
// Setup first stack-frame
|
||||
let main_instance = ty::Instance::mono(tcx, main_id);
|
||||
let main_mir = ecx.load_mir(main_instance.def, None)?;
|
||||
let entry_instance = ty::Instance::mono(tcx, entry_id);
|
||||
/*let entry_mir = ecx.load_mir(entry_instance.def, None)?;
|
||||
if main_mir.arg_count != 0 {
|
||||
bug!("main function must not take any arguments");
|
||||
}
|
||||
}*/
|
||||
|
||||
let start_id = tcx.lang_items().start_fn().unwrap();
|
||||
let main_ret_ty = tcx.fn_sig(main_id).output();
|
||||
let main_ret_ty = main_ret_ty.no_bound_vars().unwrap();
|
||||
let start_instance = ty::Instance::resolve(
|
||||
tcx,
|
||||
ty::ParamEnv::reveal_all(),
|
||||
start_id,
|
||||
tcx.mk_substs(::std::iter::once(ty::subst::GenericArg::from(main_ret_ty))),
|
||||
)
|
||||
.unwrap()
|
||||
.unwrap();
|
||||
// First argument is constructed later, because its skipped if the entry function uses #[start]
|
||||
|
||||
// First argument: pointer to `main()`.
|
||||
let main_ptr = ecx.memory.create_fn_alloc(FnVal::Instance(main_instance));
|
||||
// Second argument (argc): length of `config.args`.
|
||||
let argc = Scalar::from_machine_usize(u64::try_from(config.args.len()).unwrap(), &ecx);
|
||||
// Third argument (`argv`): created from `config.args`.
|
||||
@ -237,28 +228,71 @@ pub fn create_ecx<'mir, 'tcx: 'mir>(
|
||||
argv
|
||||
};
|
||||
|
||||
/*let args: &[_] = match entry_type {
|
||||
EntryFnType::Main => {
|
||||
// First argument: pointer to `main()`.
|
||||
let main_ptr = ecx.memory.create_fn_alloc(FnVal::Instance(main_instance));
|
||||
|
||||
&[Scalar::from_pointer(main_ptr, &ecx).into(), argc.into(), argv]
|
||||
}
|
||||
EntryFnType::Start => &[argc.into(), argv],
|
||||
};*/
|
||||
|
||||
// Return place (in static memory so that it does not count as leak).
|
||||
let ret_place = ecx.allocate(ecx.machine.layouts.isize, MiriMemoryKind::Machine.into())?;
|
||||
// Call start function.
|
||||
ecx.call_function(
|
||||
start_instance,
|
||||
Abi::Rust,
|
||||
&[Scalar::from_pointer(main_ptr, &ecx).into(), argc.into(), argv],
|
||||
Some(&ret_place.into()),
|
||||
StackPopCleanup::None { cleanup: true },
|
||||
)?;
|
||||
|
||||
match entry_type {
|
||||
EntryFnType::Main => {
|
||||
let start_id = tcx.lang_items().start_fn().unwrap();
|
||||
let main_ret_ty = tcx.fn_sig(entry_id).output();
|
||||
let main_ret_ty = main_ret_ty.no_bound_vars().unwrap();
|
||||
let start_instance = ty::Instance::resolve(
|
||||
tcx,
|
||||
ty::ParamEnv::reveal_all(),
|
||||
start_id,
|
||||
tcx.mk_substs(::std::iter::once(ty::subst::GenericArg::from(main_ret_ty))),
|
||||
)
|
||||
.unwrap()
|
||||
.unwrap();
|
||||
|
||||
let main_ptr = ecx.memory.create_fn_alloc(FnVal::Instance(entry_instance));
|
||||
|
||||
ecx.call_function(
|
||||
start_instance,
|
||||
Abi::Rust,
|
||||
&[Scalar::from_pointer(main_ptr, &ecx).into(), argc.into(), argv],
|
||||
Some(&ret_place.into()),
|
||||
StackPopCleanup::None { cleanup: true },
|
||||
)?;
|
||||
}
|
||||
EntryFnType::Start => {
|
||||
ecx.call_function(
|
||||
entry_instance,
|
||||
Abi::Rust,
|
||||
&[argc.into(), argv],
|
||||
Some(&ret_place.into()),
|
||||
StackPopCleanup::None { cleanup: true },
|
||||
)?;
|
||||
}
|
||||
}
|
||||
|
||||
Ok((ecx, ret_place))
|
||||
}
|
||||
|
||||
/// Evaluates the main function specified by `main_id`.
|
||||
/// Evaluates the entry function specified by `entry_id`.
|
||||
/// Returns `Some(return_code)` if program executed completed.
|
||||
/// Returns `None` if an evaluation error occured.
|
||||
pub fn eval_main<'tcx>(tcx: TyCtxt<'tcx>, main_id: DefId, config: MiriConfig) -> Option<i64> {
|
||||
pub fn eval_entry<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
entry_id: DefId,
|
||||
entry_type: EntryFnType,
|
||||
config: MiriConfig,
|
||||
) -> Option<i64> {
|
||||
// Copy setting before we move `config`.
|
||||
let ignore_leaks = config.ignore_leaks;
|
||||
|
||||
let (mut ecx, ret_place) = match create_ecx(tcx, main_id, config) {
|
||||
let (mut ecx, ret_place) = match create_ecx(tcx, entry_id, entry_type, config) {
|
||||
Ok(v) => v,
|
||||
Err(err) => {
|
||||
err.print_backtrace();
|
||||
|
@ -60,7 +60,7 @@ pub use crate::diagnostics::{
|
||||
NonHaltingDiagnostic, TerminationInfo,
|
||||
};
|
||||
pub use crate::eval::{
|
||||
create_ecx, eval_main, AlignmentCheck, IsolatedOp, MiriConfig, RejectOpWith,
|
||||
create_ecx, eval_entry, AlignmentCheck, IsolatedOp, MiriConfig, RejectOpWith,
|
||||
};
|
||||
pub use crate::helpers::EvalContextExt as HelpersEvalContextExt;
|
||||
pub use crate::machine::{
|
||||
|
8
tests/run-pass/start.rs
Normal file
8
tests/run-pass/start.rs
Normal file
@ -0,0 +1,8 @@
|
||||
#![feature(start)]
|
||||
|
||||
#[start]
|
||||
fn start(_: isize, _: *const *const u8) -> isize {
|
||||
println!("Hello from start!");
|
||||
|
||||
0
|
||||
}
|
1
tests/run-pass/start.stdout
Normal file
1
tests/run-pass/start.stdout
Normal file
@ -0,0 +1 @@
|
||||
Hello from start!
|
Loading…
Reference in New Issue
Block a user