<p dir="auto">By accident I came across an ICE from this code: <code class="notranslate">(-1.0 as usize,)</code>. The ICE is triggered by an assertion while building the constant tuple. The field has a value of <code class="notranslate">undef</code>.</p>
<p dir="auto">Looking into it, the two floating point to integer cast instructions, <code class="notranslate">fptoui</code> and <code class="notranslate">fptosi</code> have a very large surface for producing undefined values. Any time the result cannot fit into the destination type, the result is undefined. This means casting from a negative float to an unsigned integer is undefined and casting from a float with a value outside the range for the target integer type (signed or otherwise) is undefined.</p>
<p dir="auto">Some possible solutions:</p>
<ol dir="auto">
<li>Treat it as an error always. This means generating an assertion before the cast, similar to how we generate assertions to check for divide-by-zero.</li>
<li>Clamp the value. Casting from outside the valid range will clamp to one end of the range. so <code class="notranslate">-1.0 as u32</code> would produce <code class="notranslate">0</code>.</li>
<li>A combination of both. Treat the case similarly to how we treat integer overflow and emit an assertion in debug builds, but omit them in release builds, falling back to the clamping behaviour.</li>
</ol>
<p dir="auto">I'm personally leaning towards 3. Most of the time an invalid cast of this nature will be unintentional, so protecting against it seems reasonable. The problem is also similar enough to overflowing that handling it similarly seems reasonable.</p>
<p dir="auto">/cc <a class="team-mention js-team-mention notranslate" data-error-text="Failed to load team members" data-id="1508062" data-permission-text="Team members are private" data-url="/orgs/rust-lang/teams/compiler/members" data-hovercard-type="team" data-hovercard-url="/orgs/rust-lang/teams/compiler/hovercard" href="https://github.com/orgs/rust-lang/teams/compiler">@rust-lang/compiler</a> <a class="team-mention js-team-mention notranslate" data-error-text="Failed to load team members" data-id="1508058" data-permission-text="Team members are private" data-url="/orgs/rust-lang/teams/lang/members" data-hovercard-type="team" data-hovercard-url="/orgs/rust-lang/teams/lang/hovercard" href="https://github.com/orgs/rust-lang/teams/lang">@rust-lang/lang</a></p>
<h3 dir="auto">Status as of 2020-04-18</h3>
<p dir="auto">We intend to stabilize the saturating-float-casts behavior for <code class="notranslate">as</code>, and have stabilized unsafe library functions that handle the previous behavior. See <a class="issue-link js-issue-link" data-error-text="Failed to load title" data-id="602353172" data-permission-text="Title is private" data-url="https://github.com/rust-lang/rust/issues/71269" data-hovercard-type="pull_request" data-hovercard-url="/rust-lang/rust/pull/71269/hovercard" href="https://github.com/rust-lang/rust/pull/71269">#71269</a> for the latest discussion on that stabilization process.</p>
<h3 dir="auto">Status as of 2018-11-05</h3>
<p dir="auto">A flag has been implemented in the compiler, <code class="notranslate">-Zsaturating-float-casts</code>, which will cause all float to integer casts have "saturating" behavior where if it's out of bounds it's clamped to the nearest bound. A <a href="https://internals.rust-lang.org/t/help-us-benchmark-saturating-float-casts/6231" rel="nofollow">call for benchmarking</a> of this change went out awhile ago. Results, while positive in many projects, are <a href="https://github.com/rust-lang/rust/issues/10184#issuecomment-429663706" data-hovercard-type="issue" data-hovercard-url="/rust-lang/rust/issues/10184/hovercard">quite negative for some projects</a> and indicates that we're not done here.</p>
<p dir="auto">The next steps are figuring out how to recover performance for these cases:</p>
<ul dir="auto">
<li>One option is to take today's <code class="notranslate">as</code> cast behavior (which is UB in some cases) and add <code class="notranslate">unsafe</code> functions for the relevant types and such.</li>
<li>Another is to wait for LLVM to add a <code class="notranslate">freeze</code> concept which means that we get a garbage bit pattern, but it's at least not UB</li>
<li>Another is to implement casts via inline assembly in LLVM IR, as the current codegen is not heavily optimized.</li>
</ul>
<h2 dir="auto">Old status</h2>
<p dir="auto"><strong>UPDATE (by <a class="user-mention notranslate" data-hovercard-type="user" data-hovercard-url="/users/nikomatsakis/hovercard" data-octo-click="hovercard-link-click" data-octo-dimensions="link_type:self" href="https://github.com/nikomatsakis">@nikomatsakis</a>):</strong> After much discussion, we've got <a href="https://github.com/rust-lang/rust/issues/10184#issuecomment-302198137" data-hovercard-type="issue" data-hovercard-url="/rust-lang/rust/issues/10184/hovercard">the rudiments of a plan</a> for how to address this problem. But we need some help with actually investigating the performance impact and working out the final details!</p>
<hr>
<p dir="auto"><strong>ORIGINAL ISSUE FOLLOWS:</strong></p>
<blockquote>
<p dir="auto">If the value cannot fit in ty2, the results are undefined.</p>
</blockquote>
<div class="highlight highlight-source-rust notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="1.04E+17 as u8"><pre class="notranslate"><span class="pl-c1">1.04E+17</span> <span class="pl-k">as</span> <span class="pl-smi">u8</span><span class="pl-kos"></span></pre></div>