Я бы вместо механизма исклений ввёл на уровень языка тип возвращаемого функцией значения ErrorFlag. Если программист игнорирует возвращаемое значение такой функции, то есть использует её как процедуру, то компилятор сам дописывает аналог обработчика с аварийным завершением.

Поясню на примере. В большинстве случаев отказ в выделении памяти критичен для приложения. Одна есть ситуации, когда программист намеренно пытается выделить место под, возможно, большой объём данных и хочет узнать, можно это сделать или нет. В этом случае недостаток памяти не должен привести к АВОСТу.

1) Вариант, когда программист считает, что результат должен быть всегда положительным.
NEW(A);

Результат компиляции:
IF ~NEW(A) THEN ASSERT(FALSE) END;

2) Вариант, когда программист выделяет большой объём памяти, размер которой задаётся внешними факторами (например, размеров считываемого в память файла):

IF NEW(A) THEN
...
ELSE
...
END;

Поскольку результат функции не был проигнорирован, дополнительного кода компилятор не создаёт.

Данный подход позволяет полностью избавиться от необходимости механизма исключений в подобных функциях. Пример математической функции:
FUNCTION Divide (A, B: INTEGER; OUT Res: INTEGER): ErrorFlag;

...
Divide(A, B, C); // если B = 0, то программа аварийно завершится из-за деления на нуль
...
IF Divide(A, B, C) THEN // программист определяет логику обработки
...
END;

Ну и последнее, о чём хотел написать. Исключения нужны, чтобы выполнить предсмертные действия. Здесь достаточно процедуры установки подпрограммы, которая будет выполнена при аварийном завершении программы. Что-то вроде SetHaltHandler.