Skip to content

Static lifetime deduced for constant, but not for return values of const fn #90370

Closed
@hniksic

Description

@hniksic
Contributor

In rust borrowed constants have static lifetimes, even if the constants are simple literals in the middle of a function. For example, this compiles:

fn assert_static(_r: &'static u32) {}
fn main() {
    assert_static(&1); // compiles
}

This works even in more involved situations, such as when the "literal" is a macro-generated array of structs whose fields are literals. (That's my actual use case, but I'll refer to the simple case of just having a u32 for simplicity.)

The problem is that it no longer works if the value is returned by a const fn:

const fn inc(n: u32) -> u32 {
    n + 1
}

fn assert_static(_r: &'static u32) {}

fn main() {
    assert_static(&1);
    assert_static(&inc(1)) // doesn't compile
}

Playground

error[E0716]: temporary value dropped while borrowed
  --> src/main.rs:9:20
   |
9  |     assert_static(&inc(1)) // doesn't compile
   |     ---------------^^^^^^-
   |     |              |
   |     |              creates a temporary which is freed while still in use
   |     argument requires that borrow lasts for `'static`
10 | }

I would expect (or rather wish) for the latter code to compile since the former did. Note that, since const and static are static, it is possible to work around it by creating an explicit const or static inbetween. For example, all of these compile:

fn main() {
    assert_static(&1);
    {
        const TMP: u32 = inc(1);
        assert_static(&TMP);
    }
    {
        static TMP: u32 = inc(1);
        assert_static(&TMP);
    }
    assert_static({
        const TMP: u32 = inc(1);
        &TMP
    });
    assert_static({
        static TMP: u32 = inc(1);
        &TMP
    });
}

Playground

While a workaround is available, it is not always obvious. Also it would be much nicer not to have to introduce all the temporary constants/statics, especially in code that calls several different const fns.

Activity

SkiFire13

SkiFire13 commented on Oct 28, 2021

@SkiFire13
Contributor

This seems to be intended behaviour, see rust-lang/const-eval#19, RFC 3027 and the const-eval documentation on promotion

PatchMixolydic

PatchMixolydic commented on Oct 31, 2021

@PatchMixolydic
Contributor

The inline_const feature gives a less noisy way to make this code compile (playground):

#![allow(incomplete_features)]
#![feature(inline_const)]

const fn inc(n: u32) -> u32 {
    n + 1
}

fn assert_static(_r: &'static u32) {}

fn main() {
    assert_static(&1);
    assert_static(&const { inc(1) });
}
RalfJung

RalfJung commented on Nov 3, 2021

@RalfJung
Member

Indeed, this is expected behavior -- promoting const fn implicitly can lead to compile errors in code that really ought to compile, besides leading to nightmare consequences within rustc itself. The key difference between &1 and &const_fn() is that the latter might panic or fail to evaluate for other reasons, so we cannot easily treat them the same.

So I will close this issue; the intended convenient way to write such code in the future is via inline consts, tracked at #76001.

RalfJung

RalfJung commented on Nov 3, 2021

@RalfJung
Member

Oh, also, a shameless plug: I have a little crate that partially implements inline consts as a macro -- https://crates.io/crates/inline-const.

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

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

      Development

      No branches or pull requests

        Participants

        @RalfJung@hniksic@PatchMixolydic@SkiFire13

        Issue actions

          Static lifetime deduced for constant, but not for return values of const fn · Issue #90370 · rust-lang/rust