2121//! #[custom_mir(dialect = "built")]
2222//! pub fn simple(x: i32) -> i32 {
2323//! mir!(
24- //! let temp1: i32;
25- //! let temp2: _;
24+ //! let temp2: i32;
2625//!
2726//! {
28- //! temp1 = x;
29- //! Goto(exit )
27+ //! let temp1 = x;
28+ //! Goto(my_second_block )
3029//! }
3130//!
32- //! exit = {
31+ //! my_second_block = {
3332//! temp2 = Move(temp1);
3433//! RET = temp2;
3534//! Return()
3837//! }
3938//! ```
4039//!
41- //! Hopefully most of this is fairly self-explanatory. Expanding on some notable details:
40+ //! The `custom_mir` attribute tells the compiler to treat the function as being custom MIR. This
41+ //! attribute only works on functions - there is no way to insert custom MIR into the middle of
42+ //! another function. The `dialect` and `phase` parameters indicate which [version of MIR][dialect
43+ //! docs] you are inserting here. Generally you'll want to use `#![custom_mir(dialect = "built")]`
44+ //! if you want your MIR to be modified by the full MIR pipeline, or `#![custom_mir(dialect =
45+ //! "runtime", phase = "optimized")] if you don't.
4246//!
43- //! - The `custom_mir` attribute tells the compiler to treat the function as being custom MIR. This
44- //! attribute only works on functions - there is no way to insert custom MIR into the middle of
45- //! another function.
46- //! - The `dialect` and `phase` parameters indicate which version of MIR you are inserting here.
47- //! This will normally be the phase that corresponds to the thing you are trying to test. The
48- //! phase can be omitted for dialects that have just one.
49- //! - You should define your function signature like you normally would. Externally, this function
50- //! can be called like any other function.
51- //! - Type inference works - you don't have to spell out the type of all of your locals.
47+ //! [dialect docs]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/mir/enum.MirPhase.html
5248//!
53- //! For now, all statements and terminators are parsed from nested invocations of the special
54- //! functions provided in this module. We additionally want to (but do not yet) support more
55- //! "normal" Rust syntax in places where it makes sense. Also, most kinds of instructions are not
56- //! supported yet.
49+ //! The input to the [`mir!`] macro is:
50+ //!
51+ //! - A possibly empty list of local declarations. Locals can also be declared inline on
52+ //! assignments via `let`. Type inference generally works. Shadowing does not.
53+ //! - A list of basic blocks. The first of these is the start block and is where execution begins.
54+ //! All blocks other than the start block need to be given a name, so that they can be referred
55+ //! to later.
56+ //! - Each block is a list of semicolon terminated statements, followed by a terminator. The
57+ //! syntax for the various statements and terminators is designed to be as similar as possible
58+ //! to the syntax for analogous concepts in native Rust. See below for a list.
59+ //!
60+ //! # Examples
61+ //!
62+ //! ```rust
63+ //! #![feature(core_intrinsics, custom_mir)]
64+ //!
65+ //! extern crate core;
66+ //! use core::intrinsics::mir::*;
67+ //!
68+ //! #[custom_mir(dialect = "built")]
69+ //! pub fn choose_load(a: &i32, b: &i32, c: bool) -> i32 {
70+ //! mir!(
71+ //! {
72+ //! match c {
73+ //! true => t,
74+ //! _ => f,
75+ //! }
76+ //! }
77+ //!
78+ //! t = {
79+ //! let temp = a;
80+ //! Goto(load_and_exit)
81+ //! }
82+ //!
83+ //! f = {
84+ //! temp = b;
85+ //! Goto(load_and_exit)
86+ //! }
87+ //!
88+ //! load_and_exit = {
89+ //! RET = *temp;
90+ //! Return()
91+ //! }
92+ //! )
93+ //! }
94+ //!
95+ //! #[custom_mir(dialect = "built")]
96+ //! fn unwrap_unchecked<T>(opt: Option<T>) -> T {
97+ //! mir!({
98+ //! RET = Move(Field(Variant(opt, 1), 0));
99+ //! Return()
100+ //! })
101+ //! }
102+ //! ```
103+ //!
104+ //! We can also set off compilation failures that happen in sufficiently late stages of the
105+ //! compiler:
106+ //!
107+ //! ```rust,compile_fail
108+ //! #![feature(core_intrinsics, custom_mir)]
109+ //!
110+ //! extern crate core;
111+ //! use core::intrinsics::mir::*;
112+ //!
113+ //! #[custom_mir(dialect = "built")]
114+ //! fn borrow_error(should_init: bool) -> i32 {
115+ //! mir!(
116+ //! let temp: i32;
117+ //!
118+ //! {
119+ //! match should_init {
120+ //! true => init,
121+ //! _ => use_temp,
122+ //! }
123+ //! }
124+ //!
125+ //! init = {
126+ //! temp = 0;
127+ //! Goto(use_temp)
128+ //! }
129+ //!
130+ //! use_temp = {
131+ //! RET = temp;
132+ //! Return()
133+ //! }
134+ //! )
135+ //! }
136+ //! ```
137+ //!
138+ //! ```text
139+ //! error[E0381]: used binding is possibly-uninitialized
140+ //! --> test.rs:24:13
141+ //! |
142+ //! 8 | / mir!(
143+ //! 9 | | let temp: i32;
144+ //! 10 | |
145+ //! 11 | | {
146+ //! ... |
147+ //! 19 | | temp = 0;
148+ //! | | -------- binding initialized here in some conditions
149+ //! ... |
150+ //! 24 | | RET = temp;
151+ //! | | ^^^^^^^^^^ value used here but it is possibly-uninitialized
152+ //! 25 | | Return()
153+ //! 26 | | }
154+ //! 27 | | )
155+ //! | |_____- binding declared here but left uninitialized
156+ //!
157+ //! error: aborting due to previous error
158+ //!
159+ //! For more information about this error, try `rustc --explain E0381`.
160+ //! ```
161+ //!
162+ //! # Syntax
163+ //!
164+ //! The lists below are an exhaustive description of how various MIR constructs can be created.
165+ //! Anything missing from the list should be assumed to not be supported, PRs welcome.
166+ //!
167+ //! #### Locals
168+ //!
169+ //! - The `_0` return local can always be accessed via `RET`.
170+ //! - Arguments can be accessed via their regular name.
171+ //! - All other locals need to be declared with `let` somewhere and then can be accessed by name.
172+ //!
173+ //! #### Places
174+ //! - Locals implicit convert to places.
175+ //! - Field accesses, derefs, and indexing work normally.
176+ //! - Fields in variants can be accessed via the [`Variant`] and [`Field`] associated functions,
177+ //! see their documentation for details.
178+ //!
179+ //! #### Operands
180+ //! - Places implicitly convert to `Copy` operands.
181+ //! - `Move` operands can be created via [`Move`].
182+ //! - Const blocks, literals, named constants, and const params all just work.
183+ //! - [`Static`] and [`StaticMut`] can be used to create `&T` and `*mut T`s to statics. These are
184+ //! constants in MIR and the only way to access statics.
185+ //!
186+ //! #### Statements
187+ //! - Assign statements work via normal Rust assignment.
188+ //! - [`Retag`] statements have an associated function.
189+ //!
190+ //! #### Rvalues
191+ //!
192+ //! - Operands implicitly convert to `Use` rvalues.
193+ //! - `&`, `&mut`, `addr_of!`, and `addr_of_mut!` all work to create their associated rvalue.
194+ //! - [`Discriminant`] has an associated function.
195+ //!
196+ //! #### Terminators
197+ //!
198+ //! - [`Goto`] and [`Return`] have associated functions.
199+ //! - `match some_int_operand` becomes a `SwitchInt`. Each arm should be `literal => basic_block`
200+ //! - The exception is the last arm, which must be `_ => basic_block` and corresponds to the
201+ //! otherwise branch.
57202//!
58203
59204#![ unstable(
69214pub struct BasicBlock ;
70215
71216macro_rules! define {
72- ( $name: literal, $( $sig: tt) * ) => {
217+ ( $name: literal, $( # [ $meta : meta ] ) * fn $ ( $sig: tt) * ) => {
73218 #[ rustc_diagnostic_item = $name]
74- pub $( $sig) * { panic!( ) }
219+ $( #[ $meta ] ) *
220+ pub fn $( $sig) * { panic!( ) }
75221 }
76222}
77223
@@ -82,8 +228,73 @@ define!("mir_retag_raw", fn RetagRaw<T>(place: T));
82228define ! ( "mir_move" , fn Move <T >( place: T ) -> T ) ;
83229define ! ( "mir_static" , fn Static <T >( s: T ) -> & ' static T ) ;
84230define ! ( "mir_static_mut" , fn StaticMut <T >( s: T ) -> * mut T ) ;
231+ define ! (
232+ "mir_discriminant" ,
233+ /// Gets the discriminant of a place.
234+ fn Discriminant <T >( place: T ) -> <T as :: core:: marker:: DiscriminantKind >:: Discriminant
235+ ) ;
236+ define ! ( "mir_set_discriminant" , fn SetDiscriminant <T >( place: T , index: u32 ) ) ;
237+ define ! (
238+ "mir_field" ,
239+ /// Access the field with the given index of some place.
240+ ///
241+ /// This only makes sense to use in conjunction with [`Variant`]. If the type you are looking to
242+ /// access the field of does not have variants, you can use normal field projection syntax.
243+ ///
244+ /// There is no proper way to do a place projection to a variant in Rust, and so these two
245+ /// functions are a workaround. You can access a field of a variant via `Field(Variant(place,
246+ /// var_idx), field_idx)`, where `var_idx` and `field_idx` are appropriate literals. Some
247+ /// caveats:
248+ ///
249+ /// - The return type of `Variant` is always `()`. Don't worry about that, the correct MIR will
250+ /// still be generated.
251+ /// - In some situations, the return type of `Field` cannot be inferred. You may need to
252+ /// annotate it on the function in these cases.
253+ /// - Since `Field` is a function call which is not a place expression, using this on the left
254+ /// hand side of an expression is rejected by the compiler. [`place!`] is a macro provided to
255+ /// work around that issue. Wrap the left hand side of an assignment in the macro to convince
256+ /// the compiler that it's ok.
257+ ///
258+ /// # Examples
259+ ///
260+ /// ```rust
261+ /// #![feature(custom_mir, core_intrinsics)]
262+ ///
263+ /// extern crate core;
264+ /// use core::intrinsics::mir::*;
265+ ///
266+ /// #[custom_mir(dialect = "built")]
267+ /// fn unwrap_deref(opt: Option<&i32>) -> i32 {
268+ /// mir!({
269+ /// RET = *Field::<&i32>(Variant(opt, 1), 0);
270+ /// Return()
271+ /// })
272+ /// }
273+ ///
274+ /// #[custom_mir(dialect = "built")]
275+ /// fn set(opt: &mut Option<i32>) {
276+ /// mir!({
277+ /// place!(Field(Variant(*opt, 1), 0)) = 5;
278+ /// Return()
279+ /// })
280+ /// }
281+ /// ```
282+ fn Field <F >( place: ( ) , field: u32 ) -> F
283+ ) ;
284+ define ! (
285+ "mir_variant" ,
286+ /// Adds a variant projection with the given index to the place.
287+ ///
288+ /// See [`Field`] for documentation.
289+ fn Variant <T >( place: T , index: u32 ) -> ( )
290+ ) ;
291+ define ! (
292+ "mir_make_place" ,
293+ #[ doc( hidden) ]
294+ fn __internal_make_place<T >( place: T ) -> * mut T
295+ ) ;
85296
86- /// Convenience macro for generating custom MIR.
297+ /// Macro for generating custom MIR.
87298///
88299/// See the module documentation for syntax details. This macro is not magic - it only transforms
89300/// your MIR into something that is easier to parse in the compiler.
@@ -139,6 +350,13 @@ pub macro mir {
139350 } }
140351}
141352
353+ /// Helper macro that allows you to treat a value expression like a place expression.
354+ ///
355+ /// See the documentation on [`Variant`] for why this is necessary and how to use it.
356+ pub macro place( $e: expr) {
357+ ( * :: core:: intrinsics:: mir:: __internal_make_place ( $e) )
358+ }
359+
142360/// Helper macro that extracts the `let` declarations out of a bunch of statements.
143361///
144362/// This macro is written using the "statement muncher" strategy. Each invocation parses the first
0 commit comments