# Lint against unbound lifetimes

**URL:** <https://internals.rust-lang.org/t/lint-against-unbound-lifetimes/2257>\
**Category:** Uncategorized\
**Created:** [June 18, 2015, 4:28am UTC](https://internals.rust-lang.org/t/lint-against-unbound-lifetimes/2257 "2015-06-18T04:28:10Z")\
**Posts on this page:** 8\
**Page:** 1

<div class="post-metadata">

**Author:** ![Gankra](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/gankra/32/6002_2.png) [@Gankra](https://internals.rust-lang.org/u/Gankra)\
**Post date:** [June 18, 2015, 4:28am UTC](https://internals.rust-lang.org/t/lint-against-unbound-lifetimes/2257/1 "2015-06-18T04:28:10Z")

</div>

Unsafe code can easily produce “unbound” lifetimes – lifetimes which can be inferred as anything. These lifetimes are in fact _even more powerful_ than `'static` because e.g. `&'static &'a T` is an illegal type, but an unbound lifetime will successfully promote itself to “only” `&'a &'a T` if necessary to typecheck.

An unbound lifetime is produced whenever you:

- deref a raw ptr – `let ptr = &*raw_ptr;`
- transmute to a ptr and don’t give an explicit lifetime – `transmute::<&T, &U>(foo)`

Derefing a raw ptr is certainly inevitable transiently, and creating unbound lifetimes certainly has a practical use (e.g. this is used `split_at_mut`). However I’m wondering if there are some limited scenarios where it could be linted against.

One trivial case is function signatures where output lifetimes _don’t_ appear in inputs:

```rust
fn foo<'a>() -> &'a str

```

If you write this you’re pretty much always wrong – especially if you’re marking it as safe! In the past we’ve had std-lib errors of this form deriving from unbound lifetimes in _struct definitions_, and they were promoted to an error-by-default.

---

<div class="post-metadata">

**Author:** ![tupshin](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/tupshin/32/2573_2.png) [@tupshin](https://internals.rust-lang.org/u/tupshin)\
**Post date:** [June 18, 2015, 5:25am UTC](https://internals.rust-lang.org/t/lint-against-unbound-lifetimes/2257/2 "2015-06-18T05:25:13Z")

</div>

I think this would be very useful for FFI work.

---

<div class="post-metadata">

**Author:** ![llogiq](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/llogiq/32/13692_2.png) [@llogiq](https://internals.rust-lang.org/u/llogiq)\
**Post date:** [June 18, 2015, 6:56am UTC](https://internals.rust-lang.org/t/lint-against-unbound-lifetimes/2257/3 "2015-06-18T06:56:25Z")

</div>

So functions can create unbound lifetimes via generics. structs can no longer create them (because that’s an error, right?). What else can create them?

From a `syntax::ast` perspective, this would look like a `Lifetime` with a `name` other than `'static` and an empty `bounds` Vec. Sure enough, when I put your `fn foo` definition through rustc -Z ast-json, I get (among a lot of other stuff):

```rust
"lifetimes": [
  {
    "lifetime": {
      "span": 176093659175,
      "name": {
        "_field0": 63
      },
      "id": 31
    },
    "bounds": []
  }
],

```

If this is it, we just identify where in the AST this can happen, and the rest is child’s play.

Edit: No, it’s not _that_ easy: If I plug in a `fn from_argument(a: &'a str) -> &'a str { a }`, I get the same. The difference is that the function above defines the `_field0` in its generics, while `from_arguments` has `_field0` in an argument lifetime. So we’d need to create a set of valid argument lifetimes and compare the returned lifetime (if any) against that.

---

<div class="post-metadata">

**Author:** ![Gankra](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/gankra/32/6002_2.png) [@Gankra](https://internals.rust-lang.org/u/Gankra)\
**Post date:** [June 19, 2015, 12:37am UTC](https://internals.rust-lang.org/t/lint-against-unbound-lifetimes/2257/4 "2015-06-19T00:37:25Z")

</div>

I stumbled across a “valid” safe usecase of unbound lifetimes:

```rust
fn get_str<'a>() -> &'a str {
   "hello"
}

```

But this is basically just a more obfuscated version of `'static`, so it’s not clear to me that it matters.

---

<div class="post-metadata">

**Author:** ![llogiq](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/llogiq/32/13692_2.png) [@llogiq](https://internals.rust-lang.org/u/llogiq)\
**Post date:** [June 19, 2015, 6:26am UTC](https://internals.rust-lang.org/t/lint-against-unbound-lifetimes/2257/5 "2015-06-19T06:26:26Z")

</div>

I see no problem with making the lint match this kind of code. If someone _really_ wants to do this, they can always `#[allow(unbound_lifetime)]`. As an alternative, we could check if the lifetime of every returned expression against 'static and just make it a different `static_unbound_lifetime` lint. However, as I found out in my `option_and_then` lint, this is not exactly trivial, with many early return/panic/closure-related corner cases.

Of course, doing this in rustc would still be a breaking change (albeit minor), so we may want to test this out of tree before introducing it. (@Manishearth: another one for rust-clippy, I presume?)

---

<div class="post-metadata">

**Author:** ![Manishearth](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/manishearth/32/50_2.png) [@Manishearth](https://internals.rust-lang.org/u/Manishearth)\
**Post date:** [June 19, 2015, 7:26am UTC](https://internals.rust-lang.org/t/lint-against-unbound-lifetimes/2257/6 "2015-06-19T07:26:28Z")

</div>

sounds good to me; but note that the set of valid lifetimes might be larger than it seems at first.

`bounds` is just the `: 'b` part of `'a: 'b`, which is not what we care about.

It might be better if this wasn’t checked from the AST; instead we want to use the `TyS` from `middle` and check the [`Substs`](http://manishearth.github.io/rust-internals-docs/rustc/middle/subst/struct.Substs.html) to see where the lifetime was defined. I don’t know these variants well enough to know what to look for though.

Edit: On thinking about it, this might actually be better done via the AST.

Check for lifetime params defined in the function space but only used in the return value, once.

---

<div class="post-metadata">

**Author:** ![Thiez](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/thiez/32/3344_2.png) [@Thiez](https://internals.rust-lang.org/u/Thiez)\
**Post date:** [June 25, 2015, 9:22pm UTC](https://internals.rust-lang.org/t/lint-against-unbound-lifetimes/2257/7 "2015-06-25T21:22:21Z")

</div>

Would it be sufficient to warn for cases where an unbounded lifetime leaves an `unsafe` block? This would still allow the `fn get_str<'a>() -> &'a str { "hello" }` case that Gankro mentions, while catching the cases where actual bad behaviour might result.

---

<div class="post-metadata">

**Author:** ![system](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/system/32/14092_2.png) [@system](https://internals.rust-lang.org/u/system)\
**Post date:** [March 25, 2019, 8:24am UTC](https://internals.rust-lang.org/t/lint-against-unbound-lifetimes/2257/8 "2019-03-25T08:24:43Z")

</div>

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.
