Skip to content

Commit

Permalink
Rollup merge of rust-lang#119325 - RalfJung:custom-mir, r=compiler-er…
Browse files Browse the repository at this point in the history
…rors

custom mir: make it clear what the return block is

Custom MIR recently got support for specifying the "unwind action", so now there's two things coming after the actual call part of `Call` terminators. That's not very self-explaining so I propose we change the syntax to imitate keyword arguments:
```
Call(popped = Vec::pop(v), ReturnTo(drop), UnwindContinue())
```

Also fix some outdated docs and add some docs to `Call` and `Drop`.
  • Loading branch information
matthiaskrgr committed Jan 3, 2024
2 parents 7aaa1eb + 4bf2794 commit 2d62db7
Show file tree
Hide file tree
Showing 36 changed files with 120 additions and 78 deletions.
12 changes: 10 additions & 2 deletions compiler/rustc_mir_build/src/build/custom/parse/instruction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ impl<'tcx, 'body> ParseCtxt<'tcx, 'body> {
@call(mir_drop, args) => {
Ok(TerminatorKind::Drop {
place: self.parse_place(args[0])?,
target: self.parse_block(args[1])?,
target: self.parse_return_to(args[1])?,
unwind: self.parse_unwind_action(args[2])?,
replace: false,
})
Expand Down Expand Up @@ -104,6 +104,14 @@ impl<'tcx, 'body> ParseCtxt<'tcx, 'body> {
)
}

fn parse_return_to(&self, expr_id: ExprId) -> PResult<BasicBlock> {
parse_by_kind!(self, expr_id, _, "return block",
@call(mir_return_to, args) => {
self.parse_block(args[0])
},
)
}

fn parse_match(&self, arms: &[ArmId], span: Span) -> PResult<SwitchTargets> {
let Some((otherwise, rest)) = arms.split_last() else {
return Err(ParseError {
Expand Down Expand Up @@ -146,7 +154,7 @@ impl<'tcx, 'body> ParseCtxt<'tcx, 'body> {
ExprKind::Assign { lhs, rhs } => (*lhs, *rhs),
);
let destination = self.parse_place(destination)?;
let target = self.parse_block(args[1])?;
let target = self.parse_return_to(args[1])?;
let unwind = self.parse_unwind_action(args[2])?;

parse_by_kind!(self, call, _, "function call",
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_span/src/symbol.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1041,6 +1041,7 @@ symbols! {
mir_offset,
mir_retag,
mir_return,
mir_return_to,
mir_set_discriminant,
mir_static,
mir_static_mut,
Expand Down
57 changes: 45 additions & 12 deletions library/core/src/intrinsics/mir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -104,21 +104,22 @@
//! }
//!
//! #[custom_mir(dialect = "runtime", phase = "optimized")]
#![cfg_attr(bootstrap, doc = "#[cfg(any())]")] // disable the following function in doctests when `bootstrap` is set
//! fn push_and_pop<T>(v: &mut Vec<T>, value: T) {
//! mir!(
//! let _unused;
//! let popped;
//!
//! {
//! Call(_unused = Vec::push(v, value), pop, UnwindContinue())
//! Call(_unused = Vec::push(v, value), ReturnTo(pop), UnwindContinue())
//! }
//!
//! pop = {
//! Call(popped = Vec::pop(v), drop, UnwindContinue())
//! Call(popped = Vec::pop(v), ReturnTo(drop), UnwindContinue())
//! }
//!
//! drop = {
//! Drop(popped, ret, UnwindContinue())
//! Drop(popped, ReturnTo(ret), UnwindContinue())
//! }
//!
//! ret = {
Expand Down Expand Up @@ -242,9 +243,8 @@
//! - `match some_int_operand` becomes a `SwitchInt`. Each arm should be `literal => basic_block`
//! - The exception is the last arm, which must be `_ => basic_block` and corresponds to the
//! otherwise branch.
//! - [`Call`] has an associated function as well. The third argument of this function is a normal
//! function call expression, for example `my_other_function(a, 5)`.
//!
//! - [`Call`] has an associated function as well, with special syntax:
//! `Call(ret_val = function(arg1, arg2, ...), ReturnTo(next_block), UnwindContinue())`.

#![unstable(
feature = "custom_mir",
Expand Down Expand Up @@ -287,35 +287,68 @@ macro_rules! define {
}

// Unwind actions
pub struct UnwindActionArg;
define!(
"mir_unwind_continue",
/// An unwind action that continues unwinding.
fn UnwindContinue()
fn UnwindContinue() -> UnwindActionArg
);
define!(
"mir_unwind_unreachable",
/// An unwind action that triggers undefined behaviour.
fn UnwindUnreachable() -> BasicBlock
fn UnwindUnreachable() -> UnwindActionArg
);
define!(
"mir_unwind_terminate",
/// An unwind action that terminates the execution.
///
/// `UnwindTerminate` can also be used as a terminator.
fn UnwindTerminate(reason: UnwindTerminateReason)
fn UnwindTerminate(reason: UnwindTerminateReason) -> UnwindActionArg
);
define!(
"mir_unwind_cleanup",
/// An unwind action that continues execution in a given basic blok.
fn UnwindCleanup(goto: BasicBlock)
fn UnwindCleanup(goto: BasicBlock) -> UnwindActionArg
);

// Return destination for `Call`
pub struct ReturnToArg;
define!("mir_return_to", fn ReturnTo(goto: BasicBlock) -> ReturnToArg);

// Terminators
define!("mir_return", fn Return() -> BasicBlock);
define!("mir_goto", fn Goto(destination: BasicBlock) -> BasicBlock);
define!("mir_unreachable", fn Unreachable() -> BasicBlock);
define!("mir_drop", fn Drop<T, U>(place: T, goto: BasicBlock, unwind_action: U));
define!("mir_call", fn Call<U>(call: (), goto: BasicBlock, unwind_action: U));
define!("mir_drop",
/// Drop the contents of a place.
///
/// The first argument must be a place.
///
/// The second argument must be of the form `ReturnTo(bb)`, where `bb` is the basic block that
/// will be jumped to after the destructor returns.
///
/// The third argument describes what happens on unwind. It can be one of:
/// - [`UnwindContinue`]
/// - [`UnwindUnreachable`]
/// - [`UnwindTerminate`]
/// - [`UnwindCleanup`]
fn Drop<T>(place: T, goto: ReturnToArg, unwind_action: UnwindActionArg)
);
define!("mir_call",
/// Call a function.
///
/// The first argument must be of the form `ret_val = fun(arg1, arg2, ...)`.
///
/// The second argument must be of the form `ReturnTo(bb)`, where `bb` is the basic block that
/// will be jumped to after the function returns.
///
/// The third argument describes what happens on unwind. It can be one of:
/// - [`UnwindContinue`]
/// - [`UnwindUnreachable`]
/// - [`UnwindTerminate`]
/// - [`UnwindCleanup`]
fn Call(call: (), goto: ReturnToArg, unwind_action: UnwindActionArg)
);
define!("mir_unwind_resume",
/// A terminator that resumes the unwinding.
fn UnwindResume()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ fn main() {
let ptr = std::ptr::addr_of_mut!(non_copy);
// Inside `callee`, the first argument and `*ptr` are basically
// aliasing places!
Call(_unit = callee(Move(*ptr), ptr), after_call, UnwindContinue())
Call(_unit = callee(Move(*ptr), ptr), ReturnTo(after_call), UnwindContinue())
}
after_call = {
Return()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,8 @@ LL | unsafe { ptr.write(S(0)) };
note: inside `main`
--> $DIR/arg_inplace_mutate.rs:LL:CC
|
LL | Call(_unit = callee(Move(*ptr), ptr), after_call, UnwindContinue())
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
LL | Call(_unit = callee(Move(*ptr), ptr), ReturnTo(after_call), UnwindContinue())
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: this error originates in the macro `::core::intrinsics::mir::__internal_remove_let` which comes from the expansion of the macro `mir` (in Nightly builds, run with -Z macro-backtrace for more info)

note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,8 @@ LL | unsafe { ptr.write(S(0)) };
note: inside `main`
--> $DIR/arg_inplace_mutate.rs:LL:CC
|
LL | Call(_unit = callee(Move(*ptr), ptr), after_call, UnwindContinue())
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
LL | Call(_unit = callee(Move(*ptr), ptr), ReturnTo(after_call), UnwindContinue())
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: this error originates in the macro `::core::intrinsics::mir::__internal_remove_let` which comes from the expansion of the macro `mir` (in Nightly builds, run with -Z macro-backtrace for more info)

note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ fn main() {
{
let non_copy = S(42);
// This could change `non_copy` in-place
Call(_unit = change_arg(Move(non_copy)), after_call, UnwindContinue())
Call(_unit = change_arg(Move(non_copy)), ReturnTo(after_call), UnwindContinue())
}
after_call = {
// So now we must not be allowed to observe non-copy again.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ LL | unsafe { ptr.read() };
note: inside `main`
--> $DIR/arg_inplace_observe_during.rs:LL:CC
|
LL | Call(_unit = change_arg(Move(*ptr), ptr), after_call, UnwindContinue())
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
LL | Call(_unit = change_arg(Move(*ptr), ptr), ReturnTo(after_call), UnwindContinue())
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ fn main() {
let non_copy = S(42);
let ptr = std::ptr::addr_of_mut!(non_copy);
// This could change `non_copy` in-place
Call(_unit = change_arg(Move(*ptr), ptr), after_call, UnwindContinue())
Call(_unit = change_arg(Move(*ptr), ptr), ReturnTo(after_call), UnwindContinue())
}
after_call = {
Return()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,8 @@ LL | x.0 = 0;
note: inside `main`
--> $DIR/arg_inplace_observe_during.rs:LL:CC
|
LL | Call(_unit = change_arg(Move(*ptr), ptr), after_call, UnwindContinue())
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
LL | Call(_unit = change_arg(Move(*ptr), ptr), ReturnTo(after_call), UnwindContinue())
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: this error originates in the macro `::core::intrinsics::mir::__internal_remove_let` which comes from the expansion of the macro `mir` (in Nightly builds, run with -Z macro-backtrace for more info)

note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,8 @@ LL | x.0 = 0;
note: inside `main`
--> $DIR/arg_inplace_observe_during.rs:LL:CC
|
LL | Call(_unit = change_arg(Move(*ptr), ptr), after_call, UnwindContinue())
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
LL | Call(_unit = change_arg(Move(*ptr), ptr), ReturnTo(after_call), UnwindContinue())
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: this error originates in the macro `::core::intrinsics::mir::__internal_remove_let` which comes from the expansion of the macro `mir` (in Nightly builds, run with -Z macro-backtrace for more info)

note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ LL | unsafe { ptr.read() };
note: inside `main`
--> $DIR/return_pointer_aliasing.rs:LL:CC
|
LL | Call(*ptr = myfun(ptr), after_call, UnwindContinue())
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
LL | Call(*ptr = myfun(ptr), ReturnTo(after_call), UnwindContinue())
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ pub fn main() {
let ptr = &raw mut x;
// We arrange for `myfun` to have a pointer that aliases
// its return place. Even just reading from that pointer is UB.
Call(*ptr = myfun(ptr), after_call, UnwindContinue())
Call(*ptr = myfun(ptr), ReturnTo(after_call), UnwindContinue())
}

after_call = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,8 @@ LL | unsafe { ptr.read() };
note: inside `main`
--> $DIR/return_pointer_aliasing.rs:LL:CC
|
LL | Call(*ptr = myfun(ptr), after_call, UnwindContinue())
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
LL | Call(*ptr = myfun(ptr), ReturnTo(after_call), UnwindContinue())
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: this error originates in the macro `::core::intrinsics::mir::__internal_remove_let` which comes from the expansion of the macro `mir` (in Nightly builds, run with -Z macro-backtrace for more info)

note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,8 @@ LL | unsafe { ptr.read() };
note: inside `main`
--> $DIR/return_pointer_aliasing.rs:LL:CC
|
LL | Call(*ptr = myfun(ptr), after_call, UnwindContinue())
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
LL | Call(*ptr = myfun(ptr), ReturnTo(after_call), UnwindContinue())
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: this error originates in the macro `::core::intrinsics::mir::__internal_remove_let` which comes from the expansion of the macro `mir` (in Nightly builds, run with -Z macro-backtrace for more info)

note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ pub fn main() {
let ptr = &raw mut _x;
// We arrange for `myfun` to have a pointer that aliases
// its return place. Even just reading from that pointer is UB.
Call(_x = myfun(ptr), after_call, UnwindContinue())
Call(_x = myfun(ptr), ReturnTo(after_call), UnwindContinue())
}

after_call = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,8 @@ LL | unsafe { ptr.write(0) };
note: inside `main`
--> $DIR/return_pointer_aliasing2.rs:LL:CC
|
LL | Call(_x = myfun(ptr), after_call, UnwindContinue())
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
LL | Call(_x = myfun(ptr), ReturnTo(after_call), UnwindContinue())
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: this error originates in the macro `::core::intrinsics::mir::__internal_remove_let` which comes from the expansion of the macro `mir` (in Nightly builds, run with -Z macro-backtrace for more info)

note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,8 @@ LL | unsafe { ptr.write(0) };
note: inside `main`
--> $DIR/return_pointer_aliasing2.rs:LL:CC
|
LL | Call(_x = myfun(ptr), after_call, UnwindContinue())
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
LL | Call(_x = myfun(ptr), ReturnTo(after_call), UnwindContinue())
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: this error originates in the macro `::core::intrinsics::mir::__internal_remove_let` which comes from the expansion of the macro `mir` (in Nightly builds, run with -Z macro-backtrace for more info)

note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ struct S(i32, [u8; 128]);
fn docall(out: &mut S) {
mir! {
{
Call(*out = callee(), after_call, UnwindContinue())
Call(*out = callee(), ReturnTo(after_call), UnwindContinue())
}

after_call = {
Expand All @@ -37,7 +37,7 @@ fn callee() -> S {
// become visible to the outside. In codegen we can see them
// but Miri should detect this as UB!
RET.0 = 42;
Call(_unit = startpanic(), after_call, UnwindContinue())
Call(_unit = startpanic(), ReturnTo(after_call), UnwindContinue())
}

after_call = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ fn call(f: fn(NonZeroU32)) {
let tmp = ptr::addr_of!(c);
let ptr = tmp as *const NonZeroU32;
// The call site now is a NonZeroU32-to-u32 transmute.
Call(_res = f(*ptr), retblock, UnwindContinue()) //~ERROR: expected something greater or equal to 1
Call(_res = f(*ptr), ReturnTo(retblock), UnwindContinue()) //~ERROR: expected something greater or equal to 1
}
retblock = {
Return()
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
error: Undefined Behavior: constructing invalid value: encountered 0, but expected something greater or equal to 1
--> $DIR/cast_fn_ptr_invalid_caller_arg.rs:LL:CC
|
LL | Call(_res = f(*ptr), retblock, UnwindContinue())
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0, but expected something greater or equal to 1
LL | Call(_res = f(*ptr), ReturnTo(retblock), UnwindContinue())
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0, but expected something greater or equal to 1
|
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ pub fn main() {
{
let x = 0;
let ptr = &raw mut x;
Call(*ptr = myfun(), after_call, UnwindContinue())
Call(*ptr = myfun(), ReturnTo(after_call), UnwindContinue())
}

after_call = {
Expand Down
8 changes: 4 additions & 4 deletions tests/mir-opt/building/custom/terminators.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ fn ident<T>(t: T) -> T {
fn direct_call(x: i32) -> i32 {
mir!(
{
Call(RET = ident(x), retblock, UnwindContinue())
Call(RET = ident(x), ReturnTo(retblock), UnwindContinue())
}

retblock = {
Expand All @@ -27,7 +27,7 @@ fn direct_call(x: i32) -> i32 {
fn indirect_call(x: i32, f: fn(i32) -> i32) -> i32 {
mir!(
{
Call(RET = f(x), retblock, UnwindContinue())
Call(RET = f(x), ReturnTo(retblock), UnwindContinue())
}

retblock = {
Expand All @@ -49,7 +49,7 @@ impl<'a> Drop for WriteOnDrop<'a> {
fn drop_first<'a>(a: WriteOnDrop<'a>, b: WriteOnDrop<'a>) {
mir!(
{
Drop(a, retblock, UnwindContinue())
Drop(a, ReturnTo(retblock), UnwindContinue())
}

retblock = {
Expand All @@ -64,7 +64,7 @@ fn drop_first<'a>(a: WriteOnDrop<'a>, b: WriteOnDrop<'a>) {
fn drop_second<'a>(a: WriteOnDrop<'a>, b: WriteOnDrop<'a>) {
mir!(
{
Drop(b, retblock, UnwindContinue())
Drop(b, ReturnTo(retblock), UnwindContinue())
}

retblock = {
Expand Down

0 comments on commit 2d62db7

Please sign in to comment.