Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

translate undefined intrinsics to an unreachable and a lint #1478

Closed
wants to merge 1 commit into from
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
71 changes: 71 additions & 0 deletions text/0000-undefined-intrinsic.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
- Feature Name: undefined_intrinsic
- Start Date: 2015-01-25
- RFC PR: (leave this empty)
- Rust Issue: (leave this empty)

# Summary
[summary]: #summary

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

# Motivation
[motivation]: #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
[design]: #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
[drawbacks]: #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
[alternatives]: #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
[unresolved]: #unresolved-questions

What should we do with the lint?