Since a contract's
receive() can only rely on 2300 gas being available, is there any way to use part of the
msg.value to top up the gas?
It's a security feature that gas cannot be changed within a contract. At first I thought maybe the refund mechanisms of
SSTORE[x]=0 could have been used, but aside from them being under review for deletion (EIP-3298), the refund would only be applied after the transaction to the benefit of the caller, not the smart contract itself. And finally, since the 2300 gas stipend itself is on the wishlist for removal any way to circumvent this would be futile in the long run anyway...