Skip to content

lifetime rules are overly restricted in 1.65 nightly / beta #102029

Description

@haohui

I tried this code:

type Result<T> = std::result::Result<T, std::io::Error>;

pub(crate) struct Foo<'a> {
    pub(crate) kernels: Vec<&'a str>,
}

impl<'a> Foo<'a> {
    fn parse(buf: &'a [u8]) -> Result<Foo> {
        let p = &mut StreamParser::new(buf);
        let (m, p) = p.read_map()?;
        m.try_foreach(p, |b| {
            let b0 = Self::broke(b)?;
            Ok(b0)
        })?;
        Ok(Foo {
            kernels: Vec::new(),
        })
    }

    fn broke<'b: 'a>(p: &'b mut StreamParser<'a>) -> Result<&'b mut StreamParser<'a>> {
        Ok(p)
    }
}

#[derive(Copy, Clone)]
pub(crate) struct StreamParser<'a> {
    bytes: &'a [u8],
    current_position: usize,
}

#[derive(Copy, Clone, Debug)]
pub(crate) struct Seq {
    num_entries: usize,
}

impl Seq {
    pub(crate) fn try_foreach<'a, 'b, F>(
        &self,
        p: &'b mut StreamParser<'a>,
        mut f: F
    ) -> Result<&'b mut StreamParser<'a>>
        where F: FnMut(&'b mut StreamParser<'a>) -> Result<&'b mut StreamParser<'a>>
    {
        (0..self.num_entries).try_fold(p, |p, _| (f)(p))
    }
}

impl<'a> StreamParser<'a> {
    pub(crate) fn new(bytes: &'a [u8]) -> StreamParser<'a> {
        StreamParser {
            bytes,
            current_position: 0,
        }
    }

    pub(crate) fn read_map(&mut self) -> Result<(Seq, &mut Self)> {
        let c = self.read_u8()?;
        Ok((
            Seq {
                num_entries: c as usize,
            },
            self,
        ))
    }

    fn read_u8(&mut self) -> Result<u8> {
        let r = self.bytes[self.current_position];
        self.current_position += 1;
        Ok(r)
    }
}

The rustc in 1.63 compiles the code successfully while rustc 1.65.0-nightly (cf9ed0d 2022-09-15) fails to compile it:

7  | impl<'a> Foo<'a> {
   |      -- lifetime `'a` defined here
8  |     fn parse(buf: &'a [u8]) -> Result<Foo> {
9  |         let p = &mut StreamParser::new(buf);
   |                      ^^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use
10 |         let (m, p) = p.read_map()?;
   |                      ------------ argument requires that borrow lasts for `'a`
...
18 |     }

Are there any changes in the language specifications that have tighten the lifetime rules?

Activity

  1. mejrs commented on Sep 19, 2022

    @mejrs
    Member

    @rustbot label +regression-untriaged, +regression-from-stable-to-beta +A-lifetimes

  2. added
    A-lifetimesArea: Lifetimes / regions
    regression-untriagedUntriaged performance or correctness regression.
    I-prioritizeIssue needs a team member to assess the impact. Will be replaced by P-{low,medium,high,critical}
    on Sep 19, 2022
  3. ehuss commented on Sep 19, 2022

    @ehuss
    Contributor

    Thanks for the report! Sorry you're running into that situation. This was a correctness fix, intentionally changed as part of #98835. Closing as a duplicate of #100544.

  4. jackh726 commented on Sep 20, 2022

    @jackh726
    Member

    Indeed this was changed due to a correctness fix.

    For clarity, you code can be fixed by changing let b0 = Self::broke(b)?; to let b0 = Foo::broke(b)?;

  5. haohui commented on Sep 20, 2022

    @haohui
    Author

    I thought Self is just a syntactic sugar. Just curious how does it affect the binding of lifetime?

  6. jackh726 commented on Sep 20, 2022

    @jackh726
    Member

    Self here is Foo<'a>, whereas Foo is Foo<'_>. So in the former, the closure captures the 'a lifetime, where in the latter, it captures some lifetime '_

  7. removed
    I-prioritizeIssue needs a team member to assess the impact. Will be replaced by P-{low,medium,high,critical}
    regression-untriagedUntriaged performance or correctness regression.
    on Sep 20, 2022
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

    A-lifetimesArea: Lifetimes / regionsC-bugCategory: This is a bug.regression-from-stable-to-betaPerformance or correctness regression from stable to beta.

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions