Skip to content

Commit 84b058a

Browse files
committed
add support for #[start]
1 parent 4f1fca7 commit 84b058a

File tree

6 files changed

+79
-35
lines changed

6 files changed

+79
-35
lines changed

benches/helpers/miri_helper.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,12 @@ impl rustc_driver::Callbacks for MiriCompilerCalls<'_> {
2020
compiler.session().abort_if_errors();
2121

2222
queries.global_ctxt().unwrap().peek_mut().enter(|tcx| {
23-
let (entry_def_id, _) = tcx.entry_fn(()).expect("no main or start function found");
23+
let (entry_def_id, entry_type) =
24+
tcx.entry_fn(()).expect("no main or start function found");
2425

2526
self.bencher.iter(|| {
2627
let config = miri::MiriConfig::default();
27-
miri::eval_main(tcx, entry_def_id, config);
28+
miri::eval_entry(tcx, entry_def_id, entry_type, config);
2829
});
2930
});
3031

src/bin/miri.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -58,8 +58,8 @@ impl rustc_driver::Callbacks for MiriCompilerCalls {
5858

5959
queries.global_ctxt().unwrap().peek_mut().enter(|tcx| {
6060
init_late_loggers(tcx);
61-
let (entry_def_id, _) = if let Some((entry_def, x)) = tcx.entry_fn(()) {
62-
(entry_def, x)
61+
let (entry_def_id, entry_type) = if let Some(entry_def) = tcx.entry_fn(()) {
62+
entry_def
6363
} else {
6464
let output_ty = ErrorOutputType::HumanReadable(HumanReadableErrorType::Default(
6565
ColorConfig::Auto,
@@ -79,7 +79,7 @@ impl rustc_driver::Callbacks for MiriCompilerCalls {
7979
env::set_current_dir(cwd).unwrap();
8080
}
8181

82-
if let Some(return_code) = miri::eval_main(tcx, entry_def_id, config) {
82+
if let Some(return_code) = miri::eval_entry(tcx, entry_def_id, entry_type, config) {
8383
std::process::exit(
8484
i32::try_from(return_code).expect("Return value was too large!"),
8585
);

src/eval.rs

Lines changed: 63 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ use rustc_middle::ty::{self, layout::LayoutCx, TyCtxt};
1010
use rustc_target::abi::LayoutOf;
1111
use rustc_target::spec::abi::Abi;
1212

13+
use rustc_session::config::EntryFnType;
14+
1315
use crate::*;
1416

1517
#[derive(Copy, Clone, Debug, PartialEq)]
@@ -117,12 +119,13 @@ impl Default for MiriConfig {
117119
}
118120

119121
/// Returns a freshly created `InterpCx`, along with an `MPlaceTy` representing
120-
/// the location where the return value of the `start` lang item will be
122+
/// the location where the return value of the `start` function will be
121123
/// written to.
122124
/// Public because this is also used by `priroda`.
123125
pub fn create_ecx<'mir, 'tcx: 'mir>(
124126
tcx: TyCtxt<'tcx>,
125-
main_id: DefId,
127+
entry_id: DefId,
128+
entry_type: EntryFnType,
126129
config: MiriConfig,
127130
) -> InterpResult<'tcx, (InterpCx<'mir, 'tcx, Evaluator<'mir, 'tcx>>, MPlaceTy<'tcx, Tag>)> {
128131
let param_env = ty::ParamEnv::reveal_all();
@@ -145,26 +148,14 @@ pub fn create_ecx<'mir, 'tcx: 'mir>(
145148
}
146149

147150
// Setup first stack-frame
148-
let main_instance = ty::Instance::mono(tcx, main_id);
149-
let main_mir = ecx.load_mir(main_instance.def, None)?;
151+
let entry_instance = ty::Instance::mono(tcx, entry_id);
152+
/*let entry_mir = ecx.load_mir(entry_instance.def, None)?;
150153
if main_mir.arg_count != 0 {
151154
bug!("main function must not take any arguments");
152-
}
155+
}*/
156+
157+
// First argument is constructed later, because its skipped if the entry function uses #[start]
153158

154-
let start_id = tcx.lang_items().start_fn().unwrap();
155-
let main_ret_ty = tcx.fn_sig(main_id).output();
156-
let main_ret_ty = main_ret_ty.no_bound_vars().unwrap();
157-
let start_instance = ty::Instance::resolve(
158-
tcx,
159-
ty::ParamEnv::reveal_all(),
160-
start_id,
161-
tcx.mk_substs(::std::iter::once(ty::subst::GenericArg::from(main_ret_ty))),
162-
)
163-
.unwrap()
164-
.unwrap();
165-
166-
// First argument: pointer to `main()`.
167-
let main_ptr = ecx.memory.create_fn_alloc(FnVal::Instance(main_instance));
168159
// Second argument (argc): length of `config.args`.
169160
let argc = Scalar::from_machine_usize(u64::try_from(config.args.len()).unwrap(), &ecx);
170161
// Third argument (`argv`): created from `config.args`.
@@ -237,28 +228,71 @@ pub fn create_ecx<'mir, 'tcx: 'mir>(
237228
argv
238229
};
239230

231+
/*let args: &[_] = match entry_type {
232+
EntryFnType::Main => {
233+
// First argument: pointer to `main()`.
234+
let main_ptr = ecx.memory.create_fn_alloc(FnVal::Instance(main_instance));
235+
236+
&[Scalar::from_pointer(main_ptr, &ecx).into(), argc.into(), argv]
237+
}
238+
EntryFnType::Start => &[argc.into(), argv],
239+
};*/
240+
240241
// Return place (in static memory so that it does not count as leak).
241242
let ret_place = ecx.allocate(ecx.machine.layouts.isize, MiriMemoryKind::Machine.into())?;
242243
// Call start function.
243-
ecx.call_function(
244-
start_instance,
245-
Abi::Rust,
246-
&[Scalar::from_pointer(main_ptr, &ecx).into(), argc.into(), argv],
247-
Some(&ret_place.into()),
248-
StackPopCleanup::None { cleanup: true },
249-
)?;
244+
245+
match entry_type {
246+
EntryFnType::Main => {
247+
let start_id = tcx.lang_items().start_fn().unwrap();
248+
let main_ret_ty = tcx.fn_sig(entry_id).output();
249+
let main_ret_ty = main_ret_ty.no_bound_vars().unwrap();
250+
let start_instance = ty::Instance::resolve(
251+
tcx,
252+
ty::ParamEnv::reveal_all(),
253+
start_id,
254+
tcx.mk_substs(::std::iter::once(ty::subst::GenericArg::from(main_ret_ty))),
255+
)
256+
.unwrap()
257+
.unwrap();
258+
259+
let main_ptr = ecx.memory.create_fn_alloc(FnVal::Instance(entry_instance));
260+
261+
ecx.call_function(
262+
start_instance,
263+
Abi::Rust,
264+
&[Scalar::from_pointer(main_ptr, &ecx).into(), argc.into(), argv],
265+
Some(&ret_place.into()),
266+
StackPopCleanup::None { cleanup: true },
267+
)?;
268+
}
269+
EntryFnType::Start => {
270+
ecx.call_function(
271+
entry_instance,
272+
Abi::Rust,
273+
&[argc.into(), argv],
274+
Some(&ret_place.into()),
275+
StackPopCleanup::None { cleanup: true },
276+
)?;
277+
}
278+
}
250279

251280
Ok((ecx, ret_place))
252281
}
253282

254-
/// Evaluates the main function specified by `main_id`.
283+
/// Evaluates the entry function specified by `entry_id`.
255284
/// Returns `Some(return_code)` if program executed completed.
256285
/// Returns `None` if an evaluation error occured.
257-
pub fn eval_main<'tcx>(tcx: TyCtxt<'tcx>, main_id: DefId, config: MiriConfig) -> Option<i64> {
286+
pub fn eval_entry<'tcx>(
287+
tcx: TyCtxt<'tcx>,
288+
entry_id: DefId,
289+
entry_type: EntryFnType,
290+
config: MiriConfig,
291+
) -> Option<i64> {
258292
// Copy setting before we move `config`.
259293
let ignore_leaks = config.ignore_leaks;
260294

261-
let (mut ecx, ret_place) = match create_ecx(tcx, main_id, config) {
295+
let (mut ecx, ret_place) = match create_ecx(tcx, entry_id, entry_type, config) {
262296
Ok(v) => v,
263297
Err(err) => {
264298
err.print_backtrace();

src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ pub use crate::diagnostics::{
6060
NonHaltingDiagnostic, TerminationInfo,
6161
};
6262
pub use crate::eval::{
63-
create_ecx, eval_main, AlignmentCheck, IsolatedOp, MiriConfig, RejectOpWith,
63+
create_ecx, eval_entry, AlignmentCheck, IsolatedOp, MiriConfig, RejectOpWith,
6464
};
6565
pub use crate::helpers::EvalContextExt as HelpersEvalContextExt;
6666
pub use crate::machine::{

tests/run-pass/start.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
#![feature(start)]
2+
3+
#[start]
4+
fn start(_: isize, _: *const *const u8) -> isize {
5+
println!("Hello from start!");
6+
7+
0
8+
}

tests/run-pass/start.stdout

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Hello from start!

0 commit comments

Comments
 (0)