On the second println, which runs inside f2, you get 0x7fff4c7147ec again, because you took a reference to s, same as you did in the previous println.
The third println is identical to the second.
The fourth println is run inside of f. f is declared as such:
fn f(ref _s: S);
However, the ref pattern is only something that's exposed to the function's contents. To any caller, the signature is:
fn f(_s: S);
Indeed, a ref pattern moves the value, and then takes a reference to it.
It's essentially syntactical sugar for the following:
fn f(_s: S) {
let _s = &_s;
// The rest of your function...
}
And so we get a different address because now it's been moved into a different stack, the one belonging to f instead of main. However, it's completely plausible for them to print the same number, since certain optimizations will completely optimize out the need for a move.