Skip to content

Commit 1cc822e

Browse files
committed
Auto merge of #1884 - DrMeepster:start, r=RalfJung
add support for `#[start]` This PR adds support for the `#[start]` attribute and fixes #1825. It also renames `eval_main` to `eval_entry` to reflect that it can evaluate any entry function.
2 parents b97c340 + 1ec28f7 commit 1cc822e

File tree

6 files changed

+66
-36
lines changed

6 files changed

+66
-36
lines changed

benches/helpers/miri_helper.rs

+3-2
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

+3-3
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

+50-30
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ use rustc_middle::ty::{
1313
};
1414
use rustc_target::spec::abi::Abi;
1515

16+
use rustc_session::config::EntryFnType;
17+
1618
use crate::*;
1719

1820
#[derive(Copy, Clone, Debug, PartialEq)]
@@ -120,12 +122,13 @@ impl Default for MiriConfig {
120122
}
121123

122124
/// Returns a freshly created `InterpCx`, along with an `MPlaceTy` representing
123-
/// the location where the return value of the `start` lang item will be
125+
/// the location where the return value of the `start` function will be
124126
/// written to.
125127
/// Public because this is also used by `priroda`.
126128
pub fn create_ecx<'mir, 'tcx: 'mir>(
127129
tcx: TyCtxt<'tcx>,
128-
main_id: DefId,
130+
entry_id: DefId,
131+
entry_type: EntryFnType,
129132
config: MiriConfig,
130133
) -> InterpResult<'tcx, (InterpCx<'mir, 'tcx, Evaluator<'mir, 'tcx>>, MPlaceTy<'tcx, Tag>)> {
131134
let param_env = ty::ParamEnv::reveal_all();
@@ -148,26 +151,10 @@ pub fn create_ecx<'mir, 'tcx: 'mir>(
148151
}
149152

150153
// Setup first stack-frame
151-
let main_instance = ty::Instance::mono(tcx, main_id);
152-
let main_mir = ecx.load_mir(main_instance.def, None)?;
153-
if main_mir.arg_count != 0 {
154-
bug!("main function must not take any arguments");
155-
}
154+
let entry_instance = ty::Instance::mono(tcx, entry_id);
156155

157-
let start_id = tcx.lang_items().start_fn().unwrap();
158-
let main_ret_ty = tcx.fn_sig(main_id).output();
159-
let main_ret_ty = main_ret_ty.no_bound_vars().unwrap();
160-
let start_instance = ty::Instance::resolve(
161-
tcx,
162-
ty::ParamEnv::reveal_all(),
163-
start_id,
164-
tcx.mk_substs(::std::iter::once(ty::subst::GenericArg::from(main_ret_ty))),
165-
)
166-
.unwrap()
167-
.unwrap();
156+
// First argument is constructed later, because its skipped if the entry function uses #[start]
168157

169-
// First argument: pointer to `main()`.
170-
let main_ptr = ecx.memory.create_fn_alloc(FnVal::Instance(main_instance));
171158
// Second argument (argc): length of `config.args`.
172159
let argc = Scalar::from_machine_usize(u64::try_from(config.args.len()).unwrap(), &ecx);
173160
// Third argument (`argv`): created from `config.args`.
@@ -243,25 +230,58 @@ pub fn create_ecx<'mir, 'tcx: 'mir>(
243230
// Return place (in static memory so that it does not count as leak).
244231
let ret_place = ecx.allocate(ecx.machine.layouts.isize, MiriMemoryKind::Machine.into())?;
245232
// Call start function.
246-
ecx.call_function(
247-
start_instance,
248-
Abi::Rust,
249-
&[Scalar::from_pointer(main_ptr, &ecx).into(), argc.into(), argv],
250-
Some(&ret_place.into()),
251-
StackPopCleanup::None { cleanup: true },
252-
)?;
233+
234+
match entry_type {
235+
EntryFnType::Main => {
236+
let start_id = tcx.lang_items().start_fn().unwrap();
237+
let main_ret_ty = tcx.fn_sig(entry_id).output();
238+
let main_ret_ty = main_ret_ty.no_bound_vars().unwrap();
239+
let start_instance = ty::Instance::resolve(
240+
tcx,
241+
ty::ParamEnv::reveal_all(),
242+
start_id,
243+
tcx.mk_substs(::std::iter::once(ty::subst::GenericArg::from(main_ret_ty))),
244+
)
245+
.unwrap()
246+
.unwrap();
247+
248+
let main_ptr = ecx.memory.create_fn_alloc(FnVal::Instance(entry_instance));
249+
250+
ecx.call_function(
251+
start_instance,
252+
Abi::Rust,
253+
&[Scalar::from_pointer(main_ptr, &ecx).into(), argc.into(), argv],
254+
Some(&ret_place.into()),
255+
StackPopCleanup::None { cleanup: true },
256+
)?;
257+
}
258+
EntryFnType::Start => {
259+
ecx.call_function(
260+
entry_instance,
261+
Abi::Rust,
262+
&[argc.into(), argv],
263+
Some(&ret_place.into()),
264+
StackPopCleanup::None { cleanup: true },
265+
)?;
266+
}
267+
}
253268

254269
Ok((ecx, ret_place))
255270
}
256271

257-
/// Evaluates the main function specified by `main_id`.
272+
/// Evaluates the entry function specified by `entry_id`.
258273
/// Returns `Some(return_code)` if program executed completed.
259274
/// Returns `None` if an evaluation error occured.
260-
pub fn eval_main<'tcx>(tcx: TyCtxt<'tcx>, main_id: DefId, config: MiriConfig) -> Option<i64> {
275+
pub fn eval_entry<'tcx>(
276+
tcx: TyCtxt<'tcx>,
277+
entry_id: DefId,
278+
entry_type: EntryFnType,
279+
config: MiriConfig,
280+
) -> Option<i64> {
261281
// Copy setting before we move `config`.
262282
let ignore_leaks = config.ignore_leaks;
263283

264-
let (mut ecx, ret_place) = match create_ecx(tcx, main_id, config) {
284+
let (mut ecx, ret_place) = match create_ecx(tcx, entry_id, entry_type, config) {
265285
Ok(v) => v,
266286
Err(err) => {
267287
err.print_backtrace();

src/lib.rs

+1-1
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

+8
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

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Hello from start!

0 commit comments

Comments
 (0)