A simpler example of the error is
fn oops<'a: 'b, 'b>(a: &'b mut &'a mut i32) {
let _: &'a mut i32 = *a; // error!
}
The issue here is that having a (a mutable reference to some data) lets you mutate (change) the value it points to, but it does not let you move the value (leaving nothing behind). In oops, since you can only have one mutable reference to anything at a time, *a needs to be moved to _, but that leaves *a without data and a pointing to "garbage". But whoever lent *a to oops expects *a to have a value upon it returning, so this must be banned. (I say "garbage" because the move probably doesn't really mutate *a, and if we forced this to execute probably nothing would go wrong. But if we didn't care about performance, the move could in principle destroy *a to enforce the "one mutable borrow" rule, in which case you're hosed.)
In your case, index_mut (which is implementing the [1..] syntax) takes &mut [i32], so *s needs to be moved to the function. But that leaves *s without a value, and you don't own *s, which is illegal. It doesn't matter that you will eventually put a value back. E.g. if index_mut panics, the caller will be expecting a value in whatever variable it lent to inc, but there won't be any. In contrast, foo does own a, so it's okay to leave a valueless for the duration of index_mut in a = &mut a[1..] (the compiler can track when owned variables have and don't have values).
One fix (without changing the interface) is to stick a default value into *s while you're operating on it. The impl<'a, T> Default for &'a mut[T] provides this (the default value points to an empty slice), and std::mem::take packages that Default implementation in a safe way.
fn inc<'a: 'b, 'b>(s: &'b mut &'a mut [i32]) {
*s = &mut std::mem::take(s)[1..];
}
I agree with @cdhowie that writing
fn inc<'a>(s: &'a mut [i32]) -> &'a mut [i32] {
return s[1..];
}
and requiring usage by a = inc(a) is a better idea than the inc(&mut a) interface.