Summary

Stabilize implementing

実装する
panics as aborts.

  • Stabilize the -Z no-landing-pads flag under the name -C panic=strategy
  • Implement
    実装する
    a number of unstable features akin to custom allocators to swap out implementations
    実装
    of panic just before a final product is generated.
    生成する
  • Add a [profile.dev] option to Cargo to configure how panics are implemented.
    実装する

Motivation

Panics in Rust have long since been implemented

実装する
with the intention of being caught at particular boundaries (for example the thread boundary). This is quite useful for isolating failures in Rust code, for example:

  • Servers can avoid
    避ける、回避する
    taking
    とる
    down the entire process but can instead just take
    とる
    down one request.
  • Embedded
    埋め込む
    Rust libraries can avoid
    避ける、回避する
    taking
    とる
    down the entire process and can instead gracefully inform the caller
    呼び出し側
    that an internal logic error occurred.
    起こる
  • Rust applications can isolate failure from various
    さまざまな
    components.
    構成要素
    The classical example of this is Servo can display a "red X" for an image which fails to decode instead of aborting the entire browser or killing an entire page.

While these are examples where a recoverable panic is useful, there are many applications where recovering panics is undesirable or doesn't lead to anything productive:

  • Rust applications which use Result for error handling typically
    一般的に、典型的に
    use panic! to indicate
    指し示す
    a fatal error, in which case the process should be taken down.
  • Many applications simply can't recover from an internal assertion
    アサーション
    failure, so there's no need trying to recover it.
  • To implement
    実装する
    a recoverable panic, the compiler and standard library use a method called
    呼び出し
    stack unwinding. The compiler must generate code to support this unwinding, however, and this takes
    とる
    time in codegen and optimizers.
  • Low-level applications typically
    一般的に、典型的に
    don't use unwinding at all as there's no stack unwinder (e.g. kernels).

Note: as an idea of the compile-time and object-size savings from disabling the extra codegen, compiling Cargo as a library is 11% faster (16s from 18s) and 13% smaller (15MB to 13MB). Sizable gains!

Overall, the ability to recover panics is something that needs to be decided at the application level rather than at the language

言語
level. Currently the compiler does not support the ability to translate panics to process aborts in a stable fashion, and the purpose of this RFC is to add such a venue.

With such an important codegen option, however, as whether or not exceptions

例外
can be caught, it's easy to get into a situation where libraries of mixed compilation modes are linked together, causing odd or unknown errors. This RFC proposes a situation similar
似ている、同様の
to the design
設計(する)
of custom allocators to alleviate this situation.

Detailed design
設計(する)

The major goal of this RFC is to develop a work flow around managing crates which wish to disable unwinding. This intends to set

セットする、集合
forth a complete
完全な
vision for how these crates interact with the ecosystem at large. Much of this design
設計(する)
will be similar
似ている、同様の
to the custom allocator RFC.

High level design
設計(する)

This section

serves
働く、用をなす
as a high-level tour through the design
設計(する)
proposed in this RFC. The linked sections
provide
与える
more complete
完全な
explanation as to what each step entails.

  • The compiler will have a new stable flag, -C panic which will configure how unwinding-related code is generated.
    生成する
  • Two new unstable attributes will be added
    たす
    to the compiler, #![needs_panic_runtime] and #![panic_runtime]. The standard library will need a runtime and will be lazily linked to a crate which has #![panic_runtime].
  • Two unstable crates tagged with #![panic_runtime] will be distributed as the runtime implementation
    実装
    of panicking, panic_abort and panic_unwind crates. The former will translate all panics to process aborts, whereas the latter will be implemented
    実装する
    as unwinding is today, via the system stack unwinder.
  • Cargo will gain a new panic option in the [profile.foo] sections
    to indicate
    指し示す
    how that profile should compile panic support.

New Compiler Flags

The first component

構成要素
to this design
設計(する)
is to have a stable flag to the compiler which configures how panic-related code is generated.
生成する
This will be stabilized in the form:
形式、形態、形作る

