Skip to content

Stabilize RFC 2345: Allow panicking in constants #85194

Closed

Description

@nikomatsakis

Stabilization report

🛑 Issue with Rust 2021 🛑

Stabilization is currently blocked on resolving how this works with Rust 2021

Summary

This feature allows panicking within constants and reporting a custom message as a compile-time error.

The following code will become valid on stable:

const fn foo(val: u8) {
    assert!(val == 1, "val is not 1");
}

const MSG: &str = "custom message";

const _: () = std::panic!(MSG);
const _: () = panic!("custom message");

The message looks like:

error: any use of this value will cause an error
 --> src/main.rs:4:15
  |
4 | const _: () = std::panic!(MSG);
  | --------------^^^^^^^^^^^^^^^^-
  |               |
  |               the evaluated program panicked at 'custom message', src/main.rs:4:15
  |
  = note: `#[deny(const_err)]` on by default
  = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
  = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
  = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)

Motivation for this RFC can be found here: https://rust-lang.github.io/rfcs/2345-const-panic.html#motivation

More examples can be found here: https://github.com/rust-lang/rust/blob/673d0db5e393e9c64897005b470bfeb6d5aec61b/src/test/ui/consts/const-eval/const_panic.rs

Edge cases & tests

Some questions which should be resolved in the future

We have some "unresolved questions" but they aren't an actual blocker.

  • Should there be some additional message in the error about this being a panic turned error?
    Or do we just produce the exact message the panic would produce?
  • This change becomes really useful if Result::unwrap and Option::unwrap become const fn, doing both in one go might be a good idea.

See the brief summary comment here: #51999 (comment)

Originally posted by @JohnTitor in #51999 (comment)

