<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
    <title>felixwrt.dev</title>
    <link href="/atom.xml" rel="self" type="application/atom+xml"/>
    <link href="/"/>
    <generator uri="https://www.getzola.org/">Zola</generator>
    <updated>2025-03-11T00:00:00+00:00</updated>
    <id>/atom.xml</id>
    <entry xml:lang="en">
        <title>When are Rust&#x27;s `const fn`s executed?</title>
        <published>2025-03-11T00:00:00+00:00</published>
        <updated>2025-03-11T00:00:00+00:00</updated>
        <author>
          <name>Felix</name>
        </author>
        <link rel="alternate" href="/posts/const-fn/" type="text/html"/>
        <id>/posts/const-fn/</id>
        <content type="html">&lt;p&gt;I&#x27;ve been playing with &lt;code&gt;const fn&lt;&#x2F;code&gt;s in Rust recently and kept wondering when they are executed. In this post, I&#x27;m going to take a closer look at them. &lt;&#x2F;p&gt;
&lt;p&gt;First, some background on regular functions and &lt;code&gt;const fn&lt;&#x2F;code&gt;s:&lt;&#x2F;p&gt;
&lt;h2 id=&quot;regular-functions&quot;&gt;Regular functions&lt;&#x2F;h2&gt;
&lt;p&gt;Regular (non-const) functions in Rust are compiled into machine code and are executed at runtime. They can take any kind of arguments, both constants and non-constants. The result of a regular function can only be used in non-const contexts though. Using a regular function in a constant context (for example in a constant or as the length of an array) leads to a compiler error.&lt;&#x2F;p&gt;
&lt;p&gt;The following example shows a simple regular function &lt;code&gt;square&lt;&#x2F;code&gt;. It can be used with const and non-const arguments, but its result cannot be used in a constant.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#2e3440;color:#d8dee9;&quot; class=&quot;language-rust &quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span style=&quot;color:#81a1c1;&quot;&gt;fn &lt;&#x2F;span&gt;&lt;span style=&quot;color:#88c0d0;&quot;&gt;square&lt;&#x2F;span&gt;&lt;span&gt;(x&lt;&#x2F;span&gt;&lt;span style=&quot;color:#eceff4;&quot;&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#81a1c1;&quot;&gt;usize&lt;&#x2F;span&gt;&lt;span&gt;) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#eceff4;&quot;&gt;-&amp;gt; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#81a1c1;&quot;&gt;usize &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;    x &lt;&#x2F;span&gt;&lt;span style=&quot;color:#81a1c1;&quot;&gt;*&lt;&#x2F;span&gt;&lt;span&gt; x
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#81a1c1;&quot;&gt;pub fn &lt;&#x2F;span&gt;&lt;span style=&quot;color:#88c0d0;&quot;&gt;main&lt;&#x2F;span&gt;&lt;span&gt;() {
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#616e88;&quot;&gt;&#x2F;&#x2F; called with constants
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#81a1c1;&quot;&gt;const &lt;&#x2F;span&gt;&lt;span&gt;CONST_ARG&lt;&#x2F;span&gt;&lt;span style=&quot;color:#eceff4;&quot;&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#81a1c1;&quot;&gt;usize = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;2&lt;&#x2F;span&gt;&lt;span style=&quot;color:#eceff4;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#81a1c1;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; res_a &lt;&#x2F;span&gt;&lt;span style=&quot;color:#81a1c1;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#88c0d0;&quot;&gt;square&lt;&#x2F;span&gt;&lt;span&gt;(CONST_ARG)&lt;&#x2F;span&gt;&lt;span style=&quot;color:#eceff4;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#616e88;&quot;&gt;&#x2F;&#x2F; called with non-consts
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#81a1c1;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; runtime_arg&lt;&#x2F;span&gt;&lt;span style=&quot;color:#eceff4;&quot;&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#81a1c1;&quot;&gt;usize = &lt;&#x2F;span&gt;&lt;span&gt;std&lt;&#x2F;span&gt;&lt;span style=&quot;color:#81a1c1;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span&gt;env&lt;&#x2F;span&gt;&lt;span style=&quot;color:#81a1c1;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span&gt;args()&lt;&#x2F;span&gt;&lt;span style=&quot;color:#81a1c1;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#88c0d0;&quot;&gt;len&lt;&#x2F;span&gt;&lt;span&gt;()&lt;&#x2F;span&gt;&lt;span style=&quot;color:#eceff4;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#81a1c1;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; res_b &lt;&#x2F;span&gt;&lt;span style=&quot;color:#81a1c1;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#88c0d0;&quot;&gt;square&lt;&#x2F;span&gt;&lt;span&gt;(runtime_arg)&lt;&#x2F;span&gt;&lt;span style=&quot;color:#eceff4;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;    
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#616e88;&quot;&gt;&#x2F;&#x2F; const RES_CONST: usize = square(5);
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#616e88;&quot;&gt;&#x2F;&#x2F; error: cannot call non-const fn `square` in constants
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h2 id=&quot;const-fn&quot;&gt;const fn&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;code&gt;const fn&lt;&#x2F;code&gt;s in Rust are declared like regular functions, the only difference is that the &lt;code&gt;const&lt;&#x2F;code&gt; keyword is added to the beginning of the declaration. &lt;code&gt;const fn&lt;&#x2F;code&gt;s can be used in constant contexts and can also be compiled and executed like regular functions.&lt;&#x2F;p&gt;
&lt;p&gt;The following example contains the same &lt;code&gt;square&lt;&#x2F;code&gt; function, but now it&#x27;s a &lt;code&gt;const fn&lt;&#x2F;code&gt;. Compared to the regular function we&#x27;ve had before, &lt;code&gt;square&lt;&#x2F;code&gt; can now be used in a constant!&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#2e3440;color:#d8dee9;&quot; class=&quot;language-rust &quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span style=&quot;color:#81a1c1;&quot;&gt;const fn &lt;&#x2F;span&gt;&lt;span style=&quot;color:#88c0d0;&quot;&gt;square&lt;&#x2F;span&gt;&lt;span&gt;(x&lt;&#x2F;span&gt;&lt;span style=&quot;color:#eceff4;&quot;&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#81a1c1;&quot;&gt;usize&lt;&#x2F;span&gt;&lt;span&gt;) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#eceff4;&quot;&gt;-&amp;gt; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#81a1c1;&quot;&gt;usize &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;    x &lt;&#x2F;span&gt;&lt;span style=&quot;color:#81a1c1;&quot;&gt;*&lt;&#x2F;span&gt;&lt;span&gt; x
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#81a1c1;&quot;&gt;pub fn &lt;&#x2F;span&gt;&lt;span style=&quot;color:#88c0d0;&quot;&gt;main&lt;&#x2F;span&gt;&lt;span&gt;() {
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#616e88;&quot;&gt;&#x2F;&#x2F; called with constants
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#81a1c1;&quot;&gt;const &lt;&#x2F;span&gt;&lt;span&gt;CONST_ARG&lt;&#x2F;span&gt;&lt;span style=&quot;color:#eceff4;&quot;&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#81a1c1;&quot;&gt;usize = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;2&lt;&#x2F;span&gt;&lt;span style=&quot;color:#eceff4;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#81a1c1;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; res_a &lt;&#x2F;span&gt;&lt;span style=&quot;color:#81a1c1;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#88c0d0;&quot;&gt;square&lt;&#x2F;span&gt;&lt;span&gt;(CONST_ARG)&lt;&#x2F;span&gt;&lt;span style=&quot;color:#eceff4;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#616e88;&quot;&gt;&#x2F;&#x2F; called with non-const arg
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#81a1c1;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; runtime_arg&lt;&#x2F;span&gt;&lt;span style=&quot;color:#eceff4;&quot;&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#81a1c1;&quot;&gt;usize = &lt;&#x2F;span&gt;&lt;span&gt;std&lt;&#x2F;span&gt;&lt;span style=&quot;color:#81a1c1;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span&gt;env&lt;&#x2F;span&gt;&lt;span style=&quot;color:#81a1c1;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span&gt;args()&lt;&#x2F;span&gt;&lt;span style=&quot;color:#81a1c1;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#88c0d0;&quot;&gt;len&lt;&#x2F;span&gt;&lt;span&gt;()&lt;&#x2F;span&gt;&lt;span style=&quot;color:#eceff4;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#81a1c1;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; res_b &lt;&#x2F;span&gt;&lt;span style=&quot;color:#81a1c1;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#88c0d0;&quot;&gt;square&lt;&#x2F;span&gt;&lt;span&gt;(runtime_arg)&lt;&#x2F;span&gt;&lt;span style=&quot;color:#eceff4;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;    
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#616e88;&quot;&gt;&#x2F;&#x2F; evaluated at compile time
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#81a1c1;&quot;&gt;const &lt;&#x2F;span&gt;&lt;span&gt;RES_CONST&lt;&#x2F;span&gt;&lt;span style=&quot;color:#eceff4;&quot;&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#81a1c1;&quot;&gt;usize = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#88c0d0;&quot;&gt;square&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;5&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color:#eceff4;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;You can think of &lt;code&gt;const fn&lt;&#x2F;code&gt;s as being generic over whether they&#x27;re evaluated at compile time or executed at runtime. By adding the &lt;code&gt;const&lt;&#x2F;code&gt; keyword to a function, we declare that in addition to being compiled and executed at runtime, the code we&#x27;ve written can also be evaluated at compile time. &lt;&#x2F;p&gt;
&lt;p&gt;This additional use-case comes with some restrictions though. Not everything we&#x27;re allowed to do in a regular function can also be done in a &lt;code&gt;const fn&lt;&#x2F;code&gt;. For example, you cannot allocate memory in a &lt;code&gt;const fn&lt;&#x2F;code&gt;. The subset of Rust that&#x27;s usable in &lt;code&gt;const fn&lt;&#x2F;code&gt;s is documented in the &lt;a href=&quot;https:&#x2F;&#x2F;doc.rust-lang.org&#x2F;reference&#x2F;const_eval.html&quot;&gt;Rust Reference&lt;&#x2F;a&gt; and continuously expanded by the Rust developers.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;em&gt;By the way: changing a regular function into a &lt;code&gt;const fn&lt;&#x2F;code&gt; is a backwards-compatible change! Existing (non-const) uses of the function will continue to work, but additionally, the function can now be used in constant contexts as well. Many functions in Rust&#x27;s standard library are already &lt;code&gt;const fn&lt;&#x2F;code&gt;s and new releases of Rust often contain functions that were changed into &lt;code&gt;const fn&lt;&#x2F;code&gt;s.&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Now that we know what &lt;code&gt;const fn&lt;&#x2F;code&gt;s are and how they&#x27;re different from regular functions, we can look into the real question:&lt;&#x2F;p&gt;
&lt;h2 id=&quot;compile-time-or-runtime&quot;&gt;Compile time or runtime?&lt;&#x2F;h2&gt;
&lt;p&gt;Whether a &lt;code&gt;const fn&lt;&#x2F;code&gt; is evaluated at compile time or executed at runtime depends on the arguments passed to the function as well as the context in which it is called. In fact, the same function can be used in multiple places, some of which are evaluated at compile time and others being executed at runtime.&lt;&#x2F;p&gt;
&lt;p&gt;For each usage of a &lt;code&gt;const fn&lt;&#x2F;code&gt;, we can ask the following two questions to determine when it is run:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Are all arguments available at compile time (only &lt;code&gt;const&lt;&#x2F;code&gt; arguments)?&lt;&#x2F;li&gt;
&lt;li&gt;Is the result of the function needed at compile time (function called within a constant context)?&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;These two simple yes&#x2F;no questions generate four different cases which we will look at individually:&lt;&#x2F;p&gt;
&lt;h3 id=&quot;non-const-arguments-non-const-context&quot;&gt;non-const arguments &amp;amp;&amp;amp; non-const context&lt;&#x2F;h3&gt;
&lt;p&gt;The simplest and most common case is a function that takes non-const arguments and that is used in a non-const context. In this case, the function needs to be executed at runtime because the arguments can&#x27;t be known at compile time. &lt;&#x2F;p&gt;
&lt;p&gt;The following example uses the same &lt;code&gt;square&lt;&#x2F;code&gt; constant function as above and passes the number of command line arguments to it. The number of arguments the program is called with cannot be known at compile time, so the function can only be executed at runtime. That&#x27;s fine because the result (&lt;code&gt;res_b&lt;&#x2F;code&gt;) is also a runtime variable and its value isn&#x27;t needed during compilation.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#2e3440;color:#d8dee9;&quot; class=&quot;language-rust &quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span style=&quot;color:#81a1c1;&quot;&gt;pub fn &lt;&#x2F;span&gt;&lt;span style=&quot;color:#88c0d0;&quot;&gt;main&lt;&#x2F;span&gt;&lt;span&gt;() {
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#616e88;&quot;&gt;&#x2F;&#x2F; called with non-const args
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#81a1c1;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; runtime_arg&lt;&#x2F;span&gt;&lt;span style=&quot;color:#eceff4;&quot;&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#81a1c1;&quot;&gt;usize = &lt;&#x2F;span&gt;&lt;span&gt;std&lt;&#x2F;span&gt;&lt;span style=&quot;color:#81a1c1;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span&gt;env&lt;&#x2F;span&gt;&lt;span style=&quot;color:#81a1c1;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span&gt;args()&lt;&#x2F;span&gt;&lt;span style=&quot;color:#81a1c1;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#88c0d0;&quot;&gt;len&lt;&#x2F;span&gt;&lt;span&gt;()&lt;&#x2F;span&gt;&lt;span style=&quot;color:#eceff4;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#81a1c1;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; res_b &lt;&#x2F;span&gt;&lt;span style=&quot;color:#81a1c1;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#88c0d0;&quot;&gt;square&lt;&#x2F;span&gt;&lt;span&gt;(runtime_arg)&lt;&#x2F;span&gt;&lt;span style=&quot;color:#eceff4;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h3 id=&quot;const-arguments-const-context&quot;&gt;const arguments &amp;amp;&amp;amp; const context&lt;&#x2F;h3&gt;
&lt;p&gt;If the function is used in a constant context and used with constant arguments, it is guaranteed to be evaluated at compile time. Evaluating it at compile time is possible because all arguments are also constants and therefore available during compilation.&lt;&#x2F;p&gt;
&lt;p&gt;In the example below, &lt;code&gt;square&lt;&#x2F;code&gt; is called with a constant argument &lt;code&gt;CONST_ARG&lt;&#x2F;code&gt; and the result of the evaluation becomes the constant &lt;code&gt;RES_CONST&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#2e3440;color:#d8dee9;&quot; class=&quot;language-rust &quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span style=&quot;color:#81a1c1;&quot;&gt;pub fn &lt;&#x2F;span&gt;&lt;span style=&quot;color:#88c0d0;&quot;&gt;main&lt;&#x2F;span&gt;&lt;span&gt;() {
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#81a1c1;&quot;&gt;const &lt;&#x2F;span&gt;&lt;span&gt;CONST_ARG&lt;&#x2F;span&gt;&lt;span style=&quot;color:#eceff4;&quot;&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#81a1c1;&quot;&gt;usize = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;2&lt;&#x2F;span&gt;&lt;span style=&quot;color:#eceff4;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#81a1c1;&quot;&gt;const &lt;&#x2F;span&gt;&lt;span&gt;RES_CONST&lt;&#x2F;span&gt;&lt;span style=&quot;color:#eceff4;&quot;&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#81a1c1;&quot;&gt;usize = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#88c0d0;&quot;&gt;square&lt;&#x2F;span&gt;&lt;span&gt;(CONST_ARG)&lt;&#x2F;span&gt;&lt;span style=&quot;color:#eceff4;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h3 id=&quot;non-const-arguments-const-context&quot;&gt;non-const arguments &amp;amp;&amp;amp; const context&lt;&#x2F;h3&gt;
&lt;p&gt;Using a &lt;code&gt;const fn&lt;&#x2F;code&gt; in a constant context and providing non-const arguments leads to a compile error. The constant context means that the function would need to be evaluated at compile time, but the arguments aren&#x27;t available until runtime:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#2e3440;color:#d8dee9;&quot; class=&quot;language-rust &quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span style=&quot;color:#81a1c1;&quot;&gt;pub fn &lt;&#x2F;span&gt;&lt;span style=&quot;color:#88c0d0;&quot;&gt;main&lt;&#x2F;span&gt;&lt;span&gt;() {
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#616e88;&quot;&gt;&#x2F;&#x2F; called with non-const args
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#81a1c1;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; runtime_arg&lt;&#x2F;span&gt;&lt;span style=&quot;color:#eceff4;&quot;&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#81a1c1;&quot;&gt;usize = &lt;&#x2F;span&gt;&lt;span&gt;std&lt;&#x2F;span&gt;&lt;span style=&quot;color:#81a1c1;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span&gt;env&lt;&#x2F;span&gt;&lt;span style=&quot;color:#81a1c1;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span&gt;args()&lt;&#x2F;span&gt;&lt;span style=&quot;color:#81a1c1;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#88c0d0;&quot;&gt;len&lt;&#x2F;span&gt;&lt;span&gt;()&lt;&#x2F;span&gt;&lt;span style=&quot;color:#eceff4;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#81a1c1;&quot;&gt;const &lt;&#x2F;span&gt;&lt;span&gt;RES_CONST&lt;&#x2F;span&gt;&lt;span style=&quot;color:#eceff4;&quot;&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#81a1c1;&quot;&gt;usize = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#88c0d0;&quot;&gt;square&lt;&#x2F;span&gt;&lt;span&gt;(runtime_arg)&lt;&#x2F;span&gt;&lt;span style=&quot;color:#eceff4;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#616e88;&quot;&gt;&#x2F;&#x2F; error: attempt to use a non-constant value in a constant
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h3 id=&quot;const-arguments-non-const-context&quot;&gt;const arguments &amp;amp;&amp;amp; non-const context&lt;&#x2F;h3&gt;
&lt;p&gt;Lastly, what happens is the function is used in a non-const context, but with const arguments?&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#2e3440;color:#d8dee9;&quot; class=&quot;language-rust &quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span style=&quot;color:#81a1c1;&quot;&gt;pub fn &lt;&#x2F;span&gt;&lt;span style=&quot;color:#88c0d0;&quot;&gt;main&lt;&#x2F;span&gt;&lt;span&gt;() {
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#81a1c1;&quot;&gt;const &lt;&#x2F;span&gt;&lt;span&gt;CONST_ARG&lt;&#x2F;span&gt;&lt;span style=&quot;color:#eceff4;&quot;&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#81a1c1;&quot;&gt;usize = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;2&lt;&#x2F;span&gt;&lt;span style=&quot;color:#eceff4;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#81a1c1;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; res &lt;&#x2F;span&gt;&lt;span style=&quot;color:#81a1c1;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#88c0d0;&quot;&gt;square&lt;&#x2F;span&gt;&lt;span&gt;(CONST_ARG)&lt;&#x2F;span&gt;&lt;span style=&quot;color:#eceff4;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;All arguments are known at compile time, so the function could be evaluated during compilation. The result is only needed at runtime though, so it would also be possible to compile the function and execute it at runtime.&lt;&#x2F;p&gt;
&lt;p&gt;Looking at the code, it&#x27;s not obvious what the Rust compiler will do here. Let&#x27;s do some experiments!&lt;&#x2F;p&gt;
&lt;h2 id=&quot;inspecting-compiler-output&quot;&gt;Inspecting compiler output&lt;&#x2F;h2&gt;
&lt;p&gt;To see what&#x27;s going on, we&#x27;re going to look at the assembly code generated by the compiler.&lt;&#x2F;p&gt;
&lt;p&gt;Assembly code quickly becomes huge and difficult to read, so we&#x27;re going to take a look at a minimal example that&#x27;s adapted to generate simple assembly code:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#2e3440;color:#d8dee9;&quot; class=&quot;language-rust &quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span style=&quot;color:#81a1c1;&quot;&gt;const fn &lt;&#x2F;span&gt;&lt;span style=&quot;color:#88c0d0;&quot;&gt;square&lt;&#x2F;span&gt;&lt;span&gt;(x&lt;&#x2F;span&gt;&lt;span style=&quot;color:#eceff4;&quot;&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#81a1c1;&quot;&gt;i32&lt;&#x2F;span&gt;&lt;span&gt;) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#eceff4;&quot;&gt;-&amp;gt; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#81a1c1;&quot;&gt;i32 &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;    x&lt;&#x2F;span&gt;&lt;span style=&quot;color:#81a1c1;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#88c0d0;&quot;&gt;wrapping_mul&lt;&#x2F;span&gt;&lt;span&gt;(x)
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#81a1c1;&quot;&gt;pub fn &lt;&#x2F;span&gt;&lt;span style=&quot;color:#88c0d0;&quot;&gt;main&lt;&#x2F;span&gt;&lt;span&gt;() {
&lt;&#x2F;span&gt;&lt;span&gt;    std&lt;&#x2F;span&gt;&lt;span style=&quot;color:#81a1c1;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span&gt;process&lt;&#x2F;span&gt;&lt;span style=&quot;color:#81a1c1;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span&gt;exit(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#88c0d0;&quot;&gt;square&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;10&lt;&#x2F;span&gt;&lt;span&gt;))&lt;&#x2F;span&gt;&lt;span style=&quot;color:#eceff4;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The example program simply calls the &lt;code&gt;square&lt;&#x2F;code&gt; function with a hard-coded constant value of 10 and exits with the value returned from the function call. I&#x27;m using &lt;code&gt;wrapping_mul&lt;&#x2F;code&gt; and &lt;code&gt;std::process::exit&lt;&#x2F;code&gt; here to make the resulting assembly code simpler. &lt;&#x2F;p&gt;
&lt;p&gt;There are a couple of ways to view assembly code, but my favorite is the &lt;a href=&quot;https:&#x2F;&#x2F;godbolt.org&#x2F;&quot;&gt;godbolt.org compiler explorer&lt;&#x2F;a&gt;. &lt;&#x2F;p&gt;
&lt;p&gt;Entering our example program and selecting the latest stable Rust compiler (1.80) generates the following output (&lt;a href=&quot;https:&#x2F;&#x2F;godbolt.org&#x2F;z&#x2F;baadjhejs&quot;&gt;godbolt.org&lt;&#x2F;a&gt;):&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;asm&quot; style=&quot;background-color:#2e3440;color:#d8dee9;&quot; class=&quot;language-asm &quot;&gt;&lt;code class=&quot;language-asm&quot; data-lang=&quot;asm&quot;&gt;&lt;span style=&quot;color:#88c0d0;&quot;&gt;example::square:
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#88c0d0;&quot;&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#81a1c1;&quot;&gt;mov     &lt;&#x2F;span&gt;&lt;span&gt;eax, edi
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#88c0d0;&quot;&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#81a1c1;&quot;&gt;imul    &lt;&#x2F;span&gt;&lt;span&gt;eax, eax
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#88c0d0;&quot;&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#81a1c1;&quot;&gt;ret
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#88c0d0;&quot;&gt;example::main:
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#88c0d0;&quot;&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#81a1c1;&quot;&gt;push    &lt;&#x2F;span&gt;&lt;span&gt;rax
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#88c0d0;&quot;&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#81a1c1;&quot;&gt;mov     &lt;&#x2F;span&gt;&lt;span&gt;edi, 10
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#88c0d0;&quot;&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#81a1c1;&quot;&gt;call    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#88c0d0;&quot;&gt;example::square
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#88c0d0;&quot;&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#81a1c1;&quot;&gt;mov     &lt;&#x2F;span&gt;&lt;span&gt;edi, eax
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#88c0d0;&quot;&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#81a1c1;&quot;&gt;mov     &lt;&#x2F;span&gt;&lt;span&gt;rax, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#88c0d0;&quot;&gt;qword ptr &lt;&#x2F;span&gt;&lt;span&gt;[rip + &lt;&#x2F;span&gt;&lt;span style=&quot;color:#81a1c1;&quot;&gt;std&lt;&#x2F;span&gt;&lt;span style=&quot;color:#88c0d0;&quot;&gt;::process::exit@GOTPCREL&lt;&#x2F;span&gt;&lt;span&gt;]
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#88c0d0;&quot;&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#81a1c1;&quot;&gt;call    &lt;&#x2F;span&gt;&lt;span&gt;rax
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Looking at the assembly of the &lt;code&gt;main&lt;&#x2F;code&gt; function, we can see that the &lt;code&gt;square&lt;&#x2F;code&gt; function is called at runtime. Interesting!&lt;&#x2F;p&gt;
&lt;p&gt;Let&#x27;s try again, this time with optimizations enabled (&lt;code&gt;-C opt-level=3&lt;&#x2F;code&gt;, &lt;a href=&quot;https:&#x2F;&#x2F;godbolt.org&#x2F;z&#x2F;bc3fE1z3r&quot;&gt;godbolt.org&lt;&#x2F;a&gt;):&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;asm&quot; style=&quot;background-color:#2e3440;color:#d8dee9;&quot; class=&quot;language-asm &quot;&gt;&lt;code class=&quot;language-asm&quot; data-lang=&quot;asm&quot;&gt;&lt;span style=&quot;color:#88c0d0;&quot;&gt;example::main:
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#88c0d0;&quot;&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#81a1c1;&quot;&gt;push    &lt;&#x2F;span&gt;&lt;span&gt;rax
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#88c0d0;&quot;&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#81a1c1;&quot;&gt;mov     &lt;&#x2F;span&gt;&lt;span&gt;edi, 100
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#88c0d0;&quot;&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#81a1c1;&quot;&gt;call    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#88c0d0;&quot;&gt;qword ptr &lt;&#x2F;span&gt;&lt;span&gt;[rip + &lt;&#x2F;span&gt;&lt;span style=&quot;color:#81a1c1;&quot;&gt;std&lt;&#x2F;span&gt;&lt;span style=&quot;color:#88c0d0;&quot;&gt;::process::exit@GOTPCREL&lt;&#x2F;span&gt;&lt;span&gt;]
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Now, the call to &lt;code&gt;square&lt;&#x2F;code&gt; and the &lt;code&gt;square&lt;&#x2F;code&gt; function itself aren&#x27;t present anymore. Instead, the program simply returns a constant &lt;code&gt;100&lt;&#x2F;code&gt;, which happens to be the result of out &lt;code&gt;square(10)&lt;&#x2F;code&gt; call. The function call has been evaluated at compile time.&lt;&#x2F;p&gt;
&lt;p&gt;It seems like the compiler&#x27;s evaluation of &lt;code&gt;const fn&lt;&#x2F;code&gt;s depends on the optimization mode (debug &#x2F; release). Just to make sure, let&#x27;s try the same example with optimizations, but this time using a non-const &lt;code&gt;square&lt;&#x2F;code&gt; function (&lt;a href=&quot;https:&#x2F;&#x2F;godbolt.org&#x2F;z&#x2F;ooK9sonMq&quot;&gt;godbolt.org&lt;&#x2F;a&gt;):&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;asm&quot; style=&quot;background-color:#2e3440;color:#d8dee9;&quot; class=&quot;language-asm &quot;&gt;&lt;code class=&quot;language-asm&quot; data-lang=&quot;asm&quot;&gt;&lt;span style=&quot;color:#88c0d0;&quot;&gt;example::main:
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#88c0d0;&quot;&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#81a1c1;&quot;&gt;push    &lt;&#x2F;span&gt;&lt;span&gt;rax
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#88c0d0;&quot;&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#81a1c1;&quot;&gt;mov     &lt;&#x2F;span&gt;&lt;span&gt;edi, 100
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#88c0d0;&quot;&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#81a1c1;&quot;&gt;call    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#88c0d0;&quot;&gt;qword ptr &lt;&#x2F;span&gt;&lt;span&gt;[rip + &lt;&#x2F;span&gt;&lt;span style=&quot;color:#81a1c1;&quot;&gt;std&lt;&#x2F;span&gt;&lt;span style=&quot;color:#88c0d0;&quot;&gt;::process::exit@GOTPCREL&lt;&#x2F;span&gt;&lt;span&gt;]
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;It&#x27;s the same output as before! Our regular function &lt;code&gt;square&lt;&#x2F;code&gt; has been evaluated at compile time. What&#x27;s going on here?&lt;&#x2F;p&gt;
&lt;h2 id=&quot;constant-propagation&quot;&gt;Constant propagation&lt;&#x2F;h2&gt;
&lt;p&gt;We&#x27;re seeing compiler optimizations in action here, most likely &lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Inline_expansion&quot;&gt;function inlining&lt;&#x2F;a&gt; and &lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Constant_folding&quot;&gt;constant propagation&lt;&#x2F;a&gt;. The Rust compiler uses llvm to generate machine code and when compiling in release mode, llvm applies lots of clever optimizations to the code it is given. These are general optimization techniques and for them to work it doesn&#x27;t matter whether we declared the function as &lt;code&gt;const&lt;&#x2F;code&gt; or not. The downside of these optimizations is that in general, we can&#x27;t rely on the optimization to work. The outcome depends on optimization flags (as we&#x27;ve seen before) and might also change when updating to another version of the compiler. For simple programs like the example we&#x27;ve used, these optimizations are very likely to work, but they probably won&#x27;t be able to handle more complex cases.&lt;&#x2F;p&gt;
&lt;p&gt;Let&#x27;s try this with a function that&#x27;s a bit more complex: &lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#2e3440;color:#d8dee9;&quot; class=&quot;language-rust &quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span style=&quot;color:#81a1c1;&quot;&gt;const fn &lt;&#x2F;span&gt;&lt;span style=&quot;color:#88c0d0;&quot;&gt;fib&lt;&#x2F;span&gt;&lt;span&gt;(n&lt;&#x2F;span&gt;&lt;span style=&quot;color:#eceff4;&quot;&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#81a1c1;&quot;&gt;i32&lt;&#x2F;span&gt;&lt;span&gt;) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#eceff4;&quot;&gt;-&amp;gt; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#81a1c1;&quot;&gt;i32 &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#81a1c1;&quot;&gt;if&lt;&#x2F;span&gt;&lt;span&gt; n &lt;&#x2F;span&gt;&lt;span style=&quot;color:#81a1c1;&quot;&gt;&amp;lt; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;2 &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#81a1c1;&quot;&gt;return&lt;&#x2F;span&gt;&lt;span&gt; n&lt;&#x2F;span&gt;&lt;span style=&quot;color:#eceff4;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;    }
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#88c0d0;&quot;&gt;fib&lt;&#x2F;span&gt;&lt;span&gt;(n&lt;&#x2F;span&gt;&lt;span style=&quot;color:#81a1c1;&quot;&gt;-&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#81a1c1;&quot;&gt;+ &lt;&#x2F;span&gt;&lt;span style=&quot;color:#88c0d0;&quot;&gt;fib&lt;&#x2F;span&gt;&lt;span&gt;(n&lt;&#x2F;span&gt;&lt;span style=&quot;color:#81a1c1;&quot;&gt;-&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;2&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#81a1c1;&quot;&gt;pub fn &lt;&#x2F;span&gt;&lt;span style=&quot;color:#88c0d0;&quot;&gt;main&lt;&#x2F;span&gt;&lt;span&gt;() {
&lt;&#x2F;span&gt;&lt;span&gt;    std&lt;&#x2F;span&gt;&lt;span style=&quot;color:#81a1c1;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span&gt;process&lt;&#x2F;span&gt;&lt;span style=&quot;color:#81a1c1;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span&gt;exit(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#88c0d0;&quot;&gt;fib&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;10&lt;&#x2F;span&gt;&lt;span&gt;))&lt;&#x2F;span&gt;&lt;span style=&quot;color:#eceff4;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Compiling this code with optimizations enabled, we get the following &lt;code&gt;main&lt;&#x2F;code&gt; function (&lt;a href=&quot;https:&#x2F;&#x2F;godbolt.org&#x2F;z&#x2F;56GojPa56&quot;&gt;godbolt.org&lt;&#x2F;a&gt;):&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;asm&quot; style=&quot;background-color:#2e3440;color:#d8dee9;&quot; class=&quot;language-asm &quot;&gt;&lt;code class=&quot;language-asm&quot; data-lang=&quot;asm&quot;&gt;&lt;span style=&quot;color:#88c0d0;&quot;&gt;example::main:
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#88c0d0;&quot;&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#81a1c1;&quot;&gt;push    &lt;&#x2F;span&gt;&lt;span&gt;rax
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#88c0d0;&quot;&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#81a1c1;&quot;&gt;mov     &lt;&#x2F;span&gt;&lt;span&gt;edi, 10
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#88c0d0;&quot;&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#81a1c1;&quot;&gt;call    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#88c0d0;&quot;&gt;example::fib
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#88c0d0;&quot;&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#81a1c1;&quot;&gt;mov     &lt;&#x2F;span&gt;&lt;span&gt;edi, eax
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#88c0d0;&quot;&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#81a1c1;&quot;&gt;call    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#88c0d0;&quot;&gt;qword ptr &lt;&#x2F;span&gt;&lt;span&gt;[rip + &lt;&#x2F;span&gt;&lt;span style=&quot;color:#81a1c1;&quot;&gt;std&lt;&#x2F;span&gt;&lt;span style=&quot;color:#88c0d0;&quot;&gt;::process::exit@GOTPCREL&lt;&#x2F;span&gt;&lt;span&gt;]
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This time, the compiler optimizations were&#x27;t able to evaluate the function call at compile time.&lt;&#x2F;p&gt;
&lt;p&gt;We can still force the compile time evaluation by calling the function in a constant context:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#2e3440;color:#d8dee9;&quot; class=&quot;language-rust &quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span style=&quot;color:#81a1c1;&quot;&gt;pub fn &lt;&#x2F;span&gt;&lt;span style=&quot;color:#88c0d0;&quot;&gt;main&lt;&#x2F;span&gt;&lt;span&gt;() {
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#81a1c1;&quot;&gt;const &lt;&#x2F;span&gt;&lt;span&gt;RES&lt;&#x2F;span&gt;&lt;span style=&quot;color:#eceff4;&quot;&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#81a1c1;&quot;&gt;i32 = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#88c0d0;&quot;&gt;fib&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;10&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color:#eceff4;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;    std&lt;&#x2F;span&gt;&lt;span style=&quot;color:#81a1c1;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span&gt;process&lt;&#x2F;span&gt;&lt;span style=&quot;color:#81a1c1;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span&gt;exit(RES)&lt;&#x2F;span&gt;&lt;span style=&quot;color:#eceff4;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Compiling with optimizations (&lt;a href=&quot;https:&#x2F;&#x2F;godbolt.org&#x2F;z&#x2F;87GWEMT5W&quot;&gt;godbolt.org&lt;&#x2F;a&gt;):&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;asm&quot; style=&quot;background-color:#2e3440;color:#d8dee9;&quot; class=&quot;language-asm &quot;&gt;&lt;code class=&quot;language-asm&quot; data-lang=&quot;asm&quot;&gt;&lt;span style=&quot;color:#88c0d0;&quot;&gt;example::main:
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#88c0d0;&quot;&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#81a1c1;&quot;&gt;push    &lt;&#x2F;span&gt;&lt;span&gt;rax
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#88c0d0;&quot;&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#81a1c1;&quot;&gt;mov     &lt;&#x2F;span&gt;&lt;span&gt;edi, 55
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#88c0d0;&quot;&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#81a1c1;&quot;&gt;call    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#88c0d0;&quot;&gt;qword ptr &lt;&#x2F;span&gt;&lt;span&gt;[rip + &lt;&#x2F;span&gt;&lt;span style=&quot;color:#81a1c1;&quot;&gt;std&lt;&#x2F;span&gt;&lt;span style=&quot;color:#88c0d0;&quot;&gt;::process::exit@GOTPCREL&lt;&#x2F;span&gt;&lt;span&gt;]
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This time, the function has been evaluated at compile time and the main function simply returns the result of the &lt;code&gt;fib(10)&lt;&#x2F;code&gt; call, which is &lt;code&gt;55&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;rust-s-const-eval-policy&quot;&gt;Rust&#x27;s const eval policy&lt;&#x2F;h2&gt;
&lt;p&gt;The &lt;a href=&quot;https:&#x2F;&#x2F;doc.rust-lang.org&#x2F;reference&#x2F;const_eval.html&quot;&gt;Constant evaluation&lt;&#x2F;a&gt; chapter in the &lt;a href=&quot;https:&#x2F;&#x2F;doc.rust-lang.org&#x2F;reference&#x2F;const_eval.html&quot;&gt;Rust reference&lt;&#x2F;a&gt; contains the following statement regarding compile time evaluation (emphasis mine):&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;Certain forms of expressions, called constant expressions, can be evaluated at compile time. In const contexts, these are the only allowed expressions, and are always evaluated at compile time. &lt;strong&gt;In other places, such as let statements, constant expressions may be, but are not guaranteed to be, evaluated at compile time.&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;This means that when calling a &lt;code&gt;const fn&lt;&#x2F;code&gt; with const arguments and in a non-const context, Rust is free to decide whether to do compile time evaluation or not. From what I&#x27;ve seen and have been told, the Rust compiler &lt;em&gt;currently&lt;&#x2F;em&gt; doesn&#x27;t do compile time evaluation in these cases, but that might change in the future. &lt;&#x2F;p&gt;
&lt;h2 id=&quot;enforcing-compile-time-evaluation&quot;&gt;Enforcing compile time evaluation&lt;&#x2F;h2&gt;
&lt;p&gt;What if we want to make sure that a call to a &lt;code&gt;const fn&lt;&#x2F;code&gt; is evaluated at compile time? &lt;&#x2F;p&gt;
&lt;p&gt;One way to do it is to assign the result of the function call to a constant. This forces the function to be evaluated at compile time and I&#x27;ve used this trick in previous examples.&lt;&#x2F;p&gt;
&lt;p&gt;Instead of directly using the function from a non-const context&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#2e3440;color:#d8dee9;&quot; class=&quot;language-rust &quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span style=&quot;color:#81a1c1;&quot;&gt;pub fn &lt;&#x2F;span&gt;&lt;span style=&quot;color:#88c0d0;&quot;&gt;main&lt;&#x2F;span&gt;&lt;span&gt;() {
&lt;&#x2F;span&gt;&lt;span&gt;    std&lt;&#x2F;span&gt;&lt;span style=&quot;color:#81a1c1;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span&gt;process&lt;&#x2F;span&gt;&lt;span style=&quot;color:#81a1c1;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span&gt;exit(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#88c0d0;&quot;&gt;fib&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;10&lt;&#x2F;span&gt;&lt;span&gt;))&lt;&#x2F;span&gt;&lt;span style=&quot;color:#eceff4;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;you simply write assign the result of the function to a constant and use the constant&#x27;s value in the non-const context:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#2e3440;color:#d8dee9;&quot; class=&quot;language-rust &quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span style=&quot;color:#81a1c1;&quot;&gt;pub fn &lt;&#x2F;span&gt;&lt;span style=&quot;color:#88c0d0;&quot;&gt;main&lt;&#x2F;span&gt;&lt;span&gt;() {
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#81a1c1;&quot;&gt;const &lt;&#x2F;span&gt;&lt;span&gt;RES&lt;&#x2F;span&gt;&lt;span style=&quot;color:#eceff4;&quot;&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#81a1c1;&quot;&gt;i32 = &lt;&#x2F;span&gt;&lt;span style=&quot;color:#88c0d0;&quot;&gt;fib&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;10&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color:#eceff4;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;    std&lt;&#x2F;span&gt;&lt;span style=&quot;color:#81a1c1;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span&gt;process&lt;&#x2F;span&gt;&lt;span style=&quot;color:#81a1c1;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span&gt;exit(RES)&lt;&#x2F;span&gt;&lt;span style=&quot;color:#eceff4;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This has been the only way to ensure compile time evaluation for a long time, but has two downsides. It introduces an extra declaration and since it&#x27;s a constant, you&#x27;re required to explicitly state the type.&lt;&#x2F;p&gt;
&lt;p&gt;Fortunately, Rust 1.79 (release in June 2024) introduced &lt;a href=&quot;https:&#x2F;&#x2F;blog.rust-lang.org&#x2F;2024&#x2F;06&#x2F;13&#x2F;Rust-1.79.0.html#inline-const-expressions&quot;&gt;inline &lt;code&gt;const&lt;&#x2F;code&gt; expressions&lt;&#x2F;a&gt;. Using them, it&#x27;s easy to force compile time evaluation:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#2e3440;color:#d8dee9;&quot; class=&quot;language-rust &quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span style=&quot;color:#81a1c1;&quot;&gt;pub fn &lt;&#x2F;span&gt;&lt;span style=&quot;color:#88c0d0;&quot;&gt;main&lt;&#x2F;span&gt;&lt;span&gt;() {
&lt;&#x2F;span&gt;&lt;span&gt;    std&lt;&#x2F;span&gt;&lt;span style=&quot;color:#81a1c1;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span&gt;process&lt;&#x2F;span&gt;&lt;span style=&quot;color:#81a1c1;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span&gt;exit(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#81a1c1;&quot;&gt;const &lt;&#x2F;span&gt;&lt;span&gt;{ &lt;&#x2F;span&gt;&lt;span style=&quot;color:#88c0d0;&quot;&gt;fib&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b48ead;&quot;&gt;10&lt;&#x2F;span&gt;&lt;span&gt;) })&lt;&#x2F;span&gt;&lt;span style=&quot;color:#eceff4;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h2 id=&quot;summary&quot;&gt;Summary&lt;&#x2F;h2&gt;
&lt;p&gt;Here&#x27;s a short TL;DR of the post:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;const fn&lt;&#x2F;code&gt;s in Rust can be evaluated at compile time, but can also be compiled and executed at runtime just like regular functions.&lt;&#x2F;li&gt;
&lt;li&gt;What happens depends on the arguments and the context in which a &lt;code&gt;const fn&lt;&#x2F;code&gt; is used.&lt;&#x2F;li&gt;
&lt;li&gt;For function calls that could either be compile time evaluated or not, the Rust compiler &lt;em&gt;currently&lt;&#x2F;em&gt; seems to be conservative and doesn&#x27;t seem to do compile time evaluation.&lt;&#x2F;li&gt;
&lt;li&gt;General code optimization passes in the compiler backend (llvm) can do inlining and constant propagation though, which can have the same effect on the output. &lt;&#x2F;li&gt;
&lt;li&gt;To make sure that a function call is evaluated at compile time, wrap it with a constant declaration or use &lt;a href=&quot;https:&#x2F;&#x2F;blog.rust-lang.org&#x2F;2024&#x2F;06&#x2F;13&#x2F;Rust-1.79.0.html#inline-const-expressions&quot;&gt;inline &lt;code&gt;const&lt;&#x2F;code&gt; expressions&lt;&#x2F;a&gt;.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Thanks to oli_obk for answering my questions and providing feedback on an earlier version of this post!&lt;&#x2F;p&gt;
&lt;p&gt;Discussion on &lt;a href=&quot;https:&#x2F;&#x2F;www.reddit.com&#x2F;r&#x2F;rust&#x2F;comments&#x2F;1j8oupb&#x2F;blog_when_are_rusts_const_fns_executed&#x2F;&quot;&gt;reddit&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
</content>
    </entry>
    <entry xml:lang="en">
        <title>Hello World²</title>
        <published>2024-04-25T00:00:00+00:00</published>
        <updated>2024-04-25T00:00:00+00:00</updated>
        <author>
          <name>Felix</name>
        </author>
        <link rel="alternate" href="/posts/hello-world-2/" type="text/html"/>
        <id>/posts/hello-world-2/</id>
        <content type="html">&lt;p&gt;This is my new second-generation blog, enjoy!&lt;&#x2F;p&gt;
</content>
    </entry>
</feed>
