rust-lang / rust-lang/rust-clippy

New lint: types which cannot be constructed in `const`

Open
#8,021 0 comments 1 reaction 0 assignees View on GitHub

Nobody has claimed this yet.

A-lint
Dominant language
Rust
Stars
13.5k
Forks
2.2k
Avg merge
2d 10h
Merged PRs (30d)
32

Description

Possible name: missing_const_constructor

What it does

Flags types which cannot be constructed using any constant expression. That is, the type meets all of these criteria:

  • Is public in a library crate.
  • Cannot be constructed as a literal outside the crate (struct or union with private fields or #[non_exhaustive]).
  • Does not have an associated nonmethod function pub const fn <any name>(...) -> Self { or constant pub const <ANY NAME>: Self. (When const trait impls are stabilized, const impl Default should be checked for too.)
  • Has only fields whose types are themselves constructible in const or generic. (This rule might be hard to implement precisely, but is only to reduce false positives.)
Categories
  • Kind: Restriction

I think something this might be a good lint to warn by default, similar to new_without_default, but it would require much better rules for avoiding false positives before that would be reasonable. As described, I think it's like exhaustive_structs — something one will opt into and then often allow anyway.

This is also a close relative of missing_const_for_fn (which I just learned about while writing this up) but this will trigger when the type has no public const constructor even if it doesn't have a public non-const constructor that could be const.

Advantages

Making sure types have const constructors increases composability: if some crate wants to have a constant instance of some struct it defines, then all fields of it must also be constructible in const. Thus, a single forgotten consideration of const in a library can have a wide impact. If you aren't a const enthusiast it is easy to forget to add const to fns, let alone to add alternatives when the function obviously can't be const.

Drawbacks
  • It will warn about some types which should not be constructible in const even if the definition seems to permit it, such as newtyped integer handles to runtime-allocated resources.
  • It might encourage authors to use const fn without knowing the reasons not to (constraint on future compatible versions of the same function).
  • missing_const_for_fn probably covers a lot of the same ground. However, that lint won't catch cases where the existing constructors can't be constified but a const constructor could be written, so I think this is still worthwhile. (For example, Vec::new() exists and is const, even though Vec::from([]) has the same function and cannot be const since it may allocate.)
Example

To copy an example in my own code,

#[derive(Clone, Debug)]
pub struct IntAllocator<T: num_traits::int::PrimInt + Debug> {
    last_allocated: Option<T>,
    free_list: Vec<T>,
}

impl<T: PrimInt + Debug> IntAllocator<T> {
    pub fn new() -> Self {
        Self {
            last_allocated: None,
            free_list: Vec::new(),
        }
    }

    // ... non-constructor functions follow...
}

would trigger the lint on the struct IntAllocator. Perhaps the logic from missing_const_for_fn could produce a suggestion to modify the existing new; if no such function was found, there would still be a lint but no suggestion.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by reviewing the existing missing_const_for_fn lint and compare its analysis and suggestion behavior with the proposed missing_const_constructor rules. Define how the listed visibility, construction, field-type, and false-positive cases should be handled, then add coverage for the IntAllocator example and the stated exclusions. Done means the lint reliably identifies public types without a usable const construction path.

Written by the indexing model from the issue text.

Assessment

Tech stack
rust
Domain
tooling
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
30/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.