Suspected unsound of borrowing checks in `impl Trait<'a> + 'static`

Consider the code:

trait Lifetime<'s>: Copy + 'static {}

impl<'s> Lifetime<'s> for () {}

/// We only know that the return type `impl Lifetime<'s>` is valid for this lifetime 's
fn lifetime_of_ref<'s, T: ?Sized>(x: &'s T) -> impl Lifetime<'s> {}

/// Here, we require the lifetime 's to be valid
fn lifetime_active<'s>(lifetime: impl Lifetime<'s>) {}

fn foo() {
    let l = {
        let i = 0;
        lifetime_of_ref(&i)
    };
    // So, the implementation of the lifetime trait needs to be invalidated
    // or say: `i` does not live long enough
    lifetime_active(l);
}

After analysis, I think this is because region '?2 not include bb1: StorageDead(_2);

'?2 | U0 | {bb0[6..=8], bb1[7]}

// MIR for `foo` 0 nll

| Free Region Mapping
| '?0 | Global | ['?0, '?1]
| '?1 | Local | ['?1]
|
| Inferred Region Values
| '?0 | U0 | {bb0[0..=8], bb1[0..=7], bb2[0..=4], bb3[0], '?0, '?1}
| '?1 | U0 | {bb0[0..=8], bb1[0..=7], bb2[0..=4], bb3[0], '?1}
| '?2 | U0 | {bb0[6..=8], bb1[7]}
| '?3 | U0 | {bb0[7..=8], bb1[7]}
| '?4 | U0 | {bb0[8], bb1[7]}
| '?5 | U0 | {bb0[8], bb1[7]}
| '?6 | U0 | {bb0[8], bb1[7]}
| '?7 | U0 | {bb0[8], bb1[7]}
| '?8 | U0 | {bb0[7..=8], bb1[7]}
| '?9 | U0 | {bb0[8], bb1[7]}
| '?10 | U0 | {bb0[8], bb1[7]}
|
| Inference Constraints
| '?0 live at {bb0[0..=8], bb1[0..=7], bb2[0..=4], bb3[0]}
| '?1 live at {bb0[0..=8], bb1[0..=7], bb2[0..=4], bb3[0]}
| '?2 live at {bb0[6]}
| '?3 live at {bb0[7]}
| '?4 live at {bb1[7]}
| '?5 live at {bb1[7]}
| '?7 live at {bb0[8]}
| '?8 live at {bb0[7]}
| '?10 live at {bb0[8]}
| '?2: '?8 due to Boring at Single(bb0[6]) (src\main.rs:30:25: 30:27 (#0)
| '?3: '?7 due to Boring at Single(bb0[7]) (src\main.rs:30:25: 30:27 (#0)
| '?4: '?5 due to Predicate(src\main.rs:11:39: 11:51 (#0)) at Single(bb1[7]) (src\main.rs:34:5: 34:23 (#0)
| '?5: '?4 due to Predicate(src\main.rs:11:39: 11:51 (#0)) at Single(bb1[7]) (src\main.rs:34:5: 34:23 (#0)
| '?5: '?9 due to CallArgument(Some(FnDef(DefId(0:10 ~ rust_demo[fad8]::lifetime_active), [ReErased, Alias(Opaque, AliasTy { args: [i32, ReErased], def_id: DefId(0:27 ~ rust_demo[fad8]::lifetime_of_ref::{opaque#0}) })]))) at Single(bb1[7]) (src\main.rs:34:5: 34:23 (#0)
| '?6: '?9 due to Boring at Single(bb1[6]) (src\main.rs:34:21: 34:22 (#0)
| '?6: '?10 due to Assignment at Single(bb0[8]) (src\main.rs:30:9: 30:28 (#0)
| '?7: '?10 due to CallArgument(Some(FnDef(DefId(0:8 ~ rust_demo[fad8]::lifetime_of_ref), [i32]))) at Single(bb0[8]) (src\main.rs:30:9: 30:28 (#0)
| '?8: '?3 due to Boring at Single(bb0[7]) (src\main.rs:30:25: 30:27 (#0)
| '?9: '?5 due to CallArgument(Some(FnDef(DefId(0:10 ~ rust_demo[fad8]::lifetime_active), [ReErased, Alias(Opaque, AliasTy { args: [i32, ReErased], def_id: DefId(0:27 ~ rust_demo[fad8]::lifetime_of_ref::{opaque#0}) })]))) at Single(bb1[7]) (src\main.rs:34:5: 34:23 (#0)
| '?9: '?6 due to Boring at Single(bb1[6]) (src\main.rs:34:21: 34:22 (#0)
| '?10: '?6 due to Assignment at Single(bb0[8]) (src\main.rs:30:9: 30:28 (#0)
|
fn foo() -> () {
    let mut _0: ();
    let _1: impl Lifetime<'_>;
    let _2: i32;
    let mut _3: &i32;
    let _4: &i32;
    let _5: ();
    let mut _6: impl Lifetime<'_>;
    scope 1 {
        debug l => _1;
    }
    scope 2 {
        debug i => _2;
    }

    bb0: {
        StorageLive(_1);
        StorageLive(_2);
        _2 = const 0_i32;
        FakeRead(ForLet(None), _2);
        StorageLive(_3);
        StorageLive(_4);
        _4 = &_2;
        _3 = &(*_4);
        _1 = lifetime_of_ref::<i32>(move _3) -> [return: bb1, unwind: bb3];
    }

    bb1: {
        StorageDead(_3);
        StorageDead(_2);
        FakeRead(ForLet(None), _1);
        StorageDead(_4);
        StorageLive(_5);
        StorageLive(_6);
        _6 = _1;
        _5 = lifetime_active::<'_, impl Lifetime<'_>>(move _6) -> [return: bb2, unwind: bb3];
    }

    bb2: {
        StorageDead(_6);
        StorageDead(_5);
        _0 = const ();
        StorageDead(_1);
        return;
    }

    bb3 (cleanup): {
        resume;
    }
}

Github issuse: We should check lifetime boundaries when fulfill trait implementations with lifetime parameters. · Issue #120156 · rust-lang/rust (github.com)

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