summaryrefslogtreecommitdiff
path: root/compiler_and_linker/FrontEnd/C/CException.c
diff options
context:
space:
mode:
authorAsh Wolf <ninji@wuffs.org>2023-01-26 11:30:47 +0000
committerAsh Wolf <ninji@wuffs.org>2023-01-26 11:30:47 +0000
commit094b96ca1df4a035b5f93c351f773306c0241f3f (patch)
tree95ce05e3ebe816c7ee7996206bb37ea17d8ca33c /compiler_and_linker/FrontEnd/C/CException.c
parentfc0c4c0df7b583b55a08317cf1ef6a71d27c0440 (diff)
downloadMWCC-094b96ca1df4a035b5f93c351f773306c0241f3f.tar.gz
MWCC-094b96ca1df4a035b5f93c351f773306c0241f3f.zip
move lots of source files around to match their actual placement in the original treemain
Diffstat (limited to 'compiler_and_linker/FrontEnd/C/CException.c')
-rw-r--r--compiler_and_linker/FrontEnd/C/CException.c2183
1 files changed, 2183 insertions, 0 deletions
diff --git a/compiler_and_linker/FrontEnd/C/CException.c b/compiler_and_linker/FrontEnd/C/CException.c
new file mode 100644
index 0000000..d68ce13
--- /dev/null
+++ b/compiler_and_linker/FrontEnd/C/CException.c
@@ -0,0 +1,2183 @@
+#include "compiler/CException.h"
+#include "compiler/CABI.h"
+#include "compiler/CClass.h"
+#include "compiler/CDecl.h"
+#include "compiler/CError.h"
+#include "compiler/CExpr.h"
+#include "compiler/CFunc.h"
+#include "compiler/CInline.h"
+#include "compiler/CInit.h"
+#include "compiler/CMachine.h"
+#include "compiler/CMangler.h"
+#include "compiler/CParser.h"
+#include "compiler/CPrep.h"
+#include "compiler/CPrepTokenizer.h"
+#include "compiler/CScope.h"
+#include "compiler/CompilerTools.h"
+#include "compiler/Exceptions.h"
+#include "compiler/objects.h"
+#include "compiler/scopes.h"
+#include "compiler/types.h"
+
+typedef struct UniqueObj {
+ struct UniqueObj *next;
+ Object *object;
+ SInt32 uniqueid;
+} UniqueObj;
+
+ExceptionAction *cexcept_dobjstack;
+Boolean cexcept_hasdobjects;
+Boolean cexcept_magic;
+static UniqueObj *cexcept_uniqueobjs;
+static Boolean cexcept_canthrow;
+static DtorTemp *cexcept_dtortemps;
+static Statement *cexcept_prevstmt;
+static ExceptionAction *cexcept_eabefore;
+static ExceptionAction *cexcept_eaafter;
+static Boolean cexcept_expandtrycatch;
+static Boolean cexcept_hastrycatch;
+static Boolean cexcept_serialize;
+
+// forward decls
+static ENode *CExcept_TempTransExprCond(ENode *expr);
+static ENode *CExcept_TempTransExpr(ENode *expr);
+
+void CExcept_Setup(void) {
+ cexcept_dobjstack = NULL;
+ cexcept_uniqueobjs = NULL;
+ cexcept_hasdobjects = 0;
+ cexcept_magic = 0;
+}
+
+Boolean CExcept_CanThrowException(Object *object, Boolean flag) {
+ if (copts.optEH && IS_TYPE_FUNC(object->type)) {
+ if (flag)
+ return 1;
+
+ if (TYPE_FUNC(object->type)->flags & FUNC_NOTHROW)
+ return 0;
+
+ if (
+ !flag &&
+ TYPE_FUNC(object->type)->exspecs &&
+ TYPE_FUNC(object->type)->exspecs &&
+ !TYPE_FUNC(object->type)->exspecs->type
+ )
+ return 0;
+
+ if (
+ copts.optEH2 &&
+ !(object->qual & Q_MANGLE_NAME) &&
+ object != rt_ptmf_call &&
+ object != rt_ptmf_scall &&
+ object != Rdync_func &&
+ object != rt_som_glue1 &&
+ object != rt_som_glue2 &&
+ object != rt_som_glue3 &&
+ object != carr_func &&
+ object != cnar_func &&
+ object != darr_func &&
+ object != dnar_func &&
+ object != dnar3_func &&
+ object != Xthrw_func
+ )
+ return 0;
+ }
+
+ return 1;
+}
+
+void CExcept_CheckStackRefs(ExceptionAction *actions) {
+ while (actions) {
+ switch (actions->type) {
+ case EAT_DESTROYLOCAL:
+ CInline_ObjectAddrRef(actions->data.destroy_local.dtor);
+ break;
+ case EAT_DESTROYLOCALCOND:
+ CInline_ObjectAddrRef(actions->data.destroy_local_cond.dtor);
+ break;
+ case EAT_DESTROYLOCALOFFSET:
+ CInline_ObjectAddrRef(actions->data.destroy_local_offset.dtor);
+ break;
+ case EAT_DESTROYLOCALPOINTER:
+ CInline_ObjectAddrRef(actions->data.destroy_local_pointer.dtor);
+ break;
+ case EAT_DESTROYLOCALARRAY:
+ CInline_ObjectAddrRef(actions->data.destroy_local_array.dtor);
+ break;
+ case EAT_DESTROYPARTIALARRAY:
+ CInline_ObjectAddrRef(actions->data.destroy_partial_array.dtor);
+ break;
+ case EAT_DESTROYMEMBER:
+ case EAT_DESTROYBASE:
+ CInline_ObjectAddrRef(actions->data.destroy_member.dtor);
+ break;
+ case EAT_DESTROYMEMBERCOND:
+ CInline_ObjectAddrRef(actions->data.destroy_member_cond.dtor);
+ break;
+ case EAT_DESTROYMEMBERARRAY:
+ CInline_ObjectAddrRef(actions->data.destroy_member_array.dtor);
+ break;
+ case EAT_DELETEPOINTER:
+ case EAT_DELETELOCALPOINTER:
+ CInline_ObjectAddrRef(actions->data.delete_pointer.deletefunc);
+ break;
+ case EAT_DELETEPOINTERCOND:
+ CInline_ObjectAddrRef(actions->data.delete_pointer_cond.deletefunc);
+ break;
+ case EAT_CATCHBLOCK:
+ case EAT_ACTIVECATCHBLOCK:
+ case EAT_SPECIFICATION:
+ case EAT_TERMINATE:
+ break;
+ default:
+ CError_FATAL(192);
+ }
+ actions = actions->prev;
+ }
+}
+
+void CExcept_CompareSpecifications(ExceptSpecList *a, ExceptSpecList *b) {
+ ExceptSpecList *aa;
+ ExceptSpecList *bb;
+
+ aa = a;
+ bb = b;
+ while (1) {
+ if (!aa) {
+ if (!bb)
+ break;
+ CError_Error(CErrorStr265);
+ return;
+ }
+
+ if (!bb) {
+ CError_Error(CErrorStr265);
+ return;
+ }
+
+ aa = aa->next;
+ bb = bb->next;
+ }
+
+ if (a->type == NULL) {
+ if (b->type != NULL)
+ CError_Error(CErrorStr265);
+ } else if (b->type == NULL) {
+ CError_Error(CErrorStr265);
+ } else {
+ for (aa = a; aa; aa = aa->next) {
+ for (bb = b; bb; bb = bb->next) {
+ if (is_typesame(aa->type, bb->type) && aa->qual == bb->qual)
+ break;
+ }
+
+ if (bb == NULL) {
+ CError_Error(CErrorStr265);
+ return;
+ }
+ }
+ }
+}
+
+Boolean CExcept_ActionCompare(ExceptionAction *a, ExceptionAction *b) {
+ if (a->type == b->type) {
+ switch (a->type) {
+ case EAT_DESTROYLOCAL:
+ return a->data.destroy_local.local == b->data.destroy_local.local;
+ case EAT_DESTROYLOCALCOND:
+ return a->data.destroy_local_cond.local == b->data.destroy_local_cond.local;
+ case EAT_DESTROYLOCALOFFSET:
+ return a->data.destroy_local_offset.local == b->data.destroy_local_offset.local &&
+ a->data.destroy_local_offset.offset == b->data.destroy_local_offset.offset;
+ case EAT_DESTROYLOCALPOINTER:
+ return a->data.destroy_local_pointer.pointer == b->data.destroy_local_pointer.pointer;
+ case EAT_DESTROYLOCALARRAY:
+ return a->data.destroy_local_array.localarray == b->data.destroy_local_array.localarray;
+ case EAT_DESTROYPARTIALARRAY:
+ return a->data.destroy_partial_array.arraypointer == b->data.destroy_partial_array.arraypointer;
+ case EAT_DESTROYMEMBER:
+ case EAT_DESTROYBASE:
+ return a->data.destroy_member.objectptr == b->data.destroy_member.objectptr &&
+ a->data.destroy_member.offset == b->data.destroy_member.offset;
+ case EAT_DESTROYMEMBERCOND:
+ return a->data.destroy_member_cond.objectptr == b->data.destroy_member_cond.objectptr &&
+ a->data.destroy_member_cond.offset == b->data.destroy_member_cond.offset;
+ case EAT_DESTROYMEMBERARRAY:
+ return a->data.destroy_member_array.objectptr == b->data.destroy_member_array.objectptr &&
+ a->data.destroy_member_array.offset == b->data.destroy_member_array.offset;
+ case EAT_DELETEPOINTER:
+ case EAT_DELETELOCALPOINTER:
+ return a->data.delete_pointer.pointerobject == b->data.delete_pointer.pointerobject &&
+ a->data.delete_pointer.deletefunc == b->data.delete_pointer.deletefunc;
+ case EAT_DELETEPOINTERCOND:
+ return a->data.delete_pointer_cond.cond == b->data.delete_pointer_cond.cond;
+ case EAT_CATCHBLOCK:
+ return a->data.catch_block.catch_label == b->data.catch_block.catch_label;
+ case EAT_ACTIVECATCHBLOCK:
+ return a->data.active_catch_block.catch_info_object == b->data.active_catch_block.catch_info_object;
+ case EAT_TERMINATE:
+ return 1;
+ case EAT_SPECIFICATION:
+ return a->data.specification.unexp_id == b->data.specification.unexp_id;
+ default:
+ CError_FATAL(314);
+ }
+ }
+
+ return 0;
+}
+
+int CExcept_IsSubList(ExceptionAction *a, ExceptionAction *b) {
+ int diff;
+ int i;
+ int count1;
+ int count2;
+ ExceptionAction *scan;
+
+ if (a == b)
+ return 0;
+
+ count1 = 0;
+ scan = a;
+ while (scan) {
+ scan = scan->prev;
+ count1++;
+ }
+
+ scan = b;
+ count2 = 0;
+ while (scan) {
+ scan = scan->prev;
+ count2++;
+ }
+
+ diff = count2 - count1;
+ if (diff < 0)
+ return -1;
+
+ for (i = 0; i < diff; i++)
+ b = b->prev;
+
+ while (a != b) {
+ if (!a || !b || !CExcept_ActionCompare(a, b))
+ return -1;
+ a = a->prev;
+ b = b->prev;
+ }
+
+ return diff;
+}
+
+Boolean CExcept_ActionNeedsDestruction(ExceptionAction *action) {
+ switch (action->type) {
+ case EAT_CATCHBLOCK:
+ return 0;
+ case EAT_DESTROYLOCAL:
+ case EAT_DESTROYLOCALOFFSET:
+ case EAT_DESTROYLOCALARRAY:
+ case EAT_DELETELOCALPOINTER:
+ case EAT_ACTIVECATCHBLOCK:
+ return 1;
+ case EAT_NOP:
+ case EAT_DESTROYMEMBER:
+ case EAT_DESTROYMEMBERCOND:
+ case EAT_DESTROYMEMBERARRAY:
+ case EAT_DESTROYBASE:
+ break;
+ default:
+ CError_FATAL(363);
+ }
+
+ return 0;
+}
+
+ENode *CExcept_RegisterDestructorObject(Object *local, SInt32 offset, Object *dtor, Boolean flag) {
+ ExceptionAction *action;
+ ENode *expr;
+ Object *dtorObject;
+
+ action = lalloc(sizeof(ExceptionAction));
+ memclrw(action, sizeof(ExceptionAction));
+
+ action->prev = cexcept_dobjstack;
+ cexcept_dobjstack = action;
+
+ expr = create_objectrefnode(local);
+ dtorObject = CABI_GetDestructorObject(dtor, CABIDestroy1);
+
+ if (offset == 0) {
+ action->type = EAT_DESTROYLOCAL;
+ action->data.destroy_local.local = local;
+ action->data.destroy_local.dtor = dtorObject;
+ } else {
+ action->type = EAT_DESTROYLOCALOFFSET;
+ action->data.destroy_local_offset.local = local;
+ action->data.destroy_local_offset.dtor = dtorObject;
+ action->data.destroy_local_offset.offset = offset;
+ expr = makediadicnode(expr, intconstnode(TYPE(&stunsignedlong), offset), EADD);
+ }
+
+ cexcept_hasdobjects = 1;
+ return expr;
+}
+
+void CExcept_RegisterLocalArray(Statement *stmt, Object *localarray, Object *dtor, SInt32 elements, SInt32 element_size) {
+ ExceptionAction *action;
+ Object *dtorObject;
+
+ action = lalloc(sizeof(ExceptionAction));
+ memclrw(action, sizeof(ExceptionAction));
+
+ action->prev = cexcept_dobjstack;
+ cexcept_dobjstack = action;
+
+ dtorObject = CABI_GetDestructorObject(dtor, CABIDestroy1);
+
+ action->type = EAT_DESTROYLOCALARRAY;
+ action->data.destroy_local_array.localarray = localarray;
+ action->data.destroy_local_array.dtor = dtorObject;
+ action->data.destroy_local_array.elements = elements;
+ action->data.destroy_local_array.element_size = element_size;
+
+ cexcept_hasdobjects = 1;
+}
+
+void CExcept_RegisterDeleteObject(Statement *stmt, Object *pointerobject, Object *deletefunc) {
+ ExceptionAction *action;
+
+ action = lalloc(sizeof(ExceptionAction));
+ memclrw(action, sizeof(ExceptionAction));
+
+ action->prev = cexcept_dobjstack;
+ cexcept_dobjstack = action;
+
+ action->type = EAT_DELETELOCALPOINTER;
+ action->data.delete_pointer.pointerobject = pointerobject;
+ action->data.delete_pointer.deletefunc = deletefunc;
+
+ cexcept_hasdobjects = 1;
+}
+
+static void CExcept_PatchConstructorAction(Statement *stmt, ExceptionAction *actionArg) {
+ ExceptionAction *action30;
+ ExceptionAction *action;
+ ExceptionAction *scan;
+
+ for (action = stmt->dobjstack; action; action = action->prev) {
+ switch (action->type) {
+ case EAT_DESTROYMEMBER:
+ case EAT_DESTROYMEMBERCOND:
+ case EAT_DESTROYMEMBERARRAY:
+ case EAT_SPECIFICATION:
+ case EAT_DESTROYBASE:
+ goto exitFirstLoop;
+ case EAT_CATCHBLOCK:
+ action30 = action;
+ while (1) {
+ if (!action30->prev)
+ goto exitFirstLoop;
+ action30 = action30->prev;
+ if (action30->type != EAT_CATCHBLOCK) {
+ CError_FATAL(481);
+ }
+ }
+ }
+ }
+ exitFirstLoop:
+ if (action == NULL) {
+ while (stmt) {
+ if ((scan = stmt->dobjstack)) {
+ while (1) {
+ if (scan == actionArg)
+ break;
+ if (scan->prev == NULL) {
+ scan->prev = actionArg;
+ break;
+ }
+ scan = scan->prev;
+ }
+ } else {
+ stmt->dobjstack = actionArg;
+ }
+ stmt = stmt->next;
+ }
+ } else {
+ actionArg->prev = action;
+ while (stmt) {
+ if (stmt->dobjstack != action) {
+ scan = stmt->dobjstack;
+ do {
+ if (scan == actionArg)
+ goto nextStmt;
+ if (scan->prev == action) {
+ scan->prev = actionArg;
+ goto nextStmt;
+ }
+ } while ((scan = scan->prev));
+
+ while (1) {
+ if (action->type == EAT_CATCHBLOCK && action->prev == NULL)
+ return;
+
+ action = action->prev;
+ if (!action)
+ CError_FATAL(531);
+ }
+ } else {
+ stmt->dobjstack = actionArg;
+ }
+ nextStmt:
+ stmt = stmt->next;
+ }
+ }
+}
+
+void CExcept_Terminate(void) {
+ ExceptionAction *action;
+
+ action = lalloc(sizeof(ExceptionAction));
+ memclrw(action, sizeof(ExceptionAction));
+
+ action->type = EAT_TERMINATE;
+
+ action->prev = cexcept_dobjstack;
+ cexcept_dobjstack = action;
+}
+
+void CExcept_Magic(void) {
+ cexcept_magic = 1;
+}
+
+static Object *CExcept_FindLocalObject(char *name) {
+ NameResult result;
+ NameSpaceObjectList *list;
+
+ list = CScope_FindObjectList(&result, GetHashNameNodeExport(name));
+ if (list && list->object->otype == OT_OBJECT && OBJECT(list->object)->datatype == DLOCAL)
+ return OBJECT(list->object);
+
+ CError_FATAL(580);
+ return NULL;
+}
+
+void CExcept_ArrayInit(void) {
+ ExceptionAction *action;
+
+ action = lalloc(sizeof(ExceptionAction));
+ memclrw(action, sizeof(ExceptionAction));
+
+ action->type = EAT_DESTROYPARTIALARRAY;
+ action->data.destroy_partial_array.arraypointer = CExcept_FindLocalObject("ptr");
+ action->data.destroy_partial_array.arraycounter = CExcept_FindLocalObject("i");
+ action->data.destroy_partial_array.dtor = CExcept_FindLocalObject("dtor");
+ action->data.destroy_partial_array.element_size = CExcept_FindLocalObject("size");
+
+ action->prev = cexcept_dobjstack;
+ cexcept_dobjstack = action;
+}
+
+void CExcept_RegisterMember(Statement *stmt, Object *objectptr, SInt32 offset, Object *dtor, Object *cond, Boolean isMember) {
+ ExceptionAction *action;
+
+ action = lalloc(sizeof(ExceptionAction));
+ memclrw(action, sizeof(ExceptionAction));
+
+ if (cond == NULL) {
+ if (isMember) {
+ action->type = EAT_DESTROYMEMBER;
+ action->data.destroy_member.dtor = CABI_GetDestructorObject(dtor, CABIDestroy1);
+ } else {
+ action->type = EAT_DESTROYBASE;
+ action->data.destroy_member.dtor = CABI_GetDestructorObject(dtor, CABIDestroy0);
+ }
+ action->data.destroy_member.objectptr = objectptr;
+ action->data.destroy_member.offset = offset;
+ } else {
+ CError_ASSERT(632, cond->type == TYPE(&stsignedshort));
+ action->type = EAT_DESTROYMEMBERCOND;
+ action->data.destroy_member_cond.objectptr = objectptr;
+ action->data.destroy_member_cond.cond = cond;
+ action->data.destroy_member_cond.dtor = CABI_GetDestructorObject(dtor, CABIDestroy1);
+ action->data.destroy_member_cond.offset = offset;
+ }
+
+ CExcept_PatchConstructorAction(stmt, action);
+ stmt->flags |= StmtFlag_2;
+}
+
+void CExcept_RegisterMemberArray(Statement *stmt, Object *objectptr, SInt32 offset, Object *dtor, SInt32 elements, SInt32 element_size) {
+ ExceptionAction *action;
+
+ action = lalloc(sizeof(ExceptionAction));
+ memclrw(action, sizeof(ExceptionAction));
+
+ action->type = EAT_DESTROYMEMBERARRAY;
+ action->data.destroy_member_array.objectptr = objectptr;
+ action->data.destroy_member_array.dtor = CABI_GetDestructorObject(dtor, CABIDestroy1);
+ action->data.destroy_member_array.offset = offset;
+ action->data.destroy_member_array.elements = elements;
+ action->data.destroy_member_array.element_size = element_size;
+
+ CExcept_PatchConstructorAction(stmt, action);
+ stmt->flags |= StmtFlag_2;
+}
+
+static Statement *CExcept_DestroyLocal(ExceptionAction *ea, Statement *stmt, Object *object, Object *dtor, SInt32 offset) {
+ ENode *expr;
+
+ expr = create_objectrefnode(object);
+ if (offset)
+ expr = makediadicnode(expr, intconstnode(TYPE(&stunsignedlong), offset), EADD);
+
+ expr = CABI_DestroyObject(dtor, expr, CABIDestroy1, 1, 0);
+
+ CError_ASSERT(687, expr->type == EFUNCCALL && expr->data.funccall.funcref->type == EOBJREF);
+ if (expr->data.funccall.funcref->data.objref->datatype == DVFUNC)
+ expr->data.funccall.funcref->flags |= ENODE_FLAG_80;
+
+ stmt = CFunc_InsertStatement(ST_EXPRESSION, stmt);
+ stmt->expr = expr;
+ stmt->dobjstack = ea->prev;
+ return stmt;
+}
+
+static Statement *CExcept_DestroyLocalPointer(ExceptionAction *ea, Statement *stmt, Object *object, Object *deletefunc) {
+ Statement *newStmt;
+
+ newStmt = CFunc_InsertStatement(ST_EXPRESSION, stmt);
+ newStmt->expr = funccallexpr(deletefunc, create_objectnode2(object), NULL, NULL, NULL);
+ newStmt->dobjstack = ea->prev;
+ return newStmt;
+}
+
+static Statement *CExcept_DestroyLocalArray(ExceptionAction *ea, Statement *stmt, Object *object, Object *dtor, SInt32 elements, SInt32 element_size) {
+ Statement *newStmt;
+ ENode *dtorExpr;
+
+ newStmt = CFunc_InsertStatement(ST_EXPRESSION, stmt);
+
+ if (dtor)
+ dtorExpr = create_objectrefnode(CABI_GetDestructorObject(dtor, CABIDestroy1));
+ else
+ dtorExpr = nullnode();
+
+ newStmt->expr = funccallexpr(
+ darr_func,
+ create_objectrefnode(object),
+ dtorExpr,
+ intconstnode(TYPE(&stunsignedlong), element_size),
+ intconstnode(TYPE(&stunsignedlong), elements)
+ );
+
+ newStmt->dobjstack = ea->prev;
+ return newStmt;
+}
+
+static Statement *CExcept_EndCatch(ExceptionAction *ea, Statement *stmt) {
+ stmt = CFunc_InsertStatement(ST_ENDCATCHDTOR, stmt);
+ stmt->expr = create_objectrefnode(ea->data.active_catch_block.catch_info_object);
+ stmt->dobjstack = ea->prev;
+ if (!ea->data.active_catch_block.call_dtor)
+ stmt->type = ST_ENDCATCH;
+ return stmt;
+}
+
+Statement *CExcept_ActionCleanup(ExceptionAction *ea, Statement *stmt) {
+ switch (ea->type) {
+ case EAT_DESTROYLOCALCOND:
+ case EAT_DESTROYLOCALPOINTER:
+ case EAT_DESTROYPARTIALARRAY:
+ case EAT_DESTROYMEMBER:
+ case EAT_DESTROYMEMBERCOND:
+ case EAT_DESTROYMEMBERARRAY:
+ case EAT_DELETEPOINTER:
+ case EAT_DELETEPOINTERCOND:
+ case EAT_CATCHBLOCK:
+ case EAT_SPECIFICATION:
+ case EAT_TERMINATE:
+ case EAT_DESTROYBASE:
+ break;
+ case EAT_DESTROYLOCAL:
+ stmt = CExcept_DestroyLocal(
+ ea, stmt,
+ ea->data.destroy_local.local,
+ ea->data.destroy_local.dtor,
+ 0);
+ break;
+ case EAT_DESTROYLOCALOFFSET:
+ stmt = CExcept_DestroyLocal(
+ ea, stmt,
+ ea->data.destroy_local.local,
+ ea->data.destroy_local.dtor,
+ ea->data.destroy_local_offset.offset);
+ break;
+ case EAT_DELETELOCALPOINTER:
+ stmt = CExcept_DestroyLocalPointer(
+ ea, stmt,
+ ea->data.delete_pointer.pointerobject,
+ ea->data.delete_pointer.deletefunc);
+ break;
+ case EAT_DESTROYLOCALARRAY:
+ stmt = CExcept_DestroyLocalArray(
+ ea, stmt,
+ ea->data.destroy_local_array.localarray,
+ ea->data.destroy_local_array.dtor,
+ ea->data.destroy_local_array.elements,
+ ea->data.destroy_local_array.element_size);
+ break;
+ case EAT_ACTIVECATCHBLOCK:
+ stmt = CExcept_EndCatch(ea, stmt);
+ break;
+ default:
+ CError_FATAL(827);
+ }
+
+ return stmt;
+}
+
+static void CExcept_MangleNameSpaceName(NameSpace *nspace) {
+ while (nspace) {
+ if (nspace->name) {
+ CExcept_MangleNameSpaceName(nspace->parent);
+ AppendGListName(&name_mangle_list, nspace->name->name);
+ AppendGListName(&name_mangle_list, "::");
+ break;
+ }
+ nspace = nspace->parent;
+ }
+}
+
+static void CExcept_MangleClassName(TypeClass *tclass) {
+ NameSpace *nspace;
+ char buf[64];
+
+ CExcept_MangleNameSpaceName(tclass->nspace->parent);
+ AppendGListName(&name_mangle_list, tclass->classname->name);
+
+ for (nspace = tclass->nspace->parent; nspace; nspace = nspace->parent) {
+ if (!nspace->is_global && !nspace->is_templ && !nspace->name) {
+ CError_ASSERT(868, cscope_currentfunc != NULL);
+
+ sprintf(buf, "*%" PRIxPTR "*%" PRIxPTR "*", &cscope_currentfunc, &nspace);
+ AppendGListName(&name_mangle_list, buf);
+ break;
+ }
+ }
+}
+
+typedef struct BCL {
+ struct BCL *next;
+ TypeClass *tclass;
+ SInt32 offset;
+ Boolean is_virtual;
+ Boolean is_public;
+ Boolean is_ambig;
+} BCL;
+
+static void CExcept_MakeBaseClassListAmbig(BCL *bcl, TypeClass *tclass) {
+ BCL *scan;
+ ClassList *list;
+
+ for (scan = bcl; scan; scan = scan->next) {
+ if (scan->tclass == tclass)
+ scan->is_ambig = 1;
+ }
+
+ for (list = tclass->bases; list; list = list->next)
+ CExcept_MakeBaseClassListAmbig(bcl, list->base);
+}
+
+static BCL *CExcept_GetBaseClassList(BCL *bcl, TypeClass *tclass1, TypeClass *tclass2, SInt32 offset, Boolean is_virtual, Boolean is_public) {
+ BCL *node;
+ ClassList *base;
+ Boolean new_is_public;
+
+ for (node = bcl; node; node = node->next) {
+ if (node->tclass == tclass2) {
+ if (is_virtual && node->is_virtual) {
+ if (is_public)
+ node->is_public = 1;
+ } else {
+ CExcept_MakeBaseClassListAmbig(bcl, tclass2);
+ }
+ return bcl;
+ }
+ }
+
+ node = lalloc(sizeof(BCL));
+ node->tclass = tclass2;
+ node->offset = offset;
+ node->is_virtual = is_virtual;
+ node->is_public = is_public;
+ node->is_ambig = 0;
+ node->next = bcl;
+ bcl = node;
+
+ for (base = tclass2->bases; base; base = base->next) {
+ new_is_public = is_public && (base->access == ACCESSPUBLIC);
+ bcl = base->is_virtual
+ ? CExcept_GetBaseClassList(bcl, tclass1, base->base, CClass_VirtualBaseOffset(tclass1, base->base), 1, new_is_public)
+ : CExcept_GetBaseClassList(bcl, tclass1, base->base, offset + base->offset, 0, new_is_public);
+ }
+
+ return bcl;
+}
+
+static void CExcept_MangleClass(TypeClass *tclass) {
+ BCL *bcl;
+ char buf[20];
+
+ for (bcl = CExcept_GetBaseClassList(NULL, tclass, tclass, 0, 0, 1); bcl; bcl = bcl->next) {
+ if (bcl->is_public && !bcl->is_ambig) {
+ CExcept_MangleClassName(bcl->tclass);
+ AppendGListByte(&name_mangle_list, '!');
+
+ if (bcl->offset) {
+ sprintf(buf, "%" PRId32 "!", bcl->offset);
+ AppendGListName(&name_mangle_list, buf);
+ } else {
+ AppendGListByte(&name_mangle_list, '!');
+ }
+ }
+ }
+}
+
+static ENode *CExcept_GetTypeID(Type *type, UInt32 qual, Boolean flag) {
+ ENode *expr;
+ TypePointer my_tptr;
+
+ if (IS_TYPE_REFERENCE(type))
+ type = TPTR_TARGET(type);
+
+ if (IS_TYPE_CLASS(type) || (IS_TYPE_POINTER_ONLY(type) && IS_TYPE_CLASS(TPTR_TARGET(type)))) {
+ name_mangle_list.size = 0;
+ if (IS_TYPE_POINTER_ONLY(type)) {
+ AppendGListByte(&name_mangle_list, '*');
+ type = TPTR_TARGET(type);
+ } else {
+ AppendGListByte(&name_mangle_list, '!');
+ }
+
+ if (flag) {
+ CExcept_MangleClass(TYPE_CLASS(type));
+ } else {
+ CExcept_MangleClassName(TYPE_CLASS(type));
+ AppendGListByte(&name_mangle_list, '!');
+ }
+ } else {
+ if (IS_TYPE_POINTER_ONLY(type)) {
+ if (TPTR_QUAL(type) & (Q_CONST | Q_VOLATILE)) {
+ my_tptr = *TYPE_POINTER(type);
+ my_tptr.qual = 0;
+ type = TYPE(&my_tptr);
+ }
+ } else {
+ qual = 0;
+ }
+ CMangler_MangleType(type, qual);
+ }
+
+ AppendGListByte(&name_mangle_list, 0);
+
+ expr = CExpr_NewENode(ESTRINGCONST);
+ expr->rtype = CDecl_NewPointerType(TYPE(&stchar));
+ expr->data.string.size = name_mangle_list.size;
+ expr->data.string.data = galloc(name_mangle_list.size);
+ memcpy(expr->data.string.data, *name_mangle_list.data, name_mangle_list.size);
+ return expr;
+}
+
+static Object *CExcept_TypeID(Type *type, UInt32 qual) {
+ ENode *expr = CExcept_GetTypeID(type, qual, 0);
+ CError_ASSERT(1086, expr->type == ESTRINGCONST);
+ return CInit_DeclareString(expr->data.string.data, expr->data.string.size, 0, 0);
+}
+
+void CExcept_ScanExceptionSpecification(TypeFunc *tfunc) {
+ ExceptSpecList *exspecs;
+ ExceptSpecList *exspec;
+ DeclInfo di;
+
+ exspecs = NULL;
+
+ if (lex() != '(') {
+ CError_Error(CErrorStr114);
+ return;
+ }
+
+ if ((tk = lex()) != ')') {
+ while (1) {
+ memclrw(&di, sizeof(di));
+ CParser_GetDeclSpecs(&di, 0);
+ if (di.storageclass)
+ CError_Error(CErrorStr177);
+
+ CError_QualifierCheck(di.qual & ~(Q_CONST | Q_VOLATILE | Q_PASCAL | Q_ALIGNED_MASK));
+
+ scandeclarator(&di);
+ if (di.name)
+ CError_Error(CErrorStr146);
+
+ if (IS_TYPE_POINTER_ONLY(di.thetype)) {
+ if (TPTR_QUAL(di.thetype) & (Q_CONST | Q_VOLATILE)) {
+ TypePointer *newtype = galloc(sizeof(TypePointer));
+ *newtype = *TYPE_POINTER(di.thetype);
+ newtype->qual = 0;
+ di.thetype = TYPE(newtype);
+ }
+ } else {
+ di.qual = 0;
+ }
+
+ for (exspec = exspecs; exspec; exspec = exspec->next) {
+ if (is_typesame(exspec->type, di.thetype) && exspec->qual == di.qual)
+ break;
+ }
+
+ if (!exspec) {
+ exspec = galloc(sizeof(ExceptSpecList));
+ memclrw(exspec, sizeof(ExceptSpecList));
+ exspec->next = exspecs;
+ exspec->type = di.thetype;
+ exspec->qual = di.qual;
+ exspecs = exspec;
+ }
+
+ if (tk == ')')
+ break;
+
+ if (tk != ',') {
+ CError_Error(CErrorStr115);
+ break;
+ }
+
+ tk = lex();
+ }
+ }
+
+ if (!exspecs) {
+ exspecs = galloc(sizeof(ExceptSpecList));
+ memclrw(exspecs, sizeof(ExceptSpecList));
+ }
+ tfunc->exspecs = exspecs;
+ tk = lex();
+}
+
+static ENode *CExcept_CallCopyCtor(Object *object, Type *type, ENode *expr1, ENode *expr2) {
+ ENodeList *list;
+ ENode *expr;
+ FuncArg *arg;
+
+ if (
+ !IS_TYPE_FUNC(object->type) ||
+ !(arg = TYPE_FUNC(object->type)->args) ||
+ !(arg = arg->next)
+ )
+ CError_FATAL(1169);
+
+ expr = funccallexpr(object, expr1, NULL, NULL, NULL);
+ list = expr->data.funccall.args;
+
+ if (TYPE_CLASS(type)->flags & CLASS_HAS_VBASES) {
+ CError_ASSERT(1179, arg = arg->next);
+ list->next = lalloc(sizeof(ENodeList));
+ list = list->next;
+ list->next = NULL;
+ list->node = intconstnode(TYPE(&stsignedshort), 1);
+ }
+
+ list->next = lalloc(sizeof(ENodeList));
+ list = list->next;
+ list->next = NULL;
+ list->node = expr2;
+
+ while ((arg = arg->next)) {
+ CError_ASSERT(1195, arg->dexpr);
+
+ list->next = lalloc(sizeof(ENodeList));
+ list = list->next;
+ list->next = NULL;
+ list->node = CExpr_GetDefaultArgument(expr->data.funccall.funcref, arg);
+ }
+
+ return expr;
+}
+
+ENode *CExcept_ScanThrowExpression(void) {
+ ENode *expr;
+ Object *func;
+ ENode *resultExpr;
+ Object *obj;
+ ENode *thrownExpr;
+ ENode *tempExpr;
+
+ if (!copts.exceptions)
+ CError_Error(CErrorStr252);
+
+ switch ((tk = lex())) {
+ case ')':
+ case ',':
+ case ':':
+ case ';':
+ expr = funccallexpr(Xthrw_func, nullnode(), nullnode(), nullnode(), NULL);
+ break;
+ default:
+ thrownExpr = pointer_generation(assignment_expression());
+ obj = create_temp_object(thrownExpr->rtype);
+ if (!IS_TYPE_CLASS(thrownExpr->rtype) || !(resultExpr = CExpr_IsTempConstruction(thrownExpr, thrownExpr->rtype, &expr))) {
+ tempExpr = create_objectrefnode(obj);
+ if (IS_TYPE_CLASS(thrownExpr->rtype) && (func = CClass_CopyConstructor(TYPE_CLASS(thrownExpr->rtype)))) {
+ resultExpr = CExcept_CallCopyCtor(func, thrownExpr->rtype, tempExpr, getnodeaddress(thrownExpr, 0));
+ } else {
+ if (thrownExpr->rtype->size == 0)
+ CError_Error(CErrorStr146);
+
+ tempExpr = makemonadicnode(tempExpr, EINDIRECT);
+ tempExpr->rtype = thrownExpr->rtype;
+ resultExpr = makediadicnode(tempExpr, thrownExpr, EASS);
+ resultExpr = makediadicnode(resultExpr, create_objectrefnode(obj), ECOMMA);
+ resultExpr->rtype = TYPE(&void_ptr);
+ }
+ } else {
+ *expr = *create_objectrefnode(obj);
+ }
+
+ expr = CExcept_GetTypeID(thrownExpr->rtype, ENODE_QUALS(thrownExpr), 1);
+ if (IS_TYPE_CLASS(thrownExpr->rtype) && (func = CClass_Destructor(TYPE_CLASS(thrownExpr->rtype)))) {
+ expr = funccallexpr(
+ Xthrw_func,
+ expr,
+ resultExpr,
+ create_objectrefnode(CABI_GetDestructorObject(func, CABIDestroy1)),
+ NULL);
+ } else {
+ expr = funccallexpr(
+ Xthrw_func,
+ expr,
+ resultExpr,
+ nullnode(),
+ NULL);
+ }
+ }
+
+ expr->flags |= ENODE_FLAG_VOLATILE;
+ return expr;
+}
+
+static Boolean CExcept_MightNeedDtor(Type *type) {
+ if (type) {
+ if (IS_TYPE_CLASS(type)) {
+ if (!CClass_Destructor(TYPE_CLASS(type)))
+ return 0;
+ } else if (IS_TYPE_POINTER_ONLY(type)) {
+ if (!(TPTR_QUAL(type) & Q_REFERENCE) || !IS_TYPE_CLASS(TPTR_TARGET(type)))
+ return 0;
+ } else {
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+typedef struct CatchBlock {
+ struct CatchBlock *next;
+ Object *catch_object;
+ Object *catch_info_object;
+ Statement *stmt;
+ Statement *anotherStmt;
+ Type *type;
+ UInt32 qual;
+} CatchBlock;
+
+static void CExcept_PatchDObjStack(Statement *beginCatchStmt, Statement *tryEndStmt, Statement *endStmt, CatchBlock *catchBlock) {
+ ExceptionAction *ea;
+ ExceptionAction *stackHead;
+ ExceptionAction *stackTail;
+ ExceptionAction *firstEA;
+ Statement *stmt;
+ Object *catch_info_object;
+ Boolean call_dtor;
+
+ catch_info_object = catchBlock->catch_info_object;
+ call_dtor = 0;
+ stackHead = stackTail = beginCatchStmt->dobjstack;
+ firstEA = NULL;
+
+ while (catchBlock) {
+ ea = lalloc(sizeof(ExceptionAction));
+ memclrw(ea, sizeof(ExceptionAction));
+
+ ea->prev = stackTail;
+ stackTail = ea;
+
+ if (!firstEA)
+ firstEA = ea;
+
+ ea->type = EAT_CATCHBLOCK;
+ ea->data.catch_block.catch_object = catchBlock->catch_object;
+ ea->data.catch_block.catch_label = catchBlock->stmt->label;
+ if (catchBlock->type)
+ ea->data.catch_block.catch_typeid = CExcept_TypeID(catchBlock->type, catchBlock->qual);
+ ea->data.catch_block.catch_info_object = catch_info_object;
+
+ if (!call_dtor && CExcept_MightNeedDtor(catchBlock->type))
+ call_dtor = 1;
+
+ ea->data.catch_block.catch_type = catchBlock->type;
+ ea->data.catch_block.catch_qual = catchBlock->qual;
+ catchBlock = catchBlock->next;
+ }
+
+ stmt = beginCatchStmt;
+ while (1) {
+ if ((ea = stmt->dobjstack) != stackHead) {
+ while (1) {
+ CError_ASSERT(1404, ea);
+ if (ea->prev == stackTail)
+ break;
+ if (ea->prev == stackHead) {
+ ea->prev = stackTail;
+ break;
+ }
+ ea = ea->prev;
+ }
+ } else {
+ stmt->dobjstack = stackTail;
+ }
+
+ if (stmt == endStmt)
+ break;
+
+ if (stmt == tryEndStmt) {
+ ea = lalloc(sizeof(ExceptionAction));
+ memclrw(ea, sizeof(ExceptionAction));
+ ea->prev = stackHead;
+ ea->type = EAT_ACTIVECATCHBLOCK;
+ ea->data.active_catch_block.catch_info_object = catch_info_object;
+ ea->data.active_catch_block.call_dtor = call_dtor;
+ stackTail = ea;
+ }
+
+ stmt = stmt->next;
+ CError_ASSERT(1426, stmt);
+ }
+
+ cexcept_hasdobjects = 1;
+}
+
+static void CExcept_CheckTryObjects(ENode *expr) {
+ if (expr->data.objref->datatype == DLOCAL && expr->data.objref->u.var.info)
+ expr->data.objref->u.var.info->noregister = 1;
+}
+
+static ENode *CExcept_CatchExpressionInit(DeclInfo *di, CatchBlock *catchBlock) {
+ Object *catch_object;
+ Object *copyCtor;
+ Object *dtor;
+ ENode *expr;
+
+ if (CScope_FindName(cscope_current, di->name))
+ CError_Error(CErrorStr122, di->name->name);
+
+ catch_object = CParser_NewLocalDataObject(di, 1);
+ CFunc_SetupLocalVarInfo(catch_object);
+ CScope_AddObject(cscope_current, di->name, OBJ_BASE(catch_object));
+ catchBlock->catch_object = catch_object;
+
+ expr = makediadicnode(
+ create_objectrefnode(catchBlock->catch_info_object),
+ intconstnode(TYPE(&stunsignedlong), 12),
+ EADD);
+ expr->rtype = CDecl_NewPointerType(CDecl_NewPointerType(di->thetype));
+
+ expr = makemonadicnode(expr, EINDIRECT);
+ expr->rtype = CDecl_NewPointerType(di->thetype);
+
+ if (IS_TYPE_REFERENCE(di->thetype))
+ return makediadicnode(create_objectnode2(catch_object), expr, EASS);
+
+ if (IS_TYPE_CLASS(di->thetype) && (copyCtor = CClass_CopyConstructor(TYPE_CLASS(di->thetype)))) {
+ dtor = CClass_Destructor(TYPE_CLASS(di->thetype));
+ return CExcept_CallCopyCtor(
+ copyCtor,
+ di->thetype,
+ (dtor == NULL) ? create_objectrefnode(catch_object) : CExcept_RegisterDestructorObject(catch_object, 0, dtor, 0),
+ expr);
+ }
+
+ expr = makemonadicnode(expr, EINDIRECT);
+ expr->rtype = di->thetype;
+ return makediadicnode(create_objectnode(catch_object), expr, EASS);
+}
+
+void CExcept_ScanTryBlock(DeclThing *dt, Boolean flag) {
+ Object *catch_info_object; // r27
+ Statement *beginCatchStmt; // r14
+ Statement *tryEndStmt; // r16
+ Statement *endStmt; // r17
+ Statement *stmt; // r14
+ CLabel *catchEndLabel; // r19
+ CLabel *endLabel; // r24
+ CatchBlock *catchStack; // r23
+ CatchBlock *catchBlock; // r22
+ DeclBlock *declBlock; // r20
+ DeclInfo di;
+
+ if (!copts.exceptions)
+ CError_Error(CErrorStr252);
+
+ catch_info_object = create_temp_object(TYPE(&catchinfostruct));
+ if (cexcept_magic) {
+ catch_info_object->name = GetHashNameNodeExport("__exception_magic");
+ CScope_AddObject(cscope_current, catch_info_object->name, OBJ_BASE(catch_info_object));
+ }
+
+ stmt = CFunc_AppendStatement(ST_LABEL);
+ stmt->flags = StmtFlag_1;
+ stmt->label = newlabel();
+ stmt->label->stmt = stmt;
+
+ beginCatchStmt = CFunc_AppendStatement(ST_BEGINCATCH);
+ beginCatchStmt->expr = create_objectrefnode(catch_info_object);
+
+ if (tk != '{') {
+ CError_Error(CErrorStr135);
+ return;
+ }
+
+ CFunc_CompoundStatement(dt);
+
+ if (tk != TK_CATCH) {
+ CError_Error(CErrorStr242);
+ return;
+ }
+
+ stmt = CFunc_AppendStatement(ST_GOTO);
+ catchEndLabel = stmt->label = newlabel();
+ tryEndStmt = stmt;
+
+ endLabel = newlabel();
+ catchStack = NULL;
+
+ while (1) {
+ CPrep_GetFileOffsetInfo2(&cparser_fileoffset, &sourceoffset, &sourcefilepath);
+
+ stmt = CFunc_AppendStatement(ST_LABEL);
+ stmt->flags = StmtFlag_1;
+ stmt->label = newlabel();
+ stmt->label->stmt = stmt;
+
+ declBlock = NULL;
+
+ catchBlock = lalloc(sizeof(ExceptionAction));
+ memclrw(catchBlock, sizeof(ExceptionAction));
+ catchBlock->next = catchStack;
+ catchStack = catchBlock;
+
+ catchBlock->stmt = stmt;
+ catchBlock->catch_info_object = catch_info_object;
+
+ if ((tk = lex()) != '(') {
+ CError_Error(CErrorStr114);
+ break;
+ }
+
+ if ((tk = lex()) == TK_ELLIPSIS) {
+ tk = lex();
+ } else {
+ memclrw(&di, sizeof(di));
+ CParser_GetDeclSpecs(&di, 0);
+
+ if (di.x48)
+ CError_Error(CErrorStr121);
+ if (di.storageclass)
+ CError_Error(CErrorStr177);
+
+ CError_QualifierCheck(di.qual & ~(Q_CONST | Q_VOLATILE | Q_PASCAL | Q_ALIGNED_MASK));
+
+ scandeclarator(&di);
+
+ if (IS_TYPE_FUNC(di.thetype))
+ di.thetype = CDecl_NewPointerType(di.thetype);
+ else if (IS_TYPE_ARRAY(di.thetype))
+ di.thetype = CDecl_NewPointerType(TPTR_TARGET(di.thetype));
+
+ IsCompleteType(di.thetype);
+ if (IS_TYPE_CLASS(di.thetype) && (TYPE_CLASS(di.thetype)->flags & CLASS_ABSTRACT))
+ CError_AbstractClassError(TYPE_CLASS(di.thetype));
+
+ catchBlock->type = di.thetype;
+ catchBlock->qual = di.qual;
+
+ if (di.name) {
+ ENode *expr;
+ declBlock = CFunc_NewDeclBlock();
+ expr = CExcept_CatchExpressionInit(&di, catchBlock);
+ stmt = CFunc_AppendStatement(ST_EXPRESSION);
+ stmt->expr = expr;
+ }
+ }
+
+ if (tk != ')') {
+ CError_Error(CErrorStr115);
+ break;
+ }
+
+ if ((tk = lex()) != '{') {
+ CError_Error(CErrorStr123);
+ break;
+ }
+
+ CFunc_CompoundStatement(dt);
+ if (flag) {
+ stmt = CFunc_AppendStatement(ST_EXPRESSION);
+ stmt->expr = funccallexpr(Xthrw_func, nullnode(), nullnode(), nullnode(), NULL);
+ }
+
+ catchBlock->anotherStmt = stmt;
+
+ if (declBlock)
+ CFunc_RestoreBlock(declBlock);
+
+ if (tk != TK_CATCH)
+ break;
+
+ CFunc_AppendStatement(ST_GOTO)->label = endLabel;
+ }
+
+ endStmt = CFunc_AppendStatement(ST_LABEL);
+ endStmt->label = endLabel;
+ endLabel->stmt = endStmt;
+
+ CExcept_PatchDObjStack(beginCatchStmt, tryEndStmt, endStmt, catchBlock);
+
+ stmt = CFunc_AppendStatement(ST_LABEL);
+ stmt->label = catchEndLabel;
+ catchEndLabel->stmt = stmt;
+}
+
+static Statement *CExcept_InsertPrevStatement(StatementType sttype) {
+ Statement *stmt = CFunc_InsertStatement(sttype, cexcept_prevstmt);
+ stmt->sourceoffset = stmt->next->sourceoffset;
+ stmt->sourcefilepath = stmt->next->sourcefilepath;
+ stmt->dobjstack = cexcept_eabefore;
+ return stmt;
+}
+
+static Object *CExcept_GetETEMPObject(ENode *expr) {
+ UniqueObj *uobj;
+ SInt32 id;
+
+ if ((id = expr->data.temp.uniqueid)) {
+ for (uobj = cexcept_uniqueobjs; uobj; uobj = uobj->next) {
+ if (uobj->uniqueid == id)
+ return uobj->object;
+ }
+
+ uobj = galloc(sizeof(UniqueObj));
+ uobj->next = cexcept_uniqueobjs;
+ cexcept_uniqueobjs = uobj;
+ uobj->uniqueid = id;
+ return (uobj->object = create_temp_object(expr->data.temp.type));
+ } else {
+ return create_temp_object(expr->data.temp.type);
+ }
+}
+
+static ENode *CExcept_TempTrans_ETEMP(ENode *expr) {
+ Object *object;
+ ExceptionAction *ea;
+ DtorTemp *dtorTemp;
+ Object *dtor;
+
+ object = CExcept_GetETEMPObject(expr);
+ if (expr->data.temp.needs_dtor) {
+ dtorTemp = lalloc(sizeof(DtorTemp));
+ dtorTemp->next = cexcept_dtortemps;
+ cexcept_dtortemps = dtorTemp;
+ dtorTemp->object = object;
+ dtorTemp->temp = NULL;
+
+ if (
+ !IS_TYPE_CLASS(expr->data.temp.type) ||
+ !(dtorTemp->dtor = CClass_Destructor(TYPE_CLASS(expr->data.temp.type)))
+ )
+ CError_FATAL(1749);
+
+ ea = lalloc(sizeof(ExceptionAction));
+ ea->prev = cexcept_eabefore;
+ cexcept_eabefore = ea;
+ ea->type = EAT_DESTROYLOCAL;
+ ea->data.destroy_local.local = dtorTemp->object;
+ ea->data.destroy_local.dtor = CABI_GetDestructorObject(dtorTemp->dtor, CABIDestroy1);
+
+ ea = lalloc(sizeof(ExceptionAction));
+ *ea = *cexcept_eabefore;
+ ea->prev = cexcept_eaafter;
+ cexcept_eaafter = ea;
+ }
+
+ expr->type = EOBJREF;
+ expr->data.objref = object;
+ return expr;
+}
+
+static ENode *CExcept_TransNewException(ENode *expr, Boolean isCond) {
+ Object *tempObj;
+ CLabel *label;
+ Boolean isArray;
+ Statement *stmt;
+ ExceptionAction *ea;
+ ENode *result;
+
+ isArray = expr->type == ENEWEXCEPTIONARRAY;
+
+ if (isCond) {
+ expr->data.newexception.initexpr = CExcept_TempTransExprCond(expr->data.newexception.initexpr);
+ expr->data.newexception.tryexpr = CExcept_TempTransExprCond(expr->data.newexception.tryexpr);
+ tempObj = create_temp_object(TYPE(&stchar));
+
+ stmt = CExcept_InsertPrevStatement(ST_EXPRESSION);
+ stmt->expr = makediadicnode(create_objectnode(tempObj), intconstnode(TYPE(&stchar), 0), EASS);
+ cexcept_prevstmt = stmt;
+
+ ea = lalloc(sizeof(ExceptionAction));
+ ea->prev = cexcept_eabefore;
+ cexcept_eabefore = ea;
+
+ ea->type = EAT_DELETEPOINTERCOND;
+ ea->data.delete_pointer_cond.pointerobject = expr->data.newexception.pointertemp;
+ ea->data.delete_pointer_cond.deletefunc = expr->data.newexception.deletefunc;
+ ea->data.delete_pointer_cond.cond = tempObj;
+
+ if (isArray) {
+ result = makediadicnode(
+ makediadicnode(
+ expr->data.newexception.initexpr,
+ makediadicnode(create_objectnode(tempObj), intconstnode(TYPE(&stchar), 1), EASS),
+ ECOMMA
+ ),
+ expr->data.newexception.tryexpr,
+ ECOMMA
+ );
+
+ result = makediadicnode(
+ result,
+ makediadicnode(create_objectnode(tempObj), intconstnode(TYPE(&stchar), 0), EASS),
+ ECOMMA
+ );
+
+ result = makediadicnode(
+ result,
+ create_objectnode(expr->data.newexception.pointertemp),
+ ECOMMA
+ );
+ } else {
+ result = makediadicnode(
+ makediadicnode(create_objectnode(tempObj), intconstnode(TYPE(&stchar), 1), EASS),
+ expr->data.newexception.tryexpr,
+ ECOMMA
+ );
+
+ result = makediadicnode(
+ expr->data.newexception.initexpr,
+ makediadicnode(
+ result,
+ makediadicnode(create_objectnode(tempObj), intconstnode(TYPE(&stchar), 0), EASS),
+ ECOMMA
+ ),
+ ELAND
+ );
+
+ result = makediadicnode(
+ result,
+ create_objectnode(expr->data.newexception.pointertemp),
+ ECOMMA
+ );
+ }
+ } else {
+ expr->data.newexception.initexpr = CExcept_TempTransExpr(expr->data.newexception.initexpr);
+ expr->data.newexception.tryexpr = CExcept_TempTransExpr(expr->data.newexception.tryexpr);
+
+ if (isArray) {
+ stmt = CExcept_InsertPrevStatement(ST_EXPRESSION);
+ stmt->expr = expr->data.newexception.initexpr;
+ } else {
+ stmt = CExcept_InsertPrevStatement(ST_IFNGOTO);
+ stmt->expr = expr->data.newexception.initexpr;
+ label = newlabel();
+ stmt->label = label;
+ }
+
+ stmt = CFunc_InsertStatement(ST_EXPRESSION, stmt);
+ stmt->expr = expr->data.newexception.tryexpr;
+
+ ea = lalloc(sizeof(ExceptionAction));
+ ea->prev = cexcept_eabefore;
+ ea->type = EAT_DELETEPOINTER;
+ ea->data.delete_pointer.pointerobject = expr->data.newexception.pointertemp;
+ ea->data.delete_pointer.deletefunc = expr->data.newexception.deletefunc;
+ stmt->dobjstack = ea;
+
+ if (!isArray) {
+ stmt = CFunc_InsertStatement(ST_LABEL, stmt);
+ stmt->label = label;
+ label->stmt = stmt;
+ stmt->dobjstack = cexcept_eabefore;
+ }
+
+ cexcept_prevstmt = stmt;
+ result = create_objectnode(expr->data.newexception.pointertemp);
+ }
+
+ result->rtype = expr->rtype;
+ return result;
+}
+
+static ENode *CExcept_TransInitTryCatch(ENode *expr, Boolean isCond) {
+ CLabel *label1;
+ CLabel *label2;
+ CLabel *label3;
+ Object *catch_info_object;
+ Statement *stmt;
+ ExceptionAction *ea;
+
+ cexcept_hastrycatch = 1;
+
+ if (isCond) {
+ CError_ASSERT(1877, !cexcept_expandtrycatch);
+
+ cexcept_serialize = 1;
+ expr->data.itc.initexpr = CExcept_TempTransExprCond(expr->data.itc.initexpr);
+ expr->data.itc.tryexpr = CExcept_TempTransExprCond(expr->data.itc.tryexpr);
+ expr->data.itc.catchexpr = CExcept_TempTransExprCond(expr->data.itc.catchexpr);
+ expr->data.itc.result = CExcept_TempTransExprCond(expr->data.itc.result);
+ return expr;
+ }
+
+ expr->data.itc.initexpr = CExcept_TempTransExpr(expr->data.itc.initexpr);
+ expr->data.itc.tryexpr = CExcept_TempTransExpr(expr->data.itc.tryexpr);
+ expr->data.itc.catchexpr = CExcept_TempTransExpr(expr->data.itc.catchexpr);
+ expr->data.itc.result = CExcept_TempTransExpr(expr->data.itc.result);
+
+ if (!cexcept_expandtrycatch)
+ return expr;
+
+ label1 = newlabel();
+ label2 = newlabel();
+ label3 = newlabel();
+
+ catch_info_object = create_temp_object(TYPE(&catchinfostruct));
+
+ stmt = CExcept_InsertPrevStatement(ST_IFNGOTO);
+ stmt->expr = expr->data.itc.initexpr;
+ stmt->label = label3;
+
+ ea = lalloc(sizeof(ExceptionAction));
+ memclrw(ea, sizeof(ExceptionAction));
+ ea->type = EAT_CATCHBLOCK;
+ ea->data.catch_block.catch_label = label2;
+ ea->data.catch_block.catch_info_object = catch_info_object;
+ ea->prev = stmt->dobjstack;
+
+ stmt = CFunc_InsertStatement(ST_LABEL, stmt);
+ stmt->flags = StmtFlag_1;
+ stmt->label = label1;
+ label1->stmt = stmt;
+ stmt->dobjstack = ea;
+
+ stmt = CFunc_InsertStatement(ST_BEGINCATCH, stmt);
+ stmt->expr = create_objectrefnode(catch_info_object);
+
+ stmt = CFunc_InsertStatement(ST_EXPRESSION, stmt);
+ stmt->expr = expr->data.itc.tryexpr;
+
+ stmt = CFunc_InsertStatement(ST_GOTO, stmt);
+ stmt->label = label3;
+
+ CError_ASSERT(1928, stmt->dobjstack == ea);
+
+ stmt->dobjstack = ea->prev;
+
+ ea = lalloc(sizeof(ExceptionAction));
+ memclrw(ea, sizeof(ExceptionAction));
+ ea->type = EAT_ACTIVECATCHBLOCK;
+ ea->data.active_catch_block.catch_info_object = catch_info_object;
+ ea->prev = stmt->dobjstack;
+
+ stmt = CFunc_InsertStatement(ST_LABEL, stmt);
+ stmt->flags = StmtFlag_1;
+ stmt->label = label2;
+ label2->stmt = stmt;
+ stmt->dobjstack = ea;
+
+ stmt = CFunc_InsertStatement(ST_EXPRESSION, stmt);
+ stmt->expr = expr->data.itc.catchexpr;
+
+ stmt = CFunc_InsertStatement(ST_EXPRESSION, stmt);
+ stmt->expr = funccallexpr(Xthrw_func, nullnode(), nullnode(), nullnode(), NULL);
+
+ stmt = CFunc_InsertStatement(ST_LABEL, stmt);
+ stmt->label = label3;
+ label3->stmt = stmt;
+
+ CError_ASSERT(1968, stmt->dobjstack == ea);
+
+ stmt->dobjstack = ea->prev;
+
+ cexcept_prevstmt = stmt;
+ return expr->data.itc.result;
+}
+
+static ENode *CExcept_TempTransFuncCall(ENode *expr, Boolean isCond) {
+ ENodeList *tempArg;
+ ENodeList **argArray;
+ ENodeList *args;
+ ExceptionAction *ea;
+ Statement *stmt;
+ DtorTemp *dtorTemp;
+ ENode *tempNode;
+
+ tempArg = NULL;
+ if ((args = expr->data.funccall.args)) {
+ tempNode = args->node;
+ if (tempNode->type == ETEMP) {
+ if (tempNode->data.temp.needs_dtor)
+ tempArg = args;
+ } else if (args->next) {
+ tempNode = args->next->node;
+ if (tempNode->type == ETEMP) {
+ if (tempNode->data.temp.needs_dtor)
+ tempArg = args->next;
+ }
+ }
+ }
+
+ if (tempArg) {
+ if (isCond) {
+ ENodeList *arg = args;
+ SInt32 i = 0;
+ while (arg) {
+ arg = arg->next;
+ i++;
+ }
+
+ argArray = lalloc(sizeof(ENodeList *) * i);
+ for (args = expr->data.funccall.args, i = 0; args; args = args->next)
+ argArray[i++] = args;
+
+ while (i > 0) {
+ i--;
+ if (argArray[i] != tempArg)
+ argArray[i]->node = CExcept_TempTransExprCond(argArray[i]->node);
+ }
+ } else {
+ while (args) {
+ if (args != tempArg)
+ args->node = CExcept_TempTransExpr(args->node);
+ args = args->next;
+ }
+ }
+
+ dtorTemp = lalloc(sizeof(DtorTemp));
+ dtorTemp->next = cexcept_dtortemps;
+ cexcept_dtortemps = dtorTemp;
+
+ dtorTemp->object = CExcept_GetETEMPObject(tempNode);
+ dtorTemp->temp = NULL;
+
+ if (
+ !IS_TYPE_CLASS(tempNode->data.temp.type) ||
+ !(dtorTemp->dtor = CClass_Destructor(TYPE_CLASS(tempNode->data.temp.type)))
+ )
+ CError_FATAL(2046);
+
+ tempNode->type = EOBJREF;
+ tempNode->data.objref = dtorTemp->object;
+
+ if (isCond) {
+ Type *type24 = expr->rtype;
+ dtorTemp->temp = create_temp_object(TYPE(&stchar));
+
+ expr = makediadicnode(
+ expr,
+ makediadicnode(create_objectnode(dtorTemp->temp), intconstnode(TYPE(&stchar), 1), EASS),
+ ECOMMA
+ );
+
+ expr = makediadicnode(
+ expr,
+ create_objectrefnode(dtorTemp->object),
+ ECOMMA
+ );
+ expr->rtype = type24;
+
+ stmt = CExcept_InsertPrevStatement(ST_EXPRESSION);
+ stmt->expr = makediadicnode(
+ create_objectnode(dtorTemp->temp),
+ intconstnode(TYPE(&stchar), 0),
+ EASS
+ );
+ cexcept_prevstmt = stmt;
+
+ ea = lalloc(sizeof(ExceptionAction));
+ ea->prev = cexcept_eabefore;
+ cexcept_eabefore = ea;
+
+ ea->type = EAT_DESTROYLOCALCOND;
+ ea->data.destroy_local_cond.local = dtorTemp->object;
+ ea->data.destroy_local_cond.dtor = CABI_GetDestructorObject(dtorTemp->dtor, CABIDestroy1);
+ ea->data.destroy_local_cond.cond = dtorTemp->temp;
+
+ ea = lalloc(sizeof(ExceptionAction));
+ *ea = *cexcept_eabefore;
+ ea->prev = cexcept_eaafter;
+ cexcept_eaafter = ea;
+ } else {
+ stmt = CExcept_InsertPrevStatement(ST_EXPRESSION);
+ stmt->expr = expr;
+ cexcept_prevstmt = stmt;
+
+ ea = lalloc(sizeof(ExceptionAction));
+ ea->prev = cexcept_eabefore;
+ cexcept_eabefore = ea;
+
+ ea->type = EAT_DESTROYLOCAL;
+ ea->data.destroy_local.local = dtorTemp->object;
+ ea->data.destroy_local.dtor = CABI_GetDestructorObject(dtorTemp->dtor, CABIDestroy1);
+
+ ea = lalloc(sizeof(ExceptionAction));
+ *ea = *cexcept_eabefore;
+ ea->prev = cexcept_eaafter;
+ cexcept_eaafter = ea;
+
+ expr = lalloc(sizeof(ENode));
+ *expr = *stmt->expr;
+ expr->type = EOBJREF;
+ expr->data.objref = tempArg->node->data.objref;
+ }
+ return expr;
+ } else {
+ if (isCond) {
+ SInt32 i = 0;
+ while (args) {
+ args = args->next;
+ i++;
+ }
+
+ argArray = lalloc(sizeof(ENodeList *) * i);
+ for (args = expr->data.funccall.args, i = 0; args; args = args->next)
+ argArray[i++] = args;
+
+ while (i > 0) {
+ i--;
+ argArray[i]->node = CExcept_TempTransExprCond(argArray[i]->node);
+ }
+
+ expr->data.funccall.funcref = CExcept_TempTransExprCond(expr->data.funccall.funcref);
+ } else {
+ while (args) {
+ args->node = CExcept_TempTransExpr(args->node);
+ args = args->next;
+ }
+
+ expr->data.funccall.funcref = CExcept_TempTransExpr(expr->data.funccall.funcref);
+ }
+
+ return expr;
+ }
+}
+
+static ENode *CExcept_TempTransExprCond(ENode *expr) {
+ switch (expr->type) {
+ case ETEMP:
+ return CExcept_TempTrans_ETEMP(expr);
+ case ENEWEXCEPTION:
+ case ENEWEXCEPTIONARRAY:
+ return CExcept_TransNewException(expr, 1);
+ case EINITTRYCATCH:
+ return CExcept_TransInitTryCatch(expr, 1);
+ case ENULLCHECK:
+ expr->data.nullcheck.nullcheckexpr = CExcept_TempTransExprCond(expr->data.nullcheck.nullcheckexpr);
+ expr->data.nullcheck.condexpr = CExcept_TempTransExprCond(expr->data.nullcheck.condexpr);
+ return expr;
+ case ECOND:
+ expr->data.cond.cond = CExcept_TempTransExprCond(expr->data.cond.cond);
+ expr->data.cond.expr1 = CExcept_TempTransExprCond(expr->data.cond.expr1);
+ expr->data.cond.expr2 = CExcept_TempTransExprCond(expr->data.cond.expr2);
+ return expr;
+ case ELAND:
+ case ELOR:
+ expr->data.diadic.left = CExcept_TempTransExprCond(expr->data.diadic.left);
+ expr->data.diadic.right = CExcept_TempTransExprCond(expr->data.diadic.right);
+ return expr;
+ case EFUNCCALL:
+ case EFUNCCALLP:
+ return CExcept_TempTransFuncCall(expr, 1);
+ case EMUL:
+ case EDIV:
+ case EMODULO:
+ case EADD:
+ case ESUB:
+ case ESHL:
+ case ESHR:
+ case ELESS:
+ case EGREATER:
+ case ELESSEQU:
+ case EGREATEREQU:
+ case EEQU:
+ case ENOTEQU:
+ case EAND:
+ case EXOR:
+ case EOR:
+ case EASS:
+ case EMULASS:
+ case EDIVASS:
+ case EMODASS:
+ case EADDASS:
+ case ESUBASS:
+ case ESHLASS:
+ case ESHRASS:
+ case EANDASS:
+ case EXORASS:
+ case EORASS:
+ case ECOMMA:
+ case EROTL:
+ case EROTR:
+ expr->data.diadic.left = CExcept_TempTransExprCond(expr->data.diadic.left);
+ expr->data.diadic.right = CExcept_TempTransExprCond(expr->data.diadic.right);
+ return expr;
+ case EPOSTINC:
+ case EPOSTDEC:
+ case EPREINC:
+ case EPREDEC:
+ case EINDIRECT:
+ case EMONMIN:
+ case EBINNOT:
+ case ELOGNOT:
+ case ETYPCON:
+ case EBITFIELD:
+ expr->data.monadic = CExcept_TempTransExprCond(expr->data.monadic);
+ return expr;
+ case EINTCONST:
+ case EFLOATCONST:
+ case ESTRINGCONST:
+ case EOBJREF:
+ case EPRECOMP:
+ case ELABEL:
+ case EINSTRUCTION:
+ case EVECTOR128CONST:
+ return expr;
+ default:
+ CError_FATAL(2236);
+ return expr;
+ }
+}
+
+static ENode *CExcept_TempTransExpr(ENode *expr) {
+ switch (expr->type) {
+ case ETEMP:
+ return CExcept_TempTrans_ETEMP(expr);
+ case ENEWEXCEPTION:
+ case ENEWEXCEPTIONARRAY:
+ return CExcept_TransNewException(expr, 0);
+ case EINITTRYCATCH:
+ return CExcept_TransInitTryCatch(expr, 0);
+ case ENULLCHECK:
+ expr->data.nullcheck.nullcheckexpr = CExcept_TempTransExpr(expr->data.nullcheck.nullcheckexpr);
+ expr->data.nullcheck.condexpr = CExcept_TempTransExprCond(expr->data.nullcheck.condexpr);
+ return expr;
+ case ECOND:
+ expr->data.cond.cond = CExcept_TempTransExpr(expr->data.cond.cond);
+ expr->data.cond.expr1 = CExcept_TempTransExprCond(expr->data.cond.expr1);
+ expr->data.cond.expr2 = CExcept_TempTransExprCond(expr->data.cond.expr2);
+ return expr;
+ case ELAND:
+ case ELOR:
+ case ECOMMA:
+ expr->data.diadic.left = CExcept_TempTransExpr(expr->data.diadic.left);
+ expr->data.diadic.right = CExcept_TempTransExprCond(expr->data.diadic.right);
+ return expr;
+ case EFUNCCALL:
+ case EFUNCCALLP:
+ return CExcept_TempTransFuncCall(expr, 0);
+ case EMUL:
+ case EDIV:
+ case EMODULO:
+ case EADD:
+ case ESUB:
+ case ESHL:
+ case ESHR:
+ case ELESS:
+ case EGREATER:
+ case ELESSEQU:
+ case EGREATEREQU:
+ case EEQU:
+ case ENOTEQU:
+ case EAND:
+ case EXOR:
+ case EOR:
+ case EASS:
+ case EMULASS:
+ case EDIVASS:
+ case EMODASS:
+ case EADDASS:
+ case ESUBASS:
+ case ESHLASS:
+ case ESHRASS:
+ case EANDASS:
+ case EXORASS:
+ case EORASS:
+ case EROTL:
+ case EROTR:
+ expr->data.diadic.left = CExcept_TempTransExpr(expr->data.diadic.left);
+ expr->data.diadic.right = CExcept_TempTransExpr(expr->data.diadic.right);
+ return expr;
+ case EPOSTINC:
+ case EPOSTDEC:
+ case EPREINC:
+ case EPREDEC:
+ case EINDIRECT:
+ case EMONMIN:
+ case EBINNOT:
+ case ELOGNOT:
+ case ETYPCON:
+ case EBITFIELD:
+ expr->data.monadic = CExcept_TempTransExpr(expr->data.monadic);
+ return expr;
+ case EINTCONST:
+ case EFLOATCONST:
+ case ESTRINGCONST:
+ case EOBJREF:
+ case EMFPOINTER:
+ case EPRECOMP:
+ case ELABEL:
+ case EOBJLIST:
+ case EMEMBER:
+ case EINSTRUCTION:
+ case EVECTOR128CONST:
+ return expr;
+ default:
+ CError_FATAL(2350);
+ return expr;
+ }
+}
+
+static Statement *CExcept_DtorTransform(Statement *stmt) {
+ DtorTemp *dtorTemp;
+ Statement *curStmt;
+ CLabel *lastLabel;
+
+ dtorTemp = cexcept_dtortemps;
+ curStmt = stmt;
+ while (dtorTemp) {
+ if (
+ cexcept_eaafter &&
+ (cexcept_eaafter->type == EAT_DESTROYLOCAL || cexcept_eaafter->type == EAT_DESTROYLOCALCOND) &&
+ cexcept_eaafter->data.destroy_local.local == dtorTemp->object
+ )
+ {
+ cexcept_eaafter = cexcept_eaafter->prev;
+ } else {
+ CError_FATAL(2374);
+ }
+
+ if (dtorTemp->temp) {
+ curStmt = CFunc_InsertStatement(ST_IFNGOTO, curStmt);
+ curStmt->expr = create_objectnode(dtorTemp->temp);
+ curStmt->dobjstack = cexcept_eaafter;
+ lastLabel = curStmt->label = newlabel();
+ }
+
+ curStmt = CFunc_InsertStatement(ST_EXPRESSION, curStmt);
+ curStmt->expr = CABI_DestroyObject(dtorTemp->dtor, create_objectrefnode(dtorTemp->object), CABIDestroy1, 1, 0);
+ curStmt->dobjstack = cexcept_eaafter;
+
+ if (dtorTemp->temp) {
+ curStmt = CFunc_InsertStatement(ST_LABEL, curStmt);
+ curStmt->label = lastLabel;
+ lastLabel->stmt = curStmt;
+ }
+
+ dtorTemp = dtorTemp->next;
+ }
+
+ return curStmt;
+}
+
+static void CExcept_TempTransform(Statement *stmt, Boolean flag1, Boolean flag2) {
+ Statement *prevStmt;
+ Statement *iter;
+ Statement copy;
+ Object *tempObj;
+
+ prevStmt = cexcept_prevstmt;
+ cexcept_dtortemps = NULL;
+ cexcept_serialize = 0;
+ cexcept_expandtrycatch = 0;
+ cexcept_hastrycatch = 0;
+ stmt->expr = CExcept_TempTransExpr(stmt->expr);
+
+ if (cexcept_hastrycatch) {
+ cexcept_expandtrycatch = 1;
+ if (cexcept_serialize) {
+ CInline_SerializeStatement(stmt);
+ cexcept_prevstmt = stmt;
+ } else {
+ cexcept_prevstmt = prevStmt;
+ }
+
+ iter = prevStmt;
+ while (1) {
+ CError_ASSERT(2425, iter);
+
+ switch (iter->type) {
+ case ST_RETURN:
+ CError_ASSERT(2429, iter->expr != NULL);
+ case ST_EXPRESSION:
+ case ST_SWITCH:
+ case ST_IFGOTO:
+ case ST_IFNGOTO:
+ iter->expr = CExcept_TempTransExpr(iter->expr);
+ }
+
+ if (iter == stmt)
+ break;
+ cexcept_prevstmt = iter;
+ iter = iter->next;
+ }
+ }
+
+ if (cexcept_dtortemps) {
+ if (!flag1) {
+ if (flag2) {
+ ENode *expr = stmt->expr;
+ CError_ASSERT(2456, !IS_TYPE_CLASS(expr->rtype) || !CClass_Destructor(TYPE_CLASS(expr->rtype)));
+
+ tempObj = create_temp_object(expr->rtype);
+ stmt->expr = makediadicnode(create_objectnode(tempObj), expr, EASS);
+ }
+
+ copy = *stmt;
+ stmt->type = ST_EXPRESSION;
+ stmt = CExcept_DtorTransform(stmt);
+ stmt = CFunc_InsertStatement(copy.type, stmt);
+ stmt->label = copy.label;
+
+ if (flag2)
+ stmt->expr = create_objectnode(tempObj);
+ else
+ stmt->expr = nullnode();
+ } else {
+ CExcept_DtorTransform(stmt);
+ }
+ }
+}
+
+static void CExcept_CleanupExceptionActions(Statement *stmt) {
+ Statement *iter;
+ ENode *expr;
+ ExceptionAction *ea;
+
+ cexcept_prevstmt = stmt;
+ for (iter = stmt; iter; iter = iter->next) {
+ cexcept_eabefore = cexcept_eaafter = ea = iter->dobjstack;
+
+ if (iter->flags & StmtFlag_2) {
+ cexcept_eabefore = ea->prev;
+ } else if (iter->type == ST_EXPRESSION) {
+ expr = iter->expr;
+ while (ENODE_IS(expr, ECOMMA))
+ expr = expr->data.diadic.left;
+ if (ENODE_IS(expr, EINDIRECT))
+ expr = expr->data.monadic;
+
+ if (
+ ENODE_IS(expr, EFUNCCALL) &&
+ ENODE_IS(expr->data.funccall.funcref, EOBJREF) &&
+ CClass_IsConstructor(expr->data.funccall.funcref->data.objref) &&
+ iter->dobjstack &&
+ iter->dobjstack->type == EAT_DESTROYLOCAL &&
+ expr->data.funccall.args &&
+ ENODE_IS(expr->data.funccall.args->node, EOBJREF) &&
+ expr->data.funccall.args->node->data.objref == iter->dobjstack->data.destroy_local.local
+ )
+ cexcept_eabefore = cexcept_eabefore->prev;
+ }
+
+ switch (iter->type) {
+ case ST_EXPRESSION:
+ CExcept_TempTransform(iter, 1, 0);
+ break;
+ case ST_SWITCH:
+ case ST_IFGOTO:
+ case ST_IFNGOTO:
+ CExcept_TempTransform(iter, 0, 1);
+ break;
+ case ST_RETURN:
+ if (iter->expr) {
+ CExcept_TempTransform(
+ iter,
+ 0,
+ CMach_GetFunctionResultClass(TYPE_FUNC(cscope_currentfunc->type)) != 1
+ );
+ }
+ break;
+ }
+
+ iter->dobjstack = cexcept_eabefore;
+ cexcept_prevstmt = iter;
+ }
+}
+
+static void CExcept_InsertSpecificationActions(Statement *stmt, ExceptSpecList *exspecs) {
+ Statement *iter;
+ Statement *last;
+ ExceptionAction *ea_spec;
+ ExceptionAction *ea;
+ ExceptSpecList *spec_iter;
+ SInt32 i;
+ Object *catch_info_object;
+ CLabel *label;
+
+ ea_spec = lalloc(sizeof(ExceptionAction));
+ memclrw(ea_spec, sizeof(ExceptionAction));
+ ea_spec->type = EAT_SPECIFICATION;
+
+ for (iter = stmt; iter; iter = iter->next) {
+ if ((ea = iter->dobjstack)) {
+ while (1) {
+ if (ea->type == EAT_SPECIFICATION)
+ break;
+ if (ea->prev == NULL) {
+ ea->prev = ea_spec;
+ break;
+ }
+ ea = ea->prev;
+ }
+ } else {
+ iter->dobjstack = ea_spec;
+ }
+ }
+
+ last = stmt;
+ while (last->next)
+ last = last->next;
+
+ if (last->type != ST_GOTO && last->type != ST_RETURN) {
+ last = CFunc_InsertStatement(ST_RETURN, last);
+ last->expr = NULL;
+ last->dobjstack = NULL;
+ if (TYPE_FUNC(cscope_currentfunc->type)->functype != &stvoid && (copts.pedantic || copts.cplusplus))
+ CError_Warning(CErrorStr184);
+ }
+
+ last = CFunc_InsertStatement(ST_LABEL, last);
+ last->label = newlabel();
+ last->label->stmt = last;
+ last->flags = StmtFlag_1;
+ last->dobjstack = NULL;
+
+ catch_info_object = create_temp_object(TYPE(&catchinfostruct));
+
+ if (!exspecs->type)
+ exspecs = NULL;
+
+ i = 0;
+ spec_iter = exspecs;
+ while (spec_iter) {
+ spec_iter = spec_iter->next;
+ i++;
+ }
+
+ ea_spec->data.specification.unexp_ids = i;
+ ea_spec->data.specification.unexp_id = galloc(sizeof(Object *) * i);
+ ea_spec->data.specification.unexp_label = last->label;
+ ea_spec->data.specification.unexp_info_object = catch_info_object;
+
+ i = 0;
+ while (exspecs) {
+ ea_spec->data.specification.unexp_id[i] = CExcept_TypeID(exspecs->type, exspecs->qual);
+ exspecs = exspecs->next;
+ i++;
+ }
+
+ last = CFunc_InsertStatement(ST_EXPRESSION, last);
+ last->expr = funccallexpr(Xunex_func, create_objectrefnode(catch_info_object), NULL, NULL, NULL);
+
+ ea = lalloc(sizeof(ExceptionAction));
+ memclrw(ea, sizeof(ExceptionAction));
+ ea->type = EAT_ACTIVECATCHBLOCK;
+ ea->data.active_catch_block.catch_info_object = catch_info_object;
+ ea->data.active_catch_block.call_dtor = 1;
+ last->dobjstack = ea;
+
+ last = CFunc_InsertStatement(ST_LABEL, last);
+ last->label = label = newlabel();
+ last->label->stmt = last;
+ last->dobjstack = NULL;
+
+ last = CFunc_InsertStatement(ST_GOTO, last);
+ last->label = label;
+}
+
+static void CExcept_HasFuncCallCallBack(ENode *expr) {
+ ENode *funcref = expr->data.funccall.funcref;
+ if (ENODE_IS(funcref, EOBJREF)) {
+ Object *func = funcref->data.objref;
+ if (CExcept_CanThrowException(func, func->datatype == DVFUNC && !(expr->flags & ENODE_FLAG_80)))
+ cexcept_canthrow = 1;
+ } else {
+ cexcept_canthrow = 1;
+ }
+}
+
+static Boolean CExcept_CanThrowCheck(Object *func, Statement *stmt) {
+ cexcept_canthrow = 0;
+
+ while (stmt) {
+ switch (stmt->type) {
+ case ST_NOP:
+ case ST_LABEL:
+ case ST_GOTO:
+ case ST_ASM:
+ break;
+ case ST_RETURN:
+ if (!stmt->expr)
+ break;
+ case ST_EXPRESSION:
+ case ST_SWITCH:
+ case ST_IFGOTO:
+ case ST_IFNGOTO:
+ case ST_BEGINCATCH:
+ case ST_ENDCATCH:
+ case ST_ENDCATCHDTOR:
+ case ST_GOTOEXPR:
+ CExpr_SearchExprTree(stmt->expr, CExcept_HasFuncCallCallBack, 2, EFUNCCALL, EFUNCCALLP);
+ break;
+ default:
+ CError_FATAL(2687);
+ }
+ stmt = stmt->next;
+ }
+
+ if (!cexcept_canthrow) {
+ TYPE_FUNC(cscope_currentfunc->type)->flags |= FUNC_NOTHROW;
+ return 0;
+ } else {
+ return 1;
+ }
+}
+
+void CExcept_ExceptionTansform(Statement *stmt) {
+ cexcept_uniqueobjs = NULL;
+ CExcept_CleanupExceptionActions(stmt);
+
+ if (cscope_currentfunc && CExcept_CanThrowCheck(cscope_currentfunc, stmt)) {
+ CError_ASSERT(2716, IS_TYPE_FUNC(cscope_currentfunc->type));
+ if (TYPE_FUNC(cscope_currentfunc->type)->exspecs && copts.exceptions)
+ CExcept_InsertSpecificationActions(stmt, TYPE_FUNC(cscope_currentfunc->type)->exspecs);
+ }
+}