Skip to content

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

Closed as not planned
@haohui

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?

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