Skip to content

Make const_err a future-incompatibility lint and eventually a hard error #71800

Closed
@RalfJung

Description

@RalfJung

Currently, when Miri raises an error while evaluating a const, that does not lead to a hard compiler error (sess.struct_err or so). Instead, the const_err lint is emitted (and there are a bunch of exceptions I keep forgetting... promoteds and static each get their own treatment). Then later consumers of consts have to remember to struct_err when they query for the value of the const (and they do that with inconsistent messages and some might even forget to do it), usually without any actual details so if you allow(const_err) the error makes no sense... in a word, it's a mess (and so is the code backing this).

Can we clean that up? I think we should try. IMO the long-term goal should be to just make errors when evaluating a const hard errors, so we can have that error-reporting code once in librustc_mir/const_eval and not worry about it everywhere else in the compiler. Right now, it's a deny-by-default lint, for backwards compatibility.

To make this slightly more complicated, we also evaluate consts that the program does not actually use, so we can tell library crate authors when their consts are wrong. Inside the const-eval engine, these look like normal const-eval queries, so if we switch to a hard error, that would be a hard error, too. We have to decide what to do about that.

Option 1: treat unused consts like used consts whenever we can

The easiest way forward would be to say that an eventual hard error for CTFE failures in unused consts is fine. Then we can just make the current const_err lint reporting into a future-incompatibility lint (maybe clean it up a little, and clean up the way that we error when we truly need the const value). Later, we can experiment with making it a hard error, and at that point everything would become simple and uniform and beautiful. (Promoteds would still only lint as the user did not ask for const-evaluation, but at least behavior wouldn't depend on context any more: const/static always hard-error [which currently const only does for some callers], and promoteds never do. Okay maybe it's not beautiful but it is better.)

Note that this matches what we already do for static. However, unlike static, const can exist in generic contexts (as associated consts), and those we cannot evaluate and thus not lint or error for. So, "top-level" const would behave differently from associated consts in terms of error reporting. (That is already the case, but currently the difference is a deny-by-default lint that can be allow'ed away.) There is no technical need to hard-error on CTFE failures in unused consts, but then one could say the same about unused statics and we do already hard-error there (and I don't remember anyone ever complaining about that). So my personal preference would be to hard-error for failing consts as often as we can.

Option 2: keep just linting for unused consts

Alternatively, maybe we don't want to hard-error when a const that is not used fails to evaluate (consistently with how we cannot produce a hard error when an assoc const fails to evaluate as we cannot even check that). Arguably we should then downgrade such messages to warn-by-default.

In this case we should probably find a way for the caller to inform the const-eval engine whether they truly need the result of the query or not (almost always they do need it, except for that lint), and then use that to control our lint level... but how can we do that without duplicating errors or work? Currently it is deduplicated because the query only runs once, and it always emits a lint, and then the caller potentially additionally emits a hard error but pointing at the span where the const actually gets used. But this is bad, it means that with allow(const_err) none of the relevant error details are shown even when we do get a hard error.

Backwards compatibility concerns

A potential concern here might be that if we make CTFE errors hard errors, we have to be careful with making the Miri engine raise more CTFE errors (like, improved UB checking). But that is already the case: when raise more CTFE errors, the consts affected by it go from having a value to not having one, and cannot be used any more. So I don't think the proposal here creates any new backcompat issues.

Cc @rust-lang/wg-const-eval @rust-lang/lang

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-const-evalArea: Constant evaluation, covers all const contexts (static, const fn, ...)C-cleanupCategory: PRs that clean code up or issues documenting cleanup.C-future-incompatibilityCategory: Future-incompatibility lintsT-langRelevant to the language team, which will review and decide on the PR/issue.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions