Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Lifetime bound "forgotten" in a function #10703

Closed
honzasp opened this issue Nov 28, 2013 · 4 comments
Closed

Lifetime bound "forgotten" in a function #10703

honzasp opened this issue Nov 28, 2013 · 4 comments
Labels
A-lifetimes Area: Lifetimes / regions

Comments

@honzasp
Copy link

honzasp commented Nov 28, 2013

Hi,

if a struct is bound by a lifetime which is not used in the body of the struct, this bound seems to be excluded from typechecking.

Consider following functions (not valid Rust, because the function and struct bodies are omitted):

struct BananaTree;
struct Banana<'a>;

fn create_banana<'a>(tree: &'a BananaTree) -> Banana<'a>;
fn banana_calories<'a>(banana: Banana<'a>) -> int;
fn transform_banana<'a>(banana: Banana<'a>) -> Banana<'a>;

Bananas are created from BananaTrees and their lifetime must not exceed the lifetime of their tree. banana_calories expects the passed banana to be alive, and transform_banana creates a banana from another one, preserving the lifetime information.

The lifetimes should cause the following function to be rejected by the compiler, because the result of transform_banana has lifetime bound to the lifetime of tree, which is tied to the enclosing block. leaked_banana and the following call to banana_calories should then be invalid.

fn main() {
  let leaked_banana = {
    let tree = BananaTree { ... };
    let banana = create_banana(&tree);
    transform_banana(banana)
  };
  println!("{}", banana_calories(leaked_banana));
}

If the bananas and functions are defined like this:

struct BananaTree { calories: int, }
struct Banana<'a> { calories: &'a int }

fn create_banana<'a>(tree: &'a BananaTree) -> Banana<'a> {
  Banana { calories: &tree.calories }
}

fn banana_calories<'a>(banana: Banana<'a>) -> int {
  *banana.calories
}

fn transform_banana<'a>(banana: Banana<'a>) -> Banana<'a> {
  banana
}

The lifetime bound 'a in Banana<'a> is used in the field calories, forcing the borrow checks and making the invalid use shown above fail with appropriate error message (tree does not live long enough):

fn main() {
  let leaked_banana = {
    let tree = BananaTree { calories: 105 };
    let banana = create_banana(&tree);
    transform_banana(banana)
  };
  println!("{}", banana_calories(leaked_banana));
}

On the other hand, if the implementation is like:

struct BananaTree;
struct Banana<'a> { calories: int }

fn create_banana<'a>(tree: &'a BananaTree) -> Banana<'a> {
  Banana { calories: 105 }
}

fn banana_calories<'a>(banana: Banana<'a>) -> int {
  banana.calories
}

fn transform_banana<'a>(banana: Banana<'a>) -> Banana<'a> {
  banana
}

Then the lifetime bound on Banana<'a> is not used in the member fields at all, but it still should be tied to the lifetime of the BananaTree passed to create_banana and it should limit the use of the created banana. It doesn't work like that, though, because the following function compiles:

fn main() {
  let leaked_banana = {
    let tree = BananaTree;
    let banana = create_banana(&tree);
    transform_banana(banana)
  };
  println!("{}", banana_calories(leaked_banana));
}

The lifetime of banana from create_banana is clearly not tied to lifetime of tree, because the compiler allows us to use the banana when its mother tree went out of scope.

This is in fact safe, because Banana didn't contain any reference to the BananaTree. The point is that I would like to use Rust's lifetimes in a C library bindings, where the Banana values live as long as their respective BananaTrees (as a matter of fact, the library is LLVM, banana trees are modules/functions and bananas are values).

@alexcrichton
Copy link
Member

cc @nikomatsakis, it seems like if we're able to have shadow type parameters you should be able to have shadow lifetime parameters.

@Aatch
Copy link
Contributor

Aatch commented Nov 28, 2013

This has come up before though I'm not sure if there's another issue open for it. The case when this last came up was dealing with symbols from a dynamically loaded extension. It would be useful for, as @honzasp says, exposing lifetime information from external libraries.

@pnkfelix
Copy link
Member

cc me

@nikomatsakis
Copy link
Contributor

this is a dup of #5922 -- I will comment there.

flip1995 pushed a commit to flip1995/rust that referenced this issue May 5, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-lifetimes Area: Lifetimes / regions
Projects
None yet
Development

No branches or pull requests

5 participants