Ensure an Rc isn't freed while running its own destructor.

A weak pointer inside itself will have its destructor run when the last
strong pointer to that data disappears, so we need to make sure that the
Weak and Rc destructors don't duplicate work (i.e. freeing).

By making the Rc destructor effectively take a weak pointer, we ensure
that no Weak destructor will free the pointer while still ensuring that
Weak pointers can't be upgraded to strong ones as the destructors run.

Fixes #12046.