MWCC/compiler_and_linker/unsorted/CException.c

2188 lines
68 KiB
C
Raw Normal View History

2022-12-29 12:32:55 +00:00
#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;
typedef struct DtorTemp {
struct DtorTemp *next;
Object *object;
Object *dtor;
Object *temp;
} DtorTemp;
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, 1);
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, 1);
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, 1);
} else {
action->type = EAT_DESTROYBASE;
action->data.destroy_member.dtor = CABI_GetDestructorObject(dtor, 0);
}
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, 1);
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, 1);
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, 1, 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, 1));
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, "*%lx*%lx*", &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, "%ld!", 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, 1)),
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, 1);
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, 1);
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, 1);
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:
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 ECOMMA:
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 EPRECOMP:
case ELABEL:
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), 1, 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);
}
}