Skip to content

Commit f4b69f3

Browse files
committed
Auto merge of #134299 - RalfJung:remove-start, r=compiler-errors
remove support for the (unstable) #[start] attribute As explained by `@Noratrieb:` `#[start]` should be deleted. It's nothing but an accidentally leaked implementation detail that's a not very useful mix between "portable" entrypoint logic and bad abstraction. I think the way the stable user-facing entrypoint should work (and works today on stable) is pretty simple: - `std`-using cross-platform programs should use `fn main()`. the compiler, together with `std`, will then ensure that code ends up at `main` (by having a platform-specific entrypoint that gets directed through `lang_start` in `std` to `main` - but that's just an implementation detail) - `no_std` platform-specific programs should use `#![no_main]` and define their own platform-specific entrypoint symbol with `#[no_mangle]`, like `main`, `_start`, `WinMain` or `my_embedded_platform_wants_to_start_here`. most of them only support a single platform anyways, and need cfg for the different platform's ways of passing arguments or other things *anyways* `#[start]` is in a super weird position of being neither of those two. It tries to pretend that it's cross-platform, but its signature is a total lie. Those arguments are just stubbed out to zero on ~~Windows~~ wasm, for example. It also only handles the platform-specific entrypoints for a few platforms that are supported by `std`, like Windows or Unix-likes. `my_embedded_platform_wants_to_start_here` can't use it, and neither could a libc-less Linux program. So we have an attribute that only works in some cases anyways, that has a signature that's a total lie (and a signature that, as I might want to add, has changed recently, and that I definitely would not be comfortable giving *any* stability guarantees on), and where there's a pretty easy way to get things working without it in the first place. Note that this feature has **not** been RFCed in the first place. *This comment was posted [in May](rust-lang/rust#29633 (comment)) and so far nobody spoke up in that issue with a usecase that would require keeping the attribute.* Closes rust-lang/rust#29633 try-job: x86_64-gnu-nopt try-job: x86_64-msvc-1 try-job: x86_64-msvc-2 try-job: test-various
2 parents dfb8d32 + 36bd681 commit f4b69f3

21 files changed

+53
-76
lines changed

Diff for: src/bin/miri.rs

+6-6
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ use std::sync::atomic::{AtomicI32, Ordering};
3333
use std::sync::{Arc, Once};
3434

3535
use miri::{
36-
BacktraceStyle, BorrowTrackerMethod, MiriConfig, ProvenanceMode, RetagFields, ValidationMode,
36+
BacktraceStyle, BorrowTrackerMethod, MiriConfig, MiriEntryFnType,ProvenanceMode, RetagFields, ValidationMode,
3737
};
3838
use rustc_abi::ExternAbi;
3939
use rustc_data_structures::sync;
@@ -51,7 +51,7 @@ use rustc_middle::query::LocalCrate;
5151
use rustc_middle::traits::{ObligationCause, ObligationCauseCode};
5252
use rustc_middle::ty::{self, Ty, TyCtxt};
5353
use rustc_middle::util::Providers;
54-
use rustc_session::config::{CrateType, EntryFnType, ErrorOutputType, OptLevel};
54+
use rustc_session::config::{CrateType, ErrorOutputType, OptLevel};
5555
use rustc_session::search_paths::PathKind;
5656
use rustc_session::{CtfeBacktrace, EarlyDiagCtxt};
5757
use rustc_span::def_id::DefId;
@@ -73,9 +73,9 @@ impl MiriCompilerCalls {
7373
}
7474
}
7575

