#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_FLAGS_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_80000) && 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) { CScopeParseResult 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_FLAGS_20) { 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_FLAGS_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_FLAGS_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); } }