diff --git a/src/const-eval.md b/src/const-eval.md index aaa2ed2d6..2a5c5d2f9 100644 --- a/src/const-eval.md +++ b/src/const-eval.md @@ -5,7 +5,7 @@ specific item (constant/static/array length) this happens after the MIR for the item is borrow-checked and optimized. In many cases trying to const evaluate an item will trigger the computation of its MIR for the first time. -Prominent examples are +Prominent examples are: * The initializer of a `static` * Array length @@ -20,19 +20,26 @@ Additionally constant evaluation can be used to reduce the workload or binary size at runtime by precomputing complex operations at compiletime and only storing the result. -Constant evaluation can be done by calling the `const_eval` query of `TyCtxt`. - -The `const_eval` query takes a [`ParamEnv`](./param_env.html) of environment in -which the constant is evaluated (e.g. the function within which the constant is -used) and a `GlobalId`. The `GlobalId` is made up of an -`Instance` referring to a constant or static or of an -`Instance` of a function and an index into the function's `Promoted` table. - -Constant evaluation returns a `Result` with either the error, or the simplest -representation of the constant. "simplest" meaning if it is representable as an -integer or fat pointer, it will directly yield the value (via `ConstValue::Scalar` or -`ConstValue::ScalarPair`), instead of referring to the [`miri`](./miri.html) virtual -memory allocation (via `ConstValue::ByRef`). This means that the `const_eval` -function cannot be used to create miri-pointers to the evaluated constant or -static. If you need that, you need to directly work with the functions in -[src/librustc_mir/const_eval.rs](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_mir/const_eval/index.html). +Constant evaluation can be done by calling the `const_eval_*` functions of `TyCtxt`. +They're the wrappers of the `const_eval` query. + +The `const_eval_*` functions use a [`ParamEnv`](./param_env.html) of environment +in which the constant is evaluated (e.g. the function within which the constant is used) +and a [`GlobalId`]. The `GlobalId` is made up of an `Instance` referring to a constant +or static or of an `Instance` of a function and an index into the function's `Promoted` table. + +Constant evaluation returns a [`ConstEvalResult`] with either the error, or the a +representation of the constant. `static` initializers are always represented as +[`miri`](./miri.html) virtual memory allocations (via [`ConstValue::ByRef`]). +Other constants get represented as [`ConstValue::Scalar`] +or [`ConstValue::Slice`] if possible. This means that the `const_eval_*` +functions cannot be used to create miri-pointers to the evaluated constant. +If you need the value of a constant inside Miri, you need to directly work with +[`eval_const_to_op`]. + +[`GlobalId`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/mir/interpret/struct.GlobalId.html +[`ConstValue::Scalar`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/mir/interpret/value/enum.ConstValue.html#variant.Scalar +[`ConstValue::Slice`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/mir/interpret/value/enum.ConstValue.html#variant.Slice +[`ConstValue::ByRef`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/mir/interpret/value/enum.ConstValue.html#variant.ByRef +[`ConstEvalResult`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/mir/interpret/error/type.ConstEvalResult.html +[`eval_const_to_op`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_mir/interpret/struct.InterpCx.html#method.eval_const_to_op diff --git a/src/miri.md b/src/miri.md index 16f2a18f2..76996271d 100644 --- a/src/miri.md +++ b/src/miri.md @@ -1,9 +1,9 @@ # Miri Miri (**MIR** **I**nterpreter) is a virtual machine for executing MIR without -compiling to machine code. It is usually invoked via `tcx.const_eval`. +compiling to machine code. It is usually invoked via `tcx.const_eval_*` functions. -If you start out with a constant +If you start out with a constant: ```rust const FOO: usize = 1 << 12; @@ -12,7 +12,7 @@ const FOO: usize = 1 << 12; rustc doesn't actually invoke anything until the constant is either used or placed into metadata. -Once you have a use-site like +Once you have a use-site like: ```rust,ignore type Foo = [u8; FOO - 42]; @@ -35,17 +35,17 @@ Invoking `tcx.const_eval(param_env.and(gid))` will now trigger the creation of the MIR of the array length expression. The MIR will look something like this: ```mir -const Foo::{{initializer}}: usize = { - let mut _0: usize; // return pointer +Foo::{{constant}}#0: usize = { + let mut _0: usize; let mut _1: (usize, bool); bb0: { - _1 = CheckedSub(const Unevaluated(FOO, Slice([])), const 42usize); - assert(!(_1.1: bool), "attempt to subtract with overflow") -> bb1; + _1 = CheckedSub(const FOO, const 42usize); + assert(!move (_1.1: bool), "attempt to subtract with overflow") -> bb1; } bb1: { - _0 = (_1.0: usize); + _0 = move (_1.0: usize); return; } } @@ -55,16 +55,16 @@ Before the evaluation, a virtual memory location (in this case essentially a `vec![u8; 4]` or `vec![u8; 8]`) is created for storing the evaluation result. At the start of the evaluation, `_0` and `_1` are -`Operand::Immediate(Immediate::Scalar(ScalarMaybeUndef::Undef))`. This is quite +`Operand::Immediate(Immediate::Scalar(ScalarMaybeUndef::Undef))`. This is quite a mouthful: [`Operand`] can represent either data stored somewhere in the [interpreter memory](#memory) (`Operand::Indirect`), or (as an optimization) immediate data stored in-line. And [`Immediate`] can either be a single (potentially uninitialized) [scalar value][`Scalar`] (integer or thin pointer), -or a pair of two of them. In our case, the single scalar value is *not* (yet) +or a pair of two of them. In our case, the single scalar value is *not* (yet) initialized. When the initialization of `_1` is invoked, the value of the `FOO` constant is -required, and triggers another call to `tcx.const_eval`, which will not be shown +required, and triggers another call to `tcx.const_eval_*`, which will not be shown here. If the evaluation of FOO is successful, `42` will be subtracted from its value `4096` and the result stored in `_1` as `Operand::Immediate(Immediate::ScalarPair(Scalar::Raw { data: 4054, .. }, @@ -200,8 +200,8 @@ division on pointer values. ## Interpretation -Although the main entry point to constant evaluation is the `tcx.const_eval` -query, there are additional functions in +Although the main entry point to constant evaluation is the `tcx.const_eval_*` +functions, there are additional functions in [librustc_mir/const_eval.rs](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_mir/const_eval/index.html) that allow accessing the fields of a `ConstValue` (`ByRef` or otherwise). You should never have to access an `Allocation` directly except for translating it to the @@ -217,7 +217,7 @@ A stack frame is defined by the `Frame` type in and contains all the local variables memory (`None` at the start of evaluation). Each frame refers to the evaluation of either the root constant or subsequent calls to `const fn`. The -evaluation of another constant simply calls `tcx.const_eval`, which produces an +evaluation of another constant simply calls `tcx.const_eval_*`, which produce an entirely new and independent stack frame. The frames are just a `Vec`, there's no way to actually refer to a @@ -229,4 +229,4 @@ Miri now calls the `step` method (in ) until it either returns an error or has no further statements to execute. Each statement will now initialize or modify the locals or the virtual memory referred to by a local. This might require evaluating other constants or -statics, which just recursively invokes `tcx.const_eval`. +statics, which just recursively invokes `tcx.const_eval_*`.