$ rustc -C help Available codegen options: ... -C panic=val -- strategy to compile in for panic related code ...

There will currently be two supported strategies:

  • unwind - this is what the compiler implements
    実装する
    by default today via the invoke LLVM instruction.
    命令
  • abort - this will implement
    実装する
    that -Z no-landing-pads does today, which is to disable the invoke instruction
    命令
    and use call instead everywhere.

This codegen option will default to unwind if not specified

特定する、指定する、規定する
(what happens today), and the value will be encoded
符号化する
into the crate metadata. This option is planned with extensibility in mind to future panic strategies if we ever implement
実装する
some (return-based unwinding is at least one other possible option).

Panic Attributes

Very similarly

同様に
to custom allocators, two new unstable crate attributes will be added
たす
to the compiler:

  • #![needs_panic_runtime] - indicates that this crate requires a "panic runtime" to link correctly. This will be attached to the standard library and is not intended to be attached to any other crate.
  • #![panic_runtime] - indicates that this crate is a runtime implementation
    実装
    of panics.

As with allocators, there are a number of limitations imposed by these attributes by the compiler:

  • Any crate DAG can only contain
    含む
    at most one instance
    実例
    of #![panic_runtime].
  • Implicit
    暗黙の
    dependency
    依存、依存関係
    edges are drawn from crates tagged with #![needs_panic_runtime] to those tagged with #![panic_runtime]. Loops as usual are forbidden (e.g. a panic runtime can't depend on libstd).
  • Complete
    完全な
    artifacts which include a crate tagged with #![needs_panic_runtime] must include a panic runtime. This includes executables, dylibs, and staticlibs. If no panic runtime is explicitly
    明示的に
    linked, then the compiler will select an appropriate runtime to inject.
  • Finally, the compiler will ensure
    保証する
    that panic runtimes and compilation modes are not mismatched. For a final product (outputs that aren't rlibs) the -C panic mode of the panic runtime must match
    一致する、マッチさせる
    the final product itself. If the panic mode is abort, then no other validation is performed, but otherwise
    さもなければ
    all crates in the DAG must have the same value of -C panic.

The purpose of these limitations is to solve a number of problems that arise when switching panic strategies. For example with aborting panic crates won't have to link to runtime support of unwinding, or rustc will disallow

許可しない
mixing panic strategies by accident.

The actual

実際の
API of panic runtimes will not be detailed in this RFC. These new attributes will be unstable, and consequently
結果として
the API itself will also be unstable. It suffices to say, however, that like custom allocators a panic runtime will implement
実装する
some public extern symbols known to the crates that need a panic runtime, and that's how they'll communicate/link up.

Panic Crates

Two new unstable crates will be added

たす
to the distribution for each target:

  • panic_unwind - this is an extraction of the current implementation
    実装
    of panicking from the standard library. It will use the same mechanism
    仕組み、機構
    of stack unwinding as is implemented
    実装する
    on all current platforms.
  • panic_abort - this is a new implementation
    実装
    of panicking which will simply translate unwinding to process aborts. There will be no runtime support required by this crate.

The compiler will assume

仮定する
that these crates are distributed for each platform where the standard library is also distributed (e.g. a crate that has #![needs_panic_runtime]).

Compiler defaults

The compiler will ship with a few defaults which affect how panic runtimes are selected in Rust programs. Specifically:

特に

  • The -C panic option will default to unwind as it does today.

  • The libtest crate will explicitly

    明示的に
    link to panic_unwind. The test runner that libtest implements
    実装する
    relies on equating panics with failure and cannot work if panics are translated to aborts.

  • If no panic runtime is explicitly

    明示的に
    selected, the compiler will employ the following logic to decide what panic runtime to inject:

    1. If any crate in the DAG is compiled with -C panic=abort, then panic_abort will be injected.
    2. If all crates in the DAG are compiled with -C panic=unwind, then panic_unwind is injected.

Cargo changes

In order

順序
to export this new feature to Cargo projects, a new option will be added
たす
to the [profile] section
of manifests:

[profile.dev] panic = 'unwind'

This will cause

起こす
Cargo to pass -C panic=unwind to all rustc invocations
呼び出し
for a crate graph. Cargo will have special knowledge, however, that for cargo test it cannot pass -C panic=abort.

Drawbacks

  • The implementation

    実装
    of custom allocators was no small feat in the compiler, and much of this RFC is essentially the same thing. Similar
    似ている、同様の
    infrastructure can likely be leveraged to alleviate the implementation
    実装
    complexity, but this is undeniably a large change to the compiler for albeit a relatively minor option. The counter point to this, however, is that disabling unwinding in a principled fashion provides
    与える
    far higher quality error messages, prevents
    防ぐ
    erroneous
    誤った、間違いの
    situations, and provides
    与える
    an immediate benefit for many Rust users today.

  • The binary

    2進数
    distribution of the standard library will not change from what it is today. In other words, the standard library (and dependency
    依存、依存関係
    crates like libcore) will be compiled with -C panic=unwind. This introduces the opportunity for extra code bloat or missed optimizations in applications that end up disabling unwinding in the long run. Distribution, however, is far easier because there's only one copy of the standard library and we don't have to rely on any other form
    形式、形態、形作る
    of infrastructure.

  • This represents

    表現する
    a proliferation of the #![needs_foo] and #![foo] style system that allocators have begun. This may be indicative of a deeper underlying
    裏に潜んだ、背後の
    requirement here of the standard library or perhaps showing how the strategy in the standard library needs to change. If the standard library were a crates.io crate it would arguably support these options via Cargo features, but without that option is this the best way to be implementing
    実装する
    these switches for the standard library?

Alternatives

  • Currently this RFC allows

    許可する、可能にする
    mixing multiple
    複数の
    panic runtimes in a crate graph so long as the actual
    実際の
    runtime is compiled with -C panic=abort. This is primarily done to immediately
    直後に、直接的に
    reap benefit from -C panic=abort even though the standard library we distribute will still have unwinding support compiled in (compiled with -C panic=unwind). In the not-too-distant future however, we will likely be poised to distribute multiple
    複数の
    binary
    2進数
    copies of the standard library compiled with different profiles. We may be able to tighten this restriction
    制限
    on behalf of the compiler, requiring that all crates in a DAG have the same -C panic compilation mode, but there would unfortunately be no immediate benefit to implementing
    実装する
    the RFC from users of our precompiled nightlies.

    This alternative,

    代わりのもの、選択肢
    additionally, can also be viewed as a drawback. It's unclear what a future libstd distribution mechanism
    仕組み、機構
    would look like and how this RFC might interact with it. Stabilizing disabling unwinding via a compiler switch or a Cargo profile option may not end up meshing well with the strategy we pursue with shipping multiple
    複数の
    standard libraries.

  • Instead of the panic runtime support in this RFC, we could instead just ship two different copies of the standard library where one simply translates panics to abort instead of unwinding. This is unfortunately very difficult for Cargo or the compiler to track, however, to ensure

    保証する
    that the codegen option of how panics are translated is propagated throughout the rest of the crate graph. Additionally it may be easy to mix up crates of different panic strategies.

Unresolved questions

  • One possible implementation

    実装
    of unwinding is via return-based flags. Much of this RFC is designed
    設計(する)
    with the intention of supporting arbitrary
    任意の
    unwinding implementations,
    実装
    but it's unclear whether it's too heavily biased towards panic is either unwinding or aborting.

  • The current implementation

    実装
    of Cargo would mean that a naive implementation
    実装
    of the profile option would cause
    起こす
    recompiles between cargo build and cargo test for projects that specify
    特定する、指定する、規定する
    panic = 'abort'. Is this acceptable? Should Cargo cache both copies of the crate?