76-
fn entry_fn(tcx: TyCtxt<'_>) -> (DefId, EntryFnType) {
77-
if let Some(entry_def) = tcx.entry_fn(()) {
78-
return entry_def;
76+
fn entry_fn(tcx: TyCtxt<'_>) -> (DefId, MiriEntryFnType) {
77+
if let Some((def_id, entry_type)) = tcx.entry_fn(()) {
78+
return (def_id, MiriEntryFnType::Rustc(entry_type));
7979
}
8080
// Look for a symbol in the local crate named `miri_start`, and treat that as the entry point.
8181
let sym = tcx.exported_symbols(LOCAL_CRATE).iter().find_map(|(sym, _)| {
@@ -102,7 +102,7 @@ fn entry_fn(tcx: TyCtxt<'_>) -> (DefId, EntryFnType) {
102102
.is_ok();
103103

104104
if correct_func_sig {
105-
(*id, EntryFnType::Start)
105+
(*id, MiriEntryFnType::MiriStart)
106106
} else {
107107
tcx.dcx().fatal(
108108
"`miri_start` must have the following signature:\n\

Diff for: src/eval.rs

+12-8
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,12 @@ use crate::diagnostics::report_leaks;
1919
use crate::shims::tls;
2020
use crate::*;
2121

22+
#[derive(Copy, Clone, Debug)]
23+
pub enum MiriEntryFnType {
24+
MiriStart,
25+
Rustc(EntryFnType),
26+
}
27+
2228
/// When the main thread would exit, we will yield to any other thread that is ready to execute.
2329
/// But we must only do that a finite number of times, or a background thread running `loop {}`
2430
/// will hang the program.
@@ -272,7 +278,7 @@ impl<'tcx> MainThreadState<'tcx> {
272278
pub fn create_ecx<'tcx>(
273279
tcx: TyCtxt<'tcx>,
274280
entry_id: DefId,
275-
entry_type: EntryFnType,
281+
entry_type: MiriEntryFnType,
276282
config: &MiriConfig,
277283
) -> InterpResult<'tcx, InterpCx<'tcx, MiriMachine<'tcx>>> {
278284
let typing_env = ty::TypingEnv::fully_monomorphized();
@@ -300,7 +306,7 @@ pub fn create_ecx<'tcx>(
300306
// Setup first stack frame.
301307
let entry_instance = ty::Instance::mono(tcx, entry_id);
302308

303-
// First argument is constructed later, because it's skipped if the entry function uses #[start].
309+
// First argument is constructed later, because it's skipped for `miri_start.`
304310

305311
// Second argument (argc): length of `config.args`.
306312
let argc =
@@ -373,11 +379,9 @@ pub fn create_ecx<'tcx>(
373379
// Call start function.
374380

375381
match entry_type {
376-
EntryFnType::Main { .. } => {
382+
MiriEntryFnType::Rustc(EntryFnType::Main { .. }) => {
377383
let start_id = tcx.lang_items().start_fn().unwrap_or_else(|| {
378-
tcx.dcx().fatal(
379-
"could not find start function. Make sure the entry point is marked with `#[start]`."
380-
);
384+
tcx.dcx().fatal("could not find start lang item");
381385
});
382386
let main_ret_ty = tcx.fn_sig(entry_id).no_bound_vars().unwrap().output();
383387
let main_ret_ty = main_ret_ty.no_bound_vars().unwrap();
@@ -413,7 +417,7 @@ pub fn create_ecx<'tcx>(
413417
StackPopCleanup::Root { cleanup: true },
414418
)?;
415419
}
416-
EntryFnType::Start => {
420+
MiriEntryFnType::MiriStart => {
417421
ecx.call_function(
418422
entry_instance,
419423
ExternAbi::Rust,
@@ -434,7 +438,7 @@ pub fn create_ecx<'tcx>(
434438
pub fn eval_entry<'tcx>(
435439
tcx: TyCtxt<'tcx>,
436440
entry_id: DefId,
437-
entry_type: EntryFnType,
441+
entry_type: MiriEntryFnType,
438442
config: MiriConfig,
439443
) -> Option<i32> {
440444
// Copy setting before we move `config`.

Diff for: src/lib.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -135,8 +135,8 @@ pub use crate::diagnostics::{
135135
EvalContextExt as _, NonHaltingDiagnostic, TerminationInfo, report_error,
136136
};
137137
pub use crate::eval::{
138-
AlignmentCheck, BacktraceStyle, IsolatedOp, MiriConfig, RejectOpWith, ValidationMode,
139-
create_ecx, eval_entry,
138+
AlignmentCheck, BacktraceStyle, IsolatedOp, MiriConfig, MiriEntryFnType, RejectOpWith,
139+
ValidationMode, create_ecx, eval_entry,
140140
};
141141
pub use crate::helpers::{AccessKind, EvalContextExt as _};
142142
pub use crate::intrinsics::EvalContextExt as _;

Diff for: test-cargo-miri/no-std-smoke/src/main.rs

+2-3
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
// Copied from tests/pass/no-std.rs
22

3-
#![feature(start)]
43
#![no_std]
54

65
// Plumbing to let us use `writeln!` to host stdout:
@@ -22,8 +21,8 @@ impl Write for Host {
2221
}
2322
}
2423

25-
#[start]
26-
fn start(_: isize, _: *const *const u8) -> isize {
24+
#[no_mangle]
25+
fn miri_start(_: isize, _: *const *const u8) -> isize {
2726
writeln!(Host, "hello, world!").unwrap();
2827
0
2928
}

Diff for: tests/fail/alloc/alloc_error_handler_custom.rs

+4-3
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
//@compile-flags: -Cpanic=abort
2-
#![feature(start, core_intrinsics)]
2+
#![feature(core_intrinsics)]
33
#![feature(alloc_error_handler)]
44
#![feature(allocator_api)]
55
#![no_std]
6+
#![no_main]
67

78
extern crate alloc;
89

@@ -43,7 +44,7 @@ mod plumbing {
4344
static GLOBAL: NoAlloc = NoAlloc;
4445
}
4546

46-
#[start]
47-
fn start(_: isize, _: *const *const u8) -> isize {
47+
#[no_mangle]
48+
fn miri_start(_argc: isize, _argv: *const *const u8) -> isize {
4849
handle_alloc_error(Layout::for_value(&0));
4950
}

Diff for: tests/fail/alloc/alloc_error_handler_custom.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ LL | fn alloc_error_handler(layout: Layout) -> ! {
1616
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
1717
= note: inside `alloc::alloc::handle_alloc_error::rt_error` at RUSTLIB/alloc/src/alloc.rs:LL:CC
1818
= note: inside `alloc::alloc::handle_alloc_error` at RUSTLIB/alloc/src/alloc.rs:LL:CC
19-
note: inside `start`
19+
note: inside `miri_start`
2020
--> tests/fail/alloc/alloc_error_handler_custom.rs:LL:CC
2121
|
2222
LL | handle_alloc_error(Layout::for_value(&0));

Diff for: tests/fail/alloc/alloc_error_handler_no_std.rs

+4-3
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
//@compile-flags: -Cpanic=abort
2-
#![feature(start, core_intrinsics)]
2+
#![feature(core_intrinsics)]
33
#![feature(alloc_error_handler)]
44
#![feature(allocator_api)]
55
#![no_std]
6+
#![no_main]
67

78
extern crate alloc;
89

@@ -41,7 +42,7 @@ mod plumbing {
4142
static GLOBAL: NoAlloc = NoAlloc;
4243
}
4344

44-
#[start]
45-
fn start(_: isize, _: *const *const u8) -> isize {
45+
#[no_mangle]
46+
fn miri_start(_argc: isize, _argv: *const *const u8) -> isize {
4647
handle_alloc_error(Layout::for_value(&0));
4748
}

Diff for: tests/fail/alloc/alloc_error_handler_no_std.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ LL | core::intrinsics::abort();
1212
= note: inside `alloc::alloc::__alloc_error_handler::__rdl_oom` at RUSTLIB/alloc/src/alloc.rs:LL:CC
1313
= note: inside `alloc::alloc::handle_alloc_error::rt_error` at RUSTLIB/alloc/src/alloc.rs:LL:CC
1414
= note: inside `alloc::alloc::handle_alloc_error` at RUSTLIB/alloc/src/alloc.rs:LL:CC
15-
note: inside `start`
15+
note: inside `miri_start`
1616
--> tests/fail/alloc/alloc_error_handler_no_std.rs:LL:CC
1717
|
1818
LL | handle_alloc_error(Layout::for_value(&0));

Diff for: tests/fail/alloc/no_global_allocator.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,15 @@
22
//@normalize-stderr-test: "OS `.*`" -> "$$OS"
33
// Make sure we pretend the allocation symbols don't exist when there is no allocator
44

5-
#![feature(start)]
65
#![no_std]
6+
#![no_main]
77

88
extern "Rust" {
99
fn __rust_alloc(size: usize, align: usize) -> *mut u8;
1010
}
1111

12-
#[start]
13-
fn start(_: isize, _: *const *const u8) -> isize {
12+
#[no_mangle]
13+
fn miri_start(_argc: isize, _argv: *const *const u8) -> isize {
1414
unsafe {
1515
__rust_alloc(1, 1); //~ERROR: unsupported operation: can't call foreign function `__rust_alloc`
1616
}

Diff for: tests/fail/alloc/no_global_allocator.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ LL | __rust_alloc(1, 1);
77
= help: if this is a basic API commonly used on this target, please report an issue with Miri
88
= help: however, note that Miri does not aim to support every FFI function out there; for instance, we will not support APIs for things such as GUIs, scripting languages, or databases
99
= note: BACKTRACE:
10-
= note: inside `start` at tests/fail/alloc/no_global_allocator.rs:LL:CC
10+
= note: inside `miri_start` at tests/fail/alloc/no_global_allocator.rs:LL:CC
1111

1212
error: aborting due to 1 previous error
1313

Diff for: tests/fail/panic/no_std.rs

+4-3
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,15 @@
11
//@compile-flags: -Cpanic=abort
2-
#![feature(start, core_intrinsics)]
2+
#![feature(core_intrinsics)]
33
#![no_std]
4+
#![no_main]
45

56
use core::fmt::Write;
67

78
#[path = "../../utils/mod.no_std.rs"]
89
mod utils;
910

10-
#[start]
11-
fn start(_: isize, _: *const *const u8) -> isize {
11+
#[no_mangle]
12+
fn miri_start(_argc: isize, _argv: *const *const u8) -> isize {
1213
panic!("blarg I am dead")
1314
}
1415

Diff for: tests/fail/panic/no_std.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ LL | core::intrinsics::abort();
88
|
99
= note: BACKTRACE:
1010
= note: inside `panic_handler` at tests/fail/panic/no_std.rs:LL:CC
11-
note: inside `start`
11+
note: inside `miri_start`
1212
--> tests/fail/panic/no_std.rs:LL:CC
1313
|
1414
LL | panic!("blarg I am dead")

Diff for: tests/pass/alloc-access-tracking.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
#![feature(start)]
21
#![no_std]
2+
#![no_main]
33
//@compile-flags: -Zmiri-track-alloc-id=21 -Zmiri-track-alloc-accesses -Cpanic=abort
44
//@normalize-stderr-test: "id 21" -> "id $$ALLOC"
55
//@only-target: linux # alloc IDs differ between OSes (due to extern static allocations)
@@ -9,8 +9,8 @@ extern "Rust" {
99
fn miri_dealloc(ptr: *mut u8, size: usize, align: usize);
1010
}
1111

12-
#[start]
13-
fn start(_: isize, _: *const *const u8) -> isize {
12+
#[no_mangle]
13+
fn miri_start(_argc: isize, _argv: *const *const u8) -> isize {
1414
unsafe {
1515
let ptr = miri_alloc(123, 1);
1616
*ptr = 42; // Crucially, only a write is printed here, no read!

Diff for: tests/pass/alloc-access-tracking.stderr

+4-4
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ LL | let ptr = miri_alloc(123, 1);
55
| ^^^^^^^^^^^^^^^^^^ created Miri bare-metal heap allocation of 123 bytes (alignment ALIGN bytes) with id $ALLOC
66
|
77
= note: BACKTRACE:
8-
= note: inside `start` at tests/pass/alloc-access-tracking.rs:LL:CC
8+
= note: inside `miri_start` at tests/pass/alloc-access-tracking.rs:LL:CC
99

1010
note: tracking was triggered
1111
--> tests/pass/alloc-access-tracking.rs:LL:CC
@@ -14,7 +14,7 @@ LL | *ptr = 42; // Crucially, only a write is printed here, no read!
1414
| ^^^^^^^^^ write access to allocation with id $ALLOC
1515
|
1616
= note: BACKTRACE:
17-
= note: inside `start` at tests/pass/alloc-access-tracking.rs:LL:CC
17+
= note: inside `miri_start` at tests/pass/alloc-access-tracking.rs:LL:CC
1818

1919
note: tracking was triggered
2020
--> tests/pass/alloc-access-tracking.rs:LL:CC
@@ -23,7 +23,7 @@ LL | assert_eq!(*ptr, 42);
2323
| ^^^^^^^^^^^^^^^^^^^^ read access to allocation with id $ALLOC
2424
|
2525
= note: BACKTRACE:
26-
= note: inside `start` at RUSTLIB/core/src/macros/mod.rs:LL:CC
26+
= note: inside `miri_start` at RUSTLIB/core/src/macros/mod.rs:LL:CC
2727
= note: this note originates in the macro `assert_eq` (in Nightly builds, run with -Z macro-backtrace for more info)
2828

2929
note: tracking was triggered
@@ -33,5 +33,5 @@ LL | miri_dealloc(ptr, 123, 1);
3333
| ^^^^^^^^^^^^^^^^^^^^^^^^^ freed allocation with id $ALLOC
3434
|
3535
= note: BACKTRACE:
36-
= note: inside `start` at tests/pass/alloc-access-tracking.rs:LL:CC
36+
= note: inside `miri_start` at tests/pass/alloc-access-tracking.rs:LL:CC
3737

Diff for: tests/pass/miri-alloc.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
#![feature(start)]
21
#![no_std]
2+
#![no_main]
33
//@compile-flags: -Cpanic=abort
44
// windows tls dtors go through libstd right now, thus this test
55
// cannot pass. When windows tls dtors go through the special magic
@@ -11,8 +11,8 @@ extern "Rust" {
1111
fn miri_dealloc(ptr: *mut u8, size: usize, align: usize);
1212
}
1313

14-
#[start]
15-
fn start(_: isize, _: *const *const u8) -> isize {
14+
#[no_mangle]
15+
fn miri_start(_argc: isize, _argv: *const *const u8) -> isize {
1616
unsafe {
1717
let ptr = miri_alloc(123, 1);
1818
core::ptr::write_bytes(ptr, 0u8, 123);

Diff for: tests/pass/miri_start.stdout

-1
This file was deleted.

Diff for: tests/pass/no_std.rs

-19
This file was deleted.

Diff for: tests/pass/miri_start.rs renamed to tests/pass/no_std_miri_start.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
//@compile-flags: -Cpanic=abort
2-
#![no_main]
32
#![no_std]
3+
#![no_main]
44

55
use core::fmt::Write;
66

@@ -9,7 +9,7 @@ mod utils;
99

1010
#[no_mangle]
1111
fn miri_start(_argc: isize, _argv: *const *const u8) -> isize {
12-
writeln!(utils::MiriStdout, "Hello from miri_start!").unwrap();
12+
writeln!(utils::MiriStdout, "hello, world!").unwrap();
1313
0
1414
}
1515

File renamed without changes.

Diff for: tests/pass/start.rs

-8
This file was deleted.

Diff for: tests/pass/start.stdout

-1
This file was deleted.

0 commit comments

Comments
 (0)