Стандарт не делает разницы между простыми и сложными типами. Удаление наследника через указатель на родителя без виртуального деструктора - всегда неопределенное поведение.
In a single-object delete expression, if the static type of the object to be deleted is not similar ([conv.qual]) to its dynamic type and the selected deallocation function (see below) is not a destroying operator delete, the static type shall be a base class of the dynamic type of the object to be deleted and the static type shall have a virtual destructor or the behavior is undefined.
Вольный перевод: если вызвать delete на указателе типа A *, который на самом деле указывает на объект типа B, то B должен быть наследником A, и у A должен быть виртуальный деструктор, иначе поведение не определено.
На практике да, если B не добавляет новых полей с непустыми деструкторами, то ничего не должно сломаться.
Но можно словить краш, если экземпляр родителя находится не в самом начале потомка, а где-то в середине (потому что перед ним - другой родитель, или указатель на виртуальную таблицу). Из-за этого в функцию, освобождающую память (operator delete()) приходит не тот адрес.
struct A {int x;};
struct C : A {virtual void foo() {}};
int main()
{
A *a = new C;
delete a;
}
struct A {int x;};
struct B {int y;};
struct C : A, B {};
int main()
{
B *b = new C;
delete b;
}
struct A {int x;};
struct C : virtual A {};
int main()
{
A *a = new C;
delete a;
}