What the T && 'a get after a assign

struct defination as below:

    struct OutRef<'a, T : 'a> {
        ptr: *mut T,
        _lifetime: PhantomData<&'a ()>,
    }

what does T and 'a get after:

OutRef::<&'static str>

T == &str, or T == &'static str?
'a == 'static?

And what is the matching rule?

If you have a OutRef<&'static str>, then T = &'static str, but it puts no constraint on 'a, so it could be anything.

seems what ypu said is not really true

    struct OutRef<'a, T : 'a> {
        ptr: ptr::NonNull<T>,
        _lifetime: PhantomData<&'a ()>,
    }

    impl<'a, T : 'a> OutRef<'a, T> {
        #[inline]
        pub fn from1 (p: &'a mut T)
          -> OutRef<'a, T>
        {
            let i: i32 = 0;
            //let k = p as i32;
            #[allow(unused_unsafe)]
            unsafe {
                // # Safety
                //
                //   - Respects the invariant, since something
                //     init can be seen as maybeuninit
                OutRef {
                    ptr: p.into(),
                    _lifetime: PhantomData,
                }
            }
        }
    }
fn main ()
{
    let mut s: &'static str = "Static str"; // s pointer to static str
    let mut s = 9;
    s = OutRef::<&'static str>::from1(&mut s); // pointer to s
    {

        let s = String::from("Short-lived str");
        at_s.write(&s); // override s with a pointer to the short-lived str
    }
    dbg!(s); // Use after free!
}

get error:

error[E0308]: mismatched types
  --> src/main.rs:94:39
   |
94 |     s = OutRef::<&'static str>::from1(&mut s); // pointer to s
   |                                       ^^^^^^ expected &str, found integer
   |
   = note: expected type `&mut &str`
              found type `&mut {integer}`

error[E0308]: mismatched types
  --> src/main.rs:94:9
   |
94 |     s = OutRef::<&'static str>::from1(&mut s); // pointer to s
   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected integer, found struct `lib::OutRef`
   |
   = note: expected type `{integer}`
              found type `lib::OutRef<'_, &str>`

error: aborting due to 3 previous errors

Some errors have detailed explanations: E0308, E0425.
For more information about an error, try `rustc --explain E0308`.
error: could not compile `playground`.

e.g.
although from1 is called on OutRef::<&'static str>,
the T is not &'static str, but &str

You just have type mismatch errors. That has nothing to do with lifetimes. You're trying to call from1 with 9 as an argument while having defined T to be of the type &str.

Yes, but the error message shows the expected type, which is the T

Error messages don't show lifetimes, if they're irrelevant to the error, IIRC.

another example

fn main ()
{
    let mut s: &'static str = "Static str"; // s pointer to static str
    let n = 9;
    let s1 = String::from("dynamic str"); 
    let mut s = s1.as_str();
    let at_s = OutRef::<&'static str>::from1(&mut s); // pointer to s
    {

        let s = String::from("Short-lived str");
        //.write(&s); // override s with a pointer to the short-lived str
    }
    dbg!(s); // Use after free!
}

shows compiler expected 'a to be 'static:

error[E0597]: s1 does not live long enough
--> src/main.rs:95:17
|
95 | let mut s = s1.as_str();
| ^^---------
| |
| borrowed value does not live long enough
| argument requires that s1 is borrowed for 'static
...
103 | }
| - s1 dropped here while still borrowed

so, should it be clear that:
OutRef::<&'static str>

assign 'static to 'a, &str to T of the

struct OutRef<'a, T : 'a>

?

can't understand what is your meaning.

The compiling error does reveals something, which is indeed why I wrote the wrong codes for.

The first reply correctly tells you, that T is &'static str, but 'a doesn't have to be 'static. That just means you can call OutRef::from1 with a &str regardless of its lifetime. Not more not less. You can never assign a short-lived value to a longer-lived value, because it'd allow you to access freed memory.

'a is 'static in your example

in my example, OutRef::<&'static str>, you agree

but 'a doesn't have to be 'static

then you say:

'a is 'static in your example

So, in My example, does the 'a doesn't have to be 'static or 'a is 'static ?

and T, does it a &str or a 'static str?
my compiling error shows it is a &str, So, if you tell me I am wrong, could you explain:

^^^^^^ expected &str, found integer

The error message hides the lifetime, otherwise it'd either show &'static, &'a or &'_ (anonymous lifetime, aka there is no name, because it has been inferred dynamically). In your second error case, it specifically complains about your value to not be 'static, because you yourself declared at_s to be of the type OutRef<&'static str>, which is inferred from the usage of the turbofish operator when you called OutRef::from1.

so, in this error:

error[E0597]: s1 does not live long enough
--> src/main.rs:95:17
|
95 | let mut s = s1.as_str();
| ^^---------
| |
| borrowed value does not live long enough
| argument requires that s1 is borrowed for 'static
...
103 | }
| - s1 dropped here while still borrowed

does it mean
OutRef::<&'static str> has assigned 'static to 'a?

Exactly

what does "exactly" means?

Exactly

If you think it did means 'a is 'static, then you have to agree my conclusion:
OutRef::<&'static str>
assign &str ===> T, 'static ===> 'a

or you can try another example, this time delete 'static from OutRef::<&'static str>::from1 to OutRef::<&str>::from, then you will find compiling passes

fn main ()
{
    let mut s: &'static str = "Static str"; // s pointer to static str
    let n = 9;
    let s1 = String::from("dynamic str"); 
    let mut s = s1.as_str();
    let at_s = OutRef::<&str>::from1(&mut s);
    {

        let s = String::from("Short-lived str");
        at_s.write(&s); // override s with a pointer to the short-lived str
    }
    dbg!(s); // Use after free!
}

Is OutRef::write declared as fn write(&mut self, value: T)?

yes

What happens if you call std::mem::drop(at_s); right before dbg! at the end? My guess is, it won't compile.

No. You can create one where 'a < 'static.

fn lol<'a>(s: &'a mut &'static str) -> OutRef<'a, &'static str> {
    OutRef::from1(s)
}

fn main() {
    let r = {
        let mut s = "abc";
        let r = lol(&mut s);
        // r is valid inside this block...
        println!("{:?}", r);
        // ...but not outside it. (therefore 'a is not 'static)
        r // Error: `s` does not live long enough
    };
}
1 Like

you can run it online at Rust Playground
the code is not exactly my modified version but you can modify it for testing

it is exactly same with my conclusion indeed
s is really &'r mut T which in turn 'a = 'r T = &'static str

all we need is to make it clear what is in the T