Skip to content

Latest commit

 

History

History
71 lines (53 loc) · 2.54 KB

0000-undefined-intrinsic.md

File metadata and controls

71 lines (53 loc) · 2.54 KB
  • Feature Name: undefined_intrinsic
  • Start Date: 2015-01-25
  • RFC PR: (leave this empty)
  • Rust Issue: (leave this empty)

Summary

Translate undefined generic intrinsics to an LLVM unreachable and a lint.

Motivation

Many generic intrinsics are only defined for particular type substitutions. For example, transmute is only defined when both arguments have the same size, and atomic operations are only defined for types with a CPU-supported size and alignmen.

Unsafe code often desires to do these operations opportunistically - for example, to use an atomic operation if that is supported, and to otherwise default to mutual exclusion.

In addition, the precise constraints required by these operations are hard to encode in the type-system, which means that even if we wanted to use specialization for opportunsitic operations, we would be restricted.

Finally, the current strategy for handling undefined intrinsics is to cause compilation errors in a fairly fragmented and buggy way (that's it, either rustc errors or LLVM assertions). As that kind of undefined use is often unintentional, this has the useful effect of not causing subtle crashes, but is obviously suboptimal.

Detailed design

When translating an undefined intrinsic, translate it to an LLVM unreachable instruction, without causing an error or emitting invalid LLVM-IR.

This is not a safety issue as intrinsics are unsafe, and unsafe code can easily cause an LLVM unreachable through generating code that exhibits UB.

To retain the error-detecting effect of the previous strategy, introduce a undefined_intrinsic lint, which should warn when an unreachable is generated in this way. As intrinsics are generated by monomorphization, the lint would need to be stored in metadata.

Drawbacks

Metadata lints are annoying and may pose implementation difficulties. In addition they make intrinsic reexports more different from intrinsic wrappers than they are now.

If we do not check generic functions, we risk accidental modifications causing hard-to-track unreachable generation and code erasure. Luckily, unlike other kinds of UB, these unreachable instructions would still appear in debug mode.

Alternatives

  • Keep the current fragmented strategy, with its disadvantages.
  • Do not do the undefined_intrinsic check on generic functions, or cross-crate instantiations.

Unresolved questions

What should we do with the lint?