The assignment operator is not defined in terms of memcpy (§12.8/28).
The implicitly-defined copy/move assignment operator for a non-union
  class X performs memberwise copy/move assignment of its subobjects.
  The direct base classes of X are assigned first, in the order of their
  declaration in the base-specifier-list, and then the immediate
  non-static data members of X are assigned, in the order in which they
  were declared in the class definition. Let x be either the parameter
  of the function or, for the move operator, an xvalue referring to the
  parameter. Each subobject is assigned in the manner appropriate to its
  type:
[...]
— if the subobject is an array, each element is assigned, in the
  manner appropriate to the element type;
[...]
As you see, each char element will be assigned individually. That is always safe.
However, under the as-if rule, a compiler may replace this with a memmove because it has identical behaviour for a char array. It could also replace it with a memcpy if it can guarantee that memcpy will result in this same behaviour, even if theoretically such a thing is undefined. Compilers can rely on theoretically undefined behaviour; one of the reasons undefined behaviour exists is so that compilers can define it to whatever is more appropriate for their operation.
Actually, in this case a compiler could take the as-if rule even further and not do anything with the array at all, since that also results in the same behaviour.