mirror of https://git.wuffs.org/MWCC
2184 lines
68 KiB
C
2184 lines
68 KiB
C
#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);
|
|
}
|
|
}
|