Skip to content

Better help message for missing lifetime specifier #143389

Open
@leonardo-m

Description

@leonardo-m

Code

This is a simple sieve that currently compiles fine:

const MAX: usize = 1_000_000;

fn create_sieve<'a, const LENP: usize>(sieve: &mut [bool; MAX],
                                       primes: &'a mut [u32; LENP]) -> &'a [u32] {
    const SM: usize = MAX.isqrt();
    sieve[0] = false;
    sieve[1] = false;

    let mut primes_len = 0;

    let mut i = 0;
    while i < SM {
        while i < SM && !sieve[i] {
            i += 1;
        }

        primes[primes_len] = i as u32;
        primes_len += 1;

        let mut j = 2 * i;
        while j < MAX {
            sieve[j] = false;
            j += i;
        }
        i += 1;
    }

    for j in i .. MAX {
        if sieve[j] && primes_len < LENP {
            primes[primes_len] = j as u32;
            primes_len += 1;
        }
    }

    &primes[.. primes_len]
}

fn main() {}

If I don't put the 'a lifetime there (you can think of this as a precedent version):

const MAX: usize = 1_000_000;

fn create_sieve<const LENP: usize>(sieve: &mut [bool; MAX],
                                   primes: &mut [u32; LENP]) -> &[u32] {
    const SM: usize = MAX.isqrt();
    sieve[0] = false;
    sieve[1] = false;

    let mut primes_len = 0;

    let mut i = 0;
    while i < SM {
        while i < SM && !sieve[i] {
            i += 1;
        }

        primes[primes_len] = i as u32;
        primes_len += 1;

        let mut j = 2 * i;
        while j < MAX {
            sieve[j] = false;
            j += i;
        }
        i += 1;
    }

    for j in i .. MAX {
        if sieve[j] && primes_len < LENP {
            primes[primes_len] = j as u32;
            primes_len += 1;
        }
    }

    &primes[.. primes_len]
}

fn main() {}

Current output

Currently (rustc 1.90.0-nightly 6677875 2025-07-02) rust gives an error, because it refuses to guess where the output comes from:

error[E0106]: missing lifetime specifier
 --> ...\test2.rs:4:65
  |
3 | fn create_sieve<const LENP: usize>(sieve: &mut [bool; MAX],
  |                                           ----------------
4 |                                    primes: &mut [u32; LENP]) -> &[u32] {
  |                                            ----------------     ^ expected named lifetime parameter
  |
  = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from `sieve` or `primes`
help: consider introducing a named lifetime parameter
  |
3 ~ fn create_sieve<'a, const LENP: usize>(sieve: &'a mut [bool; MAX],
4 ~                                    primes: &'a mut [u32; LENP]) -> &'a [u32] {
  |

Desired output

I suggest to replace the current suggestion and replace (for simple cases) with a better guess generated from just the signature, so it doesn't use the lifetime of an array of bools if the output is a slice of u32:

fn create_sieve<'a, const LENP: usize>(sieve: &mut [bool; MAX],
                                       primes: &'a mut [u32; LENP]) -> &'a [u32] {

In more complex cases it's perhaps better to avoid guessing, and avoid giving a suggestion.

Rationale and extra context

Many cases are simple, in such cases guessing could be reasonable.

Other cases

Rust Version

rustc 1.90.0-nightly (667787527 2025-07-02)
binary: rustc
commit-hash: 6677875279b560442a07a08d5119b4cd6b3c5593
commit-date: 2025-07-02
host: x86_64-pc-windows-gnu
release: 1.90.0-nightly
LLVM version: 20.1.7

Anything else?

No response

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-diagnosticsArea: Messages for errors, warnings, and lintsT-compilerRelevant to the compiler 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