This is a helpful response, at least in breaking down the issues in a coherent fashion. I added some comments/followup questions.
The 'when receiving' part refers to the fact that the MSSP module (at least in SPI mode) always exchanges values/bits - as it sends out one bit it is receiving the comparable bit from the other device.
I get the general point here, but I still wonder why the manual specifically uses the "when receiving" distinction. The MSSP module is always receiving as it is transmitting, right? Why bother with this unnecessary terminology?
As an aside, I don't think the problem I was seeing before I added the first read of the SPIBUF was due to any double-buffering because I tried doing two consecutive reads of the SPIBUF after sending the second control byte and that didn't fix the problem.
As a slave, the code has to write a value to the buffer before the exchange is started. As a master, writing to the buffer initiates the exchange. In either case (for these older-style SPI implementations) if you were to write another value to the buffer while the exchange is occurring, then you can corrupt the value being sent. However the module can 'assume' that the firmware is doing the right thing in terms of timing the writing to the buffer and the exchange process..
Yes, this is why the SSPOV bit is only set when in Slave mode - the assumption is that in Master mode, the software is controlling the timing, so there shouldn't ever be a problem.
On the 'receive' side, the module cannot make that assumption. It is quote possible for the exchange to be started (either as the master by writing to the buffer, or as the slave by the master starting to send clocks) and for the firmware to read from the buffer while the exchange is in progress. The value that is read is the complete value that was last received, regardless of what is in the shift register at that time. Therefore, they are saying that the 'receive' side is effectively double buffered.
Here is where I get a bit confused about the distinction between slave/master and "receive" side. The master controls the pace of the clock, so it doesn't really need any double buffering since it can guarantee that the next byte won't be transferred before the incoming byte is read.
As to any difference between C18 and XC8, I don't know the answer. However I do know that in master mode, the module will continue to work if you don't read the last received buffer before the next exchange is complete. IIRC you will get the 'buffer overflow' bit set but that does not stop the module. However on the slave side, if the overflow bit is set then it will stop working until the bit is cleared by the firmware.
According to the manual, the overflow bit only operates in Slave mode. Again, probably because the assumption is that Master has complete control over the transfer timing, so it should never encounter an overflow if it is coded correctly. On the Slave side, you might have timing issues (interrupt latency or whatever) that could create overflows if the Master is really pumping out the bytes.
Why this happens only with this particular piece of code (and only when built by XC8) remains a mystery. I've got a nearly identical piece of code in different XC8 project that reads the same chip over SPI and it skips the first read and works just fine.
It's not a critical problem because the code now works fine with the fix shown above - I'm just curious as to why it failed in this circumstance.