Activity

  1. Aaron1011 commented on May 11, 2021

    @Aaron1011
    Contributor

    One additional unresolved question that @RalfJung had brought up previously - do we ever want to allow catching panics in constants? The only issue I can think of would be users expecting panic!() to always abort compilation - but users should be aware that panics can be caught, especially if they're writing a const fn, which can also be called at runtime.

  2. nikomatsakis commented on May 11, 2021

    @nikomatsakis
    ContributorAuthor

    Is the question really about whether we want to allow catching panics in constants?

  3. Aaron1011 commented on May 11, 2021

    @Aaron1011
    Contributor

    IIRC, the original question was about whether panic!() is compatible with later deciding we want to allow catching panics in constants.

  4. Nemo157 commented on May 11, 2021

    @Nemo157
    Contributor
    const MSG: &str = "custom message";
    const _: () = std::panic!(MSG);

    This specific example triggers the non_fmt_panic lint, and will not compile in Edition 2021. To support usecases like this we would need to make std::panic::panic_any a const fn too (or get support for traits-in-const to allow using the format machinery).

  5. nikomatsakis commented on May 11, 2021

    @nikomatsakis
    ContributorAuthor

    @Aaron1011 so in other words, the question is, will someone write a constant that panics and assumes that this panic aborts compilation in some crucial way, but then we introduce a wrapper that captures the panic, and now the safety guarantee is not upheld?

  6. jhpratt commented on May 11, 2021

    @jhpratt
    Member

    Personally I'd like to be able to panic in a const context to perform data validation from a macro. This would allow me to eliminate a procedural macro. If a const panic could be caught, that would effectively eliminate the ability to validate data (I think, feel free to correct me).

    Reference to what I hope will be possible once const_panic is stabilized: time-rs/time#322

  7. rodrimati1992 commented on May 12, 2021

    @rodrimati1992
    Contributor

    @jhpratt The code in that issue would not be affected by catch_unwind being usable in const contexts, since it stores the validated data in a const before returning it.

  8. CodesInChaos commented on May 12, 2021

    @CodesInChaos

    @Nemo157 In my comment on the original issue I proposed other options, which might be easier to implement:

    1. make formatting work for string slice arguments, without relying on formatting traits
    2. make the precise pattern panic!("{}", str) work, where str is a string slice
    3. make panic_any const, but only if the argument is a string slice.
  9. nikomatsakis commented on May 13, 2021

    @nikomatsakis
    ContributorAuthor

    I'd like an example where there is a panic that should abort compilation but catching it would produce a problem -- it feels like the panic erases the const value being produced, so I'm not clear on what kind of error would be swallowed that would be a problem.

  10. RalfJung commented on May 13, 2021

    @RalfJung
    Member

    @Aaron1011 wrote

    One additional unresolved question that @RalfJung had brought up previously - do we ever want to allow panicking in constants?

    I am confused -- yes we do want to allow panicking in constants...?

    EDIT: Oh, I guess you forgot a "catch" somewhere... could you edit the text? Looks like I am not the only one who got confused. ;)

  11. RalfJung commented on May 13, 2021

    @RalfJung
    Member

    it feels like the panic erases the const value being produced, so I'm not clear on what kind of error would be swallowed that would be a problem.

    I guess if a const fn would perform some validation and then return (), if you can catch panics you can circumvent this validation.

    But I don't see how this would be any more problematic at compile-time than it is at run-time.

  12. RalfJung commented on May 13, 2021

    @RalfJung
    Member

    Another question that came up is if we should change the error that is emitted when a const/static panic such that it can not be allowed. I am sympathetic to that idea. The only reason CTFE error can be allowed at all is backwards compatibility, and there is no such concern with panics.

  13. nikomatsakis commented on May 13, 2021

    @nikomatsakis
    ContributorAuthor

    I see. I definitely think it should be a hard error.

  14. lachlansneff commented on May 16, 2021

    @lachlansneff

    Are unwrap and expect going to be stabilized at the same time as this?

  15. RalfJung commented on May 16, 2021

    @RalfJung
    Member

    Option::unwrap can be stabilized; the others require parts of the format! machinery that are not const-compatible (they will be, eventually, but that'll require a lot of other infrastructure first).

  16. 28 remaining items

  17. removed
    proposed-final-comment-periodProposed to merge/close by relevant subteam, see T-<team> label. Will enter FCP once signed off.
    disposition-mergeThis issue / PR is in PFCP or FCP with a disposition to merge it.
    on Jun 22, 2021
  18. added a commit that references this issue on Jun 27, 2021
  19. nbdd0121 commented on Jul 4, 2021

    @nbdd0121
    Member

    Is it possible to special-case Rust 2021 panic!("{}", expr) to mean Rust 2015 panic!(expr)?

  20. m-ou-se commented on Jul 5, 2021

    @m-ou-se
    Member

    @nbdd0121 Those are not the same:

    • panic!("{}", 123); throws a String containing "123". panic!(123) throws an i32 with the value 123.
    • panic!("{}", &some_temporary) is valid, while panic!(&some_temporary) is not.

    We can make panic_any(expr) work in constants, but that function only exists in std, not in core.

  21. clarfonthey commented on Sep 6, 2021

    @clarfonthey
    Contributor

    So, I see that there are a lot of blockers on the 2021-edition-style panicking, but I don't actually know what the plan is for this. Got lead here from the tracking issue for #53188, which is blocked on this but still open.

    Is the plan to just never allow panicking in const functions, ever? That seems wrong. Are we blocking it on const trait impls to ensure that arbitrary panic! can be const? It seems like closing this issue without pointing to a replacement is a bit confusing.

  22. jhpratt commented on Sep 6, 2021

    @jhpratt
    Member

    Personally I'd like to see const panic with only string literals supported — this would permit things along the lines of (debug) assertions so long as a custom message is provided. Something is better than nothing.

  23. clarfonthey commented on Sep 6, 2021

    @clarfonthey
    Contributor

    I should add that @m-ou-se opened #78356 to help make the literal-only case identical on 2021 edition, which is mostly the primary blocker.

  24. m-ou-se commented on Sep 6, 2021

    @m-ou-se
    Member

    @clarfonthey There's multiple ways forward:

    In addition, I've heard this idea floating around to make const_panic enable some kind of -Z unleash-the-miri-inside-of-you-like thing on panic!(). (cc @oli-obk) The idea is that since compilation is going to fail/panic anyway, the compiler doesn't have to follow the strict const evaluation rules anymore and can just try to evaluate anything to try to generate the full panic message, regardless of if Display implementations etc. were marked as const. (Miri can already evaluate pretty much all of them, as long as they don't open files etc.)

  25. jhpratt commented on Sep 6, 2021

    @jhpratt
    Member
    • panic!("literal") already works in Rust 2021 starting in 1.56:

    Still unstably by the looks of it? playground

    Just asking for clarity purposes because your wording makes it sound like that subset has been stabilized.

  26. m-ou-se commented on Sep 6, 2021

    @m-ou-se
    Member

    Yes, gated behind const_panic, like all const panic, yes.

  27. m-ou-se commented on Sep 6, 2021

    @m-ou-se
    Member

    @clarfonthey Note that this issue was just for the stabilization report.

    The tracking issue for const_panic is here, and still open and active: #51999

  28. clarfonthey commented on Sep 6, 2021

    @clarfonthey
    Contributor

    Oh! That makes a lot of sense now.

  29. CodesInChaos commented on Sep 6, 2021

    @CodesInChaos

    I'd like to see at least panic!(literal) stabilized as soon as possible. I believe that case has no open concerns, and it's already much clearer than the index-out-of-bounds hacks people use at the moment.

  30. nbdd0121 commented on Sep 7, 2021

    @nbdd0121
    Member

    I'd like to see at least panic!(literal) stabilized as soon as possible. I believe that case has no open concerns, and it's already much clearer than the index-out-of-bounds hacks people use at the moment.

    The issue is that we want all code that works in Rust 2018 to work (or auto-fixed to working code) in Rust 2021. If we stablise panic!(literal), then panic!("{}") works in Rust 2018 but not work in Rust 2021. I see three options here for the MVP:

    • Change the lint to suggest panic!("{{}}") instead of panic!("{}", "{}").
    • Only const-stablise panic!(literal) in Rust 2018 if literal doesn't contain '{' and '}'.
    • Treat panic!("{}", literal) to same as panic!(escaped_liteal).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    T-langRelevant to the language team

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions