I have a buffer that I use for UART, which is declared this way:
union   Eusart_Buff {
    uint8_t     b8[16];
    uint16_t    b9[16];
};
struct  Eusart_Msg {
    uint8_t             msg_posn;
    uint8_t             msg_len;
    union Eusart_Buff   buff;
};
struct  Eusart {
    struct Eusart_Msg   tx;
    struct Eusart_Msg   rx;
};
extern  volatile    struct Eusart   eusart;
And here is the function that fills the buffer (which will be sent using interrupts):
void    eusart_msg_transmit (uint8_t n, void *msg)
{
    if (!n)
        return;
    /*
     * The end of the previous transmission will reset
     * eusart.tx.msg_len (i.e. ISR is off)
     */
    while (eusart.tx.msg_len)
        ;
    if (data_9b) {
        memcpy((void *)eusart.tx.buff.b9, msg,
                sizeof(eusart.tx.buff.b9[0]) * n);
    } else {
        memcpy((void *)eusart.tx.buff.b8, msg,
                sizeof(eusart.tx.buff.b8[0]) * n);
    }
    eusart.tx.msg_len   = n;
    eusart.tx.msg_posn  = 0;
    reg_PIE1_TXIE_write(true);
}
At the moment of using memcpy(), I know no one else is going to use the buffer (atomic), because the while loop ensures that the last message has been sent, and therefore the interrupt is disabled.
Is it safe to cast away volatile this way so that I am able to use memcpy() or should I make a function maybe called memcpy_v() like these to be safe?:
void *memcpy_vin(void *dest, const volatile void *src, size_t n)
{
    const volatile char *src_c  = (const volatile char *)src;
    char *dest_c                = (char *)dest;
    for (size_t i = 0; i < n; i++)
        dest_c[i]   = src_c[i];
    return  dest;
}
volatile void *memcpy_vout(volatile void *dest, const void *src, size_t n)
{
    const char *src_c       = (const char *)src;
    volatile char *dest_c   = (volatile char *)dest;
    for (size_t i = 0; i < n; i++)
        dest_c[i]   = src_c[i];
    return  dest;
}
volatile void *memcpy_v(volatile void *dest, const volatile void *src, size_t n)
{
    const volatile char *src_c  = (const volatile char *)src;
    volatile char *dest_c       = (volatile char *)dest;
    for (size_t i = 0; i < n; i++)
        dest_c[i]   = src_c[i];
    return  dest;
}
Edit:
If I need those new functions,
given that I know no one is going to modify the array at the same time, would it make sense to use restrict to (maybe) help the compiler optimize (if it can)?
Possibly this way (correct me if I'm wrong):
volatile void *memcpy_v(restrict volatile void *dest,
                        const restrict volatile void *src,
                        size_t n)
{
    const restrict volatile char *src_c = src;
    restrict volatile char *dest_c      = dest;
    for (size_t i = 0; i < n; i++)
        dest_c[i]   = src_c[i];
    return  dest;
}
Edit 2 (add context):
void    eusart_end_transmission (void)
{
    reg_PIE1_TXIE_write(false); /* TXIE is TX interrupt enable */
    eusart.tx.msg_len   = 0;
    eusart.tx.msg_posn  = 0;
}
void    eusart_tx_send_next_c   (void)
{
    uint16_t    tmp;
    if (data_9b) {
        tmp     = eusart.tx.buff.b9[eusart.tx.msg_posn++];
        reg_TXSTA_TX9D_write(tmp >> 8);
        TXREG   = tmp;
    } else {
        TXREG   = eusart.tx.buff.b8[eusart.tx.msg_posn++];
    }
}
void __interrupt()  isr(void)
{
    if (reg_PIR1_TXIF_read()) {
        if (eusart.tx.msg_posn >= eusart.tx.msg_len)
            eusart_end_transmission();
        else
            eusart_tx_send_next_c();
    }
}
Although volatile may not be is needed (I asked it in another question: volatile for variable that is only read in ISR?), this question still should be answered in the assumption that volatile is needed so that future users that really need volatile (for example me when I implement the RX buffer), can know what to do.
EDIT (Related) (Jul/19):
volatile vs memory barrier for interrupts
Basically says that volatile is not needed, and therefore this issue disappears.
 
     
     
    