diff options
author | Ash Wolf <ninji@wuffs.org> | 2023-01-26 11:30:47 +0000 |
---|---|---|
committer | Ash Wolf <ninji@wuffs.org> | 2023-01-26 11:30:47 +0000 |
commit | 094b96ca1df4a035b5f93c351f773306c0241f3f (patch) | |
tree | 95ce05e3ebe816c7ee7996206bb37ea17d8ca33c /compiler_and_linker/FrontEnd/C | |
parent | fc0c4c0df7b583b55a08317cf1ef6a71d27c0440 (diff) | |
download | MWCC-094b96ca1df4a035b5f93c351f773306c0241f3f.tar.gz MWCC-094b96ca1df4a035b5f93c351f773306c0241f3f.zip |
move lots of source files around to match their actual placement in the original treemain
Diffstat (limited to 'compiler_and_linker/FrontEnd/C')
23 files changed, 53629 insertions, 1 deletions
diff --git a/compiler_and_linker/FrontEnd/C/CABI.c b/compiler_and_linker/FrontEnd/C/CABI.c new file mode 100644 index 0000000..2a88de1 --- /dev/null +++ b/compiler_and_linker/FrontEnd/C/CABI.c @@ -0,0 +1,2033 @@ +#include "compiler/CABI.h" +#include "compiler/CClass.h" +#include "compiler/CDecl.h" +#include "compiler/CError.h" +#include "compiler/CException.h" +#include "compiler/CExpr.h" +#include "compiler/CFunc.h" +#include "compiler/CInit.h" +#include "compiler/CInline.h" +#include "compiler/CMachine.h" +#include "compiler/CMangler.h" +#include "compiler/CParser.h" +#include "compiler/CScope.h" +#include "compiler/CSOM.h" +#include "compiler/CompilerTools.h" +#include "compiler/objects.h" +#include "compiler/scopes.h" +#include "compiler/types.h" + +typedef struct OffsetList { + struct OffsetList *next; + SInt32 offset; +} OffsetList; + +static OffsetList *trans_vtboffsets; +static BClassList cabi_pathroot; +static BClassList *cabi_pathcur; +static TypeClass *cabi_loop_class; +static Boolean cabi_loop_construct; + +short CABI_GetStructResultArgumentIndex(TypeFunc *tfunc) { + return 0; +} + +Type *CABI_GetSizeTType(void) { + return TYPE(&stunsignedlong); +} + +Type *CABI_GetPtrDiffTType(void) { + return TYPE(&stsignedlong); +} + +SInt16 CABI_StructSizeAlignValue(Type *type, SInt32 size) { + SInt16 align = CMach_GetTypeAlign(type); + if (align <= 1) + return 0; + else + return (align - 1) & (align - ((size & (align - 1)))); +} + +void CABI_ReverseBitField(TypeBitfield *tbitfield) { + UInt8 bits; + UInt8 a; + UInt8 b; + + switch (tbitfield->bitfieldtype->size) { + case 1: + bits = 8; + break; + case 2: + bits = 16; + break; + case 4: + bits = 32; + break; + case 8: + bits = 64; + break; + default: + CError_FATAL(172); + } + + b = tbitfield->bitlength; + a = tbitfield->offset; + tbitfield->offset = (bits - a) - b; +} + +static void CABI_AllocateZeroVTablePointer(void *unk, TypeClass *tclass) { + ClassList *base; + + for (base = tclass->bases; base; base = base->next) { + if (!base->is_virtual && base->base->vtable) + return; + } + + tclass->size += void_ptr.size; +} + +static SInt32 CABI_GetBaseSize(TypeClass *tclass) { + SInt32 size = tclass->size; + + if (copts.vbase_abi_v2 && tclass->vbases) + return tclass->vbases->offset; + + return size; +} + +static void CABI_AllocateBases(ClassLayout *layout, TypeClass *tclass) { + Boolean flag; + TypeClass *baseclass; + ClassList *base; + VClassList *vbase; + SInt32 size; + + flag = 0; + size = tclass->size; + + for (base = tclass->bases; base; base = base->next) { + if (!base->is_virtual) { + baseclass = base->base; + if (!(baseclass->flags & CLASS_EMPTY)) { + base->offset = size + CMach_MemberAlignValue(TYPE(baseclass), size); + if (copts.vbase_abi_v2) { + size = base->offset + CABI_GetBaseSize(baseclass); + } else { + size = base->offset + baseclass->size; + for (vbase = baseclass->vbases; vbase; vbase = vbase->next) + size -= vbase->base->size; + } + flag = 0; + } else { + if (flag) + base->offset = ++size; + else + base->offset = size; + flag = 1; + } + } + } + + tclass->size = size; +} + +static void CABI_AllocateVirtualBasePointers(ClassLayout *layout, TypeClass *tclass) { + ClassList *base; + SInt32 size; + + size = tclass->size; + + for (base = tclass->bases; base; base = base->next) { + if (base->is_virtual) { + base->offset = size + CMach_MemberAlignValue(TYPE(&void_ptr), size); + size = base->offset + void_ptr.size; + } + } + + tclass->size = size; +} + +static SInt32 CABI_GetMemberOffset(TypeClass *tclass, HashNameNode *name) { + ObjMemberVar *ivar; + + if (!name) + return 0; + + ivar = tclass->ivars; + while (1) { + if (ivar->name == name) + return ivar->offset; + + if (!(ivar = ivar->next)) + CError_FATAL(362); + } +} + +static void CABI_AllocateMembers(ClassLayout *layout, TypeClass *tclass) { + ObjMemberVar *ivar; + SInt32 initialSize; + SInt32 maxSize; + TypeClass *unionClass; + SInt32 unionStart; + Boolean inAnonUnion; + Boolean removeNoNameIvars; + + removeNoNameIvars = 0; + initialSize = maxSize = tclass->size; + CMach_StructLayoutInitOffset(maxSize); + + unionClass = NULL; + for (ivar = tclass->ivars; ivar; ivar = ivar->next) { + if (!ivar->anonunion) { + if (!(ivar->offset & 0x80000000)) { + if (tclass->mode == CLASS_MODE_UNION) + CMach_StructLayoutInitOffset(initialSize); + + if (IS_TYPE_BITFIELD(ivar->type)) + ivar->offset = CMach_StructLayoutBitfield(TYPE_BITFIELD(ivar->type), ivar->qual); + else + ivar->offset = CMach_StructLayoutGetOffset(ivar->type, ivar->qual); + + if (tclass->mode == CLASS_MODE_UNION) { + SInt32 tmp = CMach_StructLayoutGetCurSize(); + if (tmp > maxSize) + maxSize = tmp; + } + + unionClass = NULL; + } else { + CError_ASSERT(412, unionClass); + ivar->offset = unionStart + CABI_GetMemberOffset(unionClass, ivar->name); + if (!inAnonUnion) + ivar->anonunion = 1; + inAnonUnion = 0; + } + + if (ivar->name == no_name_node || ivar->name == NULL) + removeNoNameIvars = 1; + } else { + CError_ASSERT(422, IS_TYPE_CLASS(ivar->type)); + + if (tclass->mode == CLASS_MODE_UNION) + CMach_StructLayoutInitOffset(initialSize); + + unionStart = CMach_StructLayoutGetOffset(ivar->type, ivar->qual); + unionClass = TYPE_CLASS(ivar->type); + inAnonUnion = 1; + + if (tclass->mode == CLASS_MODE_UNION) { + SInt32 tmp = CMach_StructLayoutGetCurSize(); + if (tmp > maxSize) + maxSize = tmp; + } + + removeNoNameIvars = 1; + } + + if (layout->vtable_ivar == ivar) + tclass->vtable->offset = ivar->offset; + } + + if (removeNoNameIvars) { + ObjMemberVar **ptr = &tclass->ivars; + while (*ptr) { + if ((*ptr)->name == NULL || (*ptr)->name == no_name_node) + *ptr = (*ptr)->next; + else + ptr = &(*ptr)->next; + } + } + + if (tclass->mode == CLASS_MODE_UNION) + tclass->size = maxSize; + else + tclass->size = CMach_StructLayoutGetCurSize(); + + if (copts.reverse_bitfields) { + for (ivar = tclass->ivars; ivar; ivar = ivar->next) { + if (IS_TYPE_BITFIELD(ivar->type)) + CABI_ReverseBitField(TYPE_BITFIELD(ivar->type)); + } + } +} + +static void CABI_AllocateVirtualBases(ClassLayout *layout, TypeClass *tclass) { + VClassList *vbase; + SInt32 size; + + size = tclass->size; + + for (vbase = tclass->vbases; vbase; vbase = vbase->next) { + vbase->offset = size + CMach_MemberAlignValue(TYPE(vbase->base), size); + size = vbase->offset + CABI_GetBaseSize(vbase->base); + + if (vbase->has_override) + size += CMach_MemberAlignValue(TYPE(&stunsignedlong), size) + 4; + } + + tclass->size = size; +} + +static Boolean CABI_FindZeroDeltaVPtr(TypeClass *tclass) { + ClassList *base; + + for (base = tclass->bases; base; base = base->next) { + if (!base->is_virtual && base->base->vtable && !base->offset) { + tclass->vtable->offset = base->base->vtable->offset; + return 1; + } + } + + return 0; +} + +static Object *CABI_FindZeroVirtualBaseMember(TypeClass *tclass, Object *obj) { + NameSpaceObjectList *nsol; + ClassList *base; + Object *chk; + + for (base = tclass->bases; base; base = base->next) { + if (!base->is_virtual && !base->offset && !base->voffset && base->base->vtable) { + for (nsol = CScope_FindName(base->base->nspace, obj->name); nsol; nsol = nsol->next) { + chk = OBJECT(nsol->object); + if ( + chk->otype == OT_OBJECT && + chk->datatype == DVFUNC && + CClass_GetOverrideKind(TYPE_FUNC(chk->type), TYPE_FUNC(obj->type), 0) == 1 + ) + return chk; + } + + if ((chk = CABI_FindZeroVirtualBaseMember(base->base, obj))) + return chk; + } + } + + return NULL; +} + +void CABI_AddVTable(TypeClass *tclass) { + tclass->vtable = galloc(sizeof(VTable)); + memclrw(tclass->vtable, sizeof(VTable)); +} + +SInt32 CABI_GetVTableOffset(TypeClass *tclass) { + return 0; +} + +static SInt32 CABI_GetBaseVTableSize(TypeClass *tclass) { + VClassList *vbase; + SInt32 size; + + size = tclass->vtable->size; + + for (vbase = tclass->vbases; vbase; vbase = vbase->next) { + if (vbase->base->vtable) + size -= CABI_GetBaseVTableSize(vbase->base); + } + + return size; +} + +static void CABI_ApplyClassFlags(Object *obj, UInt8 flags, Boolean unused) { + if (flags & CLASS_EFLAGS_INTERNAL) + obj->flags = obj->flags | OBJECT_INTERNAL; + if (flags & CLASS_EFLAGS_IMPORT) + obj->flags = obj->flags | OBJECT_IMPORT; + if (flags & CLASS_EFLAGS_EXPORT) + obj->flags = obj->flags | OBJECT_EXPORT; +} + +static void CABI_AllocateVTable(ClassLayout *layout, TypeClass *tclass) { + SInt32 size; + ObjBase *objbase; + Object *obj; + ObjMemberVar *ivar; + ClassList *base; + VClassList *vbase; + int i; + + size = 0; + + if (!tclass->vtable) { + CABI_AddVTable(tclass); + layout->xA = layout->lex_order_count - 1; + } + + if (!CABI_FindZeroDeltaVPtr(tclass)) { + ivar = galloc(sizeof(ObjMemberVar)); + memclrw(ivar, sizeof(ObjMemberVar)); + + ivar->otype = OT_MEMBERVAR; + ivar->access = ACCESSPUBLIC; + ivar->name = vptr_name_node; + ivar->type = TYPE(&void_ptr); + layout->vtable_ivar = ivar; + + for (i = layout->xA; ; i--) { + if (i < 0) { + ivar->next = tclass->ivars; + tclass->ivars = ivar; + break; + } + + CError_ASSERT(666, layout->objlist[i]); + + if (layout->objlist[i]->otype == OT_MEMBERVAR) { + ivar->next = OBJ_MEMBER_VAR(layout->objlist[i])->next; + OBJ_MEMBER_VAR(layout->objlist[i])->next = ivar; + break; + } + } + + if (tclass->flags & (CLASS_SINGLE_OBJECT | CLASS_COM_OBJECT)) + size = void_ptr.size; + else + size = 8; + } else { + layout->vtable_ivar = NULL; + } + + for (base = tclass->bases; base; base = base->next) { + if (base->base->vtable && !base->is_virtual) { + base->voffset = size; + if (copts.vbase_abi_v2) { + size += CABI_GetBaseVTableSize(base->base); + } else { + size += base->base->vtable->size; + for (vbase = base->base->vbases; vbase; vbase = vbase->next) { + if (vbase->base->vtable) + size -= vbase->base->vtable->size; + } + } + } + } + + for (i = 0; i < layout->lex_order_count; i++) { + CError_ASSERT(714, objbase = layout->objlist[i]); + + if (objbase->otype == OT_OBJECT && OBJECT(objbase)->datatype == DVFUNC) { + TypeMemberFunc *tmethod = TYPE_METHOD(OBJECT(objbase)->type); + Object *baseobj = CABI_FindZeroVirtualBaseMember(tclass, OBJECT(objbase)); + + if (baseobj) { + tmethod->vtbl_index = TYPE_METHOD(baseobj->type)->vtbl_index; + } else { + tmethod->vtbl_index = size; + size += 4; + } + } + } + + for (vbase = tclass->vbases; vbase; vbase = vbase->next) { + if (vbase->base->vtable) { + vbase->voffset = size; + if (copts.vbase_abi_v2) + size += CABI_GetBaseVTableSize(vbase->base); + else + size += vbase->base->vtable->size; + } + } + + obj = CParser_NewCompilerDefDataObject(); + CABI_ApplyClassFlags(obj, tclass->eflags, 0); + + obj->name = CMangler_VTableName(tclass); + obj->type = CDecl_NewStructType(size, 4); + obj->qual = Q_CONST; + obj->nspace = tclass->nspace; + switch (tclass->action) { + case CLASS_ACTION_0: + obj->sclass = TK_STATIC; + obj->qual |= Q_20000; + break; + } + + CParser_UpdateObject(obj, NULL); + + tclass->vtable->object = obj; + tclass->vtable->owner = tclass; + tclass->vtable->size = size; +} + +void CABI_LayoutClass(ClassLayout *layout, TypeClass *tclass) { + char saveAlignMode = copts.structalignment; + + tclass->size = 0; + if (!tclass->sominfo) { + if (tclass->bases) + CABI_AllocateBases(layout, tclass); + if (tclass->flags & CLASS_HAS_VBASES) + CABI_AllocateVirtualBasePointers(layout, tclass); + if (layout->has_vtable) + CABI_AllocateVTable(layout, tclass); + CABI_AllocateMembers(layout, tclass); + if (tclass->flags & CLASS_HAS_VBASES) + CABI_AllocateVirtualBases(layout, tclass); + } else { + copts.structalignment = AlignMode2_PPC; + CABI_AllocateMembers(layout, tclass); + } + + tclass->align = CMach_GetClassAlign(tclass); + if (tclass->size == 0) { + tclass->size = 1; + tclass->flags = tclass->flags | CLASS_EMPTY; + } else { + tclass->size += CABI_StructSizeAlignValue(TYPE(tclass), tclass->size); + } + + tclass->flags = tclass->flags | CLASS_COMPLETED; + + copts.structalignment = saveAlignMode; +} + +void CABI_MakeDefaultArgConstructor(TypeClass *tclass, Object *func) { + DefArgCtorInfo *info; + Boolean saveDebugInfo; + ENodeList *copied; + ENodeList *argexprs; + FuncArg *args; + CScopeSave savedScope; + Statement firstStmt; + Statement returnStmt; + + CError_FATAL(860); + + if (anyerrors || func->access == ACCESSNONE) + return; + + CError_ASSERT(866, info = func->u.func.defargdata); + + CABI_ApplyClassFlags(func, tclass->eflags, 0); + + CScope_SetFunctionScope(func, &savedScope); + + CFunc_FuncGenSetup(&firstStmt, func); + + saveDebugInfo = copts.filesyminfo; + copts.filesyminfo = 0; + + CFunc_SetupNewFuncArgs(func, TYPE_FUNC(func->type)->args); + + if (tclass->flags & CLASS_HAS_VBASES) + arguments->next->object->name = no_name_node; + + firstStmt.next = &returnStmt; + + memclrw(&returnStmt, sizeof(Statement)); + returnStmt.type = ST_RETURN; + returnStmt.expr = lalloc(sizeof(ENode)); + returnStmt.expr->type = EFUNCCALL; + returnStmt.expr->cost = 200; + returnStmt.expr->flags = 0; + returnStmt.expr->rtype = TYPE(&void_ptr); + + returnStmt.expr->data.funccall.funcref = CExpr_MakeObjRefNode(info->default_func, 0); + returnStmt.expr->data.funccall.functype = TYPE_FUNC(info->default_func->type); + args = TYPE_FUNC(info->default_func->type)->args; + returnStmt.expr->data.funccall.args = lalloc(sizeof(ENodeList)); + argexprs = returnStmt.expr->data.funccall.args; + + argexprs->node = create_objectnode(arguments->object); + + if (tclass->flags & CLASS_HAS_VBASES) { + args = args->next; + argexprs->next = lalloc(sizeof(ENodeList)); + argexprs = argexprs->next; + argexprs->node = create_objectnode(arguments->next->object); + } + + args = args->next; + argexprs->next = lalloc(sizeof(ENodeList)); + argexprs = argexprs->next; + argexprs->node = CInline_CopyExpression(info->default_arg, CopyMode0); + + while ((args = args->next) && args->dexpr) { + argexprs->next = lalloc(sizeof(ENodeList)); + argexprs = argexprs->next; + argexprs->node = CInline_CopyExpression(args->dexpr, CopyMode0); + } + + argexprs->next = NULL; + + CFunc_CodeCleanup(&firstStmt); + CFunc_Gen(&firstStmt, func, 0); + + CScope_RestoreScope(&savedScope); + copts.filesyminfo = saveDebugInfo; + + func->u.func.defargdata = NULL; +} + +static Object *CABI_ThisArg(void) { + CError_ASSERT(931, arguments && IS_TYPE_POINTER_ONLY(arguments->object->type)); + return arguments->object; +} + +ENode *CABI_MakeThisExpr(TypeClass *tclass, SInt32 offset) { + ENode *expr; + + if (tclass) { + if (!tclass->sominfo) { + expr = create_objectnode(CABI_ThisArg()); + if (tclass->flags & CLASS_HANDLEOBJECT) + expr = makemonadicnode(expr, EINDIRECT); + } else { + expr = CSOM_SOMSelfObjectExpr(tclass); + } + } else { + expr = create_objectnode(CABI_ThisArg()); + expr->rtype = TYPE(&void_ptr); + } + + if (offset) + expr = makediadicnode(expr, intconstnode(TYPE(&stunsignedlong), offset), EADD); + + return expr; +} + +static Object *CABI_VArg(void) { + CError_ASSERT(976, arguments && arguments->next && IS_TYPE_INT(arguments->next->object->type)); + return arguments->next->object; +} + +static ENode *CABI_MakeVArgExpr(void) { + return create_objectnode(CABI_VArg()); +} + +static ENode *CABI_MakeCopyConArgExpr(TypeClass *tclass, Boolean flag) { + ObjectList *args; + + CError_ASSERT(1000, args = arguments); + CError_ASSERT(1001, args = args->next); + if (flag && (tclass->flags & CLASS_HAS_VBASES)) + CError_ASSERT(1002, args = args->next); + CError_ASSERT(1003, IS_TYPE_POINTER_ONLY(args->object->type)); + + return create_objectnode(args->object); +} + +static ENode *CABI_InitVBasePtr1(ENode *expr, TypeClass *tclass1, TypeClass *tclass2, TypeClass *tclass3, SInt32 offset) { + ClassList *base; + SInt32 newOffset; + OffsetList *list; + + for (base = tclass2->bases; base; base = base->next) { + if (base->base == tclass3 && base->is_virtual) { + newOffset = offset + base->offset; + + for (list = trans_vtboffsets; list; list = list->next) { + if (newOffset == list->offset) + break; + } + + if (!list) { + list = lalloc(sizeof(OffsetList)); + list->offset = newOffset; + list->next = trans_vtboffsets; + trans_vtboffsets = list; + + expr = makediadicnode( + makemonadicnode(CABI_MakeThisExpr(NULL, newOffset), EINDIRECT), + expr, + EASS); + } + } + + if (base->is_virtual) + newOffset = CClass_VirtualBaseOffset(tclass1, base->base); + else + newOffset = offset + base->offset; + + expr = CABI_InitVBasePtr1(expr, tclass1, base->base, tclass3, newOffset); + } + + return expr; +} + +static Statement *CABI_InitVBasePtrs(Statement *stmt, TypeClass *tclass) { + ENode *expr; + VClassList *vbase; + + for (vbase = tclass->vbases, trans_vtboffsets = NULL; vbase; vbase = vbase->next) { + expr = CABI_InitVBasePtr1(CABI_MakeThisExpr(NULL, vbase->offset), tclass, tclass, vbase->base, 0); + stmt = CFunc_InsertStatement(ST_EXPRESSION, stmt); + stmt->expr = expr; + } + + return stmt; +} + +static OffsetList *CABI_GetVBasePath(TypeClass *tclass, TypeClass *baseclass) { + ClassList *base; + OffsetList *best; + OffsetList *list; + OffsetList *scan; + short bestLength; + short length; + + for (base = tclass->bases; base; base = base->next) { + if (base->base == baseclass && base->is_virtual) { + best = lalloc(sizeof(OffsetList)); + best->next = NULL; + best->offset = base->offset; + return best; + } + } + + best = NULL; + + for (base = tclass->bases; base; base = base->next) { + if ((list = CABI_GetVBasePath(base->base, baseclass))) { + for (scan = list->next, length = 1; scan; scan = scan->next) + length++; + + if (base->is_virtual) + length++; + + if (!best || length < bestLength) { + if (base->is_virtual) { + best = lalloc(sizeof(OffsetList)); + best->next = list; + best->offset = base->offset; + } else { + best = list; + best->offset += base->offset; + } + bestLength = length; + } + } + } + + return best; +} + +static ENode *CABI_GetVBasePtr(TypeClass *tclass, TypeClass *baseclass) { + OffsetList *path; + ENode *expr; + + CError_ASSERT(1127, path = CABI_GetVBasePath(tclass, baseclass)); + + expr = makemonadicnode(CABI_MakeThisExpr(NULL, path->offset), EINDIRECT); + + while ((path = path->next)) { + if (path->offset) + expr = makediadicnode(expr, intconstnode(TYPE(&stunsignedlong), path->offset), EADD); + expr = makemonadicnode(expr, EINDIRECT); + } + + return expr; +} + +static SInt32 CABI_FindNVBase(TypeClass *tclass, TypeClass *baseclass, SInt32 offset) { + ClassList *base; + SInt32 tmp; + + if (tclass == baseclass) + return offset; + + for (base = tclass->bases; base; base = base->next) { + if (!base->is_virtual && (tmp = CABI_FindNVBase(base->base, baseclass, offset + base->offset)) >= 0) + return tmp; + } + + return -1; +} + +SInt32 CABI_GetCtorOffsetOffset(TypeClass *tclass, TypeClass *baseclass) { + SInt32 baseSize; + SInt32 size; + char saveAlignMode; + + size = CABI_GetBaseSize(tclass); + if (baseclass) { + baseSize = CABI_FindNVBase(tclass, baseclass, 0); + CError_ASSERT(1178, baseSize >= 0); + size -= baseSize; + } + + saveAlignMode = copts.structalignment; + if (tclass->eflags & CLASS_EFLAGS_F0) + copts.structalignment = ((tclass->eflags & CLASS_EFLAGS_F0) >> 4) - 1; + size += CMach_MemberAlignValue(TYPE(&stunsignedlong), size); + copts.structalignment = saveAlignMode; + + return size; +} + +static Statement *CABI_InitVBaseCtorOffsets(Statement *stmt, TypeClass *tclass) { + VClassList *vbase; + Object *tempObj; + ENode *expr; + ENode *vbaseptr; + SInt32 vboffset; + SInt32 ctorOffsetOffset; + + tempObj = NULL; + + for (vbase = tclass->vbases; vbase; vbase = vbase->next) { + if (vbase->has_override) { + if (!tempObj) + tempObj = create_temp_object(TYPE(&void_ptr)); + + vboffset = CClass_VirtualBaseOffset(tclass, vbase->base); + ctorOffsetOffset = CABI_GetCtorOffsetOffset(vbase->base, NULL); + vbaseptr = CABI_GetVBasePtr(tclass, vbase->base); + CError_ASSERT(1215, vbaseptr); + + expr = makediadicnode(create_objectnode(tempObj), vbaseptr, EASS); + stmt = CFunc_InsertStatement(ST_EXPRESSION, stmt); + stmt->expr = expr; + + expr = makediadicnode( + create_objectnode(tempObj), + intconstnode(TYPE(&stunsignedlong), ctorOffsetOffset), + EADD); + expr = makemonadicnode(expr, EINDIRECT); + expr->rtype = TYPE(&stunsignedlong); + expr = makediadicnode( + expr, + makediadicnode( + CABI_MakeThisExpr(NULL, vboffset), + create_objectnode(tempObj), + ESUB), + EASS); + stmt = CFunc_InsertStatement(ST_EXPRESSION, stmt); + stmt->expr = expr; + } + } + + return stmt; +} + +static Statement *CABI_InitVTablePtrs(Statement *stmt, Object *vtableObj, TypeClass *tclass, TypeClass *baseclass, SInt32 offset, SInt32 voffset) { + ClassList *base; + BClassList *orig_pathcur; + SInt32 newOffset; + SInt32 newVOffset; + OffsetList *offsetList; + SInt32 vtblOffset; + ENode *vtblExpr; + ENode *pathExpr; + BClassList path; + + if (baseclass->vtable->owner == baseclass) { + vtblOffset = offset + baseclass->vtable->offset; + for (offsetList = trans_vtboffsets; offsetList; offsetList = offsetList->next) { + if (vtblOffset == offsetList->offset) + break; + } + + if (!offsetList) { + offsetList = lalloc(sizeof(OffsetList)); + offsetList->offset = vtblOffset; + offsetList->next = trans_vtboffsets; + trans_vtboffsets = offsetList; + + vtblExpr = create_objectrefnode(vtableObj); + vtblExpr->rtype = TYPE(&void_ptr); + if ((vtblOffset = voffset + CABI_GetVTableOffset(baseclass))) + vtblExpr = makediadicnode(vtblExpr, intconstnode(TYPE(&stunsignedlong), vtblOffset), EADD); + + pathExpr = CClass_AccessPathCast(&cabi_pathroot, CABI_MakeThisExpr(tclass, 0), 0); + if (baseclass->vtable->offset && !canadd(pathExpr, baseclass->vtable->offset)) { + pathExpr = makediadicnode(pathExpr, intconstnode(TYPE(&stunsignedlong), baseclass->vtable->offset), EADD); + optimizecomm(pathExpr); + } + + stmt = CFunc_InsertStatement(ST_EXPRESSION, stmt); + stmt->expr = makediadicnode(makemonadicnode(pathExpr, EINDIRECT), vtblExpr, EASS); + } + } + + for (base = baseclass->bases; base; base = base->next) { + if (base->base->vtable) { + orig_pathcur = cabi_pathcur; + + cabi_pathcur->next = &path; + path.next = NULL; + path.type = TYPE(base->base); + cabi_pathcur = &path; + + if (base->is_virtual) { + newOffset = CClass_VirtualBaseOffset(tclass, base->base); + newVOffset = CClass_VirtualBaseVTableOffset(tclass, base->base); + } else { + newOffset = offset + base->offset; + newVOffset = voffset + base->voffset; + } + + stmt = CABI_InitVTablePtrs(stmt, vtableObj, tclass, base->base, newOffset, newVOffset); + + cabi_pathcur = orig_pathcur; + } + } + + return stmt; +} + +static Boolean CABI_IsOperatorNew(ObjBase *obj) { + return + obj->otype == OT_OBJECT && + IS_TYPE_FUNC(OBJECT(obj)->type) && + TYPE_FUNC(OBJECT(obj)->type)->args && + TYPE_FUNC(OBJECT(obj)->type)->args->type == CABI_GetSizeTType() && + !TYPE_FUNC(OBJECT(obj)->type)->args->next; +} + +Object *CABI_ConstructorCallsNew(TypeClass *tclass) { + NameSpaceObjectList *nsol; + NameResult pr; + + if (!tclass->sominfo && (tclass->flags & CLASS_HANDLEOBJECT)) { + if (CScope_FindClassMemberObject(tclass, &pr, CMangler_OperatorName(TK_NEW))) { + if (pr.obj_10) { + if (CABI_IsOperatorNew(pr.obj_10)) + return OBJECT(pr.obj_10); + } else { + for (nsol = pr.nsol_14; nsol; nsol = nsol->next) { + if (CABI_IsOperatorNew(nsol->object)) + return OBJECT(nsol->object); + } + } + } + + return newh_func; + } + + return NULL; +} + +void CABI_TransConstructor(Object *obj, Statement *firstStmt, TypeClass *tclass, TransConstructorCallback callback, Boolean has_try) { + Statement *stmt; + Object *tmpfunc; + Object *tmpfunc2; + CLabel *label; + ENode *expr; + ClassList *base; + VClassList *vbase; + ObjMemberVar *ivar; + Type *type; + CtorChain *chain; + Boolean errorflag; + + stmt = firstStmt; + + if ((tmpfunc = CABI_ConstructorCallsNew(tclass))) { + label = newlabel(); + + stmt = CFunc_InsertStatement(ST_IFGOTO, firstStmt); + stmt->expr = CABI_MakeThisExpr(NULL, 0); + stmt->label = label; + + expr = makediadicnode( + CABI_MakeThisExpr(NULL, 0), + funccallexpr(tmpfunc, intconstnode(CABI_GetSizeTType(), tclass->size), NULL, NULL, NULL), + EASS); + stmt = CFunc_InsertStatement(ST_IFGOTO, stmt); + stmt->expr = expr; + stmt->label = label; + + stmt = CFunc_InsertStatement(ST_RETURN, stmt); + stmt->expr = NULL; + + stmt = CFunc_InsertStatement(ST_LABEL, stmt); + stmt->label = label; + label->stmt = stmt; + } + + if (has_try) { + for (stmt = firstStmt; ; stmt = stmt->next) { + CError_ASSERT(1408, stmt); + if (stmt->type == ST_BEGINCATCH) + break; + } + } + + if (!tclass->sominfo) { + if (tclass->flags & CLASS_HAS_VBASES) { + label = newlabel(); + + stmt = CFunc_InsertStatement(ST_IFGOTO, stmt); + stmt->expr = CExpr_New_EEQU_Node(CABI_MakeVArgExpr(), intconstnode(TYPE(&stsignedshort), 0)); + stmt->label = label; + + stmt = CABI_InitVBasePtrs(stmt, tclass); + + for (vbase = tclass->vbases; vbase; vbase = vbase->next) { + if (!callback) { + for (chain = ctor_chain; chain; chain = chain->next) { + if (chain->what == CtorChain_VBase && chain->u.vbase == vbase) + break; + } + + if (chain) { + stmt = CFunc_InsertStatement(ST_EXPRESSION, stmt); + stmt->expr = chain->objexpr; + } else { + expr = CClass_DefaultConstructorCall( + vbase->base, + tclass, + CABI_MakeThisExpr(NULL, vbase->offset), + 0, 1, 1, &errorflag); + if (expr) { + stmt = CFunc_InsertStatement(ST_EXPRESSION, stmt); + stmt->expr = expr; + } else if (errorflag) { + CError_Error(CErrorStr213, tclass, 0, vbase->base, 0); + } + } + } else { + stmt = callback(stmt, tclass, vbase->base, vbase->offset, 1); + } + + if ((tmpfunc = CClass_Destructor(vbase->base))) + CExcept_RegisterMember(stmt, CABI_ThisArg(), vbase->offset, tmpfunc, CABI_VArg(), 0); + } + + stmt = CFunc_InsertStatement(ST_LABEL, stmt); + stmt->label = label; + label->stmt = stmt; + } + + for (base = tclass->bases; base; base = base->next) { + if (base->is_virtual) + continue; + + if (!callback) { + for (chain = ctor_chain; chain; chain = chain->next) { + if (chain->what == CtorChain_Base && chain->u.base == base) + break; + } + + if (chain) { + stmt = CFunc_InsertStatement(ST_EXPRESSION, stmt); + stmt->expr = chain->objexpr; + } else { + expr = CClass_DefaultConstructorCall( + base->base, + tclass, + CABI_MakeThisExpr(NULL, base->offset), + 0, 1, 0, &errorflag); + if (expr) { + stmt = CFunc_InsertStatement(ST_EXPRESSION, stmt); + stmt->expr = expr; + } else if (errorflag) { + CError_Error(CErrorStr213, tclass, 0, base->base, 0); + } + } + } else { + stmt = callback(stmt, tclass, base->base, base->offset, 1); + } + + if ((tmpfunc = CClass_Destructor(base->base))) + CExcept_RegisterMember(stmt, CABI_ThisArg(), base->offset, tmpfunc, NULL, 0); + } + + if (tclass->vtable && tclass->vtable->object && tclass->vtable->owner == tclass) { + cabi_pathroot.next = NULL; + cabi_pathroot.type = TYPE(tclass); + cabi_pathcur = &cabi_pathroot; + trans_vtboffsets = NULL; + + stmt = CABI_InitVTablePtrs(stmt, tclass->vtable->object, tclass, tclass, 0, 0); + } + } + + if (!tclass->sominfo && (tclass->flags & CLASS_FLAGS_8000)) + stmt = CABI_InitVBaseCtorOffsets(stmt, tclass); + + if (!callback) { + for (ivar = tclass->ivars; ivar; ivar = ivar->next) { + for (chain = ctor_chain; chain; chain = chain->next) { + if (chain->what == CtorChain_MemberVar && chain->u.membervar == ivar) { + if (IS_TYPE_ARRAY(ivar->type)) + chain = NULL; + break; + } + } + + if (chain) { + stmt = CFunc_InsertStatement(ST_EXPRESSION, stmt); + stmt->expr = chain->objexpr; + type = ivar->type; + switch (type->type) { + case TYPEARRAY: + do { + type = TPTR_TARGET(type); + } while (IS_TYPE_ARRAY(type)); + if (IS_TYPE_CLASS(type)) { + if ((tmpfunc = CClass_Destructor(TYPE_CLASS(type)))) { + CError_ASSERT(1560, type->size); + CExcept_RegisterMemberArray( + stmt, + CABI_ThisArg(), + ivar->offset, + tmpfunc, + ivar->type->size / type->size, + type->size); + } + } + break; + case TYPECLASS: + if ((tmpfunc = CClass_Destructor(TYPE_CLASS(type)))) { + CExcept_RegisterMember( + stmt, + CABI_ThisArg(), + ivar->offset, + tmpfunc, + NULL, + 1); + } + break; + } + } else { + type = ivar->type; + switch (type->type) { + case TYPEARRAY: + do { + type = TPTR_TARGET(type); + } while (IS_TYPE_ARRAY(type)); + if (IS_TYPE_CLASS(type) && CClass_Constructor(TYPE_CLASS(type))) { + if ( + (tmpfunc = CClass_DefaultConstructor(TYPE_CLASS(type))) || + (tmpfunc = CClass_DummyDefaultConstructor(TYPE_CLASS(type))) + ) + { + tmpfunc2 = CClass_Destructor(TYPE_CLASS(type)); + if (tmpfunc2) + tmpfunc2 = CABI_GetDestructorObject(tmpfunc2, 1); + + stmt = CInit_ConstructClassArray( + stmt, + TYPE_CLASS(type), + tmpfunc, + tmpfunc2, + CABI_MakeThisExpr(tclass, ivar->offset), + ivar->type->size / type->size); + + if (tmpfunc2) + CExcept_RegisterMemberArray( + stmt, + CABI_ThisArg(), + ivar->offset, + tmpfunc2, + ivar->type->size / type->size, + type->size); + } else { + CError_Error(CErrorStr214, tclass, 0, ivar->name->name); + } + } + break; + case TYPECLASS: + expr = CClass_DefaultConstructorCall( + TYPE_CLASS(type), + NULL, + CABI_MakeThisExpr(tclass, ivar->offset), + 1, 1, 0, &errorflag); + if (expr) { + stmt = CFunc_InsertStatement(ST_EXPRESSION, stmt); + stmt->expr = expr; + } else if (errorflag) { + CError_Error(CErrorStr214, tclass, 0, ivar->name->name); + } + + if ((tmpfunc = CClass_Destructor(TYPE_CLASS(type)))) { + if (!expr) { + stmt = CFunc_InsertStatement(ST_EXPRESSION, stmt); + stmt->expr = nullnode(); + } + CExcept_RegisterMember( + stmt, + CABI_ThisArg(), + ivar->offset, + tmpfunc, + NULL, + 1); + } + break; + } + } + } + } else { + stmt = callback(stmt, tclass, NULL, 0, 1); + } + + if (!tclass->sominfo) { + for (stmt = firstStmt->next; stmt; stmt = stmt->next) { + if (stmt->type == ST_RETURN) { + CError_ASSERT(1661, !stmt->expr); + stmt->expr = CABI_MakeThisExpr(NULL, 0); + } + } + } +} + +void CABI_MakeDefaultConstructor(TypeClass *tclass, Object *func) { + Boolean saveDebugInfo; + CScopeSave savedScope; + Statement firstStmt; + Statement returnStmt; + + if (anyerrors || func->access == ACCESSNONE) + return; + + CABI_ApplyClassFlags(func, tclass->eflags, 0); + + CScope_SetFunctionScope(func, &savedScope); + + CFunc_FuncGenSetup(&firstStmt, func); + + saveDebugInfo = copts.filesyminfo; + copts.filesyminfo = 0; + + CFunc_SetupNewFuncArgs(func, TYPE_FUNC(func->type)->args); + + ctor_chain = NULL; + if (tclass->flags & CLASS_HAS_VBASES) + arguments->next->object->name = CParser_GetUniqueName(); + + firstStmt.next = &returnStmt; + + memclrw(&returnStmt, sizeof(Statement)); + returnStmt.type = ST_RETURN; + + CABI_TransConstructor(func, &firstStmt, tclass, NULL, 0); + + CFunc_CodeCleanup(&firstStmt); + CFunc_Gen(&firstStmt, func, 0); + + CScope_RestoreScope(&savedScope); + copts.filesyminfo = saveDebugInfo; +} + +static ENode *CABI_AssignObject(TypeClass *tclass, ENode *expr1, ENode *expr2) { + Object *assignfunc; + FuncArg *arg; + + assignfunc = CClass_AssignmentOperator(tclass); + if (!assignfunc) { + expr1 = makemonadicnode(expr1, EINDIRECT); + expr1->rtype = TYPE(tclass); + return makediadicnode(expr1, expr2, EASS); + } + + CError_ASSERT(1731, + IS_TYPE_FUNC(assignfunc->type) && + (arg = TYPE_FUNC(assignfunc->type)->args) && + (arg = arg->next)); + + expr2 = argumentpromotion(expr2, arg->type, arg->qual, 1); + return funccallexpr(assignfunc, expr1, expr2, NULL, NULL); +} + +static Type *CABI_FindIntegralSizeType(SInt32 size) { + if (stunsignedchar.size == size) + return TYPE(&stunsignedchar); + if (stunsignedshort.size == size) + return TYPE(&stunsignedshort); + if (stunsignedint.size == size) + return TYPE(&stunsignedint); + if (stunsignedlong.size == size) + return TYPE(&stunsignedlong); + if (stunsignedlonglong.size == size) + return TYPE(&stunsignedlonglong); + + CError_FATAL(1756); + return NULL; +} + +#ifdef __MWERKS__ +#pragma options align=mac68k +#endif +typedef struct CopyRegion { + struct CopyRegion *next; + Type *type; + SInt32 start; + SInt32 end; + Boolean flag; +} CopyRegion; +#ifdef __MWERKS__ +#pragma options align=reset +#endif + +static CopyRegion *CABI_AppendCopyRegion(CopyRegion *regions, Type *type, SInt32 start, Boolean flag) { + CopyRegion *region; + SInt32 end; + + if (IS_TYPE_BITFIELD(type)) + type = TYPE_BITFIELD(type)->bitfieldtype; + + end = start + type->size; + + if (flag) { + for (region = regions; region; region = region->next) { + if (region->flag) { + if (region->start <= start && region->end >= end) + return regions; + + if (region->start >= start && region->end <= end) { + region->type = type; + region->start = start; + region->end = end; + for (region = region->next; region; region = region->next) { + if (region->start >= start && region->end <= end) + region->end = region->start; + } + return regions; + } + } + } + } + + if (regions) { + region = regions; + while (region->next) + region = region->next; + + region->next = lalloc(sizeof(CopyRegion)); + region = region->next; + } else { + regions = lalloc(sizeof(CopyRegion)); + region = regions; + } + + region->next = NULL; + region->type = type; + region->start = start; + region->end = end; + region->flag = flag; + + return regions; +} + +static ENode *CABI_ClassInitLoopCallBack(ENode *var1, ENode *var2) { + ENodeList *list; + + var2 = makemonadicnode(var2, EINDIRECT); + var2->rtype = TYPE(cabi_loop_class); + + if (cabi_loop_construct) { + list = lalloc(sizeof(ENodeList)); + memclrw(list, sizeof(ENodeList)); + list->node = var2; + return CExpr_ConstructObject(cabi_loop_class, var1, list, 1, 1, 0, 1, 1); + } else { + return CABI_AssignObject(cabi_loop_class, var1, var2); + } +} + +static Statement *CABI_CopyConAssignCB(Statement *stmt, TypeClass *tclass, TypeClass *baseclass, SInt32 offset, Boolean flag) { + ENode *expr; + ENode *expr2; + ENode *startExpr; + ENode *endExpr; + ENodeList *list; + ObjMemberVar *ivar; + CopyRegion *regions; + Type *type; + SInt32 i; + SInt32 count; + Boolean isFlagNotSet; + Object *tmpfunc; + + if (baseclass) { + if (baseclass->flags & CLASS_EMPTY) { + if ( + (flag && !CClass_CopyConstructor(baseclass)) || + (!flag && !CClass_AssignmentOperator(baseclass)) + ) + return stmt; + } + + expr = CABI_MakeCopyConArgExpr(tclass, flag); + expr->rtype = TYPE(baseclass); + expr->data.monadic = CClass_DirectBasePointerCast(expr->data.monadic, tclass, baseclass); + + stmt = CFunc_InsertStatement(ST_EXPRESSION, stmt); + if (flag) { + list = lalloc(sizeof(ENodeList)); + list->next = NULL; + list->node = expr; + + stmt->expr = CExpr_ConstructObject( + baseclass, + CABI_MakeThisExpr(NULL, offset), + list, + 1, 0, 0, 0, 1); + } else { + stmt->expr = CABI_AssignObject( + baseclass, + CClass_DirectBasePointerCast(CABI_MakeThisExpr(NULL, 0), tclass, baseclass), + expr); + } + } else { + isFlagNotSet = !flag; + for (ivar = tclass->ivars, regions = NULL; ivar; ivar = ivar->next) { + if (ivar->name == vptr_name_node) + continue; + + type = ivar->type; + if (isFlagNotSet) { + if (CParser_IsConst(type, ivar->qual) || IS_TYPE_REFERENCE(type) != 0) { + CError_Error(CErrorStr387, tclass, 0); + isFlagNotSet = 0; + } + } + + switch (type->type) { + case TYPEARRAY: + while (IS_TYPE_ARRAY(type)) + type = TPTR_TARGET(type); + if (!IS_TYPE_CLASS(type)) { + regions = CABI_AppendCopyRegion(regions, ivar->type, ivar->offset, 1); + break; + } + case TYPECLASS: + if (flag) { + if (CClass_CopyConstructor(TYPE_CLASS(type)) || CClass_CopyConstructor(TYPE_CLASS(type))) { + regions = CABI_AppendCopyRegion(regions, ivar->type, ivar->offset, 0); + break; + } + } else { + if (CClass_AssignmentOperator(TYPE_CLASS(type))) { + regions = CABI_AppendCopyRegion(regions, ivar->type, ivar->offset, 0); + break; + } + } + default: + regions = CABI_AppendCopyRegion(regions, ivar->type, ivar->offset, 1); + } + } + + for (; regions; regions = regions->next) { + if (regions->start >= regions->end) + continue; + + type = regions->type; + expr = CABI_MakeCopyConArgExpr(tclass, flag); + expr->rtype = type; + + if (!canadd(expr->data.monadic, regions->start)) { + expr->data.monadic = makediadicnode( + expr->data.monadic, + intconstnode(TYPE(&stunsignedlong), regions->start), + EADD); + optimizecomm(expr->data.monadic); + } + + if (!regions->flag) { + if (IS_TYPE_ARRAY(type)) { + while (IS_TYPE_ARRAY(type)) + type = TPTR_TARGET(type); + + CError_ASSERT(1966, IS_TYPE_CLASS(type)); + + if (type->size) { + count = regions->type->size / type->size; + if (count > 4) { + startExpr = CABI_MakeThisExpr(tclass, regions->start); + endExpr = CABI_MakeThisExpr(tclass, regions->start + regions->type->size); + expr = CABI_MakeCopyConArgExpr(tclass, flag)->data.monadic; + if (!canadd(expr, regions->start)) { + expr = makediadicnode( + expr, + intconstnode(TYPE(&stunsignedlong), regions->start), + EADD); + optimizecomm(expr); + } + + cabi_loop_class = TYPE_CLASS(type); + cabi_loop_construct = flag; + stmt = CFunc_GenerateLoop( + stmt, + CDecl_NewPointerType(type), + startExpr, + endExpr, + intconstnode(TYPE(&stunsignedlong), type->size), + expr, + CABI_ClassInitLoopCallBack); + } else { + for (i = 0, offset = regions->start; i < count; i++, offset += type->size) { + expr = CABI_MakeCopyConArgExpr(tclass, flag); + expr->rtype = type; + + if (!canadd(expr->data.monadic, offset)) { + expr->data.monadic = makediadicnode( + expr->data.monadic, + intconstnode(TYPE(&stunsignedlong), offset), + EADD); + optimizecomm(expr->data.monadic); + } + + stmt = CFunc_InsertStatement(ST_EXPRESSION, stmt); + if (flag) { + list = lalloc(sizeof(ENodeList)); + memclrw(list, sizeof(ENodeList)); + list->node = expr; + stmt->expr = CExpr_ConstructObject( + TYPE_CLASS(type), + CABI_MakeThisExpr(tclass, offset), + list, + 1, 1, 0, 1, 1); + } else { + stmt->expr = CABI_AssignObject( + TYPE_CLASS(type), + CABI_MakeThisExpr(tclass, offset), + expr); + } + } + } + + if (flag && (tmpfunc = CClass_Destructor(TYPE_CLASS(type)))) + CExcept_RegisterMemberArray(stmt, CABI_ThisArg(), regions->start, tmpfunc, count, type->size); + } + } else { + CError_ASSERT(2027, IS_TYPE_CLASS(type)); + + stmt = CFunc_InsertStatement(ST_EXPRESSION, stmt); + + if (flag) { + list = lalloc(sizeof(ENodeList)); + memclrw(list, sizeof(ENodeList)); + list->node = expr; + stmt->expr = CExpr_ConstructObject( + TYPE_CLASS(type), + CABI_MakeThisExpr(tclass, regions->start), + list, + 1, 1, 0, 1, 1); + + if ((tmpfunc = CClass_Destructor(TYPE_CLASS(type)))) + CExcept_RegisterMember(stmt, CABI_ThisArg(), regions->start, tmpfunc, NULL, 1); + } else { + stmt->expr = CABI_AssignObject( + TYPE_CLASS(type), + CABI_MakeThisExpr(tclass, regions->start), + expr); + } + } + } else { + if (IS_TYPE_ARRAY(type)) { + if (type->size > 1 && ((regions->start & 1) || (type->size & 1))) { + stmt = CFunc_InsertStatement(ST_EXPRESSION, stmt); + stmt->expr = funccallexpr( + copy_func, + CABI_MakeThisExpr(tclass, regions->start), + getnodeaddress(expr, 0), + intconstnode(CABI_GetSizeTType(), type->size), + NULL); + continue; + } + + type = CDecl_NewStructType(type->size, CMach_GetTypeAlign(type)); + expr->rtype = type; + } + + expr2 = makemonadicnode(CABI_MakeThisExpr(tclass, regions->start), EINDIRECT); + expr2->rtype = type; + stmt = CFunc_InsertStatement(ST_EXPRESSION, stmt); + stmt->expr = makediadicnode(expr2, expr, EASS); + } + } + } + + return stmt; +} + +void CABI_MakeDefaultCopyConstructor(TypeClass *tclass, Object *func) { + Boolean saveDebugInfo; + CScopeSave savedScope; + Statement firstStmt; + Statement returnStmt; + + if (anyerrors || func->access == ACCESSNONE) + return; + + CABI_ApplyClassFlags(func, tclass->eflags, 0); + + CScope_SetFunctionScope(func, &savedScope); + + CFunc_FuncGenSetup(&firstStmt, func); + + saveDebugInfo = copts.filesyminfo; + copts.filesyminfo = 0; + + CFunc_SetupNewFuncArgs(func, TYPE_FUNC(func->type)->args); + + ctor_chain = NULL; + if (tclass->flags & CLASS_HAS_VBASES) + arguments->next->object->name = CParser_GetUniqueName(); + + firstStmt.next = &returnStmt; + + memclrw(&returnStmt, sizeof(Statement)); + returnStmt.type = ST_RETURN; + + CABI_TransConstructor(func, &firstStmt, tclass, CABI_CopyConAssignCB, 0); + + CFunc_CodeCleanup(&firstStmt); + CFunc_Gen(&firstStmt, func, 0); + + CScope_RestoreScope(&savedScope); + copts.filesyminfo = saveDebugInfo; +} + +void CABI_MakeDefaultAssignmentOperator(TypeClass *tclass, Object *func) { + Boolean saveDebugInfo; + Statement *stmt; + ClassList *base; + VClassList *vbase; + ENode *expr1; + ENode *expr2; + CScopeSave savedScope; + Statement firstStmt; + + if (anyerrors || func->access == ACCESSNONE) + return; + + CABI_ApplyClassFlags(func, tclass->eflags, 0); + + CScope_SetFunctionScope(func, &savedScope); + + CFunc_FuncGenSetup(&firstStmt, func); + + saveDebugInfo = copts.filesyminfo; + copts.filesyminfo = 0; + + CFunc_SetupNewFuncArgs(func, TYPE_FUNC(func->type)->args); + + stmt = curstmt; + + if (tclass->mode == CLASS_MODE_UNION) { + expr1 = makemonadicnode(CABI_MakeThisExpr(tclass, 0), EINDIRECT); + expr1->rtype = TYPE(tclass); + + expr2 = CABI_MakeCopyConArgExpr(tclass, 0); + expr2->rtype = TYPE(tclass); + + stmt = CFunc_InsertStatement(ST_EXPRESSION, stmt); + stmt->expr = makediadicnode(expr1, expr2, EASS); + } else { + for (vbase = tclass->vbases; vbase; vbase = vbase->next) { + stmt = CABI_CopyConAssignCB(stmt, tclass, vbase->base, vbase->offset, 0); + } + + for (base = tclass->bases; base; base = base->next) { + if (!base->is_virtual) + stmt = CABI_CopyConAssignCB(stmt, tclass, base->base, base->offset, 0); + } + + stmt = CABI_CopyConAssignCB(stmt, tclass, NULL, 0, 0); + } + + stmt = CFunc_InsertStatement(ST_RETURN, stmt); + stmt->expr = CABI_MakeThisExpr(NULL, 0); + + CFunc_CodeCleanup(&firstStmt); + CFunc_Gen(&firstStmt, func, 0); + + CScope_RestoreScope(&savedScope); + copts.filesyminfo = saveDebugInfo; +} + +static Statement *CABI_DestroyMembers(Statement *stmt, ObjMemberVar *ivars, TypeClass *tclass) { + Type *type; + Object *dtor; + ENode *expr; + + for (; ivars; ivars = ivars->next) { + type = ivars->type; + + if (IS_TYPE_ARRAY(type)) { + while (IS_TYPE_ARRAY(type)) + type = TPTR_TARGET(type); + + if (IS_TYPE_CLASS(type) && (dtor = CClass_Destructor(TYPE_CLASS(type)))) { + dtor = CABI_GetDestructorObject(dtor, 1); + stmt = CABI_DestroyMembers(stmt, ivars->next, tclass); + expr = create_objectrefnode(dtor); + expr->flags = expr->flags | ENODE_FLAG_80; + + stmt = CFunc_InsertStatement(ST_EXPRESSION, stmt); + stmt->expr = funccallexpr( + darr_func, + CABI_MakeThisExpr(tclass, ivars->offset), + expr, + intconstnode(TYPE(&stsignedlong), type->size), + intconstnode(TYPE(&stsignedlong), ivars->type->size / type->size) + ); + return stmt; + } + } else { + if (IS_TYPE_CLASS(type) && (dtor = CClass_Destructor(TYPE_CLASS(type)))) { + stmt = CABI_DestroyMembers(stmt, ivars->next, tclass); + + stmt = CFunc_InsertStatement(ST_EXPRESSION, stmt); + stmt->expr = CABI_DestroyObject( + dtor, + CABI_MakeThisExpr(tclass, ivars->offset), + CABIDestroy1, + 1, + 0 + ); + return stmt; + } + } + } + + return stmt; +} + +static Statement *CABI_DestroyBases(Statement *stmt, ClassList *bases) { + ClassList *base; + Object *dtor; + SInt32 count; + SInt32 i; + + base = bases; + count = 0; + while (base) { + base = base->next; + count++; + } + + while (count > 0) { + base = bases; + i = count; + while (i-- > 1) + base = base->next; + + if (!base->is_virtual && (dtor = CClass_Destructor(base->base))) { + stmt = CFunc_InsertStatement(ST_EXPRESSION, stmt); + stmt->expr = CABI_DestroyObject( + dtor, + CABI_MakeThisExpr(NULL, base->offset), + CABIDestroy0, + 1, + 0); + } + + count--; + } + + return stmt; +} + +static Statement *CABI_DestroyVBases(Statement *stmt, VClassList *vbases) { + Object *dtor; + + for (; vbases; vbases = vbases->next) { + if ((dtor = CClass_Destructor(vbases->base))) { + stmt = CABI_DestroyVBases(stmt, vbases->next); + stmt = CFunc_InsertStatement(ST_EXPRESSION, stmt); + stmt->expr = CABI_DestroyObject( + dtor, + CABI_MakeThisExpr(NULL, vbases->offset), + CABIDestroy0, + 1, + 0); + break; + } + } + + return stmt; +} + +void CABI_TransDestructor(Object *obj1, Object *obj2, Statement *stmt, TypeClass *tclass, CABIDestroyMode mode) { + CLabel *label2; + Boolean flag29; + CLabel *label; + Statement *scan; + Boolean flag25; + Boolean flag24; + Boolean flag23; + CLabel *label3; + Object *dealloc; + Boolean deallocFlag; + + if (tclass->sominfo) { + flag24 = 0; + flag25 = 0; + flag29 = 0; + flag23 = 1; + } else { + flag24 = 1; + flag23 = 1; + flag25 = 1; + flag29 = 1; + } + + label = newlabel(); + + for (scan = stmt; scan; scan = scan->next) { + if (scan->type == ST_RETURN) { + CError_ASSERT(2329, !scan->expr); + scan->type = ST_GOTO; + scan->label = label; + } + + if (scan->next && scan->next->type == ST_RETURN && !scan->next->next) { + CError_ASSERT(2334, !scan->next->expr); + scan->next = NULL; + break; + } + } + + scan = stmt; + + if (flag29) { + label2 = newlabel(); + scan = CFunc_InsertStatement(ST_IFNGOTO, scan); + scan->expr = CABI_MakeThisExpr(NULL, 0); + scan->label = label2; + } + + if (flag25 && tclass->vtable && tclass->vtable->object && tclass->vtable->owner == tclass) { + cabi_pathroot.next = NULL; + cabi_pathroot.type = TYPE(tclass); + cabi_pathcur = &cabi_pathroot; + trans_vtboffsets = NULL; + scan = CABI_InitVTablePtrs(scan, tclass->vtable->object, tclass, tclass, 0, 0); + } + + if (!tclass->sominfo && (tclass->flags & CLASS_FLAGS_8000)) + CABI_InitVBaseCtorOffsets(scan, tclass); + + scan = stmt; + while (scan->next) + scan = scan->next; + + scan = CFunc_InsertStatement(ST_LABEL, scan); + scan->label = label; + scan->dobjstack = NULL; + label->stmt = scan; + + if (flag23 && !(tclass->flags & CLASS_HANDLEOBJECT)) + scan = CABI_DestroyMembers(scan, tclass->ivars, tclass); + + if (flag25 && tclass->bases) + scan = CABI_DestroyBases(scan, tclass->bases); + + if (flag24 && (tclass->flags & CLASS_HAS_VBASES)) { + label3 = newlabel(); + scan = CFunc_InsertStatement(ST_IFNGOTO, scan); + scan->expr = CABI_MakeVArgExpr(); + scan->label = label3; + + scan = CABI_DestroyVBases(scan, tclass->vbases); + + scan = CFunc_InsertStatement(ST_LABEL, scan); + scan->label = label3; + label3->stmt = scan; + } + + if (flag29) { + scan = CFunc_InsertStatement(ST_IFGOTO, scan); + scan->expr = CExpr_New_ELESSEQU_Node(CABI_MakeVArgExpr(), intconstnode(TYPE(&stsignedshort), 0)); + scan->label = label2; + + scan = CFunc_InsertStatement(ST_EXPRESSION, scan); + dealloc = CParser_FindDeallocationObject(TYPE(tclass), NULL, 0, 0, &deallocFlag); + if (deallocFlag) { + scan->expr = funccallexpr( + dealloc, + CABI_MakeThisExpr(NULL, 0), + intconstnode(CABI_GetSizeTType(), tclass->size), + NULL, + NULL); + } else { + scan->expr = funccallexpr(dealloc, CABI_MakeThisExpr(NULL, 0), NULL, NULL, NULL); + } + + scan = CFunc_InsertStatement(ST_LABEL, scan); + scan->label = label2; + label2->stmt = scan; + } + + scan = CFunc_InsertStatement(ST_RETURN, scan); + if (tclass->sominfo) + scan->expr = NULL; + else + scan->expr = CABI_MakeThisExpr(NULL, 0); +} + +void CABI_MakeDefaultDestructor(TypeClass *tclass, Object *func) { + Boolean saveDebugInfo; + CScopeSave savedScope; + Statement firstStmt; + Statement returnStmt; + + if (anyerrors || func->access == ACCESSNONE) + return; + + CABI_ApplyClassFlags(func, tclass->eflags, 0); + + CScope_SetFunctionScope(func, &savedScope); + + CFunc_FuncGenSetup(&firstStmt, func); + + saveDebugInfo = copts.filesyminfo; + copts.filesyminfo = 0; + + CFunc_SetupNewFuncArgs(func, TYPE_FUNC(func->type)->args); + + firstStmt.next = &returnStmt; + + memclrw(&returnStmt, sizeof(Statement)); + returnStmt.type = ST_RETURN; + + CFunc_CodeCleanup(&firstStmt); + + CABI_TransDestructor(func, func, &firstStmt, tclass, CABIDestroy0); + + CFunc_Gen(&firstStmt, func, 0); + + CScope_RestoreScope(&savedScope); + copts.filesyminfo = saveDebugInfo; +} + +static void CABI_CreateLayeredDestructor(TypeClass *tclass, Object *obj1, Object *func, CABIDestroyMode mode) { + Boolean saveDebugInfo; + CScopeSave savedScope; + Statement firstStmt; + Statement returnStmt; + + CError_FATAL(2524); + + CScope_SetFunctionScope(func, &savedScope); + + CFunc_FuncGenSetup(&firstStmt, func); + + saveDebugInfo = copts.filesyminfo; + copts.filesyminfo = 0; + + CFunc_SetupNewFuncArgs(func, TYPE_FUNC(func->type)->args); + + firstStmt.next = &returnStmt; + + memclrw(&returnStmt, sizeof(Statement)); + returnStmt.type = ST_RETURN; + + CFunc_CodeCleanup(&firstStmt); + + CABI_TransDestructor(obj1, func, &firstStmt, tclass, mode); + + CFunc_Gen(&firstStmt, func, 0); + + CScope_RestoreScope(&savedScope); + copts.filesyminfo = saveDebugInfo; +} + +void CABI_MakeLayeredDestructor(TypeClass *tclass, Object *func) { + Object *dtor; + CABIDestroyMode mode; + + CError_FATAL(2557); + + if (anyerrors || func->access == ACCESSNONE) + return; + + if ((dtor = CClass_Destructor(tclass))) { + if (CABI_GetDestructorObject(dtor, CABIDestroy0) == func) + mode = CABIDestroy0; + else if (CABI_GetDestructorObject(dtor, CABIDestroy2) == func) + mode = CABIDestroy2; + else if (CABI_GetDestructorObject(dtor, CABIDestroy3) == func) + mode = CABIDestroy3; + else if (CABI_GetDestructorObject(dtor, CABIDestroy1) == func) + mode = CABIDestroy1; + else + CError_FATAL(2567); + } + + CABI_CreateLayeredDestructor(tclass, dtor, func, mode); +} + +Object *CABI_GetDestructorObject(Object *obj, CABIDestroyMode mode) { + return obj; +} + +static void CABI_AddLayeredDestructor(TypeClass *tclass, Object *dtor, HashNameNode *name, Boolean is_virtual) { + Object *func; + + CError_FATAL(2667); + + func = CParser_NewFunctionObject(NULL); + func->nspace = dtor->nspace; + func->name = name; + func->type = TYPE(CDecl_MakeDefaultDtorType(tclass, is_virtual)); + func->qual = Q_20000 | Q_MANGLE_NAME; + func->qual |= Q_INLINE; + CABI_ApplyClassFlags(func, tclass->eflags, 1); + + CError_ASSERT(2678, IS_TYPE_FUNC(func->type)); + TYPE_FUNC(func->type)->flags |= FUNC_AUTO_GENERATED; + + if (dtor->datatype == DVFUNC) { + func->datatype = DVFUNC; + CMangler_GetLinkName(func); + func->datatype = DFUNC; + } + + CScope_AddObject(func->nspace, func->name, OBJ_BASE(func)); +} + +void CABI_AddLayeredDestructors(TypeClass *tclass) { + Object *dtor; + + CError_FATAL(2707); + + if ((dtor = CClass_Destructor(tclass))) { + CABI_AddLayeredDestructor(tclass, dtor, CMangler_DeleteDtorName(), 1); + CABI_AddLayeredDestructor(tclass, dtor, CMangler_SDeleteDtorName(), 1); + if (tclass->vbases) + CABI_AddLayeredDestructor(tclass, dtor, CMangler_VBaseDtorName(), 0); + } +} + +ENode *CABI_DestroyObject(Object *dtor, ENode *objexpr, CABIDestroyMode mode, Boolean flag1, Boolean flag2) { + ENode *expr; + short arg; + ENodeList *list; + + switch (mode) { + case CABIDestroy2: + case CABIDestroy3: + if (flag2) + arg = 1; + else + arg = -1; + break; + case CABIDestroy1: + arg = -1; + break; + case CABIDestroy0: + arg = 0; + break; + default: + CError_FATAL(2786); + } + + expr = lalloc(sizeof(ENode)); + expr->type = EFUNCCALL; + expr->cost = 200; + expr->flags = 0; + expr->rtype = &stvoid; + expr->data.funccall.funcref = create_objectrefnode(dtor); + if (flag1) + expr->data.funccall.funcref->flags = expr->data.funccall.funcref->flags | ENODE_FLAG_80; + expr->data.funccall.functype = TYPE_FUNC(dtor->type); + dtor->flags = dtor->flags | OBJECT_USED; + + list = lalloc(sizeof(ENodeList)); + list->node = objexpr; + expr->data.funccall.args = list; + + list->next = lalloc(sizeof(ENodeList)); + list = list->next; + list->next = NULL; + list->node = intconstnode(TYPE(&stsignedshort), arg); + + return expr; +} diff --git a/compiler_and_linker/FrontEnd/C/CBrowse.c b/compiler_and_linker/FrontEnd/C/CBrowse.c new file mode 100644 index 0000000..12ea4c8 --- /dev/null +++ b/compiler_and_linker/FrontEnd/C/CBrowse.c @@ -0,0 +1,737 @@ +#include "compiler/CBrowse.h" +#include "compiler/CDecl.h" +#include "compiler/CError.h" +#include "compiler/CMangler.h" +#include "compiler/CParser.h" +#include "compiler/CPrep.h" +#include "compiler/CompilerTools.h" +#include "compiler/Unmangle.h" +#include "compiler/objects.h" +#include "compiler/templates.h" +#include "cos.h" +#include "plugin.h" + +Boolean gUseTokenStreamSource; +Boolean gForceSourceLoc; +Boolean gUseNameTable; +static GList gBrowseData; +static GList gClassData; +static GList gMemberFuncList; +static int gNextMemberFuncID; + +enum ELanguage { + langUnknown, + langC, + langCPlus, + langPascal, + langObjectPascal, + langJava, + langAssembler, + langFortran, + langRez +}; + +enum EBrowserItem { + browseFunction, + browseGlobal, + browseClass, + browseMacro, + browseEnum, + browseTypedef, + browseConstant, + browseTemplate, + browsePackage, + browseCompSymbolStart = 0x70, + browseEnd = 0xFF +}; + +enum { + kAbstract = 1, + kStatic = 2, + kFinal = 4, + kMember = 8, + + kInterface = 0x80, + kPublic = 0x100, + + kInline = 0x80, + kPascal = 0x100, + kAsm = 0x200, + kVirtual = 0x400, + kCtor = 0x800, + kDtor = 0x1000, + kNative = 0x2000, + kSynch = 0x4000, + kIntrinsic = 0x8000, + kConst = 0x10000, + + kTransient = 0x80, + kVolatile = 0x100 +}; + +enum EAccess { + accessNone = 0, + accessPrivate = 1, + accessProtected = 2, + accessPublic = 4 +}; + +enum EMember { + memberFunction, + memberData, + memberEnd = 0xFF +}; + +enum ETemplateType { + templateClass, + templateFunction +}; + +static enum EAccess gFromAccessType[] = { + accessPublic, + accessPrivate, + accessProtected, + accessNone +}; + +typedef struct BrowseHeader { + SInt32 browse_header; + SInt32 browse_version; + SInt16 browse_language; + SInt16 uses_name_table; + SInt32 earliest_compatible_version; + SInt32 reserved[15]; +} BrowseHeader; + +// forward decls +static void RecordUndefinedMemberFunctions(void); + +void CBrowse_Setup(CompilerLinkerParamBlk *params) { + BrowseHeader hdr; + + CError_ASSERT(123, params != NULL); + + params->object.browsedata = NULL; + + InitGList(&gBrowseData, 0x10000); + InitGList(&gMemberFuncList, 1024); + + gNextMemberFuncID = 1; + gForceSourceLoc = 0; + gUseNameTable = 0; + + memclrw(&hdr, sizeof(hdr)); + hdr.browse_header = 0xBEABBAEB; + hdr.browse_version = 2; + hdr.earliest_compatible_version = 2; + hdr.browse_language = copts.cplusplus ? langCPlus : langC; + hdr.uses_name_table = gUseNameTable; + + AppendGListData(&gBrowseData, &hdr, sizeof(hdr)); +} + +void CBrowse_Finish(CompilerLinkerParamBlk *params) { + CWMemHandle hnd; + + CError_ASSERT(151, params != NULL); + + if (gBrowseData.size >= sizeof(BrowseHeader)) { + RecordUndefinedMemberFunctions(); + AppendGListByte(&gBrowseData, -1); + + COS_ResizeHandle(gBrowseData.data, gBrowseData.size); + + if (CWSecretAttachHandle(params->context, gBrowseData.data, &hnd) == cwNoErr) { + params->object.browsedata = hnd; + gBrowseData.data = NULL; + } + } +} + +void CBrowse_Cleanup(CompilerLinkerParamBlk *params) { + FreeGList(&gBrowseData); + FreeGList(&gClassData); + FreeGList(&gMemberFuncList); +} + +static void AppendGList(GList *dst, GList *src) { + SInt32 offset = dst->size; + + AppendGListNoData(dst, src->size); + memcpy(*dst->data + offset, *src->data, src->size); +} + +static void RecordName(GList *gl, const char *str, SInt32 id) { + HashNameNode *name; + + CError_ASSERT(190, gl && str && *str); + + if (id < 0 && gUseNameTable) { + for (name = name_hash_nodes[CHash(str)]; name; name = name->next) { + if (!strcmp(str, name->name)) { + id = name->id; + break; + } + } + } + + if (id >= 0 && gUseNameTable) { + AppendGListWord(gl, -1); + AppendGListLong(gl, id); + } else { + int len = strlen(str); + AppendGListWord(gl, len); + if (len) + AppendGListData(gl, str, len + 1); + } +} + +void CBrowse_BeginClass(DeclInfo *di, GList *gl) { + char *buf; + ClassList *base; + SInt32 i; + TypeClass *tclass; + + CError_ASSERT(227, di && di->thetype && gl); + + *gl = gClassData; + + if ( + !di->file || + !di->file->fileID || + !di->file->recordbrowseinfo || + !di->file2 || + !di->file2->fileID || + di->sourceoffset <= 0 + ) + { + memclrw(&gClassData, sizeof(gClassData)); + return; + } + + if (IsTempName(TYPE_CLASS(di->thetype)->classname)) { + memclrw(&gClassData, sizeof(gClassData)); + return; + } + + InitGList(&gClassData, 0x4000); + AppendGListByte(&gClassData, browseClass); + AppendGListWord(&gClassData, di->file->fileID); + AppendGListWord(&gClassData, di->file2->fileID); + AppendGListLong(&gClassData, di->sourceoffset - 1); + CError_ASSERT(270, gClassData.size == 9); + AppendGListLong(&gClassData, di->sourceoffset - 1); + AppendGListLong(&gClassData, 0); + RecordName(&gClassData, TYPE_CLASS(di->thetype)->classname->name, TYPE_CLASS(di->thetype)->classname->id); + + CMangler_MangleType(di->thetype, 0); + AppendGListByte(&name_mangle_list, 0); + + buf = lalloc(name_mangle_list.size + 1); + strcpy(buf, *name_mangle_list.data); + + while (*buf && *buf >= '0' && *buf <= '9') + buf++; + + if (strcmp(TYPE_CLASS(di->thetype)->classname->name, buf)) + RecordName(&gClassData, buf, -1); + else + AppendGListWord(&gClassData, 0); + + AppendGListLong(&gClassData, 0); + + i = 0; + base = TYPE_CLASS(di->thetype)->bases; + while (base) { + base = base->next; + i++; + } + + AppendGListByte(&gClassData, i); + + for (base = TYPE_CLASS(di->thetype)->bases; base; base = base->next) { + AppendGListByte(&gClassData, gFromAccessType[base->access]); + AppendGListByte(&gClassData, base->is_virtual); + + tclass = base->base; + if ((tclass->flags & CLASS_IS_TEMPL_INST) && !TEMPL_CLASS_INST(tclass)->is_specialized) + tclass = TYPE_CLASS(TEMPL_CLASS_INST(tclass)->templ); + + CMangler_MangleType(TYPE(tclass), 0); + AppendGListByte(&name_mangle_list, 0); + + buf = lalloc(name_mangle_list.size + 1); + strcpy(buf, *name_mangle_list.data); + + while (*buf && *buf >= '0' && *buf <= '9') + buf++; + + i = base->base->classname->id; + while (*buf && *buf >= '0' && *buf <= '9') { + i = -1; + buf++; + } + + RecordName(&gClassData, buf, i); + } +} + +void CBrowse_AddClassMemberVar(ObjMemberVar *ivar, SInt32 startOffset, SInt32 endOffset) { + short len; + + CError_ASSERT(360, ivar); + + if (gClassData.data && startOffset > 0 && endOffset >= startOffset) { + if (tk == ';') + endOffset++; + + AppendGListByte(&gClassData, memberData); + AppendGListByte(&gClassData, gFromAccessType[ivar->access]); + AppendGListLong(&gClassData, 0); + AppendGListLong(&gClassData, startOffset - 1); + AppendGListLong(&gClassData, endOffset - 1); + + len = strlen(ivar->name->name); + AppendGListWord(&gClassData, len); + AppendGListData(&gClassData, ivar->name->name, len + 1); + } +} + +void CBrowse_AddClassMemberFunction(Object *object, SInt32 startOffset, SInt32 endOffset) { + SInt32 flags; + SInt32 id; + TypeMemberFunc *tfunc; + + CError_ASSERT(380, object); + + if ( + !IsTempName(object->name) && + gClassData.data && + startOffset > 0 && + endOffset >= startOffset + ) + { + flags = 0; + CError_ASSERT(391, object->type && IS_TYPE_FUNC(object->type)); + tfunc = TYPE_METHOD(object->type); + + if (tfunc->flags & FUNC_AUTO_GENERATED) + return; + + if (object->datatype == DVFUNC) + flags |= kVirtual; + if (tfunc->flags & FUNC_PURE) + flags |= kAbstract; + if (tfunc->is_static) + flags |= kStatic; + if (tfunc->flags & FUNC_IS_CTOR) + flags |= kCtor; + if (tfunc->flags & FUNC_IS_DTOR) + flags |= kDtor; + + AppendGListByte(&gClassData, memberFunction); + AppendGListByte(&gClassData, gFromAccessType[object->access]); + AppendGListLong(&gClassData, flags); + + id = tfunc->funcid; + if (id <= 0) { + // TODO: this is not 64-bit safe + if (!(tfunc->flags & FUNC_DEFINED) || id == -1) + AppendGListLong(&gMemberFuncList, (SInt32) object); + tfunc->funcid = id = gNextMemberFuncID++; + } + + AppendGListLong(&gClassData, id); + AppendGListLong(&gClassData, startOffset - 1); + AppendGListLong(&gClassData, endOffset); + } +} + +void CBrowse_AddClassMemberData(Object *object, SInt32 startOffset, SInt32 endOffset) { + short len; + + CError_ASSERT(435, object); + + if (gClassData.data && startOffset > 0 && endOffset >= startOffset && object->datatype == DDATA) { + if (tk == ';') + endOffset++; + + AppendGListByte(&gClassData, memberData); + AppendGListByte(&gClassData, gFromAccessType[object->access]); + AppendGListLong(&gClassData, kStatic); + AppendGListLong(&gClassData, startOffset - 1); + AppendGListLong(&gClassData, endOffset - 1); + + len = strlen(object->name->name); + AppendGListWord(&gClassData, len); + AppendGListData(&gClassData, object->name->name, len + 1); + } +} + +void CBrowse_EndClass(SInt32 offset, GList *gl) { + CError_ASSERT(453, gl); + + if (gClassData.data) { + if (gClassData.size > 0) { + if (tk == ';') + offset++; + memcpy(*gClassData.data + 9, &offset, 4); + AppendGList(&gBrowseData, &gClassData); + AppendGListByte(&gBrowseData, memberEnd); + } + FreeGList(&gClassData); + } + + gClassData = *gl; +} + +void CBrowse_BeginStruct(DeclInfo *di, TypeStruct *tstruct, GList *gl) { + HashNameNode *name; + + CError_ASSERT(480, di && gl); + + *gl = gClassData; + + if ( + !di->file || + !di->file->fileID || + !di->file->recordbrowseinfo || + !di->file2 || + !di->file2->fileID || + di->sourceoffset <= 0 + ) + { + memclrw(&gClassData, sizeof(gClassData)); + return; + } + + name = tstruct->name; + if (!name || IsTempName(name)) { + memclrw(&gClassData, sizeof(gClassData)); + return; + } + + InitGList(&gClassData, 0x4000); + AppendGListByte(&gClassData, browseClass); + AppendGListWord(&gClassData, di->file->fileID); + AppendGListWord(&gClassData, di->file2->fileID); + AppendGListLong(&gClassData, di->sourceoffset - 1); + CError_ASSERT(521, gClassData.size == 9); + AppendGListLong(&gClassData, di->sourceoffset - 1); + AppendGListLong(&gClassData, 0); + RecordName(&gClassData, name->name, name->id); + AppendGListWord(&gClassData, 0); + AppendGListLong(&gClassData, 0); + AppendGListByte(&gClassData, 0); +} + +void CBrowse_AddStructMember(StructMember *member, SInt32 startOffset, SInt32 endOffset) { + short len; + + if (tk == ';') + endOffset++; + + if (gClassData.data && member && startOffset > 0 && endOffset >= startOffset) { + AppendGListByte(&gClassData, memberData); + AppendGListByte(&gClassData, accessPublic); + AppendGListLong(&gClassData, 0); + AppendGListLong(&gClassData, startOffset - 1); + AppendGListLong(&gClassData, endOffset - 1); + + len = strlen(member->name->name); + AppendGListWord(&gClassData, len); + AppendGListData(&gClassData, member->name->name, len + 1); + } +} + +void CBrowse_EndStruct(SInt32 offset, GList *gl) { + CError_ASSERT(558, gl); + + if (gClassData.data) { + if (offset > 0 && gClassData.size > 0) { + memcpy(*gClassData.data + 9, &offset, 4); + AppendGList(&gBrowseData, &gClassData); + AppendGListByte(&gBrowseData, memberEnd); + } + FreeGList(&gClassData); + } + + gClassData = *gl; +} + +static void EmitStandardData(int item, int fileID1, int fileID2, SInt32 startOffset, SInt32 endOffset, const char *str, SInt32 id, const char *str2, SInt32 id2) { + CError_ASSERT(584, str); + + AppendGListByte(&gBrowseData, item); + AppendGListWord(&gBrowseData, fileID1); + AppendGListWord(&gBrowseData, fileID2); + AppendGListLong(&gBrowseData, startOffset - 1); + AppendGListLong(&gBrowseData, endOffset - 1); + AppendGListLong(&gBrowseData, 0); + + RecordName(&gBrowseData, str, id); + if (str2 && str2 != str) + RecordName(&gBrowseData, str2, id2); + else + AppendGListWord(&gBrowseData, 0); +} + +void CBrowse_NewTypedef(NameSpace *nspace, HashNameNode *name, CPrepFileInfo *file1, CPrepFileInfo *file2, SInt32 startOffset, SInt32 endOffset) { + CError_ASSERT(618, file1 && file1->recordbrowseinfo); + + if (file2 && file2->fileID && startOffset > 0 && endOffset >= startOffset) { + EmitStandardData(browseTypedef, + file1->fileID, file2->fileID, + startOffset, endOffset, + name->name, name->id, + CError_GetQualifiedName(nspace, name), -1); + } +} + +void CBrowse_NewEnum(NameSpace *nspace, HashNameNode *name, CPrepFileInfo *file1, CPrepFileInfo *file2, SInt32 startOffset, SInt32 endOffset) { + CError_ASSERT(632, file1 && file1->recordbrowseinfo); + + if (file2 && file2->fileID && startOffset > 0 && endOffset >= startOffset) { + EmitStandardData(browseEnum, + file1->fileID, file2->fileID, + startOffset, endOffset, + name->name, name->id, + CError_GetQualifiedName(nspace, name), -1); + } +} + +void CBrowse_NewEnumConstant(NameSpace *nspace, HashNameNode *name, CPrepFileInfo *file1, CPrepFileInfo *file2, SInt32 startOffset, SInt32 endOffset) { + CError_ASSERT(646, file1 && file1->recordbrowseinfo); + + if (tk == ',') + endOffset++; + + if (file2 && file2->fileID && startOffset > 0 && endOffset >= startOffset) { + EmitStandardData(browseConstant, + file1->fileID, file2->fileID, + startOffset, endOffset, + name->name, name->id, + CError_GetQualifiedName(nspace, name), -1); + } +} + +static HashNameNode *CBrowse_GetLinkName(Object *object) { + return CMangler_GetLinkName(object); +} + +static void RecordFunction(Object *object, int fileID1, int fileID2, SInt32 startOffset, SInt32 endOffset) { + TypeFunc *tfunc; + char *tmp; + Boolean flag; + char *str29; + HashNameNode *linkname; + SInt32 flags; + char *namestr; + SInt32 nameid; + char *namestr2; + SInt32 nameid2; + int funcid; + char buf[2048]; + char buf2[256]; + + CError_ASSERT(740, object->type && IS_TYPE_FUNC(object->type)); + + if (IsTempName(object->name)) + return; + + tfunc = TYPE_FUNC(object->type); + if ((tfunc->flags & (FUNC_AUTO_GENERATED | FUNC_INTRINSIC)) && (!fileID2 || startOffset < 0)) + return; + + linkname = object->name; + tmp = linkname->name; + if (!(linkname->name[0] == '_' && linkname->name[1] == '_')) { + namestr = tmp; + nameid = linkname->id; + switch (tmp[0]) { + case '.': + nameid = -1; + namestr += 1; + break; + case '_': + switch (tmp[1]) { + case '#': + case '%': + case '@': + nameid = -1; + namestr += 2; + break; + } + break; + } + } else { + flag = 1; + if (tfunc->flags & (FUNC_IS_CTOR | FUNC_IS_DTOR)) { + tmp = TYPE_METHOD(tfunc)->theclass->classname->name; + while (*tmp >= '0' && *tmp <= '9') + tmp++; + MWUnmangleClassName(tmp, buf, sizeof(buf)); + + str29 = buf; + if ((tmp = strrchr(str29, ':'))) + str29 = tmp + 1; + + if (tfunc->flags & FUNC_IS_DTOR) { + buf2[0] = '~'; + strncpy(&buf2[1], str29, sizeof(buf2) - 1); + namestr = buf2; + } else { + namestr = str29; + } + + flag = 0; + } + + if (flag) { + MWUnmangle(object->name->name, buf, sizeof(buf)); + namestr = buf; + } + + nameid = -1; + } + + while (*namestr >= '0' && *namestr <= '9') { + nameid = -1; + namestr++; + } + + namestr2 = NULL; + nameid2 = -1; + + linkname = CBrowse_GetLinkName(object); + if (object->name != linkname) { + namestr2 = linkname->name; + if (linkname->name[0] == '.') + namestr2++; + else + nameid2 = linkname->id; + } + + EmitStandardData(browseFunction, fileID1, fileID2, startOffset, endOffset, namestr, nameid, namestr2, nameid2); + + flags = 0; + if (object->qual & Q_INLINE) + flags |= kInline; + if (object->qual & Q_PASCAL) + flags |= kPascal; + if (object->qual & Q_ASM) + flags |= kAsm; + if (object->sclass == TK_STATIC) + flags |= kStatic; + if (tfunc->flags & FUNC_METHOD) + flags |= kMember; + AppendGListLong(&gBrowseData, flags); + + funcid = 0; + if (tfunc->flags & FUNC_METHOD) { + funcid = TYPE_METHOD(tfunc)->funcid; + if (funcid <= 0) { + TYPE_METHOD(tfunc)->funcid = funcid = gNextMemberFuncID++; + } + } + AppendGListLong(&gBrowseData, funcid); +} + +void CBrowse_NewFunction(Object *object, CPrepFileInfo *file1, CPrepFileInfo *file2, SInt32 startOffset, SInt32 endOffset) { + CError_ASSERT(890, file1 && file1->recordbrowseinfo); + + if (file2 && file2->fileID && startOffset > 0 && (endOffset + 1) >= startOffset) + RecordFunction(object, file1->fileID, file2->fileID, startOffset, endOffset + 1); +} + +void CBrowse_NewData(Object *object, CPrepFileInfo *file1, CPrepFileInfo *file2, SInt32 startOffset, SInt32 endOffset) { + char *namestr = NULL; + SInt32 flags = 0; + Boolean is_const = is_const_object(object); + + CError_ASSERT(912, file1 && file1->recordbrowseinfo); + CError_ASSERT(913, object); + + if (tk == ';') + endOffset++; + + if (file2 && file2->fileID && startOffset > 0 && endOffset >= startOffset) { + HashNameNode *name = CBrowse_GetLinkName(object); + if (object->name != name) + namestr = name->name; + + EmitStandardData( + is_const ? browseConstant : browseGlobal, + file1->fileID, file2->fileID, + startOffset, endOffset, + object->name->name, object->name->id, + namestr, name->id + ); + + if (!is_const) { + if (object->sclass == TK_STATIC) + flags |= kStatic; + AppendGListLong(&gBrowseData, flags); + } + } +} + +void CBrowse_NewMacro(Macro *macro, CPrepFileInfo *file, SInt32 startOffset, SInt32 endOffset) { + CError_ASSERT(951, !file || (file->recordbrowseinfo && !macro->is_special)); + + if (file && file->fileID && startOffset > 0 && endOffset >= startOffset) + EmitStandardData( + browseMacro, + file->fileID, file->fileID, + startOffset, endOffset, + macro->name->name, macro->name->id, + NULL, -1 + ); +} + +void CBrowse_NewTemplateClass(TemplClass *tmclass, CPrepFileInfo *file, SInt32 startOffset, SInt32 endOffset) { + CError_ASSERT(965, !file || file->recordbrowseinfo); + + if (file && file->fileID && startOffset > 0 && endOffset >= startOffset) { + EmitStandardData( + browseTemplate, + file->fileID, file->fileID, + startOffset, endOffset, + tmclass->theclass.classname->name, tmclass->theclass.classname->id, + NULL, -1 + ); + AppendGListByte(&gBrowseData, templateClass); + } +} + +void CBrowse_NewTemplateFunc(TemplateFunction *tmfunc) { + CError_ASSERT(979, !tmfunc->srcfile || tmfunc->srcfile->recordbrowseinfo); + + if (tmfunc->srcfile && tmfunc->srcfile->fileID && tmfunc->startoffset > 0 && tmfunc->endoffset >= tmfunc->startoffset) { + EmitStandardData( + browseTemplate, + tmfunc->srcfile->fileID, tmfunc->srcfile->fileID, + tmfunc->startoffset, tmfunc->endoffset, + tmfunc->name->name, tmfunc->name->id, + NULL, -1 + ); + AppendGListByte(&gBrowseData, templateFunction); + } +} + +static void RecordUndefinedMemberFunctions(void) { + int i; + int count; + Object **array; + + COS_LockHandleHi(gMemberFuncList.data); + + count = gMemberFuncList.size / sizeof(Object *); + array = (Object **) *gMemberFuncList.data; + for (i = 0; i < count; i++, array++) { + if (IS_TYPE_FUNC((*array)->type) && !(TYPE_FUNC((*array)->type)->flags & FUNC_DEFINED)) + RecordFunction(*array, 0, 0, -1, -1); + } + + COS_UnlockHandle(gMemberFuncList.data); +} diff --git a/compiler_and_linker/FrontEnd/C/CClass.c b/compiler_and_linker/FrontEnd/C/CClass.c new file mode 100644 index 0000000..fad276e --- /dev/null +++ b/compiler_and_linker/FrontEnd/C/CClass.c @@ -0,0 +1,2312 @@ +#include "compiler/CClass.h" +#include "compiler/CABI.h" +#include "compiler/CDecl.h" +#include "compiler/CError.h" +#include "compiler/CExpr.h" +#include "compiler/CInit.h" +#include "compiler/CInline.h" +#include "compiler/CMachine.h" +#include "compiler/CMangler.h" +#include "compiler/CObjC.h" +#include "compiler/CParser.h" +#include "compiler/CRTTI.h" +#include "compiler/CSOM.h" +#include "compiler/CompilerTools.h" +#include "compiler/CodeGen.h" +#include "compiler/objects.h" +#include "compiler/scopes.h" + +#ifdef __MWERKS__ +#pragma options align=mac68k +#endif +typedef struct OVClassBase { + struct OVClassBase *next; + struct OVClass *ovclass; + Boolean is_virtual; +} OVClassBase; + +typedef struct OVFunc { + struct OVFunc *next; + Object *obj; + struct OVClass *ovc8; + struct OVFunc *ovfC; + struct OVFunc *ovf10; +} OVFunc; + +typedef struct OVClass { + TypeClass *tclass; + OVFunc *vfuncs; + OVClassBase *bases; + SInt32 offset; + SInt32 voffset; + Boolean alloced_vtable; +} OVClass; + +typedef struct ThunkList { + struct ThunkList *next; + Object *thunkobj; + Object *obj; + SInt32 a; + SInt32 b; + SInt32 c; +} ThunkList; +#ifdef __MWERKS__ +#pragma options align=reset +#endif + +static TypeClass *main_class; +static ThunkList *cclass_thunklist; +static TypeClass *cclass_isbase_mostderived; +static SInt32 cclass_isbase_foundoffset; +static Boolean cclass_isambigbase; +static short cclass_founddepth; +static char *vtable_object_data; +static SInt32 vtable_data_size; +static OLinkList *vtable_object_links; +static TypeClass *cclass_vbase; +static OVClass *cclass_ovbase; +static OVClass *cclass_root; +static Object *found_pure; +static Boolean check_pures; +static Object *cclass_dominator_vobject; +static SInt32 cclass_dominator_voffset; +static Object *cclass_dominator_oobject; +static TypeClass *cclass_dominator_oclass; +static SInt32 cclass_dominator_ooffset; +static Object *cclass_dominator_eobject; + +void CClass_Init(void) { + cclass_thunklist = NULL; +} + +void CClass_GenThunks(void) { + ThunkList *list; + + for (list = cclass_thunklist; list; list = list->next) { + list->thunkobj->flags |= OBJECT_DEFINED; + CodeGen_GenVDispatchThunk(list->thunkobj, list->obj, list->a, list->b, list->c); + } +} + +static Object *CClass_ThunkObject(Object *obj, SInt32 a, SInt32 b, SInt32 c) { + Object *thunkobj; + ThunkList *list; + + CInline_ObjectAddrRef(obj); + for (list = cclass_thunklist; list; list = list->next) { + if (obj == list->obj && a == list->a && b == list->b && c == list->c) + return list->thunkobj; + } + + thunkobj = CParser_NewCompilerDefFunctionObject(); + thunkobj->name = CMangler_ThunkName(obj, a, b, c); + thunkobj->type = TYPE(&rt_func); + thunkobj->sclass = TK_EXTERN; + thunkobj->qual = Q_20000; + thunkobj->u.func.linkname = thunkobj->name; + + list = galloc(sizeof(ThunkList)); + list->thunkobj = thunkobj; + list->obj = obj; + list->a = a; + list->b = b; + list->c = c; + list->next = cclass_thunklist; + cclass_thunklist = list; + + return thunkobj; +} + +static Boolean CClass_IsZeroOffsetClass(TypeClass *a, TypeClass *b) { + while (1) { + if (a == b) + return 1; + + if (!a->bases || a->bases->is_virtual) + return 0; + + a = a->bases->base; + } +} + +static UInt8 CClass_IsCovariantResult(Type *a, UInt32 qualA, Type *b, UInt32 qualB, Boolean errorflag) { + TypeClass *tclassA; + TypeClass *tclassB; + + if ( + IS_TYPE_POINTER_ONLY(a) && + IS_TYPE_POINTER_ONLY(b) && + TPTR_QUAL(a) == TPTR_QUAL(b) && + !CParser_IsMoreCVQualified(qualB, qualA) && + IS_TYPE_CLASS(TPTR_TARGET(a)) && + IS_TYPE_CLASS(TPTR_TARGET(b)) + ) + { + tclassA = TYPE_CLASS(TPTR_TARGET(a)); + tclassB = TYPE_CLASS(TPTR_TARGET(b)); + if (tclassA == tclassB || CClass_IsBaseClass(tclassB, tclassA, NULL, errorflag, errorflag)) { + if (!CClass_IsZeroOffsetClass(tclassB, tclassA)) + return 2; + else + return 1; + } + } + + return 0; +} + +UInt8 CClass_GetOverrideKind(TypeFunc *a, TypeFunc *b, Boolean errorflag) { + if (!a->args || !b->args) + return 0; + + if ( + (a->flags & FUNC_CALL_CONV_MASK) != (b->flags & FUNC_CALL_CONV_MASK) || + !is_arglistsame(a->args->next, b->args->next) || + a->args->qual != b->args->qual + ) + return 0; + + if (!is_typesame(a->functype, b->functype)) { + switch (CClass_IsCovariantResult(a->functype, a->qual, b->functype, b->qual, errorflag)) { + case 0: + if (errorflag) + CError_Error(CErrorStr227); + return 0; + case 1: + return 1; + case 2: + return 2; + default: + CError_FATAL(225); + } + } + + return 1; +} + +Boolean CClass_IsEmpty(TypeClass *tclass) { + ClassList *base; + + if (tclass->ivars) + return 0; + + for (base = tclass->bases; base; base = base->next) { + if (!CClass_IsEmpty(base->base)) + return 0; + } + + return 1; +} + +Boolean CClass_IsNonStaticMemberFunc(TypeFunc *tfunc) { + return IS_TYPEFUNC_NONSTATIC_METHOD(tfunc) || (tfunc->flags & FUNC_FLAGS_80); +} + +Object *CClass_DefaultConstructor(TypeClass *tclass) { + NameSpaceObjectList *nsol; + Object *object; + + for (nsol = CScope_FindName(tclass->nspace, constructor_name_node); nsol; nsol = nsol->next) { + object = OBJECT(nsol->object); + if (object->otype == OT_OBJECT && IS_TYPE_FUNC(object->type)) { + if ((tclass->flags & CLASS_HAS_VBASES) && !tclass->sominfo) { + if (TYPE_FUNC(object->type)->args->next && !TYPE_FUNC(object->type)->args->next->next) + return object; + } else { + if (!TYPE_FUNC(object->type)->args->next) + return object; + } + } + } + + return NULL; +} + +Object *CClass_DummyDefaultConstructor(TypeClass *tclass) { + Object *ctor; + FuncArg *args; + NameSpaceObjectList *nsol; + HashNameNode *name; + TypeMemberFunc *tmethod; + Object *object; + ObjectList list; + + ctor = NULL; + + for (nsol = CScope_FindName(tclass->nspace, constructor_name_node); nsol; nsol = nsol->next) { + object = OBJECT(nsol->object); + if (object->otype == OT_OBJECT && IS_TYPE_FUNC(object->type)) { + CError_ASSERT(305, args = TYPE_FUNC(object->type)->args); + args = args->next; + if ((tclass->flags & CLASS_HAS_VBASES) && !tclass->sominfo) { + CError_ASSERT(309, args); + args = args->next; + } + CError_ASSERT(312, args); + + if (args->dexpr) { + if (ctor) { + list.next = NULL; + list.object = object; + CError_OverloadedFunctionError(ctor, &list); + break; + } + ctor = object; + } + } + } + + if (!ctor) { + CError_Error(CErrorStr203); + return NULL; + } + + name = GetHashNameNodeExport("__defctor"); + if ((nsol = CScope_FindName(tclass->nspace, name))) { + CError_ASSERT(339, nsol->object->otype == OT_OBJECT && IS_TYPE_FUNC(OBJECT(nsol->object)->type)); + return OBJECT(nsol->object); + } + + tmethod = galloc(sizeof(TypeMemberFunc)); + memclrw(tmethod, sizeof(TypeMemberFunc)); + + tmethod->type = TYPEFUNC; + tmethod->functype = TYPE(&void_ptr); + tmethod->flags = FUNC_METHOD; + tmethod->theclass = tclass; + CDecl_SetFuncFlags(TYPE_FUNC(tmethod), 0); + + if ((tclass->flags & CLASS_HAS_VBASES) && !tclass->sominfo) + CDecl_AddArgument(TYPE_FUNC(tmethod), TYPE(&stsignedshort)); + + CDecl_AddThisPointerArgument(TYPE_FUNC(tmethod), tclass); + + object = CParser_NewCompilerDefFunctionObject(); + object->type = TYPE(tmethod); + object->qual = Q_INLINE | Q_MANGLE_NAME; + object->nspace = tclass->nspace; + object->name = name; + + CScope_AddObject(tclass->nspace, name, OBJ_BASE(object)); + CParser_RegisterDummyCtorFunction(object, ctor); + return object; +} + +ENode *CClass_DefaultConstructorCall(TypeClass *tclass, TypeClass *b, ENode *objexpr, SInt32 varg, Boolean flag1, Boolean flag2, Boolean *errorflag) { + NameSpaceObjectList *nsol; + Object *ctor; + Object *object; + FuncArg *args; + ENodeList *argexprs; + ENode *expr; + BClassList *path; + BClassList list1; + ObjectList objlist; + BClassList list2; + short founddepth; + Boolean isambigbase; + + *errorflag = 0; + + if (!(nsol = CScope_FindName(tclass->nspace, constructor_name_node))) + return NULL; + + ctor = NULL; + do { + object = OBJECT(nsol->object); + if (object->otype == OT_OBJECT && IS_TYPE_FUNC(object->type)) { + CError_ASSERT(397, args = TYPE_FUNC(object->type)->args); + + args = args->next; + + if ((tclass->flags & CLASS_HAS_VBASES) && !tclass->sominfo) { + CError_ASSERT(401, args); + args = args->next; + } + + if (!args || args->dexpr) { + if (ctor) { + objlist.next = NULL; + objlist.object = object; + CError_OverloadedFunctionError(ctor, &objlist); + break; + } + ctor = object; + } + } + } while ((nsol = nsol->next)); + + if (!ctor) { + *errorflag = 1; + return NULL; + } + + if (flag1) { + if (b) { + if (flag2) { + if ((path = CClass_GetBasePath(b, tclass, &founddepth, &isambigbase))) + list1 = *path; + else + goto skipCheck; + } else { + list1.next = &list2; + list1.type = TYPE(b); + list2.next = NULL; + list2.type = TYPE(tclass); + } + } else { + list1.next = NULL; + list1.type = TYPE(tclass); + } + CClass_CheckPathAccess(&list1, ctor, ctor->access); + } + +skipCheck: + if ((tclass->flags & CLASS_HAS_VBASES) && !tclass->sominfo) { + argexprs = lalloc(sizeof(ENodeList)); + argexprs->next = NULL; + argexprs->node = intconstnode(TYPE(&stsignedshort), varg); + } else { + argexprs = NULL; + } + + CError_ASSERT(471, IS_TYPE_POINTER_ONLY(objexpr->rtype)); + + objexpr = makemonadicnode(objexpr, EINDIRECT); + objexpr->rtype = TYPE(tclass); + + list1.next = NULL; + list1.type = TYPE(tclass); + + expr = CExpr_GenericFuncCall( + &list1, + objexpr, + 0, + ctor, + NULL, + NULL, + argexprs, + 0, + 0, + 0 + ); + + if (ENODE_IS2(expr, EFUNCCALL, EFUNCCALLP)) + expr->rtype = CDecl_NewPointerType(TYPE(tclass)); + + return expr; +} + +Object *CClass_AssignmentOperator(TypeClass *tclass) { + NameSpaceObjectList *nsol; + Object *object; + + for (nsol = CScope_FindName(tclass->nspace, asop_name_node); nsol; nsol = nsol->next) { + object = OBJECT(nsol->object); + if ( + object->otype == OT_OBJECT && + IS_TYPE_FUNC(object->type) && + TYPE_FUNC(object->type)->args && + TYPE_FUNC(object->type)->args->next && + !TYPE_FUNC(object->type)->args->next->next + ) + { + if ( + IS_TYPE_CLASS(TYPE_FUNC(object->type)->args->next->type) && + TYPE_CLASS(TYPE_FUNC(object->type)->args->next->type) == tclass + ) + return object; + + if ( + IS_TYPE_REFERENCE(TYPE_FUNC(object->type)->args->next->type) && + TPTR_TARGET(TYPE_FUNC(object->type)->args->next->type) == TYPE(tclass) + ) + return object; + } + } + + return NULL; +} + +Object *CClass_CopyConstructor(TypeClass *tclass) { + NameSpaceObjectList *nsol; + Object *object; + FuncArg *args; + + if (tclass->sominfo) + return NULL; + + for (nsol = CScope_FindName(tclass->nspace, constructor_name_node); nsol; nsol = nsol->next) { + object = OBJECT(nsol->object); + if (object->otype == OT_OBJECT && IS_TYPE_FUNC(object->type)) { + CError_ASSERT(532, args = TYPE_FUNC(object->type)->args); + + args = args->next; + + if (tclass->flags & CLASS_HAS_VBASES) { + CError_ASSERT(536, args); + args = args->next; + } + + if ( + args && + args != &elipsis && + (!args->next || args->next->dexpr) && + IS_TYPE_REFERENCE(args->type) && + TPTR_TARGET(args->type) == TYPE(tclass) + ) + return object; + } + } + + return NULL; +} + +NameSpaceObjectList *CClass_MemberObject(TypeClass *tclass, HashNameNode *name) { + NameSpaceObjectList *nsol; + + if ((nsol = CScope_FindName(tclass->nspace, name)) && nsol->object->otype == OT_OBJECT) + return nsol; + + return NULL; +} + +NameSpaceObjectList *CClass_Constructor(TypeClass *tclass) { + NameSpaceObjectList *nsol; + + if ( + (nsol = CScope_FindName(tclass->nspace, constructor_name_node)) && + nsol->object->otype == OT_OBJECT && + IS_TYPE_FUNC(OBJECT(nsol->object)->type) + ) + return nsol; + + return NULL; +} + +Object *CClass_Destructor(TypeClass *tclass) { + NameSpaceObjectList *nsol; + + for (nsol = CScope_FindName(tclass->nspace, destructor_name_node); nsol; nsol = nsol->next) { + if ( + nsol->object->otype == OT_OBJECT && + IS_TYPE_FUNC(OBJECT(nsol->object)->type) + ) + return OBJECT(nsol->object); + } + + return NULL; +} + +Boolean CClass_IsConstructor(Object *obj) { + return obj && IS_TYPE_FUNC(obj->type) && (TYPE_FUNC(obj->type)->flags & FUNC_IS_CTOR); +} + +Boolean CClass_IsDestructor(Object *obj) { + return obj && IS_TYPE_FUNC(obj->type) && (TYPE_FUNC(obj->type)->flags & FUNC_IS_DTOR); +} + +Boolean CClass_IsPODClass(TypeClass *tclass) { + NameSpaceObjectList *nsol; + Object *object; + ObjMemberVar *ivar; + Type *type; + + if (tclass->vtable || tclass->bases || CClass_Destructor(tclass)) + return 0; + + for (nsol = CClass_Constructor(tclass); nsol; nsol = nsol->next) { + if ( + nsol->object->otype == OT_OBJECT && + IS_TYPE_FUNC(OBJECT(nsol->object)->type) && + !(TYPE_FUNC(OBJECT(nsol->object)->type)->flags & FUNC_AUTO_GENERATED) + ) + return 0; + } + + object = CClass_AssignmentOperator(tclass); + if (object && !(TYPE_FUNC(object->type)->flags & FUNC_AUTO_GENERATED)) + return 0; + + for (ivar = tclass->ivars; ivar; ivar = ivar->next) { + if (ivar->access != ACCESSPUBLIC) + return 0; + + type = ivar->type; + while (IS_TYPE_ARRAY(type)) + type = TPTR_TARGET(type); + + switch (type->type) { + case TYPECLASS: + if (!CClass_IsPODClass(TYPE_CLASS(type))) + return 0; + break; + case TYPEMEMBERPOINTER: + return 0; + case TYPEPOINTER: + if (TPTR_QUAL(type) & Q_REFERENCE) + return 0; + break; + } + } + + return 1; +} + +Boolean CClass_IsTrivialCopyClass(TypeClass *tclass) { + Object *object; + ClassList *base; + ObjMemberVar *ivar; + Type *type; + + if (tclass->vtable || tclass->vbases || CClass_Destructor(tclass)) + return 0; + + object = CClass_CopyConstructor(tclass); + if (object && IS_TYPE_FUNC(object->type) && !(TYPE_FUNC(object->type)->flags & FUNC_AUTO_GENERATED)) + return 0; + + for (base = tclass->bases; base; base = base->next) { + if (!CClass_IsTrivialCopyClass(base->base)) + return 0; + } + + for (ivar = tclass->ivars; ivar; ivar = ivar->next) { + type = ivar->type; + while (IS_TYPE_ARRAY(type)) + type = TPTR_TARGET(type); + + if (IS_TYPE_CLASS(type) && !CClass_IsTrivialCopyClass(TYPE_CLASS(type))) + return 0; + } + + return 1; +} + +Boolean CClass_IsTrivialCopyAssignClass(TypeClass *tclass) { + Object *object; + ObjMemberVar *ivar; + Type *type; + + if (tclass->vtable || tclass->bases || CClass_Destructor(tclass)) + return 0; + + object = CClass_AssignmentOperator(tclass); + if (object && !(TYPE_FUNC(object->type)->flags & FUNC_AUTO_GENERATED)) + return 0; + + for (ivar = tclass->ivars; ivar; ivar = ivar->next) { + type = ivar->type; + while (IS_TYPE_ARRAY(type)) + type = TPTR_TARGET(type); + + if (IS_TYPE_REFERENCE(type)) + return 0; + if (CParser_IsConst(type, ivar->qual)) + return 0; + if (IS_TYPE_CLASS(type) && !CClass_IsTrivialCopyAssignClass(TYPE_CLASS(type))) + return 0; + } + + return 1; +} + +Boolean CClass_ReferenceArgument(TypeClass *tclass) { + if ((tclass->flags & (CLASS_COMPLETED | CLASS_IS_TEMPL_INST)) == CLASS_IS_TEMPL_INST) + CDecl_CompleteType(TYPE(tclass)); + + if (copts.simple_class_byval) + return !CClass_IsTrivialCopyClass(tclass); + + return CClass_Destructor(tclass) || CClass_CopyConstructor(tclass); +} + +BClassList *CClass_GetPathCopy(BClassList *path, Boolean is_global) { + BClassList *last; + BClassList *copy; + + if (!path) + return NULL; + + copy = last = is_global ? galloc(sizeof(BClassList)) : lalloc(sizeof(BClassList)); + last->next = path->next; + last->type = path->type; + + while ((path = path->next)) { + last->next = is_global ? galloc(sizeof(BClassList)) : lalloc(sizeof(BClassList)); + last = last->next; + last->next = path->next; + last->type = path->type; + } + + return copy; +} + +BClassList *CClass_AppendPath(BClassList *dest, BClassList *src) { + BClassList *last; + + if (!(last = dest)) + return src; + + while (last->next) + last = last->next; + + while (src && src->type == last->type) + src = src->next; + + last->next = src; + return dest; +} + +static AccessType CClass_GetPathAccess(BClassList *path) { + AccessType result; + ClassList *base; + TypeClass *tclass; + + CError_ASSERT(930, path); + + result = ACCESSPUBLIC; + + while (1) { + tclass = TYPE_CLASS(path->type); + if (!(path = path->next)) + break; + + for (base = tclass->bases; base; base = base->next) { + if (base->base == TYPE_CLASS(path->type)) + break; + } + + CError_ASSERT(939, base); + + switch (base->access) { + case ACCESSPUBLIC: + break; + case ACCESSPROTECTED: + if (result == ACCESSPUBLIC) + result = ACCESSPROTECTED; + break; + case ACCESSPRIVATE: + if (result == ACCESSPUBLIC || result == ACCESSPROTECTED) + result = ACCESSPRIVATE; + else + return ACCESSNONE; + break; + case ACCESSNONE: + return ACCESSNONE; + default: + CError_FATAL(960); + } + } + + return result; +} + +Boolean CClass_IsMoreAccessiblePath(BClassList *path1, BClassList *path2) { + switch (CClass_GetPathAccess(path2)) { + case ACCESSPUBLIC: + return 0; + case ACCESSNONE: + return 1; + default: + CError_FATAL(978); + case ACCESSPROTECTED: + switch (CClass_GetPathAccess(path1)) { + case ACCESSPUBLIC: + return 1; + case ACCESSPRIVATE: + case ACCESSPROTECTED: + case ACCESSNONE: + return 0; + default: + CError_FATAL(987); + } + case ACCESSPRIVATE: + switch (CClass_GetPathAccess(path1)) { + case ACCESSPUBLIC: + case ACCESSPROTECTED: + return 1; + case ACCESSPRIVATE: + case ACCESSNONE: + return 0; + default: + CError_FATAL(997); + } + } + + return 0; +} + +static BClassList *CClass_GetBasePathRec(TypeClass *a, TypeClass *b, SInt32 offset, short depth) { + ClassList *base; + BClassList *checkpath; + BClassList *bestpath; + BClassList *newpath; + SInt32 newOffset; + + for (base = a->bases, bestpath = NULL; base; base = base->next) { + if (base->is_virtual) + newOffset = CClass_VirtualBaseOffset(cclass_isbase_mostderived, base->base); + else + newOffset = offset + base->offset; + + if (base->base == b) { + if (cclass_founddepth && newOffset != cclass_isbase_foundoffset) { + cclass_isambigbase = 1; + return NULL; + } + + cclass_isbase_foundoffset = newOffset; + cclass_founddepth = depth; + + bestpath = lalloc(sizeof(BClassList)); + bestpath->next = NULL; + bestpath->type = TYPE(b); + } else if ((checkpath = CClass_GetBasePathRec(base->base, b, newOffset, depth + 1))) { + newpath = lalloc(sizeof(BClassList)); + newpath->next = checkpath; + newpath->type = TYPE(base->base); + if (!bestpath || CClass_IsMoreAccessiblePath(newpath, bestpath)) + bestpath = newpath; + } + } + + return bestpath; +} + +BClassList *CClass_GetBasePath(TypeClass *a, TypeClass *b, short *founddepth, Boolean *isambigbase) { + BClassList *path; + BClassList *result; + + if ((a->flags & (CLASS_COMPLETED | CLASS_IS_TEMPL_INST)) == CLASS_IS_TEMPL_INST) + CDecl_CompleteType(TYPE(a)); + if ((b->flags & (CLASS_COMPLETED | CLASS_IS_TEMPL_INST)) == CLASS_IS_TEMPL_INST) + CDecl_CompleteType(TYPE(b)); + + cclass_founddepth = 0; + cclass_isbase_mostderived = a; + cclass_isbase_foundoffset = -1; + cclass_isambigbase = 0; + + if ((path = CClass_GetBasePathRec(a, b, 0, 1))) { + *founddepth = cclass_founddepth; + *isambigbase = cclass_isambigbase; + + result = lalloc(sizeof(BClassList)); + result->next = path; + result->type = TYPE(a); + return result; + } else { + *isambigbase = 0; + return NULL; + } +} + +Boolean CClass_IsBaseClass(TypeClass *a, TypeClass *b, short *founddepth, Boolean pathcheckflag, Boolean ambigerrorflag) { + BClassList *path; + short depth; + Boolean isambigbase; + + if ((path = CClass_GetBasePath(a, b, &depth, &isambigbase))) { + if (isambigbase && ambigerrorflag) + CError_Error(CErrorStr188); + + if (pathcheckflag) + CClass_CheckPathAccess(path, NULL, ACCESSPUBLIC); + + if (founddepth) + *founddepth = depth; + + return 1; + } + + return 0; +} + +TypeClass *CClass_GetQualifiedClass(void) { + DeclInfo di; + + memclrw(&di, sizeof(di)); + CParser_GetDeclSpecs(&di, 0); + + if (IS_TYPE_CLASS(di.thetype)) + return TYPE_CLASS(di.thetype); + + return NULL; +} + +ENode *CClass_AccessPathCast(BClassList *path, ENode *expr, Boolean reverse) { + ClassList *base; + SInt32 offset; + + while (path && path->next) { + base = TYPE_CLASS(path->type)->bases; + while (1) { + if (base->base == TYPE_CLASS(path->next->type)) + break; + CError_ASSERT(1157, base = base->next); + } + + if (base->is_virtual) { + if (reverse) { + CError_Error(CErrorStr164); + break; + } + + if (!base->base->sominfo) { + offset = base->offset; + if (offset && !canadd(expr, offset)) { + expr = makediadicnode(expr, intconstnode(TYPE(&stunsignedlong), offset), EADD); + optimizecomm(expr); + } + + expr->rtype = CDecl_NewPointerType(CDecl_NewPointerType(TYPE(base->base))); + expr = makemonadicnode(expr, EINDIRECT); + expr->rtype = expr->data.monadic->rtype; + } + } else { + offset = base->offset; + if (offset) { + if (reverse) + offset = -offset; + if (!canadd(expr, offset)) { + expr = makediadicnode(expr, intconstnode(TYPE(&stunsignedlong), offset), EADD); + optimizecomm(expr); + } + } + } + + path = path->next; + } + + return expr; +} + +ENode *CClass_ClassPointerCast(ENode *expr, TypeClass *a, TypeClass *b, Boolean typconflag, Boolean ambigerrorflag, Boolean pathcheckflag) { + BClassList *path; + Boolean reverse; + short depth; + Boolean isambigbase; + + reverse = 0; + + if (a != b) { + if (!(path = CClass_GetBasePath(a, b, &depth, &isambigbase))) { + CError_ASSERT(1216, typconflag); + if ((path = CClass_GetBasePath(b, a, &depth, &isambigbase))) { + reverse = 1; + goto doCast; + } + } else { + doCast: + if (isambigbase && ambigerrorflag) + CError_Error(CErrorStr188); + if (pathcheckflag) + CClass_CheckPathAccess(path, NULL, ACCESSPUBLIC); + if (!(a->flags & CLASS_SINGLE_OBJECT) && !b->sominfo) + expr = CClass_AccessPathCast(path, expr, reverse); + } + } + + if (typconflag && ENODE_IS(expr, EINDIRECT) && IS_TYPE_POINTER_ONLY(expr->rtype)) + expr = makemonadicnode(expr, ETYPCON); + + return expr; +} + +ENode *CClass_DirectBasePointerCast(ENode *expr, TypeClass *a, TypeClass *b) { + ClassList *base; + VClassList *vbase; + BClassList *path; + BClassList list1; + BClassList list2; + short depth; + Boolean isambigbase; + + for (base = a->bases; base; base = base->next) { + if (base->base == b) { + list1.next = &list2; + list1.type = TYPE(a); + list2.next = NULL; + list2.type = TYPE(b); + return CClass_AccessPathCast(&list1, expr, 0); + } + } + + for (vbase = a->vbases; vbase; vbase = vbase->next) { + if (vbase->base == b) { + CError_ASSERT(1273, path = CClass_GetBasePath(a, b, &depth, &isambigbase)); + return CClass_AccessPathCast(path, expr, 0); + } + } + + CError_FATAL(1277); + return expr; +} + +SInt32 CClass_GetPathOffset(BClassList *path) { + SInt32 offset; + ClassList *base; + + offset = 0; + + while (path->next) { + if (path->type != path->next->type) { + for (base = TYPE_CLASS(path->type)->bases; base; base = base->next) { + if (base->base == TYPE_CLASS(path->next->type)) + break; + } + + if (!base) { + CError_Error(CErrorStr221); + return offset; + } + } + + if (base->is_virtual) + return -1; + offset += base->offset; + + path = path->next; + } + + return offset; +} + +Boolean CClass_ClassDominates(TypeClass *tclass, TypeClass *baseclass) { + ClassList *base; + + for (base = tclass->bases; base; base = base->next) { + if (base->base == baseclass || CClass_ClassDominates(base->base, baseclass)) + return 1; + } + + return 0; +} + +SInt32 CClass_VirtualBaseOffset(TypeClass *tclass, TypeClass *baseclass) { + VClassList *vbase; + + for (vbase = tclass->vbases; vbase; vbase = vbase->next) { + if (vbase->base == baseclass) + return vbase->offset; + } + + CError_FATAL(1342); + return 0; +} + +SInt32 CClass_VirtualBaseVTableOffset(TypeClass *tclass, TypeClass *baseclass) { + VClassList *vbase; + + for (vbase = tclass->vbases; vbase; vbase = vbase->next) { + if (vbase->base == baseclass) + return vbase->voffset; + } + + CError_FATAL(1359); + return 0; +} + +SInt32 CClass_GetMemberOffset(TypeClass *tclass, HashNameNode *name, ObjMemberVar **resultIvar) { + ObjMemberVar *ivar; + ClassList *base; + SInt32 offset; + SInt32 tmp; + Boolean foundflag; + + for (ivar = tclass->ivars; ivar; ivar = ivar->next) { + if (ivar->name == name) { + if (resultIvar) + *resultIvar = ivar; + return ivar->offset; + } + } + + for (base = tclass->bases, foundflag = 0; base; base = base->next) { + switch ((tmp = CClass_GetMemberOffset(base->base, name, resultIvar))) { + case -3: + case -2: + return tmp; + case -1: + break; + default: + if (base->is_virtual) + return -3; + if (foundflag) + return -2; + foundflag = 1; + offset = base->offset + tmp; + } + } + + return foundflag ? offset : -1; +} + +Boolean CClass_OverridesBaseMember(TypeClass *tclass, HashNameNode *name, Object *obj) { + NameSpaceObjectList *nsol; + ClassList *base; + Boolean result; + + result = 0; + for (base = tclass->bases; base; base = base->next) { + if (base->base->vtable) { + for (nsol = CScope_FindName(base->base->nspace, name); nsol; nsol = nsol->next) { + if ( + nsol->object->otype == OT_OBJECT && + OBJECT(nsol->object)->datatype == DVFUNC && + CClass_GetOverrideKind(TYPE_FUNC(OBJECT(nsol->object)->type), TYPE_FUNC(obj->type), 1) + ) + result = 1; + } + + if (CClass_OverridesBaseMember(base->base, name, obj)) + result = 1; + } + } + + return result; +} + +static OVClass *CClass_FindOVClass(OVClass *ovclass, TypeClass *tclass, SInt32 offset) { + OVClassBase *ovbase; + + if (ovclass->tclass == tclass && ovclass->offset == offset) + return ovclass; + + for (ovbase = ovclass->bases; ovbase; ovbase = ovbase->next) { + if ((ovclass = CClass_FindOVClass(ovbase->ovclass, tclass, offset))) + return ovclass; + } + + return NULL; +} + +static OVClass *CClass_BuildOVClassTree(OVClass *root, TypeClass *tclass, SInt32 offset, SInt32 voffset) { + ClassList *base; + Object *object; + OVClass *tree; + OVFunc *ovfunc; + OVClassBase *ovbase; + SInt32 vboffset; + SInt32 vbvoffset; + CScopeObjectIterator iter; + + tree = lalloc(sizeof(OVClass)); + memclrw(tree, sizeof(OVClass)); + + tree->tclass = tclass; + tree->offset = offset; + tree->voffset = voffset; + if (!root) + root = tree; + + CScope_InitObjectIterator(&iter, tclass->nspace); + while (1) { + if (!(object = OBJECT(CScope_NextObjectIteratorObject(&iter)))) + break; + + if (object->datatype == DVFUNC) { + ovfunc = lalloc(sizeof(OVFunc)); + memclrw(ovfunc, sizeof(OVFunc)); + + ovfunc->next = tree->vfuncs; + ovfunc->obj = object; + tree->vfuncs = ovfunc; + } + } + + for (base = tclass->bases; base; base = base->next) { + if (base->base->vtable || base->base->sominfo) { + ovbase = lalloc(sizeof(OVClassBase)); + memclrw(ovbase, sizeof(OVClassBase)); + + if (base->is_virtual) { + vboffset = CClass_VirtualBaseOffset(main_class, base->base); + if (!(ovbase->ovclass = CClass_FindOVClass(root, base->base, vboffset))) { + vbvoffset = CClass_VirtualBaseVTableOffset(main_class, base->base); + ovbase->ovclass = CClass_BuildOVClassTree(root, base->base, vboffset, vbvoffset); + } + ovbase->is_virtual = 1; + } else { + ovbase->ovclass = CClass_BuildOVClassTree( + root, + base->base, + offset + base->offset, + voffset + base->voffset); + ovbase->is_virtual = 0; + } + + ovbase->next = tree->bases; + tree->bases = ovbase; + } + } + + return tree; +} + +static Boolean CClass_IsBaseOf(OVClass *a, OVClass *b) { + OVClassBase *ovbase; + + for (ovbase = b->bases; ovbase; ovbase = ovbase->next) { + if ( + (ovbase->ovclass->tclass == a->tclass && ovbase->ovclass->offset == a->offset) || + CClass_IsBaseOf(a, ovbase->ovclass) + ) + { + if (!cclass_ovbase && ovbase->is_virtual) + cclass_ovbase = ovbase->ovclass; + return 1; + } + } + + return 0; +} + +static void CClass_FindOVFunc(OVClass *a, OVClass *b, OVFunc *func) { + OVFunc *scan; + OVClassBase *ovbase; + UInt8 overrideKind; + + if (CClass_IsBaseOf(b, a)) { + for (scan = a->vfuncs; scan; scan = scan->next) { + if ( + (func->obj->name == scan->obj->name) && + (overrideKind = CClass_GetOverrideKind(TYPE_FUNC(func->obj->type), TYPE_FUNC(scan->obj->type), 0)) + ) + { + if (func->ovc8) { + if (func->ovc8->tclass == a->tclass || CClass_ClassDominates(func->ovc8->tclass, a->tclass)) + return; + if (!CClass_ClassDominates(a->tclass, func->ovc8->tclass)) { + func->ovf10 = scan; + return; + } + } + + if (a == cclass_root) { + TYPE_FUNC(scan->obj->type)->flags |= FUNC_FLAGS_20; + if (overrideKind == 2) + TYPE_FUNC(scan->obj->type)->flags |= FUNC_FLAGS_400000; + } + + func->ovc8 = a; + func->ovfC = scan; + func->ovf10 = NULL; + return; + } + } + + for (ovbase = a->bases; ovbase; ovbase = ovbase->next) + CClass_FindOVFunc(ovbase->ovclass, b, func); + } +} + +static TypeList *CClass_GetCoVariantClassList(TypeList *list, TypeClass *tclass, Object *func, Boolean flag) { + Object *object; + TypeList *scan; + Type *type; + ClassList *base; + CScopeObjectIterator iter; + + if (!flag) { + CScope_InitObjectIterator(&iter, tclass->nspace); + while (1) { + if (!(object = OBJECT(CScope_NextObjectIteratorObject(&iter)))) + break; + + if ( + object->name == func->name && + object->datatype == DVFUNC && + CClass_GetOverrideKind(TYPE_FUNC(object->type), TYPE_FUNC(func->type), 0) == 2 + ) + { + CError_ASSERT(1686, + IS_TYPE_POINTER_ONLY(TYPE_FUNC(object->type)->functype) && + IS_TYPE_CLASS(TPTR_TARGET(TYPE_FUNC(object->type)->functype))); + + type = TPTR_TARGET(TYPE_FUNC(object->type)->functype); + for (scan = list; scan; scan = scan->next) { + if (scan->type == type) + break; + } + + if (!scan) { + scan = lalloc(sizeof(TypeList)); + scan->type = type; + scan->next = list; + list = scan; + } + } + } + } + + for (base = tclass->bases; base; base = base->next) { + if (base->base->vtable) + list = CClass_GetCoVariantClassList(list, base->base, func, 0); + } + + return list; +} + +static TypeMemberFunc *CClass_GetCovariantType(TypeMemberFunc *tmethod, Type *type) { + TypePointer *tptr; + TypeMemberFunc *result; + + CError_ASSERT(1724, + IS_TYPE_METHOD(tmethod) && + IS_TYPE_POINTER_ONLY(tmethod->functype)); + + tptr = galloc(sizeof(TypePointer)); + *tptr = *TYPE_POINTER(tmethod->functype); + tptr->target = type; + + result = galloc(sizeof(TypeMemberFunc)); + *result = *tmethod; + result->flags &= ~(FUNC_FLAGS_20 | FUNC_FLAGS_400000); + result->functype = TYPE(tptr); + return result; +} + +static Object *CClass_FindCovariantFunction(Object *func, Type *type) { + NameSpaceObjectList *nsol; + + nsol = CScope_FindName( + TYPE_METHOD(func->type)->theclass->nspace, + CMangler_GetCovariantFunctionName(func, TYPE_CLASS(type))); + + CError_ASSERT(1754, nsol && !nsol->next && nsol->object->otype == OT_OBJECT); + + return OBJECT(nsol->object); +} + +static ObjectList *CClass_DeclareCovariantFuncs(ObjectList *list, Object *func, TypeClass *tclass) { + Object *newfunc; + HashNameNode *name; + TypeList *types; + ObjectList *newlist; + + for (types = CClass_GetCoVariantClassList(NULL, tclass, func, 1); types; types = types->next) { + name = CMangler_GetCovariantFunctionName(func, TYPE_CLASS(types->type)); + + newfunc = galloc(sizeof(Object)); + memclrw(newfunc, sizeof(Object)); + + newfunc->otype = OT_OBJECT; + newfunc->datatype = DFUNC; + newfunc->section = func->section; + newfunc->nspace = func->nspace; + newfunc->name = name; + newfunc->type = TYPE(CClass_GetCovariantType(TYPE_METHOD(func->type), types->type)); + newfunc->qual = func->qual & ~Q_INLINE; + newfunc->sclass = func->sclass; + newfunc->u.func.linkname = name; + + newlist = lalloc(sizeof(ObjectList)); + newlist->object = newfunc; + newlist->next = list; + list = newlist; + } + + return list; +} + +void CClass_DefineCovariantFuncs(Object *method, CI_FuncData *ifuncdata) { + NameSpace *nspace; + TypeList *types; + Object *covariantFunc; + Statement *stmt; + Type *tptr; + Statement firstStmt; + + for (types = CClass_GetCoVariantClassList(NULL, TYPE_METHOD(method->type)->theclass, method, 1); types; types = types->next) { + covariantFunc = CClass_FindCovariantFunction(method, types->type); + tptr = CDecl_NewPointerType(types->type); + + nspace = CFunc_FuncGenSetup(&firstStmt, covariantFunc); + CInline_UnpackIFunctionData(covariantFunc, ifuncdata, &firstStmt); + + for (stmt = &firstStmt; stmt; stmt = stmt->next) { + if (stmt->type == ST_RETURN && stmt->expr) + stmt->expr = CExpr_AssignmentPromotion(stmt->expr, tptr, ENODE_QUALS(stmt->expr), 0); + } + + CFunc_Gen(&firstStmt, covariantFunc, 0); + cscope_current = nspace->parent; + } +} + +static void CClass_OverrideOVClassTree(OVClass *ovclass) { + OVClassBase *ovbase; + OVFunc *ovfunc; + + if (cclass_root != ovclass) { + for (ovfunc = ovclass->vfuncs; ovfunc; ovfunc = ovfunc->next) + CClass_FindOVFunc(cclass_root, ovclass, ovfunc); + } + + for (ovbase = ovclass->bases; ovbase; ovbase = ovbase->next) + CClass_OverrideOVClassTree(ovbase->ovclass); +} + +static void CClass_AllocVTableRec(OVClass *ovclass) { + OVFunc *ovfunc; + Object *object; + SInt32 offset27; + SInt32 offset26; + SInt32 offset23; + OVClassBase *ovbase; + OLinkList *link; + + if (ovclass->alloced_vtable) + return; + + for (ovfunc = ovclass->vfuncs; ovfunc; ovfunc = ovfunc->next) { + offset27 = ovclass->voffset + TYPE_METHOD(ovfunc->obj->type)->vtbl_index + CABI_GetVTableOffset(ovclass->tclass); + CError_ASSERT(1867, offset27 < vtable_data_size); + + if (!(vtable_object_data[offset27])) { + if (ovfunc->ovfC) { + object = ovfunc->ovfC->obj; + if ( + (TYPE_FUNC(object->type)->flags & FUNC_FLAGS_400000) && + CClass_GetOverrideKind(TYPE_FUNC(ovfunc->obj->type), TYPE_FUNC(object->type), 0) == 2 + ) + { + CError_ASSERT(1887, + IS_TYPE_POINTER_ONLY(TYPE_FUNC(ovfunc->obj->type)->functype) && + IS_TYPE_CLASS(TPTR_TARGET(TYPE_FUNC(ovfunc->obj->type)->functype))); + object = CClass_FindCovariantFunction( + object, + TPTR_TARGET(TYPE_FUNC(ovfunc->obj->type)->functype)); + } + + if ((offset26 = ovfunc->ovc8->offset - ovclass->offset)) { + if (!(TYPE_FUNC(object->type)->flags & FUNC_PURE)) { + cclass_ovbase = NULL; + CError_ASSERT(1899, CClass_IsBaseOf(ovclass, ovfunc->ovc8)); + + if (cclass_ovbase && (main_class->flags & CLASS_FLAGS_8000)) { + offset23 = ovclass->offset - cclass_ovbase->offset; + offset23 = CABI_GetCtorOffsetOffset(cclass_ovbase->tclass, NULL) - offset23; + CError_ASSERT(1906, offset23 > 0); + object = CClass_ThunkObject(object, offset26, 0, offset23); + } else { + object = CClass_ThunkObject(object, offset26, 0, -1); + } + } + } + } else { + object = ovfunc->obj; + } + + if (!(TYPE_FUNC(object->type)->flags & FUNC_PURE)) { + link = lalloc(sizeof(OLinkList)); + link->next = vtable_object_links; + link->obj = object; + link->offset = offset27; + link->somevalue = 0; + vtable_object_links = link; + vtable_object_data[offset27] = 1; + } + } + } + + ovclass->alloced_vtable = 1; + + for (ovbase = ovclass->bases; ovbase; ovbase = ovbase->next) + CClass_AllocVTableRec(ovbase->ovclass); +} + +static Object *CClass_CheckClass(OVClass *ovclass, Boolean errorflag) { + Object *object; + Object *check; + OVFunc *ovfunc; + OVClassBase *ovbase; + + object = NULL; + + for (ovfunc = ovclass->vfuncs; ovfunc; ovfunc = ovfunc->next) { + if (ovfunc->ovf10 && errorflag) + CError_Error(CErrorStr251, main_class, 0, ovfunc->obj, ovfunc->ovfC->obj, ovfunc->ovf10->obj); + + if (!object) { + check = ovfunc->ovfC ? ovfunc->ovfC->obj : ovfunc->obj; + if (TYPE_FUNC(check->type)->flags & FUNC_PURE) + object = check; + } + } + + for (ovbase = ovclass->bases; ovbase; ovbase = ovbase->next) { + if (object) + CClass_CheckClass(ovbase->ovclass, errorflag); + else + object = CClass_CheckClass(ovbase->ovclass, errorflag); + } + + return object; +} + +static void CClass_AllocVTable(TypeClass *tclass) { + OVClass *ovclass; + + main_class = tclass; + ovclass = CClass_BuildOVClassTree(NULL, tclass, 0, 0); + cclass_root = ovclass; + CClass_OverrideOVClassTree(ovclass); + CClass_CheckClass(ovclass, 1); + CClass_AllocVTableRec(ovclass); +} + +static Object *CClass_CheckVirtuals(TypeClass *tclass) { + OVClass *ovclass; + + main_class = tclass; + ovclass = CClass_BuildOVClassTree(NULL, tclass, 0, 0); + cclass_root = ovclass; + CClass_OverrideOVClassTree(ovclass); + return CClass_CheckClass(ovclass, 0); +} + +static void CClass_CheckVirtualBaseOverrides(OVClass *a, OVClass *b, Boolean flag) { + VClassList *vbase; + OVFunc *ovfunc; + OVClassBase *ovbase; + + if (flag) { + for (ovfunc = b->vfuncs; ovfunc; ovfunc = ovfunc->next) { + if (ovfunc->ovfC) { + cclass_ovbase = NULL; + CError_ASSERT(2040, CClass_IsBaseOf(b, ovfunc->ovc8)); + + if (cclass_ovbase) { + for (vbase = a->tclass->vbases; vbase; vbase = vbase->next) { + if (vbase->base == cclass_ovbase->tclass) + break; + } + + CError_ASSERT(2047, vbase); + vbase->has_override = 1; + } + } + } + } + + for (ovbase = b->bases; ovbase; ovbase = ovbase->next) { + CClass_CheckVirtualBaseOverrides(a, ovbase->ovclass, flag || ovbase->is_virtual); + } +} + +static void CClass_CheckHideVirtual(OVClass *a, OVClass *b) { + OVClassBase *ovbase; + OVFunc *ovfunc; + Object *foundObject; + Boolean isAlias; + Object *object; + CScopeObjectIterator iter; + + if (a != b) { + for (ovfunc = b->vfuncs; ovfunc; ovfunc = ovfunc->next) { + if (ovfunc->ovc8 != a) { + foundObject = NULL; + isAlias = 0; + CScope_InitObjectIterator(&iter, a->tclass->nspace); + + while (1) { + if (!(object = OBJECT(CScope_NextObjectIteratorObject(&iter)))) + break; + + if (object->name == ovfunc->obj->name && IS_TYPE_FUNC(object->type)) { + if (object->datatype != DALIAS) { + if (!(TYPE_FUNC(object->type)->flags & FUNC_FLAGS_20)) + foundObject = object; + } else { + if (object->u.alias.object == ovfunc->obj) { + // don't show a warning if this is just an alias to the base function + isAlias = 1; + break; + } + } + } + } + + if (foundObject && !isAlias) + CError_Warning(CErrorStr225, foundObject, ovfunc->obj); + } + } + } + + for (ovbase = b->bases; ovbase; ovbase = ovbase->next) + CClass_CheckHideVirtual(a, ovbase->ovclass); +} + +void CClass_CheckOverrides(TypeClass *tclass) { + OVClass *tree; + Object *object; + ObjectList *objlist; + ClassList *base; + VClassList *vbase; + int i; + CScopeObjectIterator iter; + + i = 0; + for (base = tclass->bases; base; base = base->next) { + base->offset = i; + base->voffset = i; + i++; + } + for (vbase = tclass->vbases; vbase; vbase = vbase->next) { + vbase->offset = i; + vbase->voffset = i; + i++; + } + + main_class = tclass; + tree = CClass_BuildOVClassTree(NULL, tclass, 0, 0); + cclass_root = tree; + + CClass_OverrideOVClassTree(tree); + if (CClass_CheckClass(tree, 0)) + tclass->flags |= CLASS_ABSTRACT; + + if (copts.warn_hidevirtual) + CClass_CheckHideVirtual(tree, tree); + + if (tclass->flags & CLASS_FLAGS_8000) + CClass_CheckVirtualBaseOverrides(tree, tree, 0); + + objlist = NULL; + CScope_InitObjectIterator(&iter, tclass->nspace); + while (1) { + if (!(object = OBJECT(CScope_NextObjectIteratorObject(&iter)))) + break; + + if (object->datatype == DVFUNC) { + CError_ASSERT(2175, IS_TYPE_FUNC(object->type)); + if (TYPE_FUNC(object->type)->flags & FUNC_FLAGS_400000) + objlist = CClass_DeclareCovariantFuncs(objlist, object, tclass); + } + } + + while (objlist) { + CScope_AddObject(tclass->nspace, objlist->object->name, OBJ_BASE(objlist->object)); + objlist = objlist->next; + } + + for (base = tclass->bases; base; base = base->next) { + base->offset = 0; + base->voffset = 0; + } + for (vbase = tclass->vbases; vbase; vbase = vbase->next) { + vbase->offset = 0; + vbase->voffset = 0; + } +} + +static void CClass_FindDominator(TypeClass *tclass1, SInt32 offset1, Object *object1, TypeClass *tclass2, SInt32 offset2, TypeClass *tclass3) { + Object *object; + ClassList *base; + CScopeObjectIterator iter; + + CScope_InitObjectIterator(&iter, tclass1->nspace); + while (1) { + if (!(object = OBJECT(CScope_NextObjectIteratorObject(&iter)))) + break; + + if ( + object->name == cclass_dominator_vobject->name && + object->datatype == DVFUNC && + CClass_GetOverrideKind(TYPE_FUNC(cclass_dominator_vobject->type), TYPE_FUNC(object->type), 0) + ) + { + if (object == cclass_dominator_vobject && offset1 == cclass_dominator_voffset) { + if (object1) { + if (cclass_dominator_oobject && cclass_dominator_ooffset != offset2) { + if (CClass_ClassDominates(cclass_dominator_oclass, tclass2)) + return; + if (!CClass_ClassDominates(tclass2, cclass_dominator_oclass)) { + cclass_dominator_eobject = object1; + cclass_vbase = tclass3; + return; + } + } + + cclass_dominator_oobject = object1; + cclass_dominator_ooffset = offset2; + cclass_dominator_oclass = tclass2; + cclass_dominator_eobject = NULL; + cclass_vbase = tclass3; + } + return; + } else { + if (!object1) { + object1 = object; + tclass2 = tclass1; + offset2 = offset1; + } + break; + } + } + } + + for (base = tclass1->bases; base; base = base->next) { + if (base->base->vtable) { + if (!base->is_virtual) { + CClass_FindDominator(base->base, offset1 + base->offset, object1, tclass2, offset2, tclass3); + } else { + SInt32 vboffset = CClass_VirtualBaseOffset(main_class, base->base); + CClass_FindDominator(base->base, vboffset, object1, tclass2, offset2, base->base); + } + } + } +} + +static void CClass_ConstructVTable(TypeClass *tclass, SInt32 voffset, SInt32 offset, TypeClass *baseclass) { + Object *object; + Object *thunkobject; + SInt32 newoffset; + SInt32 newvoffset; + ClassList *base; + SInt32 thunkoffset; + OLinkList *olink; + CScopeObjectIterator iter; + + CScope_InitObjectIterator(&iter, tclass->nspace); + while (1) { + if (!(object = OBJECT(CScope_NextObjectIteratorObject(&iter)))) + break; + + if (object->datatype == DVFUNC) { + newoffset = voffset + TYPE_METHOD(object->type)->vtbl_index + CABI_GetVTableOffset(tclass); + CError_ASSERT(2288, newoffset < vtable_data_size); + + if (!vtable_object_data[newoffset]) { + cclass_dominator_vobject = object; + cclass_dominator_voffset = offset; + cclass_dominator_oobject = NULL; + cclass_dominator_ooffset = offset; + CClass_FindDominator(main_class, 0, NULL, NULL, 0, NULL); + + if (cclass_dominator_oobject) { + if (cclass_dominator_eobject) + CError_Error(CErrorStr251, main_class, 0, cclass_dominator_vobject, cclass_dominator_oobject, cclass_dominator_eobject); + } else { + cclass_dominator_oobject = object; + cclass_vbase = NULL; + } + + vtable_object_data[newoffset] = 1; + + if (!(TYPE_FUNC(cclass_dominator_oobject->type)->flags & FUNC_PURE)) { + if (!check_pures) { + thunkobject = cclass_dominator_oobject; + if ((thunkoffset = cclass_dominator_ooffset - offset)) { + if (cclass_vbase && (main_class->flags & CLASS_FLAGS_8000)) { + thunkobject = CClass_ThunkObject(cclass_dominator_oobject, thunkoffset, 0, + CABI_GetCtorOffsetOffset(cclass_vbase, tclass)); + } else { + thunkobject = CClass_ThunkObject(cclass_dominator_oobject, thunkoffset, 0, -1); + } + } + + olink = lalloc(sizeof(OLinkList)); + olink->next = vtable_object_links; + olink->obj = thunkobject; + olink->offset = newoffset; + olink->somevalue = 0; + vtable_object_links = olink; + } + } else { + found_pure = cclass_dominator_oobject; + } + } + } + } + + for (base = tclass->bases; base; base = base->next) { + if (base->base->vtable) { + if (base->is_virtual) { + newoffset = CClass_VirtualBaseOffset(main_class, base->base); + newvoffset = CClass_VirtualBaseVTableOffset(main_class, base->base); + CClass_ConstructVTable( + base->base, + newvoffset, + newoffset, + base->base + ); + } else { + CClass_ConstructVTable( + base->base, + voffset + base->voffset, + offset + base->offset, + baseclass + ); + } + } + } +} + +void CClass_ClassDefaultFuncAction(TypeClass *tclass) { +} + +void CClass_ClassAction(TypeClass *tclass) { + if (tclass->sominfo) { + CSOM_GenerateClassStructures(tclass); + } else if (tclass->vtable) { + vtable_data_size = tclass->vtable->size; + vtable_object_data = lalloc(vtable_data_size); + memclrw(vtable_object_data, vtable_data_size); + + main_class = tclass; + vtable_object_links = NULL; + found_pure = NULL; + check_pures = 0; + + CClass_AllocVTable(tclass); + + memclrw(vtable_object_data, vtable_data_size); + if (copts.RTTI && !(tclass->flags & (CLASS_SINGLE_OBJECT | CLASS_COM_OBJECT))) + vtable_object_links = CRTTI_ConstructVTableHeaders(tclass, vtable_object_data, vtable_object_links); + + CError_ASSERT(2492, tclass->vtable->object->type->size == tclass->vtable->size); + CInit_DeclareData(tclass->vtable->object, vtable_object_data, vtable_object_links, tclass->vtable->size); + } +} + +void CClass_MakeStaticActionClass(TypeClass *tclass) { + if (tclass->vtable) { + tclass->vtable->object->sclass = TK_STATIC; + tclass->vtable->object->qual |= Q_20000; + if (!(tclass->vtable->object->flags & OBJECT_FLAGS_2)) { + CParser_NewCallBackAction(tclass->vtable->object, tclass); + } else if (cparamblkptr->precompile != 1) { + CParser_NewClassAction(tclass); + } + } +} + +Object *CClass_CheckPures(TypeClass *tclass) { + return CClass_CheckVirtuals(tclass); +} + +void CClass_MemberDef(Object *obj, TypeClass *tclass) { + switch (tclass->action) { + case CLASS_ACTION_0: + break; + case CLASS_ACTION_1: + if (IS_TYPE_FUNC(obj->type) && (TYPE_FUNC(obj->type)->flags & FUNC_FLAGS_4)) { + if (obj->qual & Q_INLINE) { + if (tclass->sominfo) + CError_Error(CErrorStr280); + tclass->action = CLASS_ACTION_0; + CClass_MakeStaticActionClass(tclass); + } else if (cparamblkptr->precompile != 1) { + CParser_NewClassAction(tclass); + } + } + break; + case CLASS_ACTION_2: + CError_FATAL(2682); + break; + case CLASS_ACTION_3: + break; + default: + CError_FATAL(2701); + } +} + +Object *CClass_ThisSelfObject(void) { + ObjectList *list; + + if (cscope_currentfunc && cscope_currentclass) { + if (cscope_currentclass->objcinfo) { + for (list = arguments; list; list = list->next) { + if (list->object->name == self_name_node) + return list->object; + } + CError_Error(CErrorStr301); + } else { + if (cscope_is_member_func) { + for (list = arguments; list; list = list->next) { + if (list->object->name == this_name_node) + return list->object; + } + } + CError_Error(CErrorStr189); + } + } + + CError_Error(copts.cplusplus ? CErrorStr189 : CErrorStr301); + return NULL; +} + +ENode *CClass_CreateThisSelfExpr(void) { + Object *object; + ENode *expr; + + if (!(object = CClass_ThisSelfObject())) + return NULL; + + expr = create_objectrefnode(object); + expr->rtype = CDecl_NewPointerType(TYPE(cscope_currentclass)); + expr = makemonadicnode(expr, EINDIRECT); + expr->data.monadic->rtype = CDecl_NewPointerType(expr->rtype); + + return expr; +} + +static AccessType CClass_BaseMemberAccess(BClassList *path, AccessType access) { + ClassList *base; + + if (path->next) { + access = CClass_BaseMemberAccess(path->next, access); + switch (access) { + case ACCESSPRIVATE: + case ACCESSNONE: + return ACCESSNONE; + } + + for (base = TYPE_CLASS(path->type)->bases; ; base = base->next) { + if (!base) + return ACCESSNONE; + + if (base->base == TYPE_CLASS(path->next->type)) { + switch (base->access) { + case ACCESSNONE: + access = ACCESSNONE; + break; + case ACCESSPROTECTED: + if (access == ACCESSPUBLIC) + access = ACCESSPROTECTED; + break; + case ACCESSPRIVATE: + if (access == ACCESSPRIVATE) + access = ACCESSNONE; + else + access = ACCESSPRIVATE; + break; + case ACCESSPUBLIC: + break; + } + break; + } + } + } + + return access; +} + +static Boolean CClass_CanAccess(BClassList *path, AccessType access) { + AccessType access2; + BClassList *scan; + BClassList *next; + TypeClass *prevclass; + TypeClass *tclass; + ClassList *base; + ClassFriend *cfriend; + + tclass = TYPE_CLASS(path->type); + access2 = access; + if ((scan = path->next)) { + if (access2 != ACCESSPRIVATE) { + prevclass = tclass; + while (scan) { + for (base = prevclass->bases; base; base = base->next) { + if (base->base == TYPE_CLASS(scan->type)) + break; + } + + if (!base) + return 0; + + switch (base->access) { + case ACCESSNONE: + access2 = ACCESSNONE; + break; + case ACCESSPROTECTED: + if (access2 == ACCESSPUBLIC) + access2 = ACCESSPROTECTED; + break; + case ACCESSPRIVATE: + if (access2 == ACCESSPRIVATE) + access2 = ACCESSNONE; + else + access2 = ACCESSPRIVATE; + break; + case ACCESSPUBLIC: + break; + } + + prevclass = TYPE_CLASS(scan->type); + scan = scan->next; + } + } else { + access2 = ACCESSNONE; + } + } + + if (access2 == ACCESSPUBLIC) + return 1; + + if (access2 != ACCESSNONE) { + if (cscope_currentclass == tclass) + return 1; + if (cobjc_currentclass == tclass) + return 1; + + for (cfriend = tclass->friends; cfriend; cfriend = cfriend->next) { + if (cfriend->isclass) { + if (cfriend->u.theclass == cscope_currentclass) + return 1; + } else { + if (cfriend->u.obj == cscope_currentfunc) + return 1; + } + } + } + + for (scan = path; scan->next; scan = scan->next) { + if (CClass_CanAccess(scan->next, access)) { + if ((next = scan->next->next) || access != ACCESSPUBLIC) { + scan->next->next = NULL; + if (CClass_CanAccess(path, ACCESSPUBLIC)) { + scan->next->next = next; + return 1; + } + scan->next->next = next; + } + } + } + + return 0; +} + +void CClass_CheckPathAccess(BClassList *path, Object *obj, AccessType access) { + if (!CClass_CanAccess(path, access)) { + if (path && obj) + CError_Error(CErrorStr381, path->type, 0, obj); + else + CError_Error(CErrorStr187); + } +} + +static BClassList *CClass_PathCleanup(BClassList *path, TypeClass *tclass) { + BClassList *first; + ClassList *base; + + first = path; + + while (1) { + if (!path->next) { + if (!tclass) + return first; + if (path->type == TYPE(tclass)) + return first; + return NULL; + } + + if (path->type != path->next->type) { + for (base = TYPE_CLASS(path->type)->bases; base; base = base->next) { + if (base->base == TYPE_CLASS(path->next->type)) + break; + } + + if (base) { + path = path->next; + } else { + first = path = path->next; + } + } else { + path->next = path->next->next; + } + } +} + +void CClass_CheckStaticAccess(BClassList *path, TypeClass *tclass, AccessType access) { + ClassFriend *cfriend; + + if (path) { + path = CClass_PathCleanup(path, tclass); + if (path && path->next) { + if (!CClass_CanAccess(path, access)) + CError_Error(CErrorStr187); + return; + } + } + + switch (access) { + case ACCESSPUBLIC: + return; + case ACCESSPRIVATE: + case ACCESSPROTECTED: + if (tclass == cscope_currentclass) + return; + + for (cfriend = tclass->friends; cfriend; cfriend = cfriend->next) { + if (cfriend->isclass) { + if (cfriend->u.theclass == cscope_currentclass) + return; + } else { + if (cfriend->u.obj == cscope_currentfunc) + return; + } + } + case ACCESSNONE: + CError_Warning(CErrorStr187); + return; + default: + CError_FATAL(3013); + } +} + +void CClass_CheckObjectAccess(BClassList *path, Object *obj) { + short depth; + Boolean isambigbase; + + if (obj->nspace && obj->nspace->theclass) { + if (!path && cscope_currentclass) + path = CClass_GetBasePath(cscope_currentclass, obj->nspace->theclass, &depth, &isambigbase); + + CClass_CheckStaticAccess(path, obj->nspace->theclass, obj->access); + } +} + +void CClass_CheckEnumAccess(BClassList *path, ObjEnumConst *objec) { + if (path) { + if ((path = CClass_PathCleanup(path, NULL))) { + if (!CClass_CanAccess(path, objec->access)) + CError_Error(CErrorStr187); + return; + } + } + + if ( + objec->access != ACCESSPUBLIC && + IS_TYPE_ENUM(objec->type) && + TYPE_ENUM(objec->type)->nspace && + TYPE_ENUM(objec->type)->nspace->theclass + ) + CClass_CheckStaticAccess(NULL, TYPE_ENUM(objec->type)->nspace->theclass, objec->access); +} + +static Type *CClass_PointerTypeCopy(Type *type) { + Type *copy; + + switch (type->type) { + case TYPEPOINTER: + case TYPEARRAY: + copy = galloc(sizeof(TypePointer)); + *TYPE_POINTER(copy) = *TYPE_POINTER(type); + TPTR_TARGET(copy) = CClass_PointerTypeCopy(TPTR_TARGET(copy)); + return copy; + case TYPEMEMBERPOINTER: + copy = galloc(sizeof(TypeMemberPointer)); + *TYPE_MEMBER_POINTER(copy) = *TYPE_MEMBER_POINTER(type); + return copy; + default: + return type; + } +} + +Type *CClass_CombineClassAccessQualifiers(Type *type, UInt32 qual1, UInt32 qual2, UInt32 *outflags) { + Type *inner; + + qual2 = qual2 & (Q_CONST | Q_VOLATILE); + if (qual1 & Q_MUTABLE) + qual2 &= ~Q_CONST; + qual1 = qual1 & (Q_CONST | Q_VOLATILE); + + inner = type; + while (IS_TYPE_ARRAY(inner)) + inner = TPTR_TARGET(inner); + + switch (inner->type) { + case TYPEMEMBERPOINTER: + case TYPEPOINTER: + if (qual2) { + type = CClass_PointerTypeCopy(type); + inner = type; + while (IS_TYPE_ARRAY(inner)) + inner = TPTR_TARGET(inner); + + switch (inner->type) { + case TYPEPOINTER: + TPTR_QUAL(inner) |= qual2; + break; + case TYPEMEMBERPOINTER: + TYPE_MEMBER_POINTER(inner)->qual |= qual2; + break; + default: + CError_FATAL(3125); + } + } + break; + default: + qual1 |= qual2; + } + + *outflags = qual1; + return type; +} + +static void CClass_OptimizeBitFieldAccess(Type **ptype, SInt32 *poffset) { + Type *innertype; + TypeBitfield *newtype; + short i; + + innertype = TYPE_BITFIELD(*ptype)->bitfieldtype; + if (TYPE_BITFIELD(*ptype)->bitlength == 8) { + switch (TYPE_BITFIELD(*ptype)->offset) { + case 0: + i = 0; + break; + case 8: + i = 1; + break; + case 16: + i = 2; + break; + case 24: + i = 3; + break; + default: + i = -1; + break; + } + + if (i >= 0) { + if (innertype->size != 1) { + if (is_unsigned(TYPE_BITFIELD(*ptype)->bitfieldtype)) + *ptype = TYPE(&stunsignedchar); + else + *ptype = TYPE(&stsignedchar); + } else { + *ptype = innertype; + } + *poffset += i; + return; + } + } + + if (TYPE_BITFIELD(*ptype)->bitlength == 16) { + switch (TYPE_BITFIELD(*ptype)->offset) { + case 0: + i = 0; + break; + case 16: + i = 2; + break; + default: + i = -1; + break; + } + + if (i >= 0) { + if (innertype->size != stsignedshort.size) { + if (is_unsigned(innertype)) + *ptype = TYPE(&stunsignedshort); + else + *ptype = TYPE(&stsignedshort); + } else { + *ptype = innertype; + } + *poffset += i; + return; + } + } + + if (TYPE_BITFIELD(*ptype)->bitlength == 32 && TYPE_BITFIELD(*ptype)->offset == 0) { + if (innertype->size != stsignedlong.size) { + if (is_unsigned(innertype)) + *ptype = TYPE(&stunsignedlong); + else + *ptype = TYPE(&stsignedlong); + } else { + *ptype = innertype; + } + return; + } + + if ((*ptype)->size != stsignedchar.size) { + i = TYPE_BITFIELD(*ptype)->offset + TYPE_BITFIELD(*ptype)->bitlength - 1; + + if (TYPE_BITFIELD(*ptype)->bitlength < 8 && (TYPE_BITFIELD(*ptype)->offset & 0xFFF8) == (i & 0xFFF8)) { + newtype = galloc(sizeof(TypeBitfield)); + *newtype = *TYPE_BITFIELD(*ptype); + *ptype = TYPE(newtype); + + i = 0; + if (newtype->offset >= 8) + i = 1; + if (newtype->offset >= 16) + i = 2; + if (newtype->offset >= 24) + i = 3; + *poffset += i; + newtype->offset -= 8 * i; + + newtype->bitfieldtype = is_unsigned(innertype) ? TYPE(&stunsignedchar) : TYPE(&stsignedchar); + newtype->size = newtype->bitfieldtype->size; + return; + } + + if ((*ptype)->size != stsignedshort.size) { + if (TYPE_BITFIELD(*ptype)->bitlength < 16 && (TYPE_BITFIELD(*ptype)->offset & 0xFFF0) == (i & 0xFFF0)) { + newtype = galloc(sizeof(TypeBitfield)); + *newtype = *TYPE_BITFIELD(*ptype); + *ptype = TYPE(newtype); + + i = 0; + if (newtype->offset >= 16) + i = stsignedshort.size; + *poffset += i; + newtype->offset -= 8 * i; + + newtype->bitfieldtype = is_unsigned(innertype) ? TYPE(&stunsignedshort) : TYPE(&stsignedshort); + newtype->size = newtype->bitfieldtype->size; + return; + } + } + } +} + +ENode *CClass_AccessMember(ENode *classexpr, Type *type, UInt32 qual, SInt32 offset) { + Type *innertype; + UInt32 flags; + + innertype = NULL; + + if (IS_TYPE_CLASS(classexpr->rtype) && (TYPE_CLASS(classexpr->rtype)->flags & CLASS_HANDLEOBJECT)) { + classexpr = makemonadicnode(classexpr, EINDIRECT); + classexpr->data.monadic->rtype = CDecl_NewPointerType(classexpr->rtype); + } + + if (IS_TYPE_BITFIELD(type)) { + innertype = TYPE_BITFIELD(type)->bitfieldtype; + CClass_OptimizeBitFieldAccess(&type, &offset); + } + + if (offset && !canadd(classexpr->data.monadic, offset)) { + classexpr->data.monadic = makediadicnode( + classexpr->data.monadic, + intconstnode(TYPE(&stunsignedlong), offset), + EADD); + optimizecomm(classexpr->data.monadic); + } + + if (innertype) { + if (IS_TYPE_BITFIELD(type)) { + classexpr->data.monadic = makemonadicnode(classexpr->data.monadic, EBITFIELD); + classexpr->data.monadic->rtype = type; + classexpr->rtype = TYPE_BITFIELD(type)->bitfieldtype; + } else { + classexpr->rtype = type; + } + } else { + classexpr->rtype = type; + } + + classexpr->rtype = CClass_CombineClassAccessQualifiers(classexpr->rtype, qual, ENODE_QUALS(classexpr), &flags); + classexpr->flags = flags; + return classexpr; +} diff --git a/compiler_and_linker/FrontEnd/C/CDecl.c b/compiler_and_linker/FrontEnd/C/CDecl.c new file mode 100644 index 0000000..43ca92e --- /dev/null +++ b/compiler_and_linker/FrontEnd/C/CDecl.c @@ -0,0 +1,4845 @@ +#include "compiler/CDecl.h" +#include "compiler/CABI.h" +#include "compiler/CBrowse.h" +#include "compiler/CClass.h" +#include "compiler/CError.h" +#include "compiler/CException.h" +#include "compiler/CExpr.h" +#include "compiler/CFunc.h" +#include "compiler/CInit.h" +#include "compiler/CInline.h" +#include "compiler/CInt64.h" +#include "compiler/CMachine.h" +#include "compiler/CMangler.h" +#include "compiler/CObjC.h" +#include "compiler/CParser.h" +#include "compiler/CPrep.h" +#include "compiler/CPrepTokenizer.h" +#include "compiler/CSOM.h" +#include "compiler/CTemplateClass.h" +#include "compiler/CTemplateFunc.h" +#include "compiler/CTemplateNew.h" +#include "compiler/CTemplateTools.h" +#include "compiler/CompilerTools.h" +#include "compiler/objects.h" +#include "compiler/scopes.h" +#include "compiler/templates.h" +#include "compiler/tokens.h" + +AccessType global_access; +FileOffsetInfo member_fileoffset; + +// forward declarations +static void scandirectdecl1(DeclInfo *declinfo); + +Type *CDecl_NewStructType(SInt32 size, SInt16 align) { + TypeStruct *tstruct = galloc(sizeof(TypeStruct)); + memclrw(tstruct, sizeof(TypeStruct)); + + tstruct->type = TYPESTRUCT; + tstruct->size = size; + tstruct->align = align; + tstruct->stype = STRUCT_TYPE_STRUCT; + + return (Type *) tstruct; +} + +Type *CDecl_NewArrayType(Type *type, SInt32 size) { + TypePointer *tarray = galloc(sizeof(TypePointer)); + memclrw(tarray, sizeof(TypePointer)); + + tarray->type = TYPEARRAY; + tarray->size = size; + tarray->target = type; + tarray->qual = 0; + + return (Type *) tarray; +} + +Type *CDecl_NewPointerType(Type *type) { + TypePointer *tptr = galloc(sizeof(TypePointer)); + memclrw(tptr, sizeof(TypePointer)); + + tptr->type = TYPEPOINTER; + tptr->size = 4; + tptr->target = type; + + return (Type *) tptr; +} + +Type *CDecl_NewRefPointerType(Type *type) { + TypePointer *tptr = galloc(sizeof(TypePointer)); + memclrw(tptr, sizeof(TypePointer)); + + tptr->type = TYPEPOINTER; + tptr->size = 4; + tptr->target = type; + tptr->qual = Q_REFERENCE; + + return (Type *) tptr; +} + +Type *CDecl_NewTemplDepType(TypeTemplDepType tdt) { + TypeTemplDep *t = galloc(sizeof(TypeTemplDep)); + memclrw(t, sizeof(TypeTemplDep)); + + t->type = TYPETEMPLATE; + t->size = 1; + t->dtype = tdt; + + return (Type *) t; +} + +void CDecl_SetResultReg(TypeFunc *tfunc) { +} + +static void CDecl_SetFuncResultReg(TypeFunc *tfunc) { +} + +void CDecl_SetFuncFlags(TypeFunc *tfunc, UInt32 flags) { + CDecl_SetResultReg(tfunc); +} + +static void CDecl_ParseCPPFuncDecl(TypeFunc *tfunc) { + for (;;) { + if (tk == TK_CONST) { + if (tfunc->flags & FUNC_CONST) + CError_Warning(CErrorStr313, "const"); + tfunc->flags |= FUNC_CONST; + tk = lex(); + } else if (tk == TK_VOLATILE) { + if (tfunc->flags & FUNC_VOLATILE) + CError_Warning(CErrorStr313, "volatile"); + tfunc->flags |= FUNC_VOLATILE; + tk = lex(); + } else { + break; + } + } + + if (tk == TK_THROW) + CExcept_ScanExceptionSpecification(tfunc); +} + +void CDecl_NewConvFuncType(DeclInfo *declinfo) { + TypeFunc *tfunc; + + if (tk != '(') + CError_Error(CErrorStr114); + else + tk = lex(); + + if (tk == TK_VOID) + tk = lex(); + + if (tk != ')') + CError_Error(CErrorStr115); + else + tk = lex(); + + tfunc = galloc(sizeof(TypeFunc)); + memclrw(tfunc, sizeof(TypeFunc)); + declinfo->name = CMangler_ConversionFuncName(declinfo->thetype, declinfo->qual); + tfunc->type = TYPEFUNC; + tfunc->functype = declinfo->thetype; + tfunc->qual = declinfo->qual & (Q_CONST | Q_VOLATILE); + tfunc->flags = FUNC_CONVERSION; + declinfo->x49 = 0; + CDecl_SetFuncFlags(tfunc, 1); + CDecl_ParseCPPFuncDecl(tfunc); + + declinfo->thetype = (Type *) tfunc; + declinfo->qual &= ~(Q_CONST | Q_VOLATILE); + declinfo->storageclass = 0; +} + +void CDecl_CompleteType(Type *type) { + switch (type->type) { + case TYPEPOINTER: + if ((TYPE_POINTER(type)->qual & Q_REFERENCE) && IS_TYPE_CLASS(TYPE_POINTER(type)->target)) { + type = TYPE_POINTER(type)->target; + break; + } + return; + case TYPEARRAY: + do { + type = TYPE_POINTER(type)->target; + } while (IS_TYPE_ARRAY(type)); + if (IS_TYPE_CLASS(type)) + break; + return; + case TYPECLASS: + break; + default: + return; + } + + if ((TYPE_CLASS(type)->flags & (CLASS_COMPLETED | CLASS_IS_TEMPL_INST)) == CLASS_IS_TEMPL_INST) + CTempl_InstantiateTemplateClass(TYPE_CLASS(type)); +} + +Boolean IsCompleteType(Type *type) { + switch (type->type) { + case TYPEVOID: + CError_Error(CErrorStr126); + return 0; + case TYPEFUNC: + CError_Error(CErrorStr146); + return 0; + case TYPESTRUCT: + if (!type->size) { + CError_Error(CErrorStr136, type, 0); + return 0; + } + return 1; + case TYPECLASS: + if ( + !(TYPE_CLASS(type)->flags & CLASS_COMPLETED) && + ( + !(TYPE_CLASS(type)->flags & CLASS_IS_TEMPL_INST) || + !CTempl_InstantiateTemplateClass(TYPE_CLASS(type)) + ) + ) + { + CError_Error(CErrorStr136, type, 0); + return 0; + } + return 1; + default: + if (!type->size) { + CError_Error(CErrorStr145); + return 0; + } + return 1; + } +} + +Boolean CanAllocObject(Type *type) { + switch (type->type) { + case TYPEVOID: + CError_Error(CErrorStr126); + return 0; + case TYPEFUNC: + CError_Error(CErrorStr146); + return 0; + case TYPECLASS: + if (TYPE_CLASS(type)->flags & CLASS_ABSTRACT) { + CError_AbstractClassError(TYPE_CLASS(type)); + return 0; + } + default: + return 1; + } +} + +Boolean CanCreateObject(Type *type) { + if (!CanAllocObject(type)) + return 0; + + if (IS_TYPE_CLASS(type)) { + if (TYPE_CLASS(type)->flags & CLASS_HANDLEOBJECT) { + CError_Error(CErrorStr191); + return 0; + } + if (TYPE_CLASS(type)->objcinfo) { + CError_Error(CErrorStr307); + return 0; + } + } + + return 1; +} + +static Boolean CanCreateHandleMemberObject(Type *type) { + while (IS_TYPE_ARRAY(type)) + type = TYPE_POINTER(type)->target; + + if (!CanCreateObject(type)) + return 0; + + if (IS_TYPE_CLASS(type)) { + if (CClass_Destructor(TYPE_CLASS(type)) || CClass_Constructor(TYPE_CLASS(type))) { + CError_Error(CErrorStr191); + return 0; + } + } + + return 1; +} + +void makethetypepointer(DeclInfo *declinfo, UInt32 qual) { + declinfo->thetype = CDecl_NewPointerType(declinfo->thetype); + TYPE_POINTER(declinfo->thetype)->qual = qual; +} + +void CDecl_AddThisPointerArgument(TypeFunc *tfunc, TypeClass *tclass) { + Type *ptype; + FuncArg *arg; + + ptype = CDecl_NewPointerType(!tclass->sominfo ? (Type *) tclass : &stvoid); + TYPE_POINTER(ptype)->qual = Q_CONST; + + arg = CParser_NewFuncArg(); + arg->name = this_name_node; + arg->type = ptype; + if (tfunc->flags & FUNC_CONST) + arg->qual |= Q_CONST; + if (tfunc->flags & FUNC_VOLATILE) + arg->qual |= Q_VOLATILE; + arg->next = tfunc->args; + tfunc->args = arg; +} + +void CDecl_MakePTMFuncType(TypeFunc *tfunc) { + Type *cvoidp; + FuncArg *arg1; + FuncArg *arg2; + + cvoidp = CDecl_NewPointerType(&stvoid); + TYPE_POINTER(cvoidp)->qual = Q_CONST; + + arg1 = CParser_NewFuncArg(); + arg1->name = this_name_node; + arg1->type = cvoidp; + if (tfunc->flags & FUNC_CONST) + arg1->qual |= Q_CONST; + if (tfunc->flags & FUNC_VOLATILE) + arg1->qual |= Q_VOLATILE; + + arg2 = CParser_NewFuncArg(); + arg2->name = this_name_node; + arg2->type = cvoidp; + arg2->qual = Q_CONST; + + arg1->next = tfunc->args; + arg2->next = arg1; + tfunc->args = arg2; + tfunc->flags |= FUNC_FLAGS_80; +} + +void CDecl_AddArgument(TypeFunc *tfunc, Type *argtype) { + FuncArg *arg = CParser_NewFuncArg(); + arg->type = argtype; + + arg->next = tfunc->args; + tfunc->args = arg; + + if (arg->next && arg->next->type == &stvoid) + arg->next = NULL; +} + +Boolean CDecl_CheckArrayIntegr(Type *type) { + if (!IsCompleteType(type)) + return 0; + + if (IS_TYPE_CLASS(type) && TYPE_CLASS(type)->sominfo) { + CError_Error(CErrorStr289); + return 0; + } + + if (IS_TYPE_REFERENCE(type)) { + CError_Error(CErrorStr196); + return 0; + } + + return CanCreateObject(type); +} + +static Boolean checkfuncintegr(Type *type) { + if (IS_TYPE_VOID(type)) + return 1; + + if (IS_TYPE_CLASS(type) && TYPE_CLASS(type)->sominfo) { + CError_Error(CErrorStr283); + return 0; + } + + return CanCreateObject(type); +} + +void CDecl_ParseDirectFuncDecl(DeclInfo *declinfo) { + FuncArg *list; + TypeFunc *tfunc; + + if (tk == ')') { + if (copts.cplusplus) + list = NULL; + else + list = &oldstyle; + tk = lex(); + } else { + list = parameter_type_list(declinfo); + if (tk != ')') + CError_ErrorSkip(CErrorStr115); + else + tk = lex(); + } + + tfunc = galloc(sizeof(TypeFunc)); + memclrw(tfunc, sizeof(TypeFunc)); + tfunc->type = TYPEFUNC; + tfunc->args = list; + if (declinfo->qual & Q_PASCAL) { + declinfo->qual &= ~Q_PASCAL; + tfunc->flags = FUNC_PASCAL; + } + + if (copts.cplusplus) { + CDecl_ParseCPPFuncDecl(tfunc); + if (declinfo->storageclass == TK_TYPEDEF && tfunc->exspecs) + CError_Error(CErrorStr264); + } + + scandirectdecl1(declinfo); + if (!checkfuncintegr(declinfo->thetype)) + declinfo->thetype = &stvoid; + + tfunc->functype = declinfo->thetype; + tfunc->qual = declinfo->qual & (Q_CONST | Q_VOLATILE); + declinfo->thetype = (Type *) tfunc; + declinfo->qual &= ~(Q_CONST | Q_VOLATILE); + declinfo->x49 = 0; +} + +static void scandirectdecl1(DeclInfo *declinfo) { + Boolean flag; + CInt64 len; + ENode *expr; + TypeTemplDep *ttempl; + + flag = 0; + if (tk == '[') { + if ((tk = lex()) == ']') { + len = cint64_zero; + tk = lex(); + flag = 1; + } else { + if (!declinfo->x46 || declinfo->x47) { + expr = CExpr_IntegralConstOrDepExpr(); + if (!ENODE_IS(expr, EINTCONST)) { + if (tk != ']') + CError_ErrorSkip(CErrorStr125); + else + tk = lex(); + declinfo->x47 = 1; + scandirectdecl1(declinfo); + if (!CDecl_CheckArrayIntegr(declinfo->thetype)) + declinfo->thetype = (Type *) &stsignedchar; + ttempl = (TypeTemplDep *) CDecl_NewTemplDepType(TEMPLDEP_ARRAY); + ttempl->u.array.type = declinfo->thetype; + ttempl->u.array.index = CInline_CopyExpression(expr, CopyMode1); + declinfo->thetype = (Type *) ttempl; + return; + } + len = expr->data.intval; + if (CInt64_IsNegative(&len)) { + CError_Error(CErrorStr124); + len = cint64_one; + } else if (CInt64_IsZero(&len)) { + if (!copts.ANSIstrict && declinfo->x50) { + flag = 1; + } else { + CError_Error(CErrorStr124); + len = cint64_one; + } + } + } else { + len = cint64_one; + expr = expression(); + if (IS_TYPE_INT(expr->rtype)) { + if (!ENODE_IS(expr, EINTCONST)) + declinfo->x24 = expr; + else + len = expr->data.intval; + } else { + CError_Error(CErrorStr124); + } + } + + if (tk != ']') + CError_ErrorSkip(CErrorStr125); + else + tk = lex(); + } + + declinfo->x47 = 1; + scandirectdecl1(declinfo); + + if (!flag && !CDecl_CheckArrayIntegr(declinfo->thetype)) + declinfo->thetype = (Type *) &stsignedchar; + + if (!declinfo->thetype->size && CTemplTool_IsTemplateArgumentDependentType(declinfo->thetype)) { + ttempl = (TypeTemplDep *) CDecl_NewTemplDepType(TEMPLDEP_ARRAY); + ttempl->u.array.type = declinfo->thetype; + ttempl->u.array.index = CInline_CopyExpression(intconstnode((Type *) &stsignedint, CInt64_GetULong(&len)), CopyMode1); + declinfo->thetype = (Type *) ttempl; + } else { + declinfo->thetype = CDecl_NewArrayType(declinfo->thetype, declinfo->thetype->size * CInt64_GetULong(&len)); + } + } else if (tk == '(') { + if (!copts.cplusplus || !declinfo->name || IS_TYPE_VOID(declinfo->thetype) || CParser_TryParamList(!IS_TYPE_CLASS(declinfo->thetype))) { + tk = lex(); + CDecl_ParseDirectFuncDecl(declinfo); + } + } +} + +static void substitute_type(Type *type1, Type *type2) { + SInt32 oldsize; + + while (1) { + switch (type1->type) { + case TYPEPOINTER: + if (TYPE_POINTER(type1)->target == &stillegal) { + TYPE_POINTER(type1)->target = type2; + type1->size = 4; + return; + } + type1 = TYPE_POINTER(type1)->target; + break; + case TYPEMEMBERPOINTER: + if (TYPE_MEMBER_POINTER(type1)->ty1 == &stillegal) { + TYPE_MEMBER_POINTER(type1)->ty1 = type2; + if (IS_TYPE_FUNC(type2)) { + CDecl_MakePTMFuncType(TYPE_FUNC(type2)); + type1->size = 12; + } else { + type1->size = 4; + } + return; + } + type1 = TYPE_MEMBER_POINTER(type1)->ty1; + break; + case TYPEARRAY: + if (TYPE_POINTER(type1)->target == &stillegal) { + if (!CDecl_CheckArrayIntegr(type2)) + type2 = (Type *) &stsignedchar; + type1->size *= type2->size; + TYPE_POINTER(type1)->target = type2; + return; + } + oldsize = TYPE_POINTER(type1)->target->size; + substitute_type(TYPE_POINTER(type1)->target, type2); + if (oldsize != TYPE_POINTER(type1)->target->size && oldsize != 0) + type1->size = TYPE_POINTER(type1)->target->size * (type1->size / oldsize); + return; + case TYPEFUNC: + if (TYPE_FUNC(type1)->functype == &stillegal) { + if (!checkfuncintegr(type2)) + type2 = &stvoid; + TYPE_FUNC(type1)->functype = type2; + CDecl_SetFuncResultReg((TypeFunc *) type1); + return; + } + type1 = TYPE_FUNC(type1)->functype; + break; + case TYPETEMPLATE: + if (TYPE_TEMPLATE(type1)->dtype == TEMPLDEP_ARRAY) { + if (TYPE_TEMPLATE(type1)->u.array.type == &stillegal) { + if (!CDecl_CheckArrayIntegr(type2)) + type2 = (Type *) &stsignedchar; + TYPE_TEMPLATE(type1)->u.array.type = type2; + return; + } + type1 = TYPE_TEMPLATE(type1)->u.array.type; + } else { + CError_Error(CErrorStr146); + return; + } + break; + default: + CError_Error(CErrorStr121); + return; + } + } +} + +static void scandecl(DeclInfo *declinfo) { + Type *oldtype; + Type *newtype; + + oldtype = declinfo->thetype; + declinfo->thetype = &stillegal; + scandeclarator(declinfo); + + if (tk != ')') + CError_ErrorSkip(CErrorStr115); + else + tk = lex(); + + newtype = declinfo->thetype; + if (newtype == &stillegal) { + declinfo->thetype = oldtype; + scandirectdecl1(declinfo); + } else { + declinfo->thetype = oldtype; + scandirectdecl1(declinfo); + substitute_type(newtype, declinfo->thetype); + declinfo->thetype = newtype; + } +} + +static Boolean CDecl_ParseOperatorDecl(DeclInfo *declinfo) { + if (declinfo->operator_token) { + CError_Error(CErrorStr121); + return 0; + } + + declinfo->operator_token = 0; + if (!CParser_ParseOperatorName(&declinfo->operator_token, declinfo->x4A && cscope_current->theclass, 0)) + return 0; + + if (!declinfo->operator_token) { + conversion_type_name(declinfo); + tkidentifier = CMangler_ConversionFuncName(declinfo->thetype, declinfo->qual); + declinfo->x54 = 1; + } + return 1; +} + +static Boolean CDecl_IsEnumClassTypeOrRef(Type *type) { + if (IS_TYPE_CLASS(type) || IS_TYPE_ENUM(type)) + return 1; + if (!IS_TYPE_REFERENCE(type)) + return 0; + type = TYPE_POINTER(type)->target; + return IS_TYPE_CLASS(type) || IS_TYPE_ENUM(type); +} + +static Boolean CDecl_CheckOperatorType(DeclInfo *declinfo, Boolean flag) { + FuncArg *args; + FuncArg *secondarg; + Type *functype; + short argCount; + Boolean isMethod; + + if (!IS_TYPE_FUNC(declinfo->thetype)) { + CError_Error(CErrorStr193); + return 0; + } + + functype = TYPE_FUNC(declinfo->thetype)->functype; + args = TYPE_FUNC(declinfo->thetype)->args; + if (args) { + if (args != &elipsis && args != &oldstyle) { + argCount = 1; + if (args->dexpr) { + switch (declinfo->operator_token) { + case TK_NEW: + case TK_DELETE: + case TK_NEW_ARRAY: + case TK_DELETE_ARRAY: + break; + default: + CError_Error(CErrorStr205); + } + } + + secondarg = args->next; + if (secondarg) { + argCount = ((secondarg != &elipsis && !secondarg->next) != 0) ? 2 : 3; + if (secondarg->dexpr) { + switch (declinfo->operator_token) { + case '(': + case TK_NEW: + case TK_DELETE: + case TK_NEW_ARRAY: + case TK_DELETE_ARRAY: + break; + default: + CError_Error(CErrorStr205); + } + } + } + } else { + argCount = 3; + } + } else { + CError_Error(CErrorStr193); + return 0; + } + + isMethod = flag && + IS_TYPEFUNC_METHOD(TYPE_FUNC(declinfo->thetype)) && + !TYPE_METHOD(declinfo->thetype)->is_static; + + switch (declinfo->operator_token) { + case TK_NEW: + case TK_NEW_ARRAY: + if (isMethod || !is_typesame(functype, TYPE(&void_ptr)) || argCount < 1 || args->type != CABI_GetSizeTType()) { + CError_Error(CErrorStr193); + return 0; + } + return 1; + case TK_DELETE: + case TK_DELETE_ARRAY: + if (isMethod || !IS_TYPE_VOID(functype) || argCount < 1 || !is_typesame(args->type, TYPE(&void_ptr))) { + CError_Error(CErrorStr193); + return 0; + } + return 1; + case '=': + if (!isMethod) { + CError_Error(CErrorStr193); + return 0; + } + break; + case '(': + if (!isMethod) { + CError_Error(CErrorStr193); + return 0; + } + return 1; + case '[': + if (!isMethod) { + CError_Error(CErrorStr193); + return 0; + } + break; + case TK_ARROW: + if (argCount != 1 || isMethod == 0) { + CError_Error(CErrorStr193); + return 0; + } + return 1; + case TK_INCREMENT: + case TK_DECREMENT: + if (argCount == 2 && secondarg->type != TYPE(&stsignedint)) { + CError_Error(CErrorStr193); + return 0; + } + break; + } + + if (flag && !isMethod) { + CError_Error(CErrorStr193); + return 0; + } + + switch (declinfo->operator_token) { + case '&': + case '*': + case '+': + case '-': + case TK_INCREMENT: + case TK_DECREMENT: + if (argCount != 1) + goto whatever; + case '!': + case '~': + if (argCount == 1) { + if (flag || CDecl_IsEnumClassTypeOrRef(args->type)) + return 1; + } + break; + case '%': + case ',': + case '/': + case '<': + case '=': + case '>': + case '[': + case '^': + case '|': + case TK_MULT_ASSIGN: + case TK_DIV_ASSIGN: + case TK_MOD_ASSIGN: + case TK_ADD_ASSIGN: + case TK_SUB_ASSIGN: + case TK_SHL_ASSIGN: + case TK_SHR_ASSIGN: + case TK_AND_ASSIGN: + case TK_XOR_ASSIGN: + case TK_OR_ASSIGN: + case TK_LOGICAL_OR: + case TK_LOGICAL_AND: + case TK_LOGICAL_EQ: + case TK_LOGICAL_NE: + case TK_LESS_EQUAL: + case TK_GREATER_EQUAL: + case TK_SHL: + case TK_SHR: + case TK_ARROW: + case TK_DOT_STAR: + case TK_ARROW_STAR: + whatever: + if (argCount == 2) { + if (flag || CDecl_IsEnumClassTypeOrRef(args->type) || CDecl_IsEnumClassTypeOrRef(secondarg->type)) + return 1; + } + break; + } + + CError_Error(CErrorStr193); + return 0; +} + +static void scandirectdeclarator(DeclInfo *declinfo, NameSpace *nspace) { + HashNameNode *saveident; + CScopeSave scopesave; + Boolean flag; + + if (nspace) + CScope_SetNameSpaceScope(nspace, &scopesave); + + if (tk == '(') { + if ((tk = lex()) == ')') { + if (declinfo->x55) { + CDecl_ParseDirectFuncDecl(declinfo); + if (nspace) + CScope_RestoreScope(&scopesave); + return; + } else { + CError_Error(CErrorStr121); + if (nspace) + CScope_RestoreScope(&scopesave); + return; + } + } + + if (!(tk >= TK_AUTO && tk <= TK_BYREF)) { + if (!(tk == TK_IDENTIFIER && CScope_PossibleTypeName(tkidentifier))) { + scandecl(declinfo); + if (nspace) + CScope_RestoreScope(&scopesave); + return; + } else { + saveident = tkidentifier; + switch (lookahead()) { + case ')': + case ',': + break; + default: + tkidentifier = saveident; + scandecl(declinfo); + if (nspace) + CScope_RestoreScope(&scopesave); + return; + } + } + } + + if (declinfo->name) + CError_Error(CErrorStr121); + + CDecl_ParseDirectFuncDecl(declinfo); + if (nspace) + CScope_RestoreScope(&scopesave); + return; + } + + if (nspace) { + if (tk == TK_OPERATOR) { + if (!CDecl_ParseOperatorDecl(declinfo)) { + CScope_RestoreScope(&scopesave); + return; + } + + if (declinfo->x54) { + declinfo->nspace = nspace; + declinfo->name = tkidentifier; + if (nspace) + CScope_RestoreScope(&scopesave); + + if (tk == '(') { + tk = lex(); + CDecl_ParseDirectFuncDecl(declinfo); + if (IS_TYPE_FUNC(declinfo->thetype)) + TYPE_FUNC(declinfo->thetype)->flags |= FUNC_CONVERSION; + else + CError_Error(CErrorStr121); + } else { + CError_Error(CErrorStr114); + } + return; + } + + flag = 1; + } else if (tk != TK_IDENTIFIER) { + CError_Error(CErrorStr107); + CScope_RestoreScope(&scopesave); + return; + } else { + flag = 0; + } + + if (declinfo->name) { + CError_Error(CErrorStr121); + CScope_RestoreScope(&scopesave); + return; + } + + declinfo->nspace = nspace; + declinfo->name = tkidentifier; + if (!flag) + tk = lex(); + } else if (tk == TK_IDENTIFIER) { + if (declinfo->name) + CError_Error(CErrorStr121); + declinfo->name = tkidentifier; + tk = lex(); + } else if (tk == TK_OPERATOR) { + if (!CDecl_ParseOperatorDecl(declinfo)) + return; + declinfo->name = tkidentifier; + } + + if (tk == '<' && declinfo->x51) { + declinfo->expltargs = CTempl_ParseUncheckTemplArgs(NULL, 0); + declinfo->has_expltargs = 1; + declinfo->x51 = 0; + tk = lex(); + } + + scandirectdecl1(declinfo); + + if (nspace) + CScope_RestoreScope(&scopesave); +} + +void makememberpointertype(DeclInfo *declinfo, TypeClass *tclass, UInt32 qual) { + TypeMemberPointer *tmemp; + TypeFunc *tfunc; + + if (tclass->flags & CLASS_HANDLEOBJECT) { + CError_Error(CErrorStr191); + declinfo->thetype = (Type *) &stsignedint; + return; + } + if (tclass->sominfo) { + CError_Error(CErrorStr290); + declinfo->thetype = (Type *) &stsignedint; + return; + } + + tmemp = galloc(sizeof(TypeMemberPointer)); + memclrw(tmemp, sizeof(TypeMemberPointer)); + tmemp->type = TYPEMEMBERPOINTER; + tmemp->ty2 = (Type *) tclass; + tmemp->qual = qual; + + if (IS_TYPE_FUNC(declinfo->thetype)) { + tfunc = galloc(sizeof(TypeFunc)); + *tfunc = *TYPE_FUNC(declinfo->thetype); + tmemp->ty1 = (Type *) tfunc; + tmemp->size = 12; + CDecl_MakePTMFuncType(tfunc); + } else { + tmemp->size = 4; + tmemp->ty1 = declinfo->thetype; + } + declinfo->thetype = (Type *) tmemp; +} + +void CDecl_ScanPointer(DeclInfo *declinfo, NameSpace *nspace, Boolean flag) { + NameResult pr; + UInt32 qual; + + while (1) { + qual = (tk == '&') ? Q_REFERENCE : 0; + + for (tk = lex(); ; tk = lex()) { + switch (tk) { + case TK_CONST: + if (qual & Q_CONST) + CError_Error(CErrorStr121); + qual |= Q_CONST; + continue; + case TK_VOLATILE: + if (qual & Q_VOLATILE) + CError_Error(CErrorStr121); + qual |= Q_VOLATILE; + continue; + case TK_RESTRICT: + if (qual & Q_RESTRICT) + CError_Error(CErrorStr121); + qual |= Q_RESTRICT; + continue; + default: + break; + } + break; + } + + if (IS_TYPE_REFERENCE(declinfo->thetype) || ((qual & Q_REFERENCE) && IS_TYPE_VOID(declinfo->thetype))) { + CError_Error(CErrorStr196); + return; + } + + if (nspace) { + makememberpointertype(declinfo, nspace->theclass, qual); + nspace = NULL; + } else { + makethetypepointer(declinfo, qual); + } + + switch (tk) { + case '*': + continue; + case '&': + if (!copts.cplusplus) { + if (flag) + scandirectdeclarator(declinfo, NULL); + return; + } + continue; + case TK_IDENTIFIER: + if (!copts.cplusplus) + break; + if (copts.cpp_extensions && cscope_current->theclass && cscope_current->theclass->classname == tkidentifier && lookahead() == TK_COLON_COLON) { + tk = lex(); + tk = lex(); + break; + } + case TK_COLON_COLON: + if (CScope_ParseQualifiedNameSpace(&pr, 1, 0)) { + if ((nspace = pr.nspace_0)) { + if (nspace->theclass && tk == '*') + continue; + } else { + if (pr.type && IS_TYPE_TEMPLATE(pr.type) && declinfo->x30) { + if (CTempl_IsQualifiedMember(declinfo, pr.type, &nspace)) + scandirectdeclarator(declinfo, nspace); + else + declinfo->x20 = pr.type; + return; + } + CError_Error(CErrorStr121); + } + } + break; + } + break; + } + + if (flag) + scandirectdeclarator(declinfo, nspace); +} + +static void CDecl_TemplatePTM(DeclInfo *declinfo, Type *type) { + TypeMemberPointer *tmemp = galloc(sizeof(TypeMemberPointer)); + tmemp->type = TYPEMEMBERPOINTER; + if (IS_TYPE_FUNC(declinfo->thetype)) { + CDecl_MakePTMFuncType((TypeFunc *) declinfo->thetype); + tmemp->size = 12; + } else { + tmemp->size = 4; + } + + tmemp->ty1 = declinfo->thetype; + tmemp->ty2 = type; + tmemp->qual = 0; + declinfo->thetype = (Type *) tmemp; +} + +void scandeclarator(DeclInfo *declinfo) { + NameResult pr; + NameSpace *nspace; + + switch (tk) { + case '&': + if (!copts.cplusplus) + break; + case '*': + CDecl_ScanPointer(declinfo, NULL, 1); + if (tk == TK_UU_ATTRIBUTE_UU) + CParser_ParseAttribute(NULL, declinfo); + return; + case TK_IDENTIFIER: + if (!copts.cplusplus) + break; + case TK_COLON_COLON: + if (CScope_ParseQualifiedNameSpace(&pr, 1, 0)) { + nspace = pr.nspace_0; + if (nspace) { + if (nspace->theclass && tk == '*') + CDecl_ScanPointer(declinfo, nspace, 1); + else + scandirectdeclarator(declinfo, nspace); + return; + } + if (pr.type && IS_TYPE_TEMPLATE(pr.type)) { + if (declinfo->x30 && CTempl_IsQualifiedMember(declinfo, pr.type, &nspace)) { + scandirectdeclarator(declinfo, nspace); + return; + } else if (declinfo->x30 && tk == TK_OPERATOR) { + declinfo->x20 = pr.type; + return; + } else if ((tk = lex()) == TK_COLON_COLON && (tk = lex()) == '*') { + CDecl_TemplatePTM(declinfo, pr.type); + tk = lex(); + break; + } else if (declinfo->x30) { + declinfo->x20 = pr.type; + return; + } + } + CError_Error(CErrorStr121); + } + break; + } + + scandirectdeclarator(declinfo, NULL); + if (tk == TK_UU_ATTRIBUTE_UU) + CParser_ParseAttribute(NULL, declinfo); +} + +void conversion_type_name(DeclInfo *declinfo) { + NameResult pr; + DeclInfo subdeclinfo; + + memclrw(&subdeclinfo, sizeof(DeclInfo)); + CParser_GetDeclSpecs(&subdeclinfo, 0); + + switch (tk) { + case '&': + case '*': + CDecl_ScanPointer(&subdeclinfo, NULL, 0); + break; + case TK_IDENTIFIER: + case TK_COLON_COLON: + if (CScope_ParseQualifiedNameSpace(&pr, 0, 0)) { + if (pr.nspace_0 && pr.nspace_0->theclass && tk == '*') + CDecl_ScanPointer(&subdeclinfo, pr.nspace_0, 0); + else + CError_Error(CErrorStr121); + } + break; + } + + declinfo->name = subdeclinfo.name; + declinfo->thetype = subdeclinfo.thetype; + declinfo->qual |= subdeclinfo.qual; +} + +static void scaninlinefunc(Object *obj) { + short array[256]; + short r29; + CInt64 val; + + if (tk == '{') { + tk = lex(); + r29 = 0; + while (1) { + if (r29 >= 256) { + CError_Error(CErrorStr127); + r29 = 255; + } + val = CExpr_IntegralConstExpr(); + array[r29++] = CInt64_GetULong(&val); + if (tk != '}') { + if (tk != ',') + CError_Error(CErrorStr116); + tk = lex(); + } else { + tk = lex(); + break; + } + } + } else { + val = CExpr_IntegralConstExpr(); + array[0] = CInt64_GetULong(&val); + r29 = 1; + } + + obj->datatype = DINLINEFUNC; + obj->u.ifunc.size = r29 * 2; + obj->u.ifunc.data = galloc(obj->u.ifunc.size); + obj->u.ifunc.xrefs = NULL; + memcpy(obj->u.ifunc.data, array, obj->u.ifunc.size); + + if (tk != ';') + CError_Error(CErrorStr123); +} + +typedef enum { + OverloadMode0, + OverloadMode1, + OverloadMode2, + OverloadMode3 +} OverloadMode; + +static Object *CDecl_OverloadFunctionObject(NameSpaceObjectList *list, DeclInfo *declinfo, Boolean *outflag, OverloadMode mode, Boolean flag2) { + TypeFunc *scanfunc; + NameSpaceObjectList *scan; + TypeFunc *tfunc; + FuncArg *args; + FuncArg *scanargs; + Object *obj; + Boolean r24; + short compareresult; + + if (outflag) + *outflag = 0; + + tfunc = (TypeFunc *) declinfo->thetype; + args = tfunc->args; + r24 = 0; + for (scan = list; scan; scan = scan->next) { + obj = OBJECT(scan->object); + if (obj->otype != OT_OBJECT) + continue; + + scanfunc = TYPE_FUNC(obj->type); + if (!IS_TYPE_FUNC(scanfunc)) + continue; + + scanargs = scanfunc->args; + if (scanfunc->flags & FUNC_IS_TEMPL) + r24 = 1; + + if (IS_TYPEFUNC_METHOD(scanfunc)) { + switch (mode) { + case OverloadMode0: + CError_Error(CErrorStr197); + break; + case OverloadMode1: + if (!TYPE_METHOD(scanfunc)->is_static) + continue; + break; + case OverloadMode2: + if (TYPE_METHOD(scanfunc)->is_static) + continue; + break; + case OverloadMode3: + if (!TYPE_METHOD(scanfunc)->is_static) { + if (scanargs->qual & Q_CV) + continue; + scanargs = scanargs->next; + } + break; + } + } else { + if (mode) + CError_Error(CErrorStr197); + } + + compareresult = CParser_CompareArgLists(args, scanargs); + if (compareresult == 1) { + if (scanfunc->flags & FUNC_CONVERSION) { + if (!(tfunc->flags & FUNC_CONVERSION)) { + CError_Error(CErrorStr197); + break; + } + if (!is_typesame(tfunc->functype, scanfunc->functype)) + continue; + if ((tfunc->qual & Q_CV) != (scanfunc->qual & Q_CV)) + continue; + if ((tfunc->flags & FUNC_CALL_CONV_MASK) != (scanfunc->flags & FUNC_CALL_CONV_MASK)) { + CError_Error(CErrorStr197); + break; + } + if (tfunc->exspecs || scanfunc->exspecs) + CExcept_CompareSpecifications(tfunc->exspecs, scanfunc->exspecs); + return obj; + } + + if (tfunc->flags & FUNC_CONVERSION) { + CError_Error(CErrorStr197); + break; + } + + if ( + !is_typesame(tfunc->functype, scanfunc->functype) || + ((tfunc->qual & (Q_CONST | Q_PASCAL)) != (scanfunc->qual & (Q_CONST | Q_PASCAL))) || + ((tfunc->flags & FUNC_CALL_CONV_MASK) != (scanfunc->flags & FUNC_CALL_CONV_MASK)) + ) + { + CError_Error(CErrorStr197); + break; + } + + if (tfunc->exspecs || scanfunc->exspecs) { + if (obj->name != newp_fobj->name && obj->name != newa_fobj->name && obj->name != delp_fobj->name && obj->name != dela_fobj->name) + CExcept_CompareSpecifications(tfunc->exspecs, scanfunc->exspecs); + } + + return obj; + } else if (compareresult == 2) { + CError_Error(CErrorStr197); + break; + } + } + + if (r24 && (flag2 || declinfo->x3C)) { + if ((obj = CTempl_TemplateFunctionCheck(declinfo, list))) + return obj; + } + + if (!outflag) { + CError_Error(CErrorStr197); + return NULL; + } + + if (declinfo->nspace) + CError_Error(CErrorStr336); + + *outflag = 1; + obj = CParser_NewFunctionObject(declinfo); + CheckDefaultArgs(TYPE_FUNC(obj->type)->args); + + if (tfunc->flags & FUNC_PASCAL) { + for (scan = list; scan; scan = scan->next) { + if (scan->object->otype == OT_OBJECT && IS_TYPE_FUNC(OBJECT(scan->object)->type)) { + if (TYPE_FUNC(OBJECT(scan->object)->type)->flags & FUNC_PASCAL) + CError_Error(CErrorStr226); + } + } + } + + if (copts.cplusplus && declinfo->is_extern_c) { + for (scan = list; scan; scan = scan->next) { + if (scan->object->otype == OT_OBJECT && !(OBJECT(scan->object)->qual & Q_MANGLE_NAME)) + CError_Error(CErrorStr197); + } + } + + CScope_AddObject(cscope_current, declinfo->name, OBJ_BASE(obj)); + if (cscope_current->theclass && (cscope_current->theclass->flags & CLASS_IS_TEMPL) && + CTemplTool_IsTemplateArgumentDependentType(declinfo->thetype)) + CTemplClass_RegisterObjectDef(TEMPL_CLASS(cscope_current->theclass), OBJ_BASE(obj)); + + return obj; +} + +void MergeDefaultArgs(FuncArg *a, FuncArg *b) { + FuncArg *scan_a; + FuncArg *scan_b; + + if (a == &oldstyle || b == &oldstyle) + return; + + scan_a = a; + scan_b = b; + while (scan_a && scan_b) { + if (scan_a->dexpr) { + while (scan_b) { + if (scan_b->dexpr) { + while (a) { + a->dexpr = NULL; + a = a->next; + } + while (b) { + b->dexpr = NULL; + b = b->next; + } + CError_Error(CErrorStr205); + return; + } + scan_b = scan_b->next; + } + break; + } else if (scan_b->dexpr) { + do { + scan_a = scan_a->next; + scan_b = scan_b->next; + if (!scan_a) goto secondpart; + if (scan_a == &elipsis) goto secondpart; + if (scan_a->dexpr && scan_b->dexpr) break; + } while (scan_a->dexpr || scan_b->dexpr); + + while (a) { + a->dexpr = NULL; + a = a->next; + } + while (b) { + b->dexpr = NULL; + b = b->next; + } + CError_Error(CErrorStr205); + return; + } else { + scan_a = scan_a->next; + scan_b = scan_b->next; + } + } + +secondpart: + while (a && b) { + if (b->dexpr) + a->dexpr = b->dexpr; + else + b->dexpr = a->dexpr; + a = a->next; + b = b->next; + } +} + +void CheckDefaultArgs(FuncArg *args) { + FuncArg *scan; + + scan = args; + while (scan && !scan->dexpr) + scan = scan->next; + + while (scan && scan != &elipsis && scan != &oldstyle) { + if (!scan->dexpr) { + while (args) { + args->dexpr = NULL; + args = args->next; + } + CError_Error(CErrorStr205); + return; + } + scan = scan->next; + } +} + +static void CDecl_FuncRedeclCheck(Object *obj, DeclInfo *declinfo, Boolean flag) { + if (declinfo->storageclass == TK_STATIC && obj->sclass != TK_STATIC) { + if (copts.cplusplus) + CError_Error(CErrorStr260); + else + obj->sclass = TK_STATIC; + } + + obj->qual |= declinfo->qual; + if (flag) + CheckDefaultArgs(TYPE_FUNC(obj->type)->args); + else + MergeDefaultArgs(TYPE_FUNC(obj->type)->args, TYPE_FUNC(declinfo->thetype)->args); + + if (!declinfo->x45) + TYPE_FUNC(obj->type)->args = TYPE_FUNC(declinfo->thetype)->args; +} + +Object *CDecl_GetFunctionObject(DeclInfo *declinfo, NameSpace *nspace, Boolean *pflag, Boolean someotherflag) { + NameSpace *nspace2; + Type *type; + Object *obj; + NameSpaceObjectList *list; + TypeMemberFunc tmp; + Boolean r27; + Boolean outflag; + + r27 = 0; + if (pflag) + *pflag = 0; + + nspace2 = declinfo->nspace; + if (!nspace2) + nspace2 = cscope_current; + + CError_QualifierCheck(declinfo->qual & ~(Q_ALIGNED_MASK | Q_WEAK | Q_20000 | Q_INLINE | Q_PASCAL | Q_ASM | Q_VOLATILE | Q_CONST)); + switch (TYPE_FUNC(declinfo->thetype)->functype->type) { + case TYPEFUNC: + case TYPEARRAY: + CError_Error(CErrorStr128); + TYPE_FUNC(declinfo->thetype)->functype = TYPE(&stsignedint); + break; + } + + if (nspace2->theclass) { + CError_ASSERT(1969, declinfo->name); + if (!nspace2->theclass->size) + CDecl_CompleteType(TYPE(nspace2->theclass)); + if (!(list = CScope_GetLocalObject(nspace2, declinfo->name))) { + CError_Error(CErrorStr140, declinfo->name->name); + return NULL; + } + + obj = OBJECT(list->object); + type = obj->type; + if (!IS_TYPE_FUNC(type)) { + CError_Error(CErrorStr249, CError_GetObjectName(obj), type, obj->qual, declinfo->thetype, declinfo->qual); + return NULL; + } + + if (declinfo->has_expltargs) + return CTempl_TemplateFunctionCheck(declinfo, list); + + if (declinfo->x3C || (list->next && list->next->object->otype == OT_OBJECT)) { + if (TYPE_FUNC(declinfo->thetype)->flags & (FUNC_CONST | FUNC_VOLATILE)) { + CDecl_AddThisPointerArgument(TYPE_FUNC(declinfo->thetype), nspace2->theclass); + obj = CDecl_OverloadFunctionObject(list, declinfo, NULL, OverloadMode2, someotherflag); + if (!obj) + return NULL; + } else { + obj = CDecl_OverloadFunctionObject(list, declinfo, NULL, OverloadMode3, someotherflag); + if (!obj) + return NULL; + if (!TYPE_METHOD(obj->type)->is_static) + CDecl_AddThisPointerArgument(TYPE_FUNC(declinfo->thetype), nspace2->theclass); + } + } else { + if (TYPE_METHOD(type)->is_static) { + if (nspace2->theclass->sominfo) + CSOM_FixNewDeleteFunctype(TYPE_FUNC(declinfo->thetype)); + } else { + CDecl_AddThisPointerArgument(TYPE_FUNC(declinfo->thetype), nspace2->theclass); + } + + if (copts.cpp_extensions) { + declinfo->qual |= obj->qual & (Q_PASCAL | Q_CONST); + TYPE_FUNC(declinfo->thetype)->qual |= TYPE_FUNC(obj->type)->qual & (Q_PASCAL | Q_CONST); + TYPE_FUNC(declinfo->thetype)->flags |= TYPE_FUNC(obj->type)->flags & (FUNC_FLAGS_4000000 | FUNC_FLAGS_10000000); + } + + if (!is_typesame(declinfo->thetype, obj->type) || (declinfo->qual & (Q_PASCAL | Q_CONST)) != (obj->qual & (Q_PASCAL | Q_CONST))) { + tmp = *TYPE_METHOD(obj->type); + *(TYPE_FUNC(&tmp)) = *TYPE_FUNC(declinfo->thetype); + tmp.flags |= FUNC_METHOD; + CError_Error(CErrorStr249, CError_GetObjectName(obj), obj->type, obj->qual, &tmp, declinfo->qual); + } + + if (TYPE_FUNC(declinfo->thetype)->exspecs || TYPE_FUNC(obj->type)->exspecs) + CExcept_CompareSpecifications(TYPE_FUNC(declinfo->thetype)->exspecs, TYPE_FUNC(obj->type)->exspecs); + } + + CDecl_FuncRedeclCheck(obj, declinfo, 0); + if (declinfo->x3C) { + if (obj->nspace->theclass && !(obj->nspace->theclass->flags & CLASS_IS_TEMPL_INST)) + CError_Error(CErrorStr335); + declinfo->x3C = 0; + } + } else { + if (TYPE_FUNC(declinfo->thetype)->flags & (FUNC_VOLATILE | FUNC_CONST)) + CError_Error(CErrorStr384); + + if (declinfo->operator_token && !CDecl_CheckOperatorType(declinfo, 0)) + return NULL; + + list = CScope_GetLocalObject(nspace2, declinfo->name); + if (declinfo->has_expltargs) + return CTempl_TemplateFunctionCheck(declinfo, list); + + if (list) { + if (copts.cplusplus) { + obj = CDecl_OverloadFunctionObject(list, declinfo, &outflag, OverloadMode0, someotherflag); + if (!obj) + return NULL; + if (pflag) + *pflag = outflag; + if (nspace) + obj->nspace = nspace; + } else { + obj = OBJECT(list->object); + if (!is_typesame(declinfo->thetype, obj->type) || (declinfo->qual & (Q_CONST | Q_PASCAL)) != (obj->qual & (Q_CONST | Q_PASCAL))) { + CError_Error(CErrorStr249, CError_GetObjectName(obj), obj->type, obj->qual, declinfo->thetype, declinfo->qual); + r27 = 1; + if (!IS_TYPE_FUNC(obj->type)) + return NULL; + } + } + + if (!r27 && pflag) + CDecl_FuncRedeclCheck(obj, declinfo, *pflag); + } else { + if (declinfo->nspace) + CError_Error(CErrorStr336); + + if (declinfo->has_expltargs) { + if (declinfo->name) + CError_Error(CErrorStr140, declinfo->name->name); + else + CError_Error(CErrorStr127); + } + + obj = CParser_NewFunctionObject(declinfo); + if (nspace) + obj->nspace = nspace; + if (pflag) + *pflag = 1; + else + CError_Error(CErrorStr127); + + CheckDefaultArgs(TYPE_FUNC(obj->type)->args); + CScope_AddObject(nspace2, declinfo->name, OBJ_BASE(obj)); + } + } + + return obj; +} + +void CDecl_TypedefDeclarator(DeclInfo *declinfo) { + NameSpace *nspace; + NameSpaceObjectList *list; + ObjType *objt; + + nspace = declinfo->nspace; + if (!nspace) + nspace = cscope_current; + + CError_QualifierCheck(declinfo->qual & ~(Q_ALIGNED_MASK | Q_REFERENCE | Q_PASCAL | Q_VOLATILE | Q_CONST)); + if (declinfo->x48 || declinfo->x44) + CError_Error(CErrorStr121); + if (declinfo->operator_token) + CError_Error(CErrorStr193); + + objt = NULL; + list = CScope_FindName(nspace, declinfo->name); + if (list) { + switch (list->object->otype) { + case OT_TYPE: + objt = OBJ_TYPE(list->object); + break; + case OT_TYPETAG: + break; + case OT_NAMESPACE: + CError_Error(CErrorStr321); + return; + case OT_ENUMCONST: + case OT_OBJECT: + CError_Error(CErrorStr322); + return; + default: + CError_FATAL(2156); + } + } + + if (objt) { + const UInt32 mask = Q_ALIGNED_MASK | Q_REFERENCE | Q_PASCAL | Q_VOLATILE | Q_CONST; + if (!is_typesame(objt->type, declinfo->thetype) || (objt->qual & mask) != (declinfo->qual & mask)) { + CError_Error(CErrorStr249, declinfo->name->name, objt->type, objt->qual, declinfo->thetype, declinfo->qual); + } else if (!copts.cplusplus && (copts.pedantic || copts.ANSIstrict)) { + if (copts.pedantic) + CError_Warning(CErrorStr122, declinfo->name->name); + else + CError_Error(CErrorStr122, declinfo->name->name); + } + return; + } + + objt = galloc(sizeof(ObjType)); + memclrw(objt, sizeof(ObjType)); + objt->otype = OT_TYPE; + objt->access = ACCESSPUBLIC; + objt->type = declinfo->thetype; + objt->qual = declinfo->qual; + CScope_AddObject(nspace, declinfo->name, OBJ_BASE(objt)); + + if (nspace->theclass && (nspace->theclass->flags & CLASS_IS_TEMPL) && + CTemplTool_IsTemplateArgumentDependentType(declinfo->thetype)) + CTemplClass_RegisterObjectDef(TEMPL_CLASS(nspace->theclass), OBJ_BASE(objt)); + + if (copts.cplusplus) { + if (IS_TYPE_CLASS(declinfo->thetype) && IsTempName(TYPE_CLASS(declinfo->thetype)->classname)) { + TYPE_CLASS(declinfo->thetype)->classname = declinfo->name; + TYPE_CLASS(declinfo->thetype)->nspace->name = declinfo->name; + } + if (IS_TYPE_ENUM(declinfo->thetype) && IsTempName(TYPE_ENUM(declinfo->thetype)->enumname)) { + TYPE_ENUM(declinfo->thetype)->enumname = declinfo->name; + } + } + + if (cparamblkptr->browseoptions.recordTypedefs && declinfo->file->recordbrowseinfo) + CBrowse_NewTypedef(nspace, declinfo->name, declinfo->file, declinfo->file2, declinfo->sourceoffset, CPrep_BrowserFileOffset()); +} + +static void CDecl_DataDeclarator(DeclInfo *declinfo, AccessType access, Boolean flag) { + NameSpaceObjectList *list; + Object *obj; + NameSpace *nspace; + Boolean tmpflag; + ENode *expr; + + nspace = declinfo->nspace; + if (!nspace) + nspace = cscope_current; + + CError_QualifierCheck(declinfo->qual & ~(Q_ALIGNED_MASK | Q_WEAK | Q_20000 | Q_PASCAL | Q_VOLATILE | Q_CONST)); + if (declinfo->x48 || declinfo->x44) + CError_Error(CErrorStr121); + if (declinfo->operator_token) + CError_Error(CErrorStr193); + + obj = NULL; + list = CScope_FindName(nspace, declinfo->name); + if (list) { + switch (list->object->otype) { + case OT_OBJECT: + obj = OBJECT(list->object); + if (flag) + CError_Error(CErrorStr122, declinfo->name->name); + break; + case OT_TYPETAG: + break; + case OT_NAMESPACE: + CError_Error(CErrorStr321); + return; + case OT_ENUMCONST: + case OT_TYPE: + CError_Error(CErrorStr322); + break; + case OT_MEMBERVAR: + CError_Error(CErrorStr221); + break; + default: + CError_FATAL(2281); + } + } + + if (copts.cplusplus) { + if (!flag) + CDecl_CompleteType(declinfo->thetype); + switch (declinfo->storageclass) { + case TK_EXTERN: + if (tk == '=' || tk == '(') + declinfo->storageclass = 0; + break; + case 0: + if (CParser_IsConst(declinfo->thetype, declinfo->qual)) { + if ((!obj && !nspace->theclass) || (obj && obj->sclass != TK_EXTERN && !obj->nspace->theclass)) + declinfo->storageclass = TK_STATIC; + } + break; + } + } else { + if (declinfo->storageclass == TK_EXTERN && tk == '=') + declinfo->storageclass = 0; + } + + if (IS_TYPE_ARRAY(declinfo->thetype) && !declinfo->thetype->size && !declinfo->storageclass && tk != '=') + declinfo->storageclass = TK_EXTERN; + + if (obj) { + if ((!obj->type->size || !declinfo->thetype->size) && IS_TYPE_ARRAY(declinfo->thetype) && IS_TYPE_ARRAY(obj->type)) + tmpflag = is_typesame(TYPE_POINTER(declinfo->thetype)->target, TYPE_POINTER(obj->type)->target); + else + tmpflag = is_typesame(declinfo->thetype, obj->type); + + if (!tmpflag || (obj->qual & (Q_PASCAL | Q_VOLATILE | Q_CONST)) != (declinfo->qual & (Q_PASCAL | Q_VOLATILE | Q_CONST))) + CError_Error(CErrorStr249, CError_GetObjectName(obj), obj->type, obj->qual, declinfo->thetype, declinfo->qual); + + if (obj->qual & Q_INLINE_DATA) { + if (tk == ',' || tk == ';') + return; + CError_Error(CErrorStr333, obj); + } + + if (declinfo->storageclass != TK_EXTERN) { + if (obj->sclass != TK_EXTERN && declinfo->storageclass && obj->sclass != declinfo->storageclass) + CError_Error(CErrorStr333, obj); + + if (tmpflag) { + obj->sclass = declinfo->storageclass; + obj->qual |= declinfo->qual; + if (declinfo->thetype->size) + obj->type = declinfo->thetype; + } + + CParser_UpdateObject(obj, declinfo); + } else { + flag = 1; + } + } else { + if (declinfo->nspace) + CError_Error(CErrorStr336); + if (IS_TYPE_CLASS(declinfo->thetype) && TYPE_CLASS(declinfo->thetype)->sominfo) + CError_Error(CErrorStr288); + if (!CanCreateObject(declinfo->thetype)) + declinfo->thetype = TYPE(&stsignedint); + + obj = CParser_NewGlobalDataObject(declinfo); + obj->access = access; + CScope_AddObject(nspace, declinfo->name, OBJ_BASE(obj)); + + if (nspace->theclass && (nspace->theclass->flags & CLASS_IS_TEMPL) && + CTemplTool_IsTemplateArgumentDependentType(declinfo->thetype)) + CTemplClass_RegisterObjectDef(TEMPL_CLASS(nspace->theclass), OBJ_BASE(obj)); + + if (flag && nspace->theclass && cparamblkptr->browseoptions.recordClasses) + CBrowse_AddClassMemberData(obj, CPrep_BrowserTokenOffset(&member_fileoffset) + 1, CPrep_BrowserFileOffset()); + } + + if (!flag) { + if (declinfo->nspace) { + CScopeSave save; + CScope_SetNameSpaceScope(declinfo->nspace, &save); + CInit_InitializeData(obj); + CScope_RestoreScope(&save); + + if (declinfo->x3C && obj->nspace->theclass && (TYPE_CLASS(obj->nspace->theclass)->flags & CLASS_IS_TEMPL_INST)) + declinfo->x3C = 0; + } else { + CInit_InitializeData(obj); + } + + if (declinfo->file->recordbrowseinfo && obj->sclass != TK_EXTERN) + CBrowse_NewData(obj, declinfo->file, declinfo->file2, declinfo->sourceoffset, CPrep_BrowserFileOffset()); + } else if (tk == '=') { + tk = lex(); + expr = CExpr_IntegralConstOrDepExpr(); + if (IS_TYPE_TEMPLATE(obj->type) || !ENODE_IS(expr, EINTCONST)) { + CError_ASSERT(2426, nspace->theclass && (nspace->theclass->flags & CLASS_IS_TEMPL)); + CTemplClass_RegisterObjectInit(TEMPL_CLASS(nspace->theclass), obj, expr); + } else if ((obj->qual & Q_CONST) && IS_TYPE_INT_OR_ENUM(obj->type)) { + obj->u.data.u.intconst = expr->data.intval; + obj->qual |= Q_INLINE_DATA | Q_20000; + } else { + CError_Error(CErrorStr354, obj->name->name); + } + } +} + +Boolean CDecl_FunctionDeclarator(DeclInfo *declinfo, NameSpace *nspace, Boolean flag, Boolean flag2) { + Object *obj; + Boolean pflag; + + obj = CDecl_GetFunctionObject(declinfo, nspace, &pflag, 0); + if (obj) { + if (declinfo->x44 || tk == '{' || tk == TK_TRY || (declinfo->x4B && tk == ':') || (!copts.cplusplus && isdeclaration(0, 0, 0, 0))) { + if (!flag || cscope_currentfunc) { + CError_Error(CErrorStr127); + if (cscope_currentfunc) + return 0; + } + + if (obj->nspace == cscope_root && !strcmp(obj->name->name, "main")) { + if (obj->sclass == TK_STATIC || (copts.ANSIstrict && TYPE_FUNC(obj->type)->functype != (Type *) &stsignedint)) + CError_Error(CErrorStr334); + } else if (copts.checkprotos && (pflag || declinfo->x64)) { + if (obj->sclass != TK_STATIC && !(obj->qual & Q_INLINE) && !obj->nspace->is_unnamed) + CError_Warning(CErrorStr178); + } + + CFunc_ParseFuncDef(obj, declinfo, NULL, 0, 0, NULL); + if (declinfo->file->recordbrowseinfo) + CBrowse_NewFunction( + obj, + declinfo->file, + declinfo->file2, + declinfo->sourceoffset, + CPrep_BrowserFileOffset()); + + if (copts.cplusplus && lookahead() == ';') + tk = lex(); + return 0; + } + } + + return 1; +} + +static void CDecl_ParseSpecialMember(DeclInfo *declinfo, Boolean flag) { + Object *r28; + NameSpace *r25; + + if (!(r28 = declinfo->x10)) { + CError_ASSERT(2544, declinfo->x14); + r28 = OBJECT(declinfo->x14->object); + CError_ASSERT(2546, r28->otype == OT_OBJECT); + } + + if (!r28->nspace->theclass) { + CError_Error(CErrorStr121); + return; + } + + if (IS_TYPE_FUNC(r28->type)) { + if (TYPE_FUNC(r28->type)->flags & (FUNC_IS_CTOR | FUNC_IS_DTOR)) { + if (r28->nspace->theclass->sominfo) + declinfo->thetype = TYPE(&stvoid); + else + declinfo->thetype = TYPE(&void_ptr); + declinfo->nspace = r28->nspace; + declinfo->name = r28->name; + if (TYPE_FUNC(r28->type)->flags & FUNC_IS_CTOR) + declinfo->x4B = 1; + + if ((tk = lex()) == '(') { + tk = lex(); + + r25 = cscope_current; + cscope_current = r28->nspace; + CDecl_ParseDirectFuncDecl(declinfo); + cscope_current = r25; + + if (IS_TYPE_FUNC(declinfo->thetype)) { + if (TYPE_FUNC(r28->type)->flags & FUNC_IS_CTOR) { + if ((r28->nspace->theclass->flags & CLASS_HAS_VBASES) && !r28->nspace->theclass->sominfo) + CDecl_AddArgument(TYPE_FUNC(declinfo->thetype), TYPE(&stsignedshort)); + } else { + if (!r28->nspace->theclass->sominfo) + CDecl_AddArgument(TYPE_FUNC(declinfo->thetype), TYPE(&stsignedshort)); + } + if (flag) + CDecl_FunctionDeclarator(declinfo, NULL, 1, 1); + } else { + CError_Error(CErrorStr121); + } + } else { + CError_Error(CErrorStr114); + } + return; + } else if (TYPE_FUNC(r28->type)->flags & FUNC_CONVERSION) { + CError_FATAL(2603); + + declinfo->thetype = TYPE_FUNC(r28->type)->functype; + declinfo->qual |= TYPE_FUNC(r28->type)->qual; + declinfo->nspace = r28->nspace; + declinfo->name = r28->name; + + if ((tk = lex()) == '(') { + tk = lex(); + CDecl_ParseDirectFuncDecl(declinfo); + if (IS_TYPE_FUNC(declinfo->thetype)) { + TYPE_FUNC(declinfo->thetype)->flags |= FUNC_CONVERSION; + if (flag) + CDecl_FunctionDeclarator(declinfo, NULL, 1, 1); + } else { + CError_Error(CErrorStr121); + } + } else { + CError_Error(CErrorStr114); + } + return; + } else { + declinfo->thetype = TYPE(&stsignedint); + declinfo->nspace = r28->nspace; + declinfo->name = r28->name; + + if ((tk = lex()) == '(') { + tk = lex(); + + r25 = cscope_current; + cscope_current = r28->nspace; + CDecl_ParseDirectFuncDecl(declinfo); + cscope_current = r25; + + if (IS_TYPE_FUNC(declinfo->thetype)) { + if (flag) + CDecl_FunctionDeclarator(declinfo, NULL, 1, 1); + return; + } + } else { + CError_Error(CErrorStr114); + } + } + } + + CError_Error(CErrorStr121); +} + +void CDecl_ScanDeclarator(DeclInfo *declinfo) { + if (declinfo->x14 || declinfo->x10) { + CDecl_ParseSpecialMember(declinfo, 0); + CDecl_GetFunctionObject(declinfo, NULL, NULL, 1); + return; + } + + if (IS_TYPE_FUNC(declinfo->thetype)) { + TypeFunc *copy = galloc(sizeof(TypeFunc)); + *copy = *TYPE_FUNC(declinfo->thetype); + declinfo->thetype = TYPE(copy); + } + scandeclarator(declinfo); + if (!declinfo->name) { + CError_Error(CErrorStr121); + return; + } + + if (declinfo->storageclass && declinfo->storageclass != TK_EXTERN) + CError_Error(CErrorStr177); + + if (IS_TYPE_FUNC(declinfo->thetype)) { + CDecl_GetFunctionObject(declinfo, NULL, NULL, 1); + return; + } + + if (declinfo->x48 || declinfo->x44) + CError_Error(CErrorStr121); + + if (declinfo->operator_token) + CError_Error(CErrorStr193); + + if ( + (declinfo->qual & ~(Q_ALIGNED_MASK | Q_WEAK | Q_20000 | Q_PASCAL | Q_VOLATILE | Q_CONST)) || + (declinfo->storageclass == TK_TYPEDEF && (declinfo->qual & ~(Q_ALIGNED_MASK | Q_REFERENCE | Q_PASCAL | Q_VOLATILE | Q_CONST))) + ) + CError_Error(CErrorStr176); +} + +void scandeclaratorlist(DeclInfo *declinfo) { + CScopeSave savescope; + Type *r30; + UInt32 r29; + Boolean r28; + + if (declinfo->x14 || declinfo->x10) { + CDecl_ParseSpecialMember(declinfo, 1); + return; + } + + CScope_GetScope(&savescope); + CError_ASSERT(2707, declinfo->thetype); + + r28 = 1; + while (1) { + r30 = declinfo->thetype; + r29 = declinfo->qual; + declinfo->nspace = NULL; + declinfo->operator_token = 0; + if (IS_TYPE_FUNC(r30)) { + declinfo->thetype = galloc(sizeof(TypeFunc)); + *TYPE_FUNC(declinfo->thetype) = *TYPE_FUNC(r30); + } + declinfo->name = NULL; + scandeclarator(declinfo); + if (!declinfo->name) { + CError_Error(CErrorStr121); + break; + } + + if (declinfo->storageclass != TK_TYPEDEF) { + if (IS_TYPE_FUNC(declinfo->thetype)) { + if (!CDecl_FunctionDeclarator(declinfo, NULL, r28, 1)) + return; + } else { + CDecl_DataDeclarator(declinfo, ACCESSPUBLIC, 0); + } + } else { + CDecl_TypedefDeclarator(declinfo); + } + + CScope_RestoreScope(&savescope); + declinfo->thetype = r30; + declinfo->qual = r29; + + if (tk != ',') + break; + tk = lex(); + r28 = 0; + } + + if (tk != ';') + CError_Error(CErrorStr123); +} + +static TypeIntegral *CDecl_FindSignedType(short size) { + if (stsignedchar.size == size) + return &stsignedchar; + if (stsignedshort.size == size) + return &stsignedshort; + if (stsignedint.size == size) + return &stsignedint; + if (stsignedlong.size == size) + return &stsignedlong; + if (copts.longlong && copts.longlong_enums && stsignedlonglong.size == size) + return &stsignedlonglong; + return &stsignedlong; +} + +static TypeIntegral *CDecl_FindUnsignedType(short size) { + if (stunsignedchar.size == size) + return &stunsignedchar; + if (stunsignedshort.size == size) + return &stunsignedshort; + if (stunsignedint.size == size) + return &stunsignedint; + if (stunsignedlong.size == size) + return &stunsignedlong; + if (copts.longlong && copts.longlong_enums && stunsignedlonglong.size == size) + return &stunsignedlonglong; + return &stunsignedlong; +} + +static TypeIntegral *CDecl_IterateIntegralEnumType(int *t) { + switch (*t) { + case 0: + *t = 1; + return &stsignedchar; + case 1: + if (stsignedshort.size > stsignedchar.size) { + *t = 2; + return &stsignedshort; + } + case 2: + if (stsignedint.size > stsignedshort.size) { + *t = 3; + return &stsignedint; + } + case 3: + if (stsignedlong.size > stsignedint.size) { + *t = 4; + return &stsignedlong; + } + case 4: + *t = 5; + if (stsignedlonglong.size > stsignedlong.size && copts.longlong && copts.longlong_enums) + return &stsignedlonglong; + default: + return NULL; + } +} + +static TypeIntegral *CDecl_IterateUIntegralEnumType(int *t) { + switch (*t) { + case 0: + *t = 1; + return &stunsignedchar; + case 1: + if (stunsignedshort.size > stunsignedchar.size) { + *t = 2; + return &stunsignedshort; + } + case 2: + if (stunsignedint.size > stunsignedshort.size) { + *t = 3; + return &stunsignedint; + } + case 3: + if (stunsignedlong.size > stunsignedint.size) { + *t = 4; + return &stunsignedlong; + } + case 4: + *t = 5; + if (stunsignedlonglong.size > stunsignedlong.size && copts.longlong && copts.longlong_enums) + return &stunsignedlonglong; + default: + return NULL; + } +} + +static TypeEnum *CDecl_OldParseEnumList(TypeEnum *tenum, HashNameNode *name) { + AccessType access; + Boolean has_template_value; + Boolean r24; + Boolean r23; + ObjEnumConst *oec; + ObjEnumConst *last; + Boolean overflowed; + CInt64 val; + CInt64 minimum; + CInt64 maximum; + CInt64 var_74; + CInt64 unused; + Type *basetype; + Type *basetype2; + CPrepFileInfo *fileinfo; + SInt32 offset; + ENode *expr; + Type *tmp; + + if (!tenum) { + tenum = galloc(sizeof(TypeEnum)); + memclrw(tenum, sizeof(TypeEnum)); + tenum->type = TYPEENUM; + tenum->nspace = cscope_current; + + if (name) { + tenum->enumname = name; + CScope_DefineTypeTag(cscope_current, name, TYPE(tenum)); + } + + if (!cscope_current->is_global) { + do { + tenum->nspace = tenum->nspace->parent; + } while (!tenum->nspace->is_global); + if (tenum->enumname) + tenum->enumname = CParser_AppendUniqueNameFile(tenum->enumname->name); + } + } + + if (cscope_current->theclass && (cscope_current->theclass->flags & CLASS_IS_TEMPL)) { + CTemplClass_RegisterEnumType(TEMPL_CLASS(cscope_current->theclass), tenum); + } + + access = cscope_current->theclass ? global_access : ACCESSPUBLIC; + last = NULL; + unused = cint64_zero; + val = cint64_zero; + minimum = cint64_zero; + maximum = cint64_zero; + r23 = 0; + if (copts.enumsalwaysint) { + basetype = TYPE(&stsignedint); + r24 = 1; + } else { + basetype = TYPE(&stunsignedchar); + r24 = 0; + } + + tk = lex(); + if (!copts.cplusplus || tk != '}') { + do { + if (tk != TK_IDENTIFIER) { + if (tk == '}') { + if (copts.cpp_extensions) + break; + if (!copts.warn_extracomma) + break; + } + CError_Warning(CErrorStr107); + break; + } + + oec = galloc(sizeof(ObjEnumConst)); + memclrw(oec, sizeof(ObjEnumConst)); + oec->otype = OT_ENUMCONST; + oec->access = access; + oec->type = TYPE(tenum); + oec->name = tkidentifier; + CPrep_BrowserFilePosition(&fileinfo, &offset); + overflowed = 0; + if ((tk = lex()) == '=') { + tk = lex(); + val = CExpr_IntegralConstExprType(&basetype2); + if (!CInt64_IsNegative(&val) || is_unsigned(basetype2)) { + if (CInt64_GreaterU(val, minimum)) { + minimum = val; + overflowed = 1; + } + } else { + if (CInt64_Less(val, maximum)) { + maximum = val; + overflowed = 1; + } + if (!r24) { + basetype = TYPE(&stsignedchar); + r24 = 1; + } + } + r23 = 0; + } else { + if (r23) + CError_Error(CErrorStr154); + + if (!r24 || !CInt64_IsNegative(&val)) { + if (CInt64_GreaterU(val, minimum)) { + minimum = val; + overflowed = 1; + } + } else { + if (CInt64_Less(val, maximum)) { + maximum = val; + overflowed = 1; + } + } + } + + if (copts.enumsalwaysint) { + if (copts.ANSIstrict) { + if (!CInt64_IsInRange(val, stsignedint.size)) + CError_Error(CErrorStr154); + } else { + if (!CInt64_IsInRange(val, stsignedint.size) && !CInt64_IsInURange(val, stunsignedint.size)) + CError_Error(CErrorStr154); + } + } else if (r24) { + switch (basetype->size) { + case 1: + if (CInt64_IsInRange(minimum, 1) && CInt64_IsInRange(maximum, 1)) + break; + basetype = TYPE(CDecl_FindSignedType(2)); + case 2: + if (CInt64_IsInRange(minimum, 2) && CInt64_IsInRange(maximum, 2)) + break; + basetype = TYPE(CDecl_FindSignedType(4)); + case 4: + if (CInt64_IsInRange(minimum, 4) && CInt64_IsInRange(maximum, 4)) + break; + basetype = TYPE(CDecl_FindSignedType(8)); + if (basetype->size != 8) { + if (!copts.ANSIstrict && CInt64_IsInRange(maximum, 4) && CInt64_IsInURange(minimum, 4)) + break; + if (overflowed) + CError_Error(CErrorStr154); + break; + } + case 8: + if (CInt64_Equal(val, minimum) && CInt64_IsNegative(&val)) + CError_Error(CErrorStr154); + break; + default: + CError_FATAL(3071); + } + } else { + switch (basetype->size) { + case 1: + if (CInt64_IsInURange(minimum, 1)) + break; + basetype = TYPE(CDecl_FindUnsignedType(2)); + case 2: + if (CInt64_IsInURange(minimum, 2)) + break; + basetype = TYPE(CDecl_FindUnsignedType(4)); + case 4: + if (CInt64_IsInURange(minimum, 4)) + break; + basetype = TYPE(CDecl_FindUnsignedType(8)); + if (basetype->size != 8) { + if (overflowed) + CError_Error(CErrorStr154); + break; + } + case 8: + break; + default: + CError_FATAL(3099); + } + } + + tenum->size = basetype->size; + tenum->enumtype = basetype; + oec->val = val; + CScope_AddObject(cscope_current, oec->name, OBJ_BASE(oec)); + + if (last) { + last->next = oec; + last = oec; + } else { + last = oec; + tenum->enumlist = oec; + } + + if (cparamblkptr->browseoptions.recordEnums) { + CPrepFileInfo *f = CPrep_BrowserCurrentFile(); + if (f->recordbrowseinfo) { + CBrowse_NewEnumConstant(cscope_current, oec->name, f, fileinfo, offset, CPrep_BrowserFileOffset()); + } + } + + var_74 = CInt64_Add(val, cint64_one); + if (r24) { + if (CInt64_IsNegative(&var_74) && !CInt64_IsNegative(&val)) + r23 = 1; + } else { + if (CInt64_IsZero(&var_74)) + r23 = 1; + } + val = var_74; + + if (tk != ',') + break; + tk = lex(); + } while (1); + } + + tenum->size = basetype->size; + tenum->enumtype = basetype; + + for (oec = tenum->enumlist; oec; oec = oec->next) + oec->type = TYPE(tenum); + + if (tk != '}') + CError_ErrorSkip(CErrorStr130); + else + tk = lex(); + + return tenum; +} + +static Type *CDecl_MaxType(Type *a, Type *b) { + if (a->size > b->size) + return a; + if (b->size > a->size) + return b; + if (is_unsigned(b)) + return b; + else + return a; +} + +void CDecl_ComputeUnderlyingEnumType(TypeEnum *tenum) { + ObjEnumConst *oec; + ObjEnumConst *oec2; + Type *r26; + int t; + + if (!copts.enumsalwaysint) { + for (oec2 = tenum->enumlist; oec2; oec2 = oec2->next) { + if (CInt64_IsNegative(&oec2->val) && !is_unsigned(oec2->type)) + break; + } + + if (oec2) { + CInt64 unused = cint64_zero; + CInt64 minimum = cint64_zero; + CInt64 maximum = cint64_zero; + for (oec = tenum->enumlist; oec; oec = oec->next) { + if (CInt64_IsNegative(&oec->val) && !is_unsigned(oec->type)) { + if (CInt64_Less(oec->val, minimum)) + minimum = oec->val; + } else { + if (CInt64_GreaterU(oec->val, maximum)) + maximum = oec->val; + } + } + + if (CInt64_IsNegative(&maximum)) + CError_Error(CErrorStr154); + + t = 0; + do { + r26 = TYPE(CDecl_IterateIntegralEnumType(&t)); + if (!r26) { + r26 = TYPE(&stsignedlong); + CError_Error(CErrorStr154); + break; + } + + if (CInt64_IsInRange(maximum, r26->size) && CInt64_IsInRange(minimum, r26->size)) + break; + if (r26->size == stsignedlong.size && !copts.ANSIstrict && CInt64_IsInRange(minimum, r26->size) && CInt64_IsInURange(maximum, r26->size)) + break; + } while (1); + } else { + CInt64 val = cint64_zero; + + for (oec = tenum->enumlist; oec; oec = oec->next) { + if (CInt64_GreaterU(oec->val, val)) + val = oec->val; + } + + t = 0; + do { + r26 = TYPE(CDecl_IterateUIntegralEnumType(&t)); + if (!r26) { + r26 = TYPE(&stunsignedlong); + CError_Error(CErrorStr154); + break; + } + if (CInt64_IsInURange(val, r26->size)) + break; + } while (1); + } + } else { + r26 = TYPE(&stsignedint); + } + + tenum->size = r26->size; + tenum->enumtype = r26; + for (oec = tenum->enumlist; oec; oec = oec->next) + oec->type = TYPE(tenum); +} + +static Type *CDecl_FindUnderlyingType(short size, CInt64 *a, CInt64 *b) { + if (CInt64_IsZero(a)) { + if (size <= stsignedchar.size && CInt64_IsInURange(*b, stunsignedchar.size)) + return TYPE(&stunsignedchar); + if (size <= stsignedshort.size && CInt64_IsInURange(*b, stunsignedshort.size)) + return TYPE(&stunsignedshort); + if (size <= stsignedint.size && CInt64_IsInURange(*b, stunsignedint.size)) + return TYPE(&stunsignedint); + if (size <= stsignedlong.size && CInt64_IsInURange(*b, stunsignedlong.size)) + return TYPE(&stunsignedlong); + if (size <= stsignedlonglong.size && copts.longlong && copts.longlong_enums && CInt64_IsInURange(*b, stunsignedlonglong.size)) + return TYPE(&stunsignedlonglong); + } else { + if (size <= stsignedchar.size && CInt64_IsInRange(*a, stsignedchar.size) && CInt64_IsInRange(*b, stsignedchar.size)) + return TYPE(&stsignedchar); + if (size <= stsignedshort.size && CInt64_IsInRange(*a, stsignedshort.size) && CInt64_IsInRange(*b, stsignedshort.size)) + return TYPE(&stsignedshort); + if (size <= stsignedint.size && CInt64_IsInRange(*a, stsignedint.size) && CInt64_IsInRange(*b, stsignedint.size)) + return TYPE(&stsignedint); + if (size <= stsignedlong.size && CInt64_IsInRange(*a, stsignedlong.size) && CInt64_IsInRange(*b, stsignedlong.size)) + return TYPE(&stsignedlong); + if (size <= stsignedlonglong.size && copts.longlong && copts.longlong_enums && CInt64_IsInRange(*a, stsignedlonglong.size) && CInt64_IsInRange(*b, stsignedlonglong.size)) + return TYPE(&stsignedlonglong); + if (!copts.ANSIstrict && size <= stsignedlong.size && CInt64_IsInRange(*a, stsignedlong.size) && CInt64_IsInURange(*b, stunsignedlong.size)) + return TYPE(&stsignedlong); + } + + return NULL; +} + +static TypeEnum *CDecl_ParseEnumList(TypeEnum *tenum, HashNameNode *name) { + AccessType access; + TemplClass *tmclass; + ObjEnumConst *oec; + Boolean has_template_value; + Boolean overflowed; + Boolean is_first; + CInt64 val; + CInt64 minimum; + CInt64 maximum; + CInt64 unused; + Type *basetype; + CPrepFileInfo *fileinfo; + SInt32 offset; + ENode *expr; + Type *tmp; + ObjEnumConst *last; + + if (!tenum) { + tenum = galloc(sizeof(TypeEnum)); + memclrw(tenum, sizeof(TypeEnum)); + tenum->type = TYPEENUM; + tenum->nspace = cscope_current; + + if (name) { + tenum->enumname = name; + CScope_DefineTypeTag(cscope_current, name, TYPE(tenum)); + } + + if (!cscope_current->is_global) { + do { + tenum->nspace = tenum->nspace->parent; + } while (!tenum->nspace->is_global); + if (tenum->enumname) + tenum->enumname = CParser_AppendUniqueNameFile(tenum->enumname->name); + } + } + + if (cscope_current->theclass && (cscope_current->theclass->flags & CLASS_IS_TEMPL)) { + tmclass = TEMPL_CLASS(cscope_current->theclass); + CTemplClass_RegisterEnumType(tmclass, tenum); + } else { + tmclass = NULL; + } + + access = cscope_current->theclass ? global_access : ACCESSPUBLIC; + last = NULL; + is_first = 1; + has_template_value = 0; + unused = cint64_zero; + val = cint64_zero; + minimum = cint64_zero; + maximum = cint64_zero; + basetype = copts.enumsalwaysint ? TYPE(&stsignedint) : TYPE(&stsignedchar); + tenum->size = basetype->size; + tenum->enumtype = basetype; + + do { + if ((tk = lex()) != TK_IDENTIFIER) { + if (tk == '}') { + if (is_first) { + if (copts.cplusplus) + break; + } else { + if (!copts.warn_extracomma) + break; + if (copts.c9x) + break; + if (copts.cpp_extensions) + break; + } + CError_Warning(CErrorStr107); + } else { + CError_Error(CErrorStr107); + } + break; + } + + oec = galloc(sizeof(ObjEnumConst)); + memclrw(oec, sizeof(ObjEnumConst)); + oec->otype = OT_ENUMCONST; + oec->access = access; + oec->name = tkidentifier; + CPrep_BrowserFilePosition(&fileinfo, &offset); + overflowed = 0; + if ((tk = lex()) == '=') { + tk = lex(); + if (tmclass) { + expr = CExpr_IntegralConstOrDepExpr(); + if (ENODE_IS(expr, EINTCONST)) { + val = expr->data.intval; + basetype = expr->rtype; + has_template_value = 0; + } else { + val = cint64_zero; + basetype = TYPE(tenum); + CTemplClass_RegisterEnumerator(tmclass, oec, expr); + has_template_value = 1; + } + } else { + val = CExpr_IntegralConstExprType(&basetype); + has_template_value = 0; + } + } else if (has_template_value) { + CTemplClass_RegisterEnumerator(tmclass, oec, NULL); + } else if (!is_first) { + if (is_unsigned(basetype)) { + val = CInt64_Add(val, cint64_one); + if (CInt64_IsZero(&val)) + overflowed = 1; + } else if (!CInt64_IsNegative(&val)) { + val = CInt64_Add(val, cint64_one); + if (CInt64_IsNegative(&val)) + overflowed = 1; + } else { + val = CInt64_Add(val, cint64_one); + } + } + + if (!has_template_value) { + if (copts.enumsalwaysint) { + if (!CInt64_IsInRange(val, stsignedint.size) && (copts.ANSIstrict || !CInt64_IsInURange(val, stunsignedint.size))) + overflowed = 1; + basetype = TYPE(&stsignedint); + } else if (CInt64_IsNegative(&val) && !is_unsigned(basetype)) { + if (CInt64_Less(val, minimum)) { + minimum = val; + if ((tmp = CDecl_FindUnderlyingType(tenum->size, &minimum, &maximum))) { + tenum->size = tmp->size; + tenum->enumtype = tmp; + } else { + overflowed = 1; + } + } + } else { + if (CInt64_GreaterU(val, maximum)) { + maximum = val; + if ((tmp = CDecl_FindUnderlyingType(tenum->size, &minimum, &maximum))) { + tenum->size = tmp->size; + tenum->enumtype = tmp; + } else { + overflowed = 1; + } + } + } + } + + if (overflowed) + CError_Error(CErrorStr154); + + oec->val = val; + oec->type = basetype; + CScope_AddObject(cscope_current, oec->name, OBJ_BASE(oec)); + + if (last) { + last->next = oec; + last = oec; + } else { + last = oec; + tenum->enumlist = oec; + } + + if (cparamblkptr->browseoptions.recordEnums) { + CPrepFileInfo *f = CPrep_BrowserCurrentFile(); + if (f->recordbrowseinfo) { + CBrowse_NewEnumConstant(cscope_current, oec->name, f, fileinfo, offset, CPrep_BrowserFileOffset()); + } + } + + is_first = 0; + } while (tk == ','); + + for (oec = tenum->enumlist; oec; oec = oec->next) + oec->type = TYPE(tenum); + + if (tk != '}') + CError_ErrorSkip(CErrorStr130); + else + tk = lex(); + + return tenum; +} + +void scanenum(DeclInfo *declinfo) { + HashNameNode *name; + Type *type; + NameResult pr; + + if (tk == '{') { + declinfo->thetype = TYPE(CDecl_ParseEnumList(NULL, NULL)); + TYPE_ENUM(declinfo->thetype)->enumname = CParser_AppendUniqueNameFile("@enum"); + return; + } + + if (tk == TK_IDENTIFIER) { + name = tkidentifier; + if (lookahead() == '{') { + type = CScope_GetLocalTagType(cscope_current, name); + if (type) { + lex(); + do_shit: + if (type->size || !IS_TYPE_ENUM(type)) { + CError_Error(CErrorStr122, name->name); + declinfo->thetype = TYPE(CDecl_ParseEnumList(NULL, NULL)); + return; + } + declinfo->thetype = TYPE(CDecl_ParseEnumList(TYPE_ENUM(type), NULL)); + } else { + lex(); + declinfo->thetype = TYPE(CDecl_ParseEnumList(NULL, name)); + } + + if (cparamblkptr->browseoptions.recordEnums && declinfo->file->recordbrowseinfo) + CBrowse_NewEnum( + cscope_current, + TYPE_ENUM(declinfo->thetype)->enumname, + declinfo->file, + declinfo->file2, + declinfo->sourceoffset, + CPrep_BrowserFileOffset()); + return; + } else { + CError_ASSERT(3851, !copts.cplusplus || tk != ';'); + tkidentifier = name; + } + } + + if (CScope_ParseElaborateName(&pr)) { + if ((type = pr.type)) { + if (!IS_TYPE_ENUM(type)) + CError_Error(CErrorStr121); + if ((tk = lex()) == '{') + goto do_shit; + declinfo->thetype = type; + return; + } else { + CError_ASSERT(3865, pr.name_4); + if ((tk = lex()) == '{') { + declinfo->thetype = TYPE(CDecl_ParseEnumList(NULL, pr.name_4)); + return; + } else { + CError_Error(CErrorStr140, pr.name_4->name); + } + } + } else { + CError_Error(CErrorStr121); + } + + declinfo->thetype = TYPE(&stsignedint); +} + +void CDecl_ScanStructDeclarator(BigDeclInfo *bde) { + ENode *expr; + short val; + short bits; + Boolean is_bitfield; + TypeTemplDep *ttempl; + TypeBitfield *tbitfield; + Type *type; + + bde->declinfo2 = bde->declinfo; + bde->declinfo2.name = NULL; + bde->declinfo2.operator_token = 0; + bde->xCD = 0; + is_bitfield = 0; + + if (tk == ':') { + bde->declinfo2.name = no_name_node; + is_bitfield = 1; + } else { + bde->declinfo2.x50 = 1; + scandeclarator(&bde->declinfo2); + if (!bde->declinfo2.name) { + CError_Error(CErrorStr131); + return; + } + + if ((!copts.ANSIstrict || copts.c9x) && !bde->declinfo2.thetype->size && IS_TYPE_ARRAY(bde->declinfo2.thetype)) { + if (bde->declinfo2.storageclass != TK_STATIC && bde->declinfo2.storageclass != TK_TYPEDEF) { + type = TYPE_POINTER(bde->declinfo2.thetype)->target; + while (IS_TYPE_ARRAY(type)) + type = TYPE_POINTER(type)->target; + if (!IsCompleteType(type)) + return; + if (tk != ';' || lookahead() != '}') { + CError_Error(CErrorStr145); + return; + } + } + } else { + if (bde->declinfo2.storageclass != TK_STATIC && bde->declinfo2.storageclass != TK_TYPEDEF) { + if (!IS_TYPE_FUNC(bde->declinfo2.thetype) && !IsCompleteType(bde->declinfo2.thetype)) + return; + } + } + + if (IS_TYPE_CLASS(bde->declinfo2.thetype) && TYPE_CLASS(bde->declinfo2.thetype)->sominfo) { + CError_Error(CErrorStr287); + return; + } + + if (tk != ':') + goto not_a_bitfield; + } + + if (!IS_TYPE_INT_OR_ENUM(bde->declinfo2.thetype)) { + if (CTemplTool_IsTemplateArgumentDependentType(bde->declinfo2.thetype)) + goto fuckup; + CError_Error(CErrorStr138); + bde->declinfo2.thetype = TYPE(&stunsignedint); + } else if (copts.ANSIstrict && !copts.cplusplus) { + if (bde->declinfo2.thetype != TYPE(&stsignedint) && bde->declinfo2.thetype != TYPE(&stunsignedint)) { + CError_Error(CErrorStr138); + bde->declinfo2.thetype = TYPE(&stunsignedint); + } + } + + switch (bde->declinfo2.thetype->size) { + case 1: + bits = 8; + break; + case 2: + bits = 16; + break; + case 4: + bits = 32; + break; + default: + CError_Error(CErrorStr138); + return; + } +fuckup: + tk = lex(); + expr = CExpr_IntegralConstOrDepExpr(); + if (!ENODE_IS(expr, EINTCONST)) { + ttempl = TYPE_TEMPLATE(CDecl_NewTemplDepType(TEMPLDEP_BITFIELD)); + ttempl->u.bitfield.type = bde->declinfo2.thetype; + ttempl->u.bitfield.size = CInline_CopyExpression(expr, CopyMode1); + bde->declinfo2.thetype = TYPE(ttempl); + bde->xCD = 1; + return; + } + val = CInt64_GetULong(&expr->data.intval); + if (is_bitfield) { + if (val < 0 || val > bits) { + CError_Error(CErrorStr138); + return; + } + } else { + if (val <= 0 || val > bits) { + CError_Error(CErrorStr138); + return; + } + } + + tbitfield = galloc(sizeof(TypeBitfield)); + memclrw(tbitfield, sizeof(TypeBitfield)); + tbitfield->type = TYPEBITFIELD; + tbitfield->size = bde->declinfo2.thetype->size; + tbitfield->bitfieldtype = bde->declinfo2.thetype; + tbitfield->bitlength = val; + bde->declinfo2.thetype = TYPE(tbitfield); + + if (tk == TK_UU_ATTRIBUTE_UU) + CParser_ParseAttribute(NULL, &bde->declinfo2); + +not_a_bitfield: + bde->xCD = 1; +} + +static void CDecl_LayoutStruct(TypeStruct *tstruct) { + StructMember *member; + SInt32 r28; + StructMember *innermember; + SInt32 innerbase; + StructMember *newmember; + StructMember **memberp; + TypeBitfield *bf; + SInt32 r24; + Boolean r23; + SInt32 tmp; + + r28 = 0; + r23 = 0; + CMach_StructLayoutInitOffset(0); + for (member = tstruct->members; member; member = member->next) { + if (tstruct->stype == STRUCT_TYPE_UNION) + CMach_StructLayoutInitOffset(0); + + if (IS_TYPE_BITFIELD(member->type)) + member->offset = CMach_StructLayoutBitfield(TYPE_BITFIELD(member->type), member->qual); + else + member->offset = CMach_StructLayoutGetOffset(member->type, member->qual); + + if (tstruct->stype == STRUCT_TYPE_UNION) { + tmp = CMach_StructLayoutGetCurSize(); + if (tmp > r28) + r28 = tmp; + } + + if (member->name == no_name_node) + r23 = 1; + + if (!member->name) { + CError_ASSERT(4064, IS_TYPE_STRUCT(member->type)); + innerbase = member->offset; + innermember = TYPE_STRUCT(member->type)->members; + r23 = 1; + while (innermember) { + if (ismember(tstruct, innermember->name)) + CError_Error(CErrorStr133, innermember->name->name); + if (r23) { + member->type = innermember->type; + member->name = innermember->name; + member->qual = innermember->qual; + member->offset = innerbase + innermember->offset; + } else { + newmember = galloc(sizeof(StructMember)); + memclrw(newmember, sizeof(StructMember)); + newmember->next = member->next; + newmember->type = innermember->type; + newmember->name = innermember->name; + newmember->qual = innermember->qual | Q_WEAK; + newmember->offset = innerbase + innermember->offset; + member->next = newmember; + member = newmember; + } + if (copts.reverse_bitfields && IS_TYPE_BITFIELD(member->type)) { + bf = galloc(sizeof(TypeBitfield)); + *bf = *TYPE_BITFIELD(member->type); + CABI_ReverseBitField(bf); + member->type = TYPE(bf); + } + r23 = 0; + innermember = innermember->next; + } + r23 = 1; + } + } + + if (r23) { + memberp = &tstruct->members; + while (*memberp) { + if ((*memberp)->name == no_name_node || !(*memberp)->name) + *memberp = (*memberp)->next; + else + memberp = &(*memberp)->next; + } + } + + if (tstruct->stype == STRUCT_TYPE_UNION) + r24 = r28; + else + r24 = CMach_StructLayoutGetCurSize(); + tstruct->size = r24; + tstruct->align = CMach_GetStructAlign(tstruct); + tstruct->size = r24 + CABI_StructSizeAlignValue(TYPE(tstruct), r24); + + if (copts.reverse_bitfields) { + for (member = tstruct->members; member; member = member->next) { + if (IS_TYPE_BITFIELD(member->type)) + CABI_ReverseBitField(TYPE_BITFIELD(member->type)); + } + } + + if (copts.warn_padding && tstruct->stype != STRUCT_TYPE_UNION) { + StructMember *prev; + + member = tstruct->members; + prev = NULL; + while (member) { + if (prev && (prev->offset + prev->type->size) < member->offset) { + CError_Warning(CErrorStr350, member->offset - (prev->offset + prev->type->size), prev->name->name); + } + prev = member; + member = member->next; + } + + if (prev && (prev->offset + prev->type->size) < tstruct->size) { + CError_Warning(CErrorStr350, tstruct->size - (prev->offset + prev->type->size), prev->name->name); + } + } +} + +static SInt32 scanstructdeclarationlist(TypeStruct *tstruct, Boolean flag) { + SInt32 offset; + StructMember *member; + BigDeclInfo bde; + + offset = -1; + memclrw(&bde, sizeof(BigDeclInfo)); + + if (tk == TK_AT_DEFS) { + CPrep_NewFileOffsetInfo(&member_fileoffset, NULL); + CObjC_ParseDefs(tstruct); + if ((tk = lex()) != '}') + CError_Error(CErrorStr130); + } else { + do { + CPrep_NewFileOffsetInfo(&member_fileoffset, NULL); + memclrw(&bde.declinfo, sizeof(DeclInfo)); + CParser_GetDeclSpecs(&bde.declinfo, 0); + if (bde.declinfo.storageclass || bde.declinfo.x44) { + CError_Error(CErrorStr131); + tstruct->members = NULL; + return -1; + } + + if (tk != ';') { + while (1) { + CDecl_ScanStructDeclarator(&bde); + if (!CanCreateObject(bde.declinfo2.thetype)) { + CError_Error(CErrorStr131); + bde.xCD = 0; + } + + if (bde.declinfo2.operator_token) { + CError_Error(CErrorStr131); + bde.xCD = 0; + } + + if (bde.xCD) { + if (bde.declinfo2.name == no_name_node || !ismember(tstruct, bde.declinfo2.name)) { + member = galloc(sizeof(StructMember)); + memclrw(member, sizeof(StructMember)); + member->type = bde.declinfo2.thetype; + member->name = bde.declinfo2.name; + member->qual = bde.declinfo2.qual; + appendmember(tstruct, member); + + if (flag) { + CBrowse_AddStructMember(member, CPrep_BrowserTokenOffset(&member_fileoffset) + 1, CPrep_BrowserFileOffset()); + } + } else { + CError_Error(CErrorStr133, bde.declinfo2.name->name); + } + } + + if (tk != ',') + break; + tk = lex(); + } + } else if (!copts.ANSIstrict && IS_TYPE_STRUCT(bde.declinfo.thetype)) { + member = galloc(sizeof(StructMember)); + memclrw(member, sizeof(StructMember)); + member->type = bde.declinfo.thetype; + appendmember(tstruct, member); + } else { + CError_Error(CErrorStr131); + } + + if (tk != ';') { + tstruct->members = NULL; + CError_Error(CErrorStr123); + return -1; + } + + CPrep_TokenStreamFlush(); + } while ((tk = lex()) != '}'); + CDecl_LayoutStruct(tstruct); + } + + if (flag) { + offset = CPrep_BrowserFileOffset(); + if (tk == ';') + offset++; + } + + tk = lex(); + return offset; +} + +static TypeStruct *CDecl_DefineStruct(HashNameNode *name, short stype) { + TypeStruct *tstruct; + + tstruct = galloc(sizeof(TypeStruct)); + memclrw(tstruct, sizeof(TypeStruct)); + + tstruct->type = TYPESTRUCT; + tstruct->align = 1; + tstruct->stype = stype; + if (name) { + tstruct->name = name; + CScope_DefineTypeTag((in_func_arglist && !copts.cplusplus) ? cscope_root : cscope_current, name, (Type *) tstruct); + } + + return tstruct; +} + +void scanstruct(DeclInfo *declinfo, short structtype) { + Type *type; + HashNameNode *name; + TypeStruct typecopy; + Boolean add_to_browse; + GList gl; + SInt32 offset; + + if (copts.cplusplus) { + CDecl_ParseClass(declinfo, structtype, 1, 0); + return; + } + + if (tk == TK_IDENTIFIER) { + name = tkidentifier; + type = CScope_GetTagType(cscope_current, name); + if (type) { + if (IS_TYPE_CLASS(type)) { + CDecl_ParseClass(declinfo, structtype, 1, 0); + return; + } + + tk = lex(); + if (!CScope_GetLocalTagType(cscope_current, name) && (tk == ';' || tk == '{')) + type = (Type *) CDecl_DefineStruct(name, structtype); + + if (!IS_TYPE_STRUCT(type) || TYPE_STRUCT(type)->stype != structtype) { + CError_Error(CErrorStr132, name->name); + declinfo->thetype = type; + return; + } + + if (tk != '{') { + declinfo->thetype = type; + return; + } + + if (type->size) { + CError_Error(CErrorStr132, name->name); + type = (Type *) CDecl_DefineStruct(NULL, structtype); + } + } else { + type = (Type *) CDecl_DefineStruct(name, structtype); + if ((tk = lex()) != '{') { + declinfo->thetype = type; + return; + } + } + } else if (tk != '{') { + CError_Error(CErrorStr131); + declinfo->thetype = (Type *) &stsignedint; + return; + } else { + type = (Type *) CDecl_DefineStruct(NULL, structtype); + } + + if ((add_to_browse = cparamblkptr->browseoptions.recordClasses && declinfo->file->recordbrowseinfo)) + CBrowse_BeginStruct(declinfo, TYPE_STRUCT(type), &gl); + + typecopy = *TYPE_STRUCT(type); + tk = lex(); + offset = scanstructdeclarationlist(&typecopy, add_to_browse); + *TYPE_STRUCT(type) = typecopy; + declinfo->thetype = type; + + if (add_to_browse) + CBrowse_EndStruct(offset, &gl); +} + +static void InlineFunctionObject(Object *obj, TypeClass *tclass) { + TokenStream stream; + CPrepFileInfo *file; + + obj->qual |= Q_INLINE; + TYPE_FUNC(obj->type)->flags |= FUNC_DEFINED; + + CPrep_StreamGetBlock(&stream, NULL, 1); + if (stream.tokens) { + if (IS_TYPEFUNC_METHOD(TYPE_FUNC(obj->type)) && (TYPE_METHOD(obj->type)->theclass->flags & CLASS_IS_TEMPL)) { + TYPE_FUNC(obj->type)->flags |= FUNC_IS_TEMPL_INSTANCE; + CTemplClass_DefineMember(TEMPL_CLASS(TYPE_METHOD(obj->type)->theclass), obj, &member_fileoffset, &stream); + } else { + CInline_AddInlineFunctionAction(obj, tclass, &member_fileoffset, &stream, 0); + } + } + + file = CPrep_BrowserCurrentFile(); + if (file->recordbrowseinfo) { + CBrowse_NewFunction( + obj, file, + member_fileoffset.file, + CPrep_BrowserTokenOffset(&member_fileoffset) + 1, + CPrep_BrowserFileOffset()); + } + + if (lookahead() == ';') + tk = lex(); + else + tk = ';'; +} + +void CDecl_ExtractClassExportFlags(DeclInfo *declinfo, UInt8 flags) { + if (flags & CLASS_EFLAGS_INTERNAL) + declinfo->exportflags = declinfo->exportflags | EXPORT_FLAGS_INTERNAL; + if (flags & CLASS_EFLAGS_IMPORT) + declinfo->exportflags = declinfo->exportflags | EXPORT_FLAGS_IMPORT; + if (flags & CLASS_EFLAGS_EXPORT) + declinfo->exportflags = declinfo->exportflags | EXPORT_FLAGS_EXPORT; +} + +TypeMemberFunc *CDecl_MakeTypeMemberFunc(TypeFunc *tfunc, TypeClass *tclass, Boolean flag) { + TypeMemberFunc *method; + + method = galloc(sizeof(TypeMemberFunc)); + memclrw(method, sizeof(TypeMemberFunc)); + *TYPE_FUNC(method) = *tfunc; + method->theclass = tclass; + method->is_static = flag; + method->flags |= FUNC_METHOD; + if (!flag) + CDecl_AddThisPointerArgument(TYPE_FUNC(method), tclass); + + if ((flag || (tfunc->flags & (FUNC_IS_CTOR | FUNC_IS_DTOR))) && (tfunc->flags & (FUNC_CONST | FUNC_VOLATILE))) + CError_Error(CErrorStr384); + + return method; +} + +static void CDecl_MakeFunctionVirtual(TypeClass *tclass, Object *func) { + if (is_pascal_object(func)) + CError_Error(CErrorStr219); + if (tclass->mode == CLASS_MODE_UNION) + CError_Error(CErrorStr352, func); + func->datatype = DVFUNC; +} + +static void CDecl_AddFunctionMember(ClassLayout *decle, TypeClass *tclass, DeclInfo *declinfo, AccessType access, Boolean flag1, Boolean flag2, Boolean flag3, Boolean flag4) { + NameSpaceObjectList *list; // r20 + Object *obj; // also r20 + TypeMemberFunc *tfunc; // r19 + Boolean r31; + Boolean outflag; + + if (IS_TYPE_ARRAY(TYPE_FUNC(declinfo->thetype)->functype) || IS_TYPE_FUNC(TYPE_FUNC(declinfo->thetype)->functype)) { + CError_Error(CErrorStr128); + TYPE_FUNC(declinfo->thetype)->functype = (Type *) &stsignedint; + } + + if (tclass->sominfo) + CSOM_CheckFuncType(TYPE_FUNC(declinfo->thetype)); + + r31 = 0; + if (declinfo->qual & Q_VIRTUAL) { + declinfo->qual &= ~Q_VIRTUAL; + r31 = 1; + flag1 = 1; + } + + if ((list = CScope_FindName(tclass->nspace, declinfo->name))) { + if (list->object->otype != OT_TYPETAG) { + if (list->object->otype != OT_OBJECT || !IS_TYPE_FUNC(OBJECT(list->object)->type)) + CError_Error(CErrorStr133, declinfo->name->name); + } else { + list = NULL; + } + } + + if (!IS_TYPEFUNC_METHOD(TYPE_FUNC(declinfo->thetype))) { + tfunc = CDecl_MakeTypeMemberFunc(TYPE_FUNC(declinfo->thetype), tclass, flag4); + declinfo->thetype = (Type *) tfunc; + } else { + tfunc = TYPE_METHOD(declinfo->thetype); + CError_ASSERT(4579, !tclass->sominfo); + } + + CDecl_ExtractClassExportFlags(declinfo, tclass->eflags); + + CError_ASSERT(4597, cscope_current == tclass->nspace); + + if (list) { + obj = CDecl_OverloadFunctionObject(list, declinfo, &outflag, flag4 ? OverloadMode1 : OverloadMode2, 0); + if (!obj) + return; + if (outflag) + tfunc->vtbl_index = ++decle->lex_order_count; + else + CError_Error(CErrorStr133, CError_GetObjectName(obj)); + } else { + tfunc->vtbl_index = ++decle->lex_order_count; + obj = CParser_NewFunctionObject(declinfo); + if ((tclass->flags & CLASS_IS_TEMPL) && CTemplTool_IsTemplateArgumentDependentType(declinfo->thetype)) + CTemplClass_RegisterObjectDef(TEMPL_CLASS(tclass), OBJ_BASE(obj)); + CScope_AddObject(tclass->nspace, declinfo->name, OBJ_BASE(obj)); + } + + obj->access = access; + CheckDefaultArgs(TYPE_FUNC(obj->type)->args); + + if (flag2) { + tfunc->flags |= FUNC_CONVERSION; + tclass->flags = tclass->flags | CLASS_IS_CONVERTIBLE; + } + + if (r31) { + CDecl_MakeFunctionVirtual(tclass, obj); + decle->has_vtable = 1; + } + + if ((flag1 || r31) && flag3 && (tk == '=')) { + if ((tk = lex()) == TK_INTCONST) { + if (!CInt64_IsZero(&tkintconst)) + CError_Error(CErrorStr121); + tfunc->flags |= FUNC_PURE; + tclass->flags = tclass->flags | CLASS_ABSTRACT; + tk = lex(); + } else { + CError_Error(CErrorStr121); + } + } + + if (flag3 && ((tk == '{') || (tk == TK_TRY) || ((tk == ':') && CClass_IsConstructor(obj)))) { + if (declinfo->x49) + CError_Error(CErrorStr127); + InlineFunctionObject(obj, NULL); + } + + if (cparamblkptr->browseoptions.recordClasses) + CBrowse_AddClassMemberFunction(obj, CPrep_BrowserTokenOffset(&member_fileoffset) + 1, CPrep_BrowserFileOffset()); +} + +static Boolean CDecl_IsAccessDeclaration(TypeClass *tclass, AccessType access) { + SInt32 state; + Boolean flag; + + CPrep_TokenStreamGetState(&state); + flag = 0; + +restart: + switch (tk) { + case TK_IDENTIFIER: + if ((tk = lex()) != ';') + break; + case TK_OPERATOR: + CPrep_TokenStreamSetCurState(&state); + if (flag) { + CScope_ParseUsingDeclaration(tclass->nspace, access, 1); + return 1; + } + return 0; + default: + CPrep_TokenStreamSetCurState(&state); + return 0; + } + + switch (tk) { + case TK_COLON_COLON: + flag = 1; + tk = lex(); + goto restart; + case '<': + tk = lex(); + while (1) { + switch (tk) { + case 0: + case ';': + case '{': + case '}': + CPrep_TokenStreamSetCurState(&state); + return 0; + case '>': + if ((tk = lex()) == TK_COLON_COLON) { + flag = 1; + tk = lex(); + goto restart; + } + default: + tk = lex(); + } + } + } + + CPrep_TokenStreamSetCurState(&state); + return 0; +} + +void CDecl_PackDeclInfo(PackedDeclInfo *packed, DeclInfo *declinfo) { + packed->thetype = declinfo->thetype; + packed->qual = declinfo->qual; + packed->nspace = declinfo->nspace; + packed->name = declinfo->name; + packed->expltargs = CTemplTool_MakeGlobalTemplArgCopy(declinfo->expltargs); + packed->storageclass = declinfo->storageclass; + packed->section = declinfo->section; + packed->exportflags = declinfo->exportflags; + packed->has_expltargs = declinfo->has_expltargs; +} + +void CDecl_UnpackDeclInfo(DeclInfo *declinfo, PackedDeclInfo *packed) { + memclrw(declinfo, sizeof(DeclInfo)); + declinfo->thetype = packed->thetype; + declinfo->qual = packed->qual; + declinfo->nspace = packed->nspace; + declinfo->name = packed->name; + declinfo->expltargs = packed->expltargs; + declinfo->storageclass = packed->storageclass; + declinfo->section = packed->section; + declinfo->exportflags = packed->exportflags; + declinfo->has_expltargs = packed->has_expltargs; +} + +void CDecl_AddFriend(TypeClass *tclass, Object *friendfunc, TypeClass *friendclass) { + ClassFriend *scan; + ClassFriend *newfriend; + + if (friendfunc) { + for (scan = tclass->friends; scan; scan = scan->next) { + if (!scan->isclass && scan->u.obj == friendfunc) + break; + } + if (!scan) { + newfriend = galloc(sizeof(ClassFriend)); + memclrw(newfriend, sizeof(ClassFriend)); + newfriend->next = tclass->friends; + tclass->friends = newfriend; + newfriend->u.obj = friendfunc; + newfriend->isclass = 0; + } + } + + if (friendclass) { + for (scan = tclass->friends; scan; scan = scan->next) { + if (scan->isclass && scan->u.theclass == friendclass) + break; + } + if (!scan) { + newfriend = galloc(sizeof(ClassFriend)); + memclrw(newfriend, sizeof(ClassFriend)); + newfriend->next = tclass->friends; + tclass->friends = newfriend; + newfriend->u.theclass = friendclass; + newfriend->isclass = 1; + } + } +} + +static void CDecl_ParseFriendDecl(TypeClass *tclass) { + DeclInfo declinfo; + DeclInfo declinfo_copy; + Boolean is_templ; + Boolean r27; + Boolean pflag; + CScopeSave save; + Object *obj; + NameSpace *nspace; + + is_templ = (tclass->flags & CLASS_IS_TEMPL) != 0; + r27 = (tk == TK_CLASS || tk == TK_STRUCT || tk == TK_UNION); + memclrw(&declinfo, sizeof(DeclInfo)); + + declinfo.in_friend_decl = 1; + CParser_GetDeclSpecs(&declinfo, 1); + if (declinfo.storageclass) { + CError_Error(CErrorStr177); + declinfo.storageclass = 0; + } + declinfo.in_friend_decl = 0; + + if (tk == ';') { + if (!r27) + CError_Error(CErrorStr201); + + if (IS_TYPE_CLASS(declinfo.thetype)) { + if (!(TYPE_CLASS(declinfo.thetype)->flags & CLASS_IS_TEMPL) || CParser_CheckTemplateClassUsage(TEMPL_CLASS(declinfo.thetype), 1)) { + if (!is_templ) + CDecl_AddFriend(tclass, NULL, TYPE_CLASS(declinfo.thetype)); + else + CTemplClass_RegisterFriend(TEMPL_CLASS(tclass), &declinfo); + } + } else { + if (IS_TYPE_TEMPLATE(declinfo.thetype) && is_templ) + CTemplClass_RegisterFriend(TEMPL_CLASS(tclass), &declinfo); + else + CError_Error(CErrorStr201); + } + } else { + if (declinfo.x14 || declinfo.x10) { + CDecl_ParseSpecialMember(&declinfo, 0); + if (declinfo.name) { + obj = CDecl_GetFunctionObject(&declinfo, NULL, &pflag, 0); + if (obj) + CDecl_AddFriend(tclass, obj, NULL); + if (tk != ';') + CError_Error(CErrorStr123); + else + tk = lex(); + } + return; + } else { + nspace = CScope_FindGlobalNS(cscope_current); + declinfo_copy = declinfo; + while (1) { + declinfo = declinfo_copy; + declinfo.x4D = 1; + declinfo.x51 = 1; + scandeclarator(&declinfo); + + if (IS_TYPE_FUNC(declinfo.thetype)) { + if (!is_templ) { + CScope_SetNameSpaceScope(nspace, &save); + obj = CDecl_GetFunctionObject(&declinfo, NULL, &pflag, 0); + CScope_RestoreScope(&save); + + if (obj) { + CDecl_AddFriend(tclass, obj, NULL); + if (!declinfo.nspace && tk == '{') { + InlineFunctionObject(obj, tclass); + } else { + if (!obj->sclass) + obj->sclass = TK_EXTERN; + } + } + } else { + CTemplClass_RegisterFriend(TEMPL_CLASS(tclass), &declinfo); + } + } else { + CError_Error(CErrorStr201); + } + + if (tk != ',') + break; + tk = lex(); + } + } + } + + if (tk == ';') + tk = lex(); + else + CError_Error(CErrorStr123); +} + +static ObjMemberVar *CDecl_InstanceDataDeclarator(ClassLayout *decle, TypeClass *tclass, Type *type, UInt32 qual, HashNameNode *name, AccessType access) { + NameSpaceObjectList *list; + ObjMemberVar *ivar; + ObjMemberVar *scan; + + if (name && (list = CScope_FindName(tclass->nspace, name))) { + switch (list->object->otype) { + case OT_NAMESPACE: + CError_Error(CErrorStr321); + return NULL; + case OT_ENUMCONST: + case OT_TYPE: + case OT_OBJECT: + CError_Error(CErrorStr322); + return NULL; + case OT_MEMBERVAR: + CError_Error(CErrorStr122, name->name); + return NULL; + case OT_TYPETAG: + break; + default: + CError_FATAL(4989); + } + } + + ivar = galloc(sizeof(ObjMemberVar)); + memclrw(ivar, sizeof(ObjMemberVar)); + ivar->otype = OT_MEMBERVAR; + ivar->access = access; + ivar->name = name; + ivar->type = type; + ivar->qual = qual; + if (!tclass->sominfo) + decle->lex_order_count++; + + if ((scan = tclass->ivars)) { + while (scan->next) + scan = scan->next; + scan->next = ivar; + } else { + tclass->ivars = ivar; + } + + if (name && name != no_name_node) { + CScope_AddObject(tclass->nspace, name, OBJ_BASE(ivar)); + if ((tclass->flags & CLASS_IS_TEMPL) && CTemplTool_IsTemplateArgumentDependentType(type)) + CTemplClass_RegisterObjectDef(TEMPL_CLASS(tclass), OBJ_BASE(ivar)); + if (cparamblkptr->browseoptions.recordClasses) + CBrowse_AddClassMemberVar(ivar, CPrep_BrowserTokenOffset(&member_fileoffset) + 1, CPrep_BrowserFileOffset()); + } + + return ivar; +} + +void CDecl_CheckCtorIntegrity(FuncArg *args, TypeClass *tclass) { + if (args && args->type == TYPE(tclass)) { + if (!args->next || args->next->dexpr) { + CError_Error(CErrorStr239); + args->type = &stvoid; + } + } +} + +static void CDecl_ParseClassMembers(ClassLayout *decle, TypeClass *tclass, short mode) { + AccessType access; + Boolean r17; + BigDeclInfo bde; + DeclInfo declinfo; + //Type *newtype + ObjMemberVar *ivar; + ObjMemberVar *scanivar; + Type *tmptype; + UInt32 r22; + UInt32 r21; + UInt8 r20; + UInt8 r18; + Boolean r19; + short t; + + r17 = (tclass->flags & CLASS_IS_TEMPL) && TEMPL_CLASS(tclass)->pspec_owner; + memclrw(&bde, sizeof(BigDeclInfo)); + + access = (mode == CLASS_MODE_CLASS) ? ACCESSPRIVATE : ACCESSPUBLIC; + global_access = access; + + restart: + while (tk != '}') { + CPrep_NewFileOffsetInfo(&member_fileoffset, NULL); + r21 = 0; + r22 = 0; + r20 = 0; + r18 = 0; + + if (tk == TK_TEMPLATE) { + NameSpace *nspace = cscope_current; + TemplClass *tmclass; + + if (nspace->theclass && (nspace->theclass->flags & CLASS_IS_TEMPL)) { + tmclass = TEMPL_CLASS(nspace->theclass); + } else { + for (; nspace; nspace = nspace->parent) { + if (!nspace->name && !nspace->theclass && nspace->parent && !nspace->is_templ) { + CError_Error(CErrorStr347); + break; + } + } + } + + CTempl_Parse(TEMPL_CLASS(tclass), access); + tk = lex(); + continue; + } + + restart2: + r19 = 0; + switch (tk) { + case TK_UU_DECLSPEC: + if ((tk = lex()) != '(') + CError_Error(CErrorStr114); + memclrw(&declinfo, sizeof(DeclInfo)); + CParser_ParseDeclSpec(&declinfo, 1); + r21 |= declinfo.qual; + r20 |= declinfo.exportflags; + r18 = declinfo.section; + if ((tk = lex()) != ')') + CError_Error(CErrorStr115); + tk = lex(); + goto restart2; + case TK_PRIVATE: + global_access = access = ACCESSPRIVATE; + goto check_access; + case TK_PROTECTED: + global_access = access = ACCESSPROTECTED; + goto check_access; + case TK_PUBLIC: + global_access = access = ACCESSPUBLIC; + check_access: + if (r22 || r20) + CError_Error(CErrorStr121); + if ((tk = lex()) != ':') + CError_Error(CErrorStr170); + else + tk = lex(); + goto restart; + case TK_EXPLICIT: + CError_QualifierCheck(r22 & Q_EXPLICIT); + r22 |= Q_EXPLICIT; + tk = lex(); + goto restart2; + case TK_INLINE: + CError_QualifierCheck(r22 & Q_INLINE); + r22 |= Q_INLINE; + tk = lex(); + goto restart2; + case TK_ASM: + CError_QualifierCheck(r22 & Q_ASM); + r22 |= Q_ASM; + tk = lex(); + goto restart2; + case TK_VIRTUAL: + CError_QualifierCheck(r22 & Q_VIRTUAL); + r22 |= Q_VIRTUAL; + tk = lex(); + goto restart2; + case TK_IDENTIFIER: + while (1) { + if (tkidentifier == tclass->classname) { + t = lookahead(); + tkidentifier = tclass->classname; + r19 = 1; + if (copts.cpp_extensions && t == TK_COLON_COLON) { + lex(); + tk = lex(); + if (tk == TK_IDENTIFIER) + continue; + if (tk == '~') + goto restart2; + CError_Error(CErrorStr107); + } + + if (t == '(') { + redo_thing: + CError_QualifierCheck(r22 & ~(Q_EXPLICIT | Q_INLINE | Q_ASM)); + memclrw(&bde.declinfo2, sizeof(DeclInfo)); + if (tclass->sominfo) + bde.declinfo2.thetype = &stvoid; + else + bde.declinfo2.thetype = TYPE(&void_ptr); + + bde.declinfo2.qual = r22; + bde.declinfo2.exportflags = r20; + bde.declinfo2.section = r18; + bde.declinfo2.x4B = 1; + scandeclarator(&bde.declinfo2); + if (IS_TYPE_FUNC(bde.declinfo2.thetype)) { + if (r17) + bde.declinfo2.thetype = CTemplTool_ResolveMemberSelfRefs(TEMPL_CLASS(tclass), bde.declinfo2.thetype, &bde.declinfo2.qual); + if (tclass->sominfo) { + if (TYPE_FUNC(bde.declinfo2.thetype)->args) + CError_Error(CErrorStr272); + bde.declinfo2.qual |= Q_VIRTUAL; + } else { + CDecl_CheckCtorIntegrity(TYPE_FUNC(bde.declinfo2.thetype)->args, tclass); + if (tclass->flags & CLASS_HAS_VBASES) + CDecl_AddArgument(TYPE_FUNC(bde.declinfo2.thetype), TYPE(&stsignedshort)); + bde.declinfo2.qual &= ~Q_VIRTUAL; + } + TYPE_FUNC(bde.declinfo2.thetype)->flags |= FUNC_IS_CTOR; + bde.declinfo2.name = constructor_name_node; + bde.declinfo2.qual |= r21; + CDecl_AddFunctionMember(decle, tclass, &bde.declinfo2, access, 0, 0, 1, 0); + } else { + CError_Error(CErrorStr241); + } + if (tk == ';') + tk = lex(); + else + CError_Error(CErrorStr123); + goto restart; + } + } + // 6F8D8 + if (!r22 && CDecl_IsAccessDeclaration(tclass, access)) { + tk = lex(); + goto restart; + } + break; + } + break; + case TK_USING: + CError_QualifierCheck(r22); + tk = lex(); + CScope_ParseUsingDeclaration(tclass->nspace, access, 0); + tk = lex(); + goto restart; + case '~': + if ((tk = lex()) != TK_IDENTIFIER || tkidentifier != tclass->classname) { + CError_Error(CErrorStr241); + goto restart; + } + CError_QualifierCheck(r22 & ~(Q_VIRTUAL | Q_INLINE | Q_ASM)); + if (tclass->flags & CLASS_IS_TEMPL_ANY) { + t = lookahead(); + tkidentifier = tclass->classname; + if (t == '<') { + memclrw(&bde.declinfo, sizeof(DeclInfo)); + CParser_GetDeclSpecs(&bde.declinfo, 0); + if (tk != '(' || bde.declinfo.thetype != TYPE(tclass) || bde.declinfo.nspace) { + CError_Error(CErrorStr241); + goto restart; + } + CPrep_UnLex(); + tk = TK_IDENTIFIER; + tkidentifier = tclass->classname; + } + } + memclrw(&bde.declinfo2, sizeof(DeclInfo)); + bde.declinfo2.qual = r22; + bde.declinfo2.exportflags = r20; + bde.declinfo2.section = r18; + if (tclass->sominfo) + bde.declinfo2.thetype = &stvoid; + else + bde.declinfo2.thetype = TYPE(&void_ptr); + scandeclarator(&bde.declinfo2); + if (IS_TYPE_FUNC(bde.declinfo2.thetype) && !TYPE_FUNC(bde.declinfo2.thetype)->args) { + if (!CScope_FindName(tclass->nspace, destructor_name_node)) { + if (tclass->sominfo) + bde.declinfo2.qual |= Q_VIRTUAL; + else + CDecl_AddArgument(TYPE_FUNC(bde.declinfo2.thetype), TYPE(&stsignedshort)); + bde.declinfo2.name = destructor_name_node; + TYPE_FUNC(bde.declinfo2.thetype)->flags |= FUNC_IS_DTOR; + bde.declinfo2.qual |= r21; + CDecl_AddFunctionMember(decle, tclass, &bde.declinfo2, access, 1, 0, 1, 0); + } else { + CError_Error(CErrorStr133, CError_GetFunctionName(tclass->nspace, destructor_name_node, NULL)); + } + } else { + CError_Error(CErrorStr146); + } + if (tk == ';') + tk = lex(); + else + CError_Error(CErrorStr123); + goto restart; + case TK_OPERATOR: + if (CMangler_OperatorName(lookahead())) { + memclrw(&bde.declinfo, sizeof(DeclInfo)); + bde.declinfo.thetype = TYPE(&stsignedint); + goto after_various_things; + } else { + tk = lex(); + CError_QualifierCheck(r22 & ~(Q_VIRTUAL | Q_INLINE | Q_ASM)); + memclrw(&bde.declinfo2, sizeof(DeclInfo)); + bde.declinfo2.qual = r22; + bde.declinfo2.exportflags = r20; + bde.declinfo2.section = r18; + conversion_type_name(&bde.declinfo2); + bde.declinfo2.qual |= r21; + tmptype = bde.declinfo2.thetype; + CDecl_NewConvFuncType(&bde.declinfo2); + if ((tclass->flags & CLASS_IS_TEMPL) && CTemplTool_IsTemplateArgumentDependentType(tmptype)) + bde.declinfo2.name = CParser_GetUniqueName(); + CDecl_AddFunctionMember(decle, tclass, &bde.declinfo2, access, 1, 1, 1, 0); + if (tk == ';') + tk = lex(); + else + CError_Error(CErrorStr123); + goto restart; + } + case TK_FRIEND: + tk = lex(); + CDecl_ParseFriendDecl(tclass); + goto restart; + } + + CError_QualifierCheck(r22 & Q_EXPLICIT); + global_access = access; + memclrw(&bde.declinfo, sizeof(DeclInfo)); + bde.declinfo.qual = r22; + bde.declinfo.exportflags = r20; + bde.declinfo.section = r18; + CParser_GetDeclSpecs(&bde.declinfo, 0); + + if (r19 && tk == '(' && (tclass->flags & CLASS_IS_TEMPL_ANY) && bde.declinfo.thetype == TYPE(tclass) && !bde.declinfo.nspace) { + CPrep_UnLex(); + tk = TK_IDENTIFIER; + tkidentifier = tclass->classname; + r22 = bde.declinfo.qual; + goto redo_thing; + } + + after_various_things: + switch (bde.declinfo.storageclass) { + case 0: + case TK_STATIC: + case TK_TYPEDEF: + case TK_MUTABLE: + break; + default: + CError_Error(CErrorStr177); + bde.declinfo.storageclass = 0; + } + + if (tk != ';') { + while (1) { + CDecl_ScanStructDeclarator(&bde); + if (r17) + bde.declinfo2.thetype = CTemplTool_ResolveMemberSelfRefs(TEMPL_CLASS(tclass), bde.declinfo2.thetype, &bde.declinfo2.qual); + if (bde.declinfo2.nspace) + CError_Error(CErrorStr200); + if (bde.declinfo2.operator_token) { + if (bde.declinfo.storageclass == TK_MUTABLE) + CError_QualifierCheck(Q_MUTABLE); + r19 = 0; + switch (bde.declinfo2.operator_token) { + case TK_NEW: + case TK_NEW_ARRAY: + CError_QualifierCheck(bde.declinfo2.qual & Q_VIRTUAL); + r19 = 1; + break; + case TK_DELETE: + case TK_DELETE_ARRAY: + CError_QualifierCheck(bde.declinfo2.qual & Q_VIRTUAL); + r19 = 1; + break; + default: + if (bde.declinfo2.storageclass == TK_STATIC) + CError_Error(CErrorStr193); + if (tclass->sominfo) + CError_Error(CErrorStr193); + } + + bde.declinfo2.storageclass = 0; + if (IS_TYPE_FUNC(bde.declinfo2.thetype)) { + bde.declinfo2.qual |= r21; + CDecl_AddFunctionMember(decle, tclass, &bde.declinfo2, access, r19 == 0, 0, 1, r19); + CDecl_CheckOperatorType(&bde.declinfo2, 1); + if (tclass->sominfo) + CSOM_FixNewDeleteFunctype(TYPE_FUNC(bde.declinfo2.thetype)); + } else { + CError_Error(CErrorStr121); + } + } else if (bde.xCD) { + if (bde.declinfo2.name == constructor_name_node || bde.declinfo2.name == destructor_name_node) + CError_Error(CErrorStr241); + switch (bde.declinfo2.storageclass) { + case TK_TYPEDEF: + CError_QualifierCheck(bde.declinfo2.qual & Q_VIRTUAL); + CDecl_TypedefDeclarator(&bde.declinfo2); + break; + case TK_STATIC: + CError_QualifierCheck(bde.declinfo2.qual & Q_VIRTUAL); + if (tclass->sominfo) + CError_Error(CErrorStr271); + if (IS_TYPE_FUNC(bde.declinfo2.thetype)) { + bde.declinfo2.qual |= r21; + bde.declinfo2.storageclass = 0; + if (bde.declinfo2.name == tclass->classname) + CError_Error(CErrorStr241); + CDecl_AddFunctionMember(decle, tclass, &bde.declinfo2, access, 0, 0, 1, 1); + } else { + CDecl_ExtractClassExportFlags(&bde.declinfo2, tclass->eflags); + bde.declinfo2.storageclass = 0; + CDecl_DataDeclarator(&bde.declinfo2, access, 1); + } + break; + case 0: + case TK_MUTABLE: + if (IS_TYPE_FUNC(bde.declinfo2.thetype)) { + if (bde.declinfo2.name == tclass->classname) + CError_Error(CErrorStr241); + if (bde.declinfo.storageclass == TK_MUTABLE) + CError_QualifierCheck(Q_MUTABLE); + bde.declinfo2.qual |= r21; + CDecl_AddFunctionMember(decle, tclass, &bde.declinfo2, access, 1, 0, 1, 0); + } else { + CDecl_CompleteType(bde.declinfo2.thetype); + CanCreateObject(bde.declinfo2.thetype); + CError_QualifierCheck(bde.declinfo2.qual & (Q_VIRTUAL | Q_INLINE)); + if (bde.declinfo2.storageclass == TK_MUTABLE) + bde.declinfo2.qual |= Q_MUTABLE; + CDecl_InstanceDataDeclarator(decle, tclass, bde.declinfo2.thetype, bde.declinfo2.qual, bde.declinfo2.name, access); + } + break; + default: + CError_Error(CErrorStr177); + } + } + + // this should be 70058 + if (tk != ',') + break; // goes to 70148 + tk = lex(); + } + } else if (CParser_IsAnonymousUnion(&bde.declinfo, 1)) { + if ((ivar = CDecl_InstanceDataDeclarator(decle, tclass, bde.declinfo.thetype, 0, NULL, access))) + ivar->anonunion = 1; + for (scanivar = TYPE_CLASS(bde.declinfo.thetype)->ivars; scanivar; scanivar = scanivar->next) { + tmptype = scanivar->type; + if (IS_TYPE_BITFIELD(tmptype) && copts.reverse_bitfields) { + TypeBitfield *newtype = galloc(sizeof(TypeBitfield)); + *newtype = *TYPE_BITFIELD(tmptype); + CABI_ReverseBitField(newtype); + tmptype = TYPE(newtype); + } + if ((ivar = CDecl_InstanceDataDeclarator(decle, tclass, tmptype, scanivar->qual, scanivar->name, access))) + ivar->offset = scanivar->offset | 0x80000000; + } + } + + // this should be 70148 i think + if (tk != ';') { + CError_Error(CErrorStr123); + return; + } + CPrep_TokenStreamFlush(); + tk = lex(); + } +} + +static VClassList *AddVBaseToList(TypeClass *tclass, TypeClass *baseclass) { + VClassList *scan; + VClassList *vbase; + + for (scan = tclass->vbases; scan; scan = scan->next) { + if (scan->base == baseclass) + return NULL; + } + + vbase = galloc(sizeof(VClassList)); + memclrw(vbase, sizeof(VClassList)); + vbase->base = baseclass; + + if ((scan = tclass->vbases)) { + while (scan->next) + scan = scan->next; + scan->next = vbase; + } else { + tclass->vbases = vbase; + } + + return vbase; +} + +void CDecl_MakeVBaseList(TypeClass *tclass) { + ClassList *base; + VClassList *vbase; + VClassList *new_vbase; + SInt32 offset; + + if (copts.vbase_ctor_offset) + tclass->flags = tclass->flags | CLASS_FLAGS_8000; + + for (base = tclass->bases, offset = tclass->size; base; base = base->next) { + for (vbase = base->base->vbases; vbase; vbase = vbase->next) { + if ((new_vbase = AddVBaseToList(tclass, vbase->base))) { + new_vbase->offset = offset + CMach_MemberAlignValue(TYPE(vbase->base), offset); + offset = new_vbase->offset + vbase->base->size; + } + } + + if (base->is_virtual && (new_vbase = AddVBaseToList(tclass, base->base))) { + new_vbase->offset = offset + CMach_MemberAlignValue(TYPE(base->base), offset); + offset = new_vbase->offset + base->base->size; + } + } +} + +Boolean CDecl_CheckNewBase(TypeClass *tclass, TypeClass *baseclass, Boolean is_virtual) { + ClassList *scan; + + if (tclass == baseclass) { + CError_Error(CErrorStr131); + return 0; + } + + if (!(baseclass->flags & CLASS_COMPLETED)) { + CError_Error(CErrorStr136, baseclass, 0); + return 0; + } + + if (baseclass->flags & CLASS_SINGLE_OBJECT) { + if (is_virtual || tclass->bases) { + CError_Error(CErrorStr191); + return 0; + } + tclass->flags = tclass->flags | CLASS_SINGLE_OBJECT; + } + + if (baseclass->flags & CLASS_HANDLEOBJECT) { + if (is_virtual || tclass->bases) { + CError_Error(CErrorStr191); + return 0; + } + tclass->flags = tclass->flags | CLASS_HANDLEOBJECT; + } + + if (baseclass->sominfo) { + if (!is_virtual) + CError_Error(CErrorStr268); + CSOM_MakeSOMClass(tclass); + } else if (tclass->sominfo) { + CError_Error(CErrorStr267); + } + + if (tclass->bases && (tclass->flags & CLASS_SINGLE_OBJECT) && (tclass->flags & CLASS_SINGLE_OBJECT)) { + CError_Error(CErrorStr131); + return 0; + } + + if (copts.ecplusplus && (is_virtual || tclass->bases)) { + CError_Error(CErrorStr339); + return 0; + } + + for (scan = tclass->bases; scan; scan = scan->next) { + if (scan->base == baseclass) { + CError_Error(CErrorStr131); + return 0; + } + } + + if (baseclass->flags & CLASS_COM_OBJECT) + tclass->flags = tclass->flags | CLASS_COM_OBJECT; + if (baseclass->flags & CLASS_IS_CONVERTIBLE) + tclass->flags = tclass->flags | CLASS_IS_CONVERTIBLE; + if (baseclass->flags & CLASS_HAS_VBASES) + tclass->flags = tclass->flags | CLASS_HAS_VBASES; + + if (is_virtual) + tclass->flags = tclass->flags | CLASS_HAS_VBASES; + + return 1; +} + +static void CDecl_ParseBaseClassList(TypeClass *tclass, short mode, Boolean is_templ) { + Boolean is_virtual; + AccessType access; + NameResult pr; + ObjType *inherited_type; + ClassList *base; + ClassList *scan; + TypeClass *baseclass; + + do { + if (mode == CLASS_MODE_CLASS) + access = ACCESSPRIVATE; + else + access = ACCESSPUBLIC; + + is_virtual = 0; + if ((tk = lex()) == TK_VIRTUAL) { + tk = lex(); + is_virtual = 1; + } + + switch (tk) { + case TK_PRIVATE: + access = ACCESSPRIVATE; + tk = lex(); + break; + case TK_PUBLIC: + access = ACCESSPUBLIC; + tk = lex(); + break; + case TK_PROTECTED: + if (!copts.ARMconform) { + access = ACCESSPROTECTED; + tk = lex(); + } + break; + } + + if (tk == TK_VIRTUAL) { + if (is_virtual) + CError_Error(CErrorStr121); + is_virtual = 1; + tk = lex(); + } + + if (CScope_ParseDeclName(&pr)) { + if (!pr.type) { + if (!pr.name_4) { + CError_Error(CErrorStr121); + } else if (tk == TK_IDENTIFIER && pr.name_4 == tkidentifier) { + goto special_parsing; + } + CError_Error(CErrorStr140, tkidentifier->name); + continue; + } + + CDecl_CompleteType(pr.type); + if (is_templ && CTemplTool_IsTemplateArgumentDependentType(pr.type)) { + if (!IS_TYPE_CLASS(pr.type) || !(TYPE_CLASS(pr.type)->flags & CLASS_IS_TEMPL) || + CParser_CheckTemplateClassUsage(TEMPL_CLASS(pr.type), 1)) { + CTemplClass_RegisterBaseClass(TEMPL_CLASS(tclass), pr.type, access, is_virtual); + if (is_virtual) + tclass->flags = tclass->flags | CLASS_HAS_VBASES; + } + continue; + } + + if (!IS_TYPE_CLASS(pr.type) || (TYPE_CLASS(pr.type)->flags & CLASS_IS_TEMPL)) { + CError_Error(CErrorStr131); + continue; + } + baseclass = TYPE_CLASS(pr.type); + } else { + special_parsing: + if (!strcmp(tkidentifier->name, "HandleObject")) { + if (tclass->bases) + CError_Error(CErrorStr191); + tclass->flags |= CLASS_SINGLE_OBJECT | CLASS_HANDLEOBJECT; + tk = lex(); + break; + } + if (!strcmp(tkidentifier->name, "SingleObject") || !strcmp(tkidentifier->name, "SingleInheritance")) { + if (tclass->bases) + CError_Error(CErrorStr191); + tclass->flags = tclass->flags | CLASS_SINGLE_OBJECT; + tk = lex(); + break; + } + if (!strcmp(tkidentifier->name, "__comobject")) { + tclass->flags = tclass->flags | CLASS_COM_OBJECT; + tk = lex(); + break; + } + if (!strcmp(tkidentifier->name, "__somobject")) { + if (!is_virtual) + CError_Error(CErrorStr268); + CSOM_MakeSOMClass(tclass); + tk = lex(); + break; + } + if (!strcmp(tkidentifier->name, "__javaobject")) { + tk = lex(); + tclass->action = CLASS_ACTION_3; + break; + } + + CError_Error(CErrorStr140, tkidentifier->name); + continue; + } + + if (CDecl_CheckNewBase(tclass, baseclass, is_virtual)) { + base = galloc(sizeof(ClassList)); + memclrw(base, sizeof(ClassList)); + base->base = baseclass; + base->access = access; + base->is_virtual = is_virtual; + if ((scan = tclass->bases)) { + while (scan->next) + scan = scan->next; + scan->next = base; + } else { + tclass->bases = base; + } + } + } while ((tk = lex()) == ','); + + if (tclass->flags & CLASS_HAS_VBASES) + CDecl_MakeVBaseList(tclass); + + if (copts.def_inherited && tclass->bases && !tclass->bases->next) { + inherited_type = galloc(sizeof(ObjType)); + memclrw(inherited_type, sizeof(ObjType)); + inherited_type->otype = OT_TYPE; + inherited_type->access = ACCESSPUBLIC; + inherited_type->type = TYPE(tclass->bases->base); + CScope_AddObject(tclass->nspace, GetHashNameNodeExport("inherited"), OBJ_BASE(inherited_type)); + } +} + +static AccessType getaccesstype(AccessType a, AccessType b, AccessType c) { + if (a == ACCESSNONE || b == ACCESSNONE || b == ACCESSPRIVATE) + return ACCESSNONE; + + if (c == ACCESSPUBLIC && b != ACCESSPUBLIC) + return ACCESSNONE; + + return ACCESSPUBLIC; +} + +static TypeMemberFunc *CDecl_MakeDefaultCtorType(TypeClass *tclass) { + TypeMemberFunc *tmeth = galloc(sizeof(TypeMemberFunc)); + memclrw(tmeth, sizeof(TypeMemberFunc)); + tmeth->type = TYPEFUNC; + tmeth->functype = TYPE(&void_ptr); + tmeth->flags = FUNC_IS_CTOR | FUNC_AUTO_GENERATED | FUNC_METHOD; + tmeth->theclass = tclass; + CDecl_SetFuncFlags(TYPE_FUNC(tmeth), 1); + + if (tclass->flags & CLASS_HAS_VBASES) + CDecl_AddArgument(TYPE_FUNC(tmeth), TYPE(&stsignedshort)); + + CDecl_AddThisPointerArgument(TYPE_FUNC(tmeth), tclass); + return tmeth; +} + +static void CDecl_AddDefArgConstructor(TypeClass *tclass) { + // empty +} + +static void CDecl_AddMemberFunctionObject(TypeClass *tclass, HashNameNode *name, TypeMemberFunc *tmeth, AccessType access) { + Object *obj = CParser_NewCompilerDefFunctionObject(); + obj->name = name; + obj->type = TYPE(tmeth); + obj->qual = Q_MANGLE_NAME; + obj->access = access; + obj->nspace = tclass->nspace; + obj->qual = obj->qual | Q_INLINE; + CScope_AddObject(tclass->nspace, obj->name, OBJ_BASE(obj)); +} + +static void CDecl_AddDefaultConstructor(ClassLayout *decle, TypeClass *tclass) { + ClassList *base; + ObjMemberVar *ivar; + Object *obj; + Boolean has_ctor; + + if (CClass_Constructor(tclass)) { + CDecl_AddDefArgConstructor(tclass); + return; + } + + has_ctor = 0; + + if (tclass->flags & CLASS_HAS_VBASES) + has_ctor = 1; + if (decle->has_vtable) + has_ctor = 1; + + for (base = tclass->bases; base; base = base->next) { + if (CClass_Constructor(base->base)) + has_ctor = 1; + } + + for (ivar = tclass->ivars; ivar; ivar = ivar->next) { + Type *type = ivar->type; + while (IS_TYPE_ARRAY(type)) + type = TYPE_POINTER(type)->target; + if (IS_TYPE_CLASS(type) && CClass_Constructor(TYPE_CLASS(type))) + has_ctor = 1; + } + + if (has_ctor) { + CDecl_AddMemberFunctionObject( + tclass, + constructor_name_node, + CDecl_MakeDefaultCtorType(tclass), + ACCESSPUBLIC + ); + } +} + +static TypeMemberFunc *CDecl_MakeCopyCtorType(TypeClass *tclass, Boolean is_const) { + FuncArg *arg; + TypeMemberFunc *tmeth = galloc(sizeof(TypeMemberFunc)); + memclrw(tmeth, sizeof(TypeMemberFunc)); + tmeth->type = TYPEFUNC; + tmeth->functype = TYPE(&void_ptr); + tmeth->flags = FUNC_IS_CTOR | FUNC_AUTO_GENERATED | FUNC_METHOD; + tmeth->theclass = tclass; + CDecl_SetFuncFlags(TYPE_FUNC(tmeth), 1); + + arg = CParser_NewFuncArg(); + if (is_const) + arg->qual = Q_CONST; + arg->type = CDecl_NewRefPointerType(TYPE(tclass)); + tmeth->args = arg; + + if (tclass->flags & CLASS_HAS_VBASES) + CDecl_AddArgument(TYPE_FUNC(tmeth), TYPE(&stsignedshort)); + + CDecl_AddThisPointerArgument(TYPE_FUNC(tmeth), tclass); + return tmeth; +} + +static void CDecl_AddDefaultCopyConstructor(ClassLayout *decle, TypeClass *tclass) { + ClassList *base; + ObjMemberVar *ivar; + Object *obj; + AccessType access; + Boolean has_copyctor; + Boolean is_const; + FuncArg *arg; + + if (CClass_CopyConstructor(tclass)) + return; + + access = ACCESSPUBLIC; + is_const = 1; + has_copyctor = 0; + + if (CClass_Constructor(tclass)) + has_copyctor = 1; + if ((tclass->flags & CLASS_HAS_VBASES) || decle->has_vtable) + has_copyctor = 1; + + for (base = tclass->bases; base; base = base->next) { + if ((obj = CClass_CopyConstructor(base->base))) { + has_copyctor = 1; + access = getaccesstype(access, obj->access, ACCESSPRIVATE); + arg = TYPE_FUNC(obj->type)->args->next; + if (base->base->flags & CLASS_HAS_VBASES) + arg = arg->next; + if (!(arg->qual & Q_CONST)) + is_const = 0; + } + } + + for (ivar = tclass->ivars; ivar; ivar = ivar->next) { + Type *type = ivar->type; + while (IS_TYPE_ARRAY(type)) + type = TYPE_POINTER(type)->target; + if (IS_TYPE_CLASS(type) && (obj = CClass_CopyConstructor(TYPE_CLASS(type)))) { + has_copyctor = 1; + access = getaccesstype(access, obj->access, ACCESSPUBLIC); + arg = TYPE_FUNC(obj->type)->args->next; + if (TYPE_CLASS(type)->flags & CLASS_HAS_VBASES) + arg = arg->next; + if (!(arg->qual & Q_CONST)) + is_const = 0; + } + } + + if (has_copyctor) { + CDecl_AddMemberFunctionObject( + tclass, + constructor_name_node, + CDecl_MakeCopyCtorType(tclass, is_const), + access + ); + } +} + +static TypeMemberFunc *CDecl_MakeAssignmentOperatorType(TypeClass *tclass, Boolean is_const) { + FuncArg *arg; + TypeMemberFunc *tmeth = galloc(sizeof(TypeMemberFunc)); + memclrw(tmeth, sizeof(TypeMemberFunc)); + tmeth->type = TYPEFUNC; + tmeth->functype = CDecl_NewRefPointerType(TYPE(tclass)); + tmeth->flags = FUNC_AUTO_GENERATED | FUNC_METHOD; + tmeth->theclass = tclass; + CDecl_SetFuncFlags(TYPE_FUNC(tmeth), 1); + + arg = CParser_NewFuncArg(); + if (is_const) + arg->qual = Q_CONST; + arg->type = CDecl_NewRefPointerType(TYPE(tclass)); + tmeth->args = arg; + + CDecl_AddThisPointerArgument(TYPE_FUNC(tmeth), tclass); + return tmeth; +} + +static void CDecl_AddDefaultAssignmentOperator(ClassLayout *decle, TypeClass *tclass) { + ClassList *base; + ObjMemberVar *ivar; + Object *obj; + AccessType access; + Boolean is_const; + Boolean has_ass; + DeclInfo declinfo; + + is_const = 1; + has_ass = 0; + access = ACCESSPUBLIC; + + if (!CClass_AssignmentOperator(tclass)) { + if (!copts.old_argmatch) + has_ass = 1; + + if ((tclass->flags & CLASS_HAS_VBASES) || decle->has_vtable || CClass_MemberObject(tclass, asop_name_node)) + has_ass = 1; + + for (base = tclass->bases; base; base = base->next) { + if ((obj = CClass_AssignmentOperator(base->base))) { + has_ass = 1; + access = getaccesstype(access, obj->access, ACCESSPRIVATE); + if (!(TYPE_FUNC(obj->type)->args->next->qual & Q_CONST)) + is_const = 0; + } + } + + for (ivar = tclass->ivars; ivar; ivar = ivar->next) { + Type *type = ivar->type; + while (IS_TYPE_ARRAY(type)) + type = TYPE_POINTER(type)->target; + if (IS_TYPE_CLASS(type) && (obj = CClass_AssignmentOperator(TYPE_CLASS(type)))) { + has_ass = 1; + access = getaccesstype(access, obj->access, ACCESSPUBLIC); + if (!(TYPE_FUNC(obj->type)->args->next->qual & Q_CONST)) + is_const = 0; + } + } + } + + if (has_ass) { + memclrw(&declinfo, sizeof(DeclInfo)); + declinfo.qual |= Q_INLINE; + declinfo.thetype = (Type *) CDecl_MakeAssignmentOperatorType(tclass, is_const); + declinfo.name = asop_name_node; + CDecl_AddFunctionMember(decle, tclass, &declinfo, access, 1, 0, 0, 0); + } +} + +TypeMemberFunc *CDecl_MakeDefaultDtorType(TypeClass *tclass, Boolean is_virtual) { + TypeMemberFunc *tmeth = galloc(sizeof(TypeMemberFunc)); + memclrw(tmeth, sizeof(TypeMemberFunc)); + tmeth->type = TYPEFUNC; + tmeth->functype = (Type *) &void_ptr; + tmeth->flags = FUNC_IS_DTOR | FUNC_AUTO_GENERATED | FUNC_METHOD; + tmeth->theclass = tclass; + CDecl_SetFuncFlags(TYPE_FUNC(tmeth), 1); + if (is_virtual) + CDecl_AddArgument(TYPE_FUNC(tmeth), TYPE(&stsignedshort)); + CDecl_AddThisPointerArgument(TYPE_FUNC(tmeth), tclass); + return tmeth; +} + +static void CDecl_AddDefaultDestructor(ClassLayout *decle, TypeClass *tclass) { + ClassList *base; + ObjMemberVar *ivar; + Object *obj; + AccessType access; + Boolean has_dtor; + Boolean is_virtual; + DeclInfo declinfo; + + if (CClass_Destructor(tclass)) + return; + + has_dtor = 0; + is_virtual = 0; + access = ACCESSPUBLIC; + + for (base = tclass->bases; base; base = base->next) { + if ((obj = CClass_Destructor(base->base))) { + has_dtor = 1; + if (obj->datatype == DVFUNC) + is_virtual = 1; + access = getaccesstype(access, obj->access, ACCESSPRIVATE); + } + } + + for (ivar = tclass->ivars; ivar; ivar = ivar->next) { + Type *type = ivar->type; + while (IS_TYPE_ARRAY(type)) + type = TYPE_POINTER(type)->target; + if (IS_TYPE_CLASS(type) && (obj = CClass_Destructor(TYPE_CLASS(type)))) { + has_dtor = 1; + access = getaccesstype(access, obj->access, ACCESSPUBLIC); + } + } + + if (has_dtor) { + memclrw(&declinfo, sizeof(DeclInfo)); + declinfo.qual |= Q_INLINE; + if (is_virtual) + declinfo.qual |= Q_VIRTUAL; + + declinfo.thetype = (Type *) CDecl_MakeDefaultDtorType(tclass, 1); + declinfo.name = destructor_name_node; + CDecl_AddFunctionMember(decle, tclass, &declinfo, access, 1, 0, 0, 0); + } +} + +static void CDecl_SetupClassLayout(ClassLayout *decle, TypeClass *tclass, ObjBase **objbuf) { + SInt32 index; + SInt32 i; + Object *obj; + CScopeObjectIterator iter; + ObjMemberVar *ivar; + SInt32 bufsize; + + if (decle->lex_order_count > 32) { + bufsize = decle->lex_order_count * sizeof(ObjBase *); + objbuf = lalloc(bufsize); + } else { + bufsize = 32 * sizeof(ObjBase *); + } + memclrw(objbuf, bufsize); + decle->objlist = objbuf; + + CScope_InitObjectIterator(&iter, tclass->nspace); + index = 0; + while (1) { + obj = OBJECT(CScope_NextObjectIteratorObject(&iter)); + if (!obj) break; + + if (!IS_TYPE_FUNC(obj->type)) + continue; + if (!IS_TYPEFUNC_METHOD(TYPE_FUNC(obj->type))) + continue; + if (obj->datatype == DALIAS) + continue; + + i = TYPE_METHOD(obj->type)->vtbl_index; + if (i > 0) { + CError_ASSERT(6363, (i - 1) < decle->lex_order_count && !objbuf[(int) (i - 1)]); + objbuf[(int) (i - 1)] = OBJ_BASE(obj); + index++; + if (obj->datatype != DVFUNC && !TYPE_METHOD(obj->type)->is_static && CClass_OverridesBaseMember(tclass, obj->name, obj)) + CDecl_MakeFunctionVirtual(tclass, obj); + + if (obj->datatype == DVFUNC) { + decle->has_vtable = 1; + if (!tclass->vtable) { + CABI_AddVTable(tclass); + decle->xA = i - 1; + } else { + if ((i - 1) < decle->xA) + decle->xA = i - 1; + } + } else if (TYPE_FUNC(obj->type)->flags & FUNC_PURE) { + CError_Error(CErrorStr351, obj); + TYPE_FUNC(obj->type)->flags &= ~FUNC_PURE; + } + } else { + CError_ASSERT(6412, i == 0); + } + + if (!tclass->sominfo) + TYPE_METHOD(obj->type)->vtbl_index = 0; + } + + if (!tclass->action) { + for (i = 0; i < decle->lex_order_count; i++) { + Object *obj2 = OBJECT(objbuf[i]); + if (obj2 && obj2->datatype == DVFUNC && !(obj2->qual & Q_INLINE) && !(TYPE_FUNC(obj2->type)->flags & FUNC_PURE)) { + tclass->action = CLASS_ACTION_1; + TYPE_FUNC(obj2->type)->flags |= FUNC_FLAGS_4; + break; + } + } + } + + if (!tclass->sominfo) { + for (i = 0, ivar = tclass->ivars; i < decle->lex_order_count; i++) { + if (!objbuf[i]) { + CError_ASSERT(6449, ivar); + objbuf[i] = OBJ_BASE(ivar); + ivar = ivar->next; + index++; + } + } + CError_ASSERT(6455, ivar == NULL); + } + + CError_ASSERT(6458, index == decle->lex_order_count); +} + +void CDecl_CompleteClass(ClassLayout *decle, TypeClass *tclass) { + ClassList *base; + ObjBase *buf[32]; + + for (base = tclass->bases; base; base = base->next) { + if (base->base->vtable) + decle->has_vtable = 1; + } + + if (!tclass->sominfo) { + CDecl_AddDefaultDestructor(decle, tclass); + CDecl_AddDefaultAssignmentOperator(decle, tclass); + CDecl_AddDefaultConstructor(decle, tclass); + CDecl_AddDefaultCopyConstructor(decle, tclass); + } + + CDecl_SetupClassLayout(decle, tclass, buf); + if (decle->has_vtable) + CClass_CheckOverrides(tclass); + CABI_LayoutClass(decle, tclass); + if (tclass->sominfo) + CSOM_ClassComplete(tclass); + + if ((tclass->flags & CLASS_IS_TEMPL_INST) && !TEMPL_CLASS_INST(tclass)->is_specialized) + tclass->action = CLASS_ACTION_0; + + if (!tclass->action) + CClass_MakeStaticActionClass(tclass); + CClass_ClassDefaultFuncAction(tclass); +} + +TypeClass *CDecl_DefineClass(NameSpace *nspace, HashNameNode *name, TypeClass *tclass, short mode, Boolean flag2, Boolean flag3) { + NameSpace *mynspace; + ObjType *objtype; + + if (!tclass && nspace->theclass && (nspace->theclass->flags & CLASS_IS_TEMPL)) { + CError_ASSERT(6556, !flag2); + return TYPE_CLASS(CTemplClass_DefineNestedClass(TEMPL_CLASS(nspace->theclass), name, mode)); + } + + mynspace = CScope_NewListNameSpace(name, 1); + if (!tclass) { + tclass = galloc(sizeof(TypeClass)); + memclrw(tclass, sizeof(TypeClass)); + } + + tclass->type = TYPECLASS; + tclass->align = 1; + tclass->mode = mode; + tclass->action = CLASS_ACTION_0; + if (name) { + tclass->classname = name; + if (flag3) { + if (flag2) { + objtype = galloc(sizeof(ObjType)); + memclrw(objtype, sizeof(ObjType)); + objtype->otype = OT_TYPE; + objtype->access = ACCESSPUBLIC; + objtype->type = (Type *) tclass; + CScope_AddObject(nspace, name, OBJ_BASE(objtype)); + } else { + CScope_DefineTypeTag(nspace, name, (Type *) tclass); + } + } + CScope_DefineTypeTag(mynspace, name, (Type *) tclass); + + if (cscope_currentfunc) + mynspace->name = CParser_AppendUniqueNameFile(name->name); + + if (copts.direct_to_som && nspace == cscope_root && !strcmp(name->name, "SOMObject")) + CSOM_MakeSOMClass(tclass); + } else { + tclass->classname = CParser_AppendUniqueNameFile("@class"); + mynspace->name = tclass->classname; + } + + tclass->nspace = mynspace; + mynspace->theclass = tclass; + mynspace->parent = nspace; + if (!nspace->is_global) + CParser_RegisterNonGlobalClass(tclass); + + return tclass; +} + +void CDecl_ParseClassDeclSpec(UInt8 *declspec) { + DeclInfo declinfo; + + if ((tk = lex()) == '(') { + memclrw(&declinfo, sizeof(DeclInfo)); + CParser_ParseDeclSpec(&declinfo, 1); + if (declinfo.exportflags & EXPORT_FLAGS_INTERNAL) + *declspec = *declspec | CLASS_EFLAGS_INTERNAL; + if (declinfo.exportflags & EXPORT_FLAGS_IMPORT) + *declspec = *declspec | CLASS_EFLAGS_IMPORT; + if (declinfo.exportflags & EXPORT_FLAGS_EXPORT) + *declspec = *declspec | CLASS_EFLAGS_EXPORT; + if ((tk = lex()) != ')') + CError_Error(CErrorStr115); + else + tk = lex(); + } else { + CError_Error(CErrorStr114); + } +} + +static TemplClass *CDecl_SpecializeTemplateClass(TemplClass *tmclass) { + tmclass->theclass.nspace->names = 0; + tmclass->theclass.nspace->data.list = NULL; + tmclass->theclass.ivars = NULL; + tmclass->theclass.bases = NULL; + tmclass->theclass.vbases = NULL; + tmclass->theclass.friends = NULL; + tmclass->theclass.vtable = NULL; + tmclass->members = NULL; + tmclass->instances = NULL; + tmclass->pspec_owner = NULL; + tmclass->pspecs = NULL; + tmclass->actions = NULL; + tmclass->lex_order_count = 0; + tmclass->align = 0; + tmclass->flags = TEMPLCLASS_FLAGS_2; + return tmclass; +} + +void CDecl_ParseClass(DeclInfo *declinfo, short mode, Boolean flag1, UInt8 class_declspec) { + ClassLayout decle; + TypeClass *tclass; + HashNameNode *classname; + Type *search; + short t; + NameSpace *nspace; + NameResult pr; + CScopeSave scopesave; + GList gl; + FileOffsetInfo offsetsave; + SInt32 offset; + Boolean is_templ; + Boolean add_to_browse; + + memclrw(&decle, sizeof(ClassLayout)); + if (declinfo->x28) { + tclass = TYPE_CLASS(declinfo->x28); + } else { + if (tk == TK_UU_DECLSPEC) + CDecl_ParseClassDeclSpec(&class_declspec); + + switch (tk) { + case ':': + case '{': + tclass = CDecl_DefineClass(cscope_current, NULL, NULL, mode, 0, 1); + tclass->eflags |= class_declspec; + break; + case TK_IDENTIFIER: + classname = tkidentifier; + if (!declinfo->in_friend_decl && !declinfo->x4F && ((t = lookahead()) == ':' || t == ';' || t == '{')) { + tk = lex(); + search = CScope_GetLocalTagType(cscope_current, classname); + if (search) { + tagtype_search: + if (!IS_TYPE_CLASS(search)) { + if ((IS_TYPE_TEMPLATE(search) || IS_TYPE_STRUCT(search)) && tk != '{' && tk != ':') { + declinfo->thetype = search; + return; + } + if (!IS_TYPE_TEMPLATE(search) || !(tclass = TYPE_CLASS(CTemplTool_GetSelfRefTemplate(search)))) { + CError_Error(CErrorStr132, classname->name); + tclass = CDecl_DefineClass(cscope_current, NULL, NULL, mode, 0, 1); + break; + } + } else { + tclass = TYPE_CLASS(search); + } + if (tclass->mode != mode) { + if ( + (mode == CLASS_MODE_CLASS && tclass->mode == CLASS_MODE_STRUCT) || + (mode == CLASS_MODE_STRUCT && tclass->mode == CLASS_MODE_CLASS) + ) + { + if (copts.warn_structclass) + CError_Warning(CErrorStr343); + } else { + CError_Error(CErrorStr132, classname); + } + } + tclass->eflags |= class_declspec; + break; + } else { + tclass = CDecl_DefineClass(cscope_current, classname, NULL, mode, 0, 1); + tclass->eflags |= class_declspec; + break; + } + } else { + tkidentifier = classname; + } + default: + if (!CScope_ParseElaborateName(&pr)) { + CError_Error(CErrorStr121); + declinfo->thetype = TYPE(&stsignedint); + return; + } + + tk = lex(); + if ((search = pr.type)) { + goto tagtype_search; + } + + CError_ASSERT(6786, pr.name_4); + + tclass = CDecl_DefineClass(CScope_FindNonClassNonFunctionNS(cscope_current), pr.name_4, NULL, mode, 0, 1); + tclass->eflags |= class_declspec; + } + } + + declinfo->thetype = TYPE(tclass); + if (tk == ':' || tk == '{') { + if (declinfo->in_friend_decl) + CError_Error(CErrorStr201); + + if (tclass->flags & CLASS_COMPLETED) { + if ( + (tclass->flags & CLASS_IS_TEMPL) && + !TEMPL_CLASS(tclass)->instances && + !(TEMPL_CLASS(tclass)->flags & TEMPLCLASS_FLAGS_2) + ) + { + tclass = TYPE_CLASS(CDecl_SpecializeTemplateClass(TEMPL_CLASS(tclass))); + } else { + CError_Error(CErrorStr132, tclass->classname->name); + tclass = CDecl_DefineClass(cscope_current, NULL, NULL, mode, 0, 1); + } + } + + for (nspace = cscope_current; nspace; nspace = nspace->parent) { + if (nspace == tclass->nspace) { + CError_Error(CErrorStr132, tclass->classname->name); + tclass = CDecl_DefineClass(cscope_current, NULL, NULL, mode, 0, 1); + break; + } + } + + is_templ = (tclass->flags & CLASS_IS_TEMPL) != 0; + if (tclass->flags & CLASS_IS_TEMPL_INST) { + TEMPL_CLASS_INST(tclass)->is_instantiated = 1; + if (!declinfo->x28) + TEMPL_CLASS_INST(tclass)->is_specialized = 1; + } + + CError_ASSERT(6853, copts.structalignment >= 0 && copts.structalignment <= 14); + + tclass->eflags = tclass->eflags | (((copts.structalignment + 1) << 4) & 0xF0); + if (tk == ':') + CDecl_ParseBaseClassList(tclass, mode, is_templ); + + CScope_SetClassDefScope(tclass, &scopesave); + if (tk == '{') { + tk = lex(); + if ((add_to_browse = cparamblkptr->browseoptions.recordClasses && declinfo->file->recordbrowseinfo)) { + offsetsave = member_fileoffset; + CBrowse_BeginClass(declinfo, &gl); + } + CDecl_ParseClassMembers(&decle, tclass, mode); + offset = CPrep_BrowserFileOffset(); + if (flag1) + tk = lex(); + if (add_to_browse) { + member_fileoffset = offsetsave; + if (flag1 && tk == ';') + CPrep_BrowserFileOffset(); + CBrowse_EndClass(offset, &gl); + } + } else { + CError_Error(CErrorStr135); + } + + if (is_templ) + CTemplClass_CompleteClass(TEMPL_CLASS(tclass), &decle); + else + CDecl_CompleteClass(&decle, tclass); + CScope_RestoreScope(&scopesave); + } +} diff --git a/compiler_and_linker/FrontEnd/C/CError.c b/compiler_and_linker/FrontEnd/C/CError.c new file mode 100644 index 0000000..02265c3 --- /dev/null +++ b/compiler_and_linker/FrontEnd/C/CError.c @@ -0,0 +1,1098 @@ +#include "cos.h" +#include "compiler/CClass.h" +#include "compiler/CError.h" +#include "compiler/CFunc.h" +#include "compiler/CInt64.h" +#include "compiler/CMangler.h" +#include "compiler/CParser.h" +#include "compiler/CPrep.h" +#include "compiler/CPrepTokenizer.h" +#include "compiler/CTemplateNew.h" +#include "compiler/CompilerTools.h" +#include "compiler/InlineAsm.h" +#include "compiler/Unmangle.h" +#include "compiler/enode.h" +#include "compiler/objc.h" +#include "compiler/objects.h" +#include "compiler/scopes.h" +#include "compiler/templates.h" +#include "compiler/tokens.h" + +TStreamElement *cerror_locktoken; +static TStreamElement *cerror_token; +static short cerror_errorcount; +static SInt32 cerror_lasterrorline; +char cerror_synchdata[32]; +short cerror_synchoffset; +int CError_BreakPointcount; + +// forward decls +static void CError_BufferAppendType(CErrorBuffer *eb, Type *ty, UInt32 qual); +static void CError_AppendObjectName(CErrorBuffer *eb, Object *obj); + +void CError_Init(void) { + cerror_errorcount = 0; + cerror_lasterrorline = -1; + cerror_token = 0; + cerror_locktoken = 0; +} + +void CError_SetErrorToken(TStreamElement *token) { + if (token && token->tokenfile) + cerror_token = token; +} + +void CError_SetNullErrorToken(void) { + cerror_token = (TStreamElement *) -1; +} + +void CError_LockErrorPos(TStreamElement *token, TStreamElement **saved) { + *saved = cerror_locktoken; + if (token && token->tokenfile) + cerror_locktoken = token; +} + +void CError_UnlockErrorPos(TStreamElement **saved) { + cerror_locktoken = *saved; +} + +void CError_ResetErrorSkip(void) { + cerror_lasterrorline = -1; +} + +static void CError_GetErrorString(char *buf, short code) { + CError_ASSERT(142, code >= CErrorStr100 && code < CErrorStrMAX); + COS_GetString(buf, 10000, code - 99); +} + +static void CError_BufferInit(CErrorBuffer *eb, char *buf, SInt32 bufSize) { + eb->start = eb->end = buf; + eb->size = eb->remaining = bufSize - 1; +} + +static void CError_BufferGrow(CErrorBuffer *eb, SInt32 amount) { + char *newBuf; + + newBuf = lalloc(eb->size + amount); + memcpy(newBuf, eb->start, eb->size); + eb->start = newBuf; + eb->end = newBuf + eb->size - eb->remaining; + eb->size += amount; + eb->remaining += amount; +} + +static void CError_BufferAppendChar(CErrorBuffer *eb, char ch) { + if (eb) { + if (!eb->remaining) + CError_BufferGrow(eb, 256); + *(eb->end++) = ch; + eb->remaining--; + } +} + +static void CError_BufferAppendString(CErrorBuffer *eb, const char *str) { + size_t len; + + if (eb) { + len = strlen(str); + if (eb->remaining < len) + CError_BufferGrow(eb, len); + memcpy(eb->end, str, len); + eb->end += len; + eb->remaining -= len; + } +} + +static void CError_BufferTerminate(CErrorBuffer *eb) { + if (eb->remaining == 0) + CError_BufferGrow(eb, 1); + *eb->end = 0; + eb->remaining = 0; +} + +static void CError_BufferAppendQualifier(CErrorBuffer *eb, UInt32 qual) { + if (qual & Q_PASCAL) + CError_BufferAppendString(eb, "pascal "); + if (qual & Q_CONST) + CError_BufferAppendString(eb, "const "); + if (qual & Q_VOLATILE) + CError_BufferAppendString(eb, "volatile "); + if (qual & Q_EXPLICIT) + CError_BufferAppendString(eb, "explicit "); + if (qual & Q_RESTRICT) + CError_BufferAppendString(eb, "restrict "); +} + +static void CError_BufferAppendTemplArgExpr(CErrorBuffer *eb, ENode *node) { + char buf[32]; + + if (node) { + switch (node->type) { + case EINTCONST: + CInt64_PrintDec(buf, node->data.intval); + CError_BufferAppendString(eb, buf); + return; + case EOBJREF: + CError_BufferAppendChar(eb, '&'); + CError_AppendObjectName(eb, node->data.objref); + return; + } + } + + CError_BufferAppendString(eb, "{targ_expr}"); +} + +static void CError_BufferAppendTemplArg(CErrorBuffer *eb, TemplArg *targ) { + switch (targ->pid.type) { + case TPT_TYPE: + CError_BufferAppendType(eb, targ->data.typeparam.type, targ->data.typeparam.qual); + break; + case TPT_NONTYPE: + CError_BufferAppendTemplArgExpr(eb, targ->data.paramdecl.expr); + break; + case TPT_TEMPLATE: + CError_BufferAppendType(eb, targ->data.ttargtype, 0); + break; + default: + CError_FATAL(300); + } +} + +static void CError_BufferAppendTemplArgs(CErrorBuffer *eb, TemplArg *targs) { + if (targs) { + CError_BufferAppendChar(eb, '<'); + while (targs) { + CError_BufferAppendTemplArg(eb, targs); + if (targs->next) + CError_BufferAppendString(eb, ", "); + targs = targs->next; + } + CError_BufferAppendChar(eb, '>'); + } +} + +static void CError_BufferAppendNameSpace(CErrorBuffer *eb, NameSpace *nspace) { + while (nspace) { + if (nspace->name) { + CError_BufferAppendNameSpace(eb, nspace->parent); + if (nspace->theclass) { + CError_BufferAppendString(eb, nspace->theclass->classname->name); + if (nspace->theclass->flags & CLASS_IS_TEMPL_INST) + CError_BufferAppendTemplArgs( + eb, + !TEMPL_CLASS_INST(nspace->theclass)->oargs ? TEMPL_CLASS_INST(nspace->theclass)->inst_args : TEMPL_CLASS_INST(nspace->theclass)->oargs + ); + } else { + CError_BufferAppendString(eb, nspace->name->name); + } + CError_BufferAppendString(eb, "::"); + return; + } + nspace = nspace->parent; + } +} + +static void CError_BufferAppendPType(CErrorBuffer *eb, Type *ty) { + switch (ty->type) { + case TYPEPOINTER: + CError_BufferAppendPType(eb, TYPE_POINTER(ty)->target); + if (TYPE_POINTER(ty)->qual & Q_REFERENCE) + CError_BufferAppendString(eb, "&"); + else + CError_BufferAppendString(eb, "*"); + CError_BufferAppendQualifier(eb, TYPE_POINTER(ty)->qual); + break; + case TYPEMEMBERPOINTER: + CError_BufferAppendPType(eb, TYPE_MEMBER_POINTER(ty)->ty1); + CError_BufferAppendType(eb, TYPE_MEMBER_POINTER(ty)->ty2, 0); + CError_BufferAppendString(eb, "::*"); + CError_BufferAppendQualifier(eb, TYPE_MEMBER_POINTER(ty)->qual); + break; + } +} + +static void CError_BufferAppendTemplDepType(CErrorBuffer *eb, TypeTemplDep *type) { + char buf[64]; + switch (type->dtype) { + case TEMPLDEP_ARGUMENT: + if (type->u.pid.nindex) + sprintf(buf, "T%" PRId32 "_%" PRId32, type->u.pid.nindex, type->u.pid.index); + else + sprintf(buf, "T%" PRId32, type->u.pid.index); + CError_BufferAppendString(eb, buf); + break; + case TEMPLDEP_QUALNAME: + CError_BufferAppendTemplDepType(eb, type->u.qual.type); + CError_BufferAppendString(eb, "::"); + CError_BufferAppendString(eb, type->u.qual.name->name); + break; + case TEMPLDEP_TEMPLATE: + CError_BufferAppendType(eb, (Type *) type->u.templ.templ, 0); + CError_BufferAppendTemplArgs(eb, type->u.templ.args); + break; + case TEMPLDEP_ARRAY: + CError_BufferAppendType(eb, type->u.array.type, 0); + CError_BufferAppendChar(eb, '['); + CError_BufferAppendTemplArgExpr(eb, type->u.array.index); + CError_BufferAppendChar(eb, ']'); + break; + case TEMPLDEP_QUALTEMPL: + CError_BufferAppendTemplDepType(eb, type->u.qualtempl.type); + CError_BufferAppendString(eb, "::"); + CError_BufferAppendTemplArgs(eb, type->u.qualtempl.args); + break; + case TEMPLDEP_BITFIELD: + CError_BufferAppendType(eb, type->u.bitfield.type, 0); + CError_BufferAppendChar(eb, '['); + CError_BufferAppendTemplArgExpr(eb, type->u.bitfield.size); + CError_BufferAppendChar(eb, ']'); + break; + default: + CError_FATAL(463); + } +} + +static void CError_BufferAppendFuncArgs(CErrorBuffer *eb, TypeFunc *tfunc, Boolean isMethod) { + FuncArg *arg; + UInt32 qual; + + qual = 0; + CError_BufferAppendChar(eb, '('); + if ((arg = tfunc->args)) { + if (isMethod) { + qual = arg->qual; + arg = arg->next; + if (arg) + arg = arg->next; + } else if ((tfunc->flags & FUNC_METHOD) && !TYPE_METHOD(tfunc)->is_static) { + qual = arg->qual; + arg = arg->next; + if (arg) { + if ((tfunc->flags & FUNC_IS_DTOR) || ((tfunc->flags & FUNC_IS_CTOR) && (TYPE_METHOD(tfunc)->theclass->flags & CLASS_HAS_VBASES))) + arg = arg->next; + } + } + + while (arg) { + if (arg == &elipsis || arg == &oldstyle) { + CError_BufferAppendString(eb, "..."); + break; + } + + CError_BufferAppendType(eb, arg->type, arg->qual); + + if ((arg = arg->next)) + CError_BufferAppendString(eb, ", "); + else + break; + } + } + CError_BufferAppendChar(eb, ')'); + if (qual) + CError_BufferAppendQualifier(eb, qual); +} + +static void CError_BufferAppendType(CErrorBuffer *eb, Type *ty, UInt32 qual) { + // not matching - register issues + Type *scan; + Type *scan2; + char buf[16]; + + switch (ty->type) { + case TYPEVOID: + CError_BufferAppendQualifier(eb, qual); + CError_BufferAppendString(eb, "void"); + return; + case TYPEINT: + case TYPEFLOAT: + CError_BufferAppendQualifier(eb, qual); + switch (TYPE_INTEGRAL(ty)->integral) { + case IT_BOOL: + CError_BufferAppendString(eb, "bool"); + return; + case IT_CHAR: + CError_BufferAppendString(eb, "char"); + return; + case IT_UCHAR: + CError_BufferAppendString(eb, "unsigned char"); + return; + case IT_SCHAR: + CError_BufferAppendString(eb, "signed char"); + return; + case IT_WCHAR_T: + CError_BufferAppendString(eb, "wchar_t"); + return; + case IT_SHORT: + CError_BufferAppendString(eb, "short"); + return; + case IT_USHORT: + CError_BufferAppendString(eb, "unsigned short"); + return; + case IT_INT: + CError_BufferAppendString(eb, "int"); + return; + case IT_UINT: + CError_BufferAppendString(eb, "unsigned int"); + return; + case IT_LONG: + CError_BufferAppendString(eb, "long"); + return; + case IT_ULONG: + CError_BufferAppendString(eb, "unsigned long"); + return; + case IT_LONGLONG: + CError_BufferAppendString(eb, "long long"); + return; + case IT_ULONGLONG: + CError_BufferAppendString(eb, "unsigned long long"); + return; + case IT_FLOAT: + CError_BufferAppendString(eb, "float"); + return; + case IT_SHORTDOUBLE: + CError_BufferAppendString(eb, "short double"); + return; + case IT_DOUBLE: + CError_BufferAppendString(eb, "double"); + return; + case IT_LONGDOUBLE: + CError_BufferAppendString(eb, "long double"); + return; + default: + CError_FATAL(584); + } + case TYPEENUM: + CError_BufferAppendQualifier(eb, qual); + CError_BufferAppendNameSpace(eb, TYPE_ENUM(ty)->nspace); + if (TYPE_ENUM(ty)->enumname) + CError_BufferAppendString(eb, TYPE_ENUM(ty)->enumname->name); + else + CError_BufferAppendString(eb, "{unnamed-enum}"); + return; + case TYPESTRUCT: + CError_BufferAppendQualifier(eb, qual); + switch (TYPE_STRUCT(ty)->stype) { + case STRUCT_TYPE_STRUCT: + CError_BufferAppendString(eb, "struct "); + break; + case STRUCT_TYPE_UNION: + CError_BufferAppendString(eb, "union "); + break; + case STRUCT_VECTOR_UCHAR: + case STRUCT_VECTOR_SCHAR: + case STRUCT_VECTOR_BCHAR: + case STRUCT_VECTOR_USHORT: + case STRUCT_VECTOR_SSHORT: + case STRUCT_VECTOR_BSHORT: + case STRUCT_VECTOR_UINT: + case STRUCT_VECTOR_SINT: + case STRUCT_VECTOR_BINT: + case STRUCT_VECTOR_FLOAT: + case STRUCT_VECTOR_PIXEL: + break; + default: + CError_FATAL(618); + } + if (TYPE_STRUCT(ty)->name) + CError_BufferAppendString(eb, TYPE_STRUCT(ty)->name->name); + return; + case TYPECLASS: + CError_BufferAppendQualifier(eb, qual); + CError_BufferAppendNameSpace(eb, TYPE_CLASS(ty)->nspace->parent); + if (TYPE_CLASS(ty)->classname) { + CError_BufferAppendString(eb, TYPE_CLASS(ty)->classname->name); + if (TYPE_CLASS(ty)->flags & CLASS_IS_TEMPL_INST) + CError_BufferAppendTemplArgs( + eb, + TEMPL_CLASS_INST(ty)->oargs ? TEMPL_CLASS_INST(ty)->oargs : TEMPL_CLASS_INST(ty)->inst_args + ); + } else { + CError_BufferAppendString(eb, "{unnamed-class}"); + } + return; + case TYPEPOINTER: + case TYPEMEMBERPOINTER: + scan = ty; + next_ptr: + switch (scan->type) { + case TYPEPOINTER: + scan = TYPE_POINTER(scan)->target; + goto next_ptr; + case TYPEMEMBERPOINTER: + scan = TYPE_MEMBER_POINTER(scan)->ty1; + goto next_ptr; + } + + CError_BufferAppendQualifier(eb, qual); + switch (scan->type) { + case TYPEFUNC: + if (TYPE_FUNC(scan)->flags & FUNC_PASCAL) + CError_BufferAppendString(eb, "pascal "); + CError_BufferAppendType(eb, TYPE_FUNC(scan)->functype, 0); + CError_BufferAppendString(eb, " ("); + CError_BufferAppendPType(eb, ty); + CError_BufferAppendChar(eb, ')'); + CError_BufferAppendFuncArgs(eb, TYPE_FUNC(scan), ty->type == TYPEMEMBERPOINTER); + return; + case TYPEARRAY: + scan2 = scan; + while (scan->type == TYPEARRAY) + scan = TYPE_POINTER(scan)->target; + CError_BufferAppendType(eb, scan, 0); + CError_BufferAppendString(eb, " ("); + CError_BufferAppendPType(eb, ty); + CError_BufferAppendChar(eb, ')'); + ty = scan2; + goto append_array_lengths; + default: + CError_BufferAppendType(eb, scan, 0); + CError_BufferAppendChar(eb, ' '); + CError_BufferAppendPType(eb, ty); + return; + } + break; + case TYPEFUNC: + if (TYPE_FUNC(ty)->flags & FUNC_PASCAL) + CError_BufferAppendString(eb, "pascal "); + CError_BufferAppendQualifier(eb, qual); + CError_BufferAppendType(eb, TYPE_FUNC(ty)->functype, 0); + CError_BufferAppendChar(eb, ' '); + CError_BufferAppendFuncArgs(eb, TYPE_FUNC(ty), 0); + return; + case TYPEARRAY: + CError_BufferAppendQualifier(eb, qual); + scan = ty; + while (scan->type == TYPEARRAY) + scan = TYPE_POINTER(scan)->target; + CError_BufferAppendType(eb, scan, 0); + append_array_lengths: + while (ty->type == TYPEARRAY) { + CError_BufferAppendChar(eb, '['); + if (ty->size && TYPE_POINTER(ty)->target->size) { + sprintf(buf, "%" PRId32, ty->size / TYPE_POINTER(ty)->target->size); + CError_BufferAppendString(eb, buf); + } + CError_BufferAppendChar(eb, ']'); + ty = TYPE_POINTER(ty)->target; + } + return; + case TYPETEMPLATE: + CError_BufferAppendQualifier(eb, qual); + CError_BufferAppendTemplDepType(eb, TYPE_TEMPLATE(ty)); + return; + case TYPETEMPLDEPEXPR: + CError_BufferAppendString(eb, "T"); + return; + case TYPEBITFIELD: + sprintf(buf, "bitfield:%" PRId32, TYPE_BITFIELD(ty)->bitlength); + CError_BufferAppendString(eb, buf); + return; + default: + CError_FATAL(752); + } +} + +char *CError_GetTypeName(Type *ty, UInt32 qual, Boolean useGlobalHeap) { + CErrorBuffer eb; + char buf[256]; + char *ptr; + + CError_BufferInit(&eb, buf, sizeof(buf)); + CError_BufferAppendType(&eb, ty, qual); + CError_BufferTerminate(&eb); + + if (useGlobalHeap) + ptr = galloc(eb.size + 1); + else + ptr = lalloc(eb.size + 1); + + return strcpy(ptr, eb.start); +} + +static void CError_AppendUnqualFunctionName(CErrorBuffer *eb, NameSpace *nspace, HashNameNode *name, TypeFunc *tfunc) { + Boolean flag = 0; + char *opname; + + if (nspace && nspace->theclass) { + if (name == constructor_name_node) { + CError_BufferAppendString(eb, nspace->theclass->classname->name); + flag = 1; + } else if (name == destructor_name_node) { + CError_BufferAppendChar(eb, '~'); + CError_BufferAppendString(eb, nspace->theclass->classname->name); + flag = 1; + } + } + + if (!flag) { + opname = CMangler_GetOperator(name); + if (!opname) { + if (tfunc && (tfunc->flags & FUNC_CONVERSION)) { + CError_BufferAppendString(eb, "operator "); + CError_BufferAppendType(eb, tfunc->functype, tfunc->qual); + } else { + CError_BufferAppendString(eb, name->name); + } + } else { + CError_BufferAppendString(eb, opname); + } + } +} + +static void CError_AppendFunctionName(CErrorBuffer *eb, NameSpace *nspace, HashNameNode *name, TemplArg *templargs, TypeFunc *tfunc) { + while (nspace->is_templ && nspace->parent) + nspace = nspace->parent; + + CError_BufferAppendNameSpace(eb, nspace); + CError_AppendUnqualFunctionName(eb, nspace, name, tfunc); + CError_BufferAppendTemplArgs(eb, templargs); + if (tfunc) { + if (!templargs && (tfunc->flags & FUNC_IS_TEMPL)) + CError_BufferAppendString(eb, "<...>"); + CError_BufferAppendFuncArgs(eb, tfunc, 0); + } else { + CError_BufferAppendString(eb, "()"); + } +} + +static void CError_AppendObjectName(CErrorBuffer *eb, Object *obj) { + if (obj->type->type == TYPEFUNC) { + CError_AppendFunctionName(eb, obj->nspace, obj->name, obj->u.func.inst ? obj->u.func.inst->args : NULL, TYPE_FUNC(obj->type)); + } else { + CError_BufferAppendNameSpace(eb, obj->nspace); + CError_BufferAppendString(eb, obj->name->name); + } +} + +static void CError_AppendMethodName(CErrorBuffer *eb, ObjCMethod *meth) { + ObjCMethodArg *arg; + + CError_BufferAppendChar(eb, meth->is_class_method ? '+' : '-'); + CError_BufferAppendChar(eb, '('); + CError_BufferAppendType(eb, meth->return_type, meth->return_qual); + CError_BufferAppendChar(eb, ')'); + for (arg = meth->selector_args; arg; arg = arg->next) { + if (arg->selector) + CError_BufferAppendString(eb, arg->selector->name); + if (arg->type) { + CError_BufferAppendString(eb, ":("); + CError_BufferAppendType(eb, arg->type, arg->qual); + CError_BufferAppendChar(eb, ')'); + } + } + if (meth->has_valist) + CError_BufferAppendString(eb, ",..."); +} + +char *CError_GetQualifiedName(NameSpace *nspace, HashNameNode *name) { + CErrorBuffer eb; + char buf[256]; + char *ptr; + + CError_BufferInit(&eb, buf, sizeof(buf)); + CError_BufferAppendNameSpace(&eb, nspace); + CError_BufferAppendString(&eb, name->name); + CError_BufferTerminate(&eb); + + ptr = lalloc(eb.size + 1); + return strcpy(ptr, eb.start); +} + +char *CError_GetFunctionName(NameSpace *nspace, HashNameNode *name, TypeFunc *tfunc) { + CErrorBuffer eb; + char buf[256]; + char *ptr; + + CError_BufferInit(&eb, buf, sizeof(buf)); + CError_AppendFunctionName(&eb, nspace, name, 0, tfunc); + CError_BufferTerminate(&eb); + + ptr = lalloc(eb.size + 1); + return strcpy(ptr, eb.start); +} + +char *CError_GetObjectName(Object *obj) { + CErrorBuffer eb; + char buf[256]; + char *ptr; + + CError_BufferInit(&eb, buf, sizeof(buf)); + CError_AppendObjectName(&eb, obj); + CError_BufferTerminate(&eb); + + ptr = lalloc(eb.size + 1); + return strcpy(ptr, eb.start); +} + +char *CError_GetNameString(NameSpace *nspace, HashNameNode *operatorName) { + CErrorBuffer eb; + char buf[256]; + char *ptr; + char *opStr; + + CError_ASSERT(973, operatorName); + + opStr = CMangler_GetOperator(operatorName); + if (!opStr) + opStr = operatorName->name; + + if (nspace && nspace->name) { + CError_BufferInit(&eb, buf, sizeof(buf)); + CError_BufferAppendNameSpace(&eb, nspace); + CError_BufferAppendString(&eb, opStr); + CError_BufferTerminate(&eb); + ptr = lalloc(eb.size + 1); + return strcpy(ptr, eb.start); + } else { + return opStr; + } +} + +void CError_ErrorMessage(int errTable, char *str, Boolean flag1, Boolean flag2) { + TStreamElement *token; + short tokensize; + CPrepFileInfo *tokenfile; + CWMessageRef myref; + char buf[128]; + CWMessageRef *ref; + unsigned char messagetype; + + if (CWDisplayLines(cparamblkptr->context, lines) != cwNoErr) + CError_UserBreak(); + + if (!in_assembler && !flag1 && cerror_lasterrorline == lines) { + if (cerror_errorcount++ >= 50) { + if (cerror_errorcount > 60) + longjmp(errorreturn, 1); + tk = lex(); + cerror_errorcount = 0; + if (tk == 0) { + CompilerGetCString(1, buf); + CWReportMessage(cparamblkptr->context, NULL, buf, NULL, messagetypeError, errTable); + longjmp(errorreturn, 1); + } + } + } else { + if (!flag2) { + cerror_lasterrorline = lines; + cerror_errorcount = 0; + } + if (copts.warningerrors) + flag2 = 0; + + if (cerror_token) + token = cerror_token; + else if (cerror_locktoken) + token = cerror_locktoken; + else + token = NULL; + //token = cerror_token ? cerror_token : cerror_locktoken ? cerror_locktoken : NULL; + if ((SInt32) token == -1) { + ref = NULL; + } else { + CPrep_GetTokenContext(token, &tokenfile, &myref.selectionoffset, &tokensize, &myref.linenumber, buf, &myref.tokenoffset, &myref.tokenlength, cerror_synchdata, &cerror_synchoffset); + myref.selectionlength = tokensize; + myref.sourcefile = tokenfile->textfile; + ref = &myref; + } + messagetype = flag2 ? messagetypeWarning : messagetypeError; + if (!flag2) { + anyerrors = 1; + fatalerrors = 1; + } + if (CWReportMessage(cparamblkptr->context, ref, str, buf, messagetype, errTable) != cwNoErr) + longjmp(errorreturn, 1); + } + + cerror_token = NULL; +} + +static void CError_BufferAppendTemplateStack(CErrorBuffer *eb) { + TemplStack *stack[64]; + TemplStack *scan; + int index; + int indent; + int count; + + scan = ctempl_curinstance; + for (count = 0; scan && count < 64; count++) { + stack[count] = scan; + scan = scan->next; + } + + for (index = count - 1; index >= 0; index--) { + CError_BufferAppendChar(eb, LF); + for (indent = index; indent < count; indent++) + CError_BufferAppendChar(eb, ' '); + CError_BufferAppendString(eb, "(instantiating: '"); + if (stack[index]->is_func) + CError_AppendObjectName(eb, stack[index]->u.func); + else + CError_BufferAppendType(eb, (Type *) stack[index]->u.theclass, 0); + CError_BufferAppendString(eb, "')"); + } + + CError_BufferTerminate(eb); +} + +void CError_ErrorMessageVA(int code, const char *format, va_list list, Boolean flag1, Boolean flag2) { + // register allocation is fucked, matches otherwise + CErrorBuffer eb; + char buf[256]; + char unmangleBuf[256]; + SInt32 moddate; + Type *type; + UInt32 qual; + const char *p; + CError_BufferInit(&eb, buf, sizeof(buf)); + + p = format; + do { + switch (p[0]) { + case 0: + break; + case '%': + switch (p[1]) { + case 'n': + MWUnmangle(va_arg(list, const char *), unmangleBuf, sizeof(unmangleBuf)); + CError_BufferAppendString(&eb, unmangleBuf); + p += 2; + continue; + case 'u': + CError_BufferAppendString(&eb, va_arg(list, const char *)); + p += 2; + continue; + case 'o': + CError_AppendObjectName(&eb, va_arg(list, Object *)); + p += 2; + continue; + case 'm': + CError_AppendMethodName(&eb, va_arg(list, ObjCMethod *)); + p += 2; + continue; + case 't': + type = va_arg(list, Type *); + qual = va_arg(list, UInt32); + CError_BufferAppendType(&eb, type, qual); + p += 2; + continue; + case '%': + CError_BufferAppendChar(&eb, '%'); + p += 2; + continue; + case 'i': + sprintf(unmangleBuf, "%" PRId32, va_arg(list, SInt32)); + CError_BufferAppendString(&eb, unmangleBuf); + p += 2; + continue; + case 'f': + CError_BufferAppendString(&eb, CTool_GetPathName(va_arg(list, FSSpec *), &moddate)->name); + p += 2; + continue; + default: + CError_FATAL(1174); + } + break; + default: + CError_BufferAppendChar(&eb, *(p++)); + continue; + } + break; + } while (1); + + CError_BufferAppendTemplateStack(&eb); + CError_ErrorMessage(code, eb.start, flag1, flag2); +} + +static void CError_VAErrorMessage(int code, va_list list, Boolean flag1, Boolean flag2) { + char buf[256]; + + CError_GetErrorString(buf, code); + CError_ErrorMessageVA(code + 10000, buf, list, flag1, flag2); +} + +void CError_Error(int code, ...) { + va_list va; + + if (trychain) + longjmp(trychain->jmpbuf, 1); + + va_start(va, code); + CError_VAErrorMessage(code, va, 0, 0); + va_end(va); + + if (in_assembler && !preprocessing_only) + AssemblerError(); +} + +void CError_ErrorTerm(short code) { + CError_GetErrorString(string, code); + CError_ErrorMessage(code + 10000, string, 0, 0); + longjmp(errorreturn, 1); +} + +void CError_ErrorSkip(int code, ...) { + va_list va; + + if (trychain) + longjmp(trychain->jmpbuf, 1); + + va_start(va, code); + CError_VAErrorMessage(code, va, 0, 0); + va_end(va); + + if (tk != ';' && tk != ')' && tk != '}' && tk != ',' && tk != ']') + tk = lex(); +} + +void CError_ErrorFuncCall(short code, NameSpaceObjectList *args, ENodeList *argNodes) { + // does not match - one branch has loop weirdness + CErrorBuffer eb; + char buf[256]; + char *p; + ENodeList *argscan; + + if (trychain) + longjmp(trychain->jmpbuf, 1); + + CError_GetErrorString(string, code); + CError_BufferInit(&eb, buf, sizeof(buf)); + + while (args && args->object->otype != OT_OBJECT) + args = args->next; + CError_ASSERT(1268, args); + + p = string; + do { + switch (*p) { + case 0: + goto exit_main_loop; + case '*': + if (OBJECT(args->object)->type->type == TYPEFUNC) { + CError_AppendUnqualFunctionName( + &eb, + OBJECT(args->object)->nspace, + OBJECT(args->object)->name, + TYPE_FUNC(OBJECT(args->object)->type)); + if (TYPE_FUNC(OBJECT(args->object)->type)->flags & FUNC_METHOD) + if (TYPE_FUNC(OBJECT(args->object)->type)->flags & FUNC_IS_CTOR) + if (TYPE_METHOD(OBJECT(args->object)->type)->theclass->flags & CLASS_HAS_VBASES) + if (argNodes) + argNodes = argNodes->next; + } else { + CError_BufferAppendString(&eb, OBJECT(args->object)->name->name); + } + CError_BufferAppendChar(&eb, '('); + argscan = argNodes; + while (argscan) { + CError_BufferAppendType(&eb, argscan->node->rtype, argscan->node->flags & ENODE_FLAG_QUALS); + if ((argscan = argscan->next)) + CError_BufferAppendString(&eb, ", "); + else + break; + } + CError_BufferAppendChar(&eb, ')'); + break; + default: + CError_BufferAppendChar(&eb, *p); + } + p++; + } while (1); + +exit_main_loop: + while (args) { + if (args->object->otype == OT_OBJECT) { + CError_BufferAppendChar(&eb, LF); + CError_BufferAppendChar(&eb, '\''); + CError_AppendObjectName(&eb, (Object *) args->object); + CError_BufferAppendChar(&eb, '\''); + } + args = args->next; + } + + CError_BufferAppendTemplateStack(&eb); + CError_ErrorMessage(10000 + code, eb.start, 0, 0); +} + +void CError_OverloadedFunctionError2(Object *obj, ObjectList *olst, ENodeList *argNodes) { + // not sure if the arg is actually ObjectList since it's never called lmao + NameSpaceObjectList first; + NameSpaceObjectList *current; + + first.object = (ObjBase *) obj; + current = &first; + while (olst) { + current->next = lalloc(sizeof(NameSpaceObjectList)); + current = current->next; + current->object = (ObjBase *) olst->object; + olst = olst->next; + } + current->next = NULL; + + CError_ErrorFuncCall(CErrorStr392, &first, argNodes); +} + +void CError_OverloadedFunctionError(Object *obj, ObjectList *olst) { + // not sure if this arg is ObjectList or NameSpaceObjectList + CErrorBuffer eb; + char buf[256]; + + if (trychain) + longjmp(trychain->jmpbuf, 1); + + CError_GetErrorString(string, CErrorStr199); + CError_BufferInit(&eb, buf, sizeof(buf)); + CError_BufferAppendString(&eb, string); + + if (obj) { + CError_BufferAppendChar(&eb, LF); + CError_BufferAppendChar(&eb, '\''); + CError_AppendObjectName(&eb, obj); + CError_BufferAppendChar(&eb, '\''); + } + while (olst) { + CError_BufferAppendChar(&eb, LF); + CError_BufferAppendChar(&eb, '\''); + CError_AppendObjectName(&eb, olst->object); + CError_BufferAppendChar(&eb, '\''); + olst = olst->next; + } + CError_BufferAppendTemplateStack(&eb); + CError_ErrorMessage(10199, eb.start, 0, 0); +} + +void CError_AbstractClassError(TypeClass *tclass) { + Object *result = CClass_CheckPures(tclass); + if (!result) + CError_Error(CErrorStr372, tclass, 0); + else + CError_Error(CErrorStr194, result); +} + +void CError_Warning(int code, ...) { + va_list va; + if (trychain || copts.supress_warnings) + return; + + va_start(va, code); + CError_VAErrorMessage(code, va, 0, 1); + va_end(va); +} + +void CError_BreakPoint(const char *a, const char *b) { + if (!a || !strcmp(a, b)) + CError_BreakPointcount++; +} + +void CError_Internal(char *filename, int line) { + char tmp[128]; + CompilerGetCString(5, tmp); + sprintf(string, tmp, filename, line); + CError_ErrorMessage(10001, string, 1, 0); + longjmp(errorreturn, 1); + CError_BreakPoint(0, 0); +} + +void CError_ExpressionTooComplex(void) { + CompilerGetCString(6, string); + CError_ErrorMessage(10002, string, 1, 0); + longjmp(errorreturn, 1); +} + +void CError_NoMem(void) { + cprep_nomem_exit = 1; + longjmp(errorreturn, 1); +} + +void CError_UserBreak(void) { + CompilerGetCString(8, string); + longjmp(errorreturn, 1); +} + +void CError_CannotOpen(void) { + CompilerGetCString(9, string); + CWReportMessage(cparamblkptr->context, NULL, string, NULL, messagetypeError, 0); + longjmp(errorreturn, 1); +} + +void CError_QualifierCheck(UInt32 qual) { + if (qual) { + Boolean anything = 0; + + if (qual & Q_CONST) { + CError_Error(CErrorStr313, "const"); + anything = 1; + } + if (qual & Q_VOLATILE) { + CError_Error(CErrorStr313, "volatile"); + anything = 1; + } + if (qual & Q_RESTRICT) { + CError_Error(CErrorStr313, "restrict"); + anything = 1; + } + if (qual & Q_ASM) { + CError_Error(CErrorStr313, "asm"); + anything = 1; + } + if (qual & Q_PASCAL) { + CError_Error(CErrorStr313, "pascal"); + anything = 1; + } + if (qual & Q_INLINE) { + CError_Error(CErrorStr313, "inline"); + anything = 1; + } + if (qual & Q_REFERENCE) { + CError_Error(CErrorStr313, "& reference type"); + anything = 1; + } + if (qual & Q_EXPLICIT) { + CError_Error(CErrorStr313, "explicit"); + anything = 1; + } + if (qual & Q_MUTABLE) { + CError_Error(CErrorStr313, "mutable"); + anything = 1; + } + if (qual & Q_VIRTUAL) { + CError_Error(CErrorStr313, "virtual"); + anything = 1; + } + if (qual & Q_FRIEND) { + CError_Error(CErrorStr313, "friend"); + anything = 1; + } + if (qual & Q_IN) { + CError_Error(CErrorStr313, "in"); + anything = 1; + } + if (qual & Q_OUT) { + CError_Error(CErrorStr313, "out"); + anything = 1; + } + if (qual & Q_INOUT) { + CError_Error(CErrorStr313, "inout"); + anything = 1; + } + if (qual & Q_BYCOPY) { + CError_Error(CErrorStr313, "bycopy"); + anything = 1; + } + if (qual & Q_BYREF) { + CError_Error(CErrorStr313, "byref"); + anything = 1; + } + if (qual & Q_ONEWAY) { + CError_Error(CErrorStr313, "oneway"); + anything = 1; + } + if (qual & Q_ALIGNED_MASK) { + CError_Error(CErrorStr313, "__attribute__((aligned(?)))"); + anything = 1; + } + + if (!anything) + CError_Error(CErrorStr176); + } +} diff --git a/compiler_and_linker/FrontEnd/C/CException.c b/compiler_and_linker/FrontEnd/C/CException.c new file mode 100644 index 0000000..d68ce13 --- /dev/null +++ b/compiler_and_linker/FrontEnd/C/CException.c @@ -0,0 +1,2183 @@ +#include "compiler/CException.h" +#include "compiler/CABI.h" +#include "compiler/CClass.h" +#include "compiler/CDecl.h" +#include "compiler/CError.h" +#include "compiler/CExpr.h" +#include "compiler/CFunc.h" +#include "compiler/CInline.h" +#include "compiler/CInit.h" +#include "compiler/CMachine.h" +#include "compiler/CMangler.h" +#include "compiler/CParser.h" +#include "compiler/CPrep.h" +#include "compiler/CPrepTokenizer.h" +#include "compiler/CScope.h" +#include "compiler/CompilerTools.h" +#include "compiler/Exceptions.h" +#include "compiler/objects.h" +#include "compiler/scopes.h" +#include "compiler/types.h" + +typedef struct UniqueObj { + struct UniqueObj *next; + Object *object; + SInt32 uniqueid; +} UniqueObj; + +ExceptionAction *cexcept_dobjstack; +Boolean cexcept_hasdobjects; +Boolean cexcept_magic; +static UniqueObj *cexcept_uniqueobjs; +static Boolean cexcept_canthrow; +static DtorTemp *cexcept_dtortemps; +static Statement *cexcept_prevstmt; +static ExceptionAction *cexcept_eabefore; +static ExceptionAction *cexcept_eaafter; +static Boolean cexcept_expandtrycatch; +static Boolean cexcept_hastrycatch; +static Boolean cexcept_serialize; + +// forward decls +static ENode *CExcept_TempTransExprCond(ENode *expr); +static ENode *CExcept_TempTransExpr(ENode *expr); + +void CExcept_Setup(void) { + cexcept_dobjstack = NULL; + cexcept_uniqueobjs = NULL; + cexcept_hasdobjects = 0; + cexcept_magic = 0; +} + +Boolean CExcept_CanThrowException(Object *object, Boolean flag) { + if (copts.optEH && IS_TYPE_FUNC(object->type)) { + if (flag) + return 1; + + if (TYPE_FUNC(object->type)->flags & FUNC_NOTHROW) + return 0; + + if ( + !flag && + TYPE_FUNC(object->type)->exspecs && + TYPE_FUNC(object->type)->exspecs && + !TYPE_FUNC(object->type)->exspecs->type + ) + return 0; + + if ( + copts.optEH2 && + !(object->qual & Q_MANGLE_NAME) && + object != rt_ptmf_call && + object != rt_ptmf_scall && + object != Rdync_func && + object != rt_som_glue1 && + object != rt_som_glue2 && + object != rt_som_glue3 && + object != carr_func && + object != cnar_func && + object != darr_func && + object != dnar_func && + object != dnar3_func && + object != Xthrw_func + ) + return 0; + } + + return 1; +} + +void CExcept_CheckStackRefs(ExceptionAction *actions) { + while (actions) { + switch (actions->type) { + case EAT_DESTROYLOCAL: + CInline_ObjectAddrRef(actions->data.destroy_local.dtor); + break; + case EAT_DESTROYLOCALCOND: + CInline_ObjectAddrRef(actions->data.destroy_local_cond.dtor); + break; + case EAT_DESTROYLOCALOFFSET: + CInline_ObjectAddrRef(actions->data.destroy_local_offset.dtor); + break; + case EAT_DESTROYLOCALPOINTER: + CInline_ObjectAddrRef(actions->data.destroy_local_pointer.dtor); + break; + case EAT_DESTROYLOCALARRAY: + CInline_ObjectAddrRef(actions->data.destroy_local_array.dtor); + break; + case EAT_DESTROYPARTIALARRAY: + CInline_ObjectAddrRef(actions->data.destroy_partial_array.dtor); + break; + case EAT_DESTROYMEMBER: + case EAT_DESTROYBASE: + CInline_ObjectAddrRef(actions->data.destroy_member.dtor); + break; + case EAT_DESTROYMEMBERCOND: + CInline_ObjectAddrRef(actions->data.destroy_member_cond.dtor); + break; + case EAT_DESTROYMEMBERARRAY: + CInline_ObjectAddrRef(actions->data.destroy_member_array.dtor); + break; + case EAT_DELETEPOINTER: + case EAT_DELETELOCALPOINTER: + CInline_ObjectAddrRef(actions->data.delete_pointer.deletefunc); + break; + case EAT_DELETEPOINTERCOND: + CInline_ObjectAddrRef(actions->data.delete_pointer_cond.deletefunc); + break; + case EAT_CATCHBLOCK: + case EAT_ACTIVECATCHBLOCK: + case EAT_SPECIFICATION: + case EAT_TERMINATE: + break; + default: + CError_FATAL(192); + } + actions = actions->prev; + } +} + +void CExcept_CompareSpecifications(ExceptSpecList *a, ExceptSpecList *b) { + ExceptSpecList *aa; + ExceptSpecList *bb; + + aa = a; + bb = b; + while (1) { + if (!aa) { + if (!bb) + break; + CError_Error(CErrorStr265); + return; + } + + if (!bb) { + CError_Error(CErrorStr265); + return; + } + + aa = aa->next; + bb = bb->next; + } + + if (a->type == NULL) { + if (b->type != NULL) + CError_Error(CErrorStr265); + } else if (b->type == NULL) { + CError_Error(CErrorStr265); + } else { + for (aa = a; aa; aa = aa->next) { + for (bb = b; bb; bb = bb->next) { + if (is_typesame(aa->type, bb->type) && aa->qual == bb->qual) + break; + } + + if (bb == NULL) { + CError_Error(CErrorStr265); + return; + } + } + } +} + +Boolean CExcept_ActionCompare(ExceptionAction *a, ExceptionAction *b) { + if (a->type == b->type) { + switch (a->type) { + case EAT_DESTROYLOCAL: + return a->data.destroy_local.local == b->data.destroy_local.local; + case EAT_DESTROYLOCALCOND: + return a->data.destroy_local_cond.local == b->data.destroy_local_cond.local; + case EAT_DESTROYLOCALOFFSET: + return a->data.destroy_local_offset.local == b->data.destroy_local_offset.local && + a->data.destroy_local_offset.offset == b->data.destroy_local_offset.offset; + case EAT_DESTROYLOCALPOINTER: + return a->data.destroy_local_pointer.pointer == b->data.destroy_local_pointer.pointer; + case EAT_DESTROYLOCALARRAY: + return a->data.destroy_local_array.localarray == b->data.destroy_local_array.localarray; + case EAT_DESTROYPARTIALARRAY: + return a->data.destroy_partial_array.arraypointer == b->data.destroy_partial_array.arraypointer; + case EAT_DESTROYMEMBER: + case EAT_DESTROYBASE: + return a->data.destroy_member.objectptr == b->data.destroy_member.objectptr && + a->data.destroy_member.offset == b->data.destroy_member.offset; + case EAT_DESTROYMEMBERCOND: + return a->data.destroy_member_cond.objectptr == b->data.destroy_member_cond.objectptr && + a->data.destroy_member_cond.offset == b->data.destroy_member_cond.offset; + case EAT_DESTROYMEMBERARRAY: + return a->data.destroy_member_array.objectptr == b->data.destroy_member_array.objectptr && + a->data.destroy_member_array.offset == b->data.destroy_member_array.offset; + case EAT_DELETEPOINTER: + case EAT_DELETELOCALPOINTER: + return a->data.delete_pointer.pointerobject == b->data.delete_pointer.pointerobject && + a->data.delete_pointer.deletefunc == b->data.delete_pointer.deletefunc; + case EAT_DELETEPOINTERCOND: + return a->data.delete_pointer_cond.cond == b->data.delete_pointer_cond.cond; + case EAT_CATCHBLOCK: + return a->data.catch_block.catch_label == b->data.catch_block.catch_label; + case EAT_ACTIVECATCHBLOCK: + return a->data.active_catch_block.catch_info_object == b->data.active_catch_block.catch_info_object; + case EAT_TERMINATE: + return 1; + case EAT_SPECIFICATION: + return a->data.specification.unexp_id == b->data.specification.unexp_id; + default: + CError_FATAL(314); + } + } + + return 0; +} + +int CExcept_IsSubList(ExceptionAction *a, ExceptionAction *b) { + int diff; + int i; + int count1; + int count2; + ExceptionAction *scan; + + if (a == b) + return 0; + + count1 = 0; + scan = a; + while (scan) { + scan = scan->prev; + count1++; + } + + scan = b; + count2 = 0; + while (scan) { + scan = scan->prev; + count2++; + } + + diff = count2 - count1; + if (diff < 0) + return -1; + + for (i = 0; i < diff; i++) + b = b->prev; + + while (a != b) { + if (!a || !b || !CExcept_ActionCompare(a, b)) + return -1; + a = a->prev; + b = b->prev; + } + + return diff; +} + +Boolean CExcept_ActionNeedsDestruction(ExceptionAction *action) { + switch (action->type) { + case EAT_CATCHBLOCK: + return 0; + case EAT_DESTROYLOCAL: + case EAT_DESTROYLOCALOFFSET: + case EAT_DESTROYLOCALARRAY: + case EAT_DELETELOCALPOINTER: + case EAT_ACTIVECATCHBLOCK: + return 1; + case EAT_NOP: + case EAT_DESTROYMEMBER: + case EAT_DESTROYMEMBERCOND: + case EAT_DESTROYMEMBERARRAY: + case EAT_DESTROYBASE: + break; + default: + CError_FATAL(363); + } + + return 0; +} + +ENode *CExcept_RegisterDestructorObject(Object *local, SInt32 offset, Object *dtor, Boolean flag) { + ExceptionAction *action; + ENode *expr; + Object *dtorObject; + + action = lalloc(sizeof(ExceptionAction)); + memclrw(action, sizeof(ExceptionAction)); + + action->prev = cexcept_dobjstack; + cexcept_dobjstack = action; + + expr = create_objectrefnode(local); + dtorObject = CABI_GetDestructorObject(dtor, CABIDestroy1); + + if (offset == 0) { + action->type = EAT_DESTROYLOCAL; + action->data.destroy_local.local = local; + action->data.destroy_local.dtor = dtorObject; + } else { + action->type = EAT_DESTROYLOCALOFFSET; + action->data.destroy_local_offset.local = local; + action->data.destroy_local_offset.dtor = dtorObject; + action->data.destroy_local_offset.offset = offset; + expr = makediadicnode(expr, intconstnode(TYPE(&stunsignedlong), offset), EADD); + } + + cexcept_hasdobjects = 1; + return expr; +} + +void CExcept_RegisterLocalArray(Statement *stmt, Object *localarray, Object *dtor, SInt32 elements, SInt32 element_size) { + ExceptionAction *action; + Object *dtorObject; + + action = lalloc(sizeof(ExceptionAction)); + memclrw(action, sizeof(ExceptionAction)); + + action->prev = cexcept_dobjstack; + cexcept_dobjstack = action; + + dtorObject = CABI_GetDestructorObject(dtor, CABIDestroy1); + + action->type = EAT_DESTROYLOCALARRAY; + action->data.destroy_local_array.localarray = localarray; + action->data.destroy_local_array.dtor = dtorObject; + action->data.destroy_local_array.elements = elements; + action->data.destroy_local_array.element_size = element_size; + + cexcept_hasdobjects = 1; +} + +void CExcept_RegisterDeleteObject(Statement *stmt, Object *pointerobject, Object *deletefunc) { + ExceptionAction *action; + + action = lalloc(sizeof(ExceptionAction)); + memclrw(action, sizeof(ExceptionAction)); + + action->prev = cexcept_dobjstack; + cexcept_dobjstack = action; + + action->type = EAT_DELETELOCALPOINTER; + action->data.delete_pointer.pointerobject = pointerobject; + action->data.delete_pointer.deletefunc = deletefunc; + + cexcept_hasdobjects = 1; +} + +static void CExcept_PatchConstructorAction(Statement *stmt, ExceptionAction *actionArg) { + ExceptionAction *action30; + ExceptionAction *action; + ExceptionAction *scan; + + for (action = stmt->dobjstack; action; action = action->prev) { + switch (action->type) { + case EAT_DESTROYMEMBER: + case EAT_DESTROYMEMBERCOND: + case EAT_DESTROYMEMBERARRAY: + case EAT_SPECIFICATION: + case EAT_DESTROYBASE: + goto exitFirstLoop; + case EAT_CATCHBLOCK: + action30 = action; + while (1) { + if (!action30->prev) + goto exitFirstLoop; + action30 = action30->prev; + if (action30->type != EAT_CATCHBLOCK) { + CError_FATAL(481); + } + } + } + } + exitFirstLoop: + if (action == NULL) { + while (stmt) { + if ((scan = stmt->dobjstack)) { + while (1) { + if (scan == actionArg) + break; + if (scan->prev == NULL) { + scan->prev = actionArg; + break; + } + scan = scan->prev; + } + } else { + stmt->dobjstack = actionArg; + } + stmt = stmt->next; + } + } else { + actionArg->prev = action; + while (stmt) { + if (stmt->dobjstack != action) { + scan = stmt->dobjstack; + do { + if (scan == actionArg) + goto nextStmt; + if (scan->prev == action) { + scan->prev = actionArg; + goto nextStmt; + } + } while ((scan = scan->prev)); + + while (1) { + if (action->type == EAT_CATCHBLOCK && action->prev == NULL) + return; + + action = action->prev; + if (!action) + CError_FATAL(531); + } + } else { + stmt->dobjstack = actionArg; + } + nextStmt: + stmt = stmt->next; + } + } +} + +void CExcept_Terminate(void) { + ExceptionAction *action; + + action = lalloc(sizeof(ExceptionAction)); + memclrw(action, sizeof(ExceptionAction)); + + action->type = EAT_TERMINATE; + + action->prev = cexcept_dobjstack; + cexcept_dobjstack = action; +} + +void CExcept_Magic(void) { + cexcept_magic = 1; +} + +static Object *CExcept_FindLocalObject(char *name) { + NameResult result; + NameSpaceObjectList *list; + + list = CScope_FindObjectList(&result, GetHashNameNodeExport(name)); + if (list && list->object->otype == OT_OBJECT && OBJECT(list->object)->datatype == DLOCAL) + return OBJECT(list->object); + + CError_FATAL(580); + return NULL; +} + +void CExcept_ArrayInit(void) { + ExceptionAction *action; + + action = lalloc(sizeof(ExceptionAction)); + memclrw(action, sizeof(ExceptionAction)); + + action->type = EAT_DESTROYPARTIALARRAY; + action->data.destroy_partial_array.arraypointer = CExcept_FindLocalObject("ptr"); + action->data.destroy_partial_array.arraycounter = CExcept_FindLocalObject("i"); + action->data.destroy_partial_array.dtor = CExcept_FindLocalObject("dtor"); + action->data.destroy_partial_array.element_size = CExcept_FindLocalObject("size"); + + action->prev = cexcept_dobjstack; + cexcept_dobjstack = action; +} + +void CExcept_RegisterMember(Statement *stmt, Object *objectptr, SInt32 offset, Object *dtor, Object *cond, Boolean isMember) { + ExceptionAction *action; + + action = lalloc(sizeof(ExceptionAction)); + memclrw(action, sizeof(ExceptionAction)); + + if (cond == NULL) { + if (isMember) { + action->type = EAT_DESTROYMEMBER; + action->data.destroy_member.dtor = CABI_GetDestructorObject(dtor, CABIDestroy1); + } else { + action->type = EAT_DESTROYBASE; + action->data.destroy_member.dtor = CABI_GetDestructorObject(dtor, CABIDestroy0); + } + action->data.destroy_member.objectptr = objectptr; + action->data.destroy_member.offset = offset; + } else { + CError_ASSERT(632, cond->type == TYPE(&stsignedshort)); + action->type = EAT_DESTROYMEMBERCOND; + action->data.destroy_member_cond.objectptr = objectptr; + action->data.destroy_member_cond.cond = cond; + action->data.destroy_member_cond.dtor = CABI_GetDestructorObject(dtor, CABIDestroy1); + action->data.destroy_member_cond.offset = offset; + } + + CExcept_PatchConstructorAction(stmt, action); + stmt->flags |= StmtFlag_2; +} + +void CExcept_RegisterMemberArray(Statement *stmt, Object *objectptr, SInt32 offset, Object *dtor, SInt32 elements, SInt32 element_size) { + ExceptionAction *action; + + action = lalloc(sizeof(ExceptionAction)); + memclrw(action, sizeof(ExceptionAction)); + + action->type = EAT_DESTROYMEMBERARRAY; + action->data.destroy_member_array.objectptr = objectptr; + action->data.destroy_member_array.dtor = CABI_GetDestructorObject(dtor, CABIDestroy1); + action->data.destroy_member_array.offset = offset; + action->data.destroy_member_array.elements = elements; + action->data.destroy_member_array.element_size = element_size; + + CExcept_PatchConstructorAction(stmt, action); + stmt->flags |= StmtFlag_2; +} + +static Statement *CExcept_DestroyLocal(ExceptionAction *ea, Statement *stmt, Object *object, Object *dtor, SInt32 offset) { + ENode *expr; + + expr = create_objectrefnode(object); + if (offset) + expr = makediadicnode(expr, intconstnode(TYPE(&stunsignedlong), offset), EADD); + + expr = CABI_DestroyObject(dtor, expr, CABIDestroy1, 1, 0); + + CError_ASSERT(687, expr->type == EFUNCCALL && expr->data.funccall.funcref->type == EOBJREF); + if (expr->data.funccall.funcref->data.objref->datatype == DVFUNC) + expr->data.funccall.funcref->flags |= ENODE_FLAG_80; + + stmt = CFunc_InsertStatement(ST_EXPRESSION, stmt); + stmt->expr = expr; + stmt->dobjstack = ea->prev; + return stmt; +} + +static Statement *CExcept_DestroyLocalPointer(ExceptionAction *ea, Statement *stmt, Object *object, Object *deletefunc) { + Statement *newStmt; + + newStmt = CFunc_InsertStatement(ST_EXPRESSION, stmt); + newStmt->expr = funccallexpr(deletefunc, create_objectnode2(object), NULL, NULL, NULL); + newStmt->dobjstack = ea->prev; + return newStmt; +} + +static Statement *CExcept_DestroyLocalArray(ExceptionAction *ea, Statement *stmt, Object *object, Object *dtor, SInt32 elements, SInt32 element_size) { + Statement *newStmt; + ENode *dtorExpr; + + newStmt = CFunc_InsertStatement(ST_EXPRESSION, stmt); + + if (dtor) + dtorExpr = create_objectrefnode(CABI_GetDestructorObject(dtor, CABIDestroy1)); + else + dtorExpr = nullnode(); + + newStmt->expr = funccallexpr( + darr_func, + create_objectrefnode(object), + dtorExpr, + intconstnode(TYPE(&stunsignedlong), element_size), + intconstnode(TYPE(&stunsignedlong), elements) + ); + + newStmt->dobjstack = ea->prev; + return newStmt; +} + +static Statement *CExcept_EndCatch(ExceptionAction *ea, Statement *stmt) { + stmt = CFunc_InsertStatement(ST_ENDCATCHDTOR, stmt); + stmt->expr = create_objectrefnode(ea->data.active_catch_block.catch_info_object); + stmt->dobjstack = ea->prev; + if (!ea->data.active_catch_block.call_dtor) + stmt->type = ST_ENDCATCH; + return stmt; +} + +Statement *CExcept_ActionCleanup(ExceptionAction *ea, Statement *stmt) { + switch (ea->type) { + case EAT_DESTROYLOCALCOND: + case EAT_DESTROYLOCALPOINTER: + case EAT_DESTROYPARTIALARRAY: + case EAT_DESTROYMEMBER: + case EAT_DESTROYMEMBERCOND: + case EAT_DESTROYMEMBERARRAY: + case EAT_DELETEPOINTER: + case EAT_DELETEPOINTERCOND: + case EAT_CATCHBLOCK: + case EAT_SPECIFICATION: + case EAT_TERMINATE: + case EAT_DESTROYBASE: + break; + case EAT_DESTROYLOCAL: + stmt = CExcept_DestroyLocal( + ea, stmt, + ea->data.destroy_local.local, + ea->data.destroy_local.dtor, + 0); + break; + case EAT_DESTROYLOCALOFFSET: + stmt = CExcept_DestroyLocal( + ea, stmt, + ea->data.destroy_local.local, + ea->data.destroy_local.dtor, + ea->data.destroy_local_offset.offset); + break; + case EAT_DELETELOCALPOINTER: + stmt = CExcept_DestroyLocalPointer( + ea, stmt, + ea->data.delete_pointer.pointerobject, + ea->data.delete_pointer.deletefunc); + break; + case EAT_DESTROYLOCALARRAY: + stmt = CExcept_DestroyLocalArray( + ea, stmt, + ea->data.destroy_local_array.localarray, + ea->data.destroy_local_array.dtor, + ea->data.destroy_local_array.elements, + ea->data.destroy_local_array.element_size); + break; + case EAT_ACTIVECATCHBLOCK: + stmt = CExcept_EndCatch(ea, stmt); + break; + default: + CError_FATAL(827); + } + + return stmt; +} + +static void CExcept_MangleNameSpaceName(NameSpace *nspace) { + while (nspace) { + if (nspace->name) { + CExcept_MangleNameSpaceName(nspace->parent); + AppendGListName(&name_mangle_list, nspace->name->name); + AppendGListName(&name_mangle_list, "::"); + break; + } + nspace = nspace->parent; + } +} + +static void CExcept_MangleClassName(TypeClass *tclass) { + NameSpace *nspace; + char buf[64]; + + CExcept_MangleNameSpaceName(tclass->nspace->parent); + AppendGListName(&name_mangle_list, tclass->classname->name); + + for (nspace = tclass->nspace->parent; nspace; nspace = nspace->parent) { + if (!nspace->is_global && !nspace->is_templ && !nspace->name) { + CError_ASSERT(868, cscope_currentfunc != NULL); + + sprintf(buf, "*%" PRIxPTR "*%" PRIxPTR "*", &cscope_currentfunc, &nspace); + AppendGListName(&name_mangle_list, buf); + break; + } + } +} + +typedef struct BCL { + struct BCL *next; + TypeClass *tclass; + SInt32 offset; + Boolean is_virtual; + Boolean is_public; + Boolean is_ambig; +} BCL; + +static void CExcept_MakeBaseClassListAmbig(BCL *bcl, TypeClass *tclass) { + BCL *scan; + ClassList *list; + + for (scan = bcl; scan; scan = scan->next) { + if (scan->tclass == tclass) + scan->is_ambig = 1; + } + + for (list = tclass->bases; list; list = list->next) + CExcept_MakeBaseClassListAmbig(bcl, list->base); +} + +static BCL *CExcept_GetBaseClassList(BCL *bcl, TypeClass *tclass1, TypeClass *tclass2, SInt32 offset, Boolean is_virtual, Boolean is_public) { + BCL *node; + ClassList *base; + Boolean new_is_public; + + for (node = bcl; node; node = node->next) { + if (node->tclass == tclass2) { + if (is_virtual && node->is_virtual) { + if (is_public) + node->is_public = 1; + } else { + CExcept_MakeBaseClassListAmbig(bcl, tclass2); + } + return bcl; + } + } + + node = lalloc(sizeof(BCL)); + node->tclass = tclass2; + node->offset = offset; + node->is_virtual = is_virtual; + node->is_public = is_public; + node->is_ambig = 0; + node->next = bcl; + bcl = node; + + for (base = tclass2->bases; base; base = base->next) { + new_is_public = is_public && (base->access == ACCESSPUBLIC); + bcl = base->is_virtual + ? CExcept_GetBaseClassList(bcl, tclass1, base->base, CClass_VirtualBaseOffset(tclass1, base->base), 1, new_is_public) + : CExcept_GetBaseClassList(bcl, tclass1, base->base, offset + base->offset, 0, new_is_public); + } + + return bcl; +} + +static void CExcept_MangleClass(TypeClass *tclass) { + BCL *bcl; + char buf[20]; + + for (bcl = CExcept_GetBaseClassList(NULL, tclass, tclass, 0, 0, 1); bcl; bcl = bcl->next) { + if (bcl->is_public && !bcl->is_ambig) { + CExcept_MangleClassName(bcl->tclass); + AppendGListByte(&name_mangle_list, '!'); + + if (bcl->offset) { + sprintf(buf, "%" PRId32 "!", bcl->offset); + AppendGListName(&name_mangle_list, buf); + } else { + AppendGListByte(&name_mangle_list, '!'); + } + } + } +} + +static ENode *CExcept_GetTypeID(Type *type, UInt32 qual, Boolean flag) { + ENode *expr; + TypePointer my_tptr; + + if (IS_TYPE_REFERENCE(type)) + type = TPTR_TARGET(type); + + if (IS_TYPE_CLASS(type) || (IS_TYPE_POINTER_ONLY(type) && IS_TYPE_CLASS(TPTR_TARGET(type)))) { + name_mangle_list.size = 0; + if (IS_TYPE_POINTER_ONLY(type)) { + AppendGListByte(&name_mangle_list, '*'); + type = TPTR_TARGET(type); + } else { + AppendGListByte(&name_mangle_list, '!'); + } + + if (flag) { + CExcept_MangleClass(TYPE_CLASS(type)); + } else { + CExcept_MangleClassName(TYPE_CLASS(type)); + AppendGListByte(&name_mangle_list, '!'); + } + } else { + if (IS_TYPE_POINTER_ONLY(type)) { + if (TPTR_QUAL(type) & (Q_CONST | Q_VOLATILE)) { + my_tptr = *TYPE_POINTER(type); + my_tptr.qual = 0; + type = TYPE(&my_tptr); + } + } else { + qual = 0; + } + CMangler_MangleType(type, qual); + } + + AppendGListByte(&name_mangle_list, 0); + + expr = CExpr_NewENode(ESTRINGCONST); + expr->rtype = CDecl_NewPointerType(TYPE(&stchar)); + expr->data.string.size = name_mangle_list.size; + expr->data.string.data = galloc(name_mangle_list.size); + memcpy(expr->data.string.data, *name_mangle_list.data, name_mangle_list.size); + return expr; +} + +static Object *CExcept_TypeID(Type *type, UInt32 qual) { + ENode *expr = CExcept_GetTypeID(type, qual, 0); + CError_ASSERT(1086, expr->type == ESTRINGCONST); + return CInit_DeclareString(expr->data.string.data, expr->data.string.size, 0, 0); +} + +void CExcept_ScanExceptionSpecification(TypeFunc *tfunc) { + ExceptSpecList *exspecs; + ExceptSpecList *exspec; + DeclInfo di; + + exspecs = NULL; + + if (lex() != '(') { + CError_Error(CErrorStr114); + return; + } + + if ((tk = lex()) != ')') { + while (1) { + memclrw(&di, sizeof(di)); + CParser_GetDeclSpecs(&di, 0); + if (di.storageclass) + CError_Error(CErrorStr177); + + CError_QualifierCheck(di.qual & ~(Q_CONST | Q_VOLATILE | Q_PASCAL | Q_ALIGNED_MASK)); + + scandeclarator(&di); + if (di.name) + CError_Error(CErrorStr146); + + if (IS_TYPE_POINTER_ONLY(di.thetype)) { + if (TPTR_QUAL(di.thetype) & (Q_CONST | Q_VOLATILE)) { + TypePointer *newtype = galloc(sizeof(TypePointer)); + *newtype = *TYPE_POINTER(di.thetype); + newtype->qual = 0; + di.thetype = TYPE(newtype); + } + } else { + di.qual = 0; + } + + for (exspec = exspecs; exspec; exspec = exspec->next) { + if (is_typesame(exspec->type, di.thetype) && exspec->qual == di.qual) + break; + } + + if (!exspec) { + exspec = galloc(sizeof(ExceptSpecList)); + memclrw(exspec, sizeof(ExceptSpecList)); + exspec->next = exspecs; + exspec->type = di.thetype; + exspec->qual = di.qual; + exspecs = exspec; + } + + if (tk == ')') + break; + + if (tk != ',') { + CError_Error(CErrorStr115); + break; + } + + tk = lex(); + } + } + + if (!exspecs) { + exspecs = galloc(sizeof(ExceptSpecList)); + memclrw(exspecs, sizeof(ExceptSpecList)); + } + tfunc->exspecs = exspecs; + tk = lex(); +} + +static ENode *CExcept_CallCopyCtor(Object *object, Type *type, ENode *expr1, ENode *expr2) { + ENodeList *list; + ENode *expr; + FuncArg *arg; + + if ( + !IS_TYPE_FUNC(object->type) || + !(arg = TYPE_FUNC(object->type)->args) || + !(arg = arg->next) + ) + CError_FATAL(1169); + + expr = funccallexpr(object, expr1, NULL, NULL, NULL); + list = expr->data.funccall.args; + + if (TYPE_CLASS(type)->flags & CLASS_HAS_VBASES) { + CError_ASSERT(1179, arg = arg->next); + list->next = lalloc(sizeof(ENodeList)); + list = list->next; + list->next = NULL; + list->node = intconstnode(TYPE(&stsignedshort), 1); + } + + list->next = lalloc(sizeof(ENodeList)); + list = list->next; + list->next = NULL; + list->node = expr2; + + while ((arg = arg->next)) { + CError_ASSERT(1195, arg->dexpr); + + list->next = lalloc(sizeof(ENodeList)); + list = list->next; + list->next = NULL; + list->node = CExpr_GetDefaultArgument(expr->data.funccall.funcref, arg); + } + + return expr; +} + +ENode *CExcept_ScanThrowExpression(void) { + ENode *expr; + Object *func; + ENode *resultExpr; + Object *obj; + ENode *thrownExpr; + ENode *tempExpr; + + if (!copts.exceptions) + CError_Error(CErrorStr252); + + switch ((tk = lex())) { + case ')': + case ',': + case ':': + case ';': + expr = funccallexpr(Xthrw_func, nullnode(), nullnode(), nullnode(), NULL); + break; + default: + thrownExpr = pointer_generation(assignment_expression()); + obj = create_temp_object(thrownExpr->rtype); + if (!IS_TYPE_CLASS(thrownExpr->rtype) || !(resultExpr = CExpr_IsTempConstruction(thrownExpr, thrownExpr->rtype, &expr))) { + tempExpr = create_objectrefnode(obj); + if (IS_TYPE_CLASS(thrownExpr->rtype) && (func = CClass_CopyConstructor(TYPE_CLASS(thrownExpr->rtype)))) { + resultExpr = CExcept_CallCopyCtor(func, thrownExpr->rtype, tempExpr, getnodeaddress(thrownExpr, 0)); + } else { + if (thrownExpr->rtype->size == 0) + CError_Error(CErrorStr146); + + tempExpr = makemonadicnode(tempExpr, EINDIRECT); + tempExpr->rtype = thrownExpr->rtype; + resultExpr = makediadicnode(tempExpr, thrownExpr, EASS); + resultExpr = makediadicnode(resultExpr, create_objectrefnode(obj), ECOMMA); + resultExpr->rtype = TYPE(&void_ptr); + } + } else { + *expr = *create_objectrefnode(obj); + } + + expr = CExcept_GetTypeID(thrownExpr->rtype, ENODE_QUALS(thrownExpr), 1); + if (IS_TYPE_CLASS(thrownExpr->rtype) && (func = CClass_Destructor(TYPE_CLASS(thrownExpr->rtype)))) { + expr = funccallexpr( + Xthrw_func, + expr, + resultExpr, + create_objectrefnode(CABI_GetDestructorObject(func, CABIDestroy1)), + NULL); + } else { + expr = funccallexpr( + Xthrw_func, + expr, + resultExpr, + nullnode(), + NULL); + } + } + + expr->flags |= ENODE_FLAG_VOLATILE; + return expr; +} + +static Boolean CExcept_MightNeedDtor(Type *type) { + if (type) { + if (IS_TYPE_CLASS(type)) { + if (!CClass_Destructor(TYPE_CLASS(type))) + return 0; + } else if (IS_TYPE_POINTER_ONLY(type)) { + if (!(TPTR_QUAL(type) & Q_REFERENCE) || !IS_TYPE_CLASS(TPTR_TARGET(type))) + return 0; + } else { + return 0; + } + } + + return 1; +} + +typedef struct CatchBlock { + struct CatchBlock *next; + Object *catch_object; + Object *catch_info_object; + Statement *stmt; + Statement *anotherStmt; + Type *type; + UInt32 qual; +} CatchBlock; + +static void CExcept_PatchDObjStack(Statement *beginCatchStmt, Statement *tryEndStmt, Statement *endStmt, CatchBlock *catchBlock) { + ExceptionAction *ea; + ExceptionAction *stackHead; + ExceptionAction *stackTail; + ExceptionAction *firstEA; + Statement *stmt; + Object *catch_info_object; + Boolean call_dtor; + + catch_info_object = catchBlock->catch_info_object; + call_dtor = 0; + stackHead = stackTail = beginCatchStmt->dobjstack; + firstEA = NULL; + + while (catchBlock) { + ea = lalloc(sizeof(ExceptionAction)); + memclrw(ea, sizeof(ExceptionAction)); + + ea->prev = stackTail; + stackTail = ea; + + if (!firstEA) + firstEA = ea; + + ea->type = EAT_CATCHBLOCK; + ea->data.catch_block.catch_object = catchBlock->catch_object; + ea->data.catch_block.catch_label = catchBlock->stmt->label; + if (catchBlock->type) + ea->data.catch_block.catch_typeid = CExcept_TypeID(catchBlock->type, catchBlock->qual); + ea->data.catch_block.catch_info_object = catch_info_object; + + if (!call_dtor && CExcept_MightNeedDtor(catchBlock->type)) + call_dtor = 1; + + ea->data.catch_block.catch_type = catchBlock->type; + ea->data.catch_block.catch_qual = catchBlock->qual; + catchBlock = catchBlock->next; + } + + stmt = beginCatchStmt; + while (1) { + if ((ea = stmt->dobjstack) != stackHead) { + while (1) { + CError_ASSERT(1404, ea); + if (ea->prev == stackTail) + break; + if (ea->prev == stackHead) { + ea->prev = stackTail; + break; + } + ea = ea->prev; + } + } else { + stmt->dobjstack = stackTail; + } + + if (stmt == endStmt) + break; + + if (stmt == tryEndStmt) { + ea = lalloc(sizeof(ExceptionAction)); + memclrw(ea, sizeof(ExceptionAction)); + ea->prev = stackHead; + ea->type = EAT_ACTIVECATCHBLOCK; + ea->data.active_catch_block.catch_info_object = catch_info_object; + ea->data.active_catch_block.call_dtor = call_dtor; + stackTail = ea; + } + + stmt = stmt->next; + CError_ASSERT(1426, stmt); + } + + cexcept_hasdobjects = 1; +} + +static void CExcept_CheckTryObjects(ENode *expr) { + if (expr->data.objref->datatype == DLOCAL && expr->data.objref->u.var.info) + expr->data.objref->u.var.info->noregister = 1; +} + +static ENode *CExcept_CatchExpressionInit(DeclInfo *di, CatchBlock *catchBlock) { + Object *catch_object; + Object *copyCtor; + Object *dtor; + ENode *expr; + + if (CScope_FindName(cscope_current, di->name)) + CError_Error(CErrorStr122, di->name->name); + + catch_object = CParser_NewLocalDataObject(di, 1); + CFunc_SetupLocalVarInfo(catch_object); + CScope_AddObject(cscope_current, di->name, OBJ_BASE(catch_object)); + catchBlock->catch_object = catch_object; + + expr = makediadicnode( + create_objectrefnode(catchBlock->catch_info_object), + intconstnode(TYPE(&stunsignedlong), 12), + EADD); + expr->rtype = CDecl_NewPointerType(CDecl_NewPointerType(di->thetype)); + + expr = makemonadicnode(expr, EINDIRECT); + expr->rtype = CDecl_NewPointerType(di->thetype); + + if (IS_TYPE_REFERENCE(di->thetype)) + return makediadicnode(create_objectnode2(catch_object), expr, EASS); + + if (IS_TYPE_CLASS(di->thetype) && (copyCtor = CClass_CopyConstructor(TYPE_CLASS(di->thetype)))) { + dtor = CClass_Destructor(TYPE_CLASS(di->thetype)); + return CExcept_CallCopyCtor( + copyCtor, + di->thetype, + (dtor == NULL) ? create_objectrefnode(catch_object) : CExcept_RegisterDestructorObject(catch_object, 0, dtor, 0), + expr); + } + + expr = makemonadicnode(expr, EINDIRECT); + expr->rtype = di->thetype; + return makediadicnode(create_objectnode(catch_object), expr, EASS); +} + +void CExcept_ScanTryBlock(DeclThing *dt, Boolean flag) { + Object *catch_info_object; // r27 + Statement *beginCatchStmt; // r14 + Statement *tryEndStmt; // r16 + Statement *endStmt; // r17 + Statement *stmt; // r14 + CLabel *catchEndLabel; // r19 + CLabel *endLabel; // r24 + CatchBlock *catchStack; // r23 + CatchBlock *catchBlock; // r22 + DeclBlock *declBlock; // r20 + DeclInfo di; + + if (!copts.exceptions) + CError_Error(CErrorStr252); + + catch_info_object = create_temp_object(TYPE(&catchinfostruct)); + if (cexcept_magic) { + catch_info_object->name = GetHashNameNodeExport("__exception_magic"); + CScope_AddObject(cscope_current, catch_info_object->name, OBJ_BASE(catch_info_object)); + } + + stmt = CFunc_AppendStatement(ST_LABEL); + stmt->flags = StmtFlag_1; + stmt->label = newlabel(); + stmt->label->stmt = stmt; + + beginCatchStmt = CFunc_AppendStatement(ST_BEGINCATCH); + beginCatchStmt->expr = create_objectrefnode(catch_info_object); + + if (tk != '{') { + CError_Error(CErrorStr135); + return; + } + + CFunc_CompoundStatement(dt); + + if (tk != TK_CATCH) { + CError_Error(CErrorStr242); + return; + } + + stmt = CFunc_AppendStatement(ST_GOTO); + catchEndLabel = stmt->label = newlabel(); + tryEndStmt = stmt; + + endLabel = newlabel(); + catchStack = NULL; + + while (1) { + CPrep_GetFileOffsetInfo2(&cparser_fileoffset, &sourceoffset, &sourcefilepath); + + stmt = CFunc_AppendStatement(ST_LABEL); + stmt->flags = StmtFlag_1; + stmt->label = newlabel(); + stmt->label->stmt = stmt; + + declBlock = NULL; + + catchBlock = lalloc(sizeof(ExceptionAction)); + memclrw(catchBlock, sizeof(ExceptionAction)); + catchBlock->next = catchStack; + catchStack = catchBlock; + + catchBlock->stmt = stmt; + catchBlock->catch_info_object = catch_info_object; + + if ((tk = lex()) != '(') { + CError_Error(CErrorStr114); + break; + } + + if ((tk = lex()) == TK_ELLIPSIS) { + tk = lex(); + } else { + memclrw(&di, sizeof(di)); + CParser_GetDeclSpecs(&di, 0); + + if (di.x48) + CError_Error(CErrorStr121); + if (di.storageclass) + CError_Error(CErrorStr177); + + CError_QualifierCheck(di.qual & ~(Q_CONST | Q_VOLATILE | Q_PASCAL | Q_ALIGNED_MASK)); + + scandeclarator(&di); + + if (IS_TYPE_FUNC(di.thetype)) + di.thetype = CDecl_NewPointerType(di.thetype); + else if (IS_TYPE_ARRAY(di.thetype)) + di.thetype = CDecl_NewPointerType(TPTR_TARGET(di.thetype)); + + IsCompleteType(di.thetype); + if (IS_TYPE_CLASS(di.thetype) && (TYPE_CLASS(di.thetype)->flags & CLASS_ABSTRACT)) + CError_AbstractClassError(TYPE_CLASS(di.thetype)); + + catchBlock->type = di.thetype; + catchBlock->qual = di.qual; + + if (di.name) { + ENode *expr; + declBlock = CFunc_NewDeclBlock(); + expr = CExcept_CatchExpressionInit(&di, catchBlock); + stmt = CFunc_AppendStatement(ST_EXPRESSION); + stmt->expr = expr; + } + } + + if (tk != ')') { + CError_Error(CErrorStr115); + break; + } + + if ((tk = lex()) != '{') { + CError_Error(CErrorStr123); + break; + } + + CFunc_CompoundStatement(dt); + if (flag) { + stmt = CFunc_AppendStatement(ST_EXPRESSION); + stmt->expr = funccallexpr(Xthrw_func, nullnode(), nullnode(), nullnode(), NULL); + } + + catchBlock->anotherStmt = stmt; + + if (declBlock) + CFunc_RestoreBlock(declBlock); + + if (tk != TK_CATCH) + break; + + CFunc_AppendStatement(ST_GOTO)->label = endLabel; + } + + endStmt = CFunc_AppendStatement(ST_LABEL); + endStmt->label = endLabel; + endLabel->stmt = endStmt; + + CExcept_PatchDObjStack(beginCatchStmt, tryEndStmt, endStmt, catchBlock); + + stmt = CFunc_AppendStatement(ST_LABEL); + stmt->label = catchEndLabel; + catchEndLabel->stmt = stmt; +} + +static Statement *CExcept_InsertPrevStatement(StatementType sttype) { + Statement *stmt = CFunc_InsertStatement(sttype, cexcept_prevstmt); + stmt->sourceoffset = stmt->next->sourceoffset; + stmt->sourcefilepath = stmt->next->sourcefilepath; + stmt->dobjstack = cexcept_eabefore; + return stmt; +} + +static Object *CExcept_GetETEMPObject(ENode *expr) { + UniqueObj *uobj; + SInt32 id; + + if ((id = expr->data.temp.uniqueid)) { + for (uobj = cexcept_uniqueobjs; uobj; uobj = uobj->next) { + if (uobj->uniqueid == id) + return uobj->object; + } + + uobj = galloc(sizeof(UniqueObj)); + uobj->next = cexcept_uniqueobjs; + cexcept_uniqueobjs = uobj; + uobj->uniqueid = id; + return (uobj->object = create_temp_object(expr->data.temp.type)); + } else { + return create_temp_object(expr->data.temp.type); + } +} + +static ENode *CExcept_TempTrans_ETEMP(ENode *expr) { + Object *object; + ExceptionAction *ea; + DtorTemp *dtorTemp; + Object *dtor; + + object = CExcept_GetETEMPObject(expr); + if (expr->data.temp.needs_dtor) { + dtorTemp = lalloc(sizeof(DtorTemp)); + dtorTemp->next = cexcept_dtortemps; + cexcept_dtortemps = dtorTemp; + dtorTemp->object = object; + dtorTemp->temp = NULL; + + if ( + !IS_TYPE_CLASS(expr->data.temp.type) || + !(dtorTemp->dtor = CClass_Destructor(TYPE_CLASS(expr->data.temp.type))) + ) + CError_FATAL(1749); + + ea = lalloc(sizeof(ExceptionAction)); + ea->prev = cexcept_eabefore; + cexcept_eabefore = ea; + ea->type = EAT_DESTROYLOCAL; + ea->data.destroy_local.local = dtorTemp->object; + ea->data.destroy_local.dtor = CABI_GetDestructorObject(dtorTemp->dtor, CABIDestroy1); + + ea = lalloc(sizeof(ExceptionAction)); + *ea = *cexcept_eabefore; + ea->prev = cexcept_eaafter; + cexcept_eaafter = ea; + } + + expr->type = EOBJREF; + expr->data.objref = object; + return expr; +} + +static ENode *CExcept_TransNewException(ENode *expr, Boolean isCond) { + Object *tempObj; + CLabel *label; + Boolean isArray; + Statement *stmt; + ExceptionAction *ea; + ENode *result; + + isArray = expr->type == ENEWEXCEPTIONARRAY; + + if (isCond) { + expr->data.newexception.initexpr = CExcept_TempTransExprCond(expr->data.newexception.initexpr); + expr->data.newexception.tryexpr = CExcept_TempTransExprCond(expr->data.newexception.tryexpr); + tempObj = create_temp_object(TYPE(&stchar)); + + stmt = CExcept_InsertPrevStatement(ST_EXPRESSION); + stmt->expr = makediadicnode(create_objectnode(tempObj), intconstnode(TYPE(&stchar), 0), EASS); + cexcept_prevstmt = stmt; + + ea = lalloc(sizeof(ExceptionAction)); + ea->prev = cexcept_eabefore; + cexcept_eabefore = ea; + + ea->type = EAT_DELETEPOINTERCOND; + ea->data.delete_pointer_cond.pointerobject = expr->data.newexception.pointertemp; + ea->data.delete_pointer_cond.deletefunc = expr->data.newexception.deletefunc; + ea->data.delete_pointer_cond.cond = tempObj; + + if (isArray) { + result = makediadicnode( + makediadicnode( + expr->data.newexception.initexpr, + makediadicnode(create_objectnode(tempObj), intconstnode(TYPE(&stchar), 1), EASS), + ECOMMA + ), + expr->data.newexception.tryexpr, + ECOMMA + ); + + result = makediadicnode( + result, + makediadicnode(create_objectnode(tempObj), intconstnode(TYPE(&stchar), 0), EASS), + ECOMMA + ); + + result = makediadicnode( + result, + create_objectnode(expr->data.newexception.pointertemp), + ECOMMA + ); + } else { + result = makediadicnode( + makediadicnode(create_objectnode(tempObj), intconstnode(TYPE(&stchar), 1), EASS), + expr->data.newexception.tryexpr, + ECOMMA + ); + + result = makediadicnode( + expr->data.newexception.initexpr, + makediadicnode( + result, + makediadicnode(create_objectnode(tempObj), intconstnode(TYPE(&stchar), 0), EASS), + ECOMMA + ), + ELAND + ); + + result = makediadicnode( + result, + create_objectnode(expr->data.newexception.pointertemp), + ECOMMA + ); + } + } else { + expr->data.newexception.initexpr = CExcept_TempTransExpr(expr->data.newexception.initexpr); + expr->data.newexception.tryexpr = CExcept_TempTransExpr(expr->data.newexception.tryexpr); + + if (isArray) { + stmt = CExcept_InsertPrevStatement(ST_EXPRESSION); + stmt->expr = expr->data.newexception.initexpr; + } else { + stmt = CExcept_InsertPrevStatement(ST_IFNGOTO); + stmt->expr = expr->data.newexception.initexpr; + label = newlabel(); + stmt->label = label; + } + + stmt = CFunc_InsertStatement(ST_EXPRESSION, stmt); + stmt->expr = expr->data.newexception.tryexpr; + + ea = lalloc(sizeof(ExceptionAction)); + ea->prev = cexcept_eabefore; + ea->type = EAT_DELETEPOINTER; + ea->data.delete_pointer.pointerobject = expr->data.newexception.pointertemp; + ea->data.delete_pointer.deletefunc = expr->data.newexception.deletefunc; + stmt->dobjstack = ea; + + if (!isArray) { + stmt = CFunc_InsertStatement(ST_LABEL, stmt); + stmt->label = label; + label->stmt = stmt; + stmt->dobjstack = cexcept_eabefore; + } + + cexcept_prevstmt = stmt; + result = create_objectnode(expr->data.newexception.pointertemp); + } + + result->rtype = expr->rtype; + return result; +} + +static ENode *CExcept_TransInitTryCatch(ENode *expr, Boolean isCond) { + CLabel *label1; + CLabel *label2; + CLabel *label3; + Object *catch_info_object; + Statement *stmt; + ExceptionAction *ea; + + cexcept_hastrycatch = 1; + + if (isCond) { + CError_ASSERT(1877, !cexcept_expandtrycatch); + + cexcept_serialize = 1; + expr->data.itc.initexpr = CExcept_TempTransExprCond(expr->data.itc.initexpr); + expr->data.itc.tryexpr = CExcept_TempTransExprCond(expr->data.itc.tryexpr); + expr->data.itc.catchexpr = CExcept_TempTransExprCond(expr->data.itc.catchexpr); + expr->data.itc.result = CExcept_TempTransExprCond(expr->data.itc.result); + return expr; + } + + expr->data.itc.initexpr = CExcept_TempTransExpr(expr->data.itc.initexpr); + expr->data.itc.tryexpr = CExcept_TempTransExpr(expr->data.itc.tryexpr); + expr->data.itc.catchexpr = CExcept_TempTransExpr(expr->data.itc.catchexpr); + expr->data.itc.result = CExcept_TempTransExpr(expr->data.itc.result); + + if (!cexcept_expandtrycatch) + return expr; + + label1 = newlabel(); + label2 = newlabel(); + label3 = newlabel(); + + catch_info_object = create_temp_object(TYPE(&catchinfostruct)); + + stmt = CExcept_InsertPrevStatement(ST_IFNGOTO); + stmt->expr = expr->data.itc.initexpr; + stmt->label = label3; + + ea = lalloc(sizeof(ExceptionAction)); + memclrw(ea, sizeof(ExceptionAction)); + ea->type = EAT_CATCHBLOCK; + ea->data.catch_block.catch_label = label2; + ea->data.catch_block.catch_info_object = catch_info_object; + ea->prev = stmt->dobjstack; + + stmt = CFunc_InsertStatement(ST_LABEL, stmt); + stmt->flags = StmtFlag_1; + stmt->label = label1; + label1->stmt = stmt; + stmt->dobjstack = ea; + + stmt = CFunc_InsertStatement(ST_BEGINCATCH, stmt); + stmt->expr = create_objectrefnode(catch_info_object); + + stmt = CFunc_InsertStatement(ST_EXPRESSION, stmt); + stmt->expr = expr->data.itc.tryexpr; + + stmt = CFunc_InsertStatement(ST_GOTO, stmt); + stmt->label = label3; + + CError_ASSERT(1928, stmt->dobjstack == ea); + + stmt->dobjstack = ea->prev; + + ea = lalloc(sizeof(ExceptionAction)); + memclrw(ea, sizeof(ExceptionAction)); + ea->type = EAT_ACTIVECATCHBLOCK; + ea->data.active_catch_block.catch_info_object = catch_info_object; + ea->prev = stmt->dobjstack; + + stmt = CFunc_InsertStatement(ST_LABEL, stmt); + stmt->flags = StmtFlag_1; + stmt->label = label2; + label2->stmt = stmt; + stmt->dobjstack = ea; + + stmt = CFunc_InsertStatement(ST_EXPRESSION, stmt); + stmt->expr = expr->data.itc.catchexpr; + + stmt = CFunc_InsertStatement(ST_EXPRESSION, stmt); + stmt->expr = funccallexpr(Xthrw_func, nullnode(), nullnode(), nullnode(), NULL); + + stmt = CFunc_InsertStatement(ST_LABEL, stmt); + stmt->label = label3; + label3->stmt = stmt; + + CError_ASSERT(1968, stmt->dobjstack == ea); + + stmt->dobjstack = ea->prev; + + cexcept_prevstmt = stmt; + return expr->data.itc.result; +} + +static ENode *CExcept_TempTransFuncCall(ENode *expr, Boolean isCond) { + ENodeList *tempArg; + ENodeList **argArray; + ENodeList *args; + ExceptionAction *ea; + Statement *stmt; + DtorTemp *dtorTemp; + ENode *tempNode; + + tempArg = NULL; + if ((args = expr->data.funccall.args)) { + tempNode = args->node; + if (tempNode->type == ETEMP) { + if (tempNode->data.temp.needs_dtor) + tempArg = args; + } else if (args->next) { + tempNode = args->next->node; + if (tempNode->type == ETEMP) { + if (tempNode->data.temp.needs_dtor) + tempArg = args->next; + } + } + } + + if (tempArg) { + if (isCond) { + ENodeList *arg = args; + SInt32 i = 0; + while (arg) { + arg = arg->next; + i++; + } + + argArray = lalloc(sizeof(ENodeList *) * i); + for (args = expr->data.funccall.args, i = 0; args; args = args->next) + argArray[i++] = args; + + while (i > 0) { + i--; + if (argArray[i] != tempArg) + argArray[i]->node = CExcept_TempTransExprCond(argArray[i]->node); + } + } else { + while (args) { + if (args != tempArg) + args->node = CExcept_TempTransExpr(args->node); + args = args->next; + } + } + + dtorTemp = lalloc(sizeof(DtorTemp)); + dtorTemp->next = cexcept_dtortemps; + cexcept_dtortemps = dtorTemp; + + dtorTemp->object = CExcept_GetETEMPObject(tempNode); + dtorTemp->temp = NULL; + + if ( + !IS_TYPE_CLASS(tempNode->data.temp.type) || + !(dtorTemp->dtor = CClass_Destructor(TYPE_CLASS(tempNode->data.temp.type))) + ) + CError_FATAL(2046); + + tempNode->type = EOBJREF; + tempNode->data.objref = dtorTemp->object; + + if (isCond) { + Type *type24 = expr->rtype; + dtorTemp->temp = create_temp_object(TYPE(&stchar)); + + expr = makediadicnode( + expr, + makediadicnode(create_objectnode(dtorTemp->temp), intconstnode(TYPE(&stchar), 1), EASS), + ECOMMA + ); + + expr = makediadicnode( + expr, + create_objectrefnode(dtorTemp->object), + ECOMMA + ); + expr->rtype = type24; + + stmt = CExcept_InsertPrevStatement(ST_EXPRESSION); + stmt->expr = makediadicnode( + create_objectnode(dtorTemp->temp), + intconstnode(TYPE(&stchar), 0), + EASS + ); + cexcept_prevstmt = stmt; + + ea = lalloc(sizeof(ExceptionAction)); + ea->prev = cexcept_eabefore; + cexcept_eabefore = ea; + + ea->type = EAT_DESTROYLOCALCOND; + ea->data.destroy_local_cond.local = dtorTemp->object; + ea->data.destroy_local_cond.dtor = CABI_GetDestructorObject(dtorTemp->dtor, CABIDestroy1); + ea->data.destroy_local_cond.cond = dtorTemp->temp; + + ea = lalloc(sizeof(ExceptionAction)); + *ea = *cexcept_eabefore; + ea->prev = cexcept_eaafter; + cexcept_eaafter = ea; + } else { + stmt = CExcept_InsertPrevStatement(ST_EXPRESSION); + stmt->expr = expr; + cexcept_prevstmt = stmt; + + ea = lalloc(sizeof(ExceptionAction)); + ea->prev = cexcept_eabefore; + cexcept_eabefore = ea; + + ea->type = EAT_DESTROYLOCAL; + ea->data.destroy_local.local = dtorTemp->object; + ea->data.destroy_local.dtor = CABI_GetDestructorObject(dtorTemp->dtor, CABIDestroy1); + + ea = lalloc(sizeof(ExceptionAction)); + *ea = *cexcept_eabefore; + ea->prev = cexcept_eaafter; + cexcept_eaafter = ea; + + expr = lalloc(sizeof(ENode)); + *expr = *stmt->expr; + expr->type = EOBJREF; + expr->data.objref = tempArg->node->data.objref; + } + return expr; + } else { + if (isCond) { + SInt32 i = 0; + while (args) { + args = args->next; + i++; + } + + argArray = lalloc(sizeof(ENodeList *) * i); + for (args = expr->data.funccall.args, i = 0; args; args = args->next) + argArray[i++] = args; + + while (i > 0) { + i--; + argArray[i]->node = CExcept_TempTransExprCond(argArray[i]->node); + } + + expr->data.funccall.funcref = CExcept_TempTransExprCond(expr->data.funccall.funcref); + } else { + while (args) { + args->node = CExcept_TempTransExpr(args->node); + args = args->next; + } + + expr->data.funccall.funcref = CExcept_TempTransExpr(expr->data.funccall.funcref); + } + + return expr; + } +} + +static ENode *CExcept_TempTransExprCond(ENode *expr) { + switch (expr->type) { + case ETEMP: + return CExcept_TempTrans_ETEMP(expr); + case ENEWEXCEPTION: + case ENEWEXCEPTIONARRAY: + return CExcept_TransNewException(expr, 1); + case EINITTRYCATCH: + return CExcept_TransInitTryCatch(expr, 1); + case ENULLCHECK: + expr->data.nullcheck.nullcheckexpr = CExcept_TempTransExprCond(expr->data.nullcheck.nullcheckexpr); + expr->data.nullcheck.condexpr = CExcept_TempTransExprCond(expr->data.nullcheck.condexpr); + return expr; + case ECOND: + expr->data.cond.cond = CExcept_TempTransExprCond(expr->data.cond.cond); + expr->data.cond.expr1 = CExcept_TempTransExprCond(expr->data.cond.expr1); + expr->data.cond.expr2 = CExcept_TempTransExprCond(expr->data.cond.expr2); + return expr; + case ELAND: + case ELOR: + expr->data.diadic.left = CExcept_TempTransExprCond(expr->data.diadic.left); + expr->data.diadic.right = CExcept_TempTransExprCond(expr->data.diadic.right); + return expr; + case EFUNCCALL: + case EFUNCCALLP: + return CExcept_TempTransFuncCall(expr, 1); + case EMUL: + case EDIV: + case EMODULO: + case EADD: + case ESUB: + case ESHL: + case ESHR: + case ELESS: + case EGREATER: + case ELESSEQU: + case EGREATEREQU: + case EEQU: + case ENOTEQU: + case EAND: + case EXOR: + case EOR: + case EASS: + case EMULASS: + case EDIVASS: + case EMODASS: + case EADDASS: + case ESUBASS: + case ESHLASS: + case ESHRASS: + case EANDASS: + case EXORASS: + case EORASS: + case ECOMMA: + case EROTL: + case EROTR: + expr->data.diadic.left = CExcept_TempTransExprCond(expr->data.diadic.left); + expr->data.diadic.right = CExcept_TempTransExprCond(expr->data.diadic.right); + return expr; + case EPOSTINC: + case EPOSTDEC: + case EPREINC: + case EPREDEC: + case EINDIRECT: + case EMONMIN: + case EBINNOT: + case ELOGNOT: + case ETYPCON: + case EBITFIELD: + expr->data.monadic = CExcept_TempTransExprCond(expr->data.monadic); + return expr; + case EINTCONST: + case EFLOATCONST: + case ESTRINGCONST: + case EOBJREF: + case EPRECOMP: + case ELABEL: + case EINSTRUCTION: + case EVECTOR128CONST: + return expr; + default: + CError_FATAL(2236); + return expr; + } +} + +static ENode *CExcept_TempTransExpr(ENode *expr) { + switch (expr->type) { + case ETEMP: + return CExcept_TempTrans_ETEMP(expr); + case ENEWEXCEPTION: + case ENEWEXCEPTIONARRAY: + return CExcept_TransNewException(expr, 0); + case EINITTRYCATCH: + return CExcept_TransInitTryCatch(expr, 0); + case ENULLCHECK: + expr->data.nullcheck.nullcheckexpr = CExcept_TempTransExpr(expr->data.nullcheck.nullcheckexpr); + expr->data.nullcheck.condexpr = CExcept_TempTransExprCond(expr->data.nullcheck.condexpr); + return expr; + case ECOND: + expr->data.cond.cond = CExcept_TempTransExpr(expr->data.cond.cond); + expr->data.cond.expr1 = CExcept_TempTransExprCond(expr->data.cond.expr1); + expr->data.cond.expr2 = CExcept_TempTransExprCond(expr->data.cond.expr2); + return expr; + case ELAND: + case ELOR: + case ECOMMA: + expr->data.diadic.left = CExcept_TempTransExpr(expr->data.diadic.left); + expr->data.diadic.right = CExcept_TempTransExprCond(expr->data.diadic.right); + return expr; + case EFUNCCALL: + case EFUNCCALLP: + return CExcept_TempTransFuncCall(expr, 0); + case EMUL: + case EDIV: + case EMODULO: + case EADD: + case ESUB: + case ESHL: + case ESHR: + case ELESS: + case EGREATER: + case ELESSEQU: + case EGREATEREQU: + case EEQU: + case ENOTEQU: + case EAND: + case EXOR: + case EOR: + case EASS: + case EMULASS: + case EDIVASS: + case EMODASS: + case EADDASS: + case ESUBASS: + case ESHLASS: + case ESHRASS: + case EANDASS: + case EXORASS: + case EORASS: + case EROTL: + case EROTR: + expr->data.diadic.left = CExcept_TempTransExpr(expr->data.diadic.left); + expr->data.diadic.right = CExcept_TempTransExpr(expr->data.diadic.right); + return expr; + case EPOSTINC: + case EPOSTDEC: + case EPREINC: + case EPREDEC: + case EINDIRECT: + case EMONMIN: + case EBINNOT: + case ELOGNOT: + case ETYPCON: + case EBITFIELD: + expr->data.monadic = CExcept_TempTransExpr(expr->data.monadic); + return expr; + case EINTCONST: + case EFLOATCONST: + case ESTRINGCONST: + case EOBJREF: + case EMFPOINTER: + case EPRECOMP: + case ELABEL: + case EOBJLIST: + case EMEMBER: + case EINSTRUCTION: + case EVECTOR128CONST: + return expr; + default: + CError_FATAL(2350); + return expr; + } +} + +static Statement *CExcept_DtorTransform(Statement *stmt) { + DtorTemp *dtorTemp; + Statement *curStmt; + CLabel *lastLabel; + + dtorTemp = cexcept_dtortemps; + curStmt = stmt; + while (dtorTemp) { + if ( + cexcept_eaafter && + (cexcept_eaafter->type == EAT_DESTROYLOCAL || cexcept_eaafter->type == EAT_DESTROYLOCALCOND) && + cexcept_eaafter->data.destroy_local.local == dtorTemp->object + ) + { + cexcept_eaafter = cexcept_eaafter->prev; + } else { + CError_FATAL(2374); + } + + if (dtorTemp->temp) { + curStmt = CFunc_InsertStatement(ST_IFNGOTO, curStmt); + curStmt->expr = create_objectnode(dtorTemp->temp); + curStmt->dobjstack = cexcept_eaafter; + lastLabel = curStmt->label = newlabel(); + } + + curStmt = CFunc_InsertStatement(ST_EXPRESSION, curStmt); + curStmt->expr = CABI_DestroyObject(dtorTemp->dtor, create_objectrefnode(dtorTemp->object), CABIDestroy1, 1, 0); + curStmt->dobjstack = cexcept_eaafter; + + if (dtorTemp->temp) { + curStmt = CFunc_InsertStatement(ST_LABEL, curStmt); + curStmt->label = lastLabel; + lastLabel->stmt = curStmt; + } + + dtorTemp = dtorTemp->next; + } + + return curStmt; +} + +static void CExcept_TempTransform(Statement *stmt, Boolean flag1, Boolean flag2) { + Statement *prevStmt; + Statement *iter; + Statement copy; + Object *tempObj; + + prevStmt = cexcept_prevstmt; + cexcept_dtortemps = NULL; + cexcept_serialize = 0; + cexcept_expandtrycatch = 0; + cexcept_hastrycatch = 0; + stmt->expr = CExcept_TempTransExpr(stmt->expr); + + if (cexcept_hastrycatch) { + cexcept_expandtrycatch = 1; + if (cexcept_serialize) { + CInline_SerializeStatement(stmt); + cexcept_prevstmt = stmt; + } else { + cexcept_prevstmt = prevStmt; + } + + iter = prevStmt; + while (1) { + CError_ASSERT(2425, iter); + + switch (iter->type) { + case ST_RETURN: + CError_ASSERT(2429, iter->expr != NULL); + case ST_EXPRESSION: + case ST_SWITCH: + case ST_IFGOTO: + case ST_IFNGOTO: + iter->expr = CExcept_TempTransExpr(iter->expr); + } + + if (iter == stmt) + break; + cexcept_prevstmt = iter; + iter = iter->next; + } + } + + if (cexcept_dtortemps) { + if (!flag1) { + if (flag2) { + ENode *expr = stmt->expr; + CError_ASSERT(2456, !IS_TYPE_CLASS(expr->rtype) || !CClass_Destructor(TYPE_CLASS(expr->rtype))); + + tempObj = create_temp_object(expr->rtype); + stmt->expr = makediadicnode(create_objectnode(tempObj), expr, EASS); + } + + copy = *stmt; + stmt->type = ST_EXPRESSION; + stmt = CExcept_DtorTransform(stmt); + stmt = CFunc_InsertStatement(copy.type, stmt); + stmt->label = copy.label; + + if (flag2) + stmt->expr = create_objectnode(tempObj); + else + stmt->expr = nullnode(); + } else { + CExcept_DtorTransform(stmt); + } + } +} + +static void CExcept_CleanupExceptionActions(Statement *stmt) { + Statement *iter; + ENode *expr; + ExceptionAction *ea; + + cexcept_prevstmt = stmt; + for (iter = stmt; iter; iter = iter->next) { + cexcept_eabefore = cexcept_eaafter = ea = iter->dobjstack; + + if (iter->flags & StmtFlag_2) { + cexcept_eabefore = ea->prev; + } else if (iter->type == ST_EXPRESSION) { + expr = iter->expr; + while (ENODE_IS(expr, ECOMMA)) + expr = expr->data.diadic.left; + if (ENODE_IS(expr, EINDIRECT)) + expr = expr->data.monadic; + + if ( + ENODE_IS(expr, EFUNCCALL) && + ENODE_IS(expr->data.funccall.funcref, EOBJREF) && + CClass_IsConstructor(expr->data.funccall.funcref->data.objref) && + iter->dobjstack && + iter->dobjstack->type == EAT_DESTROYLOCAL && + expr->data.funccall.args && + ENODE_IS(expr->data.funccall.args->node, EOBJREF) && + expr->data.funccall.args->node->data.objref == iter->dobjstack->data.destroy_local.local + ) + cexcept_eabefore = cexcept_eabefore->prev; + } + + switch (iter->type) { + case ST_EXPRESSION: + CExcept_TempTransform(iter, 1, 0); + break; + case ST_SWITCH: + case ST_IFGOTO: + case ST_IFNGOTO: + CExcept_TempTransform(iter, 0, 1); + break; + case ST_RETURN: + if (iter->expr) { + CExcept_TempTransform( + iter, + 0, + CMach_GetFunctionResultClass(TYPE_FUNC(cscope_currentfunc->type)) != 1 + ); + } + break; + } + + iter->dobjstack = cexcept_eabefore; + cexcept_prevstmt = iter; + } +} + +static void CExcept_InsertSpecificationActions(Statement *stmt, ExceptSpecList *exspecs) { + Statement *iter; + Statement *last; + ExceptionAction *ea_spec; + ExceptionAction *ea; + ExceptSpecList *spec_iter; + SInt32 i; + Object *catch_info_object; + CLabel *label; + + ea_spec = lalloc(sizeof(ExceptionAction)); + memclrw(ea_spec, sizeof(ExceptionAction)); + ea_spec->type = EAT_SPECIFICATION; + + for (iter = stmt; iter; iter = iter->next) { + if ((ea = iter->dobjstack)) { + while (1) { + if (ea->type == EAT_SPECIFICATION) + break; + if (ea->prev == NULL) { + ea->prev = ea_spec; + break; + } + ea = ea->prev; + } + } else { + iter->dobjstack = ea_spec; + } + } + + last = stmt; + while (last->next) + last = last->next; + + if (last->type != ST_GOTO && last->type != ST_RETURN) { + last = CFunc_InsertStatement(ST_RETURN, last); + last->expr = NULL; + last->dobjstack = NULL; + if (TYPE_FUNC(cscope_currentfunc->type)->functype != &stvoid && (copts.pedantic || copts.cplusplus)) + CError_Warning(CErrorStr184); + } + + last = CFunc_InsertStatement(ST_LABEL, last); + last->label = newlabel(); + last->label->stmt = last; + last->flags = StmtFlag_1; + last->dobjstack = NULL; + + catch_info_object = create_temp_object(TYPE(&catchinfostruct)); + + if (!exspecs->type) + exspecs = NULL; + + i = 0; + spec_iter = exspecs; + while (spec_iter) { + spec_iter = spec_iter->next; + i++; + } + + ea_spec->data.specification.unexp_ids = i; + ea_spec->data.specification.unexp_id = galloc(sizeof(Object *) * i); + ea_spec->data.specification.unexp_label = last->label; + ea_spec->data.specification.unexp_info_object = catch_info_object; + + i = 0; + while (exspecs) { + ea_spec->data.specification.unexp_id[i] = CExcept_TypeID(exspecs->type, exspecs->qual); + exspecs = exspecs->next; + i++; + } + + last = CFunc_InsertStatement(ST_EXPRESSION, last); + last->expr = funccallexpr(Xunex_func, create_objectrefnode(catch_info_object), NULL, NULL, NULL); + + ea = lalloc(sizeof(ExceptionAction)); + memclrw(ea, sizeof(ExceptionAction)); + ea->type = EAT_ACTIVECATCHBLOCK; + ea->data.active_catch_block.catch_info_object = catch_info_object; + ea->data.active_catch_block.call_dtor = 1; + last->dobjstack = ea; + + last = CFunc_InsertStatement(ST_LABEL, last); + last->label = label = newlabel(); + last->label->stmt = last; + last->dobjstack = NULL; + + last = CFunc_InsertStatement(ST_GOTO, last); + last->label = label; +} + +static void CExcept_HasFuncCallCallBack(ENode *expr) { + ENode *funcref = expr->data.funccall.funcref; + if (ENODE_IS(funcref, EOBJREF)) { + Object *func = funcref->data.objref; + if (CExcept_CanThrowException(func, func->datatype == DVFUNC && !(expr->flags & ENODE_FLAG_80))) + cexcept_canthrow = 1; + } else { + cexcept_canthrow = 1; + } +} + +static Boolean CExcept_CanThrowCheck(Object *func, Statement *stmt) { + cexcept_canthrow = 0; + + while (stmt) { + switch (stmt->type) { + case ST_NOP: + case ST_LABEL: + case ST_GOTO: + case ST_ASM: + break; + case ST_RETURN: + if (!stmt->expr) + break; + case ST_EXPRESSION: + case ST_SWITCH: + case ST_IFGOTO: + case ST_IFNGOTO: + case ST_BEGINCATCH: + case ST_ENDCATCH: + case ST_ENDCATCHDTOR: + case ST_GOTOEXPR: + CExpr_SearchExprTree(stmt->expr, CExcept_HasFuncCallCallBack, 2, EFUNCCALL, EFUNCCALLP); + break; + default: + CError_FATAL(2687); + } + stmt = stmt->next; + } + + if (!cexcept_canthrow) { + TYPE_FUNC(cscope_currentfunc->type)->flags |= FUNC_NOTHROW; + return 0; + } else { + return 1; + } +} + +void CExcept_ExceptionTansform(Statement *stmt) { + cexcept_uniqueobjs = NULL; + CExcept_CleanupExceptionActions(stmt); + + if (cscope_currentfunc && CExcept_CanThrowCheck(cscope_currentfunc, stmt)) { + CError_ASSERT(2716, IS_TYPE_FUNC(cscope_currentfunc->type)); + if (TYPE_FUNC(cscope_currentfunc->type)->exspecs && copts.exceptions) + CExcept_InsertSpecificationActions(stmt, TYPE_FUNC(cscope_currentfunc->type)->exspecs); + } +} diff --git a/compiler_and_linker/FrontEnd/C/CExpr.c b/compiler_and_linker/FrontEnd/C/CExpr.c new file mode 100644 index 0000000..484f56d --- /dev/null +++ b/compiler_and_linker/FrontEnd/C/CExpr.c @@ -0,0 +1,4971 @@ +#include "compiler/CExpr.h" +#include "compiler/CABI.h" +#include "compiler/CClass.h" +#include "compiler/CDecl.h" +#include "compiler/CError.h" +#include "compiler/CException.h" +#include "compiler/CInit.h" +#include "compiler/CInline.h" +#include "compiler/CIRTransform.h" +#include "compiler/CMachine.h" +#include "compiler/CMangler.h" +#include "compiler/CInt64.h" +#include "compiler/CObjC.h" +#include "compiler/CObjCModern.h" +#include "compiler/CParser.h" +#include "compiler/CPrep.h" +#include "compiler/CPrepTokenizer.h" +#include "compiler/CRTTI.h" +#include "compiler/CSOM.h" +#include "compiler/CTemplateNew.h" +#include "compiler/CTemplateTools.h" +#include "compiler/CodeGen.h" +#include "compiler/CompilerTools.h" +#include "compiler/PPCError.h" +#include "compiler/objects.h" +#include "compiler/scopes.h" +#include "compiler/templates.h" + +Boolean (*name_obj_check)(HashNameNode *, Object *); +Boolean disallowgreaterthan; + +// forward declarations +static ENode *makeaddnode(ENode *left, ENode *right); +static ENode *makesubnode(ENode *left, ENode *right); + +ENode *CExpr_RewriteConst(ENode *expr) { + Object *obj; + +restart: + if (ENODE_IS(expr, EINDIRECT) && ENODE_IS(expr->data.monadic, EOBJREF)) { + obj = expr->data.monadic->data.objref; + if (obj->datatype == DALIAS) { + CExpr_AliasTransform(expr->data.monadic); + goto restart; + } + + if ((obj->qual & Q_INLINE_DATA) && expr->rtype == obj->type) { + switch (expr->rtype->type) { + case TYPEINT: + case TYPEENUM: + expr->type = EINTCONST; + expr->data.intval = obj->u.data.u.intconst; + break; + case TYPEPOINTER: + expr->type = EINTCONST; + expr->data.intval = obj->u.data.u.intconst; + expr->rtype = TYPE(&stunsignedlong); + expr = makemonadicnode(expr, ETYPCON); + expr->rtype = obj->type; + break; + case TYPEFLOAT: + expr->type = EFLOATCONST; + if (obj->u.data.u.floatconst) + expr->data.floatval = *obj->u.data.u.floatconst; + else + expr->data.floatval = CMach_CalcFloatConvertFromInt(TYPE(&stsignedlong), cint64_zero); + break; + default: + CError_FATAL(105); + } + } + } + + return expr; +} + +void optimizecomm(ENode *expr) { + ENode *right; + ENode *left; + + if (ENODE_IS((right = expr->data.diadic.right), EINTCONST)) + return; + if (ENODE_IS((left = expr->data.diadic.left), EINTCONST)) { + swap: + expr->data.diadic.right = left; + expr->data.diadic.left = right; + return; + } + + if (ENODE_IS(left, EFLOATCONST)) + return; + if (ENODE_IS(right, EFLOATCONST)) + goto swap; + + if (expr->rtype->type > TYPEFLOAT) + return; + + if (left->cost > right->cost) + goto swap; +} + +static void checkadditive(ENode *expr) { + switch (expr->rtype->type) { + case TYPEINT: + if (expr->rtype == TYPE(&stbool)) + break; + case TYPEFLOAT: + return; + case TYPEENUM: + if (copts.cplusplus) + break; + return; + case TYPEPOINTER: + if (TPTR_TARGET(expr->rtype)->size == 0) + CDecl_CompleteType(TPTR_TARGET(expr->rtype)); + if (TPTR_TARGET(expr->rtype)->size == 0) + break; + return; + case TYPEARRAY: + if (ENODE_IS(expr, EOBJREF)) + return; + } + + CError_Error(CErrorStr376, expr->rtype, ENODE_QUALS(expr)); +} + +static void CExpr_CompareConvert(ENode **leftp, char *opname, ENode **rightp, Boolean flag) { + ENode *left; + ENode *right; + CInt64 val; + + left = *leftp; + right = *rightp; + + switch (left->rtype->type) { + case TYPEINT: + break; + case TYPEFLOAT: + if (left->rtype != right->rtype) + CExpr_ArithmeticConversion(leftp, rightp); + return; + case TYPEENUM: + left->rtype = TYPE_ENUM(left->rtype)->enumtype; + break; + default: + CError_Error(CErrorStr377, + left->rtype, ENODE_QUALS(left), + opname, + right->rtype, ENODE_QUALS(right)); + left = nullnode(); + } + + switch (right->rtype->type) { + case TYPEINT: + break; + case TYPEFLOAT: + CExpr_ArithmeticConversion(leftp, rightp); + return; + case TYPEENUM: + right->rtype = TYPE_ENUM(right->rtype)->enumtype; + break; + default: + CError_Error(CErrorStr377, + left->rtype, ENODE_QUALS(left), + opname, + right->rtype, ENODE_QUALS(right)); + right = nullnode(); + } + + if (left->rtype == right->rtype) { + *leftp = left; + *rightp = right; + return; + } + + if (left->rtype->size == right->rtype->size) { + if (is_unsigned(left->rtype) == is_unsigned(right->rtype)) { + left->rtype = right->rtype; + *leftp = left; + *rightp = right; + return; + } + } else { + if (ENODE_IS(right, EINTCONST) && left->rtype->size <= right->rtype->size && (is_unsigned(left->rtype) == is_unsigned(right->rtype) || is_unsigned(left->rtype))) { + val = CMach_CalcIntDiadic(left->rtype, right->data.intval, '+', cint64_zero); + val = CMach_CalcIntDiadic(right->rtype, val, '+', cint64_zero); + if (CInt64_Equal(val, right->data.intval)) { + right->rtype = left->rtype; + *leftp = left; + *rightp = right; + return; + } + } + + if (ENODE_IS(left, EINTCONST) && left->rtype->size >= right->rtype->size && (is_unsigned(left->rtype) == is_unsigned(right->rtype) || is_unsigned(right->rtype))) { + val = CMach_CalcIntDiadic(right->rtype, left->data.intval, '+', cint64_zero); + val = CMach_CalcIntDiadic(left->rtype, val, '+', cint64_zero); + if (CInt64_Equal(val, left->data.intval)) { + left->rtype = right->rtype; + *leftp = left; + *rightp = right; + return; + } + } + } + + *leftp = left; + *rightp = right; + CExpr_ArithmeticConversion(leftp, rightp); +} + +static ENode *CExpr_ConstResult(ENode *expr, SInt32 value) { + ENode *constnode; + + if (IS_TYPE_FLOAT(expr->rtype)) { + constnode = intconstnode(TYPE(&stsignedint), value); + constnode->type = EFLOATCONST; + constnode->data.floatval = CMach_CalcFloatConvertFromInt(TYPE(&stsignedint), constnode->data.intval); + constnode->rtype = expr->rtype; + } else { + constnode = intconstnode(expr->rtype, value); + } + + if (CInline_ExpressionHasSideEffect(expr)) + return makediadicnode(expr, constnode, ECOMMA); + else + return constnode; +} + +static ENode *makemultnode(ENode *left, ENode *right) { + CExpr_ArithmeticConversion(&left, &right); + if (iszero(left)) + return CExpr_ConstResult(right, 0); + if (iszero(right)) + return CExpr_ConstResult(left, 0); + + if (CExpr_IsOne(right)) + return left; + if (CExpr_IsOne(left)) + return right; + + if (ENODE_IS(left, EINTCONST) && ENODE_IS(right, EINTCONST)) { + left->data.intval = CMach_CalcIntDiadic(left->rtype, left->data.intval, '*', right->data.intval); + return left; + } + if (ENODE_IS(left, EFLOATCONST) && ENODE_IS(right, EFLOATCONST)) { + left->data.floatval = CMach_CalcFloatDiadic(left->rtype, left->data.floatval, '*', right->data.floatval); + return left; + } + + left = makediadicnode(left, right, EMUL); + optimizecomm(left); + if (IS_TYPE_INT(left->rtype) && left->rtype->size > 2) { + left->cost++; + if (left->cost > 200) + left->cost = 200; + } + + if (IS_TYPE_FLOAT(left->rtype)) + left = CExpr_BinaryFloatExpression(left); + + return left; +} + +static ENode *makedivnode(ENode *left, ENode *right, Boolean no_warning) { + CExpr_ArithmeticConversion(&left, &right); + if (iszero(right) && IS_TYPE_INT(right->rtype)) { + if (!no_warning) + CError_Warning(CErrorStr139); + return right; + } + + if (CExpr_IsOne(right)) + return left; + + if (iszero(left) && IS_TYPE_INT(left->rtype)) + return CExpr_ConstResult(right, 0); + + if (ENODE_IS(left, EINTCONST) && ENODE_IS(right, EINTCONST)) { + left->data.intval = CMach_CalcIntDiadic(left->rtype, left->data.intval, '/', right->data.intval); + return left; + } + if (ENODE_IS(left, EFLOATCONST) && ENODE_IS(right, EFLOATCONST)) { + left->data.floatval = CMach_CalcFloatDiadic(left->rtype, left->data.floatval, '/', right->data.floatval); + return left; + } + + left = makediadicnode(left, right, EDIV); + if (IS_TYPE_FLOAT(left->rtype)) + left = CExpr_BinaryFloatExpression(left); + + return left; +} + +static short canadd2(ENode *expr, CInt64 value) { + Float tmp; + + if (CInt64_IsZero(&value)) + return 1; + + switch (expr->type) { + case EINTCONST: + expr->data.intval = CMach_CalcIntDiadic(expr->rtype, expr->data.intval, '+', value); + return 1; + case EFLOATCONST: + tmp = CMach_CalcFloatConvertFromInt(TYPE(&stsignedlong), value); + expr->data.floatval = CMach_CalcFloatDiadic(expr->rtype, expr->data.floatval, '+', tmp); + return 1; + case EADD: + if (canadd2(expr->data.diadic.left, value)) + return 1; + if (canadd2(expr->data.diadic.right, value)) + return 1; + return 0; + case ESUB: + if (canadd2(expr->data.diadic.left, value)) + return 1; + if (canadd2(expr->data.diadic.right, CInt64_Neg(value))) + return 1; + return 0; + case ETYPCON: + if (IS_TYPE_POINTER_ONLY(expr->rtype) && ENODE_IS(expr->data.monadic, EINTCONST)) { + expr->data.monadic->data.intval = CMach_CalcIntDiadic(TYPE(&stunsignedlong), expr->data.monadic->data.intval, '+', value); + return 1; + } + return 0; + default: + return 0; + } +} + +short canadd(ENode *expr, SInt32 value) { + CInt64 value64; + CInt64_SetLong(&value64, value); + return canadd2(expr, value64); +} + +static ENode *addconst(ENode *expr, SInt32 value) { + ENode *right; + + if (canadd(expr, value)) + return expr; + + if (stsignedint.size < 4 && (value > 0x7FFF || value < -0x8000)) + right = intconstnode(TYPE(&stsignedlong), value); + else + right = intconstnode(TYPE(&stsignedint), value); + + CExpr_ArithmeticConversion(&expr, &right); + expr = makediadicnode(expr, right, EADD); + return expr; +} + +static ENode *integralpointerpromote(ENode *expr) { + Boolean uns; + Type *type; + + if (!IS_TYPE_INT(expr->rtype)) + expr = forceintegral(expr); + + if (expr->rtype->size != 4) { + type = TYPE(&stunsignedlong); + if (is_unsigned(type) != (uns = is_unsigned(expr->rtype))) { + if (uns) { + if (stunsignedlong.size == 4) { + type = TYPE(&stunsignedlong); + } else if (stunsignedint.size == 4) { + type = TYPE(&stunsignedint); + } else { + CError_FATAL(480); + } + } else { + if (stsignedlong.size == 4) { + type = TYPE(&stsignedlong); + } else if (stsignedint.size == 4) { + type = TYPE(&stsignedint); + } else { + CError_FATAL(486); + } + } + } + + if (ENODE_IS(expr, EINTCONST)) + expr->data.intval = CExpr_IntConstConvert(type, expr->rtype, expr->data.intval); + else + expr = makemonadicnode(expr, ETYPCON); + + expr->rtype = type; + } + + return expr; +} + +static ENode *padd(ENode *left, ENode *right) { + Type *innertype; + SInt32 innersize; + ENode *expr; + + right = integralpointerpromote(right); + innertype = TPTR_TARGET(left->rtype); + innersize = innertype->size; + if (innersize == 0) { + CDecl_CompleteType(innertype); + innersize = innertype->size; + if (innersize == 0) { + CError_Error(CErrorStr146); + return left; + } + } + + expr = makemultnode( + right, + intconstnode((innersize > 0x7FFF) ? TYPE(&stsignedlong) : TYPE(&stsignedint), innersize)); + + if (ENODE_IS(expr, EINTCONST) && canadd2(left, expr->data.intval)) + return left; + + if (ENODE_IS(left, EADD) && ENODE_IS(left->data.diadic.right, EINTCONST)) { + left->data.diadic.left = makediadicnode(left->data.diadic.left, expr, EADD); + return left; + } + + expr = makediadicnode(left, expr, EADD); + expr->rtype = left->rtype; + expr->flags = left->flags; + return expr; +} + +static ENode *psub(ENode *left, ENode *right) { + Type *innertype; + SInt32 innersize; + ENode *expr; + + if (IS_TYPE_POINTER(right->rtype)) { + innersize = TPTR_TARGET(left->rtype)->size; + if (innersize == 0) { + CDecl_CompleteType(TPTR_TARGET(left->rtype)); + innersize = TPTR_TARGET(left->rtype)->size; + if (innersize == 0) { + CError_Error(CErrorStr146); + return left; + } + } + + if (!is_typeequal(left->rtype, right->rtype)) { + CError_Error(CErrorStr245, left->rtype, ENODE_QUALS(left), right->rtype, ENODE_QUALS(right)); + return left; + } + + if (ENODE_IS(left, ETYPCON) && ENODE_IS(left->data.monadic, EINTCONST) && ENODE_IS(right, ETYPCON) && ENODE_IS(right->data.monadic, EINTCONST)) { + left->data.monadic->rtype = right->data.monadic->rtype = CABI_GetPtrDiffTType(); + expr = makesubnode(left->data.monadic, right->data.monadic); + if (innersize > 1) + expr = makedivnode(expr, intconstnode(CABI_GetPtrDiffTType(), innersize), 11); + return expr; + } + + expr = makediadicnode(left, right, ESUB); + expr->rtype = CABI_GetPtrDiffTType(); + if (innersize > 1) + expr = makediadicnode(expr, intconstnode(CABI_GetPtrDiffTType(), innersize), EDIV); + return expr; + } + + right = integralpointerpromote(right); + innertype = TPTR_TARGET(left->rtype); + innersize = innertype->size; + if (innersize == 0) { + CDecl_CompleteType(innertype); + innersize = innertype->size; + if (innersize == 0) { + CError_Error(CErrorStr146); + return left; + } + } + + expr = makemultnode(right, intconstnode(CABI_GetPtrDiffTType(), innersize)); + if (ENODE_IS(expr, EINTCONST) && canadd2(left, CInt64_Neg(expr->data.intval))) + return left; + + expr = makediadicnode(left, expr, ESUB); + expr->rtype = left->rtype; + expr->flags = left->flags; + return expr; +} + +static ENode *makeaddnode(ENode *left, ENode *right) { + if (IS_TYPE_POINTER(left->rtype)) + return padd(left, right); + if (IS_TYPE_POINTER(right->rtype)) + return padd(right, left); + + CExpr_ArithmeticConversion(&left, &right); + if (iszero(right)) + return left; + if (iszero(left)) + return right; + + if (ENODE_IS(left, EINTCONST) && ENODE_IS(right, EINTCONST)) { + left->data.intval = CMach_CalcIntDiadic(left->rtype, left->data.intval, '+', right->data.intval); + return left; + } + if (ENODE_IS(left, EFLOATCONST) && ENODE_IS(right, EFLOATCONST)) { + left->data.floatval = CMach_CalcFloatDiadic(left->rtype, left->data.floatval, '+', right->data.floatval); + return left; + } + + if (ENODE_IS(left, EINTCONST) && canadd2(right, left->data.intval)) + return right; + if (ENODE_IS(right, EINTCONST) && canadd2(left, right->data.intval)) + return left; + + left = makediadicnode(left, right, EADD); + optimizecomm(left); + if (IS_TYPE_FLOAT(left->rtype)) + left = CExpr_BinaryFloatExpression(left); + return left; +} + +static ENode *makesubnode(ENode *left, ENode *right) { + if (ENODE_IS(right, EINTCONST) && !is_unsigned(right->rtype) && !IS_TYPE_FLOAT(left->rtype)) { + right->data.intval = CInt64_Neg(right->data.intval); + return makeaddnode(left, right); + } + + if (IS_TYPE_POINTER(left->rtype)) + return psub(left, right); + + CExpr_ArithmeticConversion(&left, &right); + if (iszero(right)) + return left; + if (iszero(left)) { + if (ENODE_IS(right, EINTCONST)) { + right->data.intval = CInt64_Neg(right->data.intval); + return right; + } + if (ENODE_IS(right, EFLOATCONST)) { + right->data.floatval = CMach_CalcFloatMonadic(right->rtype, '-', right->data.floatval); + return right; + } + return CExpr_UnaryFloatExpression(makemonadicnode(right, EMONMIN)); + } + + if (ENODE_IS(left, EINTCONST) && ENODE_IS(right, EINTCONST)) { + left->data.intval = CMach_CalcIntDiadic(left->rtype, left->data.intval, '-', right->data.intval); + return left; + } + if (ENODE_IS(left, EFLOATCONST) && ENODE_IS(right, EFLOATCONST)) { + left->data.floatval = CMach_CalcFloatDiadic(left->rtype, left->data.floatval, '-', right->data.floatval); + return left; + } + + if (ENODE_IS(right, EINTCONST) && canadd2(left, CInt64_Neg(right->data.intval))) + return left; + + left = makediadicnode(left, right, ESUB); + if (IS_TYPE_FLOAT(left->rtype)) + left = CExpr_BinaryFloatExpression(left); + return left; +} + +ENode *checkreference(ENode *expr) { + if (!IS_TYPE_REFERENCE(expr->rtype)) + return expr; + + expr = makemonadicnode(expr, EINDIRECT); + expr->rtype = TPTR_TARGET(expr->rtype); + return expr; +} + +static ENode *pointer_generation2(ENode *expr) { + switch (expr->type) { + case EINDIRECT: + switch (expr->rtype->type) { + case TYPEARRAY: + switch (expr->data.monadic->type) { + case EPOSTINC: + case EPOSTDEC: + case EPREINC: + case EPREDEC: + expr->type = ETYPCON; + expr->rtype = CDecl_NewPointerType(TPTR_TARGET(expr->rtype)); + return expr; + default: + expr->data.monadic->rtype = CDecl_NewPointerType(TPTR_TARGET(expr->rtype)); + expr->data.monadic->flags = expr->flags; + return expr->data.monadic; + } + case TYPEFUNC: + expr = expr->data.monadic; + if (ENODE_IS(expr, EOBJREF) && expr->data.objref->datatype == DINLINEFUNC) + CError_Error(CErrorStr175); + return expr; + } + } + return expr; +} + +ENode *pointer_generation(ENode *expr) { + return CExpr_RewriteConst(pointer_generation2(expr)); +} + +ENode *CExpr_PointerGeneration(ENode *expr) { + switch (expr->type) { + case EINDIRECT: + switch (expr->rtype->type) { + case TYPEARRAY: + expr->data.monadic->rtype = CDecl_NewPointerType(TPTR_TARGET(expr->rtype)); + return expr->data.monadic; + case TYPEFUNC: + return expr->data.monadic; + } + } + return expr; +} + +static void CExpr_ConstPointerCheck(ENode *expr, Type *type, short qual) { + Type *exprtype; + Type *b; + Type *a; + short exprqual; + + exprtype = expr->rtype; + if (IS_TYPE_POINTER_ONLY(type) && IS_TYPE_POINTER_ONLY(exprtype)) { + exprqual = expr->flags; + + if (TPTR_TARGET(type) == &stvoid) { + exprqual = CParser_GetCVTypeQualifiers(TPTR_TARGET(exprtype), exprqual); + } else { + a = TPTR_TARGET(type); + b = TPTR_TARGET(exprtype); + while (IS_TYPE_POINTER_ONLY(a) && IS_TYPE_POINTER_ONLY(b)) { + if (CParser_IsMoreCVQualified(TPTR_QUAL(b), TPTR_QUAL(a))) { + CError_Warning(CErrorStr220, expr->rtype, ENODE_QUALS(expr), type, qual); + return; + } + a = TPTR_TARGET(a); + b = TPTR_TARGET(b); + } + } + + if (CParser_IsMoreCVQualified(exprqual, qual)) { + CError_Warning(CErrorStr220, expr->rtype, ENODE_QUALS(expr), type, (UInt32) qual); + } + } +} + +ENode *oldassignmentpromotion(ENode *expr, Type *type, short qual, Boolean flag) { + Boolean is_ref; + UInt32 ref_qual; + short orig_qual; + + is_ref = 0; + if (!IS_TYPE_MEMBERPOINTER(type)) { + if (IS_TYPE_REFERENCE(type)) { + if (ENODE_IS(expr, ECOND)) + expr = CExpr_LValue(expr, 0, 0); + expr = pointer_generation2(expr); + ref_qual = CParser_GetCVTypeQualifiers(expr->rtype, expr->flags); + is_ref = 1; + } else { + expr = pointer_generation(expr); + } + } + + if (ENODE_IS(expr, EMEMBER)) + expr = getpointertomemberfunc(expr, type, 1); + + if (!is_ref) + CExpr_ConstPointerCheck(expr, type, qual); + else + CExpr_ConstPointerCheck(expr, TPTR_TARGET(type), qual); + + if (!(assign_check(expr, type, orig_qual = qual, 1, 0, flag))) + return expr; + + if (is_ref) { + if (temp_reference_init) { + switch (TPTR_TARGET(type)->type) { + case TYPEPOINTER: + qual = TPTR_QUAL(TPTR_TARGET(type)); + } + if (!(qual & Q_CONST)) + CError_Warning(CErrorStr228); + } else { + if (ref_qual && ref_qual > CParser_GetCVTypeQualifiers(TPTR_TARGET(type), orig_qual)) + CError_Warning(CErrorStr259); + } + } + + return assign_node; +} + +ENode *argumentpromotion(ENode *expr, Type *type, short qual, Boolean flag) { + ENode *tmp; + ENodeList *list; + + if (IS_TYPE_CLASS(type) && CClass_ReferenceArgument(TYPE_CLASS(type))) { + if ((tmp = CExpr_IsTempConstruction(expr, type, NULL))) + return tmp; + + list = lalloc(sizeof(ENodeList)); + list->next = NULL; + list->node = expr; + tmp = CExpr_ConstructObject( + TYPE_CLASS(type), + create_temp_node(type), + list, 1, 1, 1, 1, 0); + return getnodeaddress(tmp, 0); + } + + return CExpr_AssignmentPromotion(expr, type, qual, flag); +} + +ENode *classargument(ENode *expr) { + ENodeList *list; + + if (CClass_CopyConstructor(TYPE_CLASS(expr->rtype))) { + list = lalloc(sizeof(ENodeList)); + list->next = NULL; + list->node = expr; + return CExpr_ConstructObject( + TYPE_CLASS(expr->rtype), + create_temp_node(expr->rtype), + list, 1, 1, 1, 1, 0); + } + + return expr; +} + +ENodeList *CExpr_ScanExpressionList(Boolean is_parens) { + ENodeList *list; + ENodeList *current; + + if (is_parens && tk == ')') + return NULL; + + list = current = lalloc(sizeof(ENodeList)); + + while (1) { + current->next = NULL; + current->node = assignment_expression(); + if (copts.old_argmatch && !ENODE_IS(current->node, EMEMBER)) + current->node = pointer_generation(current->node); + + if (is_parens) { + if (tk == ')') + break; + } else { + if (tk == ']') + break; + } + + if (tk != ',') { + CError_ErrorSkip(CErrorStr116); + break; + } + + tk = lex(); + current->next = lalloc(sizeof(ENodeList)); + current = current->next; + } + + return list; +} + +static ENode *skipcommaexpr(ENode *expr) { + while (ENODE_IS(expr, ECOMMA)) + expr = expr->data.diadic.right; + return expr; +} + +ENode *CExpr_DoExplicitConversion(Type *type, UInt32 qual, ENodeList *list) { + Object *obj; + ENode *tmp; + + if (!IS_TYPE_CLASS(type)) { + if (!list) + return do_typecast(nullnode(), type, qual); + if (list->next) + CError_Error(CErrorStr356); + return do_typecast(pointer_generation(list->node), type, qual); + } + + CDecl_CompleteType(type); + if (!(TYPE_CLASS(type)->flags & CLASS_COMPLETED)) + CError_Error(CErrorStr136, type, 0); + + CanCreateObject(type); + if (!list && CClass_IsPODClass(TYPE_CLASS(type))) { + obj = CParser_NewGlobalDataObject(NULL); + obj->name = CParser_GetUniqueName(); + obj->nspace = cscope_root; + obj->type = type; + obj->qual = qual; + obj->sclass = TK_STATIC; + CInit_DeclareData(obj, NULL, NULL, type->size); + + tmp = makemonadicnode(create_temp_node(type), EINDIRECT); + tmp->rtype = type; + tmp->flags = qual & ENODE_FLAG_QUALS; + return makediadicnode(tmp, create_objectnode(obj), EASS); + } + + return CExpr_ConstructObject(TYPE_CLASS(type), create_temp_node(type), list, 1, 1, 1, 1, 1); +} + +static ENode *CExpr_TemplArgDepCast(Type *type, UInt32 qual, ENodeList *args) { + ENode *expr = CExpr_NewTemplDepENode(TDE_CAST); + expr->data.templdep.u.cast.args = args; + expr->data.templdep.u.cast.type = type; + expr->data.templdep.u.cast.qual = qual; + return expr; +} + +static ENode *CExpr_ParseExplicitConversion(Type *type, UInt32 qual) { + ENodeList *args; + ENodeList *scan; + + if (IS_TEMPL_CLASS(type) && !CParser_CheckTemplateClassUsage(TEMPL_CLASS(type), 1)) + type = TYPE(&stsignedint); + + if (tk == '(') + tk = lex(); + else + CError_Error(CErrorStr114); + + args = CExpr_ScanExpressionList(1); + if (tk != ')') { + CError_Error(CErrorStr115); + return nullnode(); + } + + tk = lex(); + if (CTemplTool_IsTemplateArgumentDependentType(type)) + return CExpr_TemplArgDepCast(type, qual, args); + + for (scan = args; scan; scan = scan->next) { + if (CTemplTool_IsTemplateArgumentDependentExpression(scan->node)) + return CExpr_TemplArgDepCast(type, qual, args); + } + + return CExpr_DoExplicitConversion(type, qual, args); +} + +static ENode *CExpr_MemberVarAccess(BClassList *path, ObjMemberVar *var, ENode *expr) { + ENode *accessnode; + BClassList *varpath; + + CError_ASSERT(1152, path); + + if (TYPE_CLASS(path->type)->sominfo) + return CSOM_MemberVarAccess(path, var, expr); + + varpath = NULL; + if (var->has_path) + varpath = OBJ_MEMBER_VAR_PATH(var)->path; + accessnode = CExpr_GetClassAccessNode(path, varpath, expr, NULL, var->access, 1); + if (!accessnode) + return nullnode(); + + return CClass_AccessMember(accessnode, var->type, var->qual, var->offset); +} + +static Boolean CExpr_IsTemplateFunc(Object *obj) { + return IS_TEMPL_FUNC(obj->type); +} + +static ENode *CExpr_ExplicitTemplateArgCheck(NameResult *pr) { + NameSpaceObjectList *list; + NameSpaceObjectList *newhead; + NameSpaceObjectList *newlist; + ENode *expr; + + if (pr->obj_10) { + if (pr->obj_10->otype != OT_OBJECT || !CExpr_IsTemplateFunc(OBJECT(pr->obj_10))) + return NULL; + + list = lalloc(sizeof(NameSpaceObjectList)); + memclrw(list, sizeof(NameSpaceObjectList)); + list->object = pr->obj_10; + } else if (pr->nsol_14) { + for (list = pr->nsol_14; list; list = list->next) { + if (list->object->otype == OT_OBJECT && CExpr_IsTemplateFunc(OBJECT(list->object))) { + newhead = newlist = galloc(sizeof(NameSpaceObjectList)); + *newlist = *list; + newlist->next = NULL; + while ((list = list->next)) { + if (list->object->otype == OT_OBJECT && CExpr_IsTemplateFunc(OBJECT(list->object))) { + newlist->next = galloc(sizeof(NameSpaceObjectList)); + newlist = newlist->next; + *newlist = *list; + newlist->next = NULL; + } + } + list = newhead; + break; + } + } + if (!list) + return NULL; + } else { + return NULL; + } + + expr = CExpr_NewENode(EOBJLIST); + expr->rtype = OBJECT(list->object)->type; + expr->data.objlist.list = list; + expr->data.objlist.templargs = CTempl_ParseUncheckTemplArgs(NULL, 0); + + tk = lex(); + return expr; +} + +ENode *CExpr_MakeNameLookupResultExpr(NameResult *pr) { + ENode *expr; + + if (pr->obj_10) { + switch (pr->obj_10->otype) { + case OT_OBJECT: + CClass_CheckObjectAccess(pr->bcl_18, OBJECT(pr->obj_10)); + return create_objectnode(OBJECT(pr->obj_10)); + case OT_ENUMCONST: + CClass_CheckEnumAccess(pr->bcl_18, OBJ_ENUM_CONST(pr->obj_10)); + expr = lalloc(sizeof(ENode)); + expr->type = EINTCONST; + expr->cost = 0; + expr->flags = 0; + expr->rtype = OBJ_ENUM_CONST(pr->obj_10)->type; + expr->data.intval = OBJ_ENUM_CONST(pr->obj_10)->val; + return expr; + case OT_MEMBERVAR: + CError_Error(CErrorStr221); + return nullnode(); + default: + CError_FATAL(1268); + } + } + + if (pr->nsol_14) { + expr = CExpr_NewENode(EOBJLIST); + expr->rtype = OBJECT(pr->nsol_14->object)->type; + expr->data.objlist.list = pr->nsol_14; + return expr; + } + + CError_FATAL(1278); + return NULL; +} + +static Type *CExpr_NewPTMType(EMemberInfo *member, Object *obj) { + TypeMemberPointer *ptm; + TypeMemberFunc *tmethod; + BClassList *path; + + ptm = galloc(sizeof(TypeMemberPointer)); + memclrw(ptm, sizeof(TypeMemberPointer)); + ptm->type = TYPEMEMBERPOINTER; + + if (member->list->object->otype == OT_MEMBERVAR) { + path = member->path; + while (path->next) + path = path->next; + ptm->size = 4; + ptm->ty2 = path->type; + ptm->ty1 = OBJ_MEMBER_VAR(member->list->object)->type; + } else { + if (!obj) { + CError_ASSERT(1306, member->list->object->otype == OT_OBJECT); + obj = OBJECT(member->list->object); + CError_ASSERT(1308, IS_TYPE_FUNC(obj->type)); + } + + tmethod = galloc(sizeof(TypeMemberFunc)); + memclrw(tmethod, sizeof(TypeMemberFunc)); + *tmethod = *TYPE_METHOD(obj->type); + + CError_ASSERT(1312, tmethod->args); + + tmethod->args = tmethod->args->next; + CDecl_MakePTMFuncType(TYPE_FUNC(tmethod)); + tmethod->flags &= ~FUNC_DEFINED; + + ptm->size = 12; + ptm->ty2 = TYPE(tmethod->theclass); + ptm->ty1 = TYPE(tmethod); + } + + return TYPE(ptm); +} + +static ENode *CExpr_ParseNameResultExpr(NameResult *pr, ENode *expr, Boolean flag1, Boolean flag2) { + ENode *result; + ENode *ta_expr; + ObjEnumConst *oec; + TemplateAction *act; + EMemberInfo *member; + NameSpaceObjectList *list; + Object *obj; + TypeFunc *tfunc; + SInt32 val; + + if (pr->type) { + if (copts.cplusplus) { + if (IS_TYPE_TEMPLATE(pr->type)) { + if (TYPE_TEMPLATE(pr->type)->dtype == TEMPLDEP_ARGUMENT && TYPE_TEMPLATE(pr->type)->u.pid.type == TPT_NONTYPE) { + result = CExpr_NewTemplDepENode(TDE_PARAM); + result->data.templdep.u.pid = TYPE_TEMPLATE(pr->type)->u.pid; + tk = lex(); + return result; + } + if (TYPE_TEMPLATE(pr->type)->dtype == TEMPLDEP_QUALNAME && !pr->x20) { + result = CExpr_NewTemplDepENode(TDE_QUALNAME); + result->data.templdep.u.qual.type = TYPE_TEMPLATE(pr->type)->u.qual.type; + result->data.templdep.u.qual.name = TYPE_TEMPLATE(pr->type)->u.qual.name; + tk = lex(); + return result; + } + } + tk = lex(); + return CExpr_ParseExplicitConversion(pr->type, pr->qual); + } + CError_ErrorSkip(CErrorStr141); + tk = lex(); + return nullnode(); + } + + if (pr->obj_10) { + switch (pr->obj_10->otype) { + case OT_OBJECT: + if (OBJECT(pr->obj_10)->nspace && OBJECT(pr->obj_10)->nspace->theclass && (OBJECT(pr->obj_10)->nspace->theclass->flags & CLASS_IS_TEMPL)) { + result = CExpr_NewTemplDepENode(TDE_OBJ); + result->data.templdep.u.obj = OBJECT(pr->obj_10); + tk = lex(); + return result; + } + if (!expr || !IS_TEMPL_FUNC(OBJECT(pr->obj_10)->type)) { + if (!IS_TYPE_NONSTATIC_METHOD(OBJECT(pr->obj_10)->type)) { + tk = lex(); + if (tk == '<' && (ta_expr = CExpr_ExplicitTemplateArgCheck(pr))) + return ta_expr; + if (OBJECT(pr->obj_10)->datatype == DLOCAL && OBJECT(pr->obj_10)->u.var.info->func != cscope_currentfunc) { + CError_Error(CErrorStr330); + return nullnode(); + } + if (OBJECT(pr->obj_10)->datatype == DEXPR) { + result = CInline_CopyExpression(OBJECT(pr->obj_10)->u.expr, CopyMode0); + if (IS_TYPE_POINTER_ONLY(result->rtype) && ENODE_IS(result, EINTCONST)) { + result = makemonadicnode(result, ETYPCON); + result->data.monadic->rtype = TYPE(&stunsignedlong); + } + return result; + } + CClass_CheckObjectAccess(pr->bcl_18, OBJECT(pr->obj_10)); + if (tk == '(' && flag2 && OBJECT(pr->obj_10)->datatype == DFUNC && copts.cplusplus && !pr->x1D && !IS_TYPEFUNC_METHOD(TYPE_FUNC(OBJECT(pr->obj_10)->type))) { + result = CExpr_NewENode(EOBJLIST); + result->rtype = OBJECT(pr->obj_10)->type; + result->data.objlist.list = galloc(sizeof(NameSpaceObjectList)); + result->data.objlist.list->next = pr->nsol_14; + result->data.objlist.list->object = pr->obj_10; + result->data.objlist.name = OBJECT(pr->obj_10)->name; + return result; + } + + result = create_objectnode(OBJECT(pr->obj_10)); + if (expr) { + while (ENODE_IS(expr, EINDIRECT)) + expr = expr->data.monadic; + switch (expr->type) { + case EINTCONST: + case EOBJREF: + case EOBJLIST: + break; + default: + result = makecommaexpression(expr, result); + } + } + return result; + } + if (CClass_IsDestructor(OBJECT(pr->obj_10))) { + if ((tk = lex()) != '(') { + CError_Error(CErrorStr114); + return nullnode(); + } + if ((tk = lex()) != ')') { + CError_Error(CErrorStr115); + return nullnode(); + } + if (!expr && (!cscope_currentfunc || !cscope_currentclass || !cscope_is_member_func)) { + CError_Error(CErrorStr221); + return nullnode(); + } + if (pr->isambig) + CError_Error(CErrorStr188); + + if ((expr = CExpr_GetClassAccessNode(pr->bcl_18, NULL, expr, OBJECT(pr->obj_10), pr->obj_10->access, 1))) { + tk = lex(); + return CABI_DestroyObject(OBJECT(pr->obj_10), expr->data.monadic, 1, pr->x1D, 0); + } + } + } + break; + case OT_ENUMCONST: + CClass_CheckEnumAccess(pr->bcl_18, OBJ_ENUM_CONST(pr->obj_10)); + oec = OBJ_ENUM_CONST(pr->obj_10); + if (CInt64_IsZero(&oec->val) && IS_TYPE_ENUM(oec->type) && TYPE_ENUM(oec->type)->nspace && TYPE_ENUM(oec->type)->nspace->theclass && (TYPE_ENUM(oec->type)->nspace->theclass->flags & CLASS_IS_TEMPL)) { + val = 0; + expr = NULL; + for (act = TEMPL_CLASS(TYPE_ENUM(oec->type)->nspace->theclass)->actions; act; act = act->next) { + if (act->type == TAT_ENUMERATOR) { + if (act->u.enumerator.initexpr) { + expr = act->u.enumerator.initexpr; + val = 0; + } else { + val++; + } + if (act->u.enumerator.objenumconst == oec) { + CError_ASSERT(1521, expr); + expr = CInline_CopyExpression(expr, CopyMode0); + if (val) + expr = makediadicnode(expr, intconstnode(TYPE(&stsignedlong), val), EADD); + tk = lex(); + return expr; + } + } + } + } + result = lalloc(sizeof(ENode)); + result->type = EINTCONST; + result->cost = 0; + result->flags = 0; + result->rtype = OBJ_ENUM_CONST(pr->obj_10)->type; + result->data.intval = OBJ_ENUM_CONST(pr->obj_10)->val; + tk = lex(); + return result; + case OT_MEMBERVAR: + if (!flag1 || expr || !pr->x1D) { + if (pr->isambig) + CError_Error(CErrorStr188); + result = checkreference(CExpr_MemberVarAccess(pr->bcl_18, OBJ_MEMBER_VAR(pr->obj_10), expr)); + tk = lex(); + return result; + } + break; + default: + CError_FATAL(1552); + } + + member = lalloc(sizeof(EMemberInfo)); + memclrw(member, sizeof(EMemberInfo)); + member->path = pr->bcl_18; + member->expr = expr; + member->pr_1D = pr->x1D; + member->isambig = pr->isambig; + if ((tk = lex()) == '<' && (ta_expr = CExpr_ExplicitTemplateArgCheck(pr))) { + CError_ASSERT(1564, ENODE_IS(ta_expr, EOBJLIST)); + member->list = ta_expr->data.objlist.list; + member->templargs = ta_expr->data.objlist.templargs; + } else { + member->list = galloc(sizeof(NameSpaceObjectList)); + member->list->next = NULL; + member->list->object = pr->obj_10; + } + + result = CExpr_NewENode(EMEMBER); + result->data.emember = member; + result->rtype = &stvoid; + return result; + } + + if (pr->nsol_14) { + if ((tk = lex()) == '<' && (ta_expr = CExpr_ExplicitTemplateArgCheck(pr))) { + CError_ASSERT(1591, ENODE_IS(ta_expr, EOBJLIST)); + for (list = ta_expr->data.objlist.list; list; list = list->next) { + if (list->object->otype == OT_OBJECT && IS_TYPE_NONSTATIC_METHOD(OBJECT(list->object)->type)) { + member = lalloc(sizeof(EMemberInfo)); + memclrw(member, sizeof(EMemberInfo)); + + member->path = pr->bcl_18; + member->expr = expr; + member->list = ta_expr->data.objlist.list; + member->templargs = ta_expr->data.objlist.templargs; + member->pr_1D = pr->x1D; + member->isambig = pr->isambig; + + result = CExpr_NewENode(EMEMBER); + result->data.emember = member; + result->rtype = &stvoid; + return result; + } + } + return ta_expr; + } + + for (list = pr->nsol_14; list; list = list->next) { + if (list->object->otype == OT_OBJECT && IS_TYPE_NONSTATIC_METHOD(OBJECT(list->object)->type)) { + member = lalloc(sizeof(EMemberInfo)); + memclrw(member, sizeof(EMemberInfo)); + + member->path = pr->bcl_18; + member->expr = expr; + member->list = pr->nsol_14; + member->pr_1D = pr->x1D; + member->isambig = pr->isambig; + + result = CExpr_NewENode(EMEMBER); + result->data.emember = member; + result->rtype = &stvoid; + return result; + } + } + + if (tk == '<' && (ta_expr = CExpr_ExplicitTemplateArgCheck(pr))) + return ta_expr; + + result = CExpr_NewENode(EOBJLIST); + result->rtype = OBJECT(pr->nsol_14->object)->type; + result->data.objlist.list = pr->nsol_14; + if (tk == '(' && copts.cplusplus && flag2 && !pr->x1D && pr->nsol_14->object->otype == OT_OBJECT) + result->data.objlist.name = OBJECT(pr->nsol_14->object)->name; + return result; + } + + if (pr->name_4) { + if (copts.cplusplus && flag2) { + if (lookahead() == '(') { + result = CExpr_NewENode(EOBJLIST); + result->rtype = &stvoid; + result->data.objlist.name = pr->name_4; + tk = lex(); + return result; + } + CError_Error(CErrorStr140, pr->name_4->name); + tk = lex(); + return nullnode(); + } + + if (lookahead() != '(') { + CError_Error(CErrorStr140, pr->name_4->name); + tk = lex(); + return nullnode(); + } + + if (copts.checkprotos) + CError_Error(CErrorStr178); + + tfunc = galloc(sizeof(TypeFunc)); + memclrw(tfunc, sizeof(TypeFunc)); + tfunc->type = TYPEFUNC; + tfunc->functype = TYPE(&stsignedint); + tfunc->args = &oldstyle; + CDecl_SetFuncFlags(tfunc, 0); + + obj = CParser_NewFunctionObject(NULL); + obj->name = pr->name_4; + obj->sclass = TK_EXTERN; + obj->nspace = cscope_root; + obj->type = TYPE(tfunc); + + CScope_AddGlobalObject(obj); + tk = lex(); + return create_objectrefnode(obj); + } + + CError_FATAL(1711); + return NULL; +} + +static ENode *CExpr_ParseRotate(Boolean is_right) { + ENode *expr1; + ENode *expr2; + + if (lex() != '(') { + CError_Error(CErrorStr114); + return nullnode(); + } + + tk = lex(); + expr1 = assignment_expression(); + + if (tk != ',') { + CError_Error(CErrorStr116); + return nullnode(); + } + + tk = lex(); + expr2 = assignment_expression(); + + if (tk != ')') { + CError_Error(CErrorStr115); + return nullnode(); + } + + if (!IS_TYPE_INT(expr1->rtype)) + expr1 = forceintegral(expr1); + expr2 = integralpromote(expr2); + + tk = lex(); + if (iszero(expr1) || iszero(expr2)) + return expr1; + + return makediadicnode(expr1, expr2, is_right ? EROTR : EROTL); +} + +static ENode *CExpr_ParseNextArg(void) { + NameSpaceObjectList *list; + NameResult pr; + ENode *expr; + SInt32 rounded_size; + + if ((tk = lex()) != '(') { + CError_Error(CErrorStr114); + return nullnode(); + } + if ((tk = lex()) != TK_IDENTIFIER) { + CError_Error(CErrorStr107); + return nullnode(); + } + + list = CScope_FindObjectList(&pr, tkidentifier); + if (!list) { + CError_Error(CErrorStr140, tkidentifier->name); + return nullnode(); + } + + if (list->object->otype != OT_OBJECT || OBJECT(list->object)->datatype != DLOCAL) { + CError_Error(CErrorStr140, tkidentifier->name); + return nullnode(); + } + + rounded_size = CMach_RoundedSizeOf(OBJECT(list->object)); + expr = CExpr_MakeObjRefNode(OBJECT(list->object), 1); + expr = makediadicnode(expr, intconstnode(CABI_GetPtrDiffTType(), rounded_size), EADD); + expr->rtype = TYPE(&void_ptr); + + if ((tk = lex()) != ')') { + CError_Error(CErrorStr115); + return expr; + } else { + tk = lex(); + return expr; + } +} + +static ENode *CExpr_ParseVecStep(void) { + ENode *expr; + Type *type; + SInt32 value; + DeclInfo di; + + expr = intconstnode(TYPE(&stsignedint), 0); + if ((tk = lex()) == '(') { + if (tk == '(' && islookaheaddeclaration()) { + tk = lex(); + memclrw(&di, sizeof(DeclInfo)); + CParser_GetDeclSpecs(&di, 0); + scandeclarator(&di); + if (di.name) + CError_Error(CErrorStr121); + + if (tk != ')') + CError_ErrorSkip(CErrorStr115); + else + tk = lex(); + + type = di.thetype; + if (IS_TYPE_REFERENCE(type)) + type = TPTR_TARGET(type); + } else { + expr = unary_expression(); + if (ENODE_IS(expr, EINDIRECT) && ENODE_IS(expr->data.monadic, EBITFIELD)) + CError_Error(CErrorStr144); + type = expr->rtype; + } + + CDecl_CompleteType(type); + if (IS_TYPE_VECTOR(type)) { + switch (TYPE_STRUCT(type)->stype) { + case STRUCT_VECTOR_UCHAR: + case STRUCT_VECTOR_SCHAR: + case STRUCT_VECTOR_BCHAR: + value = 16; + break; + case STRUCT_VECTOR_USHORT: + case STRUCT_VECTOR_SSHORT: + case STRUCT_VECTOR_BSHORT: + case STRUCT_VECTOR_PIXEL: + value = 8; + break; + default: + value = 4; + } + expr = intconstnode(TYPE(&stsignedint), value); + } else { + PPCError_Error(PPCErrorStr104, "vec_step", "vec_step", type, 0); + } + } else { + CError_Error(CErrorStr114); + } + + return expr; +} + +static SInt32 CExpr_BuiltInComputeAlign(Type *type) { + return CMach_GetTypeAlign(type); +} + +static SInt32 CExpr_AtomTypeID(IntegralType what) { + switch (what) { + case IT_BOOL: return 1; + case IT_CHAR: return 2; + case IT_SCHAR: return 3; + case IT_UCHAR: return 4; + case IT_WCHAR_T: return 5; + case IT_SHORT: return 6; + case IT_USHORT: return 7; + case IT_INT: return 8; + case IT_UINT: return 9; + case IT_LONG: return 10; + case IT_ULONG: return 10; + case IT_LONGLONG: return 12; + case IT_ULONGLONG: return 13; + case IT_FLOAT: return 14; + case IT_SHORTDOUBLE: return 15; + case IT_DOUBLE: return 16; + case IT_LONGDOUBLE: return 17; + case IT_17: return 32; + case IT_18: return 33; + case IT_19: return 34; + case IT_20: return 35; + case IT_21: return 36; + case IT_22: return 37; + case IT_23: return 38; + case IT_24: return 39; + default: + CError_FATAL(1976); + return 0; + } +} + +static SInt32 CExpr_BuiltInComputeType(Type *type) { + switch (type->type) { + case TYPEINT: + return 0x100 | CExpr_AtomTypeID(TYPE_INTEGRAL(type)->integral); + case TYPEFLOAT: + return 0x200 | CExpr_AtomTypeID(TYPE_INTEGRAL(type)->integral); + case TYPEENUM: + return 0x400 | (CExpr_BuiltInComputeType(TYPE_ENUM(type)->enumtype) & 0xFF); + case TYPEPOINTER: + return 0x800; + case TYPEARRAY: + return 0x1000; + case TYPESTRUCT: + return 0x2000; + case TYPECLASS: + return 0x2000; + case TYPEMEMBERPOINTER: + return 0x4000; + case TYPEFUNC: + return 0x8000; + default: + CError_Error(CErrorStr146); + case TYPEVOID: + return 0; + } +} + +static SInt32 CExpr_BuiltInClassifyType(Type *type) { + switch (type->type) { + case TYPEVOID: return 0; + case TYPEFUNC: return 10; + case TYPEENUM: return 3; + case TYPEINT: return 1; + case TYPEFLOAT: return 8; + case TYPEPOINTER: case TYPEMEMBERPOINTER: return 5; + case TYPEARRAY: return 14; + case TYPESTRUCT: return 12; + case TYPECLASS: return 12; + case TYPEBITFIELD: return -1; + case TYPETEMPLATE: return -1; + default: return -1; + } +} + +static SInt32 CExpr_BuiltInComputeVArgType(Type *type) { + switch (type->type) { + case TYPEINT: + case TYPEENUM: + return 0; + case TYPEFLOAT: + return 1; + default: + return 2; + } +} + +static Type *CExpr_ParseTypeExpression(Boolean *outflag) { + ENode *expr; + Type *type; + DeclInfo di; + + tk = lex(); + if (tk == '(' && islookaheaddeclaration()) { + tk = lex(); + memclrw(&di, sizeof(DeclInfo)); + CParser_GetDeclSpecs(&di, 0); + scandeclarator(&di); + if (di.name) + CError_Error(CErrorStr121); + + if (tk != ')') + CError_ErrorSkip(CErrorStr115); + else + tk = lex(); + + type = di.thetype; + if (IS_TYPE_REFERENCE(type)) + type = TPTR_TARGET(type); + } else { + expr = unary_expression(); + if (ENODE_IS(expr, EINDIRECT) && ENODE_IS(expr->data.monadic, EBITFIELD)) + CError_Error(CErrorStr144); + + if (outflag) + *outflag = ENODE_IS(expr, EINTCONST) && CInt64_IsZero(&expr->data.intval); + + type = expr->rtype; + } + + CDecl_CompleteType(type); + return type; +} + +static ENode *CExpr_ParseBuiltin(SInt32 (*parser)(Type *)) { + ENode *expr; + expr = intconstnode(TYPE(&stsignedint), 0); + CInt64_SetLong(&expr->data.intval, parser(CExpr_ParseTypeExpression(NULL))); + return expr; +} + +static ENode *CExpr_ParseBuiltin_isintconst(void) { + ENode *expr; + expr = intconstnode(TYPE(&stsignedint), 0); + + tk = lex(); + if (tk != '(') + CError_ErrorSkip(CErrorStr121); + else + tk = lex(); + + if (ENODE_IS(expression(), EINTCONST)) + CInt64_SetLong(&expr->data.intval, 1); + + if (tk != ')') + CError_ErrorSkip(CErrorStr115); + else + tk = lex(); + + return expr; +} + +static ENode *primary_expression(Boolean flag) { + NameResult pr; + ENode *expr; + + switch (tk) { + case TK_TRUE: + expr = lalloc(sizeof(ENode)); + expr->type = EINTCONST; + expr->cost = 0; + expr->flags = 0; + expr->rtype = TYPE(&stbool); + CInt64_SetULong(&expr->data.intval, 1); + tk = lex(); + return expr; + case TK_FALSE: + expr = lalloc(sizeof(ENode)); + expr->type = EINTCONST; + expr->cost = 0; + expr->flags = 0; + expr->rtype = TYPE(&stbool); + CInt64_SetULong(&expr->data.intval, 0); + tk = lex(); + return expr; + case TK_INTCONST: + expr = lalloc(sizeof(ENode)); + expr->type = EINTCONST; + expr->cost = 0; + expr->flags = 0; + expr->rtype = atomtype(); + expr->data.intval = tkintconst; + tk = lex(); + return expr; + case TK_FLOATCONST: + expr = lalloc(sizeof(ENode)); + expr->type = EFLOATCONST; + expr->cost = 0; + expr->flags = 0; + expr->rtype = atomtype(); + expr->data.floatval = tkfloatconst; + tk = lex(); + return expr; + case TK_STRING: + expr = CExpr_NewENode(ESTRINGCONST); + expr->rtype = CDecl_NewArrayType(ispascalstring ? TYPE(&stunsignedchar) : TYPE(&stchar), tksize); + expr->data.string.size = tksize; + expr->data.string.data = tkstring; + expr->data.string.ispascal = ispascalstring; + if (copts.const_strings) + expr->flags = ENODE_FLAG_CONST; + expr = makemonadicnode(expr, EINDIRECT); + expr->data.monadic->rtype = CDecl_NewPointerType(expr->rtype); + tk = lex(); + return expr; + case TK_STRING_WIDE: + expr = CExpr_NewENode(ESTRINGCONST); + expr->rtype = CDecl_NewArrayType(CParser_GetWCharType(), tksize); + expr->data.string.size = tksize; + expr->data.string.data = tkstring; + expr->data.string.ispascal = ispascalstring; + if (copts.const_strings) + expr->flags = ENODE_FLAG_CONST; + expr = makemonadicnode(expr, EINDIRECT); + expr->data.monadic->rtype = CDecl_NewPointerType(expr->rtype); + tk = lex(); + return expr; + case TK_THIS: + case TK_SELF: + expr = CClass_CreateThisSelfExpr(); + if (!expr) + expr = nullnode(); + tk = lex(); + return expr; + case TK_AT_SELECTOR: + return CObjC_ParseSelectorExpression(); + case TK_AT_ENCODE: + return CObjC_ParseEncodeExpression(); + case TK_AT_PROTOCOL: + return CObjC_ParseProtocolExpression(); + case '@': + if (copts.objective_c) + return CObjC_ParseAtExpression(); + break; + case '(': + tk = lex(); + expr = s_expression(); + if (tk != ')') + CError_ErrorSkip(CErrorStr115); + else + tk = lex(); + if (ENODE_IS(expr, EASS)) + expr->flags = expr->flags | ENODE_FLAG_80; + return expr; + case '[': + if (copts.objective_c) + return CObjC_ParseMessageExpression(); + break; + case TK_IDENTIFIER: + if (tkidentifier->name[0] == '_' && tkidentifier->name[1] == '_') { + if (!strcmp(tkidentifier->name, "__builtin_align")) + return CExpr_ParseBuiltin(CExpr_BuiltInComputeAlign); + if (!strcmp(tkidentifier->name, "__builtin_ntype")) + return CExpr_ParseBuiltin(CExpr_BuiltInComputeType); + if (!strcmp(tkidentifier->name, "__builtin_type") || !strcmp(tkidentifier->name, "__builtin_vargtype")) + return CExpr_ParseBuiltin(CExpr_BuiltInComputeVArgType); + if (!strcmp(tkidentifier->name, "__builtin_classify_type")) + return CExpr_ParseBuiltin(CExpr_BuiltInClassifyType); + if (!strcmp(tkidentifier->name, "__builtin_next_arg")) + return CExpr_ParseNextArg(); + } + if (copts.altivec_model && !strcmp("vec_step", tkidentifier->name)) + return CExpr_ParseVecStep(); + case '~': + case TK_OPERATOR: + case TK_INHERITED: + case TK_COLON_COLON: + if (CScope_ParseExprName(&pr)) + return CExpr_ParseNameResultExpr(&pr, NULL, flag, 1); + tk = lex(); + return nullnode(); + } + + CError_ErrorSkip(CErrorStr141); + return nullnode(); +} + +static ENode *CExpr_SimpleExplicitConversion(void) { + DeclInfo di; + + memclrw(&di, sizeof(DeclInfo)); + + if (!copts.cpp_extensions && tk != TK_UU_TYPEOF_UU && tk != TK_TYPENAME && lookahead() != '(') + CError_Error(CErrorStr114); + + CParser_GetDeclSpecs(&di, 0); + return CExpr_ParseExplicitConversion(di.thetype, di.qual); +} + +static ENode *CExpr_NewPTMFCall(void) { + tk = lex(); + CExpr_ScanExpressionList(1); + + if (tk != ')') { + CError_Error(CErrorStr115); + return nullnode(); + } else { + CError_FATAL(2465); + return nullnode(); + } +} + +static ENode *call_ptmf(ENode *expr) { + Type *rettype; + ENodeList *args; + ENodeList *list1; + ENodeList *list2; + Object *callobj; + + rettype = TYPE_FUNC(TPTR_TARGET(expr->data.mfpointer.mfpointer->rtype))->functype; + tk = lex(); + args = CExpr_ScanExpressionList(1); + + if (tk != ')') { + CError_Error(CErrorStr115); + return nullnode(); + } + + if (IS_TYPE_STRUCT(rettype) || IS_TYPE_CLASS(rettype) || IS_TYPE_12BYTES_MEMBERPOINTER(rettype)) + callobj = rt_ptmf_scall4; + else + callobj = rt_ptmf_scall; + + list1 = lalloc(sizeof(ENodeList)); + list1->next = args; + list1->node = expr->data.mfpointer.accessnode->data.monadic; + + list2 = lalloc(sizeof(ENodeList)); + list2->next = list1; + list2->node = expr->data.mfpointer.mfpointer->data.monadic; + + if (!copts.old_argmatch) { + CError_ASSERT(2568, IS_TYPE_POINTER_ONLY(list2->node->rtype)); + list2->node->rtype = TYPE(&void_ptr); + } + + expr = CExpr_GenericPtmfCall( + callobj, + TYPE_FUNC(TPTR_TARGET(expr->data.mfpointer.mfpointer->rtype)), + list2); + tk = lex(); + return expr; +} + +static ENode *CExpr_DummyDestr(ENode *expr) { + SInt32 state; + NameResult pr; + DeclInfo di; + NameSpace *nspace; + + CPrep_TokenStreamGetState(&state); + nspace = cscope_current; + if ((tk = lex()) == TK_COLON_COLON) { + nspace = cscope_root; + tk = lex(); + } else if (tk != '~' && tk != TK_IDENTIFIER && !(tk >= TK_AUTO && tk <= TK_BYREF)) { + CPrep_TokenStreamSetCurState(&state); + return NULL; + } + +loop: + if (tk == '~') + goto is_tilde; + if (tk == TK_IDENTIFIER) { + if (CScope_FindTypeName(nspace, tkidentifier, &pr)) { + tk = lex(); + if (pr.nspace_0) { + if (tk == TK_COLON_COLON) { + tk = lex(); + nspace = pr.nspace_0; + goto loop; + } + } else if (IS_TYPE_CLASS(pr.type) && tk == TK_COLON_COLON) { + tk = lex(); + nspace = TYPE_CLASS(pr.type)->nspace; + goto loop; + } else { + if (!is_typesame(pr.type, expr->rtype)) + CError_Error(CErrorStr146); + if (tk == TK_COLON_COLON && ((tk = lex()) == '~') && ((tk = lex()) == TK_IDENTIFIER)) { + parse_dtor: + if (CScope_FindTypeName(nspace, tkidentifier, &pr) && !pr.nspace_0) { + if (!is_typesame(pr.type, expr->rtype)) + CError_Error(CErrorStr146); + tk = lex(); + goto parsed; + } + } + } + } + } else if (tk >= TK_AUTO && tk <= TK_BYREF) { + memclrw(&di, sizeof(DeclInfo)); + CParser_GetDeclSpecs(&di, 0); + if (di.storageclass || di.qual || !is_typesame(di.thetype, expr->rtype)) + CError_Error(CErrorStr146); + if (tk == TK_COLON_COLON && ((tk = lex()) == '~')) { + is_tilde: + if ((tk = lex()) == TK_IDENTIFIER) + goto parse_dtor; + memclrw(&di, sizeof(DeclInfo)); + CParser_GetDeclSpecs(&di, 0); + if (di.storageclass || !is_typesame(di.thetype, expr->rtype)) + CError_Error(CErrorStr146); + goto parsed; + } + } + + CError_Error(CErrorStr141); + return NULL; + +parsed: + if (tk == '(') { + if ((tk = lex()) != ')') + CError_Error(CErrorStr115); + else + tk = lex(); + } else { + CError_Error(CErrorStr114); + } + + expr = makemonadicnode(expr, ETYPCON); + expr->rtype = &stvoid; + return expr; +} + +static ENode *postfix_expression(Boolean flag) { + NameResult pr; + Conversion conv; + ENode *expr; + ENode *subexpr; + ENode *funcexpr; + ENodeList *args; + ENode *copy; + ENode *tmp; + StructMember *member; + + if (copts.cplusplus) { + switch (tk) { + case TK_VOID: + case TK_CHAR: + case TK_SHORT: + case TK_INT: + case TK_LONG: + case TK_FLOAT: + case TK_DOUBLE: + case TK_SIGNED: + case TK_UNSIGNED: + case TK_UNK_113: + case TK_UNK_114: + case TK_UNK_115: + case TK_UNK_116: + case TK_UNK_117: + case TK_UNK_118: + case TK_UNK_119: + case TK_UNK_11A: + case TK_UU_TYPEOF_UU: + case TK_BOOL: + case TK_WCHAR_T: + case TK_TYPENAME: + expr = CExpr_SimpleExplicitConversion(); + break; + default: + expr = primary_expression(flag); + break; + case TK_CONST_CAST: + expr = CRTTI_Parse_const_cast(); + break; + case TK_DYNAMIC_CAST: + expr = CRTTI_Parse_dynamic_cast(); + break; + case TK_REINTERPRET_CAST: + expr = CRTTI_Parse_reinterpret_cast(); + break; + case TK_STATIC_CAST: + expr = CRTTI_Parse_static_cast(); + break; + case TK_TYPEID: + expr = CRTTI_ParseTypeID(); + break; + } + } else { + expr = primary_expression(flag); + } + +loop: + switch (tk) { + case '[': + expr = pointer_generation(expr); + tk = lex(); + subexpr = expression(); + if (copts.cplusplus && CExpr_CheckOperator('[', expr, subexpr, &conv)) { + if ((expr = conv.x0)) { + if (tk != ']') + CError_ErrorSkip(CErrorStr125); + else + tk = lex(); + goto loop; + } + + CError_ASSERT(2753, expr = conv.left); + CError_ASSERT(2754, subexpr = conv.right); + } + + if (IS_TYPE_POINTER(expr->rtype)) { + expr = padd(expr, subexpr); + } else if (IS_TYPE_POINTER(subexpr->rtype)) { + expr = padd(subexpr, expr); + } else { + CError_Error(CErrorStr148); + goto dont_do_indirect; + } + expr = makemonadicnode(expr, EINDIRECT); + expr->rtype = TPTR_TARGET(expr->rtype); + dont_do_indirect: + if (tk != ']') + CError_ErrorSkip(CErrorStr125); + else + tk = lex(); + goto loop; + + case '(': + funcexpr = CExpr_PointerGeneration(expr); + if (copts.cplusplus) { + if (CExpr_CheckOperator('(', funcexpr, NULL, &conv)) { + CError_ASSERT(2775, expr = conv.x0); + goto loop; + } + if (ENODE_IS(funcexpr, EMFPOINTER)) { + expr = checkreference(call_ptmf(funcexpr)); + goto loop; + } + } + + tk = lex(); + args = CExpr_ScanExpressionList(1); + if (tk != ')') + CError_Error(CErrorStr115); + + if (ENODE_IS(funcexpr, ETEMPLDEP)) { + expr = CExpr_NewENode(EFUNCCALL); + expr->rtype = &sttemplexpr; + expr->data.funccall.funcref = funcexpr; + expr->data.funccall.args = args; + expr->data.funccall.functype = &rt_func; + tk = lex(); + } else { + expr = checkreference(CExpr_MakeFunctionCall(funcexpr, args)); + tk = lex(); + } + goto loop; + + case TK_ARROW: + expr = pointer_generation(expr); + if (copts.cplusplus) { + while (IS_TYPE_CLASS(expr->rtype) && CExpr_CheckOperator(TK_ARROW, expr, NULL, &conv)) { + CError_ASSERT(2810, subexpr = conv.x0); + expr = pointer_generation(subexpr); + } + } + + if (!IS_TYPE_POINTER(expr->rtype)) { + CError_ErrorSkip(CErrorStr148); + return expr; + } + + if (copts.cplusplus && copts.objective_c && CObjC_IsType_id(expr->rtype)) { + expr = makemonadicnode(expr, EINDIRECT); + expr->rtype = TPTR_TARGET(expr->rtype); + if ((subexpr = CObjC_CheckModernSendMessage(NULL, expr))) + return subexpr; + } else { + expr = makemonadicnode(expr, EINDIRECT); + expr->rtype = TPTR_TARGET(expr->rtype); + } + case '.': + expr = pointer_generation(expr); + if (IS_TYPE_CLASS(expr->rtype)) { + CDecl_CompleteType(expr->rtype); + if (TYPE_CLASS(expr->rtype)->objcinfo && copts.cplusplus && (subexpr = CObjC_CheckModernSendMessage(TYPE_CLASS(expr->rtype), expr))) + return subexpr; + + if (!(TYPE_CLASS(expr->rtype)->flags & CLASS_COMPLETED)) + CError_Error(CErrorStr136, expr->rtype, 0); + + if ((tk = lex()) == TK_TEMPLATE && (tk = lex()) != TK_IDENTIFIER) + CError_Error(CErrorStr107); + + if (CScope_ParseMemberName(TYPE_CLASS(expr->rtype), &pr, 0)) { + if (pr.x1C) { + if ((tk = lex()) == '(') { + if ((tk = lex()) != ')') + CError_Error(CErrorStr115); + else + tk = lex(); + } else { + CError_Error(CErrorStr114); + } + + expr = makemonadicnode(expr, ETYPCON); + expr->rtype = &stvoid; + } else { + expr = checkreference(CExpr_ParseNameResultExpr(&pr, expr, 0, 0)); + } + } + goto loop; + } + if (!IS_TYPE_STRUCT(expr->rtype) || TYPE_STRUCT(expr->rtype)->stype > STRUCT_TYPE_MAX) { + if (copts.cplusplus && (subexpr = CExpr_DummyDestr(expr))) + return subexpr; + CError_ErrorSkip(CErrorStr149); + return expr; + } + if (!ENODE_IS(expr, EINDIRECT)) { + subexpr = CExpr_NewETEMPNode(expr->rtype, 1); + copy = lalloc(sizeof(ENode)); + *copy = *subexpr; + + tmp = makemonadicnode(subexpr, EINDIRECT); + tmp->rtype = expr->rtype; + + tmp = makediadicnode(tmp, expr, EASS); + tmp = makediadicnode(tmp, copy, ECOMMA); + tmp->rtype = copy->rtype; + + tmp = makemonadicnode(tmp, EINDIRECT); + tmp->rtype = expr->rtype; + expr = tmp; + } + if ((tk = lex()) != TK_IDENTIFIER) { + CError_Error(CErrorStr107); + return expr; + } + + member = ismember(TYPE_STRUCT(expr->rtype), tkidentifier); + if (!member) { + if (!expr->rtype->size) + CError_Error(CErrorStr136, expr->rtype, 0); + else + CError_Error(CErrorStr150, tkidentifier->name); + return expr; + } + + if (!IS_TYPE_POINTER(expr->data.monadic->rtype)) { + CError_ErrorSkip(CErrorStr149); + return expr; + } + + expr = checkreference(CClass_AccessMember(expr, member->type, member->qual, member->offset)); + tk = lex(); + goto loop; + + case TK_INCREMENT: + tmp = pointer_generation(expr); + if (copts.cplusplus && CExpr_CheckOperator(TK_INCREMENT, tmp, nullnode(), &conv)) { + if ((expr = conv.x0)) { + tk = lex(); + goto loop; + } + CError_ASSERT(2952, tmp = conv.left); + } + tmp = CExpr_LValue(tmp, 1, 1); + if (tmp->rtype == TYPE(&stbool)) { + expr = CExpr_TempModifyExpr(tmp); + tk = lex(); + } else { + checkadditive(tmp); + expr = makemonadicnode(tmp, EPOSTINC); + tk = lex(); + } + goto loop; + + case TK_DECREMENT: + tmp = pointer_generation(expr); + if (copts.cplusplus && CExpr_CheckOperator(TK_DECREMENT, tmp, nullnode(), &conv)) { + if ((expr = conv.x0)) { + tk = lex(); + goto loop; + } + CError_ASSERT(2976, tmp = conv.left); + } + tmp = CExpr_LValue(tmp, 1, 1); + checkadditive(tmp); + expr = makemonadicnode(tmp, EPOSTDEC); + tk = lex(); + goto loop; + } + + return expr; +} + +static ENode *CExpr_ParseSizeof(void) { + Type *type; + ENode *expr; + + type = CExpr_ParseTypeExpression(NULL); + if (IS_TYPE_CLASS(type) && TYPE_CLASS(type)->sominfo) + CError_Error(CErrorStr286); + + if (CTemplTool_IsTemplateArgumentDependentType(type)) { + expr = CExpr_NewTemplDepENode(TDE_SIZEOF); + expr->data.templdep.u.typeexpr.type = type; + return expr; + } + + if (type->size == 0) { + if (copts.gcc_extensions && (IS_TYPE_FUNC(type) || IS_TYPE_VOID(type))) + return intconstnode(CABI_GetSizeTType(), 1); + + if (IS_TYPE_CLASS(type) || IS_TYPE_STRUCT(type)) + CError_Error(CErrorStr136, type, 0); + else + CError_Error(CErrorStr146); + } + + return intconstnode(CABI_GetSizeTType(), type->size); +} + +SInt32 scansizeof(void) { + ENode *expr; + + expr = CExpr_ParseSizeof(); + if (!ENODE_IS(expr, EINTCONST)) { + CError_Error(CErrorStr190); + return 0; + } + + return CInt64_GetULong(&expr->data.intval); +} + +static ENode *CExpr_ParseAlignof(void) { + Type *type; + ENode *expr; + SInt16 align; + + type = CExpr_ParseTypeExpression(NULL); + if (IS_TYPE_CLASS(type) && TYPE_CLASS(type)->sominfo) + CError_Error(CErrorStr364); + + if (CTemplTool_IsTemplateArgumentDependentType(type)) { + expr = CExpr_NewTemplDepENode(TDE_ALIGNOF); + expr->data.templdep.u.typeexpr.type = type; + return expr; + } + + if (type->size == 0) { + if (IS_TYPE_CLASS(type) || IS_TYPE_STRUCT(type)) + CError_Error(CErrorStr136, type, 0); + else + CError_Error(CErrorStr146); + } + + align = CMach_GetTypeAlign(type); + if (align == 0) + align = 1; + + return intconstnode(CABI_GetSizeTType(), align); +} + +SInt32 scanalignof(void) { + ENode *expr; + + expr = CExpr_ParseAlignof(); + if (!ENODE_IS(expr, EINTCONST)) { + CError_Error(CErrorStr190); + return 0; + } + + return CInt64_GetULong(&expr->data.intval); +} + +static ENode *logicalexpression(ENode *expr) { + if (copts.cplusplus && copts.booltruefalse) + expr->rtype = TYPE(&stbool); + else + expr->rtype = TYPE(&stsignedint); + return expr; +} + +ENode *getnodeaddress(ENode *expr, Boolean flag) { + ENode *result; + Object *obj; + + if (!ENODE_IS(expr, EINDIRECT)) { + expr = CExpr_LValue(expr, flag, flag); + if (!ENODE_IS(expr, EINDIRECT)) { + if (!flag) + CError_Error(CErrorStr142); + return nullnode(); + } + } else { + if (flag && + ENODE_IS(expr->data.monadic, EOBJREF) && + expr->data.monadic->data.objref->name == this_name_node && + cscope_currentfunc && + cscope_currentclass && + expr->data.monadic->data.objref == CClass_ThisSelfObject()) + CError_Error(CErrorStr189); + } + + result = lalloc(sizeof(ENode)); + *result = *expr; +restart: + switch (result->data.monadic->type) { + case EPOSTINC: + case EPOSTDEC: + case EPREINC: + case EPREDEC: + result->type = ETYPCON; + if (IS_TYPE_POINTER_ONLY(result->rtype)) + result->flags = TPTR_QUAL(result->rtype) & ENODE_FLAG_QUALS; + result->rtype = CDecl_NewPointerType(result->rtype); + return result; + case EOBJREF: + obj = result->data.monadic->data.objref; + if (obj->datatype == DALIAS) { + CExpr_AliasTransform(result->data.monadic); + goto restart; + } + if (obj->datatype == DINLINEFUNC) + CError_Error(CErrorStr175); + obj->flags = obj->flags | OBJECT_FLAGS_2; + if (flag && !copts.cplusplus && obj->sclass == TK_REGISTER) + CError_Error(CErrorStr163); + break; + case EFUNCCALL: + if (flag && !IS_TYPE_POINTER_ONLY(result->data.monadic->data.funccall.functype->functype)) + CError_Warning(CErrorStr142); + break; + case EBITFIELD: + CError_Error(CErrorStr144); + return nullnode(); + } + + switch (result->rtype->type) { + case TYPEPOINTER: + result->data.monadic->rtype = CDecl_NewPointerType(result->rtype); + result->data.monadic->flags = result->flags; + break; + default: + result->data.monadic->rtype = CDecl_NewPointerType(result->rtype); + result->data.monadic->flags = result->flags; + } + + return result->data.monadic; +} + +static ENode *CExpr_MakeStaticMemberList(NameSpaceObjectList *list) { + NameSpaceObjectList *newlist; + NameSpaceObjectList *n; + ENode *result; + + newlist = NULL; + while (list) { + if (list->object->otype == OT_OBJECT && IS_TYPE_STATIC_METHOD(OBJECT(list->object)->type)) { + n = galloc(sizeof(NameSpaceObjectList)); + *n = *list; + n->next = newlist; + newlist = n; + } + list = list->next; + } + + if (!newlist) { + CError_Warning(CErrorStr331); + return nullnode(); + } + + result = CExpr_NewENode(EOBJLIST); + result->rtype = OBJECT(newlist->object)->type; + result->data.objlist.list = newlist; + return result; +} + +static ENode *CExpr_MakePTDM(ENode *expr) { + ENode *result; + + CError_ASSERT(3414, ENODE_IS(expr, EMEMBER) && expr->data.emember->list->object->otype == OT_MEMBERVAR); + + result = nullnode(); + result->rtype = CExpr_NewPTMType(expr->data.emember, NULL); + CInt64_SetLong(&result->data.intval, OBJ_MEMBER_VAR(expr->data.emember->list->object)->offset + 1); + return result; +} + +ENode *getpointertomemberfunc(ENode *expr, Type *type, Boolean flag) { + NameSpaceObjectList *list; + Object *obj; + Object *dataobj; + Type *ptmtype; + TypeMemberFunc *tmethod; + OLinkList *olist; + SInt32 data[3]; + + CError_ASSERT(3442, ENODE_IS(expr, EMEMBER)); + + if (expr->data.emember->expr && !copts.cpp_extensions) + CError_Error(CErrorStr141); + + if (!copts.cpp_extensions) { + if (!(expr->data.emember->x11 && expr->data.emember->pr_1D)) { + if (type && IS_TYPE_MEMBERPOINTER(type)) + CError_Warning(CErrorStr331); + } + } + + if (expr->data.emember->list->next) { + if (type) { + if (IS_TYPE_MEMBERPOINTER(type)) { + type = TYPE_MEMBER_POINTER(type)->ty1; + for (list = expr->data.emember->list; list; list = list->next) { + if (list->object->otype == OT_OBJECT && is_memberpointerequal(OBJECT(list->object)->type, type)) { + obj = OBJECT(list->object); + break; + } + } + if (!list) { + CError_Error(CErrorStr146); + return nullnode(); + } + } else { + return CExpr_MakeStaticMemberList(expr->data.emember->list); + } + } else { + obj = OBJECT(expr->data.emember->list->object); + } + } else { + obj = OBJECT(expr->data.emember->list->object); + } + + while (obj->datatype == DALIAS) + obj = obj->u.alias.object; + + CError_ASSERT(3503, obj->otype == OT_OBJECT && IS_TYPE_NONSTATIC_METHOD(obj->type)); + + if (TYPE_FUNC(obj->type)->flags & FUNC_IS_TEMPL) + CError_Error(CErrorStr190); + + ptmtype = CExpr_NewPTMType(expr->data.emember, obj); + tmethod = TYPE_METHOD(obj->type); + dataobj = CParser_NewGlobalDataObject(NULL); + dataobj->name = CParser_GetUniqueName(); + dataobj->nspace = cscope_root; + dataobj->type = ptmtype; + dataobj->sclass = TK_STATIC; + + if (flag) { + data[0] = 0; + if (obj->datatype == DVFUNC) { + olist = NULL; + data[1] = tmethod->vtbl_index; + data[2] = tmethod->theclass->vtable->offset; + } else { + data[1] = -1; + data[2] = 0; + olist = galloc(sizeof(OLinkList)); + olist->next = NULL; + olist->obj = obj; + olist->somevalue = 0; + olist->offset = 8; + } + CInit_DeclareData(dataobj, data, olist, dataobj->type->size); + } + + return create_objectnode(dataobj); +} + +static ENode *getpointertomember(ENode *expr) { + CError_ASSERT(3554, ENODE_IS(expr, EMEMBER)); + + if (expr->data.emember->expr) + CError_Error(CErrorStr141); + + expr->data.emember->x11 = 1; + if (!expr->data.emember->list->next) { + if (expr->data.emember->list->object->otype == OT_MEMBERVAR) + return CExpr_MakePTDM(expr); + else + return getpointertomemberfunc(expr, NULL, 1); + } + + return expr; +} + +ENode *CExpr_New_ELOGNOT_Node(ENode *input) { + ENode *expr; + Conversion conv; + + if (IS_TYPE_TEMPLDEPEXPR(input->rtype)) + return CTempl_MakeTemplDepExpr(NULL, ELOGNOT, input); + + expr = pointer_generation(input); + if (copts.cplusplus && CExpr_CheckOperator('!', expr, NULL, &conv)) { + if ((input = conv.x0)) + return input; + CError_ASSERT(3593, expr = conv.left); + } + + switch (expr->rtype->type) { + case TYPEINT: + case TYPEFLOAT: + case TYPEPOINTER: + case TYPEARRAY: + break; + case TYPEENUM: + expr = forceintegral(expr); + break; + case TYPEMEMBERPOINTER: + expr = CExpr_ConvertToCondition(expr); + break; + default: + CError_Error(CErrorStr144); + return expr; + } + + switch (expr->type) { + case EINTCONST: + expr->data.intval = CInt64_Not(expr->data.intval); + break; + case EFLOATCONST: + expr->type = EINTCONST; + CInt64_SetLong(&expr->data.intval, CMach_FloatIsZero(expr->data.floatval)); + break; + default: + expr = makemonadicnode(expr, ELOGNOT); + } + + return logicalexpression(expr); +} + +ENode *CExpr_New_EMONMIN_Node(ENode *input) { + ENode *expr; + Conversion conv; + + if (IS_TYPE_TEMPLDEPEXPR(input->rtype)) + return CTempl_MakeTemplDepExpr(NULL, EMONMIN, input); + + expr = pointer_generation(input); + if (copts.cplusplus && CExpr_CheckOperator('-', expr, NULL, &conv)) { + if ((input = conv.x0)) + return input; + CError_ASSERT(3652, expr = conv.left); + } + + switch (expr->rtype->type) { + case TYPEINT: + case TYPEENUM: + expr = integralpromote(expr); + if (ENODE_IS(expr, EINTCONST)) { + expr->data.intval = CMach_CalcIntMonadic(expr->rtype, '-', expr->data.intval); + return expr; + } + return makemonadicnode(expr, EMONMIN); + case TYPEFLOAT: + if (ENODE_IS(expr, EFLOATCONST)) { + expr->data.floatval = CMach_CalcFloatMonadic(expr->rtype, '-', expr->data.floatval); + return expr; + } + return CExpr_UnaryFloatExpression(makemonadicnode(expr, EMONMIN)); + default: + CError_Error(CErrorStr144); + return expr; + } +} + +ENode *CExpr_New_EBINNOT_Node(ENode *input) { + ENode *expr; + Conversion conv; + + if (IS_TYPE_TEMPLDEPEXPR(input->rtype)) + return CTempl_MakeTemplDepExpr(NULL, EBINNOT, input); + + expr = pointer_generation(input); + if (copts.cplusplus && CExpr_CheckOperator('~', expr, NULL, &conv)) { + if ((input = conv.x0)) + return input; + CError_ASSERT(3702, expr = conv.left); + } + + expr = integralpromote(expr); + + if (ENODE_IS(expr, EINTCONST)) { + expr->data.intval = CMach_CalcIntMonadic(expr->rtype, '~', expr->data.intval); + return expr; + } + return makemonadicnode(expr, EBINNOT); +} + +ENode *unary_expression(void) { + ENode *expr; + ENode *tmp; + Conversion conv; + + switch (tk) { + case TK_COLON_COLON: + switch (lookahead()) { + case TK_NEW: + tk = lex(); + return scannew(1); + case TK_DELETE: + tk = lex(); + return scandelete(1); + } + return postfix_expression(0); + + case TK_NEW: + return scannew(0); + case TK_DELETE: + return scandelete(0); + case TK_INCREMENT: + tk = lex(); + if (copts.cplusplus) { + expr = pointer_generation(cast_expression()); + if (CExpr_CheckOperator(TK_INCREMENT, expr, NULL, &conv)) { + if (conv.x0) + return conv.x0; + CError_ASSERT(3748, expr = conv.left); + } + } else { + expr = pointer_generation(unary_expression()); + } + expr = CExpr_LValue(expr, 1, 1); + if (expr->rtype == TYPE(&stbool)) { + tmp = nullnode(); + tmp->rtype = TYPE(&stbool); + CInt64_SetLong(&tmp->data.intval, 1); + return makediadicnode(expr, tmp, EASS); + } else { + checkadditive(expr); + return makemonadicnode(expr, EPREINC); + } + case TK_DECREMENT: + tk = lex(); + if (copts.cplusplus) { + expr = pointer_generation(cast_expression()); + if (CExpr_CheckOperator(TK_DECREMENT, expr, NULL, &conv)) { + if (conv.x0) + return conv.x0; + CError_ASSERT(3776, expr = conv.left); + } + } else { + expr = pointer_generation(unary_expression()); + } + expr = CExpr_LValue(expr, 1, 1); + checkadditive(expr); + return makemonadicnode(expr, EPREDEC); + + case '&': + if (copts.cplusplus) { + switch ((tk = lex())) { + case TK_IDENTIFIER: + case TK_INHERITED: + case TK_COLON_COLON: + expr = postfix_expression(1); + if (ENODE_IS(expr, EMEMBER)) + return getpointertomember(expr); + break; + default: + expr = cast_expression(); + } + + if (CExpr_CheckOperator('&', expr, NULL, &conv)) { + CError_ASSERT(3809, conv.x0); + return conv.x0; + } + } else { + tk = lex(); + expr = cast_expression(); + } + + if (copts.mpwc_relax && !copts.cplusplus && IS_TYPE_ARRAY(expr->rtype) && ENODE_IS(expr, EINDIRECT)) + return pointer_generation(expr); + if (ENODE_IS(expr, EOBJLIST)) + return expr; + + if (IS_TYPE_TEMPLDEPEXPR(expr->rtype)) { + tmp = CExpr_NewTemplDepENode(TDE_ADDRESS_OF); + tmp->data.templdep.u.monadic = expr; + return tmp; + } + + return getnodeaddress(expr, 1); + + case '*': + tk = lex(); + expr = pointer_generation(cast_expression()); + if (copts.cplusplus && CExpr_CheckOperator('*', expr, NULL, &conv)) { + if (conv.x0) + return conv.x0; + CError_ASSERT(3840, expr = conv.left); + } + + if (!IS_TYPE_POINTER(expr->rtype)) { + CError_Error(CErrorStr148); + return expr; + } + + tmp = makemonadicnode(expr, EINDIRECT); + CDecl_CompleteType(tmp->rtype = TPTR_TARGET(tmp->rtype)); + return tmp; + + case '+': + tk = lex(); + expr = pointer_generation(cast_expression()); + if (copts.cplusplus && CExpr_CheckOperator('+', expr, NULL, &conv)) { + if (conv.x0) + return conv.x0; + CError_ASSERT(3852, expr = conv.left); + } + + switch (expr->rtype->type) { + case TYPEINT: + case TYPEENUM: + return integralpromote(expr); + case TYPEFLOAT: + case TYPEPOINTER: + case TYPEARRAY: + return expr; + default: + CError_Error(CErrorStr144); + return expr; + } + + case '-': + tk = lex(); + return CExpr_New_EMONMIN_Node(cast_expression()); + case '~': + tk = lex(); + return CExpr_New_EBINNOT_Node(cast_expression()); + case '!': + tk = lex(); + return CExpr_New_ELOGNOT_Node(cast_expression()); + + case TK_SIZEOF: + return CExpr_ParseSizeof(); + case TK_UU_ALIGNOF_UU: + return CExpr_ParseAlignof(); + + case TK_LOGICAL_AND: + if (copts.ANSIstrict) + break; + + if ((tk = lex()) != TK_IDENTIFIER) { + CError_Error(CErrorStr107); + return nullnode(); + } + + expr = lalloc(sizeof(ENode)); + expr->type = ELABEL; + expr->cost = 0; + expr->flags = 0; + expr->rtype = TYPE(&void_ptr); + expr->data.label = findlabel(); + if (!expr->data.label) { + expr->data.label = newlabel(); + expr->data.label->name = tkidentifier; + expr->data.label->next = Labels; + Labels = expr->data.label; + } + tk = lex(); + return expr; + } + + return postfix_expression(0); +} + +ENode *do_castnullcheck(ENode *condexpr, ENode *nullcheckexpr) { + ENode *result; + + if (isnotzero(nullcheckexpr)) + return condexpr; + + result = lalloc(sizeof(ENode)); + *result = *condexpr; + result->type = ENULLCHECK; + result->data.nullcheck.nullcheckexpr = lalloc(sizeof(ENode)); + *result->data.nullcheck.nullcheckexpr = *nullcheckexpr; + result->data.nullcheck.condexpr = condexpr; + result->data.nullcheck.precompid = CParser_GetUniqueID(); + + nullcheckexpr->type = EPRECOMP; + nullcheckexpr->data.precompid = result->data.nullcheck.precompid; + + return result; +} + +ENode *CExpr_SafeClassPointerCast(ENode *expr, TypeClass *a, TypeClass *b, Boolean typconflag, Boolean pathcheckflag) { + ENode *result; + + result = CClass_ClassPointerCast(expr, a, b, typconflag, 1, pathcheckflag); + if (result != expr) { + if (!(ENODE_IS(result, ETYPCON) && result->data.monadic == expr)) + result = do_castnullcheck(result, expr); + } + return result; +} + +ENode *PointerToMemberCast(ENode *expr, TypeMemberPointer *tm1, TypeMemberPointer *tm2, Boolean flag) { + BClassList *path; + Boolean negate; + short depth; + Boolean isambig; + SInt32 pathoffset; + CInt64 pathoffset64; + ENode *tmp; + + CError_ASSERT(3984, IS_TYPE_CLASS(tm1->ty2)); + CError_ASSERT(3985, IS_TYPE_CLASS(tm2->ty2)); + + if (tm1->ty2 == tm2->ty2) { + expr->rtype = TYPE(tm2); + return expr; + } + + negate = 0; + path = CClass_GetBasePath(TYPE_CLASS(tm2->ty2), TYPE_CLASS(tm1->ty2), &depth, &isambig); + if (!path) { + path = CClass_GetBasePath(TYPE_CLASS(tm1->ty2), TYPE_CLASS(tm2->ty2), &depth, &isambig); + if (!path) + goto failed; + negate = 1; + } + + if (isambig) + CError_Error(CErrorStr188); + + if ((pathoffset = CClass_GetPathOffset(path)) < 0) + goto failed; + if (negate) + pathoffset = -pathoffset; + + if (flag) + CClass_CheckPathAccess(path, NULL, ACCESSPUBLIC); + + if (tm1->size != tm2->size) { + failed: + CError_Error(CErrorStr247, tm1, 0, tm2, 0); + return nullnode(); + } + + if (!pathoffset) { + expr->rtype = TYPE(tm2); + return expr; + } + + if (tm1->size == 4u) { + if (ENODE_IS(expr, EINTCONST)) { + if (!CInt64_IsZero(&expr->data.intval)) { + CInt64_SetLong(&pathoffset64, pathoffset); + expr->data.intval = CInt64_Add(expr->data.intval, pathoffset64); + } + expr->rtype = TYPE(tm2); + return expr; + } else { + expr->rtype = TYPE(&stunsignedlong); + tmp = intconstnode(TYPE(&stunsignedlong), pathoffset); + tmp = makediadicnode(expr, tmp, EADD); + tmp = makemonadicnode(tmp, ETYPCON); + tmp->rtype = TYPE(tm2); + return do_castnullcheck(tmp, expr); + } + } else { + tmp = create_temp_node(TYPE(&ptmstruct)); + expr = getnodeaddress(expr, 0); + tmp = funccallexpr(rt_ptmf_cast, intconstnode(TYPE(&stsignedlong), pathoffset), expr, tmp, NULL); + tmp = makemonadicnode(tmp, EINDIRECT); + tmp->rtype = TYPE(tm2); + return tmp; + } +} + +ENode *CExpr_MemberPointerConversion(ENode *expr, TypeMemberPointer *type, Boolean flag1) { + if (ENODE_IS(expr, EINTCONST) && CInt64_IsZero(&expr->data.intval)) { + if (IS_TYPE_FUNC(type->ty1)) + expr = create_objectnode(rt_ptmf_null); + expr->rtype = TYPE(type); + } else if (ENODE_IS(expr, EMEMBER)) { + expr = getpointertomemberfunc(expr, TYPE(type), flag1); + } + + return expr; +} + +static ENode *CExpr_MemberPointerCast(ENode *expr, TypeMemberPointer *type, UInt32 qual) { + if (!IS_TYPE_MEMBERPOINTER(expr->rtype)) + expr = CExpr_MemberPointerConversion(expr, type, 1); + + if (!IS_TYPE_MEMBERPOINTER(expr->rtype)) { + CError_Error(CErrorStr164); + return nullnode(); + } + + expr = PointerToMemberCast(expr, TYPE_MEMBER_POINTER(expr->rtype), type, 0); + expr->flags = qual & ENODE_FLAG_QUALS; + return expr; +} + +ENode *do_typecast(ENode *expr, Type *type, UInt32 qual) { + TypePointer *tptr; + ENode *tmp; + short flags; + + if (!copts.old_argmatch) + return CExpr_Convert(expr, type, qual, 1, 0); + + if (copts.cpp_extensions && is_typesame(expr->rtype, type) && !ENODE_IS(expr, EOBJLIST)) { + expr->rtype = type; + expr->flags &= ~ENODE_FLAG_QUALS; + expr->flags |= qual & ENODE_FLAG_QUALS; + return expr; + } + + switch (type->type) { + case TYPEARRAY: + CError_Error(CErrorStr247, expr->rtype, ENODE_QUALS(expr), type, qual); + return expr; + case TYPEMEMBERPOINTER: + if (!IS_TYPE_CLASS(expr->rtype)) + return CExpr_MemberPointerCast(expr, TYPE_MEMBER_POINTER(type), qual); + } + + flags = qual & ENODE_FLAG_QUALS; + + if (ENODE_IS(expr, EOBJLIST)) + return CExpr_AssignmentPromotion(expr, type, qual & ENODE_FLAG_QUALS, 1); + + if (ENODE_IS(expr, EOBJREF) && IS_TYPE_NONSTATIC_METHOD(expr->data.objref->type)) { + CError_Error(CErrorStr221); + return nullnode(); + } + + if (type == &stvoid) { + expr = makemonadicnode(expr, ETYPCON); + expr->rtype = type; + expr->flags = flags; + return expr; + } + + if (IS_TYPE_REFERENCE(type)) { + tmp = getnodeaddress(expr, 0); + tptr = galloc(sizeof(TypePointer)); + *tptr = *TYPE_POINTER(type); + tptr->qual &= ~Q_REFERENCE; + + tmp = do_typecast(tmp, TYPE(tptr), qual); + tmp = makemonadicnode(tmp, EINDIRECT); + tmp->rtype = TPTR_TARGET(type); + tmp->flags = flags; + return tmp; + } + + if (IS_TYPE_CLASS(expr->rtype) || IS_TYPE_CLASS(type)) { + if (expr->rtype->size == 0) + CDecl_CompleteType(expr->rtype); + + if (expr->rtype == type && !CClass_CopyConstructor(TYPE_CLASS(type))) + return expr; + + if (user_assign_check(expr, type, qual, 1, 1, 1)) { + assign_node->flags = flags; + return assign_node; + } + + CError_Error(CErrorStr247, expr->rtype, ENODE_QUALS(expr), type, qual); + return nullnode(); + } + + if (IS_TYPE_STRUCT(type) && copts.cplusplus && is_typesame(expr->rtype, type)) { + expr->rtype = type; + expr->flags = flags; + return expr; + } + + if (type == TYPE(&stbool)) { + expr = CExpr_ConvertToBool(expr, 1); + expr->flags = flags; + return expr; + } + + if (IS_TYPE_ENUM(type)) { + tmp = do_typecast(expr, TYPE_ENUM(type)->enumtype, qual); + if (!ENODE_IS(tmp, EINTCONST)) + tmp = makemonadicnode(tmp, ETYPCON); + tmp->rtype = type; + tmp->flags = flags; + return tmp; + } + + if (IS_TYPE_INT_OR_FLOAT(type)) { + if (ENODE_IS(expr, ETYPCON) && expr->rtype->type == type->type && expr->rtype->size == type->size) { + if (is_unsigned(expr->rtype) == is_unsigned(type) && ENODE_QUALS(expr) == qual) { + expr->rtype = type; + expr->flags = expr->flags | ENODE_FLAG_80; + return expr; + } + } + + if (IS_TYPE_ENUM(expr->rtype)) + expr = forceintegral(expr); + + if (IS_TYPE_INT_OR_FLOAT(expr->rtype)) { + expr = promote(expr, type); + expr->flags = flags; + return expr; + } + + if (!(IS_TYPE_POINTER_ONLY(expr->rtype) && !IS_TYPE_FLOAT(type))) + CError_Error(CErrorStr247, expr->rtype, ENODE_QUALS(expr), type, qual); + + if (ENODE_IS(expr, ETYPCON) && ENODE_IS(tmp = expr->data.monadic, EINTCONST)) { + tmp->rtype = type; + tmp->flags = flags; + tmp->data.intval = CExpr_IntConstConvert(type, TYPE(&stunsignedlong), tmp->data.intval); + return tmp; + } + + if (type->size != 4) { + expr = makemonadicnode(expr, ETYPCON); + expr->rtype = TYPE(&stunsignedlong); + } + + expr = makemonadicnode(expr, ETYPCON); + expr->rtype = type; + expr->flags = flags; + return expr; + } + + if (IS_TYPE_POINTER(type)) { + if (IS_TYPE_POINTER(expr->rtype)) { + if (IS_TYPE_CLASS(TPTR_TARGET(expr->rtype)) && IS_TYPE_CLASS(TPTR_TARGET(type))) + expr = CExpr_SafeClassPointerCast(expr, TYPE_CLASS(TPTR_TARGET(expr->rtype)), TYPE_CLASS(TPTR_TARGET(type)), 1, 0); + + if (!ENODE_IS(expr, ETYPCON)) + expr = makemonadicnode(expr, ETYPCON); + + expr->rtype = type; + expr->flags = flags; + return expr; + } + + if (!IS_TYPE_INT(expr->rtype)) { + if (!IS_TYPE_ENUM(expr->rtype)) { + CError_Error(CErrorStr247, expr->rtype, ENODE_QUALS(expr), type, qual); + return expr; + } + expr = forceintegral(expr); + } + + if (expr->rtype->size != 4) { + if (!ENODE_IS(expr, EINTCONST)) + expr = makemonadicnode(expr, ETYPCON); + expr->rtype = TYPE(&stunsignedlong); + } + + expr = makemonadicnode(expr, ETYPCON); + expr->rtype = type; + expr->flags = flags; + return expr; + } + + if ((tmp = CodeGen_HandleTypeCast(expr, type, qual))) + return tmp; + + CError_Error(CErrorStr247, expr->rtype, ENODE_QUALS(expr), type, qual); + return nullnode(); +} + +static Boolean isvectorconst(ENode *node) { + if (ENODE_IS3(node, ECOMMA, EINTCONST, EFLOATCONST)) + return 1; + else + return 0; +} + +ENode *cast_expression(void) { + ENode *expr; + ENode *tmp; + ENodeList *args; + MWVector128 vec; + DeclInfo di; + + if (!(tk == '(' && islookaheaddeclaration())) + return unary_expression(); + tk = lex(); + + memclrw(&di, sizeof(DeclInfo)); + CParser_GetDeclSpecs(&di, 0); + scandeclarator(&di); + + if (tk != ')') + CError_ErrorSkip(CErrorStr115); + else + tk = lex(); + + if (di.name) + CError_Error(CErrorStr164); + + if (copts.altivec_model && tk == '(' && IS_TYPE_VECTOR(di.thetype)) { + tk = lex(); + expr = s_expression(); + if (tk != ')') + CError_ErrorSkip(CErrorStr115); + else + tk = lex(); + + if (CodeGen_CollapseVectorExpression(expr, &vec, di.thetype)) { + tmp = lalloc(sizeof(ENode)); + tmp->type = EVECTOR128CONST; + if ((tmp->cost = expr->cost) == 0) + tmp->cost = 1; + tmp->flags = ENODE_QUALS(expr); + tmp->rtype = di.thetype; + tmp->data.vector128val = vec; + } else { + tmp = makemonadicnode(expr, ETYPCON); + } + tmp->rtype = di.thetype; + tmp->flags = expr->flags; + return tmp; + } + + if (tk == '{' && (!copts.ANSIstrict || copts.c9x) && !IS_TYPE_VECTOR(di.thetype)) + return CInit_AutoObject(NULL, di.thetype, di.qual); + + expr = cast_expression(); + if (copts.cplusplus && (CTemplTool_IsTemplateArgumentDependentType(di.thetype) || + CTemplTool_IsTemplateArgumentDependentExpression(expr))) { + args = lalloc(sizeof(ENodeList)); + args->next = NULL; + args->node = expr; + return CExpr_TemplArgDepCast(di.thetype, di.qual, args); + } + + if (!IS_TYPE_REFERENCE(di.thetype)) + expr = pointer_generation(expr); + return do_typecast(expr, di.thetype, di.qual); +} + +static ENode *pm_expression(void) { + ENode *left; + ENode *right; + ENode *tmp; + Type *type; + UInt32 qual; + short flags; + Conversion conv; + + left = cast_expression(); +restart: + switch (tk) { + case TK_ARROW_STAR: + left = pointer_generation(left); + tk = lex(); + right = pointer_generation(cast_expression()); + + if (CExpr_CheckOperator(TK_ARROW_STAR, left, right, &conv)) { + CError_ASSERT(4457, left = conv.x0); + goto restart; + } + + if (!IS_TYPE_POINTER(left->rtype)) { + CError_Error(CErrorStr148); + return left; + } + + left = makemonadicnode(left, EINDIRECT); + left->rtype = TPTR_TARGET(left->rtype); + goto common_part; + case TK_DOT_STAR: + left = pointer_generation(left); + tk = lex(); + right = pointer_generation(cast_expression()); + if (!ENODE_IS(left, EINDIRECT)) { + CError_Error(CErrorStr142); + return left; + } + common_part: + if (!IS_TYPE_CLASS(left->rtype)) { + CError_Error(CErrorStr149); + return left; + } + if (!IS_TYPE_MEMBERPOINTER(right->rtype)) { + CError_Error(CErrorStr144); + return left; + } + if (left->rtype != TYPE_MEMBER_POINTER(right->rtype)->ty2) { + if (CClass_IsBaseClass(TYPE_CLASS(left->rtype), TYPE_CLASS(TYPE_MEMBER_POINTER(right->rtype)->ty2), NULL, 1, 1)) { + left->data.monadic = CClass_ClassPointerCast( + left->data.monadic, + TYPE_CLASS(left->rtype), + TYPE_CLASS(TYPE_MEMBER_POINTER(right->rtype)->ty2), + 0, 1, 1); + left->rtype = TYPE_MEMBER_POINTER(right->rtype)->ty2; + } else { + CError_Error(CErrorStr146); + return left; + } + } + type = CClass_CombineClassAccessQualifiers( + TYPE_MEMBER_POINTER(right->rtype)->ty1, + ENODE_QUALS(right), + left->flags, + &qual); + flags = qual; + if (!IS_TYPE_FUNC(type)) { + if (!ENODE_IS(right, EINTCONST)) { + if (!canadd(left->data.monadic, -1)) { + left->data.monadic = makediadicnode(left->data.monadic, nullnode(), EADD); + CInt64_SetLong(&left->data.monadic->data.diadic.right->data.intval, -1); + optimizecomm(left->data.monadic); + } + right->rtype = TYPE(&stunsignedlong); + left->data.monadic = makediadicnode(left->data.monadic, right, EADD); + optimizecomm(left->data.monadic); + } else { + right->data.intval = CInt64_Sub(right->data.intval, cint64_one); + if (!canadd2(left->data.monadic, right->data.intval)) { + right->rtype = TYPE(&stunsignedlong); + left->data.monadic = makediadicnode(left->data.monadic, right, EADD); + optimizecomm(left->data.monadic); + } + } + + if (IS_TYPE_BITFIELD(type)) { + left->data.monadic = makemonadicnode(left->data.monadic, EBITFIELD); + left->data.monadic->rtype = type; + left->rtype = TYPE_BITFIELD(type)->bitfieldtype; + } else { + left->rtype = type; + } + left->flags = flags; + left = checkreference(left); + goto restart; + } else { + CError_ASSERT(4535, ENODE_IS(right, EINDIRECT)); + tmp = lalloc(sizeof(ENode)); + tmp->type = EMFPOINTER; + tmp->cost = 4; + tmp->flags = 0; + tmp->rtype = &stvoid; + tmp->data.mfpointer.accessnode = left; + tmp->data.mfpointer.mfpointer = right; + return tmp; + } + default: + return left; + } +} + +ENode *CExpr_New_EMUL_Node(ENode *left, ENode *right) { + Conversion conv; + + if (IS_TYPE_TEMPLDEPEXPR(left->rtype) || IS_TYPE_TEMPLDEPEXPR(right->rtype)) + return CTempl_MakeTemplDepExpr(left, EMUL, right); + + left = pointer_generation(left); + right = pointer_generation(right); + if (copts.cplusplus && CExpr_CheckOperator('*', left, right, &conv)) { + if (conv.x0) + return conv.x0; + CError_ASSERT(4566, left = conv.left); + CError_ASSERT(4567, right = conv.right); + } + + return makemultnode(left, right); +} + +ENode *CExpr_New_EDIV_Node(ENode *left, ENode *right, Boolean no_warning) { + Conversion conv; + + if (IS_TYPE_TEMPLDEPEXPR(left->rtype) || IS_TYPE_TEMPLDEPEXPR(right->rtype)) + return CTempl_MakeTemplDepExpr(left, EDIV, right); + + left = pointer_generation(left); + right = pointer_generation(right); + if (copts.cplusplus && CExpr_CheckOperator('/', left, right, &conv)) { + if (conv.x0) + return conv.x0; + CError_ASSERT(4592, left = conv.left); + CError_ASSERT(4593, right = conv.right); + } + + return makedivnode(left, right, no_warning); +} + +ENode *CExpr_New_EMODULO_Node(ENode *left, ENode *right, Boolean no_warning) { + Conversion conv; + + if (IS_TYPE_TEMPLDEPEXPR(left->rtype) || IS_TYPE_TEMPLDEPEXPR(right->rtype)) + return CTempl_MakeTemplDepExpr(left, EMODULO, right); + + left = pointer_generation(left); + right = pointer_generation(right); + if (copts.cplusplus && CExpr_CheckOperator('%', left, right, &conv)) { + if (conv.x0) + return conv.x0; + CError_ASSERT(4618, left = conv.left); + CError_ASSERT(4619, right = conv.right); + } + + left = integralpromote(left); + right = integralpromote(right); + CExpr_ArithmeticConversion(&left, &right); + + if (iszero(right)) { + if (!no_warning) + CError_Warning(CErrorStr139); + return left; + } + + if (ENODE_IS(left, EINTCONST) && ENODE_IS(right, EINTCONST)) { + left->data.intval = CMach_CalcIntDiadic(left->rtype, left->data.intval, '%', right->data.intval); + return left; + } + + if (iszero(left)) + return makediadicnode(right, left, ECOMMA); + + if (CExpr_IsOne(right)) { + right = nullnode(); + right->rtype = left->rtype; + return makediadicnode(left, right, ECOMMA); + } + + return makediadicnode(left, right, EMODULO); +} + +ENode *CExpr_New_EADD_Node(ENode *left, ENode *right) { + Conversion conv; + + if (IS_TYPE_TEMPLDEPEXPR(left->rtype) || IS_TYPE_TEMPLDEPEXPR(right->rtype)) + return CTempl_MakeTemplDepExpr(left, EADD, right); + + left = pointer_generation(left); + right = pointer_generation(right); + if (copts.cplusplus && CExpr_CheckOperator('+', left, right, &conv)) { + if (conv.x0) + return conv.x0; + CError_ASSERT(4665, left = conv.left); + CError_ASSERT(4666, right = conv.right); + } + + return makeaddnode(left, right); +} + +ENode *CExpr_New_ESUB_Node(ENode *left, ENode *right) { + Conversion conv; + + if (IS_TYPE_TEMPLDEPEXPR(left->rtype) || IS_TYPE_TEMPLDEPEXPR(right->rtype)) + return CTempl_MakeTemplDepExpr(left, ESUB, right); + + left = pointer_generation(left); + right = pointer_generation(right); + if (copts.cplusplus && CExpr_CheckOperator('-', left, right, &conv)) { + if (conv.x0) + return conv.x0; + CError_ASSERT(4690, left = conv.left); + CError_ASSERT(4691, right = conv.right); + } + + return makesubnode(left, right); +} + +ENode *CExpr_New_ESHL_Node(ENode *left, ENode *right) { + Conversion conv; + + if (IS_TYPE_TEMPLDEPEXPR(left->rtype) || IS_TYPE_TEMPLDEPEXPR(right->rtype)) + return CTempl_MakeTemplDepExpr(left, ESHL, right); + + left = pointer_generation(left); + right = pointer_generation(right); + if (copts.cplusplus && CExpr_CheckOperator(TK_SHL, left, right, &conv)) { + if (conv.x0) + return conv.x0; + CError_ASSERT(4715, left = conv.left); + CError_ASSERT(4716, right = conv.right); + } + + left = integralpromote(left); + right = integralpromote(right); + + if (iszero(left) || iszero(right)) { + return left; + } + + if (ENODE_IS(left, EINTCONST) && ENODE_IS(right, EINTCONST)) { + left->data.intval = CMach_CalcIntDiadic(left->rtype, left->data.intval, TK_SHL, right->data.intval); + return left; + } + + return makediadicnode(left, right, ESHL); +} + +ENode *CExpr_New_ESHR_Node(ENode *left, ENode *right) { + Conversion conv; + + if (IS_TYPE_TEMPLDEPEXPR(left->rtype) || IS_TYPE_TEMPLDEPEXPR(right->rtype)) + return CTempl_MakeTemplDepExpr(left, ESHR, right); + + left = pointer_generation(left); + right = pointer_generation(right); + if (copts.cplusplus && CExpr_CheckOperator(TK_SHR, left, right, &conv)) { + if (conv.x0) + return conv.x0; + CError_ASSERT(4752, left = conv.left); + CError_ASSERT(4753, right = conv.right); + } + + left = integralpromote(left); + right = integralpromote(right); + + if (iszero(left) || iszero(right)) { + return left; + } + + if (ENODE_IS(left, EINTCONST) && ENODE_IS(right, EINTCONST)) { + left->data.intval = CMach_CalcIntDiadic(left->rtype, left->data.intval, TK_SHR, right->data.intval); + return left; + } + + return makediadicnode(left, right, ESHR); +} + +static ENode *pointercompare(ENodeType nt, ENode *left, ENode *right) { + Type *ltype; + Type *rtype; + + ltype = left->rtype; + rtype = right->rtype; + if (IS_TYPE_POINTER_ONLY(ltype) && IS_TYPE_POINTER_ONLY(rtype)) { + ltype = TPTR_TARGET(left->rtype); + rtype = TPTR_TARGET(right->rtype); + if (IS_TYPE_CLASS(ltype) && IS_TYPE_CLASS(rtype)) { + if (ltype != rtype) { + if (ltype == TPTR_TARGET(left->rtype)) { + if (CClass_IsBaseClass(TYPE_CLASS(ltype), TYPE_CLASS(rtype), NULL, 0, 1)) { + left = CExpr_SafeClassPointerCast(left, TYPE_CLASS(ltype), TYPE_CLASS(rtype), 0, 1); + } else if (CClass_IsBaseClass(TYPE_CLASS(rtype), TYPE_CLASS(ltype), NULL, 0, 1)) { + right = CExpr_SafeClassPointerCast(right, TYPE_CLASS(rtype), TYPE_CLASS(ltype), 0, 1); + } else { + CError_Error(CErrorStr245, left->rtype, ENODE_QUALS(left), right->rtype, ENODE_QUALS(right)); + } + } else { + CError_Error(CErrorStr245, left->rtype, ENODE_QUALS(left), right->rtype, ENODE_QUALS(right)); + } + } + } else if (!is_typeequal(left->rtype, right->rtype)) { + if (!copts.objective_c || !CObjC_IsCompatibleType(left->rtype, right->rtype)) { + CError_Error(CErrorStr245, left->rtype, ENODE_QUALS(left), right->rtype, ENODE_QUALS(right)); + } + } + } else if (nt == EEQU || nt == ENOTEQU) { + if (IS_TYPE_INT(ltype)) { + if (!(ENODE_IS(left, EINTCONST) && CInt64_IsZero(&left->data.intval))) + CError_Error(CErrorStr144); + CError_ASSERT(4847, IS_TYPE_POINTER_ONLY(rtype)); + left->rtype = TYPE(&stunsignedlong); + } else if (IS_TYPE_INT(rtype)) { + if (!(ENODE_IS(right, EINTCONST) && CInt64_IsZero(&right->data.intval))) + CError_Error(CErrorStr144); + CError_ASSERT(4855, IS_TYPE_POINTER_ONLY(ltype)); + right->rtype = TYPE(&stunsignedlong); + } else if (!is_typeequal(ltype, rtype)) { + CError_Error(CErrorStr245, left->rtype, ENODE_QUALS(left), right->rtype, ENODE_QUALS(right)); + } + } else { + if (!is_typeequal(ltype, rtype)) + CError_Error(CErrorStr245, left->rtype, ENODE_QUALS(left), right->rtype, ENODE_QUALS(right)); + } + + return logicalexpression(makediadicnode(left, right, nt)); +} + +static ENode *unsigncheck(ENode *expr, Boolean flag1, Boolean flag2) { + if (is_unsigned(expr->data.diadic.left->rtype)) { + if (ENODE_IS(expr->data.diadic.left, EINTCONST) && CInt64_IsZero(&expr->data.diadic.left->data.intval)) { + flag1 = !flag1; + } else if (!(ENODE_IS(expr->data.diadic.right, EINTCONST) && CInt64_IsZero(&expr->data.diadic.right->data.intval))) { + return logicalexpression(expr); + } + + if (flag1 && flag2) { + expr->type = EEQU; + return logicalexpression(expr); + } + if (!flag1 && !flag2) { + expr->type = ENOTEQU; + return logicalexpression(expr); + } + return CExpr_ConstResult(logicalexpression(expr), !flag1); + } + return logicalexpression(expr); +} + +ENode *CExpr_New_ELESS_Node(ENode *left, ENode *right) { + Conversion conv; + + if (IS_TYPE_TEMPLDEPEXPR(left->rtype) || IS_TYPE_TEMPLDEPEXPR(right->rtype)) + return CTempl_MakeTemplDepExpr(left, ELESS, right); + + left = pointer_generation(left); + right = pointer_generation(right); + if (copts.cplusplus && CExpr_CheckOperator('<', left, right, &conv)) { + if (conv.x0) + return conv.x0; + CError_ASSERT(4929, left = conv.left); + CError_ASSERT(4930, right = conv.right); + } + + if (IS_TYPE_POINTER(left->rtype) || IS_TYPE_POINTER(right->rtype)) + return pointercompare(ELESS, left, right); + + CExpr_CompareConvert(&left, "<", &right, 0); + if (ENODE_IS(left, EINTCONST) && ENODE_IS(right, EINTCONST)) { + left->data.intval = CMach_CalcIntDiadic(left->rtype, left->data.intval, '<', right->data.intval); + left->rtype = CParser_GetBoolType(); + } else if (ENODE_IS(left, EFLOATCONST) && ENODE_IS(right, EFLOATCONST)) { + CInt64_SetLong(&left->data.intval, CMach_CalcFloatDiadicBool(left->rtype, left->data.floatval, '<', right->data.floatval)); + left->type = EINTCONST; + left->rtype = CParser_GetBoolType(); + } else { + left = unsigncheck(makediadicnode(left, right, ELESS), 1, 0); + } + + return left; +} + +ENode *CExpr_New_ELESSEQU_Node(ENode *left, ENode *right) { + Conversion conv; + + if (IS_TYPE_TEMPLDEPEXPR(left->rtype) || IS_TYPE_TEMPLDEPEXPR(right->rtype)) + return CTempl_MakeTemplDepExpr(left, ELESSEQU, right); + + left = pointer_generation(left); + right = pointer_generation(right); + if (copts.cplusplus && CExpr_CheckOperator(TK_LESS_EQUAL, left, right, &conv)) { + if (conv.x0) + return conv.x0; + CError_ASSERT(4976, left = conv.left); + CError_ASSERT(4977, right = conv.right); + } + + if (IS_TYPE_POINTER(left->rtype) || IS_TYPE_POINTER(right->rtype)) + return pointercompare(ELESSEQU, left, right); + + CExpr_CompareConvert(&left, "<=", &right, 0); + if (ENODE_IS(left, EINTCONST) && ENODE_IS(right, EINTCONST)) { + left->data.intval = CMach_CalcIntDiadic(left->rtype, left->data.intval, TK_LESS_EQUAL, right->data.intval); + left->rtype = CParser_GetBoolType(); + } else if (ENODE_IS(left, EFLOATCONST) && ENODE_IS(right, EFLOATCONST)) { + CInt64_SetLong(&left->data.intval, CMach_CalcFloatDiadicBool(left->rtype, left->data.floatval, TK_LESS_EQUAL, right->data.floatval)); + left->type = EINTCONST; + left->rtype = CParser_GetBoolType(); + } else { + left = unsigncheck(makediadicnode(left, right, ELESSEQU), 1, 1); + } + + return left; +} + +ENode *CExpr_New_EGREATER_Node(ENode *left, ENode *right) { + Conversion conv; + + if (IS_TYPE_TEMPLDEPEXPR(left->rtype) || IS_TYPE_TEMPLDEPEXPR(right->rtype)) + return CTempl_MakeTemplDepExpr(left, EGREATER, right); + + left = pointer_generation(left); + right = pointer_generation(right); + if (copts.cplusplus && CExpr_CheckOperator('>', left, right, &conv)) { + if (conv.x0) + return conv.x0; + CError_ASSERT(5023, left = conv.left); + CError_ASSERT(5024, right = conv.right); + } + + if (IS_TYPE_POINTER(left->rtype) || IS_TYPE_POINTER(right->rtype)) + return pointercompare(EGREATER, left, right); + + CExpr_CompareConvert(&left, ">", &right, 0); + if (ENODE_IS(left, EINTCONST) && ENODE_IS(right, EINTCONST)) { + left->data.intval = CMach_CalcIntDiadic(left->rtype, left->data.intval, '>', right->data.intval); + left->rtype = CParser_GetBoolType(); + } else if (ENODE_IS(left, EFLOATCONST) && ENODE_IS(right, EFLOATCONST)) { + CInt64_SetLong(&left->data.intval, CMach_CalcFloatDiadicBool(left->rtype, left->data.floatval, '>', right->data.floatval)); + left->type = EINTCONST; + left->rtype = CParser_GetBoolType(); + } else { + left = unsigncheck(makediadicnode(left, right, EGREATER), 0, 0); + } + + return left; +} + +ENode *CExpr_New_EGREATEREQU_Node(ENode *left, ENode *right) { + Conversion conv; + + if (IS_TYPE_TEMPLDEPEXPR(left->rtype) || IS_TYPE_TEMPLDEPEXPR(right->rtype)) + return CTempl_MakeTemplDepExpr(left, EGREATEREQU, right); + + left = pointer_generation(left); + right = pointer_generation(right); + if (copts.cplusplus && CExpr_CheckOperator(TK_GREATER_EQUAL, left, right, &conv)) { + if (conv.x0) + return conv.x0; + CError_ASSERT(5070, left = conv.left); + CError_ASSERT(5071, right = conv.right); + } + + if (IS_TYPE_POINTER(left->rtype) || IS_TYPE_POINTER(right->rtype)) + return pointercompare(EGREATEREQU, left, right); + + CExpr_CompareConvert(&left, ">=", &right, 0); + if (ENODE_IS(left, EINTCONST) && ENODE_IS(right, EINTCONST)) { + left->data.intval = CMach_CalcIntDiadic(left->rtype, left->data.intval, TK_GREATER_EQUAL, right->data.intval); + left->rtype = CParser_GetBoolType(); + } else if (ENODE_IS(left, EFLOATCONST) && ENODE_IS(right, EFLOATCONST)) { + CInt64_SetLong(&left->data.intval, CMach_CalcFloatDiadicBool(left->rtype, left->data.floatval, TK_GREATER_EQUAL, right->data.floatval)); + left->type = EINTCONST; + left->rtype = CParser_GetBoolType(); + } else { + left = unsigncheck(makediadicnode(left, right, EGREATEREQU), 0, 1); + } + + return left; +} + +ENode *memberpointercompare(ENodeType nt, ENode *left, ENode *right) { + Object *func; + ENodeList *arg; + + if (!IS_TYPE_MEMBERPOINTER(left->rtype)) { + if (!(IS_TYPE_INT(left->rtype) && ENODE_IS(left, EINTCONST) && CInt64_IsZero(&left->data.intval))) { + CError_Error(CErrorStr144); + return nullnode(); + } + } else if (!IS_TYPE_MEMBERPOINTER(right->rtype)) { + if (!(IS_TYPE_INT(right->rtype) && ENODE_IS(right, EINTCONST) && CInt64_IsZero(&right->data.intval))) { + CError_Error(CErrorStr144); + return nullnode(); + } + } else if (!is_typeequal(left->rtype, right->rtype)) { + left = PointerToMemberCast(left, TYPE_MEMBER_POINTER(left->rtype), TYPE_MEMBER_POINTER(right->rtype), 1); + } + + if ((ENODE_IS(left, EINTCONST) || !IS_TYPE_FUNC(TYPE_MEMBER_POINTER(left->rtype)->ty1)) && (ENODE_IS(right, EINTCONST) || !IS_TYPE_FUNC(TYPE_MEMBER_POINTER(right->rtype)->ty1))) { + left->rtype = TYPE(&stunsignedlong); + right->rtype = TYPE(&stunsignedlong); + return logicalexpression(makediadicnode(left, right, nt)); + } + + arg = lalloc(sizeof(ENodeList)); + if (ENODE_IS(left, EINTCONST) || ENODE_IS(right, EINTCONST)) { + func = rt_ptmf_test; + if (ENODE_IS(left, EINTCONST)) + arg->node = getnodeaddress(right, 0); + else + arg->node = getnodeaddress(left, 0); + arg->next = NULL; + } else { + func = rt_ptmf_cmpr; + arg->next = lalloc(sizeof(ENodeList)); + arg->node = getnodeaddress(left, 0); + arg->next->node = getnodeaddress(right, 0); + arg->next->next = NULL; + } + + left = lalloc(sizeof(ENode)); + left->type = EFUNCCALL; + left->rtype = TYPE(&stsignedlong); + left->cost = 4; + left->data.funccall.funcref = create_objectrefnode(func); + left->data.funccall.args = arg; + left->data.funccall.functype = TYPE_FUNC(func->type); + left->flags = TYPE_FUNC(func->type)->qual & ENODE_FLAG_QUALS; + + if (nt == EEQU) + left = makemonadicnode(left, ELOGNOT); + + return left; +} + +ENode *CExpr_New_EEQU_Node(ENode *left, ENode *right) { + Conversion conv; + + if (IS_TYPE_TEMPLDEPEXPR(left->rtype) || IS_TYPE_TEMPLDEPEXPR(right->rtype)) + return CTempl_MakeTemplDepExpr(left, EEQU, right); + + left = pointer_generation(left); + right = pointer_generation(right); + if (copts.cplusplus && CExpr_CheckOperator(TK_LOGICAL_EQ, left, right, &conv)) { + if (conv.x0) + return conv.x0; + CError_ASSERT(5201, left = conv.left); + CError_ASSERT(5202, right = conv.right); + } + + if (IS_TYPE_POINTER(left->rtype) || IS_TYPE_POINTER(right->rtype)) + return pointercompare(EEQU, left, right); + if (IS_TYPE_MEMBERPOINTER(left->rtype) || IS_TYPE_MEMBERPOINTER(right->rtype)) + return memberpointercompare(EEQU, left, right); + + CExpr_CompareConvert(&left, "==", &right, 1); + if (ENODE_IS(left, EINTCONST) && ENODE_IS(right, EINTCONST)) { + left->data.intval = CMach_CalcIntDiadic(left->rtype, left->data.intval, TK_LOGICAL_EQ, right->data.intval); + left->rtype = CParser_GetBoolType(); + } else if (ENODE_IS(left, EFLOATCONST) && ENODE_IS(right, EFLOATCONST)) { + left->type = EINTCONST; + CInt64_SetLong(&left->data.intval, CMach_CalcFloatDiadicBool(left->rtype, left->data.floatval, TK_LOGICAL_EQ, right->data.floatval)); + left->type = EINTCONST; + left->rtype = CParser_GetBoolType(); + } else { + left = makediadicnode(left, right, EEQU); + optimizecomm(left); + } + + return logicalexpression(left); +} + +ENode *CExpr_New_ENOTEQU_Node(ENode *left, ENode *right) { + Conversion conv; + + if (IS_TYPE_TEMPLDEPEXPR(left->rtype) || IS_TYPE_TEMPLDEPEXPR(right->rtype)) + return CTempl_MakeTemplDepExpr(left, ENOTEQU, right); + + left = pointer_generation(left); + right = pointer_generation(right); + if (copts.cplusplus && CExpr_CheckOperator(TK_LOGICAL_NE, left, right, &conv)) { + if (conv.x0) + return conv.x0; + CError_ASSERT(5261, left = conv.left); + CError_ASSERT(5262, right = conv.right); + } + + if (IS_TYPE_POINTER(left->rtype) || IS_TYPE_POINTER(right->rtype)) + return pointercompare(ENOTEQU, left, right); + if (IS_TYPE_MEMBERPOINTER(left->rtype) || IS_TYPE_MEMBERPOINTER(right->rtype)) + return memberpointercompare(ENOTEQU, left, right); + + CExpr_CompareConvert(&left, "!=", &right, 1); + if (ENODE_IS(left, EINTCONST) && ENODE_IS(right, EINTCONST)) { + left->data.intval = CMach_CalcIntDiadic(left->rtype, left->data.intval, TK_LOGICAL_NE, right->data.intval); + left->rtype = CParser_GetBoolType(); + } else if (ENODE_IS(left, EFLOATCONST) && ENODE_IS(right, EFLOATCONST)) { + CInt64_SetLong(&left->data.intval, CMach_CalcFloatDiadicBool(left->rtype, left->data.floatval, TK_LOGICAL_NE, right->data.floatval)); + left->type = EINTCONST; + left->rtype = CParser_GetBoolType(); + } else { + left = makediadicnode(left, right, ENOTEQU); + optimizecomm(left); + } + + return logicalexpression(left); +} + +ENode *CExpr_New_EAND_Node(ENode *left, ENode *right) { + Conversion conv; + + if (IS_TYPE_TEMPLDEPEXPR(left->rtype) || IS_TYPE_TEMPLDEPEXPR(right->rtype)) + return CTempl_MakeTemplDepExpr(left, EAND, right); + + left = pointer_generation(left); + right = pointer_generation(right); + if (copts.cplusplus && CExpr_CheckOperator('&', left, right, &conv)) { + if (conv.x0) + return conv.x0; + CError_ASSERT(5321, left = conv.left); + CError_ASSERT(5322, right = conv.right); + } + + left = integralpromote(left); + right = integralpromote(right); + CExpr_ArithmeticConversion(&left, &right); + + if (iszero(left) || CExpr_AllBitsSet(right)) + return left; + if (iszero(right) || CExpr_AllBitsSet(left)) + return right; + + if (ENODE_IS(left, EINTCONST) && ENODE_IS(right, EINTCONST)) { + left->data.intval = CMach_CalcIntDiadic(left->rtype, left->data.intval, '&', right->data.intval); + return left; + } + + left = makediadicnode(left, right, EAND); + optimizecomm(left); + return left; +} + +ENode *CExpr_New_EXOR_Node(ENode *left, ENode *right) { + Conversion conv; + + if (IS_TYPE_TEMPLDEPEXPR(left->rtype) || IS_TYPE_TEMPLDEPEXPR(right->rtype)) + return CTempl_MakeTemplDepExpr(left, EXOR, right); + + left = pointer_generation(left); + right = pointer_generation(right); + if (copts.cplusplus && CExpr_CheckOperator('^', left, right, &conv)) { + if (conv.x0) + return conv.x0; + CError_ASSERT(5360, left = conv.left); + CError_ASSERT(5361, right = conv.right); + } + + left = integralpromote(left); + right = integralpromote(right); + CExpr_ArithmeticConversion(&left, &right); + + if (iszero(right)) + return left; + if (iszero(left)) + return right; + + if (ENODE_IS(left, EINTCONST) && ENODE_IS(right, EINTCONST)) { + left->data.intval = CMach_CalcIntDiadic(left->rtype, left->data.intval, '^', right->data.intval); + return left; + } + + left = makediadicnode(left, right, EXOR); + optimizecomm(left); + return left; +} + +ENode *CExpr_New_EOR_Node(ENode *left, ENode *right) { + Conversion conv; + + if (IS_TYPE_TEMPLDEPEXPR(left->rtype) || IS_TYPE_TEMPLDEPEXPR(right->rtype)) + return CTempl_MakeTemplDepExpr(left, EOR, right); + + left = pointer_generation(left); + right = pointer_generation(right); + if (copts.cplusplus && CExpr_CheckOperator('|', left, right, &conv)) { + if (conv.x0) + return conv.x0; + CError_ASSERT(5399, left = conv.left); + CError_ASSERT(5400, right = conv.right); + } + + left = integralpromote(left); + right = integralpromote(right); + CExpr_ArithmeticConversion(&left, &right); + + if (iszero(right) || CExpr_AllBitsSet(left)) + return left; + if (iszero(left) || CExpr_AllBitsSet(right)) + return right; + + if (ENODE_IS(left, EINTCONST) && ENODE_IS(right, EINTCONST)) { + left->data.intval = CMach_CalcIntDiadic(left->rtype, left->data.intval, '|', right->data.intval); + return left; + } + + left = makediadicnode(left, right, EOR); + optimizecomm(left); + return left; +} + +ENode *CExpr_New_ELAND_Node(ENode *left, ENode *right) { + Conversion conv; + + if (IS_TYPE_TEMPLDEPEXPR(left->rtype) || IS_TYPE_TEMPLDEPEXPR(right->rtype)) + return CTempl_MakeTemplDepExpr(left, ELAND, right); + + left = pointer_generation(left); + right = pointer_generation(right); + if (copts.cplusplus && CExpr_CheckOperator(TK_LOGICAL_AND, left, right, &conv)) { + if (conv.x0) + return conv.x0; + CError_ASSERT(5438, left = conv.left); + CError_ASSERT(5439, right = conv.right); + } + + switch (left->rtype->type) { + case TYPEINT: + case TYPEFLOAT: + case TYPEPOINTER: + case TYPEARRAY: + break; + case TYPEENUM: + case TYPEMEMBERPOINTER: + left = CExpr_ConvertToCondition(left); + break; + default: + CError_Error(CErrorStr144); + left = nullnode(); + } + switch (right->rtype->type) { + case TYPEINT: + case TYPEFLOAT: + case TYPEPOINTER: + case TYPEARRAY: + break; + case TYPEENUM: + case TYPEMEMBERPOINTER: + right = CExpr_ConvertToCondition(right); + break; + default: + CError_Error(CErrorStr144); + right = nullnode(); + } + + if (iszero(left)) { + left->type = EINTCONST; + left->rtype = CParser_GetBoolType(); + CInt64_SetLong(&left->data.intval, 0); + return left; + } + + if (isnotzero(left)) { + if (iszero(right)) { + left->type = EINTCONST; + left->rtype = CParser_GetBoolType(); + CInt64_SetLong(&left->data.intval, 0); + return left; + } else if (isnotzero(right)) { + left->type = EINTCONST; + left->rtype = CParser_GetBoolType(); + CInt64_SetLong(&left->data.intval, 1); + return left; + } else { + left = makemonadicnode(right, ELOGNOT); + left->rtype = CParser_GetBoolType(); + return makemonadicnode(left, ELOGNOT); + } + } else { + if (isnotzero(right)) { + left = makemonadicnode(left, ELOGNOT); + left->rtype = CParser_GetBoolType(); + return makemonadicnode(left, ELOGNOT); + } else if (iszero(right)) { + right->type = EINTCONST; + right->rtype = CParser_GetBoolType(); + CInt64_SetLong(&right->data.intval, 0); + return makecommaexpression(left, right); + } else { + left = makediadicnode(left, right, ELAND); + left->rtype = CParser_GetBoolType(); + return left; + } + } +} + +ENode *CExpr_New_ELOR_Node(ENode *left, ENode *right) { + Conversion conv; + + if (IS_TYPE_TEMPLDEPEXPR(left->rtype) || IS_TYPE_TEMPLDEPEXPR(right->rtype)) + return CTempl_MakeTemplDepExpr(left, ELOR, right); + + left = pointer_generation(left); + right = pointer_generation(right); + if (copts.cplusplus && CExpr_CheckOperator(TK_LOGICAL_OR, left, right, &conv)) { + if (conv.x0) + return conv.x0; + CError_ASSERT(5543, left = conv.left); + CError_ASSERT(5544, right = conv.right); + } + + switch (left->rtype->type) { + case TYPEINT: + case TYPEFLOAT: + case TYPEPOINTER: + case TYPEARRAY: + break; + case TYPEENUM: + case TYPEMEMBERPOINTER: + left = CExpr_ConvertToCondition(left); + break; + default: + CError_Error(CErrorStr144); + left = nullnode(); + } + switch (right->rtype->type) { + case TYPEINT: + case TYPEFLOAT: + case TYPEPOINTER: + case TYPEARRAY: + break; + case TYPEENUM: + case TYPEMEMBERPOINTER: + right = CExpr_ConvertToCondition(right); + break; + default: + CError_Error(CErrorStr144); + right = nullnode(); + } + + if (isnotzero(left)) { + left->type = EINTCONST; + left->rtype = CParser_GetBoolType(); + CInt64_SetLong(&left->data.intval, 1); + return left; + } + + if (iszero(left)) { + if (iszero(right)) { + left->type = EINTCONST; + left->rtype = CParser_GetBoolType(); + CInt64_SetLong(&left->data.intval, 0); + return left; + } else if (isnotzero(right)) { + left->type = EINTCONST; + left->rtype = CParser_GetBoolType(); + CInt64_SetLong(&left->data.intval, 1); + return left; + } else { + left = makemonadicnode(right, ELOGNOT); + left->rtype = CParser_GetBoolType(); + return makemonadicnode(left, ELOGNOT); + } + } else { + if (isnotzero(right)) { + right->type = EINTCONST; + right->rtype = CParser_GetBoolType(); + CInt64_SetLong(&right->data.intval, 1); + } else if (iszero(right)) { + left = makemonadicnode(left, ELOGNOT); + left->rtype = CParser_GetBoolType(); + return makemonadicnode(left, ELOGNOT); + } + left = makediadicnode(left, right, ELOR); + left->rtype = CParser_GetBoolType(); + return left; + } +} + +ENode *CExpr_NewDyadicNode(ENode *left, ENodeType nt, ENode *right) { + switch (nt) { + default: + CError_FATAL(5642); + case EADD: return CExpr_New_EADD_Node(left, right); + case ESUB: return CExpr_New_ESUB_Node(left, right); + case EMUL: return CExpr_New_EMUL_Node(left, right); + case EDIV: return CExpr_New_EDIV_Node(left, right, 1); + case EMODULO: return CExpr_New_EMODULO_Node(left, right, 1); + case EAND: return CExpr_New_EAND_Node(left, right); + case EXOR: return CExpr_New_EXOR_Node(left, right); + case EOR: return CExpr_New_EOR_Node(left, right); + case ESHL: return CExpr_New_ESHL_Node(left, right); + case ESHR: return CExpr_New_ESHR_Node(left, right); + case ELESS: return CExpr_New_ELESS_Node(left, right); + case EGREATER: return CExpr_New_EGREATER_Node(left, right); + case ELESSEQU: return CExpr_New_ELESSEQU_Node(left, right); + case EGREATEREQU: return CExpr_New_EGREATEREQU_Node(left, right); + case EEQU: return CExpr_New_EEQU_Node(left, right); + case ENOTEQU: return CExpr_New_ENOTEQU_Node(left, right); + case ELAND: return CExpr_New_ELAND_Node(left, right); + case ELOR: return CExpr_New_ELOR_Node(left, right); + } +} + +typedef struct DyadicInfo { + ENodeType t; + UInt8 prec; +} DyadicInfo; + +static Boolean CExpr_GetDyadicInfo(short token, DyadicInfo *info) { + switch (token) { + case '*': + info->t = EMUL; + info->prec = 20; + return 1; + case '/': + info->t = EDIV; + info->prec = 20; + return 1; + case '%': + info->t = EMODULO; + info->prec = 20; + return 1; + case '+': + info->t = EADD; + info->prec = 19; + return 1; + case '-': + info->t = ESUB; + info->prec = 19; + return 1; + case TK_SHL: + info->t = ESHL; + info->prec = 18; + return 1; + case TK_SHR: + info->t = ESHR; + info->prec = 18; + return 1; + case '<': + info->t = ELESS; + info->prec = 17; + return 1; + case TK_LESS_EQUAL: + info->t = ELESSEQU; + info->prec = 17; + return 1; + case '>': + if (disallowgreaterthan) + return 0; + info->t = EGREATER; + info->prec = 17; + return 1; + case TK_GREATER_EQUAL: + info->t = EGREATEREQU; + info->prec = 17; + return 1; + case TK_LOGICAL_EQ: + info->t = EEQU; + info->prec = 16; + return 1; + case TK_LOGICAL_NE: + info->t = ENOTEQU; + info->prec = 16; + return 1; + case '&': + info->t = EAND; + info->prec = 15; + return 1; + case '^': + info->t = EXOR; + info->prec = 14; + return 1; + case '|': + info->t = EOR; + info->prec = 13; + return 1; + case TK_LOGICAL_AND: + info->t = ELAND; + info->prec = 12; + return 1; + case TK_LOGICAL_OR: + info->t = ELOR; + info->prec = 11; + return 1; + default: + return 0; + } +} + +static ENode *CExpr_ParseDyadicExpression(ENode *left, UInt8 prec, Boolean no_warning) { + ENode *right; + Boolean is_eland_or_elor; + Boolean save_dgt; + Boolean cont; + DyadicInfo left_info; + DyadicInfo right_info; + + save_dgt = disallowgreaterthan; + if (!left) { + disallowgreaterthan = 0; + left = pm_expression(); + disallowgreaterthan = save_dgt; + } + + do { + if (!CExpr_GetDyadicInfo(tk, &left_info)) + return left; + + switch (left_info.t) { + case ELAND: + CExpr_CheckUnwantedAssignment(left); + if (iszero(left)) + no_warning = 1; + is_eland_or_elor = 1; + break; + case ELOR: + CExpr_CheckUnwantedAssignment(left); + if (isnotzero(left)) + no_warning = 1; + is_eland_or_elor = 1; + break; + default: + is_eland_or_elor = 0; + } + + tk = lex(); + disallowgreaterthan = 0; + right = pm_expression(); + disallowgreaterthan = save_dgt; + inner_loop: + if (CExpr_GetDyadicInfo(tk, &right_info)) { + if (left_info.prec >= right_info.prec) { + cont = (prec >= right_info.prec); + } else { + right = CExpr_ParseDyadicExpression(right, left_info.prec, no_warning); + goto inner_loop; + } + } else { + cont = 1; + } + + if (is_eland_or_elor) + CExpr_CheckUnwantedAssignment(right); + + switch (left_info.t) { + case EDIV: + left = CExpr_New_EDIV_Node(left, right, no_warning); + break; + case EMODULO: + left = CExpr_New_EMODULO_Node(left, right, no_warning); + break; + default: + left = CExpr_NewDyadicNode(left, left_info.t, right); + } + } while (!cont); + + return left; +} + +static Boolean CExpr_IsBlockMoveType(Type *type) { + switch (type->type) { + case TYPESTRUCT: + case TYPECLASS: + return 1; + case TYPEMEMBERPOINTER: + return type->size != 4; + default: + return 0; + } +} + +ENode *CExpr_New_ECOND_Node(ENode *cond, ENode *expr1, ENode *expr2) { + ENode *result; + ENodeList *args; + short cost; + Conversion conv; + + cond = CExpr_ConvertToCondition(pointer_generation(cond)); + expr1 = pointer_generation(expr1); + expr2 = pointer_generation(expr2); + + if (!IS_TYPE_INT_OR_FLOAT(cond->rtype) && !IS_TYPE_POINTER_ONLY(cond->rtype)) { + CError_Error(CErrorStr144); + return nullnode(); + } + + cost = cond->cost + 1; + if (expr1->cost > expr2->cost) + cost += expr1->cost; + else + cost += expr2->cost; + if (expr2->cost > cost) + cost = expr2->cost; + if (cost > 200) + cost = 200; + + result = CExpr_NewENode(ECOND); + result->cost = cost; + result->rtype = expr1->rtype; + result->flags = expr1->flags | expr2->flags; + result->data.cond.cond = cond; + if (ENODE_IS(expr1, EFUNCCALL) && expr1->rtype == &stvoid && (expr1->flags & ENODE_FLAG_VOLATILE) != 0) { + result->rtype = expr2->rtype; + result->flags = expr2->flags; + result->data.cond.expr1 = expr1; + result->data.cond.expr2 = expr2; + return result; + } + if (ENODE_IS(expr2, EFUNCCALL) && expr2->rtype == &stvoid && (expr2->flags & ENODE_FLAG_VOLATILE) != 0) { + result->rtype = expr1->rtype; + result->flags = expr1->flags; + result->data.cond.expr1 = expr1; + result->data.cond.expr2 = expr2; + return result; + } + + if ( + ENODE_IS(expr1, EINDIRECT) && + ENODE_IS(expr2, EINDIRECT) && + is_typesame(expr1->rtype, expr2->rtype) && + ENODE_QUALS(expr1) == ENODE_QUALS(expr2) && + CExpr_IsBlockMoveType(expr1->rtype) && + !ENODE_IS(expr1->data.monadic, EBITFIELD) && + !ENODE_IS(expr2->data.monadic, EBITFIELD) + ) { + if (isnotzero(cond)) + return expr1; + if (iszero(cond)) + return expr2; + result->data.cond.expr1 = getnodeaddress(expr1, 0); + result->data.cond.expr2 = getnodeaddress(expr2, 0); + result->rtype = result->data.cond.expr1->rtype; + result = makemonadicnode(result, EINDIRECT); + result->rtype = TPTR_TARGET(result->rtype); + return result; + } + + if ((IS_TYPE_CLASS(expr1->rtype) || IS_TYPE_CLASS(expr2->rtype)) && !is_typesame(expr1->rtype, expr2->rtype)) { + if (!copts.old_argmatch) { + if (CExpr_CondOperatorMatch(expr1, expr2, &conv)) { + CError_ASSERT(6246, !conv.x0); + expr1 = conv.left; + expr2 = conv.right; + } else if (CExpr_CanImplicitlyConvert(expr1, expr2->rtype, ENODE_QUALS(expr2))) { + if (CExpr_CanImplicitlyConvert(expr2, expr1->rtype, ENODE_QUALS(expr1))) + CError_Error(CErrorStr188); + expr1 = CExpr_Convert(expr1, expr2->rtype, ENODE_QUALS(expr2), 0, 1); + } else if (CExpr_CanImplicitlyConvert(expr2, expr1->rtype, ENODE_QUALS(expr1))) { + expr2 = CExpr_Convert(expr2, expr1->rtype, ENODE_QUALS(expr1), 0, 1); + } else { + goto failed; + } + + result->rtype = expr1->rtype; + } else { + args = lalloc(sizeof(ENodeList)); + args->node = expr1; + args->next = lalloc(sizeof(ENodeList)); + args->next->node = expr2; + args->next->next = NULL; + + if (CExpr_CheckOperatorConversion(':', expr1, expr2, args, &conv)) { + CError_ASSERT(6274, !conv.x0); + expr1 = conv.left; + expr2 = conv.right; + } + + result->rtype = expr1->rtype; + } + } + + switch (expr1->rtype->type) { + case TYPEENUM: + if (expr1->rtype == expr2->rtype) + break; + expr1 = forceintegral(expr1); + case TYPEINT: + if (IS_TYPE_POINTER_ONLY(expr2->rtype) || IS_TYPE_MEMBERPOINTER(expr2->rtype)) { + expr1 = CExpr_Convert(expr1, expr2->rtype, ENODE_QUALS(expr2), 0, 1); + result->rtype = expr2->rtype; + break; + } + case TYPEFLOAT: + if (expr1->rtype != expr2->rtype) { + CExpr_ArithmeticConversion(&expr1, &expr2); + result->rtype = expr1->rtype; + } + break; + case TYPEPOINTER: + if (ENODE_IS(expr2, EINTCONST) && CInt64_IsZero(&expr2->data.intval)) { + expr2->rtype = TYPE(&stunsignedlong); + break; + } + if (IS_TYPE_POINTER_ONLY(expr2->rtype)) { + if (IS_TYPE_CLASS(TPTR_TARGET(expr1->rtype)) && IS_TYPE_CLASS(TPTR_TARGET(expr2->rtype))) { + if (TPTR_TARGET(expr1->rtype) != TPTR_TARGET(expr2->rtype)) { + if (CClass_IsBaseClass(TYPE_CLASS(TPTR_TARGET(expr1->rtype)), TYPE_CLASS(TPTR_TARGET(expr2->rtype)), NULL, 0, 1)) { + expr1 = CExpr_SafeClassPointerCast( + expr1, + TYPE_CLASS(TPTR_TARGET(expr1->rtype)), + TYPE_CLASS(TPTR_TARGET(expr2->rtype)), + 0, 1); + expr1->rtype = expr2->rtype; + } else if (CClass_IsBaseClass(TYPE_CLASS(TPTR_TARGET(expr2->rtype)), TYPE_CLASS(TPTR_TARGET(expr1->rtype)), NULL, 0, 1)) { + expr2 = CExpr_SafeClassPointerCast( + expr2, + TYPE_CLASS(TPTR_TARGET(expr2->rtype)), + TYPE_CLASS(TPTR_TARGET(expr1->rtype)), + 0, 1); + expr2->rtype = expr1->rtype; + } else { + goto failed; + } + } + result->rtype = expr1->rtype; + break; + } + if (TPTR_TARGET(expr2->rtype) == &stvoid) + result->rtype = expr2->rtype; + } + if (!is_typeequal(expr1->rtype, expr2->rtype)) { + if (!copts.objective_c) + goto failed; + if (!CObjC_IsCompatibleType(expr1->rtype, expr2->rtype)) + goto failed; + expr1->rtype = expr2->rtype = CObjC_GetObjCType_id(1); + } + break; + case TYPEVOID: + if (!is_typeequal(expr1->rtype, expr2->rtype)) + goto failed; + break; + case TYPESTRUCT: + case TYPECLASS: + if (!is_typeequal(expr1->rtype, expr2->rtype)) + goto failed; + result->rtype = expr1->rtype; + break; + case TYPEMEMBERPOINTER: + if (IS_TYPE_MEMBERPOINTER(expr2->rtype) && TYPE_MEMBER_POINTER(expr1->rtype)->ty2 == TYPE_MEMBER_POINTER(expr2->rtype)->ty2) { + expr2 = CExpr_Convert(expr2, expr1->rtype, ENODE_QUALS(expr1), 0, 1); + } else if (CExpr_CanImplicitlyConvert(expr1, expr2->rtype, ENODE_QUALS(expr2))) { + if (CExpr_CanImplicitlyConvert(expr2, expr1->rtype, ENODE_QUALS(expr1))) + CError_Error(CErrorStr188); + expr1 = CExpr_Convert(expr1, expr2->rtype, ENODE_QUALS(expr2), 0, 1); + } else if (CExpr_CanImplicitlyConvert(expr2, expr1->rtype, ENODE_QUALS(expr1))) { + expr2 = CExpr_Convert(expr2, expr1->rtype, ENODE_QUALS(expr1), 0, 1); + } else { + goto failed; + } + result->rtype = expr1->rtype; + break; + default: + failed: + CError_Error(CErrorStr245, expr1->rtype, ENODE_QUALS(expr1), expr2->rtype, ENODE_QUALS(expr2)); + return nullnode(); + } + + result->data.cond.expr1 = expr1; + result->data.cond.expr2 = expr2; + if (isnotzero(cond)) + result = expr1; + else if (iszero(cond)) + result = expr2; + return result; +} + +static ENode *conditional_expression(void) { + ENode *cond; + ENode *expr1; + ENode *expr2; + ENode *result; + Boolean is_templdep_cond; + + is_templdep_cond = 0; + cond = CExpr_ParseDyadicExpression(NULL, 0, 0); + if (tk != '?') + return cond; + + cond = pointer_generation(cond); + if (!IS_TYPE_TEMPLDEPEXPR(cond->rtype)) { + cond = CExpr_ConvertToCondition(cond); + if (!IS_TYPE_INT_OR_FLOAT(cond->rtype) && !IS_TYPE_POINTER_ONLY(cond->rtype)) { + CError_Error(CErrorStr144); + return nullnode(); + } + } else { + is_templdep_cond = 1; + } + + tk = lex(); + expr1 = expression(); + if (tk != ':') + CError_ErrorSkip(CErrorStr141); + else + tk = lex(); + + expr2 = (copts.cplusplus && !copts.ARMconform) ? assignment_expression() : conditional_expression(); + + if (is_templdep_cond || IS_TYPE_TEMPLDEPEXPR(expr1->rtype) || IS_TYPE_TEMPLDEPEXPR(expr2->rtype)) { + result = CExpr_NewENode(ECOND); + result->rtype = &sttemplexpr; + result->data.cond.cond = cond; + result->data.cond.expr1 = expr1; + result->data.cond.expr2 = expr2; + return result; + } + + return CExpr_New_ECOND_Node(cond, expr1, expr2); +} + +static ENode *CExpr_MakeOpAssNode(ENode *left, ENode *right, ENodeType nt) { + if (left->rtype != right->rtype) { + switch (right->rtype->type) { + case TYPEINT: + case TYPEFLOAT: + break; + case TYPEENUM: + right->rtype = TYPE_ENUM(right->rtype)->enumtype; + break; + default: + right = CExpr_AssignmentPromotion(right, left->rtype, 0, 1); + } + if (IS_TYPE_FLOAT(left->rtype)) { + if (IS_TYPE_INT(right->rtype) || (IS_TYPE_FLOAT(right->rtype) && left->rtype->size >= right->rtype->size)) + right = CExpr_AssignmentPromotion(right, left->rtype, 0, 1); + } else if (IS_TYPE_INT(left->rtype)) { + if (IS_TYPE_INT(right->rtype) && (left->rtype->size > right->rtype->size || (left->rtype->size == right->rtype->size && is_unsigned(left->rtype) == is_unsigned(right->rtype)))) + right = CExpr_AssignmentPromotion(right, left->rtype, 0, 1); + } + } + + return makediadicnode(left, right, nt); +} + +static ENode *makeassignmentnode(ENode *left, ENodeType nt, short token) { + ENode *right; + ENode *tmp; + ENode *funcexpr; + ENodeList *args; + Conversion conv; + + tk = lex(); + right = assignment_expression(); + if (copts.cplusplus) { + if (copts.old_argmatch && !ENODE_IS(right, EMEMBER)) + right = pointer_generation(right); + if (CExpr_CheckOperator(token, left, right, &conv)) { + if (!conv.x0) { + if (nt == EASS) + goto continue_anyway; + CError_FATAL(6531); + } + return conv.x0; + } + if (IS_TYPE_CLASS(left->rtype) && CClass_AssignmentOperator(TYPE_CLASS(left->rtype))) + CError_Error(CErrorStr144); + } +continue_anyway: + if (IS_TYPE_ARRAY(left->rtype)) { + if (copts.gcc_extensions && nt == EASS && is_typesame(left->rtype, right->rtype)) { + tmp = makediadicnode(left, right, nt); + tmp->flags = left->flags; + return tmp; + } + CError_Error(CErrorStr144); + return nullnode(); + } + + left = CExpr_LValue(pointer_generation(left), 1, 1); + if (nt != EASS) { + if (!IS_TYPE_INT(right->rtype)) { + if (!IS_TYPE_ENUM(right->rtype)) { + CError_Error(CErrorStr144); + return left; + } + right = forceintegral(right); + } + if (!IS_TYPE_INT(left->rtype)) { + if (copts.cplusplus) { + CError_Error(CErrorStr144); + return left; + } + left = forceintegral(left); + if (!IS_TYPE_INT(left->rtype)) { + CError_Error(CErrorStr144); + return left; + } + } + return CExpr_MakeOpAssNode(left, right, nt); + } + + if (IS_TYPE_CLASS(left->rtype) && TYPE_CLASS(left->rtype)->sominfo) { + CError_Error(CErrorStr285); + return left; + } + + if (copts.warn_implicitconv && ENODE_IS(left, EINDIRECT) && ENODE_IS(left->data.monadic, EBITFIELD) && !ENODE_IS(right, EINTCONST)) { + copts.warn_implicitconv = 0; + right = CExpr_AssignmentPromotion(right, left->rtype, left->flags, 1); + copts.warn_implicitconv = 1; + } else { + right = CExpr_AssignmentPromotion(right, left->rtype, left->flags, 1); + } + + tmp = right; + if (IS_TYPE_FLOAT(right->rtype) && ENODE_IS(right, ETYPCON) && right->rtype->size == right->data.monadic->rtype->size) + tmp = right->data.monadic; + + if ( + ENODE_IS(left, EINDIRECT) && + ENODE_IS(left->data.monadic, EOBJREF) && + ENODE_IS(tmp, EINDIRECT) && + (ENODE_IS(funcexpr = right->data.monadic, EFUNCCALL) || ENODE_IS(funcexpr, EFUNCCALLP)) && + left->rtype == funcexpr->data.funccall.functype->functype && + CMach_GetFunctionResultClass(funcexpr->data.funccall.functype) == 1 && + (args = funcexpr->data.funccall.args) + ) { + switch (CABI_GetStructResultArgumentIndex(funcexpr->data.funccall.functype)) { + case 0: + break; + case 1: + if ((args = args->next)) + break; + CError_FATAL(6625); + default: + CError_FATAL(6626); + } + if (ENODE_IS(args->node, ETEMP)) { + if (!(IS_TYPE_CLASS(left->rtype) && CClass_Destructor(TYPE_CLASS(left->rtype)))) { + args->node = getnodeaddress(left, 0); + return right; + } + } + } + + right = makediadicnode(left, right, nt); + right->flags = left->flags; + return right; +} + +static ENode *makepassignmentnode(ENode *left, ENodeType nt, short token) { + ENode *right; + Boolean is_array; + Conversion conv; + + is_array = IS_TYPE_ARRAY(left->rtype); + left = pointer_generation(left); + if (copts.cplusplus) { + tk = lex(); + right = pointer_generation(assignment_expression()); + if (CExpr_CheckOperator(token, left, right, &conv)) { + CError_ASSERT(6669, conv.x0); + return conv.x0; + } + left = CExpr_LValue(left, 1, 1); + } else { + left = CExpr_LValue(left, 1, 1); + tk = lex(); + right = pointer_generation(assignment_expression()); + } + + if (is_array) + CError_Error(CErrorStr144); + + switch (left->rtype->type) { + case TYPEINT: + case TYPEFLOAT: + case TYPEPOINTER: + break; + case TYPEENUM: + if (copts.cplusplus) { + CError_Error(CErrorStr144); + return left; + } + left = forceintegral(left); + break; + default: + CError_Error(CErrorStr144); + return left; + } + + if (IS_TYPE_ENUM(right->rtype)) + right = forceintegral(right); + + if (iszero(right)) + return left; + + if (IS_TYPE_POINTER_ONLY(left->rtype)) { + if (IS_TYPE_INT(right->rtype)) { + if (nt == ESUBASS) { + left = psub(left, right); + if (ENODE_IS(left, ESUB)) + left->type = ESUBASS; + return left; + } else { + left = padd(left, right); + if (ENODE_IS(left, EADD)) + left->type = EADDASS; + return left; + } + } + CError_Error(CErrorStr144); + return left; + } else { + return CExpr_MakeOpAssNode(left, right, nt); + } +} + +static ENode *makemulassignmentnode(ENode *left, ENodeType nt, short token) { + ENode *right; + Boolean is_array; + Conversion conv; + + is_array = IS_TYPE_ARRAY(left->rtype); + left = pointer_generation(left); + if (copts.cplusplus) { + tk = lex(); + right = pointer_generation(assignment_expression()); + if (CExpr_CheckOperator(token, left, right, &conv)) { + CError_ASSERT(6753, conv.x0); + return conv.x0; + } + if (!IS_TYPE_INT(left->rtype) && !(IS_TYPE_FLOAT(left->rtype) && nt != EMODASS)) { + CError_Error(CErrorStr144); + return nullnode(); + } + left = CExpr_LValue(left, 1, 1); + } else { + if (IS_TYPE_ENUM(left->rtype)) + left = forceintegral(left); + if (!IS_TYPE_INT(left->rtype) && !(IS_TYPE_FLOAT(left->rtype) && nt != EMODASS)) { + CError_Error(CErrorStr144); + return nullnode(); + } + + left = CExpr_LValue(left, 1, 1); + tk = lex(); + right = pointer_generation(assignment_expression()); + } + + if (is_array) + CError_Error(CErrorStr144); + + if (IS_TYPE_ENUM(right->rtype)) + right = forceintegral(right); + + if (IS_TYPE_INT(left->rtype) && IS_TYPE_FLOAT(right->rtype) && nt == EMODASS) { + CError_Error(CErrorStr144); + return nullnode(); + } + + return CExpr_MakeOpAssNode(left, right, nt); +} + +static ENode *CExpr_TransformOpAssign(ENode *expr) { + switch (expr->type) { + case EMULASS: + case EDIVASS: + case EMODASS: + case EADDASS: + case ESUBASS: + case ESHLASS: + case ESHRASS: + case EANDASS: + case EXORASS: + case EORASS: + if (expr->rtype == TYPE(&stbool)) { + expr = CIRTrans_TransformOpAss(expr); + if (ENODE_IS(expr, EASS)) { + expr->data.diadic.right = makemonadicnode(expr->data.diadic.right, ELOGNOT); + expr->data.diadic.right->rtype = TYPE(&stbool); + expr->data.diadic.right = makemonadicnode(expr->data.diadic.right, ELOGNOT); + } + } + } + + return expr; +} + +ENode *assignment_expression(void) { + ENode *expr; + + if (tk == TK_THROW) + return CExcept_ScanThrowExpression(); + + expr = conditional_expression(); + switch (tk) { + case '=': + return makeassignmentnode(expr, EASS, tk); + case TK_ADD_ASSIGN: + return CExpr_TransformOpAssign(makepassignmentnode(expr, EADDASS, tk)); + case TK_SUB_ASSIGN: + return CExpr_TransformOpAssign(makepassignmentnode(expr, ESUBASS, tk)); + case TK_MULT_ASSIGN: + expr = makemulassignmentnode(expr, EMULASS, tk); + if (ENODE_IS(expr, EMULASS) && CExpr_IsOne(expr->data.diadic.right)) + return expr->data.diadic.left; + return CExpr_TransformOpAssign(expr); + case TK_DIV_ASSIGN: + expr = makemulassignmentnode(expr, EDIVASS, tk); + if (ENODE_IS(expr, EDIVASS)) { + if (iszero(expr->data.diadic.right) && !IS_TYPE_FLOAT(expr->rtype)) { + CError_Warning(CErrorStr139); + return expr->data.diadic.left; + } + if (CExpr_IsOne(expr->data.diadic.right)) + return expr->data.diadic.left; + } + return CExpr_TransformOpAssign(expr); + case TK_MOD_ASSIGN: + expr = makemulassignmentnode(expr, EMODASS, tk); + if (ENODE_IS(expr, EMODASS)) { + if (iszero(expr->data.diadic.right)) { + CError_Warning(CErrorStr139); + return expr->data.diadic.left; + } + } + return CExpr_TransformOpAssign(expr); + case TK_SHL_ASSIGN: + expr = makeassignmentnode(expr, ESHLASS, tk); + if (ENODE_IS(expr, ESHLASS) && iszero(expr->data.diadic.right)) + return expr->data.diadic.left; + return CExpr_TransformOpAssign(expr); + case TK_SHR_ASSIGN: + expr = makeassignmentnode(expr, ESHRASS, tk); + if (ENODE_IS(expr, ESHRASS) && iszero(expr->data.diadic.right)) + return expr->data.diadic.left; + return CExpr_TransformOpAssign(expr); + case TK_AND_ASSIGN: + expr = makeassignmentnode(expr, EANDASS, tk); + if (ENODE_IS(expr, EANDASS) && CExpr_AllBitsSet(expr->data.diadic.right)) + return expr->data.diadic.left; + return expr; + case TK_XOR_ASSIGN: + expr = makeassignmentnode(expr, EXORASS, tk); + if (ENODE_IS(expr, EXORASS) && iszero(expr->data.diadic.right)) + return expr->data.diadic.left; + return CExpr_TransformOpAssign(expr); + case TK_OR_ASSIGN: + expr = makeassignmentnode(expr, EORASS, tk); + if (ENODE_IS(expr, EORASS) && iszero(expr->data.diadic.right)) + return expr->data.diadic.left; + return CExpr_TransformOpAssign(expr); + default: + return expr; + } +} + +ENode *conv_assignment_expression(void) { + return pointer_generation(assignment_expression()); +} + +static Boolean CExpr_HasSideEffect(ENode *expr) { + switch (expr->type) { + case EMONMIN: + case EBINNOT: + case ELOGNOT: + 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 ELAND: + case ELOR: + case EROTL: + case EROTR: + case EBITFIELD: + case EINTCONST: + case EFLOATCONST: + case ESTRINGCONST: + case EOBJREF: + case ETEMP: + case EARGOBJ: + case ELOCOBJ: + case EOBJLIST: + case EMEMBER: + case EVECTOR128CONST: + return 0; + case ETYPCON: + return IS_TYPE_VOID(expr->rtype); + case EINDIRECT: + switch (expr->data.monadic->type) { + case EFUNCCALL: + case EFUNCCALLP: + return 1; + default: + return 0; + } + case ECOMMA: + return CInline_ExpressionHasSideEffect(expr->data.diadic.right); + case ECOND: + return CInline_ExpressionHasSideEffect(expr->data.cond.expr1) || CInline_ExpressionHasSideEffect(expr->data.cond.expr2); + case EPOSTINC: + case EPOSTDEC: + case EPREINC: + case EPREDEC: + case EFORCELOAD: + case EASS: + case EMULASS: + case EDIVASS: + case EMODASS: + case EADDASS: + case ESUBASS: + case ESHLASS: + case ESHRASS: + case EANDASS: + case EXORASS: + case EORASS: + case EFUNCCALL: + case EFUNCCALLP: + case EMFPOINTER: + case ENULLCHECK: + case EPRECOMP: + case ELABEL: + case ENEWEXCEPTION: + case ENEWEXCEPTIONARRAY: + case EINITTRYCATCH: + case EINSTRUCTION: + return 1; + default: + CError_FATAL(7056); + return 0; + } +} + +void CExpr_CheckUnusedExpression(ENode *expr) { + ENode *scan; + ENodeList *arg; + + if (copts.warn_possunwant) { + scan = expr; + while (ENODE_IS(scan, ETYPCON)) + scan = scan->data.monadic; + if (ENODE_IS(scan, EEQU)) { + CError_Warning(CErrorStr208); + return; + } + } + + if (copts.warn_no_side_effect) { + if (!CExpr_HasSideEffect(expr)) { + CError_Warning(CErrorStr369); + return; + } + } + + if (copts.warn_resultnotused) { + scan = expr; + if (IS_TYPE_VOID(expr->rtype)) + return; + if (ENODE_IS(expr, EINDIRECT)) + scan = expr->data.monadic; + + switch (scan->type) { + case EFUNCCALL: + case EFUNCCALLP: + if (ENODE_IS(scan->data.funccall.funcref, EOBJREF) && scan->data.funccall.funcref->data.objref->name == asop_name_node) + return; + if (CMach_GetFunctionResultClass(scan->data.funccall.functype) == 1 && (arg = scan->data.funccall.args)) { + switch (CABI_GetStructResultArgumentIndex(scan->data.funccall.functype)) { + case 0: + break; + case 1: + if ((arg = arg->next)) + break; + CError_FATAL(7110); + default: + CError_FATAL(7111); + } + + if (!ENODE_IS(arg->node, ETEMP)) + return; + } + CError_Warning(CErrorStr370); + } + } +} + +ENode *s_expression(void) { + ENode *left; + ENode *right; + Conversion conv; + + left = assignment_expression(); + while (tk == ',') { + left = pointer_generation(left); + tk = lex(); + right = pointer_generation(assignment_expression()); + + if (copts.cplusplus && CExpr_CheckOperator(',', left, right, &conv)) { + CError_ASSERT(7143, left = conv.x0); + } else { + CExpr_CheckUnusedExpression(left); + left = makecommaexpression(left, right); + left->rtype = right->rtype; + } + } + + return left; +} + +ENode *expression(void) { + return pointer_generation(s_expression()); +} + +CInt64 CExpr_IntegralConstExprType(Type **tint) { + ENode *expr; + + expr = pointer_generation(conditional_expression()); + if (ENODE_IS(expr, EINTCONST)) { + switch (expr->rtype->type) { + case TYPEINT: + *tint = expr->rtype; + return expr->data.intval; + case TYPEENUM: + *tint = TYPE_ENUM(expr->rtype)->enumtype; + return expr->data.intval; + } + } + + CError_Error(CErrorStr124); + *tint = TYPE(&stchar); + return cint64_zero; +} + +ENode *CExpr_IntegralConstOrDepExpr(void) { + ENode *expr; + + expr = pointer_generation(conditional_expression()); + if (ENODE_IS(expr, EINTCONST)) { + switch (expr->rtype->type) { + case TYPEINT: + return expr; + case TYPEENUM: + expr->rtype = TYPE_ENUM(expr->rtype)->enumtype; + return expr; + default: + CError_FATAL(7209); + } + } + + if (CTemplTool_IsTemplateArgumentDependentExpression(expr)) + return expr; + + CError_Error(CErrorStr124); + expr = nullnode(); + expr->rtype = TYPE(&stchar); + return expr; +} + +CInt64 CExpr_IntegralConstExpr(void) { + Type *throwaway; + return CExpr_IntegralConstExprType(&throwaway); +} + +void CExpr_CheckUnwantedAssignment(ENode *expr) { + if (copts.warn_possunwant) { + if (ENODE_IS(expr, EASS) && !(expr->flags & ENODE_FLAG_80)) + CError_Warning(CErrorStr207); + } +} + +Boolean CExpr_ParseAsmExpr(Object **objptr, CInt64 *valptr) { + ENode *expr; + + if (objptr) + *objptr = NULL; + *valptr = cint64_zero; + + expr = pointer_generation(assignment_expression()); + if (ENODE_IS(expr, EINTCONST)) { + *valptr = expr->data.intval; + return 1; + } + + if (objptr) { + switch (expr->type) { + case EINDIRECT: + if (CInit_RelocInitCheck(expr->data.monadic, objptr, valptr, 1)) + return 1; + break; + case EOBJREF: + *objptr = expr->data.objref; + while ((*objptr)->datatype == DALIAS) + *objptr = (*objptr)->u.alias.object; + return 1; + case EMEMBER: + if (expr->data.emember->list->object->otype == OT_OBJECT) { + if (expr->data.emember->list->next && expr->data.emember->list->next->object->otype == OT_OBJECT) + CError_Error(CErrorStr199); + *objptr = OBJECT(expr->data.emember->list->object); + while ((*objptr)->datatype == DALIAS) + *objptr = (*objptr)->u.alias.object; + return 1; + } + break; + case EOBJLIST: + CError_Error(CErrorStr199); + return 0; + } + } + + CError_Error(CErrorStr155); + return 0; +} diff --git a/compiler_and_linker/FrontEnd/C/CExpr2.c b/compiler_and_linker/FrontEnd/C/CExpr2.c new file mode 100644 index 0000000..fc26c7e --- /dev/null +++ b/compiler_and_linker/FrontEnd/C/CExpr2.c @@ -0,0 +1,4206 @@ +#include "compiler/CExpr.h" +#include "compiler/CABI.h" +#include "compiler/CClass.h" +#include "compiler/CDecl.h" +#include "compiler/CInit.h" +#include "compiler/CInt64.h" +#include "compiler/CError.h" +#include "compiler/CFunc.h" +#include "compiler/CInline.h" +#include "compiler/CMachine.h" +#include "compiler/CMangler.h" +#include "compiler/CObjC.h" +#include "compiler/CObjCModern.h" +#include "compiler/CParser.h" +#include "compiler/CPrepTokenizer.h" +#include "compiler/CScope.h" +#include "compiler/CSOM.h" +#include "compiler/CTemplateFunc.h" +#include "compiler/CTemplateTools.h" +#include "compiler/CodeGen.h" +#include "compiler/CompilerTools.h" +#include "compiler/enode.h" +#include "compiler/objects.h" +#include "compiler/scopes.h" +#include "compiler/templates.h" + +#ifdef __MWERKS__ +#undef va_start +#undef va_arg +#define va_start(ap, parm) ap = __va_start(parm) +#define __va_start(parm) (va_list) (&parm + 1) +//#define va_arg(ap, type) ((((type *) (ap = (va_list) (( ((long) ap + sizeof(type) - 1) & ~(sizeof(type)) ) + sizeof(type) ) ))[-1])) +#define va_arg(ap, type) (*(((type *) (ap = (char *)((((unsigned long)ap + __builtin_align(type) - 1) & ~(__builtin_align(type) - 1) ) + sizeof(type)))) - 1)) +#endif + +ENode *assign_node; +Boolean temp_reference_init; +static SInt32 assign_value; // type? +static ENode *firstarrayexpr; +static Match5 user_std_match; +static Boolean cexpr_hascall; +static Boolean cexpr_esearch_bool[MAXEXPR]; +static Boolean cexpr_rsearch_bool[MAXEXPR]; +static CExprSearchCB cexpr_esearch_callback; +static CExprReplaceCB cexpr_rsearch_callback; +static Type *cexpr_left_conversion_type; +static Type *cexpr_right_conversion_type; + +static FuncArg mon_arg = {NULL, NULL, NULL, NULL, 0, 0, 0}; +static FuncArg diadic_arg2 = {NULL, NULL, NULL, NULL, 0, 0, 0}; +static FuncArg diadic_arg1 = {&diadic_arg1, NULL, NULL, NULL, 0, 0, 0}; + +static void CExpr_RecSearchExprTree(ENode *expr) { + ENodeList *list; + +restart: + if (cexpr_esearch_bool[expr->type]) + cexpr_esearch_callback(expr); + + switch (expr->type) { + case EPOSTINC: + case EPOSTDEC: + case EPREINC: + case EPREDEC: + case EINDIRECT: + case EMONMIN: + case EBINNOT: + case ELOGNOT: + case EFORCELOAD: + case ETYPCON: + case EBITFIELD: + expr = expr->data.monadic; + goto restart; + case EMUL: + case EMULV: + case EDIV: + case EMODULO: + case EADDV: + case ESUBV: + 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 ELAND: + case ELOR: + 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 EPMODULO: + case EROTL: + case EROTR: + case EBCLR: + case EBTST: + case EBSET: + CExpr_RecSearchExprTree(expr->data.diadic.left); + expr = expr->data.diadic.right; + goto restart; + case EINTCONST: + case EFLOATCONST: + case ESTRINGCONST: + case EOBJREF: + case EPRECOMP: + case ETEMP: + case EARGOBJ: + case ELOCOBJ: + case ELABEL: + case EOBJLIST: + case EMEMBER: + case EINSTRUCTION: + case EVECTOR128CONST: + return; + case EFUNCCALL: + case EFUNCCALLP: + for (list = expr->data.funccall.args; list; list = list->next) + CExpr_RecSearchExprTree(list->node); + expr = expr->data.funccall.funcref; + goto restart; + case ENULLCHECK: + CExpr_RecSearchExprTree(expr->data.nullcheck.nullcheckexpr); + expr = expr->data.nullcheck.condexpr; + goto restart; + case EMFPOINTER: + CExpr_RecSearchExprTree(expr->data.mfpointer.accessnode); + expr = expr->data.mfpointer.mfpointer; + goto restart; + case ECOND: + CExpr_RecSearchExprTree(expr->data.cond.cond); + CExpr_RecSearchExprTree(expr->data.cond.expr1); + expr = expr->data.cond.expr2; + goto restart; + case ENEWEXCEPTION: + case ENEWEXCEPTIONARRAY: + CExpr_RecSearchExprTree(expr->data.newexception.initexpr); + expr = expr->data.newexception.tryexpr; + goto restart; + case EINITTRYCATCH: + if (expr->data.itc.initexpr) + CExpr_RecSearchExprTree(expr->data.itc.initexpr); + if (expr->data.itc.tryexpr) + CExpr_RecSearchExprTree(expr->data.itc.tryexpr); + if (expr->data.itc.catchexpr) + CExpr_RecSearchExprTree(expr->data.itc.catchexpr); + if (expr->data.itc.result) + CExpr_RecSearchExprTree(expr->data.itc.result); + return; + default: + CError_FATAL(128); + } +} + +void CExpr_SearchExprTree(ENode *expr, CExprSearchCB callback, int count, ...) { + va_list ap; + short i; + + cexpr_esearch_callback = callback; + + va_start(ap, count); + for (i = 0; i < MAXEXPR; i++) + cexpr_esearch_bool[i] = 0; + i = 0; + while ((short) i < count) { + cexpr_esearch_bool[va_arg(ap, int)] = 1; + ++i; + } + va_end(ap); + + CExpr_RecSearchExprTree(expr); +} + +static ENode *CExpr_RecSearchExprTreeReplace(ENode *expr) { + ENodeList *list; + ENode *replaced; + + if (cexpr_rsearch_bool[expr->type]) { + replaced = cexpr_rsearch_callback(expr); + if (!replaced) + return expr; + expr = replaced; + } + + switch (expr->type) { + case EPOSTINC: + case EPOSTDEC: + case EPREINC: + case EPREDEC: + case EINDIRECT: + case EMONMIN: + case EBINNOT: + case ELOGNOT: + case EFORCELOAD: + case ETYPCON: + case EBITFIELD: + expr->data.monadic = CExpr_RecSearchExprTreeReplace(expr->data.monadic); + return expr; + case EMUL: + case EMULV: + case EDIV: + case EMODULO: + case EADDV: + case ESUBV: + 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 ELAND: + case ELOR: + 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 EPMODULO: + case EROTL: + case EROTR: + case EBCLR: + case EBTST: + case EBSET: + expr->data.diadic.left = CExpr_RecSearchExprTreeReplace(expr->data.diadic.left); + expr->data.diadic.right = CExpr_RecSearchExprTreeReplace(expr->data.diadic.right); + return expr; + case EINTCONST: + case EFLOATCONST: + case ESTRINGCONST: + case EOBJREF: + case EPRECOMP: + case ETEMP: + case EARGOBJ: + case ELOCOBJ: + case ELABEL: + case EMEMBER: + case EINSTRUCTION: + case EVECTOR128CONST: + return expr; + case EFUNCCALL: + case EFUNCCALLP: + for (list = expr->data.funccall.args; list; list = list->next) + list->node = CExpr_RecSearchExprTreeReplace(list->node); + expr->data.funccall.funcref = CExpr_RecSearchExprTreeReplace(expr->data.funccall.funcref); + return expr; + case ENULLCHECK: + expr->data.nullcheck.nullcheckexpr = CExpr_RecSearchExprTreeReplace(expr->data.nullcheck.nullcheckexpr); + expr->data.nullcheck.condexpr = CExpr_RecSearchExprTreeReplace(expr->data.nullcheck.condexpr); + return expr; + case EMFPOINTER: + expr->data.mfpointer.accessnode = CExpr_RecSearchExprTreeReplace(expr->data.mfpointer.accessnode); + expr->data.mfpointer.mfpointer = CExpr_RecSearchExprTreeReplace(expr->data.mfpointer.mfpointer); + return expr; + case ECOND: + expr->data.cond.cond = CExpr_RecSearchExprTreeReplace(expr->data.cond.cond); + expr->data.cond.expr1 = CExpr_RecSearchExprTreeReplace(expr->data.cond.expr1); + expr->data.cond.expr2 = CExpr_RecSearchExprTreeReplace(expr->data.cond.expr2); + return expr; + default: + CError_FATAL(220); + return NULL; + } +} + +ENode *CExpr_SearchExprTreeReplace(ENode *expr, CExprReplaceCB callback, int count, ...) { + va_list ap; + short i; + + cexpr_rsearch_callback = callback; + + va_start(ap, count); + for (i = 0; i < MAXEXPR; i++) + cexpr_rsearch_bool[i] = 0; + i = 0; + while ((short) i < count) { + cexpr_rsearch_bool[va_arg(ap, int)] = 1; + ++i; + } + va_end(ap); + + return CExpr_RecSearchExprTreeReplace(expr); +} + +static void CExpr_HasFuncCallCallBack(ENode *expr) { + cexpr_hascall = 1; +} + +Boolean CExpr_HasFuncCall(ENode *expr) { + cexpr_hascall = 0; + CExpr_SearchExprTree(expr, CExpr_HasFuncCallCallBack, 2, EFUNCCALL, EFUNCCALLP); + return cexpr_hascall; +} + +void CExpr_AliasTransform(ENode *expr) { + ENode *n; + + Object *obj = expr->data.objref; + if (obj->u.alias.offset) { + n = makediadicnode( + create_objectrefnode(obj->u.alias.object), + intconstnode(TYPE(&stunsignedlong), obj->u.alias.offset), + EADD); + *expr = *n; + } else { + expr->data.objref = obj->u.alias.object; + } +} + +ENode *CExpr_UnaryFloatExpression(ENode *expr) { + return expr; +} + +ENode *CExpr_BinaryFloatExpression(ENode *expr) { + return expr; +} + +ENode *CExpr_NewENode(ENodeType ty) { + ENode *expr = lalloc(sizeof(ENode)); + memclrw(expr, sizeof(ENode)); + expr->type = ty; + return expr; +} + +ENode *CExpr_NewTemplDepENode(TemplDepSubType t) { + ENode *expr = CExpr_NewENode(ETEMPLDEP); + expr->rtype = &sttemplexpr; + expr->data.templdep.subtype = t; + return expr; +} + +ENode *nullnode(void) { + ENode *expr = CExpr_NewENode(EINTCONST); + expr->rtype = (Type *) &stsignedlong; + return expr; +} + +ENode *intconstnode(Type *type, SInt32 value) { + ENode *expr = CExpr_NewENode(EINTCONST); + expr->rtype = type; + CInt64_SetLong(&expr->data.intval, value); + return expr; +} + +ENode *stringconstnode(char *str) { + ENode *expr; + SInt32 size; + + size = strlen(str) + 1; + expr = CExpr_NewENode(ESTRINGCONST); + expr->rtype = CDecl_NewArrayType((Type *) &stchar, size); + expr->data.string.size = size; + expr->data.string.data = str; + expr->data.string.ispascal = 0; + if (copts.const_strings) + expr->flags = Q_CONST; + + expr = makemonadicnode(expr, EINDIRECT); + expr->data.monadic->rtype = CDecl_NewPointerType(expr->rtype); + return expr; +} + +ENode *forceintegral(ENode *expr) { + if (!IS_TYPE_ENUM(expr->rtype)) { + CError_Error(CErrorStr144); + return nullnode(); + } else { + expr->rtype = TYPE_ENUM(expr->rtype)->enumtype; + return expr; + } +} + +ENode *makemonadicnode(ENode *inner, ENodeType ty) { + ENode *expr = lalloc(sizeof(ENode)); + expr->type = ty; + if ((expr->cost = inner->cost) == 0) + expr->cost = 1; + expr->flags = inner->flags & ENODE_FLAG_QUALS; + expr->rtype = inner->rtype; + expr->data.monadic = inner; + return expr; +} + +ENode *makediadicnode(ENode *left, ENode *right, ENodeType ty) { + ENode *expr = lalloc(sizeof(ENode)); + expr->type = ty; + expr->rtype = left->rtype; + expr->data.diadic.left = left; + expr->data.diadic.right = right; + + if (left->cost != right->cost) { + expr->cost = right->cost; + if (left->cost > expr->cost) + expr->cost = left->cost; + } else { + expr->cost = right->cost + 1; + if (expr->cost > 200) + expr->cost = 200; + } + + expr->flags = (left->flags | right->flags) & ENODE_FLAG_QUALS; + return expr; +} + +ENode *makecommaexpression(ENode *left, ENode *right) { + ENode *expr; + + if (ENODE_IS(right, EINDIRECT) && !ENODE_IS(right->data.monadic, EBITFIELD)) { + Boolean savecpp = copts.cplusplus; + copts.cplusplus = 1; + expr = makediadicnode(left, getnodeaddress(right, 0), ECOMMA); + copts.cplusplus = savecpp; + expr->rtype = expr->data.diadic.right->rtype; + expr = makemonadicnode(expr, EINDIRECT); + } else { + expr = makediadicnode(left, right, ECOMMA); + } + + expr->rtype = right->rtype; + expr->flags = right->flags; + return expr; +} + +short iszero(ENode *expr) { + switch (expr->type) { + case EINTCONST: + return CInt64_IsZero(&expr->data.intval); + case EFLOATCONST: + return CMach_FloatIsZero(expr->data.floatval); + default: + return 0; + } +} + +short isnotzero(ENode *expr) { + Object *obj; + + switch (expr->type) { + case EINTCONST: + return !CInt64_IsZero(&expr->data.intval); + case EFLOATCONST: + return !CMach_FloatIsZero(expr->data.floatval); + case ESTRINGCONST: + case ETEMP: + return 1; + case EOBJREF: + obj = expr->data.objref; + break; + case EADD: + case ESUB: + if (ENODE_IS(expr->data.diadic.left, EOBJREF) && ENODE_IS(expr->data.diadic.right, EINTCONST)) { + obj = expr->data.diadic.left->data.objref; + break; + } + if (ENODE_IS(expr->data.diadic.left, EINTCONST) && ENODE_IS(expr->data.diadic.right, EOBJREF)) { + obj = expr->data.diadic.right->data.objref; + break; + } + return 0; + default: + return 0; + } + + switch (obj->datatype) { + case DLOCAL: + return 1; + default: + return 0; + } +} + +Boolean CExpr_IsOne(ENode *expr) { + if (ENODE_IS(expr, EINTCONST)) + return CInt64_Equal(expr->data.intval, cint64_one); + else if (ENODE_IS(expr, EFLOATCONST)) + return CMach_FloatIsOne(expr->data.floatval); + else + return 0; +} + +Boolean CExpr_AllBitsSet(ENode *expr) { + SInt32 v; + + if (ENODE_IS(expr, EINTCONST)) { + switch (expr->rtype->size) { + case 1: + v = CInt64_GetULong(&expr->data.intval) & 0xFF; + return v == 0xFF; + case 2: + v = CInt64_GetULong(&expr->data.intval) & 0xFFFF; + return v == 0xFFFF; + case 3: + v = CInt64_GetULong(&expr->data.intval) & 0xFFFFFF; + return v == 0xFFFFFF; + case 4: + v = CInt64_GetULong(&expr->data.intval) & 0xFFFFFFFF; + return v == 0xFFFFFFFF; + default: + return CInt64_Equal(expr->data.intval, cint64_negone); + } + } + + return 0; +} + +ENode *CExpr_NewETEMPNode(Type *type, Boolean assign_id) { + ENode *expr = lalloc(sizeof(ENode)); + expr->type = ETEMP; + expr->cost = 0; + expr->flags = 0; + expr->rtype = CDecl_NewPointerType(type); + expr->data.temp.type = type; + expr->data.temp.uniqueid = assign_id ? CParser_GetUniqueID() : 0; + expr->data.temp.needs_dtor = 0; + return expr; +} + +static ENode *CExpr_DerefETEMPCopy(ENode *expr) { + ENode *copy; + + CError_ASSERT(636, IS_TYPE_POINTER_ONLY(expr->rtype)); + + copy = lalloc(sizeof(ENode)); + *copy = *expr; + copy = makemonadicnode(copy, EINDIRECT); + copy->rtype = TYPE_POINTER(copy->rtype)->target; + return copy; +} + +ENode *CExpr_GetETEMPCopy(ENode *expr) { + ENode *newnode; + ENode *assnode; + ENode *finalnode; + + newnode = CExpr_NewETEMPNode(expr->rtype, 1); + newnode->flags = expr->flags; + + assnode = makediadicnode(CExpr_DerefETEMPCopy(newnode), expr, EASS); + assnode->data.diadic.right = lalloc(sizeof(ENode)); + *assnode->data.diadic.right = *expr; + *expr = *assnode; + + finalnode = makemonadicnode(newnode, EINDIRECT); + finalnode->rtype = expr->rtype; + return finalnode; +} + +ENode *integralpromote(ENode *expr) { + if (!IS_TYPE_INT(expr->rtype)) + expr = forceintegral(expr); + + if (TYPE_INTEGRAL(expr->rtype)->integral >= IT_INT) + return expr; + + if (!ENODE_IS(expr, EINTCONST)) + expr = makemonadicnode(expr, ETYPCON); + expr->rtype = (Type *) &stsignedint; + + return expr; +} + +CInt64 CExpr_IntConstConvert(Type *a, Type *b, CInt64 val) { + if (a == (Type *) &stbool) + return CMach_CalcIntDiadic(b, val, TK_LOGICAL_NE, cint64_zero); + else + return CMach_CalcIntDiadic(a, val, '+', cint64_zero); +} + +ENode *promote(ENode *expr, Type *type) { + if (ENODE_IS(expr, EINTCONST)) { + if (IS_TYPE_FLOAT(type)) { + expr->type = EFLOATCONST; + expr->data.floatval = CMach_CalcFloatConvertFromInt(expr->rtype, expr->data.intval); + } else { + expr->data.intval = CExpr_IntConstConvert(type, expr->rtype, expr->data.intval); + } + expr->rtype = type; + return expr; + } + if (ENODE_IS(expr, EFLOATCONST)) { + if (IS_TYPE_FLOAT(type)) { + expr->data.floatval = CMach_CalcFloatConvert(type, expr->data.floatval); + expr->rtype = type; + return expr; + } else if (IS_TYPE_INT(type)) { + expr->data.intval = CMach_CalcIntConvertFromFloat(type, expr->data.floatval); + expr->type = EINTCONST; + expr->rtype = type; + return expr; + } + } + + expr = makemonadicnode(expr, ETYPCON); + expr->rtype = type; + return expr; +} + +void CExpr_ArithmeticConversion(ENode **left, ENode **right) { + switch ((*left)->rtype->type) { + case TYPEINT: + case TYPEFLOAT: + break; + case TYPEENUM: + (*left)->rtype = TYPE_ENUM((*left)->rtype)->enumtype; + break; + default: + CError_Error(CErrorStr144); + (*left) = nullnode(); + } + + switch ((*right)->rtype->type) { + case TYPEINT: + case TYPEFLOAT: + break; + case TYPEENUM: + (*right)->rtype = TYPE_ENUM((*right)->rtype)->enumtype; + break; + default: + CError_Error(CErrorStr144); + (*right) = nullnode(); + } + + if (IS_TYPE_FLOAT((*left)->rtype) || IS_TYPE_FLOAT((*right)->rtype)) { + if ((*left)->rtype != (*right)->rtype) { + if (TYPE_INTEGRAL((*left)->rtype)->integral > TYPE_INTEGRAL((*right)->rtype)->integral) + *right = promote(*right, (*left)->rtype); + else + *left = promote(*left, (*right)->rtype); + } + return; + } + + *left = integralpromote(*left); + *right = integralpromote(*right); + if ((*left)->rtype != (*right)->rtype) { + if (TYPE_INTEGRAL((*left)->rtype)->integral < TYPE_INTEGRAL((*right)->rtype)->integral) { + ENode **tmp = left; + left = right; + right = tmp; + } + + if ((*left)->rtype->size == (*right)->rtype->size && !is_unsigned((*left)->rtype) && is_unsigned((*right)->rtype)) { + if ((*left)->rtype == (Type *) &stsignedlong) { + *left = promote(*left, (Type *) &stunsignedlong); + } else { + CError_ASSERT(838, (*left)->rtype == (Type *) &stsignedlonglong); + *left = promote(*left, (Type *) &stunsignedlonglong); + } + } + + *right = promote(*right, (*left)->rtype); + } +} + +static ENode *CExpr_GetEA(ENode *expr) { + ENode *copy; + + for (;;) { + switch (expr->type) { + case EINDIRECT: + expr = expr->data.monadic; + for (;;) { + switch (expr->type) { + case EOBJREF: + copy = lalloc(sizeof(ENode)); + *copy = *expr; + return copy; + case ECOMMA: + expr = expr->data.diadic.right; + continue; + default: + return CExpr_GetETEMPCopy(expr); + } + } + break; + case EPOSTINC: + case EPOSTDEC: + case EPREINC: + case EPREDEC: + expr = expr->data.monadic; + continue; + case EASS: + case EMULASS: + case EDIVASS: + case EMODASS: + case EADDASS: + case ESUBASS: + case ESHLASS: + case ESHRASS: + case EANDASS: + case EXORASS: + case EORASS: + expr = expr->data.monadic; + continue; + case ECOMMA: + expr = expr->data.diadic.right; + continue; + default: + return NULL; + } + } +} + +ENode *CExpr_TempModifyExpr(ENode *expr) { + Type *type; + ENode *left; + ENode *right; + ENode *eanode; + ENode *tempnode; + ENode *indnode; + ENode *truenode; + + type = expr->rtype; + tempnode = CExpr_NewETEMPNode(type, 1); + eanode = CExpr_GetEA(expr); + if (!eanode) { + CError_Error(CErrorStr142); + return expr; + } + + // tempnode = expr + left = makemonadicnode(tempnode, EINDIRECT); + left->rtype = type; + left = makediadicnode(left, expr, EASS); + + // eanode = true + indnode = makemonadicnode(eanode, EINDIRECT); + indnode->rtype = type; + truenode = nullnode(); + truenode->rtype = (Type *) &stbool; + CInt64_SetLong(&truenode->data.intval, 1); + right = makediadicnode(indnode, truenode, EASS); + + expr = makediadicnode(left, right, ECOMMA); + + indnode = makemonadicnode(tempnode, EINDIRECT); + indnode->rtype = type; + return makediadicnode(expr, indnode, ECOMMA); +} + +Boolean CExpr_IsLValue(ENode *expr) { + while (!ENODE_IS(expr, EINDIRECT)) { + switch (expr->type) { + case EPREINC: + case EPREDEC: + return copts.cplusplus; + case EASS: + case EMULASS: + case EDIVASS: + case EMODASS: + case EADDASS: + case ESUBASS: + case ESHLASS: + case ESHRASS: + case EANDASS: + case EXORASS: + case EORASS: + if (!copts.cplusplus) + return 0; + expr = expr->data.diadic.left; + continue; + case ECOMMA: + if (!copts.cplusplus) + return 0; + expr = expr->data.diadic.right; + continue; + case ECOND: + if ( + copts.cplusplus && + is_typesame(expr->data.cond.expr1->rtype, expr->data.cond.expr2->rtype) && + (expr->data.cond.expr1->rtype->type != TYPEPOINTER || (UInt32) (expr->data.cond.expr1->flags & ENODE_FLAG_QUALS) == (expr->data.cond.expr2->flags & ENODE_FLAG_QUALS)) + ) { + return CExpr_IsLValue(expr->data.cond.expr1) && CExpr_IsLValue(expr->data.cond.expr2); + } + return 0; + default: + return 0; + } + } + + expr = expr->data.monadic; + switch (expr->type) { + case ETEMP: + return 0; + case EFUNCCALL: + if (expr->data.funccall.functype->functype->type != TYPEPOINTER || (expr->data.funccall.functype->flags & FUNC_IS_CTOR)) + return 0; + default: + return 1; + } +} + +ENode *CExpr_LValue(ENode *expr, Boolean flag1, Boolean flag2) { + ENode *eanode; + ENode *tmpnode; + +loop: + switch (expr->type) { + case ETYPCON: + if (copts.pointercast_lvalue || !copts.ANSIstrict) { + if (expr->rtype->type == TYPEPOINTER && expr->data.monadic->rtype->type == TYPEPOINTER) { + switch (expr->data.monadic->type) { + case EINDIRECT: + case ETYPCON: + expr->data.monadic->rtype = expr->rtype; + expr->data.monadic->flags = expr->flags; + expr = expr->data.monadic; + goto loop; + } + } + } + break; + case EINDIRECT: + if (flag2) { + if (!CExpr_IsLValue(expr)) + CError_Warning(CErrorStr142); + + if ( + ENODE_IS(expr->data.monadic, EOBJREF) && + expr->data.monadic->data.objref->name == this_name_node && + cscope_currentfunc && + cscope_currentclass && + expr->data.monadic->data.objref == CClass_ThisSelfObject()) + CError_Error(CErrorStr189); + } + if (flag1) { + if (CParser_IsConst(expr->rtype, expr->flags & ENODE_FLAG_QUALS)) + CError_Error(CErrorStr179); + } + return expr; + case EPREINC: + case EPREDEC: + case EASS: + case EMULASS: + case EDIVASS: + case EMODASS: + case EADDASS: + case ESUBASS: + case ESHLASS: + case ESHRASS: + case EANDASS: + case EXORASS: + case EORASS: + case ECOMMA: + if (copts.cplusplus) { + if ((eanode = CExpr_GetEA(expr))) { + tmpnode = makediadicnode(expr, eanode, ECOMMA); + tmpnode->rtype = tmpnode->data.diadic.right->rtype; + tmpnode = makemonadicnode(tmpnode, EINDIRECT); + tmpnode->rtype = expr->rtype; + return tmpnode; + } + CError_Error(CErrorStr190); + return expr; + } + break; + case ECOND: + if ( + copts.cplusplus && + is_typesame(expr->data.cond.expr1->rtype, expr->data.cond.expr2->rtype) && + (expr->data.cond.expr1->rtype->type != TYPEPOINTER || (UInt32) (expr->data.cond.expr1->flags & ENODE_FLAG_QUALS) == (expr->data.cond.expr2->flags & ENODE_FLAG_QUALS)) + ) { + expr->data.cond.expr1 = CExpr_LValue(expr->data.cond.expr1, flag1, flag2); + expr->data.cond.expr2 = CExpr_LValue(expr->data.cond.expr2, flag1, flag2); + if (ENODE_IS(expr->data.cond.expr1, EINDIRECT) && ENODE_IS(expr->data.cond.expr2, EINDIRECT)) { + if (!ENODE_IS(expr->data.cond.expr1->data.monadic, EBITFIELD) && !ENODE_IS(expr->data.cond.expr2->data.monadic, EBITFIELD)) { + expr->data.cond.expr1 = getnodeaddress(expr->data.cond.expr1, 0); + expr->data.cond.expr2 = getnodeaddress(expr->data.cond.expr2, 0); + expr->rtype = expr->data.cond.expr1->rtype; + tmpnode = makemonadicnode(expr, EINDIRECT); + tmpnode->rtype = TYPE_POINTER(tmpnode->rtype)->target; + return tmpnode; + } + } + } + break; + } + + if (flag2) + CError_Error(CErrorStr142); + return expr; +} + +ENode *CExpr_MakeObjRefNode(Object *obj, Boolean flag) { + ENode *expr; + + if (obj->sclass == TK_TYPEDEF) { + CError_Error(CErrorStr141); + return intconstnode((Type *) &void_ptr, 0); + } + + expr = lalloc(sizeof(ENode)); + memclrw(expr, sizeof(ENode)); + expr->type = EOBJREF; + expr->data.objref = obj; + expr->rtype = CDecl_NewPointerType(obj->type); + + if (!IS_TYPE_FUNC(obj->type)) + expr->flags = obj->qual & ENODE_FLAG_QUALS; + if (flag) + obj->flags |= OBJECT_USED; + + return expr; +} + +ENode *create_objectrefnode(Object *obj) { + if (name_obj_check && !name_obj_check(NULL, obj)) + return intconstnode((Type *) &void_ptr, 0); + return CExpr_MakeObjRefNode(obj, 1); +} + +ENode *create_objectnode2(Object *obj) { + ENode *expr; + + if (name_obj_check && !name_obj_check(NULL, obj)) + return nullnode(); + + expr = makemonadicnode(CExpr_MakeObjRefNode(obj, 1), EINDIRECT); + expr->rtype = TYPE_POINTER(expr->rtype)->target; + return expr; +} + +ENode *create_objectnode(Object *obj) { + return checkreference(create_objectnode2(obj)); +} + +static ENode *CExpr_ExpandArg(ENode *expr, Type *type) { + if (ENODE_IS(expr, ETYPCON) && IS_TYPE_FLOAT(type)) { + expr->rtype = type; + return expr; + } else { + return promote(expr, type); + } +} + +ENode *CExpr_IsTempConstruction(ENode *expr, Type *type, ENode **resultexpr) { + ENodeList *args; + ENode *funccall; + ENode *funcref; + + if ( + !ENODE_IS(expr, EINDIRECT) || + expr->rtype != type || + !ENODE_IS((funccall = expr->data.monadic), EFUNCCALL) || + !(args = funccall->data.funccall.args) + ) + return NULL; + + if (!ENODE_IS((funcref = funccall->data.funccall.funcref), EOBJREF) || !CClass_IsConstructor(funcref->data.objref)) { + if (expr->data.monadic->data.funccall.functype->functype != type) + return NULL; + if (CABI_GetStructResultArgumentIndex(expr->data.monadic->data.funccall.functype) == 1) { + args = args->next; + CError_ASSERT(1277, args); + } + } + + if (resultexpr) + *resultexpr = args->node; + return expr->data.monadic; +} + +ENode *CExpr_AdjustFunctionCall(ENode *expr) { + ENodeList *list; + + switch (expr->data.funccall.functype->functype->type) { + case TYPECLASS: + CDecl_CompleteType(expr->data.funccall.functype->functype); + case TYPESTRUCT: + if (!expr->data.funccall.functype->functype->size) + CError_Error(CErrorStr136, expr->data.funccall.functype->functype, 0); + } + + if (CMach_GetFunctionResultClass(expr->data.funccall.functype)) { + list = lalloc(sizeof(ENodeList)); + if (IS_TYPE_CLASS(expr->data.funccall.functype->functype)) { + CDecl_CompleteType(expr->data.funccall.functype->functype); + if (CClass_Destructor(TYPE_CLASS(expr->data.funccall.functype->functype))) + list->node = create_temp_node2(expr->rtype); + else + list->node = create_temp_node(expr->rtype); + } else { + list->node = create_temp_node(expr->rtype); + } + list->next = expr->data.funccall.args; + expr->data.funccall.args = list; + + if (expr->data.funccall.funcref->flags & ENODE_FLAG_10) + expr = CSOM_EnvCheck(expr, list); + + expr = makemonadicnode(expr, EINDIRECT); + expr->data.monadic->rtype = CDecl_NewPointerType(expr->rtype); + return expr; + } + + if (expr->data.funccall.funcref->flags & ENODE_FLAG_10) + expr = CSOM_EnvCheck(expr, NULL); + return expr; +} + +ENode *funccallexpr(Object *func, ENode *arg1, ENode *arg2, ENode *arg3, ENode *arg4) { + ENode *expr; + TypeFunc *tfunc; + ENodeList *list; + + tfunc = TYPE_FUNC(func->type); + CError_ASSERT(1411, IS_TYPE_FUNC(tfunc)); + + expr = lalloc(sizeof(ENode)); + expr->type = EFUNCCALL; + expr->cost = 4; + expr->rtype = tfunc->functype; + expr->flags = tfunc->qual & ENODE_FLAG_QUALS; + expr->data.funccall.funcref = create_objectrefnode(func); + expr->data.funccall.functype = tfunc; + + if (arg1) { + list = lalloc(sizeof(ENodeList)); + expr->data.funccall.args = list; + list->node = arg1; + if (arg2) { + list->next = lalloc(sizeof(ENodeList)); + list = list->next; + list->node = arg2; + if (arg3) { + list->next = lalloc(sizeof(ENodeList)); + list = list->next; + list->node = arg3; + if (arg4) { + list->next = lalloc(sizeof(ENodeList)); + list = list->next; + list->node = arg4; + } + } + } + list->next = NULL; + } else { + expr->data.funccall.args = NULL; + } + + return CExpr_AdjustFunctionCall(expr); +} + +ENode *CExpr_FuncCallSix(Object *func, ENode *arg1, ENode *arg2, ENode *arg3, ENode *arg4, ENode *arg5, ENode *arg6) { + ENode *expr; + TypeFunc *tfunc; + ENodeList *list; + + tfunc = TYPE_FUNC(func->type); + CError_ASSERT(1460, IS_TYPE_FUNC(tfunc)); + + expr = lalloc(sizeof(ENode)); + expr->type = EFUNCCALL; + expr->cost = 4; + expr->rtype = tfunc->functype; + expr->flags = tfunc->qual & ENODE_FLAG_QUALS; + expr->data.funccall.funcref = create_objectrefnode(func); + expr->data.funccall.functype = tfunc; + + list = lalloc(sizeof(ENodeList)); + expr->data.funccall.args = list; + list->node = arg1; + list->next = lalloc(sizeof(ENodeList)); + list = list->next; + list->node = arg2; + list->next = lalloc(sizeof(ENodeList)); + list = list->next; + list->node = arg3; + list->next = lalloc(sizeof(ENodeList)); + list = list->next; + list->node = arg4; + list->next = lalloc(sizeof(ENodeList)); + list = list->next; + list->node = arg5; + if (arg6) { + list->next = lalloc(sizeof(ENodeList)); + list = list->next; + list->node = arg6; + } + list->next = NULL; + + return CExpr_AdjustFunctionCall(expr); +} + +static void CExpr_CalcStdAssign(short checkresult, Match5 *match, Type *t1, UInt32 q1, Type *t2, UInt32 q2, Boolean flag) { + memclrw(match, sizeof(Match5)); + switch (checkresult) { + case CheckResult1: + match->x0++; + break; + case CheckResult2: + match->x2++; + break; + case CheckResult3: + match->x4++; + match->x6 += assign_value; + break; + default: + CError_FATAL(1504); + } + + if (flag || (IS_TYPE_POINTER_ONLY(t2) && (IS_TYPE_POINTER_ONLY(t1) || IS_TYPEPOINTER_REFERENCE(TYPE_POINTER(t2))) != 0)) { + if ((q2 & Q_CONST) == (q1 & Q_CONST)) + match->x8++; + if ((q2 & Q_VOLATILE) == (q1 & Q_VOLATILE)) + match->x8++; + } +} + +void CExpr_MatchCV(Type *t1, UInt32 q1, Type *t2, UInt32 q2, Match13 *match) { + Boolean r8; + + if (IS_TYPEPOINTER_REFERENCE(TYPE_POINTER(t2))) { + t2 = TYPE_POINTER(t2)->target; + r8 = 1; + } else { + r8 = 0; + } + + while (IS_TYPE_POINTER_ONLY(t2) && IS_TYPE_POINTER_ONLY(t1)) { + if (r8) { + if ((TYPE_POINTER(t1)->qual & Q_CONST) != (TYPE_POINTER(t2)->qual & Q_CONST)) + match->anotherm5.x8--; + if ((TYPE_POINTER(t1)->qual & Q_VOLATILE) != (TYPE_POINTER(t2)->qual & Q_VOLATILE)) + match->anotherm5.x8--; + } + t2 = TYPE_POINTER(t2)->target; + t1 = TYPE_POINTER(t1)->target; + r8 = 1; + } + + if ((q1 & Q_CONST) != (q2 & Q_CONST)) + match->anotherm5.x8--; + if ((q1 & Q_VOLATILE) != (q2 & Q_VOLATILE)) + match->anotherm5.x8--; +} + +Boolean CExpr_MatchAssign(Type *type, UInt32 qual, ENode *expr, Match13 *match) { + switch (assign_check(expr, type, qual, 0, 0, 1)) { + case CheckResult0: + return 0; + case CheckResult1: + match->anotherm5.x0++; + break; + case CheckResult2: + match->anotherm5.x2++; + break; + case CheckResult3: + match->anotherm5.x4++; + match->anotherm5.x6 += assign_value; + break; + case CheckResult4: + match->xE++; + match->match5.x0 += user_std_match.x0; + match->match5.x2 += user_std_match.x2; + match->match5.x4 += user_std_match.x4; + match->match5.x6 += user_std_match.x6; + match->match5.x8 += user_std_match.x8; + break; + default: + CError_FATAL(1585); + } + + if (IS_TYPE_POINTER_ONLY(type)) + CExpr_MatchCV(expr->rtype, expr->flags & ENODE_FLAG_QUALS, type, qual, match); + + return 1; +} + +static short CExpr_StdMatchCompare(Match5 *a, Match5 *b, Boolean flag) { + if (a->x0 > b->x0) return 1; + if (a->x0 == b->x0) { + if (a->x2 > b->x2) return 1; + if (a->x2 == b->x2) { + if (a->x4 > b->x4) return 1; + if (a->x4 == b->x4) { + if (a->x6 > b->x6) return 1; + if (a->x6 == b->x6) { + if (!flag) + return 0; + if (a->x8 > b->x8) return 1; + if (a->x8 == b->x8) return 0; + } + } + } + } + return -1; +} + +static short CExpr2_MemberPointerConversion(Type *type, ENode *expr, Boolean flag1) { + ENode *newnode; + short depth; + + newnode = lalloc(sizeof(ENode)); + *newnode = *expr; + if (!IS_TYPE_MEMBERPOINTER(newnode->rtype)) { + newnode = CExpr_MemberPointerConversion(newnode, TYPE_MEMBER_POINTER(type), flag1); + if (iscpp_typeequal(newnode->rtype, type)) { + if (flag1) + assign_node = newnode; + return CheckResult3; + } + } + + if (IS_TYPE_MEMBERPOINTER(newnode->rtype)) { + CError_ASSERT(1656, IS_TYPE_CLASS(TYPE_MEMBER_POINTER(type)->ty2)); + CError_ASSERT(1657, IS_TYPE_CLASS(TYPE_MEMBER_POINTER(newnode->rtype)->ty2)); + + if (CClass_IsBaseClass(TYPE_CLASS(TYPE_MEMBER_POINTER(type)->ty2), TYPE_CLASS(TYPE_MEMBER_POINTER(newnode->rtype)->ty2), &depth, 0, 0)) { + assign_value = 1000 - depth; + if (flag1) + assign_node = PointerToMemberCast(newnode, TYPE_MEMBER_POINTER(newnode->rtype), TYPE_MEMBER_POINTER(type), 1); + return CheckResult3; + } + } + + return CheckResult0; +} + +ENode *CExpr_ClassPointerCast(BClassList *cls, ENode *origexpr, Boolean nullcheckflag) { + ENode *expr; + ClassList *base; + Boolean do_nullcheck; + TypeClass *tclass; + SInt32 offset; + ENode *tmp; + + expr = origexpr; + tclass = TYPE_CLASS(cls->type); + do_nullcheck = 0; + CError_ASSERT(1691, cls); + + if (!IS_TYPE_POINTER_ONLY(origexpr->rtype)) { + CError_Error(CErrorStr141); + return origexpr; + } + + cls = cls->next; + while (cls) { + for (base = tclass->bases; base; base = base->next) { + if (base->base == TYPE_CLASS(cls->type)) + break; + } + + if (!base) { + CError_Error(CErrorStr221); + while (cls->next) + cls = cls->next; + + tmp = nullnode(); + tmp->rtype = CDecl_NewPointerType(cls->type); + return tmp; + } + + if (base->is_virtual) { + if (!base->base->sominfo) { + do_nullcheck = 1; + if ((offset = base->offset) && !canadd(expr, offset)) { + expr = makediadicnode(expr, intconstnode(TYPE(&stunsignedlong), offset), EADD); + optimizecomm(expr); + } + expr->rtype = CDecl_NewPointerType(CDecl_NewPointerType(TYPE(base->base))); + expr = makemonadicnode(expr, EINDIRECT); + } + } else { + if ((offset = base->offset)) { + do_nullcheck = 1; + if (!canadd(expr, offset)) { + expr = makediadicnode(expr, intconstnode(TYPE(&stunsignedlong), offset), EADD); + optimizecomm(expr); + } + } + } + + switch (expr->type) { + case EPOSTINC: + case EPOSTDEC: + case EPREINC: + case EPREDEC: + expr = makemonadicnode(expr, ETYPCON); + } + + expr->rtype = CDecl_NewPointerType(TYPE(base->base)); + tclass = TYPE_CLASS(cls->type); + cls = cls->next; + } + + if (nullcheckflag && do_nullcheck) + expr = do_castnullcheck(expr, origexpr); + return expr; +} + +ENode *CExpr_GetClassAccessNode(BClassList *a, BClassList *b, ENode *expr, Object *obj, AccessType access, Boolean flag) { + TypeClass *tclass; + ENode *tmp; + + if (!expr) { + if (!cscope_currentfunc || !cscope_currentclass || !cscope_is_member_func || !(expr = CClass_CreateThisSelfExpr())) { + CError_Error(CErrorStr221); + return NULL; + } + expr = makemonadicnode(expr, EINDIRECT); + expr->rtype = TYPE(cscope_currentclass); + } + + CError_ASSERT(1786, a); + CError_ASSERT(1787, IS_TYPE_CLASS(expr->rtype)); + + tclass = TYPE_CLASS(expr->rtype); + a = CScope_GetClassAccessPath(a, tclass); + if (!a || a->type != TYPE(tclass)) { + CError_Error(CErrorStr221); + return NULL; + } + + if (flag) + CClass_CheckPathAccess(a, obj, access); + + if (!TYPE_CLASS(a->type)->sominfo) { + if (b) + a = CClass_AppendPath(a, b); + + if (!ENODE_IS(expr, EINDIRECT)) + expr = CExpr_LValue(expr, 0, 0); + + if (ENODE_IS(expr, EINDIRECT)) { + expr->data.monadic->flags = expr->flags; + tmp = expr->data.monadic; + switch (tmp->type) { + case EPOSTINC: + case EPOSTDEC: + case EPREINC: + case EPREDEC: + tmp = makemonadicnode(tmp, ETYPCON); + } + expr = makemonadicnode(CExpr_ClassPointerCast(a, tmp, 0), EINDIRECT); + expr->rtype = TYPE(tclass); + } + } + + return expr; +} + +static short std_assign_check_overload(NameSpaceObjectList *list, TemplArg *templargs, Type *type, Boolean flag1) { + Object *obj; + Object *used_obj; + Boolean found_non_template_func; + Boolean is_ambig; + TemplFuncInstance *instance; + ENode *expr; + Object *cmp1; + Object *cmp2; + + if (!IS_TYPE_POINTER_ONLY(type) || !IS_TYPE_FUNC(TYPE_POINTER(type)->target)) + return CheckResult0; + + used_obj = NULL; + type = TYPE_POINTER(type)->target; + found_non_template_func = 0; + is_ambig = 0; + for (; list; list = list->next) { + obj = OBJECT(list->object); + if (obj->otype != OT_OBJECT) + continue; + + if (IS_TYPE_FUNC(obj->type) && (TYPE_FUNC(obj->type)->flags & FUNC_IS_TEMPL)) { + if (!found_non_template_func && CTempl_CanDeduceFunc(obj, TYPE_FUNC(type), templargs)) { + instance = CTempl_DeduceFunc(obj, TYPE_FUNC(type), templargs, NULL, 0); + CError_ASSERT(1861, instance); + if (is_typesame(instance->object->type, type)) { + if (used_obj && used_obj != instance->object) + is_ambig = 1; + else + used_obj = instance->object; + } + } + } else { + if (is_typesame(obj->type, type)) { + if (used_obj && found_non_template_func) { + cmp1 = obj; + if (obj->datatype == DALIAS) + cmp1 = obj->u.alias.object; + cmp2 = used_obj; + if (used_obj->datatype == DALIAS) + cmp2 = used_obj->u.alias.object; + if (cmp1 != cmp2) + is_ambig = 1; + } else { + is_ambig = 0; + used_obj = obj; + } + found_non_template_func = 1; + } + } + } + + if (used_obj) { + if (flag1) { + if (is_ambig) + CError_Error(CErrorStr199); + expr = CExpr_MakeObjRefNode(used_obj, 1); + assign_node = expr; + expr->rtype = CDecl_NewPointerType(used_obj->type); + expr->flags = obj->qual & ENODE_FLAG_QUALS; + used_obj->flags |= OBJECT_USED; + if (used_obj->datatype == DINLINEFUNC) + CError_Error(CErrorStr175); + } + return CheckResult1; + } else { + return CheckResult0; + } +} + +ENode *CExpr_ConvertToBool(ENode *expr, Boolean isExplicit) { + if (IS_TYPE_MEMBERPOINTER(expr->rtype)) + expr = CExpr_ConvertToCondition(expr); + + switch (expr->rtype->type) { + case TYPEINT: + case TYPEFLOAT: + case TYPEENUM: + case TYPEPOINTER: + if (IS_TYPE_ENUM(expr->rtype)) + expr = forceintegral(expr); + switch (expr->type) { + case EINTCONST: + CInt64_SetLong(&expr->data.intval, !CInt64_IsZero(&expr->data.intval)); + break; + case EFLOATCONST: + CInt64_SetLong(&expr->data.intval, !CMach_FloatIsZero(expr->data.floatval)); + expr->type = EINTCONST; + break; + default: + expr = makemonadicnode(expr, ELOGNOT); + expr->rtype = TYPE(&stbool); + expr = makemonadicnode(expr, ELOGNOT); + } + break; + default: + CError_Error( + isExplicit ? CErrorStr247 : CErrorStr209, + expr->rtype, + expr->flags & ENODE_FLAG_QUALS, + &stbool, + 0); + expr = nullnode(); + } + + expr->rtype = TYPE(&stbool); + return expr; +} + +static short std_assign_check(ENode *expr, Type *type, Boolean flag1, Boolean flag2) { + short result; + + if (copts.cplusplus) { + illegalimplicitconversion = 0; + + if ((result = iscpp_typeequal(expr->rtype, type))) { + assign_node = expr; + if (result == -1) { + assign_value = 1; + return CheckResult3; + } else { + return CheckResult1; + } + } + + if (flag1 && illegalimplicitconversion) { + CError_Error(CErrorStr209, expr->rtype, expr->flags & ENODE_FLAG_QUALS, type, 0); + return CheckResult0; + } + } else { + if (is_typeequal(expr->rtype, type)) { + assign_node = expr; + return CheckResult1; + } + } + + if (type == TYPE(&stbool)) { + switch (expr->rtype->type) { + case TYPEPOINTER: + case TYPEMEMBERPOINTER: + assign_value = 0; + case TYPEINT: + case TYPEFLOAT: + case TYPEENUM: + if (flag1) + assign_node = CExpr_ConvertToBool(expr, 0); + return CheckResult3; + default: + return CheckResult0; + } + } + + if (IS_TYPE_ENUM(expr->rtype) && (IS_TYPE_INT(type) || IS_TYPE_FLOAT(type))) { + result = CheckResult3; + if (IS_TYPE_INT(type)) { + if (TYPE_ENUM(expr->rtype)->enumtype == type) { + result = CheckResult2; + } else if (TYPE_INTEGRAL(TYPE_ENUM(expr->rtype)->enumtype)->integral < IT_INT) { + switch (TYPE_INTEGRAL(type)->integral) { + case IT_INT: + if (expr->rtype->size < stsignedint.size || TYPE_ENUM(expr->rtype)->enumtype == TYPE(&stsignedshort)) + result = CheckResult2; + break; + case IT_UINT: + if (expr->rtype->size >= stsignedint.size && TYPE_ENUM(expr->rtype)->enumtype != TYPE(&stsignedshort)) + result = CheckResult2; + break; + } + } + } + if (flag1) { + expr->rtype = TYPE_ENUM(expr->rtype)->enumtype; + assign_node = promote(expr, type); + } + return result; + } + + if (IS_TYPE_INT(expr->rtype) && (IS_TYPE_INT(type) || IS_TYPE_FLOAT(type))) { + result = CheckResult3; + if (TYPE_INTEGRAL(expr->rtype)->integral <= IT_INT) { + if (type == TYPE(&stsignedint) || type == TYPE(&stunsignedint)) { + switch (TYPE_INTEGRAL(type)->integral) { + case IT_INT: + if (expr->rtype->size < stsignedint.size || type != TYPE(&stunsignedshort)) + result = CheckResult2; + break; + case IT_UINT: + if (expr->rtype->size == stsignedint.size && type == TYPE(&stunsignedshort)) + result = CheckResult2; + break; + } + } + } + + if (flag1 && type != expr->rtype) + assign_node = promote(expr, type); + else + assign_node = expr; + return result; + } + + if (IS_TYPE_FLOAT(expr->rtype) && (IS_TYPE_INT(type) || IS_TYPE_FLOAT(type))) { + if (type == TYPE(&stdouble) && (expr->rtype == TYPE(&stfloat) || expr->rtype == TYPE(&stshortdouble))) + result = CheckResult2; + else + result = CheckResult3; + + if (flag1 && (!IS_TYPE_FLOAT(type) || type->size != expr->rtype->size)) + assign_node = promote(expr, type); + else + assign_node = expr; + return result; + } + + if (IS_TYPE_POINTER_ONLY(type)) { + if (ENODE_IS(expr, EINTCONST) && CInt64_IsZero(&expr->data.intval) && (IS_TYPE_INT(expr->rtype) || (!copts.cplusplus && IS_TYPE_ENUM(expr->rtype)))) { + if (flag1) + expr->rtype = TYPE(&stunsignedlong); + assign_node = expr; + return CheckResult3; + } + if (ENODE_IS(expr, EOBJLIST)) { + return std_assign_check_overload(expr->data.objlist.list, expr->data.objlist.templargs, type, flag1); + } + if (IS_TYPE_POINTER_ONLY(expr->rtype)) { + if (ENODE_IS(expr, EOBJREF) && IS_TYPE_FUNC(expr->data.objref->type) && (TYPE_FUNC(expr->data.objref->type)->flags & FUNC_IS_TEMPL)) { + NameSpaceObjectList list; + list.next = NULL; + list.object = OBJ_BASE(expr->data.objref); + return std_assign_check_overload(&list, NULL, type, flag1); + } + if (copts.objective_c && CObjC_IsCompatibleType(expr->rtype, type)) { + assign_value = 1; + return CheckResult3; + } + if (IS_TYPE_CLASS(TYPE_POINTER(expr->rtype)->target) && IS_TYPE_CLASS(TYPE_POINTER(type)->target)) { + short depth; + Boolean isambig; + BClassList *path; + path = CClass_GetBasePath( + TYPE_CLASS(TYPE_POINTER(expr->rtype)->target), + TYPE_CLASS(TYPE_POINTER(type)->target), + &depth, &isambig + ); + if (path) { + assign_value = 1000 - depth; + if (flag1) { + if (isambig) + CError_Error(CErrorStr188); + if (flag2) + CClass_CheckPathAccess(path, NULL, ACCESSPUBLIC); + assign_node = CExpr_ClassPointerCast(path, expr, 1); + } + return CheckResult3; + } else { + if (flag1) { + if (isambig) + CError_Error(CErrorStr188); + else + CError_Error( + CErrorStr244, + expr->rtype, + expr->flags & ENODE_FLAG_QUALS, + type, + 0); + } + return CheckResult0; + } + } + } + } + + if (IS_TYPE_MEMBERPOINTER(type) && !IS_TYPE_CLASS(expr->rtype)) { + return CExpr2_MemberPointerConversion(type, expr, flag1); + } + + if (IS_TYPE_CLASS(expr->rtype) && IS_TYPE_CLASS(type)) { + short depth; + Boolean isambig; + BClassList *path; + path = CClass_GetBasePath( + TYPE_CLASS(expr->rtype), + TYPE_CLASS(type), + &depth, &isambig + ); + if (path) { + assign_value = 1000 - depth; + if (flag1) { + if (isambig) + CError_Error(CErrorStr188); + CClass_CheckPathAccess(path, NULL, ACCESSPUBLIC); + assign_node = getnodeaddress(expr, 0); + assign_node = CExpr_ClassPointerCast(path, assign_node, 0); + assign_node = makemonadicnode(assign_node, EINDIRECT); + assign_node->rtype = type; + } + return CheckResult3; + } + } + + if (IS_TYPE_ENUM(type)) { + switch (expr->rtype->type) { + case TYPEINT: + case TYPEFLOAT: + case TYPEENUM: + if (!copts.cplusplus) { + if (flag1) { + if (copts.pedantic) + CError_Warning(CErrorStr217, expr->rtype, expr->flags & ENODE_FLAG_QUALS, type, 0); + assign_node = do_typecast(expr, type, 0); + assign_node->flags = expr->flags; + } + return CheckResult2; + } else { + if (flag1) + CError_Error(CErrorStr217, expr->rtype, expr->flags & ENODE_FLAG_QUALS, type, 0); + } + } + } + + return CodeGen_AssignCheck(expr, type, flag1, flag2); +} + +static short is_compatible_conversion(Type *a, Type *b) { + if (IS_TYPE_REFERENCE(a)) + a = TYPE_POINTER(a)->target; + if (IS_TYPE_REFERENCE(b)) + b = TYPE_POINTER(b)->target; + return iscpp_typeequal(b, a); +} + +static void CExpr_ConIteratorInit(ConIterator *iter) { + ClassList *base; + ConIterator *subiter; + ConIteratorList *list; + + for (base = iter->tclass->bases; base; base = base->next) { + if (base->base->flags & CLASS_IS_CONVERTIBLE) { + subiter = galloc(sizeof(ConIterator)); + memclrw(subiter, sizeof(ConIterator)); + subiter->parent = iter; + subiter->tclass = base->base; + CExpr_ConIteratorInit(subiter); + + list = galloc(sizeof(ConIteratorList)); + memclrw(list, sizeof(ConIteratorList)); + list->iter = subiter; + list->next = iter->children; + iter->children = list; + } + } +} + +void CExpr_ConversionIteratorInit(ConversionIterator *iter, TypeClass *tclass) { + memclrw(iter, sizeof(ConversionIterator)); + if (tclass->flags & CLASS_IS_CONVERTIBLE) { + iter->coniter = &iter->myconiter; + iter->myconiter.tclass = tclass; + CExpr_ConIteratorInit(&iter->myconiter); + CScope_InitObjectIterator(&iter->objiter, tclass->nspace); + } +} + +static Boolean CExpr_ConversionIteratorIsHidden(ConIterator *iter, TypeFunc *tfunc) { + CScopeObjectIterator objiter; + ObjBase *obj; + TypeFunc *objtfunc; + + while (iter) { + CScope_InitObjectIterator(&objiter, iter->tclass->nspace); + while (1) { + if (!(obj = CScope_NextObjectIteratorObject(&objiter))) + break; + + objtfunc = TYPE_FUNC(OBJECT(obj)->type); + if ( + IS_TYPE_FUNC(objtfunc) && + (objtfunc->flags & FUNC_CONVERSION) && + is_compatible_conversion(tfunc->functype, objtfunc->functype) && + (tfunc->args->qual & Q_CONST) == (objtfunc->args->qual & Q_CONST) && + (tfunc->qual & Q_CONST) == (objtfunc->qual & Q_CONST) + ) + return 1; + } + iter = iter->parent; + } + + return 0; +} + +Object *CExpr_ConversionIteratorNext(ConversionIterator *iter) { + ConIterator *ci; + Object *obj; + + ci = iter->coniter; + if (!ci) + return NULL; + +restart: + if ((obj = OBJECT(CScope_NextObjectIteratorObject(&iter->objiter)))) { + if ( + IS_TYPE_FUNC(obj->type) && + (TYPE_FUNC(obj->type)->flags & FUNC_CONVERSION) && + !CExpr_ConversionIteratorIsHidden(ci->parent, TYPE_FUNC(obj->type)) + ) { + return obj; + } + goto restart; + } + + do { + if (ci->children) { + iter->coniter = ci->children->iter; + ci->children = ci->children->next; + ci = iter->coniter; + CScope_InitObjectIterator(&iter->objiter, ci->tclass->nspace); + goto restart; + } + } while ((ci = ci->parent)); + + return NULL; +} + +short user_assign_check(ENode *expr, Type *type, UInt32 qual, Boolean flag1, Boolean flag2, Boolean flag3) { + Object *r26; + ENode *r25; + Boolean r24; + Boolean r23; + Boolean r22; + Type *r18b; + short r18; + TypeFunc *r17; + Object *r17b; + NameSpaceObjectList *r16b; + Object *r16; + Object *r15; + ENode *r15b; + ENode *r14; + short r14b; + TypeFunc *r14c; + ENodeList *r14d; + TypeMemberFunc *r13; + ENodeList *r13b; + short result; + FuncArg *arg; + ConversionIterator iter; + Match5 stdmatch; + Match5 match_8C; + Match5 match_98; + BClassList path; + UInt16 chk; + Boolean is_const, is_volatile; + + CError_ASSERT(2378, copts.old_argmatch); + + memclrw(&stdmatch, sizeof(Match5)); + r24 = 0; + r22 = 0; + r23 = 0; + + if (!type->size) + CDecl_CompleteType(type); + if (!expr->rtype->size) + CDecl_CompleteType(expr->rtype); + + if (IS_TYPE_CLASS(expr->rtype)) { + r18 = 0; + CExpr_ConversionIteratorInit(&iter, TYPE_CLASS(expr->rtype)); + while ((r16 = CExpr_ConversionIteratorNext(&iter))) { + r17 = TYPE_FUNC(r16->type); + r14 = CExpr_NewENode(ETEMP); + r14->rtype = r17->functype; + if (IS_TYPE_REFERENCE(r14->rtype)) { + r14->rtype = TYPE_POINTER(r14->rtype)->target; + if (!CParser_IsConst(r14->rtype, r17->qual)) { + r14 = makemonadicnode(r14, EINDIRECT); + r14->data.monadic->rtype = TYPE(&void_ptr); + r14 = makemonadicnode(r14, EINDIRECT); + r14->data.monadic->rtype = TYPE(&void_ptr); + } + } + if ((result = std_assign_check(r14, type, 0, flag3))) { + CExpr_CalcStdAssign(result, &match_98, r17->functype, r17->qual, type, qual, 1); + CError_ASSERT(2419, r17->args && IS_TYPE_POINTER_ONLY(r17->args->type)); + chk = expr->flags; + if (!(is_const = (r17->args->qual & Q_CONST)) && (chk & Q_CONST) != 0) + continue; + if (!(is_volatile = (r17->args->qual & Q_VOLATILE)) && (chk & Q_VOLATILE) != 0) + continue; + //if (((r17->args->qual & Q_CONST) == 0 && (chk & Q_CONST) != 0) || ((r17->args->qual & Q_VOLATILE) == 0 && (chk & Q_VOLATILE) != 0)) + // continue; + + r14b = 0; + if (is_const == (expr->flags & Q_CONST)) + r14b++; + if (is_volatile == (expr->flags & Q_VOLATILE)) + r14b++; + switch (CExpr_StdMatchCompare(&match_98, &stdmatch, 1)) { + case -1: + continue; + case 0: + if (r26 == r16) + continue; + if (r14b < r18) + continue; + if (r14b != r18) + break; + r22 = 1; + continue; + } + r26 = r16; + stdmatch = match_98; + r24 = 1; + r22 = 0; + r18 = r14b; + } + } + } + + if (IS_TYPE_CLASS(type) && (r16b = CClass_Constructor(TYPE_CLASS(type)))) { + memclrw(&match_8C, sizeof(Match5)); + for (; r16b; r16b = r16b->next) { + r17b = OBJECT(r16b->object); + if (r17b->otype != OT_OBJECT) + continue; + r14c = TYPE_FUNC(r17b->type); + if (!IS_TYPE_FUNC(r14c)) + continue; + if (!flag2 && (r14c->qual & Q_EXPLICIT)) + continue; + if (!r14c->args) + continue; + if (!(arg = r14c->args->next)) + continue; + if ((TYPE_CLASS(type)->flags & CLASS_HAS_VBASES) && !(arg = arg->next)) + continue; + if (arg == &elipsis) + continue; + if (arg->next && !arg->next->dexpr && arg->next != &elipsis) + continue; + + r18b = arg->type; + if (IS_TYPE_REFERENCE(r18b)) { + r18b = TYPE_POINTER(r18b)->target; + if (!CParser_IsConst(r18b, arg->qual) && !CExpr_IsLValue(expr)) + continue; + } + + if ((result = std_assign_check(expr, r18b, 0, flag3))) { + CExpr_CalcStdAssign(result, &match_98, r14c->functype, r14c->qual, type, qual, 0); + switch (CExpr_StdMatchCompare(&match_98, &match_8C, 1)) { + case -1: + case 0: + continue; + } + r25 = expr; + match_8C = match_98; + r23 = 1; + r15 = r17b; + } + } + + if (r23) { + if (r24) { + switch (CExpr_StdMatchCompare(&stdmatch, &match_8C, 1)) { + case -1: + stdmatch = match_8C; + r24 = 0; + break; + case 0: + r22 = 1; + break; + } + } else { + stdmatch = match_8C; + } + } + } + + if (r22 && flag1) + CError_Error(CErrorStr199); + + if (r24 || r23) { + if (flag1) { + if (r24) { + r13 = TYPE_METHOD(r26->type); + CError_ASSERT(2537, r13->flags & FUNC_METHOD); + r15b = create_objectrefnode(r26); + r26->flags |= OBJECT_USED; + r14d = lalloc(sizeof(ENodeList)); + r14d->next = NULL; + expr = getnodeaddress(expr, 0); + r14d->node = CExpr_AssignmentPromotion(expr, CDecl_NewPointerType(TYPE(r13->theclass)), expr->flags, 0); + + expr = lalloc(sizeof(ENode)); + expr->type = EFUNCCALL; + expr->cost = 4; + expr->rtype = r13->functype; + expr->flags = r13->qual & ENODE_FLAG_QUALS; + expr->data.funccall.funcref = r15b; + expr->data.funccall.args = r14d; + expr->data.funccall.functype = TYPE_FUNC(r26->type); + assign_node = checkreference(CExpr_AdjustFunctionCall(expr)); + if (assign_node->rtype != type) + assign_node = CExpr_AssignmentPromotion(assign_node, type, qual, 1); + if (!IS_TYPE_REFERENCE(r13->functype)) + temp_reference_init = 1; + } else { + r13b = lalloc(sizeof(ENodeList)); + r13b->next = NULL; + r13b->node = r25; + if (TYPE_CLASS(type)->flags & CLASS_HAS_VBASES) { + r13b->next = lalloc(sizeof(ENodeList)); + r13b->next->node = r25; + r13b->next->next = NULL; + r13b->node = intconstnode(TYPE(&stsignedshort), 1); + } + path.next = NULL; + path.type = type; + assign_node = makemonadicnode(create_temp_node(type), EINDIRECT); + assign_node->rtype = type; + assign_node = CExpr_GenericFuncCall(&path, assign_node, 0, r15, NULL, NULL, r13b, 0, 0, 1); + if (ENODE_IS2(assign_node, EFUNCCALL, EFUNCCALLP)) { + assign_node->rtype = CDecl_NewPointerType(type); + assign_node = makemonadicnode(assign_node, EINDIRECT); + assign_node->rtype = type; + } + temp_reference_init = 1; + } + } + + user_std_match = stdmatch; + return CheckResult4; + } else { + if (flag1) + CError_Error(CErrorStr244, expr->rtype, expr->flags & ENODE_FLAG_QUALS, type, qual); + return CheckResult0; + } +} + +ENode *CExpr_ConvertToCondition(ENode *expr) { + switch (expr->rtype->type) { + case TYPEINT: + case TYPEFLOAT: + case TYPEPOINTER: + return expr; + case TYPEENUM: + expr->rtype = TYPE_ENUM(expr->rtype)->enumtype; + return expr; + case TYPEMEMBERPOINTER: + return memberpointercompare(ENOTEQU, expr, nullnode()); + case TYPECLASS: + return CExpr_Convert(expr, TYPE(&stbool), 0, 0, 1); + default: + CError_Error(CErrorStr376, expr->rtype, expr->flags & ENODE_FLAG_QUALS); + return nullnode(); + } +} + +ENode *CExpr_ConvertToIntegral(ENode *expr) { + ConversionIterator iter; + Type *found; + Object *obj; + + switch (expr->rtype->type) { + case TYPEINT: + case TYPEENUM: + return integralpromote(expr); + case TYPECLASS: + CDecl_CompleteType(expr->rtype); + found = NULL; + CExpr_ConversionIteratorInit(&iter, TYPE_CLASS(expr->rtype)); + while ((obj = CExpr_ConversionIteratorNext(&iter))) { + if (IS_TYPE_INT_OR_ENUM(TYPE_FUNC(obj->type)->functype)) { + if (found) { + CError_Error(CErrorStr199); + break; + } + found = TYPE_FUNC(obj->type)->functype; + } + } + if (found) + return integralpromote(CExpr_Convert(expr, found, 0, 0, 1)); + break; + } + + CError_Error(CErrorStr376, expr->rtype, expr->flags & ENODE_FLAG_QUALS); + return nullnode(); +} + +void CExpr_CheckArithmConversion(ENode *expr, Type *type) { + CInt64 val; + + if (expr->rtype == type) + return; + if (expr->rtype == TYPE(&stbool)) + return; + + if (IS_TYPE_INT(expr->rtype)) { + if (IS_TYPE_FLOAT(type)) + return; + CError_ASSERT(2772, IS_TYPE_INT(type)); + + if (type->size > expr->rtype->size) + return; + if (type->size == expr->rtype->size && is_unsigned(type) == is_unsigned(expr->rtype)) + return; + + switch (expr->type) { + case EINTCONST: + if (!CInt64_IsNegative(&expr->data.intval) || is_unsigned(expr->rtype) || !is_unsigned(type)) { + val = CExpr_IntConstConvert(type, expr->rtype, expr->data.intval); + val = CExpr_IntConstConvert(expr->rtype, type, val); + if (CInt64_Equal(val, expr->data.intval)) + return; + } + break; + case ELOGNOT: + case ELESS: + case EGREATER: + case ELESSEQU: + case EGREATEREQU: + case EEQU: + case ENOTEQU: + case ELAND: + case ELOR: + return; + } + } else { + if (IS_TYPE_FLOAT(type) && type->size >= expr->rtype->size) + return; + } + + CError_Warning(CErrorStr317, expr->rtype, 0, type, 0); +} + +ENode *get_address_of_temp_copy(ENode *expr, Boolean flag) { + char buf[64]; + ENode *result; + Object *obj; + Type *innertype; + + if (flag) { + if (ENODE_IS2(expr, EINTCONST, EFLOATCONST)) { + obj = CParser_NewCompilerDefDataObject(); + obj->type = expr->rtype; + obj->name = CParser_GetUniqueName(); + obj->sclass = TK_STATIC; + if (ENODE_IS(expr, EINTCONST)) { + innertype = expr->rtype; + switch (innertype->type) { + case TYPEINT: + break; + case TYPEENUM: + innertype = TYPE_ENUM(innertype)->enumtype; + break; + case TYPEPOINTER: + innertype = TYPE(&stunsignedlong); + break; + default: + CError_FATAL(2857); + } + CMach_InitIntMem(innertype, expr->data.intval, buf); + } else { + CMach_InitFloatMem(expr->rtype, expr->data.floatval, buf); + } + CInit_DeclareData(obj, buf, NULL, obj->type->size); + return create_objectrefnode(obj); + } + + if (cinit_tempnodefunc == NULL) + result = CExpr_NewETEMPNode(expr->rtype, 1); + else + result = cinit_tempnodefunc(expr->rtype, 0); + result = makemonadicnode(result, EINDIRECT); + result->rtype = TYPE_POINTER(result->rtype)->target; + return makecommaexpression(makediadicnode(result, expr, EASS), result->data.monadic); + } else { + result = nullnode(); + CInt64_SetLong(&result->data.intval, -1); + result->rtype = CDecl_NewPointerType(expr->rtype); + return result; + } +} + +short assign_check(ENode *expr, Type *type, UInt32 qual, Boolean flag1, Boolean flag2, Boolean flag3) { + Type *type2; + Boolean r30; + Boolean r29; + short result; + + assign_value = 1000; + r30 = 0; + r29 = 0; + temp_reference_init = 0; + + type2 = type; + if (IS_TYPE_REFERENCE(type) && !IS_TYPE_FUNC(TYPE_POINTER(type)->target)) { + type2 = TYPE_POINTER(type)->target; + r30 = 1; + } + + assign_node = expr; + if (IS_TYPE_ARRAY(type2)) { + r29 = 1; + type2 = CDecl_NewPointerType(TYPE_POINTER(type2)->target); + } + + if (!type2->size) { + CDecl_CompleteType(type2); + if (!type2->size && !r30) { + if (flag1) { + if (IS_TYPE_CLASS(type2)) + CError_Error(CErrorStr136, type2, 0); + else + CError_Error(CErrorStr244, expr->rtype, expr->flags & ENODE_FLAG_QUALS, type2, qual); + } + return CheckResult0; + } + } + + if (copts.warn_implicitconv && flag1 && !flag2) { + if (IS_TYPE_INT_OR_FLOAT(type2) && IS_TYPE_INT_OR_FLOAT(expr->rtype)) + CExpr_CheckArithmConversion(expr, type2); + } + + result = std_assign_check(expr, type2, flag1, flag3); + if (!result) { + if (IS_TYPE_CLASS(expr->rtype) || IS_TYPE_CLASS(type2)) { + result = user_assign_check(expr, type2, qual, flag1, flag2, flag3); + } else if (flag1) { + CError_Error(CErrorStr244, expr->rtype, expr->flags & ENODE_FLAG_QUALS, type2, qual); + } + } + + if (r30 && result) { + if (flag1) { + if (!ENODE_IS(assign_node, EINDIRECT)) { + if (!r29) { + assign_node = CExpr_LValue(assign_node, 0, 0); + if (!ENODE_IS(assign_node, EINDIRECT)) { + assign_node = get_address_of_temp_copy(assign_node, 1); + temp_reference_init = 1; + } else { + assign_node = getnodeaddress(assign_node, 0); + } + } + } else { + if (!CExpr_IsLValue(assign_node)) + temp_reference_init = 1; + if (!r29) + assign_node = getnodeaddress(assign_node, 0); + } + } else { + if (!r29 && !CExpr_IsLValue(assign_node) && !CParser_IsConst(TYPE_POINTER(type)->target, qual)) { + result = CheckResult0; + } + } + } + + return result; +} + +Boolean CExpr_MatchCompare(Object *obj, Match13 *a, Match13 *b) { + Object *tmp; + ObjectList *list; + + switch (CExpr_StdMatchCompare(&b->anotherm5, &a->anotherm5, 0)) { + case -1: + return 0; + case 0: + if (a->xE > b->xE) + return 0; + if (a->xE != b->xE) + break; + switch (CExpr_StdMatchCompare(&b->match5, &a->match5, 1)) { + case -1: + return 0; + case 0: + if (a->anotherm5.x8 > b->anotherm5.x8) + return 0; + if (a->anotherm5.x8 == b->anotherm5.x8 && (tmp = a->obj)) { + if (tmp->datatype == obj->datatype) { + add_it: + list = lalloc(sizeof(ObjectList)); + list->next = a->list; + a->list = list; + list->object = obj; + return 0; + } + if (obj->datatype == DALIAS) + return 0; + if (tmp->datatype != DALIAS) + goto add_it; + } + } + } + + *a = *b; + a->obj = obj; + return 1; +} + +static void MatchOverloadFunc(Object *obj, FuncArg *args, ENodeList *argexprs, Match13 *match) { + Match13 match2; + + if (IS_TYPE_FUNC(obj->type) && !(TYPE_FUNC(obj->type)->flags & FUNC_IS_TEMPL)) { + memclrw(&match2, sizeof(Match13)); + while (1) { + if (!args || args->type == &stvoid) { + if (!argexprs) + break; + return; + } + + if (args == &elipsis) + break; + if (args == &oldstyle) + break; + + if (!argexprs) { + if (args->dexpr) + break; + return; + } + + if (!CExpr_MatchAssign(args->type, args->qual, argexprs->node, &match2)) + return; + + argexprs = argexprs->next; + args = args->next; + } + + CExpr_MatchCompare(obj, match, &match2); + } +} + +Boolean CExpr_GetFuncMatchArgs(Object *obj, ENodeList *argexprs, ENode *expr, FuncMatchArgs *result) { + ENode *intexpr; + + if (!(TYPE_FUNC(obj->type)->flags & FUNC_METHOD)) { + result->exprs = argexprs; + result->args = TYPE_FUNC(obj->type)->args; + return 1; + } + + if (TYPE_METHOD(obj->type)->is_static) { + result->exprs = argexprs; + result->args = TYPE_FUNC(obj->type)->args; + return 1; + } + + if (TYPE_FUNC(obj->type)->flags & FUNC_IS_CTOR) { + result->exprs = argexprs; + result->args = TYPE_FUNC(obj->type)->args->next; + return 1; + } + + if (expr) { + intexpr = lalloc(sizeof(ENode)); + intexpr->type = EINTCONST; + intexpr->cost = 0; + intexpr->flags = expr->flags; + intexpr->rtype = CDecl_NewPointerType(expr->rtype); + intexpr->data.intval = cint64_zero; + + result->exprs = lalloc(sizeof(ENodeList)); + result->exprs->next = argexprs; + result->exprs->node = intexpr; + + if (obj->datatype == DALIAS) { + result->args = lalloc(sizeof(FuncArg)); + *result->args = *TYPE_FUNC(obj->type)->args; + result->args->type = CDecl_NewPointerType(expr->rtype); + } else { + result->args = TYPE_FUNC(obj->type)->args; + } + + return 1; + } + + return 0; +} + +static NameSpaceObjectList *CExpr_CopyNameSpaceObjectList(NameSpaceObjectList *list) { + NameSpaceObjectList *first; + NameSpaceObjectList *work; + + first = work = lalloc(sizeof(NameSpaceObjectList)); + while (1) { + work->object = list->object; + list = list->next; + if (!list) { + work->next = NULL; + break; + } else { + work->next = lalloc(sizeof(NameSpaceObjectList)); + work = work->next; + } + } + return first; +} + +static void CExpr_MatchArgList(NameSpaceObjectList *list, TemplArg *templargs, ENodeList *argexprs, Match13 *match, ENode *expr, Boolean flag) { + NameSpaceObjectList *copied_list; + NameSpaceObjectList *scan_list; + Object *obj; + ENodeList *scan_expr; + Boolean is_template; + FuncMatchArgs fma; + + if (!copts.old_argmatch) { + CExpr_FuncArgMatch(CExpr_CopyNameSpaceObjectList(list), templargs, argexprs, match, expr, flag); + return; + } + + copied_list = CExpr_CopyNameSpaceObjectList(list); + + for (scan_expr = argexprs; scan_expr; scan_expr = scan_expr->next) + CDecl_CompleteType(scan_expr->node->rtype); + + scan_list = copied_list; + is_template = 0; + for (; scan_list; scan_list = scan_list->next) { + obj = OBJECT(scan_list->object); + if (obj->otype != OT_OBJECT) + continue; + if (IS_TYPE_FUNC(obj->type) && (!flag || !(obj->qual & Q_EXPLICIT))) { + if (!(TYPE_FUNC(obj->type)->flags & FUNC_IS_TEMPL)) { + if (CExpr_GetFuncMatchArgs(obj, argexprs, expr, &fma)) + MatchOverloadFunc(obj, fma.args, fma.exprs, match); + } else { + is_template = 1; + } + } + } + + if (is_template) { + if (!match->obj || match->anotherm5.x2 || match->anotherm5.x4 || match->xE) + CTempl_FuncMatch(copied_list, templargs, argexprs, match, expr); + } +} + +ENode *CExpr_GetDefaultArgument(ENode *funcexpr, FuncArg *arg) { + ENode *tmp; + + if (CTemplTool_IsTemplateArgumentDependentExpression(arg->dexpr)) { + CError_ASSERT(3264, ENODE_IS(funcexpr, EOBJREF)); + tmp = CTemplTool_DeduceDefaultArg( + funcexpr->data.objref, + CInline_CopyExpression(arg->dexpr, CopyMode0) + ); + return argumentpromotion(tmp, arg->type, arg->qual, 1); + } + + return CInline_CopyExpression(arg->dexpr, CopyMode0); +} + +static ENode *CExpr_GenericCall(ENode *funcexpr, ENodeList *argexprs, TypeFunc *tfunc, FuncArg *args) { + ENodeList *list; + ENode *callexpr; + + while (args) { + if (args->dexpr) { + if (argexprs) { + list = argexprs; + while (list->next) + list = list->next; + list->next = lalloc(sizeof(ENodeList)); + list = list->next; + } else { + list = argexprs = lalloc(sizeof(ENodeList)); + } + list->next = NULL; + list->node = CExpr_GetDefaultArgument(funcexpr, args); + } + args = args->next; + } + + callexpr = lalloc(sizeof(ENode)); + callexpr->type = EFUNCCALL; + callexpr->cost = 4; + callexpr->rtype = tfunc->functype; + callexpr->flags = tfunc->qual & ENODE_FLAG_QUALS; + callexpr->data.funccall.funcref = funcexpr; + callexpr->data.funccall.funcref->rtype = CDecl_NewPointerType(TYPE(tfunc)); + callexpr->data.funccall.args = argexprs; + callexpr->data.funccall.functype = tfunc; + funcexpr->data.objref->flags |= OBJECT_USED; + return CExpr_AdjustFunctionCall(callexpr); +} + +static Boolean CExpr_IsObjrefPlusX(ENode *expr) { + Type *type; + + if (ENODE_IS(expr, EOBJREF)) { + type = expr->data.objref->type; + while (IS_TYPE_ARRAY(type)) + type = TYPE_POINTER(type)->target; + return IS_TYPE_CLASS(type); + } + + if (ENODE_IS2(expr, EADD, ESUB)) { + if (CExpr_IsObjrefPlusX(expr->data.diadic.left)) + return 1; + if (CExpr_IsObjrefPlusX(expr->data.diadic.right)) + return 1; + } + + return 0; +} + +static Boolean CExpr_IsStaticType(ENode *expr) { + return ENODE_IS(expr, EINDIRECT) && CExpr_IsObjrefPlusX(expr->data.monadic); +} + +ENode *CExpr_VarArgPromotion(ENode *expr, Boolean flag) { + if (!copts.old_argmatch) + expr = pointer_generation(expr); + + switch (expr->rtype->type) { + case TYPEVOID: + case TYPEFUNC: + CError_Error(CErrorStr353); + expr = nullnode(); + break; + case TYPEINT: + case TYPEENUM: + expr = integralpromote(expr); + break; + case TYPEFLOAT: + if (TYPE_INTEGRAL(expr->rtype)->integral < IT_DOUBLE) + expr = promote(expr, TYPE(&stdouble)); + break; + case TYPECLASS: + expr = classargument(expr); + break; + } + + if (!flag && copts.warn_largeargs) { + if ((IS_TYPE_INT(expr->rtype) && TYPE_INTEGRAL(expr->rtype)->integral >= IT_LONGLONG) || IS_TYPE_FLOAT(expr->rtype)) + CError_Warning(CErrorStr316); + } + + return expr; +} + +ENode *CExpr_GenericFuncCall(BClassList *path, ENode *funcexpr, Boolean flag1, Object *obj, NameSpaceObjectList *nsol, TemplArg *templargs, ENodeList *nodes, Boolean flag2, Boolean flag3, Boolean flag4) { + TypeFunc *tfunc; + AccessType access; + FuncArg *scan_arg; + BClassList *buildpath; + ENode *objexpr; + ENodeList *scan_expr; + BClassList *pathcopy; + Boolean had_alias; + NameSpaceObjectList my_list; + Match13 match; + + memclrw(&match, sizeof(Match13)); + + if (!obj || IS_TEMPL_FUNC(obj->type)) { + if (!funcexpr && cscope_currentfunc && cscope_currentclass && cscope_is_member_func) { + funcexpr = CClass_CreateThisSelfExpr(); + if (funcexpr) { + funcexpr = makemonadicnode(funcexpr, EINDIRECT); + funcexpr->rtype = TYPE(cscope_currentclass); + } + } + + if (obj) { + my_list.next = NULL; + my_list.object = OBJ_BASE(obj); + nsol = &my_list; + } + + CExpr_MatchArgList(nsol, templargs, nodes, &match, funcexpr, flag2); + if (!match.obj) { + CError_ErrorFuncCall(CErrorStr248, nsol, nodes); + return nullnode(); + } + if (match.list) + CError_OverloadedFunctionError(match.obj, match.list); + obj = match.obj; + } + + objexpr = create_objectrefnode(obj); + tfunc = TYPE_FUNC(obj->type); + if (!IS_TYPE_FUNC(tfunc)) { + CError_Error(CErrorStr161); + return nullnode(); + } + + if (IS_TYPEFUNC_METHOD(tfunc) && !TYPE_METHOD(tfunc)->is_static) { + had_alias = 0; + buildpath = NULL; + access = obj->access; + while (obj->datatype == DALIAS) { + buildpath = buildpath ? CClass_AppendPath(buildpath, CClass_GetPathCopy(obj->u.alias.member, 0)) : CClass_GetPathCopy(obj->u.alias.member, 0); + obj = obj->u.alias.object; + objexpr = create_objectrefnode(obj); + had_alias = 1; + } + if (flag3) + CError_Error(CErrorStr188); + + if (TYPE_METHOD(tfunc)->theclass->sominfo && (!(obj->qual & Q_INLINE) || (obj->datatype == DVFUNC && !flag1))) { + pathcopy = CClass_GetPathCopy(path, 0); + funcexpr = CExpr_GetClassAccessNode(path, buildpath, funcexpr, obj, access, flag4); + if (!funcexpr) + return nullnode(); + objexpr = CSOM_MethodAccess(pathcopy, obj, flag1); + } else { + if (obj->datatype == DVFUNC) { + if (flag1 || (!copts.always_vdispatch && !had_alias && funcexpr && CExpr_IsStaticType(funcexpr))) + objexpr->flags |= ENODE_FLAG_80; + } + funcexpr = CExpr_GetClassAccessNode(path, buildpath, funcexpr, obj, access, flag4); + if (!funcexpr) + return nullnode(); + } + + if ( + (tfunc->flags & FUNC_PURE) && + cscope_currentfunc && + (TYPE_FUNC(cscope_currentfunc->type)->flags & (FUNC_IS_CTOR | FUNC_IS_DTOR)) && + cscope_currentclass == TYPE_METHOD(tfunc)->theclass && + ENODE_IS(funcexpr, EINDIRECT) && + ENODE_IS(funcexpr->data.monadic, EINDIRECT) && + ENODE_IS(funcexpr->data.monadic->data.monadic, EOBJREF) && + funcexpr->data.monadic->data.monadic->data.objref->name == this_name_node && + !(objexpr->flags & ENODE_FLAG_80) + ) + CError_Warning(CErrorStr195); + + scan_expr = lalloc(sizeof(ENodeList)); + scan_expr->next = nodes; + scan_expr->node = funcexpr->data.monadic; + if (ENODE_IS(scan_expr->node, EOBJREF)) + scan_expr->node->data.objref->flags |= OBJECT_FLAGS_2; + + if (((funcexpr->flags & Q_CONST) && !(tfunc->args->qual & Q_CONST)) || ((funcexpr->flags & Q_VOLATILE) && !(tfunc->args->qual & Q_VOLATILE))) { + if (!(tfunc->flags & (FUNC_IS_CTOR | FUNC_IS_DTOR))) + CError_Error(CErrorStr236); + } + + nodes = scan_expr; + scan_expr = scan_expr->next; + scan_arg = tfunc->args->next; + } else { + if (flag4 && obj->access != ACCESSPROTECTED) + CClass_CheckObjectAccess(path, obj); + + scan_arg = tfunc->args; + scan_expr = nodes; + if (tfunc->flags & FUNC_METHOD) { + CError_ASSERT(3599, TYPE_METHOD(tfunc)->theclass->sominfo == NULL); + } + } + + while (scan_expr) { + if (scan_arg && scan_arg != &elipsis && scan_arg != &oldstyle) { + scan_expr->node = argumentpromotion(scan_expr->node, scan_arg->type, scan_arg->qual, 1); + scan_arg = scan_arg->next; + } else { + if (!scan_arg) { + my_list.next = NULL; + my_list.object = OBJ_BASE(obj); + CError_ErrorFuncCall(CErrorStr248, &my_list, nodes); + } + scan_expr->node = CExpr_VarArgPromotion(scan_expr->node, scan_arg == &elipsis); + } + scan_expr = scan_expr->next; + } + + if (scan_arg) { + if (scan_arg != &elipsis && scan_arg != &oldstyle) { + if (!scan_arg->dexpr) { + my_list.next = NULL; + my_list.object = OBJ_BASE(obj); + CError_ErrorFuncCall(CErrorStr248, &my_list, nodes); + scan_arg = NULL; + } + } else { + scan_arg = NULL; + } + } + + return CExpr_GenericCall(objexpr, nodes, tfunc, scan_arg); +} + +ENode *CExpr_GenericPtmfCall(Object *obj, TypeFunc *tfunc, ENodeList *arg_exprs) { + ENodeList *scan_expr; + FuncArg *arg; + + scan_expr = arg_exprs; + arg = tfunc->args; + while (scan_expr) { + if (!arg) { + CError_Error(CErrorStr162); + return nullnode(); + } + + if (arg != &elipsis && arg != &oldstyle) { + scan_expr->node = argumentpromotion(scan_expr->node, arg->type, arg->qual, 1); + arg = arg->next; + } else { + scan_expr->node = CExpr_VarArgPromotion(scan_expr->node, arg == &elipsis); + } + scan_expr = scan_expr->next; + } + + if (arg) { + if (arg != &elipsis && arg != &oldstyle) { + if (!arg->dexpr) { + CError_Error(CErrorStr162); + arg = NULL; + } + } else { + arg = NULL; + } + } + + return CExpr_GenericCall(create_objectrefnode(obj), arg_exprs, tfunc, arg); +} + +static ENode *CExpr_ConvertEMember(ENode *expr) { + ENode *result; + + if (expr->data.emember->list->next || expr->data.emember->templargs) { + result = CExpr_NewENode(EOBJLIST); + result->rtype = OBJECT(expr->data.emember->list->object)->type; + result->data.objlist.list = expr->data.emember->list; + result->data.objlist.templargs = expr->data.emember->templargs; + return result; + } + + if (expr->data.emember->list->object->otype != OT_OBJECT) + return NULL; + return CExpr_MakeObjRefNode(OBJECT(expr->data.emember->list->object), 1); +} + +ENode *CExpr_MakeFunctionCall(ENode *funcexpr, ENodeList *arg_exprs) { + ENode *expr; + TypeFunc *tfunc; + BClassList *save_path; + ENode *save_expr; + Boolean save_1D; + Boolean save_isambig; + + FuncArg *scan_arg; + ENodeList *scan_expr; + Boolean has_varargs; + + if (ENODE_IS(funcexpr, EOBJLIST) && funcexpr->data.objlist.name) { + funcexpr->data.objlist.list = CScope_ArgumentDependentNameLookup( + funcexpr->data.objlist.list, + funcexpr->data.objlist.name, + arg_exprs, 0); + if (!funcexpr->data.objlist.list) { + CError_Error(CErrorStr140, CError_GetNameString(NULL, funcexpr->data.objlist.name)); + return nullnode(); + } + + if ( + funcexpr->data.objlist.list->object->otype == OT_OBJECT && + (TYPE_FUNC(OBJECT(funcexpr->data.objlist.list->object)->type)->flags & FUNC_INTRINSIC) && + (expr = CodeGen_HandleIntrinsicCall(OBJECT(funcexpr->data.objlist.list->object), arg_exprs))) + return expr; + + return CExpr_GenericFuncCall( + NULL, NULL, 0, NULL, + funcexpr->data.objlist.list, + funcexpr->data.objlist.templargs, + arg_exprs, 0, 0, 1); + } + + if (ENODE_IS(funcexpr, EMEMBER)) { + save_path = funcexpr->data.emember->path; + save_expr = funcexpr->data.emember->expr; + save_1D = funcexpr->data.emember->pr_1D; + save_isambig = funcexpr->data.emember->isambig; + funcexpr = CExpr_ConvertEMember(funcexpr); + if (!funcexpr) { + CError_Error(CErrorStr161); + return nullnode(); + } + } else { + save_path = NULL; + save_expr = NULL; + save_1D = 0; + save_isambig = 0; + } + + if (ENODE_IS(funcexpr, EOBJREF) && IS_TYPE_FUNC(funcexpr->data.objref->type) && (TYPE_FUNC(funcexpr->data.objref->type)->flags & FUNC_INTRINSIC)) { + if (!(expr = CodeGen_HandleIntrinsicCall(funcexpr->data.objref, arg_exprs))) { + expr = CExpr_GenericFuncCall( + save_path, save_expr, save_1D, funcexpr->data.objref, + NULL, NULL, + arg_exprs, 0, save_isambig, 1); + } + return expr; + } + + if (ENODE_IS(funcexpr, EOBJLIST)) { + return CExpr_GenericFuncCall( + save_path, save_expr, save_1D, NULL, + funcexpr->data.objlist.list, funcexpr->data.objlist.templargs, + arg_exprs, 0, save_isambig, 1); + } + + if (!IS_TYPE_POINTER_ONLY(funcexpr->rtype) || !IS_TYPE_FUNC((tfunc = TYPE_FUNC(TYPE_POINTER(funcexpr->rtype)->target)))) { + CError_Error(CErrorStr161); + return nullnode(); + } + + if (ENODE_IS(funcexpr, EOBJREF)) { + return CExpr_GenericFuncCall( + save_path, save_expr, save_1D, funcexpr->data.objref, + NULL, NULL, arg_exprs, 0, save_isambig, 1); + } + + scan_expr = arg_exprs; // r25 + scan_arg = tfunc->args; // r26 + has_varargs = 0; + while (scan_expr) { + if (!has_varargs) { + if (!scan_arg) { + CError_Error(CErrorStr162); + return nullnode(); + } + if (scan_arg == &elipsis || scan_arg == &oldstyle) { + scan_expr->node = CExpr_VarArgPromotion(scan_expr->node, scan_arg == &elipsis); + has_varargs = 1; + } else { + scan_expr->node = argumentpromotion(scan_expr->node, scan_arg->type, scan_arg->qual, 1); + scan_arg = scan_arg->next; + } + } else { + scan_expr->node = CExpr_VarArgPromotion(scan_expr->node, 0); + } + scan_expr = scan_expr->next; + } + + if (!has_varargs && scan_arg && scan_arg != &elipsis && scan_arg != &oldstyle) { + do { + if (!scan_arg->dexpr) { + CError_Error(CErrorStr162); + return nullnode(); + } + + if (arg_exprs) { + scan_expr = arg_exprs; + while (scan_expr->next) + scan_expr = scan_expr->next; + scan_expr->next = lalloc(sizeof(ENodeList)); + scan_expr = scan_expr->next; + } else { + scan_expr = lalloc(sizeof(ENodeList)); + arg_exprs = scan_expr; + } + + scan_expr->next = NULL; + scan_expr->node = CExpr_GetDefaultArgument(funcexpr, scan_arg); + } while ((scan_arg = scan_arg->next) && scan_arg != &elipsis && scan_arg != &oldstyle); + } + + expr = CExpr_NewENode(EFUNCCALL); + expr->cost = 4; + expr->rtype = tfunc->functype; + expr->flags = tfunc->qual & ENODE_FLAG_QUALS; + expr->data.funccall.funcref = funcexpr; + expr->data.funccall.args = arg_exprs; + expr->data.funccall.functype = tfunc; + return CExpr_AdjustFunctionCall(expr); +} + +static Boolean accept_conversion_type(Type *type, short mode) { + switch (mode) { + case 0: + return IS_TYPE_INT(type); + case 1: + return IS_TYPE_INT_OR_FLOAT(type); + case 2: + return IS_TYPE_INT_OR_FLOAT(type) || IS_TYPE_POINTER_ONLY(type); + case 3: + return IS_TYPE_POINTER_ONLY(type); + default: + CError_FATAL(3912); + return 0; + } +} + +static ENode *CExpr_OperatorConversion(ENode *expr, Type *type, UInt32 qual) { + if (IS_TYPE_CLASS(expr->rtype) && type) { + if (user_assign_check(expr, type, qual, 1, 0, 1)) + return assign_node; + CError_Error(CErrorStr144); + } + return expr; +} + +static Boolean wild_conversion_check(ENode *left, ENode *right, Conversion *conv) { + ConversionIterator iter; + Object *obj; + + Type *check; + Type *left_type; + Type *right_type; + + left_type = right_type = NULL; + if (IS_TYPE_CLASS(left->rtype)) { + CExpr_ConversionIteratorInit(&iter, TYPE_CLASS(left->rtype)); + while ((obj = CExpr_ConversionIteratorNext(&iter))) { + check = TYPE_FUNC(obj->type)->functype; + if (accept_conversion_type(check, 2)) { + while ((obj = CExpr_ConversionIteratorNext(&iter))) { + if (accept_conversion_type(TYPE_FUNC(obj->type)->functype, 2)) + CError_Error(CErrorStr199); + } + left_type = check; + goto found_left; + } + } + return 0; + } +found_left: + if (IS_TYPE_CLASS(right->rtype)) { + CExpr_ConversionIteratorInit(&iter, TYPE_CLASS(right->rtype)); + while ((obj = CExpr_ConversionIteratorNext(&iter))) { + check = TYPE_FUNC(obj->type)->functype; + if (accept_conversion_type(check, 2)) { + while ((obj = CExpr_ConversionIteratorNext(&iter))) { + if (accept_conversion_type(TYPE_FUNC(obj->type)->functype, 2)) + CError_Error(CErrorStr199); + } + right_type = check; + goto found_right; + } + } + return 0; + } +found_right: + conv->x0 = NULL; + conv->left = CExpr_OperatorConversion(left, left_type, 0); + conv->right = CExpr_OperatorConversion(right, right_type, 0); + return 1; +} + +static Boolean monadic_conversion_check(ENode *expr, short which, Conversion *conv) { + ConversionIterator iter; + Object *obj; + Type *check; + + if (!IS_TYPE_CLASS(expr->rtype)) + return 0; + + if (which == 4) + which = 2; + else if (which == 5) + which = 1; + + CExpr_ConversionIteratorInit(&iter, TYPE_CLASS(expr->rtype)); + while ((obj = CExpr_ConversionIteratorNext(&iter))) { + check = TYPE_FUNC(obj->type)->functype; + if (accept_conversion_type(check, which)) { + while ((obj = CExpr_ConversionIteratorNext(&iter))) { + if (accept_conversion_type(TYPE_FUNC(obj->type)->functype, which)) + CError_Error(CErrorStr199); + } + + conv->x0 = NULL; + conv->left = CExpr_OperatorConversion(expr, check, 0); + conv->right = NULL; + return 1; + } + } + + return 0; +} + +static Boolean is_legal_type_combination(Type *left, Type *right, short mode) { + int left_type; + int right_type; + + if (IS_TYPE_ENUM(left)) + left = TYPE_ENUM(left)->enumtype; + if (IS_TYPE_ENUM(right)) + right = TYPE_ENUM(right)->enumtype; + + if (IS_TYPE_REFERENCE(left)) + left = TYPE_POINTER(left)->target; + if (IS_TYPE_REFERENCE(right)) + right = TYPE_POINTER(right)->target; + + left_type = left->type; // r7 + right_type = right->type; // r8 + switch (mode) { + case 3: + if (left_type != TYPEPOINTER || right_type != TYPEPOINTER) + return 0; + use_cpp_typeequal: + diadic_arg1.type = left; + diadic_arg2.type = right; + return iscpp_typeequal(left, right); + case 7: + if ((left_type == TYPEPOINTER && right_type == TYPEINT) || (left_type == TYPEINT && right_type == TYPEPOINTER)) { + diadic_arg1.type = left; + diadic_arg2.type = right; + return 1; + } + return 0; + case 6: + if ((left_type == TYPEPOINTER && right_type == TYPEINT) || (left_type == TYPEINT && right_type == TYPEPOINTER)) { + diadic_arg1.type = left; + diadic_arg2.type = right; + return 1; + } + case 2: + if (left_type == TYPEPOINTER || right_type == TYPEPOINTER) + goto use_cpp_typeequal; + case 1: + mode1: + if (left_type == TYPEFLOAT || right_type == TYPEFLOAT) { + if (left_type == TYPEFLOAT) { + if (right_type == TYPEFLOAT) { + if (TYPE_INTEGRAL(right)->integral > TYPE_INTEGRAL(left)->integral) + left = right; + diadic_arg2.type = left; + diadic_arg1.type = left; + return 1; + } + if (right_type != TYPEINT) + return 0; + diadic_arg2.type = left; + diadic_arg1.type = left; + return 1; + } + if (left_type != TYPEINT) + return 0; + diadic_arg2.type = right; + diadic_arg1.type = right; + return 1; + } + case 0: + if (left_type != TYPEINT || right_type != TYPEINT) + return 0; + if (TYPE_INTEGRAL(right)->integral > TYPE_INTEGRAL(left)->integral) + left = right; + if (TYPE_INTEGRAL(left)->integral < IT_INT) + left = TYPE(&stsignedint); + diadic_arg2.type = left; + diadic_arg1.type = left; + return 1; + case 4: + if (left_type == TYPEPOINTER) { + if (right_type != TYPEINT) + return 0; + diadic_arg1.type = left; + diadic_arg2.type = right; + return 1; + } + if (right_type == TYPEPOINTER) { + if (left_type != TYPEINT) + return 0; + diadic_arg1.type = left; + diadic_arg2.type = right; + return 1; + } + goto mode1; + case 5: + if (left_type != TYPEPOINTER) + goto mode1; + if (right_type == TYPEPOINTER) + goto use_cpp_typeequal; + if (right_type != TYPEINT) + return 0; + diadic_arg1.type = left; + diadic_arg2.type = right; + return 1; + default: + CError_FATAL(4132); + return 0; + } +} + +static void match_class_type_conversion(Match13 *match, ENode *left, ENode *right, ENodeList *list, short which) { + ConversionIterator iter; + Object *obj; + + if (which == 6) { + if (!ENODE_IS(right, EINTCONST) || !CInt64_IsZero(&right->data.intval) || !IS_TYPE_INT(right->rtype)) + which = 2; + } + + CExpr_ConversionIteratorInit(&iter, TYPE_CLASS(left->rtype)); + while ((obj = CExpr_ConversionIteratorNext(&iter))) { + if (is_legal_type_combination(TYPE_FUNC(obj->type)->functype, right->rtype, which)) { + MatchOverloadFunc(obj, &diadic_arg1, list, match); + if (match->obj == obj) { + cexpr_left_conversion_type = diadic_arg1.type; + cexpr_right_conversion_type = diadic_arg2.type; + } + } + } +} + +static void match_type_class_conversion(Match13 *match, ENode *left, ENode *right, ENodeList *list, short which) { + ConversionIterator iter; + Object *obj; + + if (which == 6) { + if (!ENODE_IS(left, EINTCONST) || !CInt64_IsZero(&left->data.intval) || !IS_TYPE_INT(left->rtype)) + which = 2; + } + + CExpr_ConversionIteratorInit(&iter, TYPE_CLASS(right->rtype)); + while ((obj = CExpr_ConversionIteratorNext(&iter))) { + if (is_legal_type_combination(left->rtype, TYPE_FUNC(obj->type)->functype, which)) { + MatchOverloadFunc(obj, &diadic_arg1, list, match); + if (match->obj == obj) { + cexpr_left_conversion_type = diadic_arg1.type; + cexpr_right_conversion_type = diadic_arg2.type; + } + } + } +} + +static void match_class_class_conversion(Match13 *match, ENode *left, ENode *right, ENodeList *list, short which) { + ConversionIterator iter_left; + ConversionIterator iter_right; + Object *obj_left; + Object *obj_right; + + if (which == 6) + which = 2; + + CExpr_ConversionIteratorInit(&iter_left, TYPE_CLASS(left->rtype)); + while ((obj_left = CExpr_ConversionIteratorNext(&iter_left))) { + CExpr_ConversionIteratorInit(&iter_right, TYPE_CLASS(right->rtype)); + while ((obj_right = CExpr_ConversionIteratorNext(&iter_right))) { + if (is_legal_type_combination(TYPE_FUNC(obj_left->type)->functype, TYPE_FUNC(obj_right->type)->functype, which)) { + MatchOverloadFunc(obj_left, &diadic_arg1, list, match); + if (match->obj == obj_left) { + cexpr_left_conversion_type = diadic_arg1.type; + cexpr_right_conversion_type = diadic_arg2.type; + } + } + } + } +} + +Boolean CExpr_CheckOperatorConversion(short token, ENode *left, ENode *right, ENodeList *list, Conversion *conv) { + Match13 match; + short which; + + switch (token) { + case '*': + if (!right) { + which = 3; + break; + } + case '/': + which = 1; + break; + case '&': + if (!right) + return 0; + case '%': + case '^': + case '|': + case '~': + case TK_SHL: + case TK_SHR: + which = 0; + break; + case '[': + which = 7; + break; + case '+': + which = 4; + break; + case '-': + which = 5; + break; + case '!': + case ':': + case '<': + case '>': + case TK_LESS_EQUAL: + case TK_GREATER_EQUAL: + which = 2; + break; + case TK_LOGICAL_EQ: + case TK_LOGICAL_NE: + which = 6; + break; + case TK_LOGICAL_OR: + case TK_LOGICAL_AND: + return wild_conversion_check(left, right, conv); + default: + return 0; + } + + if (!right) + return monadic_conversion_check(left, which, conv); + + cexpr_left_conversion_type = cexpr_right_conversion_type = NULL; + memclrw(&match, sizeof(Match13)); + + if (IS_TYPE_CLASS(left->rtype)) { + if (IS_TYPE_CLASS(right->rtype)) + match_class_class_conversion(&match, left, right, list, which); + else + match_class_type_conversion(&match, left, right, list, which); + } else { + if (IS_TYPE_CLASS(right->rtype)) + match_type_class_conversion(&match, left, right, list, which); + else + return 0; + } + + if (!match.obj) + return 0; + if (match.list) + CError_OverloadedFunctionError(match.obj, match.list); + + conv->x0 = NULL; + conv->left = CExpr_OperatorConversion(left, cexpr_left_conversion_type, 0); + conv->right = CExpr_OperatorConversion(right, cexpr_right_conversion_type, 0); + return 1; +} + +Boolean CExpr_CheckOperator(short token, ENode *left, ENode *right, Conversion *conv) { + Match13 match; + NameResult pr; + NameResult pr2; + ENode *expr; + Object *obj; + ENodeList *nodes; + HashNameNode *name; + BClassList *path; + EMemberInfo *member; + Object *prev_obj; + NameSpaceObjectList mylist_A8; + NameSpaceObjectList mylist_B0; + + if (!copts.old_argmatch) { + if (token == '(') { + CDecl_CompleteType(left->rtype); + if (IS_TYPE_CLASS(left->rtype) && CScope_FindClassMemberObject(TYPE_CLASS(left->rtype), &pr, + CMangler_OperatorName(token))) { + if (pr.nsol_14 || (pr.obj_10 && pr.obj_10->otype == OT_OBJECT && IS_TYPE_FUNC(OBJECT(pr.obj_10)->type))) { + member = lalloc(sizeof(EMemberInfo)); + memclrw(member, sizeof(EMemberInfo)); + member->path = pr.bcl_18; + member->expr = left; + member->pr_1D = pr.x1D; + if (!pr.nsol_14) { + member->list = galloc(sizeof(NameSpaceObjectList)); + member->list->next = NULL; + member->list->object = pr.obj_10; + } else { + member->list = pr.nsol_14; + } + expr = CExpr_NewENode(EMEMBER); + expr->rtype = &stvoid; + expr->data.emember = member; + tk = lex(); + conv->x0 = checkreference(CExpr_MakeFunctionCall(expr, CExpr_ScanExpressionList(1))); + conv->left = NULL; + conv->right = NULL; + tk = lex(); + return 1; + } else { + CError_FATAL(4371); + } + } + return 0; + } else { + return CExpr_OperatorMatch(token, left, right, conv); + } + } + + if (!IS_TYPE_CLASS(left->rtype)) { + if (!IS_TYPE_ENUM(left->rtype)) { + if (!right) + return 0; + if (!IS_TYPE_CLASS(right->rtype) && !IS_TYPE_ENUM(right->rtype)) + return 0; + } + } else { + CDecl_CompleteType(left->rtype); + } + + memclrw(&match, sizeof(Match13)); + name = CMangler_OperatorName(token); + if (token == '(') { + if (IS_TYPE_CLASS(left->rtype) && CScope_FindClassMemberObject(TYPE_CLASS(left->rtype), &pr2, name)) { + if (pr2.nsol_14 || (pr2.obj_10 && pr2.obj_10->otype == OT_OBJECT && IS_TYPE_FUNC(OBJECT(pr2.obj_10)->type))) { + member = lalloc(sizeof(EMemberInfo)); + memclrw(member, sizeof(EMemberInfo)); + member->path = pr2.bcl_18; + member->expr = left; + member->pr_1D = pr2.x1D; + if (!pr2.nsol_14) { + member->list = galloc(sizeof(NameSpaceObjectList)); + member->list->next = NULL; + member->list->object = pr2.obj_10; + } else { + member->list = pr2.nsol_14; + } + expr = CExpr_NewENode(EMEMBER); + expr->rtype = &stvoid; + expr->data.emember = member; + tk = lex(); + conv->x0 = checkreference(CExpr_MakeFunctionCall(expr, CExpr_ScanExpressionList(1))); + conv->left = NULL; + conv->right = NULL; + tk = lex(); + return 1; + } else { + CError_FATAL(4439); + } + } + return 0; + } + + nodes = lalloc(sizeof(ENodeList)); + nodes->node = left; + if (right) { + nodes->next = lalloc(sizeof(ENodeList)); + nodes->next->node = right; + nodes->next->next = NULL; + } else { + nodes->next = NULL; + } + + obj = NULL; + if (IS_TYPE_CLASS(left->rtype) && CScope_FindClassMemberObject(TYPE_CLASS(left->rtype), &pr2, name)) { + if (pr2.obj_10) { + mylist_B0.next = NULL; + mylist_B0.object = pr2.obj_10; + pr2.nsol_14 = &mylist_B0; + } else { + CError_ASSERT(4470, pr2.nsol_14); + } + + if (token != '=' || (pr2.bcl_18->type == left->rtype && pr2.bcl_18->next == NULL)) { + prev_obj = match.obj; + CExpr_MatchArgList(pr2.nsol_14, NULL, nodes->next, &match, left, 0); + if (prev_obj != match.obj) { + obj = match.obj; + path = pr2.bcl_18; + } + } + } + + if (CScope_FindNonClassObject(cscope_current, &pr2, name)) { + if (pr2.obj_10) { + mylist_A8.next = NULL; + mylist_A8.object = pr2.obj_10; + pr2.nsol_14 = &mylist_A8; + } + } else { + pr2.nsol_14 = NULL; + } + + if (copts.arg_dep_lookup) + pr2.nsol_14 = CScope_ArgumentDependentNameLookup(pr2.nsol_14, name, nodes, 1); + if (pr2.nsol_14) + CExpr_MatchArgList(pr2.nsol_14, NULL, nodes, &match, NULL, 0); + + if (!match.obj) { + if (!IS_TYPE_CLASS(left->rtype) && (!right || !IS_TYPE_CLASS(right->rtype))) + return 0; + return CExpr_CheckOperatorConversion(token, left, right, nodes, conv); + } + + if (!(token == '&' && !right) && (token != ',')) { + if (!IS_TYPE_CLASS(left->rtype) && (!right || !IS_TYPE_CLASS(right->rtype)) && match.xE) + return 0; + if (right && match.xE == 2 && CExpr_CheckOperatorConversion(token, left, right, nodes, conv)) + return 1; + } + + if (match.list) + CError_OverloadedFunctionError(match.obj, match.list); + + if (match.obj == obj) { + conv->x0 = CExpr_GenericFuncCall(path, nodes->node, 0, match.obj, NULL, NULL, nodes->next, 0, 0, 1); + } else { + conv->x0 = CExpr_GenericFuncCall(NULL, NULL, 0, match.obj, NULL, NULL, nodes, 0, 0, 1); + } + + conv->x0 = checkreference(conv->x0); + conv->left = NULL; + conv->right = NULL; + return 1; +} + +ENode *CExpr_ConstructObject(TypeClass *tclass, ENode *addr_expr, ENodeList *args, Boolean flag1, Boolean flag2, Boolean flag3, Boolean flag4, Boolean flag5) { + ENode *expr; + NameSpaceObjectList *ctorlist; + BClassList path; + + CError_ASSERT(4595, IS_TYPE_POINTER_ONLY(addr_expr->rtype)); + + addr_expr = makemonadicnode(addr_expr, EINDIRECT); + addr_expr->rtype = TYPE(tclass); + + if (!flag3 && args && !args->next && args->node->rtype == TYPE(tclass) && !CClass_CopyConstructor(tclass)) { + CError_ASSERT(4605, IS_TYPE_CLASS(addr_expr->rtype)); + expr = makediadicnode(addr_expr, args->node, EASS); + if (!flag1) + expr = getnodeaddress(expr, 0); + return expr; + } + + if ((ctorlist = CClass_Constructor(tclass))) { + if (tclass->flags & CLASS_HAS_VBASES) { + ENodeList *list = lalloc(sizeof(ENodeList)); + list->next = args; + args = list; + list->node = intconstnode(TYPE(&stsignedshort), flag2 != 0); + } + path.next = NULL; + path.type = TYPE(tclass); + expr = CExpr_GenericFuncCall(&path, addr_expr, 0, NULL, ctorlist, NULL, args, !flag5, 0, flag4); + if (ENODE_IS2(expr, EFUNCCALL, EFUNCCALLP)) + expr->rtype = CDecl_NewPointerType(TYPE(tclass)); + if (flag1) { + expr = makemonadicnode(expr, EINDIRECT); + expr->rtype = TYPE(tclass); + } + return expr; + } else { + if (args) { + if (!args->next && ENODE_IS(addr_expr, EINDIRECT)) { + return makediadicnode( + addr_expr, + CExpr_AssignmentPromotion(args->node, TYPE(tclass), 0, 1), + EASS); + } + CError_Error(CErrorStr174); + } + return addr_expr; + } +} + +static ENode *CExpr_DeleteFuncCall(Object *obj, ENode *arg, Type *type, Boolean include_size) { + ENode *expr; + ENodeList *list; + + expr = lalloc(sizeof(ENode)); + expr->type = EFUNCCALL; + expr->cost = 4; + expr->flags = 0; + expr->rtype = &stvoid; + expr->data.funccall.funcref = create_objectrefnode(obj); + expr->data.funccall.functype = TYPE_FUNC(obj->type); + obj->flags |= OBJECT_USED; + + list = lalloc(sizeof(ENodeList)); + list->node = arg; + expr->data.funccall.args = list; + + if (include_size) { + list->next = lalloc(sizeof(ENodeList)); + list->next->node = nullnode(); + CInt64_SetLong(&list->next->node->data.intval, type->size); + list->next->node->rtype = CABI_GetSizeTType(); + list->next->next = NULL; + } else { + list->next = NULL; + } + + return expr; +} + +static ENode *CExpr_CopyPlacementNewArg(ENodeList *list) { + switch (list->node->type) { + case EINDIRECT: + if (!ENODE_IS(list->node->data.monadic, EOBJREF)) + break; + if (list->node->data.monadic->data.objref->datatype != DLOCAL && !is_const_object(list->node->data.monadic->data.objref)) + break; + case EINTCONST: + case EFLOATCONST: + case ESTRINGCONST: + case EOBJREF: + case EARGOBJ: + case ELOCOBJ: + case EOBJLIST: + case EVECTOR128CONST: + return CInline_CopyExpression(list->node, CopyMode0); + } + + switch (list->node->rtype->type) { + default: + CError_FATAL(4726); + case TYPEINT: + case TYPEFLOAT: + case TYPEENUM: + case TYPESTRUCT: + case TYPECLASS: + case TYPEMEMBERPOINTER: + case TYPEPOINTER: + case TYPEOBJCID: + return CExpr_GetETEMPCopy(list->node); + } +} + +static ENode *CExpr_PlacementDeleteCall(Type *type, ENode *expr, Object *obj, Boolean flag1, Boolean flag2) { + ENodeList *list; + Object *funcobj; + ENode *result; + ENodeList *inputarg; + Boolean outflag; + + CError_ASSERT(4752, ENODE_IS(expr, EFUNCCALL) && ENODE_IS(expr->data.funccall.funcref, EOBJREF)); + + funcobj = expr->data.funccall.funcref->data.objref; + CError_ASSERT(4756, IS_TYPE_FUNC(funcobj->type) && TYPE_FUNC(funcobj->type)->args && TYPE_FUNC(funcobj->type)->args->next); + + funcobj = CParser_FindDeallocationObject(type, TYPE_FUNC(funcobj->type)->args->next, flag1, flag2, &outflag); + if (!funcobj) + return NULL; + + result = CExpr_NewENode(EFUNCCALL); + result->type = EFUNCCALL; + result->cost = 4; + result->rtype = &stvoid; + result->data.funccall.funcref = create_objectrefnode(funcobj); + result->data.funccall.functype = TYPE_FUNC(funcobj->type); + funcobj->flags |= OBJECT_USED; + + list = lalloc(sizeof(ENodeList)); + list->node = create_objectnode(obj); + result->data.funccall.args = list; + + CError_ASSERT(4780, (inputarg = expr->data.funccall.args) && (inputarg = inputarg->next)); + + do { + list->next = lalloc(sizeof(ENodeList)); + list = list->next; + list->node = CExpr_CopyPlacementNewArg(inputarg); + inputarg = inputarg->next; + } while (inputarg); + list->next = NULL; + + return result; +} + +static Type *scan_type_name(UInt32 *qual) { + DeclInfo di; + memclrw(&di, sizeof(DeclInfo)); + + CParser_GetDeclSpecs(&di, 0); + di.x46 = 1; + scandeclarator(&di); + + if (di.name) + CError_Error(CErrorStr146); + + firstarrayexpr = di.x24; + *qual = di.qual; + return di.thetype; +} + +static UInt32 cv_qualifier_list(void) { + UInt32 qual; + + qual = 0; + tk = lex(); + while (tk >= TK_CONST && tk <= TK_ASM) { + switch (tk) { + case TK_CONST: + if (qual & Q_CONST) + CError_Error(CErrorStr121); + qual |= Q_CONST; + break; + case TK_VOLATILE: + if (qual & Q_VOLATILE) + CError_Error(CErrorStr121); + qual |= Q_VOLATILE; + break; + default: + CError_Error(CErrorStr121); + } + + tk = lex(); + } + + return qual; +} + +static void scan_new_declarator(DeclInfo *di, Boolean flag) { + NameResult pr; + SInt32 size; + ENode *expr; + + switch (tk) { + case '*': + makethetypepointer(di, cv_qualifier_list()); + if (tk != '[') + scan_new_declarator(di, flag); + break; + case TK_IDENTIFIER: + case TK_COLON_COLON: + if (CScope_ParseQualifiedNameSpace(&pr, 1, 0) && pr.nspace_0 && pr.nspace_0->theclass && tk == '*') { + makememberpointertype(di, pr.nspace_0->theclass, cv_qualifier_list()); + if (tk != '[') + scan_new_declarator(di, flag); + } else { + CError_Error(CErrorStr121); + } + break; + } + + if (tk == '[') { + tk = lex(); + expr = expression(); + + if (IS_TYPE_ENUM(expr->rtype)) + expr->rtype = TYPE_ENUM(expr->rtype)->enumtype; + if (!IS_TYPE_INT(expr->rtype)) + CError_Error(CErrorStr146); + + if (tk != ']') + CError_Error(CErrorStr125); + else + tk = lex(); + + if (tk == '[') + scan_new_declarator(di, 0); + + if (CanCreateObject(di->thetype) && IsCompleteType(di->thetype)) { + di->thetype = CDecl_NewArrayType(di->thetype, 0); + if (!ENODE_IS(expr, EINTCONST)) { + size = 1; + if (!flag) + CError_Error(CErrorStr124); + else + firstarrayexpr = expr; + } else { + size = CInt64_GetULong(&expr->data.intval); + } + TYPE_POINTER(di->thetype)->size = size * TYPE_POINTER(di->thetype)->target->size; + } else { + CError_Error(CErrorStr129); + } + } +} + +static Type *scan_new_type_name(UInt32 *qual) { + DeclInfo di; + memclrw(&di, sizeof(DeclInfo)); + + di.x4F = 1; + CParser_GetDeclSpecs(&di, 0); + scan_new_declarator(&di, 1); + + *qual = di.qual; + return di.thetype; +} + +static ENode *CExpr_NewAlloc(Type *type, ENodeList *args, Boolean flag1, Boolean flag2) { + NameSpaceObjectList *list; + Object *obj; + Boolean found; + HashNameNode *name; + NameResult pr; + + found = 0; + if (!flag1 && IS_TYPE_CLASS(type)) { + list = NULL; + obj = NULL; + name = (flag2 && copts.array_new_delete) ? newa_fobj->name : newp_fobj->name; + if (CScope_FindClassMemberObject(TYPE_CLASS(type), &pr, name)) { + list = pr.nsol_14; + obj = OBJECT(pr.obj_10); + CError_ASSERT(4935, list || obj); + found = 1; + } else if (TYPE_CLASS(type)->flags & CLASS_HANDLEOBJECT) { + CError_ASSERT(4942, !flag2); + obj = newh_func; + found = 1; + } + } + + if (!found) { + if (flag2 && copts.array_new_delete) + list = &newa_fobj->first; + else + list = &newp_fobj->first; + obj = NULL; + } + + return CExpr_GenericFuncCall(NULL, NULL, 0, obj, list, NULL, args, 0, 0, 1); +} + +static ENode *CExpr_NewExceptionSafeAlloc(Type *type, ENode *node, ENodeList *args, Boolean flag1, Boolean flag2, Object **objptr) { + Object *obj; + ENode *result; + ENode *catchexpr; + Object *deletefunc; + Boolean include_size; + + if (!cscope_currentfunc || !copts.delete_exception || !copts.exceptions) + return NULL; + + obj = create_temp_object(TYPE(&void_ptr)); + *objptr = obj; + deletefunc = NULL; + catchexpr = NULL; + include_size = 0; + if (args) + catchexpr = CExpr_PlacementDeleteCall(type, node, obj, flag1, flag2); + if (!args) + deletefunc = CParser_FindDeallocationObject(type, NULL, flag1, flag2, &include_size); + + if (!deletefunc && !catchexpr) + return NULL; + + result = lalloc(sizeof(ENode)); + *result = *node; + node = makediadicnode(create_objectnode(obj), node, EASS); + if (!catchexpr && !include_size) { + result->type = ENEWEXCEPTION; + result->data.newexception.initexpr = node; + result->data.newexception.tryexpr = NULL; + result->data.newexception.pointertemp = obj; + result->data.newexception.deletefunc = deletefunc; + } else { + if (!catchexpr) + catchexpr = CExpr_DeleteFuncCall(deletefunc, create_objectnode(obj), type, include_size); + result->type = EINITTRYCATCH; + result->data.itc.initexpr = node; + result->data.itc.tryexpr = NULL; + result->data.itc.result = create_objectnode(obj); + result->data.itc.catchexpr = catchexpr; + } + + return result; +} + +static ENode *CExpr_NewExceptionSafeInit(ENode *expr, ENode *tryexpr) { + switch (expr->type) { + case ENEWEXCEPTION: + expr->data.newexception.tryexpr = tryexpr; + break; + case EINITTRYCATCH: + expr->data.itc.tryexpr = tryexpr; + break; + default: + CError_FATAL(5056); + } + return expr; +} + +static ENode *CExpr_NewArray(Type *type, UInt32 qual, ENodeList *nodelist, Boolean flag) { + Type *tptr; + Type *sizetype; + Type *innertype; + ENodeList *newlist; + ENode *result; + Object *ctor; + Object *dtor; + ENode *ass; + ENode *etemp; + ENode *mul; + SInt32 count; + ENode *newalloc; + ENode *newESalloc; + Object *tempobj; + ENode *callexpr; + + tptr = CDecl_NewPointerType(TYPE_POINTER(type)->target); + sizetype = CABI_GetSizeTType(); + innertype = TYPE_POINTER(type)->target; + while (IS_TYPE_ARRAY(innertype)) + innertype = TYPE_POINTER(innertype)->target; + + if (!CanAllocObject(innertype) || !IsCompleteType(innertype)) + return nullnode(); + + newlist = lalloc(sizeof(ENodeList)); + newlist->next = nodelist; + if (tk == '(') { + tk = lex(); + if (CExpr_ScanExpressionList(1)) + CError_Error(CErrorStr174); + if (tk == ')') + tk = lex(); + else + CError_Error(CErrorStr115); + } + + if (!IS_TYPE_CLASS(innertype) || CClass_IsPODClass(TYPE_CLASS(innertype))) { + newlist->node = intconstnode(sizetype, type->size); + if (firstarrayexpr) { + newlist->node = makediadicnode(newlist->node, promote(firstarrayexpr, sizetype), EMUL); + optimizecomm(newlist->node); + } + result = CExpr_NewAlloc(innertype, newlist, flag, 1); + result->rtype = tptr; + result->flags |= (qual & ENODE_FLAG_QUALS); + return result; + } + + ctor = NULL; + if (CClass_Constructor(TYPE_CLASS(innertype))) { + ctor = CClass_DefaultConstructor(TYPE_CLASS(innertype)); + if (ctor) { + ctor->flags |= OBJECT_USED; + } else { + ctor = CClass_DummyDefaultConstructor(TYPE_CLASS(innertype)); + if (!ctor) + CError_Error(CErrorStr203); + } + } + + dtor = CClass_Destructor(TYPE_CLASS(innertype)); + if (dtor) + dtor = CABI_GetDestructorObject(dtor, CABIDestroy1); + + ass = NULL; + if (firstarrayexpr) { + etemp = CExpr_NewETEMPNode(sizetype, 1); + mul = promote(firstarrayexpr, sizetype); + if (innertype->size) + count = type->size / innertype->size; + else + count = 0; + if (count > 1) { + mul = makediadicnode(mul, intconstnode(sizetype, count), EMUL); + optimizecomm(mul); + } + ass = makediadicnode(CExpr_DerefETEMPCopy(etemp), mul, EASS); + mul = makediadicnode(CExpr_DerefETEMPCopy(etemp), intconstnode(sizetype, innertype->size), EMUL); + optimizecomm(mul); + mul = makediadicnode(mul, intconstnode(sizetype, 16), EADD); + optimizecomm(mul); + newlist->node = mul; + etemp = CExpr_DerefETEMPCopy(etemp); + } else { + newlist->node = intconstnode(sizetype, type->size + 16); + if (innertype->size) + count = type->size / innertype->size; + else + count = 0; + etemp = intconstnode(sizetype, count); + } + + newalloc = CExpr_NewAlloc(innertype, newlist, flag, 1); + newalloc->rtype = tptr; + newESalloc = CExpr_NewExceptionSafeAlloc(innertype, newalloc, nodelist, 1, flag, &tempobj); + if (newESalloc) { + callexpr = CExpr_FuncCallSix( + cnar_func, + create_objectnode(tempobj), + ctor ? create_objectrefnode(ctor) : nullnode(), + dtor ? create_objectrefnode(dtor) : nullnode(), + intconstnode(sizetype, innertype->size), + etemp, + NULL + ); + result = CExpr_NewExceptionSafeInit(newESalloc, makediadicnode(create_objectnode(tempobj), callexpr, EASS)); + } else { + result = CExpr_FuncCallSix( + cnar_func, + newalloc, + ctor ? create_objectrefnode(ctor) : nullnode(), + dtor ? create_objectrefnode(dtor) : nullnode(), + intconstnode(sizetype, innertype->size), + etemp, + NULL + ); + } + + if (ass) + result = makecommaexpression(ass, result); + result->rtype = tptr; + result->flags |= (qual & ENODE_FLAG_QUALS); + return result; +} + +static ENode *CExpr_NewSimpleClass(TypeClass *tclass, ENode *expr, ENodeList *args) { + ENode *precomp; + ENode *nullcheck; + + precomp = lalloc(sizeof(ENode)); + *precomp = *expr; + precomp->type = EPRECOMP; + precomp->data.precompid = CParser_GetUniqueID(); + + nullcheck = lalloc(sizeof(ENode)); + *nullcheck = *expr; + nullcheck->type = ENULLCHECK; + nullcheck->cost = 4; + nullcheck->data.nullcheck.nullcheckexpr = expr; + nullcheck->data.nullcheck.condexpr = CExpr_ConstructObject(tclass, precomp, args, 0, 1, 1, 1, 1); + nullcheck->data.nullcheck.precompid = precomp->data.precompid; + return nullcheck; +} + +static ENode *CExpr_NewClass(TypeClass *tclass, ENode *expr, ENodeList *args1, ENodeList *args2, Boolean flag) { + Object *objptr; + ENode *newESalloc; + + if (!args2 && !flag && CABI_ConstructorCallsNew(tclass)) { + expr = nullnode(); + expr->rtype = CDecl_NewPointerType(TYPE(tclass)); + return CExpr_ConstructObject(tclass, expr, args1, 0, 1, 1, 1, 1); + } else { + newESalloc = CExpr_NewExceptionSafeAlloc(TYPE(tclass), expr, args2, 0, flag, &objptr); + if (newESalloc) { + return CExpr_NewExceptionSafeInit( + newESalloc, + CExpr_ConstructObject(tclass, create_objectnode(objptr), args1, 0, 1, 1, 1, 1)); + } else { + return CExpr_NewSimpleClass(tclass, expr, args1); + } + } +} + +ENode *scannew(Boolean flag) { + Type *type; // r27 + UInt32 qual; + ENodeList *args; // r28 + Boolean placement_flag; // r26 + ENodeList *newargs; // r26 + ENode *expr; // r26 + ENodeList *args2; // r29 + Object *tempobj; + ENode *newESalloc; // r28 + ENode *tempobj_expr; // r25 + ENode *etemp_expr; // r28 + ENode *indirect_expr; // r25 + ENode *ass; // r25 + ENode *cond; // r27 + + type = NULL; + args = NULL; + firstarrayexpr = NULL; + if ((tk = lex()) == '(') { + tk = lex(); + placement_flag = isdeclaration(1, 1, 1, ')'); + if (!placement_flag) + args = CExpr_ScanExpressionList(1); + if (placement_flag) + type = scan_type_name(&qual); + if (tk != ')') + CError_Error(CErrorStr115); + else + tk = lex(); + } + + if (!type) { + if (tk == '(') { + tk = lex(); + type = scan_type_name(&qual); + if (tk != ')') + CError_Error(CErrorStr115); + else + tk = lex(); + } else { + type = scan_new_type_name(&qual); + } + } + + if (IS_TYPE_ARRAY(type)) + return CExpr_NewArray(type, qual, args, flag); + + if (IS_TYPE_CLASS(type)) { + if (TYPE_CLASS(type)->sominfo) + return CSOM_New(TYPE_CLASS(type)); + if (TYPE_CLASS(type)->objcinfo) + return CObjC_New(TYPE_CLASS(type)); + } + + if (!IsCompleteType(type) || !CanAllocObject(type)) + return nullnode(); + + newargs = lalloc(sizeof(ENodeList)); + newargs->next = args; + newargs->node = intconstnode(CABI_GetSizeTType(), type->size); + + expr = CExpr_NewAlloc(type, newargs, flag, 0); + expr->rtype = CDecl_NewPointerType(type); + expr->flags |= (qual & ENODE_FLAG_QUALS); + + if (tk == '(') { + tk = lex(); + args2 = CExpr_ScanExpressionList(1); + if (!args2 && !IS_TYPE_CLASS(type)) { + args2 = lalloc(sizeof(ENodeList)); + memclrw(args2, sizeof(ENodeList)); + args2->node = do_typecast(nullnode(), type, 0); + } + if (tk == ')') + tk = lex(); + else + CError_Error(CErrorStr115); + } else { + args2 = NULL; + } + + if (ENODE_IS(expr, EINTCONST)) + return expr; + + if (IS_TYPE_CLASS(type) && CClass_Constructor(TYPE_CLASS(type))) + return CExpr_NewClass(TYPE_CLASS(type), expr, args2, args, flag); + + if (args2) { + if (args2->next) { + CError_Error(CErrorStr174); + return nullnode(); + } + + newESalloc = CExpr_NewExceptionSafeAlloc(type, expr, args, 0, flag, &tempobj); + if (newESalloc) { + tempobj_expr = makemonadicnode(create_objectnode(tempobj), EINDIRECT); + tempobj_expr->rtype = type; + tempobj_expr->flags = args2->node->flags & ENODE_FLAG_QUALS; + return CExpr_NewExceptionSafeInit( + newESalloc, + makediadicnode(tempobj_expr, CExpr_AssignmentPromotion(args2->node, type, newESalloc->flags, 1), EASS) + ); + } else { + etemp_expr = CExpr_GetETEMPCopy(expr); + indirect_expr = makemonadicnode(etemp_expr, EINDIRECT); + indirect_expr->rtype = type; + indirect_expr->flags = args2->node->flags & ENODE_FLAG_QUALS; + ass = makediadicnode(indirect_expr, CExpr_AssignmentPromotion(args2->node, type, indirect_expr->flags, 1), EASS); + cond = CExpr_NewENode(ECOND); + cond->cost = 4; + cond->rtype = &stvoid; + cond->data.cond.cond = expr; + cond->data.cond.expr1 = ass; + cond->data.cond.expr2 = nullnode(); + cond = makecommaexpression(cond, etemp_expr); + cond->rtype = etemp_expr->rtype; + cond->flags = etemp_expr->flags; + return cond; + } + } else { + return expr; + } +} + +static ENode *CExpr_DeleteArray(ENode *expr, Type *type, Boolean flag) { + Object *obj; + Object *dtor; + Boolean outflag; + ENode *precomp; + SInt32 precompid; + ENode *tmp; + ENode *result; + + obj = CParser_FindDeallocationObject(type, NULL, 1, flag, &outflag); + + if (!IS_TYPE_CLASS(type) || CClass_IsPODClass(TYPE_CLASS(type))) + return CExpr_DeleteFuncCall(obj, expr, type, outflag); + + dtor = CClass_Destructor(TYPE_CLASS(type)); + if (dtor || outflag) { + if (obj->nspace == cscope_root && !outflag) { + return funccallexpr(dnar_func, expr, dtor ? create_objectrefnode(dtor) : nullnode(), NULL, NULL); + } + return funccallexpr( + dnar3_func, + expr, + dtor ? create_objectrefnode(dtor) : nullnode(), + create_objectrefnode(obj), + intconstnode(TYPE(&stsignedshort), outflag)); + } + + precomp = lalloc(sizeof(ENode)); + *precomp = *expr; + precomp->type = EPRECOMP; + precomp->data.precompid = precompid = CParser_GetUniqueID(); + tmp = CExpr_DeleteFuncCall(obj, makediadicnode(precomp, intconstnode(CABI_GetSizeTType(), 16), ESUB), type, 0); + + result = CExpr_NewENode(ENULLCHECK); + result->rtype = &stvoid; + result->cost = 4; + result->data.nullcheck.nullcheckexpr = expr; + result->data.nullcheck.condexpr = tmp; + result->data.nullcheck.precompid = precompid; + + return result; +} + +ENode *scandelete(Boolean flag) { + Boolean is_array; // r24 + ENode *expr; // r25 + Type *conv_type; // r22 + UInt32 conv_qual; // r23 + Type *innertype; // r23 + Type *t; + Object *obj; + Object *dtor; // r24 + ENode *result_expr; // r24??? + ENode *precomp_orig; // r31 + SInt32 precompid; // r30 + Boolean is_virtual; // r23 + ENode *nc; + ConversionIterator iter; + Boolean outflag; + BClassList path; + + if ((tk = lex()) == '[') { + if ((tk = lex()) != ']') + CError_Error(CErrorStr125); + else + tk = lex(); + is_array = 1; + } else { + is_array = 0; + } + + expr = cast_expression(); + if (!IS_TYPE_POINTER_ONLY(expr->rtype)) { + if (IS_TYPE_CLASS(expr->rtype)) { + conv_type = NULL; + CExpr_ConversionIteratorInit(&iter, TYPE_CLASS(expr->rtype)); + while ((obj = CExpr_ConversionIteratorNext(&iter))) { + if (IS_TYPE_POINTER_ONLY(TYPE_FUNC(obj->type)->functype)) { + if (conv_type) { + CError_Error(CErrorStr199); + break; + } + conv_type = TYPE_FUNC(obj->type)->functype; + conv_qual = TYPE_FUNC(obj->type)->qual; + } + } + if (conv_type) { + if (!copts.old_argmatch) { + expr = CExpr_Convert(expr, conv_type, conv_qual, 1, 1); + } else { + if (user_assign_check(expr, conv_type, conv_qual, 1, 0, 1)) + expr = assign_node; + } + } + } + if (!IS_TYPE_POINTER_ONLY(expr->rtype)) { + CError_Error(CErrorStr146); + return nullnode(); + } + } + + innertype = TYPE_POINTER(expr->rtype)->target; + if (innertype->size == 0) + CDecl_CompleteType(innertype); + + if (IS_TYPE_ARRAY(innertype) && !is_array) + CError_Error(CErrorStr146); + + if (is_array) { + t = innertype; + while (IS_TYPE_ARRAY(t)) + t = TYPE_POINTER(t)->target; + return CExpr_DeleteArray(expr, t, flag); + } + + if (copts.objective_c && CObjC_IsType_id(expr->rtype)) + return CObjC_Delete(NULL, expr); + + if (!IS_TYPE_CLASS(innertype)) { + obj = CParser_FindDeallocationObject(innertype, NULL, 0, flag, &outflag); + CClass_CheckObjectAccess(NULL, obj); + return CExpr_DeleteFuncCall(obj, expr, innertype, outflag); + } + + if (TYPE_CLASS(innertype)->sominfo) + return CSOM_Delete(TYPE_CLASS(innertype), expr); + + if (TYPE_CLASS(innertype)->objcinfo) + return CObjC_Delete(TYPE_CLASS(innertype), expr); + + if (!(TYPE_CLASS(innertype)->flags & CLASS_COMPLETED) && copts.pedantic) + CError_Warning(CErrorStr136, innertype, 0); + + obj = CParser_FindDeallocationObject(innertype, NULL, 0, flag, &outflag); + CClass_CheckObjectAccess(NULL, obj); + dtor = CClass_Destructor(TYPE_CLASS(innertype)); + if (!dtor) + return CExpr_DeleteFuncCall(obj, expr, innertype, outflag); + + path.next = NULL; + path.type = innertype; + CClass_CheckObjectAccess(&path, dtor); + + result_expr = lalloc(sizeof(ENode)); + result_expr->type = EFUNCCALL; + result_expr->cost = 4; + result_expr->flags = 0; + result_expr->rtype = &stvoid; + if (dtor->datatype == DVFUNC) { + precomp_orig = expr; + expr = lalloc(sizeof(ENode)); + *expr = *precomp_orig; + expr->type = EPRECOMP; + expr->data.precompid = precompid = CParser_GetUniqueID(); + is_virtual = 1; + } else { + is_virtual = 0; + } + + if (!flag) { + result_expr = CABI_DestroyObject(dtor, expr, 2, 0, 1); + } else { + CError_ASSERT(5650, !outflag); + result_expr = CABI_DestroyObject(dtor, expr, 2, 0, 0); + result_expr->rtype = TYPE(&void_ptr); + result_expr = funccallexpr(obj, result_expr, NULL, NULL, NULL); + obj->flags |= OBJECT_USED; + } + + if (is_virtual) { + nc = lalloc(sizeof(ENode)); + nc->type = ENULLCHECK; + nc->rtype = &stvoid; + nc->cost = 4; + nc->flags = 0; + nc->data.nullcheck.nullcheckexpr = precomp_orig; + nc->data.nullcheck.condexpr = result_expr; + nc->data.nullcheck.precompid = precompid; + return nc; + } else { + return result_expr; + } +} diff --git a/compiler_and_linker/FrontEnd/C/CExprConvMatch.c b/compiler_and_linker/FrontEnd/C/CExprConvMatch.c new file mode 100644 index 0000000..5cc145f --- /dev/null +++ b/compiler_and_linker/FrontEnd/C/CExprConvMatch.c @@ -0,0 +1,2518 @@ +#include "compiler/CExpr.h" +#include "compiler/CABI.h" +#include "compiler/CClass.h" +#include "compiler/CDecl.h" +#include "compiler/CError.h" +#include "compiler/CInt64.h" +#include "compiler/CFunc.h" +#include "compiler/CMachine.h" +#include "compiler/CMangler.h" +#include "compiler/CObjC.h" +#include "compiler/CParser.h" +#include "compiler/CScope.h" +#include "compiler/CTemplateFunc.h" +#include "compiler/CodeGen.h" +#include "compiler/CompilerTools.h" +#include "compiler/objects.h" +#include "compiler/scopes.h" +#include "compiler/templates.h" + +#ifdef __MWERKS__ +#pragma options align=mac68k +#endif +typedef struct StandardConv { + Type *type1; + Type *type2; + UInt32 qual1; + UInt32 qual2; + Boolean x10; // unknown + Boolean x11; + Boolean x12; + Boolean x13; + Boolean x14; + Boolean x15; +} StandardConv; + +typedef enum EImplicitConvType { + ICT_0, + ICT_1, + ICT_2, + ICT_3 +} EImplicitConvType; + +typedef struct ImplicitConv { + EImplicitConvType type; + union { + struct { + Object *x2; + StandardConv standardConv; + } ic2; + struct { + StandardConv standardConv; + } ic3; + } u; +} ImplicitConv; + +typedef struct ConversionTypeList { + struct ConversionTypeList *next; + Object *func; + Type *type; + UInt32 qual; +} ConversionTypeList; + +typedef struct Match { + struct Match *next; + Object *object; + Object *specialfunc; + Type *type; + UInt32 qual; + Type *type2; + UInt32 qual2; + ImplicitConv conv[3]; +} Match; +#ifdef __MWERKS__ +#pragma options align=reset +#endif + +// forward decls +static ENode *CExpr_DerivedToBase(ENode *expr, Type *type2, UInt32 qual2, Boolean flag1, Boolean flag2, Boolean flag3); + +static Type *CExpr_GetImplictObjectParamType(Object *object, UInt32 *qual) { + Type *type; + + CError_ASSERT(98, IS_TYPE_FUNC(object->type)); + CError_ASSERT(99, TYPE_FUNC(object->type)->flags & FUNC_METHOD); + CError_ASSERT(100, !TYPE_METHOD(object->type)->is_static); + CError_ASSERT(101, TYPE_METHOD(object->type)->args); + + type = CDecl_NewRefPointerType(TYPE(TYPE_METHOD(object->type)->theclass)); + *qual = TYPE_METHOD(object->type)->args->qual & Q_CV; + return type; +} + +static Type *CExpr_GetParamType(Object *object, int index, UInt32 *qual) { + FuncArg *arg; + + CError_ASSERT(120, IS_TYPE_FUNC(object->type)); + CError_ASSERT(121, arg = TYPE_FUNC(object->type)->args); + if (IS_TYPEFUNC_NONSTATIC_METHOD(TYPE_FUNC(object->type))) + CError_ASSERT(125, arg = arg->next); + + while (index > 0) { + CError_ASSERT(129, arg = arg->next); + index--; + } + + *qual = arg->qual & Q_CV; + return arg->type; +} + +static Boolean CExpr_HasNParams(Object *object, int count) { + FuncArg *arg; + int i; + + CError_ASSERT(146, IS_TYPE_FUNC(object->type)); + CError_ASSERT(147, arg = TYPE_FUNC(object->type)->args); + if (IS_TYPEFUNC_NONSTATIC_METHOD(TYPE_FUNC(object->type))) + arg = arg->next; + + i = 0; + while (arg) { + arg = arg->next; + i++; + } + + return i == count; +} + +typedef enum TypeCompareMode { + TCM_0, + TCM_1, + TCM_2 +} TypeCompareMode; + +static Boolean CExpr_TypeCompare(Type *typeA, UInt32 qualA, Type *typeB, UInt32 qualB, TypeCompareMode mode) { + if (typeA->type != typeB->type) + return 0; + + switch (mode) { + case TCM_0: + while (1) { + switch (typeA->type) { + case TYPEPOINTER: + typeA = TPTR_TARGET(typeA); + typeB = TPTR_TARGET(typeB); + if (typeA->type != typeB->type) + return 0; + continue; + + case TYPEMEMBERPOINTER: + if (!is_typesame(TYPE_MEMBER_POINTER(typeA)->ty2, TYPE_MEMBER_POINTER(typeB)->ty2)) + return 0; + typeA = TYPE_MEMBER_POINTER(typeA)->ty1; + typeB = TYPE_MEMBER_POINTER(typeB)->ty1; + if (typeA->type != typeB->type) + return 0; + continue; + } + break; + } + break; + + case TCM_1: + switch (typeA->type) { + case TYPEPOINTER: + if ((qualA & Q_CV) != (qualB & Q_CV)) + return 0; + + typeA = TPTR_TARGET(typeA); + typeB = TPTR_TARGET(typeB); + break; + + case TYPEMEMBERPOINTER: + if ((qualA & Q_CV) != (qualB & Q_CV)) + return 0; + + if (!is_typesame(TYPE_MEMBER_POINTER(typeA)->ty2, TYPE_MEMBER_POINTER(typeB)->ty2)) + return 0; + typeA = TYPE_MEMBER_POINTER(typeA)->ty1; + typeB = TYPE_MEMBER_POINTER(typeB)->ty1; + break; + } + break; + + case TCM_2: + if ((qualA & Q_CV) != (qualB & Q_CV)) + return 0; + break; + } + + return is_typesame(typeA, typeB); +} + +static int CExpr_IsReferenceCompatible(Type *typeA, UInt32 qualA, Type *typeB, UInt32 qualB) { + if (CParser_IsSameOrMoreCVQualified(CParser_GetCVTypeQualifiers(typeA, qualA), CParser_GetCVTypeQualifiers(typeB, qualB))) { + if (CExpr_TypeCompare(typeA, qualA, typeB, qualB, TCM_1)) + return 1; + + if (IS_TYPE_CLASS(typeB) && IS_TYPE_CLASS(typeA)) { + short depth; + Boolean isambigbase; + if (CClass_GetBasePath(TYPE_CLASS(typeB), TYPE_CLASS(typeA), &depth, &isambigbase)) + return 2; + } + } + + return 0; +} + +static Boolean CExpr_IsBaseOf(TypeClass *baseclass, TypeClass *superclass) { + ClassList *base; + + for (base = superclass->bases; base; base = base->next) { + if (base->base == baseclass || CExpr_IsBaseOf(baseclass, base->base)) + return 1; + } + + return 0; +} + +static Boolean CExpr_IsBetterClassConversion(TypeClass *a, TypeClass *b, TypeClass *c, TypeClass *d) { + if (a == c) + return CExpr_IsBaseOf(d, b); + if (b == d) + return CExpr_IsBaseOf(a, c); + return 0; +} + +CW_INLINE Boolean Inline_501D40(Type *a, Type *b) { + return (a == TYPE(&stbool)) && (IS_TYPE_POINTER_ONLY(b) || IS_TYPE_MEMBERPOINTER(b)); +} + +static Boolean CExpr_IsBetterStandardConv(StandardConv *a, StandardConv *b) { + Boolean flag10; + Boolean flag3; + + flag10 = 1; + flag3 = 0; + + if (b->x11) { + if (!a->x11) + flag3 = 1; + } else { + if (a->x11) + flag10 = 0; + } + + if (b->x12) { + if (!a->x12) + flag3 = 1; + } else { + if (a->x12) + flag10 = 0; + } + + if (b->x13) { + if (a->x13) { + if (Inline_501D40(b->type2, b->type1)) { + if (!Inline_501D40(a->type2, a->type1)) + return 1; + } else { + if (Inline_501D40(a->type2, a->type1)) + return 0; + } + } else { + flag3 = 1; + } + } else { + if (a->x13) + flag10 = 0; + } + + if (flag10 && flag3) + return 1; + + if (!a->x13) { + if (b->x13) + return 1; + + if (a->x12) { + if (!b->x12) + return 0; + } else { + if (b->x12) + return 1; + } + } else { + if (!b->x13) + return 0; + } + + if ( + IS_TYPE_POINTER_ONLY(a->type1) && + IS_TYPE_CLASS(TPTR_TARGET(a->type1)) && + IS_TYPE_POINTER_ONLY(a->type2) && + IS_TYPE_POINTER_ONLY(b->type1) && + IS_TYPE_CLASS(TPTR_TARGET(b->type1)) && + IS_TYPE_POINTER_ONLY(b->type2) + ) + { + if (TPTR_TARGET(b->type2) == &stvoid) { + if (TPTR_TARGET(a->type2) == &stvoid) { + if (CExpr_IsBaseOf(TYPE_CLASS(TPTR_TARGET(a->type1)), TYPE_CLASS(TPTR_TARGET(b->type1)))) + return 1; + } else { + if (TPTR_TARGET(a->type1) == TPTR_TARGET(b->type1) && IS_TYPE_CLASS(TPTR_TARGET(a->type2))) + return 1; + } + } else if (IS_TYPE_CLASS(TPTR_TARGET(a->type2)) && IS_TYPE_CLASS(TPTR_TARGET(b->type2))) { + if (CExpr_IsBetterClassConversion( + TYPE_CLASS(TPTR_TARGET(a->type1)), + TYPE_CLASS(TPTR_TARGET(a->type2)), + TYPE_CLASS(TPTR_TARGET(b->type1)), + TYPE_CLASS(TPTR_TARGET(b->type2)) + )) + return 1; + } + } + + if ( + IS_TYPE_CLASS(a->type1) && + IS_TYPE_CLASS(a->type2) && + IS_TYPE_CLASS(b->type1) && + IS_TYPE_CLASS(b->type2) && + CExpr_IsBetterClassConversion( + TYPE_CLASS(a->type1), + TYPE_CLASS(a->type2), + TYPE_CLASS(b->type1), + TYPE_CLASS(b->type2) + ) + ) + return 1; + + if ( + IS_TYPE_MEMBERPOINTER(a->type1) && + IS_TYPE_MEMBERPOINTER(a->type2) && + IS_TYPE_MEMBERPOINTER(b->type1) && + IS_TYPE_MEMBERPOINTER(b->type2) && + IS_TYPE_CLASS(TYPE_MEMBER_POINTER(a->type1)->ty2) && + IS_TYPE_CLASS(TYPE_MEMBER_POINTER(a->type2)->ty2) && + IS_TYPE_CLASS(TYPE_MEMBER_POINTER(b->type1)->ty2) && + IS_TYPE_CLASS(TYPE_MEMBER_POINTER(b->type2)->ty2) && + CExpr_IsBetterClassConversion( + TYPE_CLASS(TYPE_MEMBER_POINTER(b->type1)->ty2), + TYPE_CLASS(TYPE_MEMBER_POINTER(b->type2)->ty2), + TYPE_CLASS(TYPE_MEMBER_POINTER(a->type1)->ty2), + TYPE_CLASS(TYPE_MEMBER_POINTER(a->type2)->ty2) + ) + ) + return 1; + + if ( + a->x14 && + b->x14 && + CExpr_TypeCompare(a->type2, a->qual2, b->type2, b->qual2, TCM_1) && + CParser_IsMoreCVQualified( + CParser_GetTypeQualifiers(b->type2, b->qual2), + CParser_GetTypeQualifiers(a->type2, a->qual2) + ) + ) + return 1; + + return 0; +} + +static Boolean CExpr_IsBetterImplicitConv(ImplicitConv *a, ImplicitConv *b) { + if (a->type > b->type) + return 1; + if (a->type != b->type) + return 0; + + if (a->type == ICT_3) + return CExpr_IsBetterStandardConv(&a->u.ic3.standardConv, &b->u.ic3.standardConv); + + if (a->type == ICT_2 && a->u.ic2.x2 == b->u.ic2.x2 && CExpr_IsBetterStandardConv(&a->u.ic2.standardConv, &b->u.ic2.standardConv)) + return 1; + + return 0; +} + +typedef enum SSCRMode { + SSCR_0, + SSCR_1, + SSCR_2 +} SSCRMode; + +static Boolean CExpr_SetupStandardConversionResult(ENode *expr, Type *type2, UInt32 qual2, SSCRMode mode, Boolean x14, Boolean refFlag, StandardConv *result) { + UInt32 cv1; + UInt32 cv2; + + if (x14) { + if (!CParser_IsConst(type2, qual2)) { + if (!refFlag && !CExpr_IsLValue(expr)) + return 0; + if (mode != SSCR_0 && !IS_TYPE_CLASS(type2)) + return 0; + } + + cv2 = CParser_GetTypeQualifiers(type2, qual2) & Q_CV; + cv1 = CParser_GetTypeQualifiers(expr->rtype, ENODE_QUALS(expr)) & Q_CV; + if (cv2 != cv1 && !CParser_IsMoreCVQualified(cv2, cv1)) + return 0; + } + + memclrw(result, sizeof(StandardConv)); + result->type2 = type2; + result->qual2 = qual2; + result->type1 = expr->rtype; + result->qual1 = ENODE_QUALS(expr); + result->x14 = x14; + + switch (mode) { + case SSCR_0: + break; + case SSCR_1: + result->x12 = 1; + break; + case SSCR_2: + result->x13 = 1; + break; + default: + CError_FATAL(581); + } + + return 1; +} + +typedef enum MysteryEnum { + ME_0, + ME_1, + ME_255 = 255 +} MysteryEnum; + +CW_INLINE MysteryEnum Inline_501FF0(UInt32 qual1, UInt32 qual2) { + if ((qual1 & Q_CV) == (qual2 & Q_CV)) + return ME_0; + + if (((qual2 & Q_CONST) && !(qual1 & Q_CONST)) || ((qual2 & Q_VOLATILE) && !(qual1 & Q_VOLATILE))) + return ME_255; + + return ME_1; +} + +static Boolean CExpr_SetQualConversionResult(Type *type1, UInt32 qual1, Type *type2, UInt32 qual2, StandardConv *result) { + Boolean flag = 1; + UInt32 cv1; + UInt32 cv2; + + while (1) { + cv1 = CParser_GetCVTypeQualifiers(type1, qual1); + cv2 = CParser_GetCVTypeQualifiers(type2, qual2); + + switch (Inline_501FF0(cv1, cv2)) { + case ME_0: + break; + + case ME_1: + result->x11 = 1; + if (!flag) + return 0; + break; + + default: + return 0; + } + + if (!(cv1 & Q_CONST)) + flag = 0; + + if (IS_TYPE_POINTER_ONLY(type1)) { + CError_ASSERT(635, IS_TYPE_POINTER_ONLY(type2)); + type1 = TPTR_TARGET(type1); + type2 = TPTR_TARGET(type2); + } else { + if (!IS_TYPE_MEMBERPOINTER(type1)) + return 1; + + CError_ASSERT(642, IS_TYPE_MEMBERPOINTER(type2)); + type1 = TYPE_MEMBER_POINTER(type1)->ty1; + type2 = TYPE_MEMBER_POINTER(type2)->ty1; + } + } +} + +static Boolean CExpr_OverloadFuncMatch(NameSpaceObjectList *list, TemplArg *templargs, Type *type, ENode **outExpr) { + Object *object; + TemplFuncInstance *inst; + ENode *expr; + FuncArg *arg; + int i; + ObjectList *objlist; + Object *object26; + ObjectList *objlist25; + ObjectList *objlist24; + Boolean flag23; + + if (!IS_TYPE_POINTER_ONLY(type) || !IS_TYPE_FUNC(type = TPTR_TARGET(type))) + return 0; + + object26 = NULL; + objlist25 = NULL; + objlist24 = NULL; + flag23 = 0; + + while (list) { + object = OBJECT(list->object); + if (object->otype == OT_OBJECT) { + if (IS_TEMPL_FUNC(object->type)) { + if (!flag23 && CTempl_CanDeduceFunc(object, TYPE_FUNC(type), templargs)) { + CError_ASSERT(685, inst = CTempl_DeduceFunc(object, TYPE_FUNC(type), templargs, NULL, 0)); + if (is_typesame(inst->object->type, type)) { + objlist = lalloc(sizeof(ObjectList)); + objlist->next = objlist24; + objlist->object = object; + objlist24 = objlist; + + if (object26 && object26 != inst->object) { + objlist = lalloc(sizeof(ObjectList)); + objlist->next = objlist25; + objlist->object = inst->object; + objlist25 = objlist; + } else { + object26 = inst->object; + } + } + } + } else if (is_typesame(object->type, type)) { + if (object26 && flag23) { + Object *checkA, *checkB; + checkA = object; + if (checkA->datatype == DALIAS) + checkA = checkA->u.alias.object; + checkB = object26; + if (checkB->datatype == DALIAS) + checkB = checkB->u.alias.object; + if (checkA != checkB) { + objlist = lalloc(sizeof(ObjectList)); + objlist->next = objlist25; + objlist->object = object; + objlist25 = objlist; + } + } else { + objlist25 = NULL; + object26 = object; + } + flag23 = 1; + } + } + list = list->next; + } + + if (object26) { + if (outExpr) { + if (objlist25) { + i = 0; + for (arg = TYPE_FUNC(object->type)->args; arg; arg = arg->next) + i++; + + if (!flag23 && (object = CTempl_PartialOrdering(objlist24->object, objlist24->next, i))) { + CError_ASSERT(741, inst = CTempl_DeduceFunc(object, TYPE_FUNC(type), templargs, NULL, 0)); + object26 = inst->object; + } else { + CError_OverloadedFunctionError(object26, objlist25); + } + } + + expr = CExpr_MakeObjRefNode(object26, 1); + *outExpr = expr; + expr->rtype = CDecl_NewPointerType(object26->type); + expr->flags = object->qual & ENODE_FLAG_QUALS; + object26->flags |= OBJECT_USED; + if (object26->datatype == DINLINEFUNC) + CError_Error(CErrorStr175); + } + + return 1; + } + + return 0; +} + +static Boolean CExpr_StandardConversionMatch(ENode *expr, Type *type2, UInt32 qual2, Boolean x14, StandardConv *result) { + Type *type1; + UInt32 qual1; + Boolean refFlag; + Type *inner2; + Type *inner1; + SSCRMode mode; + NameSpaceObjectList list; + + if (IS_TYPE_REFERENCE(type2)) { + type2 = TPTR_TARGET(type2); + if (IS_TYPE_POINTER_ONLY(type2)) + expr = pointer_generation(expr); + refFlag = 1; + } else { + if ( + (IS_TYPE_ARRAY(expr->rtype) && !IS_TYPE_ARRAY(type2)) || + (IS_TYPE_FUNC(expr->rtype) && !IS_TYPE_FUNC(type2)) + ) + expr = pointer_generation(expr); + refFlag = 0; + } + + type1 = expr->rtype; + qual1 = ENODE_QUALS(expr); + + if (IS_TYPE_POINTER_ONLY(type2)) { + if (ENODE_IS(expr, EINTCONST) && CInt64_IsZero(&expr->data.intval)) { + if (IS_TYPE_INT(type1) || (!copts.cplusplus && IS_TYPE_ENUM(type1))) + return CExpr_SetupStandardConversionResult(expr, type2, qual2, SSCR_2, x14, refFlag, result); + } + + if ( + IS_TYPE_INT(expr->rtype) && + ENODE_IS_INDIRECT_TO(expr, EOBJREF) && + (expr->data.monadic->data.objref->qual & Q_INLINE_DATA) && + CInt64_IsZero(&expr->data.monadic->data.objref->u.data.u.intconst) + ) + return CExpr_SetupStandardConversionResult(expr, type2, qual2, SSCR_2, x14, refFlag, result); + + if (ENODE_IS(expr, EOBJLIST)) + return CExpr_OverloadFuncMatch(expr->data.objlist.list, expr->data.objlist.templargs, type2, NULL) && + CExpr_SetupStandardConversionResult(expr, type2, qual2, SSCR_0, refFlag, x14, result); + + if (ENODE_IS(expr, EOBJREF) && IS_TEMPL_FUNC(expr->data.objref->type)) { + list.next = NULL; + list.object = OBJ_BASE(expr->data.objref); + return CExpr_OverloadFuncMatch(&list, NULL, type2, NULL) && + CExpr_SetupStandardConversionResult(expr, type2, qual2, SSCR_0, refFlag, x14, result); + } + + if (IS_TYPE_POINTER_ONLY(type1)) { + if ( + ENODE_IS(expr, ESTRINGCONST) && + TPTR_TARGET(type2) == TPTR_TARGET(type1) && + !(qual2 & Q_CONST) && + ( + TPTR_TARGET(type2) == TYPE(&stchar) || + TPTR_TARGET(type2) == TYPE(&stunsignedchar) || + TPTR_TARGET(type2) == CParser_GetWCharType() + ) + ) + { + if ( + CExpr_SetupStandardConversionResult(expr, type2, qual2, SSCR_0, refFlag, x14, result) && + CExpr_SetQualConversionResult(TPTR_TARGET(type2), qual2, TPTR_TARGET(type1), qual1 & ~Q_CONST, result) + ) + { + result->x11 = 1; + return 1; + } else { + return 0; + } + } + + if (copts.objective_c && CObjC_IsCompatibleType(expr->rtype, type2)) + return CExpr_SetupStandardConversionResult(expr, type2, qual2, SSCR_2, x14, refFlag, result); + + if (IS_TYPE_VOID(TPTR_TARGET(type2)) || (!copts.cplusplus && IS_TYPE_VOID(TPTR_TARGET(type1)))) { + if (CExpr_SetupStandardConversionResult(expr, type2, qual2, IS_TYPE_VOID(TPTR_TARGET(type1)) ? SSCR_0 : SSCR_2, refFlag, x14, result)) { + switch (Inline_501FF0(qual2, CParser_GetCVTypeQualifiers(TPTR_TARGET(type1), qual1))) { + case ME_1: + result->x11 = 1; + case ME_0: + return 1; + default: + return 0; + } + } else { + return 0; + } + } + + inner2 = TPTR_TARGET(type2); + inner1 = TPTR_TARGET(type1); + while (1) { + if (inner2->type != inner1->type) + break; + + switch (inner2->type) { + case TYPEPOINTER: + inner2 = TPTR_TARGET(inner2); + inner1 = TPTR_TARGET(inner1); + continue; + case TYPEMEMBERPOINTER: + if (!is_typesame(TYPE_MEMBER_POINTER(inner2)->ty2, TYPE_MEMBER_POINTER(inner1)->ty2)) + break; + + inner2 = TYPE_MEMBER_POINTER(inner2)->ty1; + inner1 = TYPE_MEMBER_POINTER(inner1)->ty1; + if (!IS_TYPE_POINTER_ONLY(inner2) && !IS_TYPE_MEMBERPOINTER(inner2)) { + if (!is_memberpointerequal(inner2, inner1)) + break; + + if (CExpr_SetupStandardConversionResult(expr, type2, qual2, SSCR_0, refFlag, x14, result)) + return CExpr_SetQualConversionResult(TPTR_TARGET(type2), qual2, TPTR_TARGET(type1), qual1, result); + else + return 0; + } + continue; + default: + if (!is_typesame(inner2, inner1)) + break; + + if (CExpr_SetupStandardConversionResult(expr, type2, qual2, SSCR_0, refFlag, x14, result)) + return CExpr_SetQualConversionResult(TPTR_TARGET(type2), qual2, TPTR_TARGET(type1), qual1, result); + else + return 0; + } + + break; + } + + if (IS_TYPE_CLASS(TPTR_TARGET(type2)) && IS_TYPE_CLASS(TPTR_TARGET(type1))) { + short depth; + Boolean isambigbase; + if (CClass_GetBasePath(TYPE_CLASS(TPTR_TARGET(type1)), TYPE_CLASS(TPTR_TARGET(type2)), &depth, &isambigbase)) { + if (CExpr_SetupStandardConversionResult(expr, type2, qual2, SSCR_2, refFlag, x14, result)) + return CExpr_SetQualConversionResult(TPTR_TARGET(type2), qual2, TPTR_TARGET(type1), qual1, result); + else + return 0; + } + } + } + + if (copts.mpwc_relax && !copts.cplusplus && IS_TYPE_POINTER_ONLY(type1)) { + if (CExpr_SetupStandardConversionResult(expr, type2, qual2, SSCR_2, refFlag, x14, result)) + return 1; + } + + return 0; + } + + if (is_typesame(type2, type1)) + return CExpr_SetupStandardConversionResult(expr, type2, qual2, SSCR_0, refFlag, x14, result); + + if (type2 == TYPE(&stbool)) { + switch (type1->type) { + case TYPEINT: + case TYPEFLOAT: + case TYPEENUM: + case TYPEMEMBERPOINTER: + case TYPEPOINTER: + return CExpr_SetupStandardConversionResult(expr, type2, qual2, SSCR_2, refFlag, x14, result); + default: + return 0; + } + } + + if (IS_TYPE_MEMBERPOINTER(type2)) { + if (ENODE_IS(expr, EINTCONST) && CInt64_IsZero(&expr->data.intval)) { + if (IS_TYPE_INT(type1) || (!copts.cplusplus && IS_TYPE_ENUM(type1))) + return CExpr_SetupStandardConversionResult(expr, type2, qual2, SSCR_2, refFlag, x14, result); + } + + if (ENODE_IS(expr, EMEMBER)) { + expr = getpointertomemberfunc(expr, type2, 0); + type1 = expr->rtype; + } + + if (IS_TYPE_MEMBERPOINTER(type1)) { + short depth; + Boolean isambigbase; + + CError_ASSERT(996, IS_TYPE_CLASS(TYPE_MEMBER_POINTER(type2)->ty2) && IS_TYPE_CLASS(TYPE_MEMBER_POINTER(type1)->ty2)); + if (!is_memberpointerequal(TYPE_MEMBER_POINTER(type2)->ty1, TYPE_MEMBER_POINTER(type1)->ty1)) + return 0; + + if ( + TYPE_MEMBER_POINTER(type2)->ty2 == TYPE_MEMBER_POINTER(type1)->ty2 || + CClass_GetBasePath(TYPE_CLASS(TYPE_MEMBER_POINTER(type2)->ty2), TYPE_CLASS(TYPE_MEMBER_POINTER(type1)->ty2), &depth, &isambigbase) + ) + { + if (CExpr_SetupStandardConversionResult(expr, type2, qual2, SSCR_2, refFlag, x14, result)) + return CExpr_SetQualConversionResult(TYPE_MEMBER_POINTER(type2)->ty1, qual2, TYPE_MEMBER_POINTER(type1)->ty1, qual1, result); + else + return 0; + } + } + + return 0; + } + + mode = SSCR_2; + switch (type1->type) { + case TYPEINT: + switch (type2->type) { + case TYPEINT: + if (TYPE_INTEGRAL(type1)->integral < IT_INT) { + if (type2 == TYPE(&stsignedint)) { + if (type1->size < type2->size || !is_unsigned(type1)) + mode = SSCR_1; + } else if (type2 == TYPE(&stunsignedint)) { + if (type2->size == type1->size && is_unsigned(type1)) + mode = SSCR_1; + } + } + break; + case TYPEFLOAT: + break; + case TYPEENUM: + if (copts.cplusplus) + return 0; + break; + default: + return 0; + } + break; + + case TYPEFLOAT: + switch (type2->type) { + case TYPEINT: + break; + case TYPEFLOAT: + if (type2 == TYPE(&stdouble)) { + if (type1 == TYPE(&stfloat) || type1 == TYPE(&stshortdouble)) + mode = SSCR_1; + } + break; + case TYPEENUM: + if (copts.cplusplus) + return 0; + break; + default: + return 0; + } + break; + + case TYPEENUM: + switch (type2->type) { + case TYPEINT: + if (TYPE_INTEGRAL(TYPE_ENUM(expr->rtype)->enumtype)->integral < IT_INT) { + if (type1->size == type2->size && is_unsigned(TYPE_ENUM(type1)->enumtype)) { + if (type2 == TYPE(&stunsignedint)) + mode = SSCR_1; + } else { + if (type2 == TYPE(&stsignedint)) + mode = SSCR_1; + } + } else { + if (TYPE_ENUM(type1)->enumtype == type2) + mode = SSCR_1; + } + break; + case TYPEFLOAT: + break; + case TYPEENUM: + if (copts.cplusplus) + return 0; + break; + default: + return 0; + } + break; + + case TYPECLASS: { + short depth; + Boolean isambigbase; + + if (!IS_TYPE_CLASS(type1) || !CClass_GetBasePath(TYPE_CLASS(type1), TYPE_CLASS(type2), &depth, &isambigbase)) + return 0; + break; + } + + default: + return 0; + } + + return CExpr_SetupStandardConversionResult(expr, type2, qual2, mode, refFlag, x14, result); +} + +static ENode *CExpr_UserConversion(ENode *expr, Type *type2, UInt32 qual2, ImplicitConv *result, Boolean flag1, Boolean isExplicit, Boolean flag3) { + Object *object28; + Object *object27; + Object *object26; + ObjectList *objlist25; + ObjectList *objlist24; + ObjectList *objlist; + TypeFunc *tfunc23; + Type *tmptype23; + NameSpaceObjectList *list22; + Boolean flag22; + Boolean flag21; + FuncArg *arg21; + Boolean flag20; + ENode *newExpr; + ENode *funcref; + ENode *tmpExpr; + ENodeList *arglist; + UInt32 q1; + UInt32 q2; + StandardConv sc3; + StandardConv sc2; + StandardConv sc1; + ConversionIterator convIter; + ENodeList myarglist; + ObjectList myobjlist; + BClassList path; + + object28 = NULL; + object27 = NULL; + objlist25 = NULL; + objlist24 = NULL; + + if (type2->size == 0) + CDecl_CompleteType(type2); + if (expr->rtype->size == 0) + CDecl_CompleteType(expr->rtype); + + if (IS_TYPE_CLASS(expr->rtype)) { + CExpr_ConversionIteratorInit(&convIter, TYPE_CLASS(expr->rtype)); + flag22 = 1; + while ((object26 = CExpr_ConversionIteratorNext(&convIter))) { + tfunc23 = TYPE_FUNC(object26->type); + if (tfunc23->flags & FUNC_IS_TEMPL) { + object26 = CTempl_DeduceFromConversion(object26, type2, qual2); + if (!object26) + continue; + tfunc23 = TYPE_FUNC(object26->type); + } + + if (flag3) { + if ( + !IS_TYPE_REFERENCE(tfunc23->functype) || + !CExpr_IsReferenceCompatible(type2, qual2, TPTR_TARGET(tfunc23->functype), tfunc23->qual) + ) + continue; + } + + CError_ASSERT(1230, tfunc23->args && IS_TYPE_POINTER_ONLY(tfunc23->args->type)); + + q1 = ENODE_QUALS(expr); + q2 = tfunc23->args->qual; + if ((q1 & Q_CV) != (q2 & Q_CV)) { + if (!flag22) + continue; + if ((q1 & Q_CONST) && !(q2 & Q_CONST)) + continue; + if ((q1 & Q_VOLATILE) && !(q2 & Q_VOLATILE)) + continue; + flag21 = 1; + } else { + flag21 = 0; + } + + newExpr = CExpr_NewENode(ETEMP); + newExpr->rtype = tfunc23->functype; + newExpr->flags = tfunc23->qual & ENODE_FLAG_QUALS; + flag20 = 0; + + if (IS_TYPE_REFERENCE(newExpr->rtype)) { + newExpr->rtype = TPTR_TARGET(newExpr->rtype); + if (!CParser_IsConst(newExpr->rtype, tfunc23->qual)) { + newExpr = makemonadicnode(newExpr, EINDIRECT); + newExpr->data.monadic->rtype = TYPE(&void_ptr); + newExpr = makemonadicnode(newExpr, EINDIRECT); + newExpr->data.monadic->rtype = TYPE(&void_ptr); + flag20 = 1; + } + } + + if (CExpr_StandardConversionMatch(newExpr, type2, qual2, 0, &sc1)) { + if (flag22 && !flag21) { + object28 = NULL; + objlist25 = NULL; + flag22 = 0; + } + + if (object28 && object28 != object26) { + if (CExpr_IsBetterStandardConv(&sc3, &sc1)) + continue; + + if (!CExpr_IsBetterStandardConv(&sc1, &sc3)) { + objlist = lalloc(sizeof(ObjectList)); + objlist->next = objlist25; + objlist->object = object28; + objlist25 = objlist; + } else { + objlist25 = NULL; + } + } + + object28 = object26; + sc3 = sc1; + sc3.x15 = flag20; + } + } + } + + if (!flag3 && IS_TYPE_CLASS(type2) && (list22 = CClass_Constructor(TYPE_CLASS(type2)))) { + for (; list22; list22 = list22->next) { + object26 = OBJECT(list22->object); + if ( + object26->otype == OT_OBJECT && + IS_TYPE_FUNC(tfunc23 = TYPE_FUNC(object26->type)) && + (isExplicit || !(object26->qual & Q_EXPLICIT)) + ) + { + if (tfunc23->flags & FUNC_IS_TEMPL) { + myarglist.next = NULL; + myarglist.node = expr; + object26 = CTempl_DeduceFromFunctionCall(object26, NULL, &myarglist); + if (!object26) + continue; + tfunc23 = TYPE_FUNC(object26->type); + } + + if (!(arg21 = tfunc23->args)) + continue; + if (!(arg21 = arg21->next)) + continue; + if ((TYPE_CLASS(type2)->flags & CLASS_HAS_VBASES) && !(arg21 = arg21->next)) + continue; + if (arg21 == &elipsis) + continue; + if (arg21->next && !arg21->next->dexpr && arg21->next != &elipsis) + continue; + + tmptype23 = arg21->type; + if (IS_TYPE_REFERENCE(tmptype23)) { + tmptype23 = TPTR_TARGET(tmptype23); + if (!CParser_IsConst(tmptype23, arg21->qual) && !CExpr_IsLValue(expr)) + continue; + } + + if (CExpr_StandardConversionMatch(expr, tmptype23, arg21->qual, 0, &sc1)) { + if (object27) { + if (object26->u.func.inst && !object27->u.func.inst) + continue; + if (CExpr_IsBetterStandardConv(&sc2, &sc1)) + continue; + + if (!CExpr_IsBetterStandardConv(&sc1, &sc2)) { + if (!object26->u.func.inst && object27->u.func.inst) { + objlist24 = NULL; + } else { + objlist = lalloc(sizeof(ObjectList)); + objlist->next = objlist25; + objlist->object = object28; + objlist25 = objlist; + } + } else { + objlist25 = NULL; + } + } + + object27 = object26; + sc2 = sc1; + } + } + } + } + + if (object28 && object27) { + if (!CExpr_IsBetterStandardConv(&sc2, &sc3)) { + if (!CExpr_IsBetterStandardConv(&sc3, &sc2)) { + if (result) { + result->type = ICT_2; + result->u.ic2.x2 = object28; + result->u.ic2.standardConv = sc3; + } + if (flag1) { + myobjlist.next = NULL; + myobjlist.object = object27; + CError_OverloadedFunctionError(object28, &myobjlist); + } + } else { + object27 = NULL; + } + } else { + object28 = NULL; + } + } + + if (object28) { + if (result) { + result->type = ICT_2; + result->u.ic2.x2 = object28; + result->u.ic2.standardConv = sc3; + } + if (!flag1) + return expr; + if (objlist25) + CError_OverloadedFunctionError(object28, objlist25); + tfunc23 = TYPE_FUNC(object28->type); + CError_ASSERT(1416, IS_TYPEFUNC_METHOD(tfunc23)); + + funcref = create_objectrefnode(object28); + object28->flags |= OBJECT_USED; + + arglist = lalloc(sizeof(ENodeList)); + arglist->next = NULL; + + expr = getnodeaddress(expr, 0); + arglist->node = CExpr_AssignmentPromotion( + expr, + CDecl_NewPointerType(TYPE(TYPE_METHOD(tfunc23)->theclass)), + expr->flags, + 0); + + newExpr = lalloc(sizeof(ENode)); + newExpr->type = EFUNCCALL; + newExpr->cost = 4; + newExpr->rtype = tfunc23->functype; + newExpr->flags = tfunc23->qual & ENODE_FLAG_QUALS; + newExpr->data.funccall.funcref = funcref; + newExpr->data.funccall.args = arglist; + newExpr->data.funccall.functype = TYPE_FUNC(object28->type); + newExpr = CExpr_AdjustFunctionCall(newExpr); + newExpr = checkreference(newExpr); + + if (newExpr->rtype != type2) { + if (flag3) { + tmpExpr = CExpr_DerivedToBase(newExpr, type2, qual2, 1, 0, 1); + if (tmpExpr) + return tmpExpr; + } + newExpr = CExpr_Convert(newExpr, type2, qual2, 0, 1); + } + return newExpr; + } + + if (object27) { + if (result) { + result->type = ICT_2; + result->u.ic2.x2 = object27; + result->u.ic2.standardConv = sc2; + } + if (!flag1) + return expr; + if (objlist24) + CError_OverloadedFunctionError(object27, objlist24); + + arglist = lalloc(sizeof(ENodeList)); + arglist->next = NULL; + arglist->node = expr; + + if (TYPE_CLASS(type2)->flags & CLASS_HAS_VBASES) { + arglist->next = lalloc(sizeof(ENodeList)); + arglist->next->node = expr; + arglist->next->next = NULL; + arglist->node = intconstnode(TYPE(&stsignedshort), 1); + } + + path.next = NULL; + path.type = type2; + + tmpExpr = makemonadicnode(create_temp_node(type2), EINDIRECT); + tmpExpr->rtype = type2; + + newExpr = CExpr_GenericFuncCall( + &path, tmpExpr, 0, object27, NULL, NULL, arglist, 0, 0, 1 + ); + + if (ENODE_IS2(newExpr, EFUNCCALL, EFUNCCALLP)) { + newExpr->rtype = CDecl_NewPointerType(type2); + newExpr = makemonadicnode(newExpr, EINDIRECT); + newExpr->rtype = type2; + } + + return newExpr; + } + + return NULL; +} + +static Boolean CExpr_UserConversionMatch(ENode *expr, Type *type2, UInt32 qual2, ImplicitConv *result) { + Boolean flag; + + if (IS_TYPE_REFERENCE(type2)) { + type2 = TPTR_TARGET(type2); + flag = !CParser_IsConst(type2, qual2); + } else { + expr = pointer_generation(expr); + flag = 0; + } + + if (CExpr_UserConversion(expr, type2, qual2, result, 0, 0, flag)) + return 1; + + return 0; +} + +static Boolean CExpr_ImplicitConversionMatch(ENode *expr, Type *type2, UInt32 qual2, ImplicitConv *result) { + if (CExpr_StandardConversionMatch(expr, type2, qual2, 0, &result->u.ic3.standardConv)) { + result->type = ICT_3; + return 1; + } + + if (IS_TYPE_CLASS(expr->rtype) || IS_TYPE_CLASS(type2) || (IS_TYPE_REFERENCE(type2) && IS_TYPE_CLASS(TPTR_TARGET(type2)))) { + if (CExpr_UserConversionMatch(expr, type2, qual2, result)) { + result->type = ICT_2; + return 1; + } + } + + return 0; +} + +Boolean CExpr_CanImplicitlyConvert(ENode *expr, Type *type2, UInt32 qual2) { + ImplicitConv result; + return CExpr_ImplicitConversionMatch(expr, type2, qual2, &result); +} + +static ENode *CExpr_DerivedToBase(ENode *expr, Type *type2, UInt32 qual2, Boolean flag1, Boolean nullcheckflag, Boolean pathcheckflag) { + BClassList *path; + short depth; + Boolean isambigbase; + + if ( + IS_TYPE_CLASS(type2) && + IS_TYPE_CLASS(expr->rtype) && + (path = CClass_GetBasePath(TYPE_CLASS(expr->rtype), TYPE_CLASS(type2), &depth, &isambigbase)) + ) + { + if (isambigbase) + CError_Error(CErrorStr188); + if (flag1) + CClass_CheckPathAccess(path, NULL, ACCESSPUBLIC); + + if (pathcheckflag) { + expr = getnodeaddress(expr, 0); + expr = makemonadicnode(CExpr_ClassPointerCast(path, expr, nullcheckflag), EINDIRECT); + expr->rtype = type2; + expr->flags = qual2 & ENODE_FLAG_QUALS; + } + + return expr; + } + else { + return NULL; + } +} + +static ENode *CExpr_ClassReferenceConversion(ENode *expr, Type *type2, UInt32 qual2, Boolean pathcheckflag) { + int refcompat; + + if (CExpr_IsLValue(expr) && IS_TYPE_CLASS(type2) && IS_TYPE_CLASS(expr->rtype)) { + refcompat = CExpr_IsReferenceCompatible(type2, 0, expr->rtype, 0); + if (refcompat > 0) { + if (refcompat == 2) { + CError_ASSERT(1668, IS_TYPE_CLASS(type2) && IS_TYPE_CLASS(expr->rtype)); + expr = CExpr_DerivedToBase(expr, type2, qual2, pathcheckflag, 0, 1); + } + expr->flags = qual2 & ENODE_FLAG_QUALS; + return expr; + } + + refcompat = CExpr_IsReferenceCompatible(expr->rtype, 0, type2, 0); + if (refcompat > 0) { + expr = CClass_ClassPointerCast( + getnodeaddress(expr, 0), + TYPE_CLASS(expr->rtype), TYPE_CLASS(type2), + 1, 1, pathcheckflag + ); + CError_ASSERT(1680, IS_TYPE_POINTER_ONLY(expr->rtype)); + expr = makemonadicnode(expr, EINDIRECT); + expr->rtype = type2; + expr->flags = qual2 & ENODE_FLAG_QUALS; + return expr; + } + } + + if (IS_TYPE_CLASS(expr->rtype)) { + if ((expr = CExpr_UserConversion(expr, type2, qual2, NULL, 1, 0, 1))) + return expr; + } + + return NULL; +} + +static ENode *CExpr_BindToReference(ENode *expr, Type *type2, UInt32 qual2) { + UInt32 cv; + int refcompat; + ENode *tmp; + + cv = CParser_GetCVTypeQualifiers(type2, qual2); + + if (CExpr_IsLValue(expr)) { + refcompat = CExpr_IsReferenceCompatible(type2, qual2, expr->rtype, ENODE_QUALS(expr)); + if (refcompat > 0) { + if (refcompat == 2) { + CError_ASSERT(1718, IS_TYPE_CLASS(type2) && IS_TYPE_CLASS(expr->rtype)); + expr = CExpr_DerivedToBase(expr, type2, qual2, 1, 0, 1); + } + return getnodeaddress(expr, 0); + } + } else if (IS_TYPE_CLASS(type2) && IS_TYPE_CLASS(expr->rtype)) { + refcompat = CExpr_IsReferenceCompatible(type2, qual2, expr->rtype, ENODE_QUALS(expr)); + if (refcompat > 0) { + if (refcompat == 2) + expr = CExpr_DerivedToBase(expr, type2, qual2, 1, 0, 1); + return getnodeaddress(expr, 0); + } + } + + if (IS_TYPE_CLASS(expr->rtype)) { + if ((tmp = CExpr_UserConversion(expr, type2, qual2, NULL, 1, 0, 1))) + return getnodeaddress(tmp, 0); + } + + if (!(cv & Q_CONST)) + CError_Error(CErrorStr228); + if (cv & Q_VOLATILE) + CError_Error(CErrorStr259); + + if (expr->rtype != type2) + expr = CExpr_Convert(expr, type2, qual2, 0, 1); + + if (!CExpr_IsLValue(expr)) { + expr = CExpr_LValue(expr, 0, 0); + if (!ENODE_IS(expr, EINDIRECT)) + expr = get_address_of_temp_copy(expr, 1); + else + expr = getnodeaddress(expr, 0); + } else { + expr = getnodeaddress(expr, 0); + } + + return expr; +} + +ENode *CExpr_Convert(ENode *expr, Type *type, UInt32 qual, Boolean isExplicit, Boolean flag2) { + UInt32 cv; + ENode *refExpr; + ENode *newExpr; + Type *typeCopy; + NameSpaceObjectList myList; + + cv = qual & Q_CV; + + if (copts.cpp_extensions && is_typesame(expr->rtype, type) && !ENODE_IS(expr, EOBJLIST)) { + expr = CExpr_RewriteConst(expr); + expr->rtype = type; + expr->flags &= ~ENODE_FLAG_QUALS; + expr->flags |= cv; + return expr; + } + + if (type == TYPE(&stvoid)) { + expr = makemonadicnode(expr, ETYPCON); + expr->rtype = type; + expr->flags = cv; + return expr; + } + + if (IS_TYPE_REFERENCE(type)) { + if (isExplicit) { + refExpr = CExpr_ClassReferenceConversion(expr, TPTR_TARGET(type), qual, flag2); + if (refExpr) + return refExpr; + + expr = getnodeaddress(expr, 0); + typeCopy = galloc(sizeof(TypePointer)); + *TYPE_POINTER(typeCopy) = *TYPE_POINTER(type); + TPTR_QUAL(typeCopy) &= ~Q_REFERENCE; + expr = CExpr_Convert(expr, typeCopy, qual, 0, flag2); + expr = makemonadicnode(expr, EINDIRECT); + expr->rtype = TPTR_TARGET(type); + expr->flags = cv; + return expr; + } else { + return CExpr_BindToReference(expr, TPTR_TARGET(type), qual); + } + } + + if ( + (IS_TYPE_ARRAY(expr->rtype) && !IS_TYPE_ARRAY(type)) || + (IS_TYPE_FUNC(expr->rtype) && !IS_TYPE_FUNC(type)) + ) + { + expr = pointer_generation(expr); + } else { + expr = CExpr_RewriteConst(expr); + } + + if (ENODE_IS(expr, EOBJLIST)) { + if (CExpr_OverloadFuncMatch(expr->data.objlist.list, expr->data.objlist.templargs, type, &refExpr)) + return refExpr; + } else if (ENODE_IS(expr, EOBJREF) && IS_TEMPL_FUNC(expr->data.objref->type)) { + myList.next = NULL; + myList.object = OBJ_BASE(expr->data.objref); + if (CExpr_OverloadFuncMatch(&myList, NULL, type, &refExpr)) + return refExpr; + } else if (IS_TYPE_CLASS(expr->rtype) || IS_TYPE_CLASS(type)) { + if (expr->rtype->size == 0) + CDecl_CompleteType(expr->rtype); + + if (IS_TYPE_CLASS(type)) { + CanAllocObject(type); + if (!CClass_CopyConstructor(TYPE_CLASS(type)) || CClass_IsTrivialCopyClass(TYPE_CLASS(type))) { + if (expr->rtype == type) + return expr; + + refExpr = CExpr_DerivedToBase(expr, type, qual, flag2, 0, 1); + if (refExpr) + return refExpr; + } + } + + refExpr = CExpr_UserConversion(expr, type, qual, NULL, 1, isExplicit, 0); + if (refExpr) { + refExpr->flags = cv; + return refExpr; + } + } else if (!isExplicit && is_typesame(expr->rtype, type)) { + if (ENODE_IS(expr, EINDIRECT) && ENODE_QUALS(expr) != cv) + expr = makemonadicnode(expr, ETYPCON); + expr->rtype = type; + expr->flags = cv; + return expr; + } else { + if ( + copts.warn_implicitconv && + !isExplicit && + IS_TYPE_INT_OR_FLOAT(type) && + IS_TYPE_INT_OR_FLOAT(expr->rtype) + ) + CExpr_CheckArithmConversion(expr, type); + + switch (type->type) { + case TYPEINT: + if (type == TYPE(&stbool)) { + switch (expr->rtype->type) { + case TYPEINT: + case TYPEFLOAT: + case TYPEENUM: + case TYPEMEMBERPOINTER: + case TYPEPOINTER: + return CExpr_ConvertToBool(expr, isExplicit); + } + } else { + switch (expr->rtype->type) { + case TYPEENUM: + expr->rtype = TYPE_ENUM(expr->rtype)->enumtype; + case TYPEINT: + case TYPEFLOAT: + do_int_float_conversion: + if ( + ENODE_IS(expr, ETYPCON) && + expr->rtype->type == type->type && + expr->rtype->size == type->size && + is_unsigned(expr->rtype) == is_unsigned(type) && + ENODE_QUALS(expr) == qual + ) + { + expr->rtype = type; + expr->flags |= ENODE_FLAG_80; + return expr; + } else { + refExpr = promote(expr, type); + refExpr->flags = cv; + return refExpr; + } + break; + case TYPEPOINTER: + if (expr->rtype->size > type->size && copts.warn_ptr_int_conv) + CError_Warning(CErrorStr382); + if (ENODE_IS(expr, ETYPCON)) { + ENode *inner = expr->data.monadic; + if (ENODE_IS(inner, EINTCONST)) { + inner->rtype = type; + inner->flags = cv; + inner->data.intval = CExpr_IntConstConvert(type, TYPE(&stunsignedlong), inner->data.intval); + return inner; + } + } + if (type->size != 4) { + expr = makemonadicnode(expr, ETYPCON); + expr->rtype = TYPE(&stunsignedlong); + } + expr = makemonadicnode(expr, ETYPCON); + expr->rtype = type; + expr->flags = cv; + return expr; + } + } + break; + + case TYPEFLOAT: + switch (expr->rtype->type) { + case TYPEENUM: + expr->rtype = TYPE_ENUM(expr->rtype)->enumtype; + case TYPEINT: + case TYPEFLOAT: + goto do_int_float_conversion; + } + break; + + case TYPEENUM: + expr = CExpr_Convert(expr, TYPE_ENUM(type)->enumtype, qual, isExplicit, flag2); + if (!ENODE_IS(expr, EINTCONST)) + expr = makemonadicnode(expr, ETYPCON); + expr->rtype = type; + expr->flags = cv; + return expr; + + case TYPEPOINTER: + switch (expr->rtype->type) { + case TYPEENUM: + expr->rtype = TYPE_ENUM(expr->rtype)->enumtype; + case TYPEINT: + if (expr->rtype->size != 4) { + if (!ENODE_IS(expr, EINTCONST)) + expr = makemonadicnode(expr, ETYPCON); + expr->rtype = TYPE(&stunsignedlong); + } + expr = makemonadicnode(expr, ETYPCON); + expr->rtype = type; + expr->flags = cv; + return expr; + + case TYPEPOINTER: + if (IS_TYPE_CLASS(TPTR_TARGET(expr->rtype)) && IS_TYPE_CLASS(TPTR_TARGET(type))) + expr = CExpr_SafeClassPointerCast(expr, TYPE_CLASS(TPTR_TARGET(expr->rtype)), TYPE_CLASS(TPTR_TARGET(type)), 1, flag2); + if (!ENODE_IS(expr, ETYPCON)) + expr = makemonadicnode(expr, ETYPCON); + expr->rtype = type; + expr->flags = cv; + return expr; + } + break; + + case TYPEMEMBERPOINTER: + if (!IS_TYPE_MEMBERPOINTER(expr->rtype)) + expr = CExpr_MemberPointerConversion(expr, TYPE_MEMBER_POINTER(type), 1); + + if (IS_TYPE_MEMBERPOINTER(expr->rtype)) { + expr = PointerToMemberCast(expr, TYPE_MEMBER_POINTER(expr->rtype), TYPE_MEMBER_POINTER(type), flag2); + expr->flags = cv; + return expr; + } + break; + } + } + + if (isExplicit) { + if ((newExpr = CodeGen_HandleTypeCast(expr, type, qual))) + return newExpr; + } + + CError_Error( + isExplicit ? CErrorStr247 : CErrorStr209, + expr->rtype, ENODE_QUALS(expr), + type, qual); + return nullnode(); +} + +ENode *CExpr_AssignmentPromotion(ENode *expr, Type *type2, UInt32 qual2, Boolean flag) { + ImplicitConv result; + + if (copts.old_argmatch) + return oldassignmentpromotion(expr, type2, qual2, flag); + + if (ENODE_IS(expr, EMEMBER)) + expr = getpointertomemberfunc(expr, type2, 1); + + if (!CExpr_ImplicitConversionMatch(expr, type2, qual2, &result)) { + CError_Error(CErrorStr209, expr->rtype, ENODE_QUALS(expr), type2, qual2); + return nullnode(); + } + + return CExpr_Convert(expr, type2, qual2, 0, flag); +} + +static Boolean CExpr_IsBetterMatch(Match *a, Match *b, int count) { + ImplicitConv *convA; + ImplicitConv *convB; + int i; + Boolean flag; + + convA = a->conv; + convB = b->conv; + flag = 0; + + if (convA->type != ICT_0 && convB->type != ICT_0) { + if (CExpr_IsBetterImplicitConv(convB, convA)) + return 0; + if (CExpr_IsBetterImplicitConv(convA, convB)) + flag = 1; + } + + for (i = 0; i < count; i++) { + if (CExpr_IsBetterImplicitConv(++convB, ++convA)) + return 0; + if (CExpr_IsBetterImplicitConv(convA, convB)) + flag = 1; + } + + if (flag) + return 1; + + if (b->object) { + CError_ASSERT(2165, IS_TYPE_FUNC(b->object->type)); + if (b->object->u.func.inst) { + if (!a->object) + return 1; + + CError_ASSERT(2169, IS_TYPE_FUNC(a->object->type)); + if (!a->object->u.func.inst) + return 1; + + CError_ASSERT(2174, a->specialfunc && b->specialfunc); + if (CTempl_FuncIsMoreSpecialized(a->specialfunc, b->specialfunc)) + return 1; + } + } + + return 0; +} + +static Boolean CExpr_MatchArgs(Object *func, ENodeList *argexprs, ENode *expr, ImplicitConv *convs) { + FuncArg *args; + ENode *newExpr; + Type *type; + + args = TYPE_FUNC(func->type)->args; + + if (!(TYPE_FUNC(func->type)->flags & FUNC_METHOD)) { + convs->type = ICT_0; + } else if (TYPE_METHOD(func->type)->is_static) { + convs->type = ICT_0; + } else if (TYPE_FUNC(func->type)->flags & FUNC_IS_CTOR) { + convs->type = ICT_0; + args = args->next; + } else { + if (!expr) + return 0; + + newExpr = lalloc(sizeof(ENode)); + newExpr->type = EINTCONST; + newExpr->cost = 0; + newExpr->flags = expr->flags; + newExpr->rtype = CDecl_NewPointerType(expr->rtype); + newExpr->data.intval = cint64_zero; + + if (func->datatype == DALIAS) { + CError_ASSERT(2231, func->u.alias.member); + type = CDecl_NewPointerType(func->u.alias.member->type); + } else { + type = args->type; + } + + if (!CExpr_ImplicitConversionMatch(newExpr, type, args->qual, convs)) + return 0; + args = args->next; + } + + convs++; + while (1) { + if (!args || args->type == &stvoid) { + if (argexprs) + return 0; + else + return 1; + } + + if (args == &elipsis || args == &oldstyle) { + while (argexprs) { + convs->type = ICT_1; + argexprs = argexprs->next; + convs++; + } + return 1; + } + + if (!argexprs) + return args->dexpr != NULL; + + if (!CExpr_ImplicitConversionMatch(argexprs->node, args->type, args->qual, convs)) + return 0; + + argexprs = argexprs->next; + args = args->next; + convs++; + } +} + +static Object *CExpr_GetMatchObject(Match *match, HashNameNode *name) { + Object *object; + FuncArg *arg; + TypeFunc *tfunc; + + if (match->object) + return match->object; + + tfunc = lalloc(sizeof(TypeFunc)); + memclrw(tfunc, sizeof(TypeFunc)); + tfunc->type = TYPEFUNC; + tfunc->functype = &stvoid; + + arg = lalloc(sizeof(FuncArg)); + memclrw(arg, sizeof(FuncArg)); + arg->type = match->type; + arg->qual = match->qual; + tfunc->args = arg; + + if (match->type2) { + arg = lalloc(sizeof(FuncArg)); + memclrw(arg, sizeof(FuncArg)); + arg->type = match->type2; + arg->qual = match->qual2; + tfunc->args->next = arg; + } + + object = lalloc(sizeof(Object)); + memclrw(object, sizeof(Object)); + object->name = name; + object->datatype = DFUNC; + object->nspace = cscope_root; + object->type = TYPE(tfunc); + return object; +} + +static Match *CExpr_FindBestMatch(Match *matches, int count, HashNameNode *name, ObjectList **outList, ENodeList *argExprs) { + Match *scan; + Match *best; + ObjectList *listHead; + ObjectList *list; + + best = matches; + for (scan = matches->next; scan; scan = scan->next) { + if (CExpr_IsBetterMatch(scan, best, count)) + best = scan; + } + + for (scan = matches, listHead = NULL; scan; scan = scan->next) { + if (scan != best && !CExpr_IsBetterMatch(best, scan, count)) { + list = lalloc(sizeof(ObjectList)); + list->next = listHead; + list->object = CExpr_GetMatchObject(scan, name); + listHead = list; + } + } + + if (!outList) { + if (listHead) + CError_OverloadedFunctionError(CExpr_GetMatchObject(best, name), listHead); + } else { + *outList = listHead; + } + + return best; +} + +void CExpr_FuncArgMatch(NameSpaceObjectList *list, TemplArg *templargs, ENodeList *argexprs, Match13 *match13, ENode *expr, Boolean flag) { + NameSpaceObjectList *i; + NameSpaceObjectList *j; + Match *match; + Match *matches; + Object *object; + Object *object2; + Object *specialfunc; + ENodeList *argscan; + int argcount; + + for (argscan = argexprs, argcount = 0; argscan; argscan = argscan->next) { + CDecl_CompleteType(argscan->node->rtype); + argcount++; + } + + matches = NULL; + match = lalloc(sizeof(Match) + ((argcount - 2) * sizeof(ImplicitConv))); + + for (i = list; i; i = i->next) { + object = OBJECT(i->object); + if ( + object->otype == OT_OBJECT && + IS_TYPE_FUNC(object->type) && + (!flag || !(object->qual & Q_EXPLICIT)) + ) + { + if (object->datatype == DALIAS && (TYPE_FUNC(object->type)->flags & FUNC_METHOD)) { + for (j = list; j; j = j->next) { + if (j == i) + continue; + + object2 = OBJECT(j->object); + if ( + object2->otype == OT_OBJECT && + IS_TYPE_METHOD(object2->type) && + (TYPE_FUNC(object2->type)->flags & FUNC_FLAGS_CV) == (TYPE_FUNC(object->type)->flags & FUNC_FLAGS_CV) + ) + { + FuncArg *argsA; + FuncArg *argsB; + argsA = TYPE_FUNC(object->type)->args; + if (argsA && !TYPE_METHOD(object->type)->is_static) + argsA = argsA->next; + argsB = TYPE_FUNC(object2->type)->args; + if (argsB && !TYPE_METHOD(object2->type)->is_static) + argsB = argsB->next; + if (is_arglistsame(argsA, argsB)) + break; + } + } + + if (j) + continue; + } + + if (TYPE_FUNC(object->type)->flags & FUNC_IS_TEMPL) { + specialfunc = object; + object = CTempl_DeduceFromFunctionCall(object, templargs, argexprs); + if (!object) + continue; + } else { + if (templargs) + continue; + specialfunc = NULL; + } + + if (CExpr_MatchArgs(object, argexprs, expr, match->conv)) { + match->object = object; + match->specialfunc = specialfunc; + match->next = matches; + matches = match; + match = lalloc(sizeof(Match) + ((argcount - 2) * sizeof(ImplicitConv))); + } + } + } + + if (matches) { + matches = CExpr_FindBestMatch(matches, argcount, NULL, &match13->list, argexprs); + match13->obj = matches->object; + } +} + +static ConversionTypeList *CExpr_BuildConversionTypeList(ENode *expr) { + ConversionTypeList *first; + ConversionTypeList *list; + Object *object; + Type *type; + ConversionIterator convIter; + + if (!IS_TYPE_CLASS(expr->rtype)) { + first = lalloc(sizeof(ConversionTypeList)); + first->next = NULL; + first->func = NULL; + first->type = expr->rtype; + first->qual = ENODE_QUALS(expr); + if (IS_TYPE_ENUM(first->type)) + first->qual = 0; + } else { + first = NULL; + CExpr_ConversionIteratorInit(&convIter, TYPE_CLASS(expr->rtype)); + while ((object = CExpr_ConversionIteratorNext(&convIter))) { + type = TYPE_FUNC(object->type)->functype; + if (IS_TYPE_REFERENCE(type)) + type = TPTR_TARGET(type); + + if (!IS_TYPE_CLASS(type)) { + list = lalloc(sizeof(ConversionTypeList)); + list->next = first; + list->func = object; + list->type = type; + list->qual = TYPE_FUNC(object->type)->qual & Q_CV; + first = list; + } + } + } + + return first; +} + +static Type *CExpr_NextPromotedIntegralType(int *p) { + switch (++(*p)) { + case 1: return TYPE(&stsignedint); + case 2: return TYPE(&stunsignedint); + case 3: return TYPE(&stsignedlong); + case 4: return TYPE(&stunsignedlong); + case 5: + if (copts.longlong) + return TYPE(&stsignedlonglong); + else + return NULL; + case 6: + if (copts.longlong) + return TYPE(&stunsignedlonglong); + else + return NULL; + } + + return NULL; +} + +static Type *CExpr_NextArithmeticType(int *p) { + switch (++(*p)) { + case 1: return TYPE(&stbool); + case 2: return TYPE(&stchar); + case 3: return TYPE(&stsignedchar); + case 4: return TYPE(&stunsignedchar); + case 5: return TYPE(&stwchar); + case 6: return TYPE(&stsignedshort); + case 7: return TYPE(&stunsignedshort); + case 8: return TYPE(&stsignedint); + case 9: return TYPE(&stunsignedint); + case 10: return TYPE(&stsignedlong); + case 11: return TYPE(&stunsignedlong); + case 12: return TYPE(&stfloat); + case 13: return TYPE(&stdouble); + case 14: return TYPE(&stlongdouble); + case 15: + if (copts.longlong) + return TYPE(&stsignedlonglong); + else + return NULL; + case 16: + if (copts.longlong) + return TYPE(&stunsignedlonglong); + else + return NULL; + } + + return NULL; +} + +static Type *CExpr_NextPromotedArithmeticType(int *p) { + switch (++(*p)) { + case 1: return TYPE(&stsignedint); + case 2: return TYPE(&stunsignedint); + case 3: return TYPE(&stsignedlong); + case 4: return TYPE(&stunsignedlong); + case 5: return TYPE(&stdouble); + case 6: return TYPE(&stlongdouble); + case 7: + if (copts.longlong) + return TYPE(&stsignedlonglong); + else + return NULL; + case 8: + if (copts.longlong) + return TYPE(&stunsignedlonglong); + else + return NULL; + } + + return NULL; +} + +static Match *CExpr_MatchBuiltin(Match *matches, ENode *left, Type *leftType, UInt32 leftQual, ENode *right, Type *rightType, UInt32 rightQual) { + Match *scan; + Match mymatch; + + if (CExpr_ImplicitConversionMatch(left, leftType, leftQual, &mymatch.conv[0])) { + if (!right || CExpr_ImplicitConversionMatch(right, rightType, rightQual, &mymatch.conv[1])) { + if (right) { + for (scan = matches; scan; scan = scan->next) { + if ( + !scan->object && + is_typesame(scan->type, leftType) && + scan->qual == leftQual && + is_typesame(scan->type2, rightType) && + scan->qual2 == rightQual + ) + return matches; + } + } + + mymatch.next = matches; + mymatch.object = NULL; + mymatch.specialfunc = NULL; + mymatch.type = leftType; + mymatch.qual = leftQual; + mymatch.type2 = rightType; + mymatch.qual2 = rightQual; + + matches = lalloc(sizeof(Match)); + *matches = mymatch; + } + } + + return matches; +} + +static Match *CExpr_CheckIncDecBuiltin(Match *matches, short token, ENode *expr1, ENode *expr2) { + Object *object; + Type *type; + TypeFunc *tfunc; + ConversionIterator convIter; + + if (IS_TYPE_CLASS(expr1->rtype)) { + CExpr_ConversionIteratorInit(&convIter, TYPE_CLASS(expr1->rtype)); + while ((object = CExpr_ConversionIteratorNext(&convIter))) { + tfunc = TYPE_FUNC(object->type); + if (IS_TYPE_REFERENCE(tfunc->functype)) { + type = TPTR_TARGET(tfunc->functype); + switch (type->type) { + case TYPEINT: + if (type == TYPE(&stbool) && token == TK_DECREMENT) + break; + case TYPEFLOAT: + case TYPEPOINTER: + if (!CParser_IsConst(type, tfunc->qual)) { + matches = CExpr_MatchBuiltin( + matches, + expr1, type, tfunc->qual, + expr2, expr2 ? TYPE(&stsignedint) : NULL, 0 + ); + } + break; + } + } + } + } + + return matches; +} + +static Match *CExpr_CheckUnaryBuiltin(Match *matches, short token, ENode *expr) { + ConversionTypeList *typelist; + Type *type; + int typenum; + + switch (token) { + case TK_INCREMENT: + case TK_DECREMENT: + return CExpr_CheckIncDecBuiltin(matches, token, expr, NULL); + + case '!': + matches = CExpr_MatchBuiltin(matches, expr, TYPE(&stbool), 0, NULL, NULL, 0); + break; + + case '~': + typenum = 0; + while ((type = CExpr_NextPromotedIntegralType(&typenum))) { + matches = CExpr_MatchBuiltin(matches, expr, type, 0, NULL, NULL, 0); + } + break; + + case '*': + case '+': + for (typelist = CExpr_BuildConversionTypeList(expr); typelist; typelist = typelist->next) { + if (IS_TYPE_POINTER_ONLY(typelist->type)) + matches = CExpr_MatchBuiltin(matches, expr, typelist->type, typelist->qual, NULL, NULL, 0); + } + if (token != '+') + break; + + case '-': + typenum = 0; + while ((type = CExpr_NextPromotedArithmeticType(&typenum))) { + matches = CExpr_MatchBuiltin(matches, expr, type, 0, NULL, NULL, 0); + } + break; + } + + return matches; +} + +static Match *CExpr_CheckBinaryBuiltin(Match *matches, ENode *left, short token, ENode *right) { + int typenum1; + int typenum2; + Type *type1; + Type *type2; + Type *ptrdiff; + Boolean allowPtrDiffOnRight; + Boolean allowPtrCV; + Boolean allowPtrDiffOnLeft; + Boolean allowMemberPtrs; + Boolean allowEnum; + ConversionTypeList *leftList; + ConversionTypeList *rightList; + ConversionTypeList *scan; + + switch (token) { + case TK_INCREMENT: + case TK_DECREMENT: + return CExpr_CheckIncDecBuiltin(matches, token, left, right); + + case '*': + case '+': + case '-': + case '/': + case ':': + case '<': + case '>': + case TK_LOGICAL_EQ: + case TK_LOGICAL_NE: + case TK_LESS_EQUAL: + case TK_GREATER_EQUAL: + typenum1 = 0; + while ((type1 = CExpr_NextPromotedArithmeticType(&typenum1))) { + typenum2 = 0; + while ((type2 = CExpr_NextPromotedArithmeticType(&typenum2))) { + matches = CExpr_MatchBuiltin(matches, left, type1, 0, right, type2, 0); + } + } + break; + + case '%': + case '&': + case '^': + case '|': + case TK_SHL: + case TK_SHR: + typenum1 = 0; + while ((type1 = CExpr_NextPromotedIntegralType(&typenum1))) { + typenum2 = 0; + while ((type2 = CExpr_NextPromotedIntegralType(&typenum2))) { + matches = CExpr_MatchBuiltin(matches, left, type1, 0, right, type2, 0); + } + } + return matches; + + case TK_LOGICAL_OR: + case TK_LOGICAL_AND: + return CExpr_MatchBuiltin(matches, left, TYPE(&stbool), 0, right, TYPE(&stbool), 0); + } + + allowEnum = 0; + allowMemberPtrs = 0; + allowPtrCV = 0; + allowPtrDiffOnLeft = 0; + allowPtrDiffOnRight = 0; + + switch (token) { + case '+': + case '[': + allowPtrDiffOnLeft = 1; + allowPtrDiffOnRight = 1; + break; + case '-': + allowPtrCV = 1; + allowPtrDiffOnRight = 1; + break; + case ':': + case TK_LOGICAL_EQ: + case TK_LOGICAL_NE: + allowMemberPtrs = 1; + case '<': + case '>': + case TK_LESS_EQUAL: + case TK_GREATER_EQUAL: + allowPtrCV = 1; + allowEnum = 1; + break; + default: + return matches; + } + + leftList = CExpr_BuildConversionTypeList(left); + rightList = CExpr_BuildConversionTypeList(right); + ptrdiff = CABI_GetPtrDiffTType(); + + for (scan = leftList; ; scan = scan->next) { + if (!scan) { + scan = rightList; + if (!rightList) + break; + rightList = NULL; + } + + type1 = scan->type; + if (IS_TYPE_REFERENCE(type1)) + type1 = TPTR_TARGET(type1); + + switch (type1->type) { + case TYPEENUM: + if (allowEnum) + matches = CExpr_MatchBuiltin(matches, left, type1, scan->qual, right, type1, scan->qual); + break; + + case TYPEPOINTER: + if (allowPtrDiffOnRight) + matches = CExpr_MatchBuiltin(matches, left, type1, scan->qual, right, ptrdiff, 0); + if (allowPtrDiffOnLeft) + matches = CExpr_MatchBuiltin(matches, left, ptrdiff, 0, right, type1, scan->qual); + if (allowPtrCV) { + if (IS_TYPE_POINTER_ONLY(TPTR_TARGET(type1))) { + type2 = galloc(sizeof(TypePointer)); + *TYPE_POINTER(type2) = *TYPE_POINTER(type1); + TPTR_QUAL(type2) |= Q_CONST | Q_VOLATILE; + matches = CExpr_MatchBuiltin(matches, left, type2, scan->qual, right, type2, scan->qual); + } else { + matches = CExpr_MatchBuiltin(matches, left, type1, Q_CONST | Q_VOLATILE, right, type1, Q_CONST | Q_VOLATILE); + } + } + break; + + case TYPEMEMBERPOINTER: + if (allowMemberPtrs) + matches = CExpr_MatchBuiltin(matches, left, type1, scan->qual, right, type1, scan->qual); + break; + } + } + + return matches; +} + +static Boolean CExpr_MatchOperands(ENode *left, Type *leftType, UInt32 leftQual, ENode *right, Type *rightType, UInt32 rightQual, ImplicitConv *twoResults, Boolean flag) { + if (flag) { + if (!CExpr_StandardConversionMatch(left, leftType, leftQual, 1, &twoResults[0].u.ic3.standardConv)) + return 0; + twoResults[0].type = ICT_3; + } else { + if (!CExpr_ImplicitConversionMatch(left, leftType, leftQual, &twoResults[0])) + return 0; + } + + if (right) { + if (!CExpr_ImplicitConversionMatch(right, rightType, rightQual, &twoResults[1])) + return 0; + } + + return 1; +} + +Boolean CExpr_CondOperatorMatch(ENode *left, ENode *right, Conversion *conv) { + Match *match; + + if ((match = CExpr_CheckBinaryBuiltin(NULL, left, ':', right))) { + match = CExpr_FindBestMatch(match, 1, GetHashNameNode("operator?:"), NULL, NULL); + CError_ASSERT(2931, !match->object); + + conv->x0 = NULL; + conv->left = CExpr_Convert(left, match->type, match->qual, 0, 1); + conv->right = CExpr_Convert(right, match->type2, match->qual2, 0, 1); + return 1; + } + + return 0; +} + +Boolean CExpr_OperatorMatch(short token, ENode *left, ENode *right, Conversion *conv) { + HashNameNode *name; + ENodeList *argExprs; + BClassList *path; + int hasArg; + Match *matches; + Object *object; + Object *specialfunc; + NameSpaceObjectList *list; + Type *leftType; + UInt32 leftQual; + Type *rightType; + UInt32 rightQual; + NameResult pr; + NameSpaceObjectList myList; + Match myMatch; + + if (!IS_TYPE_CLASS(left->rtype)) { + if (!IS_TYPE_ENUM(left->rtype)) { + if (!right || !(IS_TYPE_CLASS(right->rtype) || IS_TYPE_ENUM(right->rtype))) + return 0; + } + } else { + CDecl_CompleteType(left->rtype); + } + + name = CMangler_OperatorName(token); + path = NULL; + + argExprs = lalloc(sizeof(ENodeList)); + argExprs->node = left; + if (right) { + argExprs->next = lalloc(sizeof(ENodeList)); + argExprs->next->node = right; + argExprs->next->next = NULL; + hasArg = 1; + } else { + argExprs->next = NULL; + hasArg = 0; + } + + matches = NULL; + + if (IS_TYPE_CLASS(left->rtype) && CScope_FindClassMemberObject(TYPE_CLASS(left->rtype), &pr, name)) { + if (token != '=' || (pr.bcl_18->type == left->rtype && !pr.bcl_18->next)) { + if (pr.obj_10) { + myList.next = NULL; + myList.object = pr.obj_10; + pr.nsol_14 = &myList; + } else { + CError_ASSERT(3009, pr.nsol_14); + } + + for (list = pr.nsol_14; list; list = list->next) { + object = OBJECT(list->object); + if (object->otype == OT_OBJECT && IS_TYPE_FUNC(object->type)) { + if (TYPE_FUNC(object->type)->flags & FUNC_IS_TEMPL) { + specialfunc = object; + object = CTempl_DeduceFromFunctionCall(object, NULL, argExprs->next); + if (!object) + continue; + } else { + specialfunc = NULL; + } + + leftType = CExpr_GetImplictObjectParamType(object, &leftQual); + if (right) { + if (!CExpr_HasNParams(object, 1)) + continue; + rightType = CExpr_GetParamType(object, 0, &rightQual); + } else { + if (!CExpr_HasNParams(object, 0)) + continue; + } + + if (CExpr_MatchOperands(left, leftType, leftQual, right, rightType, rightQual, myMatch.conv, 1)) { + myMatch.object = object; + myMatch.specialfunc = specialfunc; + myMatch.next = matches; + matches = lalloc(sizeof(Match)); + *matches = myMatch; + path = pr.bcl_18; + } + } + } + } + } + + if (CScope_FindNonClassObject(cscope_current, &pr, name)) { + if (pr.obj_10) { + myList.next = NULL; + myList.object = pr.obj_10; + pr.nsol_14 = &myList; + } + } else { + pr.nsol_14 = NULL; + } + + if (copts.arg_dep_lookup) + pr.nsol_14 = CScope_ArgumentDependentNameLookup(pr.nsol_14, name, argExprs, 1); + + for (list = pr.nsol_14; list; list = list->next) { + object = OBJECT(list->object); + if (object->otype == OT_OBJECT && IS_TYPE_NONMETHOD(object->type)) { + if (TYPE_FUNC(object->type)->flags & FUNC_IS_TEMPL) { + specialfunc = object; + object = CTempl_DeduceFromFunctionCall(object, NULL, argExprs); + if (!object) + continue; + } else { + specialfunc = NULL; + } + + leftType = CExpr_GetParamType(object, 0, &leftQual); + if (right) { + if (!CExpr_HasNParams(object, 2)) + continue; + rightType = CExpr_GetParamType(object, 1, &rightQual); + } else { + if (!CExpr_HasNParams(object, 1)) + continue; + } + + if (CExpr_MatchOperands(left, leftType, leftQual, right, rightType, rightQual, myMatch.conv, 0)) { + myMatch.object = object; + myMatch.specialfunc = specialfunc; + myMatch.next = matches; + matches = lalloc(sizeof(Match)); + *matches = myMatch; + } + } + } + + if (right) + matches = CExpr_CheckBinaryBuiltin(matches, left, token, right); + else + matches = CExpr_CheckUnaryBuiltin(matches, token, left); + + if (matches) { + conv->x0 = NULL; + conv->left = NULL; + conv->right = NULL; + + matches = CExpr_FindBestMatch(matches, hasArg, name, NULL, argExprs); + object = matches->object; + if (!object) { + if (IS_TYPE_CLASS(left->rtype)) + conv->left = CExpr_Convert(left, matches->type, matches->qual, 0, 1); + else + conv->left = left; + + if (right) { + if (IS_TYPE_CLASS(right->rtype)) + conv->right = CExpr_Convert(right, matches->type2, matches->qual2, 0, 1); + else + conv->right = right; + } + + return 1; + } + + if (IS_TYPEFUNC_NONSTATIC_METHOD(TYPE_FUNC(object->type))) { + CError_ASSERT(3125, path); + left = CExpr_GenericFuncCall(path, argExprs->node, 0, object, NULL, NULL, argExprs->next, 0, 0, 1); + } else { + left = CExpr_GenericFuncCall(NULL, NULL, 0, object, NULL, NULL, argExprs, 0, 0, 1); + } + + conv->x0 = checkreference(left); + return 1; + } + + return 0; +} + +static ENode *CExpr_ClassCopyInit(TypeClass *tclass, ENode *expr1, ENode *expr2) { + Object *best; + NameSpaceObjectList *list; + ObjectList *objlist; + ObjectList *objlistEntry; + ENodeList *argExprs; + FuncArg *arg; + Type *type; + Object *object; + ImplicitConv bestConv; + ImplicitConv conv; + BClassList path; + ConversionIterator convIter; + + best = NULL; + objlist = NULL; + + for (list = CClass_Constructor(tclass); list; list = list->next) { + object = OBJECT(list->object); + if (object->otype == OT_OBJECT && IS_TYPE_FUNC(object->type) && !(object->qual & Q_EXPLICIT)) { + arg = TYPE_FUNC(object->type)->args; + + CError_ASSERT(3199, arg); + arg = arg->next; + + if (tclass->flags & CLASS_HAS_VBASES) { + CError_ASSERT(3203, arg); + arg = arg->next; + } + + if ( + arg && + arg != &elipsis && + (!arg->next || arg->next->dexpr) && + CExpr_ImplicitConversionMatch(expr2, arg->type, arg->qual, &conv) + ) + { + if (!best || CExpr_IsBetterImplicitConv(&conv, &bestConv)) { + best = object; + bestConv = conv; + objlist = NULL; + } else if (!CExpr_IsBetterImplicitConv(&bestConv, &conv)) { + objlistEntry = lalloc(sizeof(ObjectList)); + objlistEntry->next = objlist; + objlistEntry->object = object; + objlist = objlistEntry; + } + } + } + } + + if (IS_TYPE_CLASS(expr2->rtype)) { + CExpr_ConversionIteratorInit(&convIter, TYPE_CLASS(expr2->rtype)); + while ((object = CExpr_ConversionIteratorNext(&convIter))) { + type = TYPE_FUNC(object->type)->functype; + if (IS_TYPE_REFERENCE(type)) + type = TPTR_TARGET(type); + + if ( + IS_TYPE_CLASS(type) && + (tclass == TYPE_CLASS(type) || CClass_IsBaseClass(tclass, TYPE_CLASS(type), NULL, 0, 0)) + ) + { + CError_ASSERT(3248, TYPE_FUNC(object->type)->args && + IS_TYPE_POINTER_ONLY(TYPE_FUNC(object->type)->args->type)); + + type = galloc(sizeof(TypePointer)); + *TYPE_POINTER(type) = *TYPE_POINTER(TYPE_FUNC(object->type)->args->type); + TPTR_QUAL(type) = Q_REFERENCE; + if (CExpr_ImplicitConversionMatch(expr2, type, TYPE_FUNC(object->type)->args->qual, &conv)) { + if (!best || CExpr_IsBetterImplicitConv(&conv, &bestConv)) { + best = object; + bestConv = conv; + objlist = NULL; + } else if (!CExpr_IsBetterImplicitConv(&bestConv, &conv)) { + objlistEntry = lalloc(sizeof(ObjectList)); + objlistEntry->next = objlist; + objlistEntry->object = object; + objlist = objlistEntry; + } + } + } + } + } + + if (objlist) + CError_OverloadedFunctionError(best, objlist); + + if (!best) { + CError_Error(CErrorStr209, expr2->rtype, ENODE_QUALS(expr2), tclass, 0); + return expr1; + } + + CError_ASSERT(3284, IS_TYPE_POINTER_ONLY(expr1->rtype)); + + expr1 = makemonadicnode(expr1, EINDIRECT); + expr1->rtype = TYPE(tclass); + + argExprs = lalloc(sizeof(ENodeList)); + argExprs->node = expr2; + if (tclass->flags & CLASS_HAS_VBASES) { + argExprs->next = lalloc(sizeof(ENodeList)); + argExprs->next->next = NULL; + argExprs->next->node = intconstnode(TYPE(&stsignedshort), 1); + } else { + argExprs->next = NULL; + } + + path.next = NULL; + path.type = TYPE(tclass); + expr1 = CExpr_GenericFuncCall(&path, expr1, 0, best, NULL, NULL, argExprs, 0, 0, 1); + + if (ENODE_IS2(expr1, EFUNCCALL, EFUNCCALLP)) + expr1->rtype = CDecl_NewPointerType(TYPE(tclass)); + + expr1 = makemonadicnode(expr1, EINDIRECT); + expr1->rtype = TYPE(tclass); + return expr1; +} diff --git a/compiler_and_linker/FrontEnd/C/CFunc.c b/compiler_and_linker/FrontEnd/C/CFunc.c new file mode 100644 index 0000000..38cfab3 --- /dev/null +++ b/compiler_and_linker/FrontEnd/C/CFunc.c @@ -0,0 +1,3224 @@ +#include "compiler/CFunc.h" +#include "compiler/CABI.h" +#include "compiler/CClass.h" +#include "compiler/CDecl.h" +#include "compiler/CError.h" +#include "compiler/CException.h" +#include "compiler/CExpr.h" +#include "compiler/CInit.h" +#include "compiler/CInline.h" +#include "compiler/CInt64.h" +#include "compiler/CMachine.h" +#include "compiler/CMangler.h" +#include "compiler/CParser.h" +#include "compiler/CPrepTokenizer.h" +#include "compiler/CSOM.h" +#include "compiler/CTemplateTools.h" +#include "compiler/CodeGen.h" +#include "compiler/CompilerTools.h" +#include "compiler/Exceptions.h" +#include "compiler/FuncLevelAsmPPC.h" +#include "compiler/InlineAsmPPC.h" +#include "compiler/ObjGenMachO.h" +#include "compiler/Switch.h" +#include "compiler/objects.h" +#include "compiler/scopes.h" +#include "compiler/types.h" + +#ifdef __MWERKS__ +#pragma options align=mac68k +#endif +struct CFuncSave { + CScopeSave scope; + ObjectList *arguments; + ObjectList *locals; + CLabel *labels; + Statement *curstmt; + DeclBlock *firstblock; + DeclBlock *currentblock; + ExceptionAction *cexcept_dobjstack; + CLabel *sinit_label; + ENode *ainit_expr; + CtorChain *ctor_chain; + ParserTryBlock *trychain; + TempNodeCB cinit_tempnodefunc; + HashNameNode *tkidentifier; + Object *sinit_first_object; + FileOffsetInfo cparser_fileoffset; + TStreamElement symdecltoken; + SInt32 functionbodyoffset; + HashNameNode *functionbodypath; + SInt32 symdecloffset; + SInt32 symdeclend; + SInt32 sourceoffset; + HashNameNode *sourcefilepath; + SInt32 curstmtvalue; + NameObjCheckCB name_obj_check; + FuncArg *check_arglist; + short blockcount; + short localcount; + short tk; + AccessType global_access; + Boolean cexcept_hasdobjects; + Boolean ainit_only_one; + Boolean cfunc_is_extern_c; + Boolean temp_reference_init; +}; +#ifdef __MWERKS__ +#pragma options align=reset +#endif + +FuncArg elipsis; +FuncArg oldstyle; +ObjectList *arguments; +ObjectList *locals; +short localcount; +SInt32 curstmtvalue; +SInt32 sourceoffset; +HashNameNode *sourcefilepath; +SInt32 functionbodyoffset; +HashNameNode *functionbodypath; +InitExpr *init_expressions; +CLabel *Labels; +CtorChain *ctor_chain; +Statement *curstmt; +static short temp_destructor_object_regmem; +static short temp_destructor_objects; +static short temp_expression_has_conditionals; +static DeclBlock *firstblock; +static DeclBlock *currentblock; +static short blockcount; +static Object *sinit_first_object; +static CLabel *sinit_label; +static Boolean ainit_only_one; +static ENode *ainit_expr; +static FuncArg *check_arglist; +static Boolean cfunc_is_extern_c; +static short cfunc_staticvarcount; +static void *destroyobjects; +static Boolean cfunc_hasdtortemp; + +// forward decls +static void statement(DeclThing *thing); + +static void CFunc_LoopIncrement(void) { + if (curstmtvalue >= 0x1000) { + if (curstmtvalue >= 0xF000) + curstmtvalue++; + else + curstmtvalue += 0x1000; + } else { + curstmtvalue <<= 3; + } +} + +static void CFunc_LoopDecrement(void) { + if (curstmtvalue > 0x1000) { + if (curstmtvalue > 0xF000) + curstmtvalue--; + else + curstmtvalue -= 0x1000; + } else { + curstmtvalue >>= 3; + } + + if (curstmtvalue < 1) + curstmtvalue = 1; +} + +DeclBlock *CFunc_NewDeclBlock(void) { + DeclBlock *block; + NameSpace *nspace; + + block = lalloc(sizeof(DeclBlock)); + if (firstblock) { + currentblock->next = block; + currentblock = block; + } else { + firstblock = block; + currentblock = block; + } + + block->index = blockcount++; + block->parent_nspace = cscope_current; + block->dobjstack = cexcept_dobjstack; + + nspace = CScope_NewListNameSpace(NULL, 0); + nspace->parent = cscope_current; + cscope_current = nspace; + + return block; +} + +void CFunc_RestoreBlock(DeclBlock *block) { + if (curstmt && curstmt->dobjstack != cexcept_dobjstack) { + Statement *stmt = CFunc_AppendStatement(ST_EXPRESSION); + stmt->expr = nullnode(); + } + + cscope_current = block->parent_nspace; + cexcept_dobjstack = block->dobjstack; +} + +void CFunc_SetupLocalVarInfo(Object *obj) { + obj->u.var.info = CodeGen_GetNewVarInfo(); + obj->u.var.info->func = cscope_currentfunc; + + if (obj->sclass == TK_REGISTER) { + if (!copts.optimizesize) + obj->u.var.info->usage = 100; + else + obj->u.var.info->usage = 5; + } + + if (obj->type && is_volatile_object(obj)) + obj->u.var.info->noregister = 1; +} + +static void adjustargumenttype(DeclInfo *declinfo) { + switch (declinfo->thetype->type) { + case TYPECLASS: + if (TYPE_CLASS(declinfo->thetype)->sominfo) { + CError_Error(CErrorStr284); + declinfo->thetype = TYPE(&stsignedint); + } + break; + case TYPEFUNC: + makethetypepointer(declinfo, 0); + return; + case TYPEARRAY: + declinfo->thetype = CDecl_NewPointerType(TPTR_TARGET(declinfo->thetype)); + return; + case TYPETEMPLATE: + if (TYPE_TEMPLATE(declinfo->thetype)->dtype == TEMPLDEP_ARRAY) + declinfo->thetype = CDecl_NewPointerType(TYPE_TEMPLATE(declinfo->thetype)->u.array.type); + return; + } + + if (!CanCreateObject(declinfo->thetype)) + declinfo->thetype = TYPE(&stsignedint); +} + +static FuncArg *CFunc_IsInArgList(FuncArg *list, HashNameNode *name) { + while (list) { + if (name == list->name) + return list; + list = list->next; + } + + return NULL; +} + +static Object *CFunc_IsInObjList(ObjectList *list, HashNameNode *name) { + while (list) { + if (name == list->object->name) + return list->object; + list = list->next; + } + + return NULL; +} + +static void CFunc_AppendArg(FuncArg **list, FuncArg *arg) { + FuncArg *tail; + + if ((tail = *list)) { + while (tail->next) + tail = tail->next; + tail->next = arg; + } else { + *list = arg; + } +} + +static void identifier_list(DeclInfo *declinfo) { + FuncArg *arg; + + declinfo->x45 = 1; + + while (1) { + if (tk != TK_IDENTIFIER) { + CError_Error(CErrorStr121); + } else { + if (CFunc_IsInArgList(declinfo->x18, tkidentifier)) + CError_Error(CErrorStr122, tkidentifier->name); + + arg = CParser_NewFuncArg(); + arg->name = tkidentifier; + CFunc_AppendArg(&declinfo->x18, arg); + declinfo->x44 = 1; + } + + if ((tk = lex()) != ',') + break; + tk = lex(); + } +} + +static Boolean defarg_name_obj_check(HashNameNode *name, Object *obj) { + FuncArg *arg; + + if (name) { + for (arg = check_arglist; arg; arg = arg->next) { + if (arg->name == name) { + CError_Error(CErrorStr205); + return 0; + } + } + } + + if (obj && obj->datatype == DLOCAL) { + CError_Error(CErrorStr205); + return 0; + } + + return 1; +} + +ENode *CFunc_DefaultArg(Type *type, UInt32 qual, FuncArg *args) { + TStreamElement *element; + ENode *expr; + ENode *templdepexpr; + + name_obj_check = defarg_name_obj_check; + check_arglist = args; + expr = conv_assignment_expression(); + name_obj_check = NULL; + + if ( + !CTemplTool_IsTemplateArgumentDependentExpression(expr) && + !CTemplTool_IsTemplateArgumentDependentType(type) + ) + { + expr = argumentpromotion(expr, type, qual, 1); + } else { + element = CPrep_CurStreamElement(); + if (element && element->tokenfile) { + templdepexpr = CExpr_NewTemplDepENode(TDE_SOURCEREF); + templdepexpr->data.templdep.u.sourceref.expr = expr; + templdepexpr->data.templdep.u.sourceref.token = galloc(sizeof(TStreamElement)); + *templdepexpr->data.templdep.u.sourceref.token = *element; + expr = templdepexpr; + } + } + + return CInline_CopyExpression(expr, CopyMode1); +} + +static FuncArg *parameter_list(DeclInfo *declinfo) { + Boolean flag26; + FuncArg *args; + FuncArg *arg; + DeclInfo my_di; + Boolean isArray; + + args = NULL; + flag26 = 1; + + while (1) { + if (tk == TK_ELLIPSIS) { + if (flag26) { + if (!copts.cplusplus && copts.ANSIstrict) + CError_Warning(CErrorStr127); + args = &elipsis; + } else { + CFunc_AppendArg(&args, &elipsis); + } + + tk = lex(); + return args; + } + + memclrw(&my_di, sizeof(my_di)); + CParser_GetDeclSpecs(&my_di, 0); + if (my_di.x48) + CError_Error(CErrorStr127); + + if ( + my_di.storageclass && + my_di.storageclass != TK_REGISTER && + (!copts.cplusplus || my_di.storageclass != TK_AUTO) + ) + { + CError_Error(CErrorStr127); + my_di.storageclass = 0; + } + + my_di.name = NULL; + + scandeclarator(&my_di); + + if (flag26) { + flag26 = 0; + if (my_di.thetype == &stvoid) { + if (my_di.storageclass || my_di.qual || my_di.name) + CError_Error(CErrorStr127); + return NULL; + } + } + + isArray = IS_TYPE_ARRAY(my_di.thetype); + adjustargumenttype(&my_di); + + if (my_di.name) { + if (args && CFunc_IsInArgList(args, my_di.name)) + CError_Error(CErrorStr122, my_di.name->name); + } else { + my_di.name = no_name_node; + } + + if (my_di.thetype == &stvoid) + CError_Error(CErrorStr126); + + arg = CParser_NewFuncArg(); + arg->name = my_di.name; + arg->type = my_di.thetype; + arg->qual = my_di.qual; + arg->sclass = my_di.storageclass; + arg->is_array = isArray; + CFunc_AppendArg(&args, arg); + + if (copts.cplusplus && tk == '=') { + tk = lex(); + arg->dexpr = CFunc_DefaultArg(arg->type, arg->qual, args); + } + + if (tk != ',') { + if (tk != TK_ELLIPSIS || !copts.cplusplus) + return args; + } else { + tk = lex(); + } + } +} + +Boolean CFunc_ParseFakeArgList(Boolean flag) { + DeclInfo di; + + if (tk == TK_ELLIPSIS) + return 1; + + do { + memclrw(&di, sizeof(di)); + CParser_GetDeclSpecs(&di, 0); + + if (di.x48) + return 0; + + scandeclarator(&di); + + if (tk == '=') { + tk = lex(); + assignment_expression(); + } + + switch (tk) { + case TK_ELLIPSIS: + return 1; + case ',': + if (!flag) + tk = lex(); + else + return 1; + break; + default: + return 0; + } + } while (tk != TK_ELLIPSIS); + + return 1; +} + +FuncArg *parameter_type_list(DeclInfo *declinfo) { + FuncArg *args; + NameSpace *nspace; + Boolean save_in_func_arglist; + + declinfo->x44 = 0; + declinfo->x45 = 0; + declinfo->x1C = NULL; + + if (tk == TK_ELLIPSIS || isdeclaration(0, 0, 0, 0)) { + if (!copts.cplusplus) { + nspace = CScope_NewListNameSpace(NULL, 0); + nspace->parent = cscope_current; + cscope_current = nspace; + + save_in_func_arglist = in_func_arglist; + in_func_arglist = 1; + args = parameter_list(declinfo); + in_func_arglist = save_in_func_arglist; + + cscope_current = nspace->parent; + + if (!CScope_IsEmptyNameSpace(nspace)) + declinfo->x1C = nspace; + } else { + args = parameter_list(declinfo); + } + } else if (copts.cplusplus) { + args = NULL; + if (tk != ')') + CError_Error(CErrorStr127); + } else { + identifier_list(declinfo); + args = &oldstyle; + } + + return args; +} + +CLabel *findlabel(void) { + CLabel *scan; + + for (scan = Labels; scan; scan = scan->next) { + if (tkidentifier == scan->name) + return scan; + } + + return NULL; +} + +CLabel *newlabel(void) { + CLabel *label = lalloc(sizeof(CLabel)); + memclrw(label, sizeof(CLabel)); + + label->name = label->uniquename = CParser_GetUniqueName(); + return label; +} + +Statement *CFunc_AppendStatement(StatementType sttype) { + Statement *stmt = lalloc(sizeof(Statement)); + + stmt->next = NULL; + stmt->type = sttype; + stmt->value = curstmtvalue; + stmt->flags = 0; + stmt->sourceoffset = sourceoffset; + stmt->sourcefilepath = sourcefilepath; + stmt->dobjstack = cexcept_dobjstack; + + curstmt->next = stmt; + curstmt = stmt; + return stmt; +} + +Statement *CFunc_InsertStatement(StatementType sttype, Statement *after) { + Statement *stmt = lalloc(sizeof(Statement)); + + stmt->next = after->next; + after->next = stmt; + stmt->type = sttype; + stmt->value = after->value; + stmt->flags = 0; + stmt->sourceoffset = after->sourceoffset; + stmt->sourcefilepath = after->sourcefilepath; + stmt->dobjstack = after->dobjstack; + + return stmt; +} + +Statement *CFunc_InsertBeforeStatement(StatementType sttype, Statement *before) { + Statement *stmt = lalloc(sizeof(Statement)); + + *stmt = *before; + before->next = stmt; + before->type = sttype; + before->flags = 0; + + return before; +} + +void CheckCLabels(void) { + CLabel *scan; + + for (scan = Labels; scan; scan = scan->next) { + if (!scan->stmt) + CError_Error(CErrorStr159, scan->name->name); + } +} + +Object *create_temp_object(Type *type) { + Object *object = CParser_NewLocalDataObject(NULL, 1); + object->name = CParser_GetUniqueName(); + object->type = type; + CFunc_SetupLocalVarInfo(object); + return object; +} + +ENode *create_temp_node(Type *type) { + ENode *node; + + if (cinit_tempnodefunc) + return cinit_tempnodefunc(type, 0); + + node = CExpr_NewETEMPNode(type, 0); + if (IS_TYPE_CLASS(type) && CClass_Destructor(TYPE_CLASS(type))) + node->data.temp.needs_dtor = 1; + return node; +} + +ENode *create_temp_node2(Type *type) { + ENode *node; + + if (cinit_tempnodefunc) + return cinit_tempnodefunc(type, 1); + + node = CExpr_NewETEMPNode(type, 0); + node->data.temp.needs_dtor = 1; + return node; +} + +static ENode *CFunc_DestroyReverse(ENode *expr, DtorTemp *list) { + expr = makediadicnode(expr, CABI_DestroyObject(list->dtor, create_objectrefnode(list->object), CABIDestroy1, 1, 0), ECOMMA); + expr->rtype = &stvoid; + if (list->next) + expr = CFunc_DestroyReverse(expr, list->next); + return expr; +} + +static ENode *CFunc_TempTransDestroy(ENode *expr, DtorTemp *list, Boolean flag) { + Object *tempobj; + + if (flag) { + CError_ASSERT(738, !(IS_TYPE_CLASS(expr->rtype) && CClass_Destructor(TYPE_CLASS(expr->rtype)))); + tempobj = create_temp_object(expr->rtype); + expr = makediadicnode(create_objectnode(tempobj), expr, EASS); + } + + expr = CFunc_DestroyReverse(expr, list); + + if (flag) { + expr = makediadicnode(expr, create_objectnode(tempobj), ECOMMA); + expr->rtype = tempobj->type; + } + + return expr; +} + +void CFunc_WarnUnused(void) { + if (copts.warn_unusedvar) { + ObjectList *list; + for (list = locals; list; list = list->next) { + if ( + !(list->object->flags & OBJECT_USED) && + !IsTempName(list->object->name) && + !(list->object->qual & Q_INLINE_DATA) + ) + { + CError_SetErrorToken(&list->object->u.var.info->deftoken); + CError_Warning(CErrorStr182, &list->object->name->name); + } + } + } + + if (copts.warn_unusedarg) { + ObjectList *list; + for (list = arguments; list; list = list->next) { + if ( + !(list->object->flags & OBJECT_USED) && + !IsTempName(list->object->name) && + list->object->name != this_name_node && + list->object->name != self_name_node + ) + { + CError_SetErrorToken(&symdecltoken); + CError_Warning(CErrorStr182, &list->object->name->name); + } + } + } +} + +void CFunc_CodeCleanup(Statement *stmt) { + if (cscope_currentclass && cscope_currentclass->sominfo) + CSOM_InitSOMSelf(cscope_currentclass, stmt); + + CFunc_WarnUnused(); + CExcept_ExceptionTansform(stmt); +} + +static Boolean DestructorNeeded(ExceptionAction *ea, ExceptionAction *end) { + while (ea) { + if (CExcept_ActionNeedsDestruction(ea)) + return 1; + if (ea == end) + break; + ea = ea->prev; + } + + return 0; +} + +static Statement *DestructLocals(Statement *stmt, ExceptionAction *ea, ExceptionAction *end) { + while (ea) { + stmt = CExcept_ActionCleanup(ea, stmt); + if (ea == end) + break; + ea = ea->prev; + } + + return stmt; +} + +static Boolean NeedsDestruction(Statement *stmt1, Statement *stmt2) { + ExceptionAction *ea2; + ExceptionAction *ea1; + ExceptionAction *scan; + + ea1 = stmt1->dobjstack; + ea2 = stmt2->dobjstack; + + for (scan = ea2; scan; scan = scan->prev) { + if (scan == ea1) + return 0; + } + + while (ea1 && ea1 != ea2) { + if (CExcept_ActionNeedsDestruction(ea1)) + return 1; + ea1 = ea1->prev; + } + + return 0; +} + +static ExceptionAction *FindLastNonCommonStackObj(Statement *stmt1, Statement *stmt2) { + ExceptionAction *ea1; + ExceptionAction *ea2; + + for (ea2 = stmt2->dobjstack; ea2; ea2 = ea2->prev) { + for (ea1 = stmt1->dobjstack; ea1; ea1 = ea1->prev) { + if (ea1->prev == ea2) + return ea1; + } + } + + return NULL; +} + +static void DestructorReturnTransform(Statement *stmt1, Statement *stmt2) { + Statement *stmt; + Object *tempobj; + + if (stmt1->dobjstack != stmt2->dobjstack && NeedsDestruction(stmt1, stmt2)) + stmt1 = DestructLocals(stmt1, stmt1->dobjstack, FindLastNonCommonStackObj(stmt1, stmt2)); + + if (DestructorNeeded(stmt2->dobjstack, NULL)) { + if (CMach_GetFunctionResultClass(TYPE_FUNC(cscope_currentfunc->type)) != 1) { + tempobj = create_temp_object(stmt2->expr->rtype); + stmt = CFunc_InsertStatement(ST_EXPRESSION, stmt1); + stmt->expr = makediadicnode(create_objectnode(tempobj), stmt2->expr, EASS); + stmt->sourceoffset = stmt2->sourceoffset; + stmt->sourcefilepath = stmt2->sourcefilepath; + DestructLocals(stmt, stmt2->dobjstack, NULL); + stmt2->expr = create_objectnode(tempobj); + } else { + stmt = CFunc_InsertStatement(ST_EXPRESSION, stmt1); + stmt->expr = stmt2->expr; + stmt->sourceoffset = stmt2->sourceoffset; + stmt->sourcefilepath = stmt2->sourcefilepath; + DestructLocals(stmt, stmt2->dobjstack, NULL); + stmt2->expr = nullnode(); + } + } +} + +static Statement *DestructorIfTransform(Statement *stmt) { + CLabel *label; + Statement *newStmt; + + if (stmt->type == ST_IFGOTO) + stmt->type = ST_IFNGOTO; + else + stmt->type = ST_IFGOTO; + + label = newlabel(); + newStmt = DestructLocals(stmt, stmt->dobjstack, FindLastNonCommonStackObj(stmt, stmt->label->stmt)); + newStmt = CFunc_InsertStatement(ST_GOTO, newStmt); + newStmt->label = stmt->label; + newStmt = CFunc_InsertStatement(ST_LABEL, newStmt); + newStmt->label = label; + label->stmt = newStmt; + stmt->label = label; + newStmt->dobjstack = stmt->dobjstack; + return newStmt; +} + +static Boolean IsSubStack(ExceptionAction *exc1, ExceptionAction *exc2) { + if (!exc1) + return 1; + + while (exc2) { + if (exc2 == exc1) + return 1; + exc2 = exc2->prev; + } + + return 0; +} + +static void CFunc_CheckInitSkip(Statement *stmt, ExceptionAction *exc) { + if (stmt->dobjstack != exc && !IsSubStack(exc, stmt->dobjstack)) { + while (exc) { + if (CExcept_ActionNeedsDestruction(exc) && exc->type != EAT_ACTIVECATCHBLOCK) { + CError_Warning(CErrorStr211); + break; + } + exc = exc->prev; + } + } +} + +void CFunc_DestructorCleanup(Statement *stmt) { + Statement *scan; + Statement *next; + SwitchCase *swcase; + + if (copts.cplusplus) { + for (scan = stmt; scan; scan = scan->next) { + switch (scan->type) { + case ST_NOP: + case ST_LABEL: + case ST_EXPRESSION: + case ST_RETURN: + case ST_BEGINCATCH: + case ST_ENDCATCH: + case ST_ENDCATCHDTOR: + case ST_GOTOEXPR: + case ST_ASM: + break; + case ST_SWITCH: + CFunc_CheckInitSkip(scan, ((SwitchInfo *) scan->label)->defaultlabel->stmt->dobjstack); + for (swcase = ((SwitchInfo *) scan->label)->cases; swcase; swcase = swcase->next) { + CFunc_CheckInitSkip(scan, swcase->label->stmt->dobjstack); + } + break; + case ST_GOTO: + case ST_IFGOTO: + case ST_IFNGOTO: + CFunc_CheckInitSkip(scan, scan->label->stmt->dobjstack); + break; + default: + CError_FATAL(1045); + } + } + + if (cexcept_hasdobjects) { + while (1) { + next = stmt->next; + if (!next) { + if (stmt->type != ST_RETURN && stmt->dobjstack) + DestructLocals(stmt, stmt->dobjstack, NULL); + return; + } + + switch (next->type) { + case ST_GOTO: + if ( + stmt->dobjstack != next->label->stmt->dobjstack && + NeedsDestruction(stmt, next->label->stmt) + ) + { + DestructLocals(stmt, stmt->dobjstack, FindLastNonCommonStackObj(stmt, next->label->stmt)); + } + stmt = next; + continue; + + case ST_RETURN: + if (next->expr && DestructorNeeded(stmt->dobjstack, NULL)) { + DestructorReturnTransform(stmt, next); + } else if (stmt->dobjstack) { + DestructLocals(stmt, stmt->dobjstack, NULL); + } + stmt = next; + continue; + } + + switch (stmt->type) { + case ST_GOTO: + case ST_SWITCH: + case ST_RETURN: + case ST_GOTOEXPR: + break; + case ST_NOP: + case ST_LABEL: + case ST_EXPRESSION: + case ST_IFGOTO: + case ST_IFNGOTO: + case ST_BEGINCATCH: + case ST_ENDCATCH: + case ST_ENDCATCHDTOR: + case ST_ASM: + if ( + stmt->dobjstack != next->dobjstack && + NeedsDestruction(stmt, next) + ) + { + DestructLocals(stmt, stmt->dobjstack, FindLastNonCommonStackObj(stmt, next)); + } + break; + default: + CError_FATAL(1109); + } + + switch (next->type) { + case ST_NOP: + case ST_LABEL: + case ST_EXPRESSION: + case ST_SWITCH: + case ST_BEGINCATCH: + case ST_ENDCATCH: + case ST_ENDCATCHDTOR: + case ST_ASM: + stmt = next; + continue; + + case ST_IFGOTO: + case ST_IFNGOTO: + if ( + next->dobjstack != next->label->stmt->dobjstack && + NeedsDestruction(next, next->label->stmt) + ) + { + stmt = DestructorIfTransform(next); + } else { + stmt = next; + } + break; + + default: + CError_FATAL(1138); + } + } + } + } +} + +static void scancase(DeclThing *thing) { + SwitchCase *swcase; + Statement *stmt; + CInt64 min; + CInt64 max; + + if (!thing->switchinfo) { + CError_Error(CErrorStr169); + return; + } + + tk = lex(); + min = CExpr_IntConstConvert(thing->switchinfo->x8, thing->switchinfo->x8, CExpr_IntegralConstExpr()); + if (!copts.ANSIstrict && tk == TK_ELLIPSIS) { + tk = lex(); + max = CExpr_IntConstConvert(thing->switchinfo->x8, thing->switchinfo->x8, CExpr_IntegralConstExpr()); + if (CInt64_Greater(min, max)) + CError_Error(CErrorStr366); + if (thing->switchinfo->x8->size == stsignedlonglong.size) + CError_Error(CErrorStr368); + } else { + max = min; + } + + for (swcase = thing->switchinfo->cases; swcase; swcase = swcase->next) { + if (CInt64_GreaterEqual(swcase->min, min) && CInt64_LessEqual(swcase->min, max)) + CError_Error(CErrorStr172); + if (CInt64_GreaterEqual(swcase->max, min) && CInt64_LessEqual(swcase->max, max)) + CError_Error(CErrorStr172); + if (CInt64_Less(swcase->min, min) && CInt64_Greater(swcase->max, max)) + CError_Error(CErrorStr172); + } + + stmt = CFunc_AppendStatement(ST_LABEL); + stmt->label = newlabel(); + stmt->label->stmt = stmt; + + swcase = lalloc(sizeof(SwitchCase)); + swcase->min = min; + swcase->label = stmt->label; + swcase->next = thing->switchinfo->cases; + thing->switchinfo->cases = swcase; + swcase->max = max; + + if (tk != ':') + CError_ErrorSkip(CErrorStr170); + else + tk = lex(); + + statement(thing); +} + +static void CFunc_NameLocalStaticDataObject(Object *obj, char *str) { + char buf[64]; + HashNameNode *name; + + if (!(cscope_currentfunc && (cscope_currentfunc->qual & Q_INLINE)) || CParser_HasInternalLinkage(cscope_currentfunc)) { + obj->name = CParser_AppendUniqueName(str); + } else { + sprintf(buf, "$localstatic%" PRId32 "$", cfunc_staticvarcount++); + name = CMangler_GetLinkName(cscope_currentfunc); + name = CParser_NameConcat(buf, name->name); + name = CParser_NameConcat(str, name->name); + obj->name = name; + obj->qual |= Q_20000; + obj->sclass = 0; + } +} + +static void sinit_insert_expr(ENode *expr) { + Statement *stmt; + + if (!sinit_first_object) { + sinit_first_object = CParser_NewCompilerDefDataObject(); + sinit_first_object->type = TYPE(&stsignedchar); + sinit_first_object->sclass = TK_STATIC; + CFunc_NameLocalStaticDataObject(sinit_first_object, "init"); + CInit_DeclareData(sinit_first_object, NULL, NULL, sinit_first_object->type->size); + + sinit_label = newlabel(); + stmt = CFunc_AppendStatement(ST_IFGOTO); + stmt->expr = create_objectnode(sinit_first_object); + stmt->label = sinit_label; + } + + stmt = CFunc_AppendStatement(ST_EXPRESSION); + stmt->expr = expr; +} + +static void ainit_insert_expr(ENode *expr) { + Statement *stmt; + + if (ainit_only_one) { + if (ainit_expr) { + stmt = CFunc_AppendStatement(ST_EXPRESSION); + stmt->expr = ainit_expr; + } + ainit_expr = expr; + } else { + stmt = CFunc_AppendStatement(ST_EXPRESSION); + stmt->expr = expr; + } +} + +static ENode *ainit_register_object(Type *type, Object *local, SInt32 offset, Boolean flag) { + return CExcept_RegisterDestructorObject(local, offset, CClass_Destructor(TYPE_CLASS(type)), flag); +} + +static void CFunc_LocalDataDeclarator(DeclInfo *di, TStreamElement *deftoken, Boolean flag1, Boolean flag2) { + Object *object; + Object *aliasObject; + NameSpace *globalNS; + NameSpaceObjectList *nsol; + NameSpaceName *nsname; + Statement *stmt; + + if (di->nspace) + CError_Error(CErrorStr121); + + CDecl_CompleteType(di->thetype); + + object = NULL; + + if ((nsol = CScope_FindName(cscope_current, di->name))) { + switch (nsol->object->otype) { + case OT_OBJECT: + object = OBJECT(nsol->object); + break; + case OT_NAMESPACE: + CError_Error(CErrorStr321); + return; + case OT_ENUMCONST: + case OT_TYPE: + CError_Error(CErrorStr322); + break; + case OT_TYPETAG: + break; + default: + CError_FATAL(1344); + } + } + + if (object) + CError_Error(CErrorStr333, object); + + if (di->storageclass == TK_EXTERN) { + object = NULL; + globalNS = CScope_FindGlobalNS(cscope_current); + if ((nsol = CScope_FindName(globalNS, di->name))) { + switch (nsol->object->otype) { + case OT_OBJECT: + object = OBJECT(nsol->object); + break; + case OT_NAMESPACE: + CError_Error(CErrorStr321); + return; + case OT_ENUMCONST: + case OT_TYPE: + CError_Error(CErrorStr322); + break; + case OT_TYPETAG: + break; + default: + CError_FATAL(1381); + } + } + + if (object) { + if ( + !is_typesame(di->thetype, object->type) || + (di->qual & (Q_CONST | Q_VOLATILE | Q_PASCAL | Q_20000 | Q_WEAK | Q_ALIGNED_MASK)) != (object->qual & (Q_CONST | Q_VOLATILE | Q_PASCAL | Q_20000 | Q_WEAK | Q_ALIGNED_MASK)) + ) + { + CError_Error(CErrorStr249, di->name->name, object->type, object->qual, di->thetype, di->qual); + } + } else { + object = CParser_NewGlobalDataObject(di); + object->nspace = globalNS; + } + + CParser_NewAliasObject(object, 0); + return; + } + + if (di->storageclass != TK_STATIC) + object = CParser_NewObject(di); + else + object = CParser_NewGlobalDataObject(di); + + object->name = di->name; + object->type = di->thetype; + object->qual = di->qual; + object->sclass = di->storageclass; + + switch (di->storageclass) { + case TK_STATIC: + if (flag1) { + CError_Error(CErrorStr177); + return; + } + if (flag2) + CError_Error(CErrorStr174); + + if (CanCreateObject(di->thetype)) { + CError_QualifierCheck(di->qual & ~(Q_CONST | Q_VOLATILE | Q_PASCAL | Q_20000 | Q_WEAK | Q_ALIGNED_MASK)); + CParser_NewAliasObject(object, 0); + object->nspace = cscope_root; + object->datatype = DDATA; + CFunc_NameLocalStaticDataObject(object, object->name->name); + + if (copts.cplusplus) { + sinit_first_object = NULL; + CInit_InitializeStaticData(object, sinit_insert_expr); + if (sinit_first_object) { + stmt = CFunc_AppendStatement(ST_EXPRESSION); + stmt->expr = makediadicnode( + create_objectnode(sinit_first_object), + intconstnode(TYPE(&stsignedchar), 1), + EASS); + stmt = CFunc_AppendStatement(ST_LABEL); + stmt->label = sinit_label; + sinit_label->stmt = stmt; + } + } else { + CInit_InitializeData(object); + } + } + break; + + case 0: + case TK_AUTO: + case TK_REGISTER: + if (CanCreateObject(di->thetype)) { + CError_QualifierCheck(di->qual & ~(Q_CONST | Q_VOLATILE | Q_PASCAL | Q_ALIGNED_MASK)); + object->datatype = DLOCAL; + CFunc_SetupLocalVarInfo(object); + + object->u.var.info->deftoken = *deftoken; + if (object->sclass == TK_REGISTER && flag1) + object->u.var.info->usage = 100; + + CScope_AddObject(cscope_current, object->name, OBJ_BASE(object)); + + if (!flag1) { + if (IS_TYPE_SOM_CLASS(di->thetype)) { + CSOM_InitAutoClass(object); + } else { + CInit_InitializeAutoData(object, ainit_insert_expr, ainit_register_object); + if (object->type != di->thetype && (IS_TYPE_STRUCT(object->type) || IS_TYPE_CLASS(object->type))) { + CError_ASSERT(1478, !cscope_current->is_hash); + CError_ASSERT(1479, nsname = CScope_FindNameSpaceName(cscope_current, object->name)); + CError_ASSERT(1480, nsname->first.object == OBJ_BASE(object)); + CError_ASSERT(1481, !nsname->first.next); + nsname->name = CParser_AppendUniqueName(object->name->name); + + aliasObject = CParser_NewAliasObject(object, 0); + aliasObject->type = di->thetype; + } + } + } + + if (object->datatype == DLOCAL) { + ObjectList *list = lalloc(sizeof(ObjectList)); + list->object = object; + list->next = locals; + locals = list; + } + + IsCompleteType(di->thetype); + } + break; + + default: + CError_FATAL(1504); + } +} + +static ENode *CFunc_ParseLocalDeclarationList(Boolean flag1, Boolean flag2, Boolean flag3, Boolean flag4) { + Type *type; + UInt32 qual; + DeclInfo di; + TStreamElement deftoken; + + ainit_expr = NULL; + ainit_only_one = flag2; + + while (flag2 || isdeclaration(copts.cplusplus, 0, 0, 0)) { + CPrep_GetFileOffsetInfo2(&cparser_fileoffset, &sourceoffset, &sourcefilepath); + + memclrw(&di, sizeof(di)); + di.is_extern_c = cfunc_is_extern_c; + CParser_GetDeclSpecs(&di, 0); + + if (IS_TYPE_TEMPLATE(di.thetype)) { + CError_Error(CErrorStr146); + di.thetype = TYPE(&stsignedint); + } + + type = di.thetype; + qual = di.qual; + + if (tk != ';') { + while (1) { + deftoken = *CPrep_CurStreamElement(); + di.name = NULL; + scandeclarator(&di); + + if (di.name) { + if (di.storageclass != TK_TYPEDEF) { + if (IS_TYPE_FUNC(di.thetype)) { + if (!CDecl_FunctionDeclarator(&di, CScope_FindGlobalNS(cscope_current), 0, 0)) + break; + } else { + CFunc_LocalDataDeclarator(&di, &deftoken, flag1, flag2); + } + } else { + CDecl_TypedefDeclarator(&di); + } + } else { + CError_Error(CErrorStr134); + } + + if (tk == ';') + break; + + if (tk != ',') { + if (!flag2) + CError_Error(CErrorStr123); + break; + } + + di.nspace = NULL; + di.thetype = type; + di.qual = qual; + tk = lex(); + } + } else { + CParser_CheckAnonymousUnion(&di, 1); + } + + if (flag2) + break; + if (flag4) + break; + tk = lex(); + } + + if (flag2) { + if (!ainit_expr) { + if (!flag3) { + CError_Error(CErrorStr141); + ainit_expr = nullnode(); + } + } else { + ainit_expr = checkreference(ainit_expr); + } + } + + return ainit_expr; +} + +static void makeifstatement(ENode *expr, CLabel *label1, CLabel *label2, Boolean flag1, Boolean flag2) { + Statement *stmt; + CLabel *tmplabel; + + if (!expr) { + if (flag1) { + stmt = CFunc_AppendStatement(ST_GOTO); + stmt->label = label1; + return; + } + return; + } + + if ( + ENODE_IS(expr, ETYPCON) && + IS_TYPE_INT(expr->rtype) && + IS_TYPE_INT(expr->data.monadic->rtype) && + expr->rtype->size >= expr->data.monadic->rtype->size + ) + expr = expr->data.monadic; + + if (isnotzero(expr)) { + if (flag1) { + stmt = CFunc_AppendStatement(ST_GOTO); + stmt->label = label1; + return; + } + return; + } + + if (iszero(expr)) { + if (!flag1) { + stmt = CFunc_AppendStatement(ST_GOTO); + stmt->label = label1; + return; + } + return; + } + + if (ENODE_IS(expr, ELOGNOT)) { + makeifstatement(expr->data.monadic, label1, label2, !flag1, flag2); + return; + } + + if (ENODE_IS(expr, ELOR)) { + tmplabel = newlabel(); + if (flag1) { + makeifstatement(expr->data.diadic.left, label1, tmplabel, 1, flag2); + tmplabel->stmt = CFunc_AppendStatement(ST_LABEL); + tmplabel->stmt->label = tmplabel; + makeifstatement(expr->data.diadic.right, label1, label2, 1, flag2); + return; + } else { + makeifstatement(expr->data.diadic.left, label2, tmplabel, 1, flag2); + tmplabel->stmt = CFunc_AppendStatement(ST_LABEL); + tmplabel->stmt->label = tmplabel; + makeifstatement(expr->data.diadic.right, label1, label2, 0, flag2); + return; + } + } + + if (ENODE_IS(expr, ELAND)) { + tmplabel = newlabel(); + if (flag1) { + makeifstatement(expr->data.diadic.left, label2, tmplabel, 0, flag2); + tmplabel->stmt = CFunc_AppendStatement(ST_LABEL); + tmplabel->stmt->label = tmplabel; + makeifstatement(expr->data.diadic.right, label1, label2, 1, flag2); + return; + } else { + makeifstatement(expr->data.diadic.left, label1, tmplabel, 0, flag2); + tmplabel->stmt = CFunc_AppendStatement(ST_LABEL); + tmplabel->stmt->label = tmplabel; + makeifstatement(expr->data.diadic.right, label1, label2, 0, flag2); + return; + } + } + + stmt = CFunc_AppendStatement(ST_IFGOTO); + stmt->label = label1; + stmt->expr = expr; + if (!flag1) + stmt->type = ST_IFNGOTO; + if (flag2) + stmt->flags = stmt->flags | StmtFlag_4; +} + +static void CFunc_HasDtorTempCallBack(ENode *expr) { + if (expr->data.temp.needs_dtor || expr->data.temp.uniqueid) + cfunc_hasdtortemp = 1; +} + +static void ifstatement(Boolean flag1, ENode *expr, CLabel *label, Boolean flag2) { + Statement *stmt; + CLabel *tmplabel; + + if (expr && copts.cplusplus && copts.exceptions) { + cfunc_hasdtortemp = 0; + CExpr_SearchExprTree(expr, CFunc_HasDtorTempCallBack, 1, ETEMP); + if (cfunc_hasdtortemp) { + stmt = CFunc_AppendStatement(flag1 ? ST_IFGOTO : ST_IFNGOTO); + stmt->label = label; + stmt->expr = expr; + if (flag2) + stmt->flags = stmt->flags | StmtFlag_4; + return; + } + } + + tmplabel = newlabel(); + makeifstatement(expr, label, tmplabel, flag1, flag2); + tmplabel->stmt = CFunc_AppendStatement(ST_LABEL); + tmplabel->stmt->label = tmplabel; +} + +Statement *CFunc_GenerateLoop(Statement *stmt, Type *type, ENode *lowerBound, ENode *upperBound, ENode *increment1, ENode *increment2, ENode *(*callback)(ENode *, ENode *)) { + ENode *var1; + ENode *var2; + CLabel *label; + ENode *ind; + ENode *ind2; + Statement *s; + + var1 = CExpr_NewETEMPNode(type, 1); + ind = lalloc(sizeof(ENode)); + *ind = *var1; + ind = makemonadicnode(ind, EINDIRECT); + ind->rtype = type; + + // initialise var1 to lowerBound + if (stmt) { + stmt = CFunc_InsertStatement(ST_EXPRESSION, stmt); + s = stmt; + } else { + s = CFunc_AppendStatement(ST_EXPRESSION); + } + s->expr = makediadicnode(ind, lowerBound, EASS); + + if (increment2) { + var2 = CExpr_NewETEMPNode(type, 1); + ind = lalloc(sizeof(ENode)); + *ind = *var2; + ind = makemonadicnode(ind, EINDIRECT); + ind->rtype = type; + + // initialise var2 to upperBound + if (stmt) { + stmt = CFunc_InsertStatement(ST_EXPRESSION, stmt); + s = stmt; + } else { + s = CFunc_AppendStatement(ST_EXPRESSION); + } + s->expr = makediadicnode(ind, upperBound, EASS); + } + + // label for loop body + label = newlabel(); + if (stmt) { + stmt = CFunc_InsertStatement(ST_LABEL, stmt); + s = stmt; + } else { + s = CFunc_AppendStatement(ST_LABEL); + } + s->label = label; + label->stmt = s; + + if (callback) { + ind = lalloc(sizeof(ENode)); + *ind = *var1; + ind = makemonadicnode(ind, EINDIRECT); + ind->rtype = type; + + if (increment2) { + ind2 = lalloc(sizeof(ENode)); + *ind2 = *var2; + ind2 = makemonadicnode(ind2, EINDIRECT); + ind2->rtype = type; + } else { + ind2 = NULL; + } + + // generate a loop body + if ((ind = callback(ind, ind2))) { + if (stmt) { + stmt = CFunc_InsertStatement(ST_EXPRESSION, stmt); + s = stmt; + } else { + s = CFunc_AppendStatement(ST_EXPRESSION); + } + s->expr = ind; + } + } + + if (increment1) { + ind = lalloc(sizeof(ENode)); + *ind = *var1; + ind = makemonadicnode(ind, EINDIRECT); + ind->rtype = type; + + // add increment1 to var1 + if (stmt) { + stmt = CFunc_InsertStatement(ST_EXPRESSION, stmt); + s = stmt; + } else { + s = CFunc_AppendStatement(ST_EXPRESSION); + } + s->expr = makediadicnode(ind, increment1, EADDASS); + + if (increment2) { + ind = lalloc(sizeof(ENode)); + *ind = *var2; + ind = makemonadicnode(ind, EINDIRECT); + ind->rtype = type; + + // add increment2 to var2 + if (stmt) { + stmt = CFunc_InsertStatement(ST_EXPRESSION, stmt); + s = stmt; + } else { + s = CFunc_AppendStatement(ST_EXPRESSION); + } + s->expr = makediadicnode(ind, increment2, EADDASS); + } + } + + ind = lalloc(sizeof(ENode)); + *ind = *var1; + ind = makemonadicnode(ind, EINDIRECT); + ind->rtype = type; + + // loop if var1 < upperBound + if (stmt) { + stmt = CFunc_InsertStatement(ST_IFGOTO, stmt); + s = stmt; + } else { + s = CFunc_AppendStatement(ST_IFGOTO); + } + s->expr = makediadicnode(ind, upperBound, ELESS); + s->expr->rtype = TYPE(&stbool); + s->label = label; + s->flags = StmtFlag_4; + + return stmt; +} + +static Boolean checklabel(void) { + HashNameNode *savename; + short savesize; + short token; + + savename = tkidentifier; + savesize = tksize; + token = lookahead(); + tkidentifier = savename; + tksize = savesize; + + return token == ':'; +} + +static ENode *returnstatementadjust(ENode *expr, Type *type, UInt32 qual) { + Object *object; + ENode *expr2; + ENode *objexpr; + ObjectList *list; + ENodeList *exprlist; + + for (list = arguments; list; list = list->next) { + if (list->object->name == temp_argument_name) + break; + } + + CError_ASSERT(1907, list); + + object = list->object; + if ((expr2 = CExpr_IsTempConstruction(expr, type, &objexpr)) && ENODE_IS(objexpr, ETEMP)) { + *objexpr = *create_objectnode(object); + return expr2; + } + + if (IS_TYPE_CLASS(type)) { + expr2 = create_objectnode(object); + exprlist = lalloc(sizeof(ENodeList)); + exprlist->next = NULL; + exprlist->node = expr; + return CExpr_ConstructObject(TYPE_CLASS(type), expr2, exprlist, 1, 1, 0, 1, 0); + } + + expr2 = create_objectnode(object); + expr2 = makemonadicnode(expr2, EINDIRECT); + expr2->rtype = type; + + return makediadicnode(expr2, CExpr_AssignmentPromotion(expr, type, qual, 1), EASS); +} + +static void CFunc_AutoResultCheck(ENode *expr) { + while (1) { + while (ENODE_IS(expr, ECOMMA)) + expr = expr->data.diadic.right; + + switch (expr->type) { + case EOBJREF: + if (expr->data.objref->datatype != DLOCAL) + break; + case ETEMP: + CError_Warning(CErrorStr326); + break; + case EADD: + case ESUB: + CFunc_AutoResultCheck(expr->data.diadic.left); + expr = expr->data.diadic.right; + continue; + default: + break; + } + break; + } +} + +static void statement(DeclThing *thing) { + Statement *stmt; + Statement *stmt2; + CLabel *label; + DeclBlock *block; + ENode *expr; + HashNameNode *name; + DeclThing subthing; + + CPrep_GetFileOffsetInfo2(&cparser_fileoffset, &sourceoffset, &sourcefilepath); + + switch (tk) { + case TK_RETURN: + tk = lex(); + if ( + (thing->thetype == &stvoid && !copts.cplusplus) || + CClass_IsConstructor(cscope_currentfunc) || + CClass_IsDestructor(cscope_currentfunc) + ) + { + if (tk != ';') { + CError_Error(CErrorStr315); + expression(); + } + + stmt = CFunc_AppendStatement(ST_RETURN); + stmt->expr = NULL; + CError_ResetErrorSkip(); + tk = lex(); + return; + } + + if (tk == ';') { + if (thing->thetype != &stvoid && (copts.pedantic || copts.cplusplus)) + CError_Warning(CErrorStr184); + + stmt = CFunc_AppendStatement(ST_RETURN); + stmt->expr = NULL; + CError_ResetErrorSkip(); + tk = lex(); + return; + } + + if (copts.old_argmatch) + expr = expression(); + else + expr = s_expression(); + + if (thing->thetype == &stvoid) { + if (expr->rtype != &stvoid) + CError_Error(CErrorStr315); + + stmt = CFunc_AppendStatement(ST_EXPRESSION); + stmt->expr = expr; + + stmt = CFunc_AppendStatement(ST_RETURN); + stmt->expr = NULL; + } else { + if (CMach_GetFunctionResultClass(TYPE_FUNC(cscope_currentfunc->type)) == 1) + expr = returnstatementadjust(expr, thing->thetype, thing->qual); + else + expr = CExpr_AssignmentPromotion(expr, thing->thetype, thing->qual, 1); + + stmt = CFunc_AppendStatement(ST_RETURN); + stmt->expr = expr; + + if (IS_TYPE_POINTER_ONLY(thing->thetype)) + CFunc_AutoResultCheck(expr); + } + + break; + + case TK_CASE: + scancase(thing); + return; + + case TK_DEFAULT: + if (!thing->switchinfo) { + CError_Error(CErrorStr169); + return; + } + + if (lex() != ':') + CError_ErrorSkip(CErrorStr170); + else + tk = lex(); + + if (thing->switchinfo->defaultlabel) + CError_ErrorSkip(CErrorStr173); + + stmt = CFunc_AppendStatement(ST_LABEL); + stmt->label = newlabel(); + stmt->label->stmt = stmt; + thing->switchinfo->defaultlabel = stmt->label; + statement(thing); + return; + + case TK_SWITCH: + if (lex() != '(') + CError_ErrorSkip(CErrorStr114); + else + tk = lex(); + + if (copts.cplusplus && !copts.ARMscoping && isdeclaration(1, 0, 0, '=')) { + block = CFunc_NewDeclBlock(); + expr = CFunc_ParseLocalDeclarationList(0, 1, 0, 0); + if (CScope_IsEmptyNameSpace(cscope_current)) { + CFunc_RestoreBlock(block); + block = NULL; + } + } else { + expr = expression(); + block = NULL; + } + + stmt = CFunc_AppendStatement(ST_SWITCH); + stmt->expr = CExpr_ConvertToIntegral(expr); + + if (tk != ')') + CError_ErrorSkip(CErrorStr115); + else + tk = lex(); + + stmt->label = (CLabel *) lalloc(sizeof(SwitchInfo)); + ((SwitchInfo *) stmt->label)->defaultlabel = NULL; + ((SwitchInfo *) stmt->label)->cases = NULL; + ((SwitchInfo *) stmt->label)->x8 = stmt->expr->rtype; + + label = newlabel(); + subthing = *thing; + subthing.loopBreak = label; + subthing.switchinfo = (SwitchInfo *) stmt->label; + CFunc_CompoundStatement(&subthing); + + if (!subthing.switchinfo->defaultlabel) + subthing.switchinfo->defaultlabel = label; + + if (!subthing.switchinfo->cases) { + stmt->type = ST_EXPRESSION; + stmt2 = lalloc(sizeof(Statement)); + *stmt2 = *stmt; + stmt->next = stmt2; + stmt2->type = ST_GOTO; + stmt2->label = subthing.switchinfo->defaultlabel; + stmt2->dobjstack = cexcept_dobjstack; + } + + stmt = CFunc_AppendStatement(ST_LABEL); + stmt->label = label; + label->stmt = stmt; + + if (block) + CFunc_RestoreBlock(block); + return; + + case TK_GOTO: + if ((tk = lex()) != TK_IDENTIFIER) { + if (tk == '*' && !copts.ANSIstrict) { + tk = lex(); + stmt = CFunc_AppendStatement(ST_GOTOEXPR); + stmt->expr = expression(); + if (!IS_TYPE_POINTER_ONLY(stmt->expr->rtype)) { + CError_Error(CErrorStr146); + stmt->expr = nullnode(); + stmt->expr->rtype = TYPE(&void_ptr); + } + } else { + CError_Error(CErrorStr107); + return; + } + } else { + stmt = CFunc_AppendStatement(ST_GOTO); + if (!(stmt->label = findlabel())) { + stmt->label = newlabel(); + stmt->label->next = Labels; + Labels = stmt->label; + stmt->label->name = tkidentifier; + } + tk = lex(); + } + break; + + case TK_BREAK: + if (thing->loopBreak) { + stmt = CFunc_AppendStatement(ST_GOTO); + stmt->label = thing->loopBreak; + } else { + CError_Error(CErrorStr169); + } + tk = lex(); + break; + + case TK_CONTINUE: + if (thing->loopContinue) { + stmt = CFunc_AppendStatement(ST_GOTO); + stmt->label = thing->loopContinue; + } else { + CError_Error(CErrorStr169); + } + tk = lex(); + break; + + case TK_FOR: { + CLabel *forLabel1; + CLabel *forLabel2; + CLabel *forLabel3; + ENode *forCond; + ENode *forInc; + + if (lex() != '(') + CError_ErrorSkip(CErrorStr114); + else + tk = lex(); + + block = NULL; + if (tk != ';') { + if (!copts.cplusplus || !isdeclaration(1, 0, 0, 0)) { + expr = expression(); + CExpr_CheckUnusedExpression(expr); + } else { + if (!copts.ARMscoping) + block = CFunc_NewDeclBlock(); + expr = CFunc_ParseLocalDeclarationList(0, 1, 1, 0); + if (block && CScope_IsEmptyNameSpace(cscope_current)) { + CFunc_RestoreBlock(block); + block = NULL; + } + } + + if (expr) { + stmt = CFunc_AppendStatement(ST_EXPRESSION); + stmt->expr = expr; + } + + if (tk == ';') + CError_ResetErrorSkip(); + else + CError_Error(CErrorStr123); + } else { + CError_ResetErrorSkip(); + } + + if ((tk = lex()) != ';') { + if (copts.cplusplus && !copts.ARMscoping && isdeclaration(1, 0, 0, '=')) { + if (!block) + block = CFunc_NewDeclBlock(); + expr = CFunc_ParseLocalDeclarationList(0, 1, 0, 0); + if (CScope_IsEmptyNameSpace(cscope_current)) { + CFunc_RestoreBlock(block); + block = NULL; + } + } else { + expr = expression(); + CExpr_CheckUnwantedAssignment(expr); + } + + forCond = CExpr_ConvertToCondition(expr); + + if (tk == ';') + CError_ResetErrorSkip(); + else + CError_Error(CErrorStr123); + } else { + CError_ResetErrorSkip(); + forCond = NULL; + } + + if ((tk = lex()) != ')') { + forInc = expression(); + CExpr_CheckUnusedExpression(forInc); + if (tk == ')') + CError_ResetErrorSkip(); + else + CError_Error(CErrorStr115); + } else { + CError_ResetErrorSkip(); + forInc = NULL; + } + + if (copts.warn_possunwant) { + spaceskip = 0; + if ((tk = lex()) == ';' && !spaceskip) + CError_Warning(CErrorStr206); + } else { + tk = lex(); + } + + if (forCond) { + stmt = CFunc_AppendStatement(ST_GOTO); + label = newlabel(); + stmt->label = label; + } else { + label = newlabel(); + } + + CFunc_LoopIncrement(); + + stmt = CFunc_AppendStatement(ST_LABEL); + forLabel1 = stmt->label = newlabel(); + forLabel1->stmt = stmt; + + forLabel2 = newlabel(); + forLabel3 = newlabel(); + + subthing = *thing; + subthing.loopContinue = forLabel3; + subthing.loopBreak = forLabel2; + + if (tk != '{') { + DeclBlock *b = CFunc_NewDeclBlock(); + CFunc_CompoundStatement(&subthing); + CFunc_RestoreBlock(b); + } else { + CFunc_CompoundStatement(&subthing); + } + + stmt = CFunc_AppendStatement(ST_LABEL); + stmt->label = forLabel3; + forLabel3->stmt = stmt; + + if (forInc) { + stmt = CFunc_AppendStatement(ST_EXPRESSION); + stmt->expr = forInc; + } + + stmt = CFunc_AppendStatement(ST_LABEL); + stmt->label = label; + label->stmt = stmt; + + ifstatement(1, forCond, forLabel1, 1); + CFunc_LoopDecrement(); + + stmt = CFunc_AppendStatement(ST_LABEL); + stmt->label = forLabel2; + forLabel2->stmt = stmt; + + if (block) + CFunc_RestoreBlock(block); + + return; + } + + case TK_DO: { + CLabel *label1; + CLabel *label2; + CLabel *label3; + + CFunc_LoopIncrement(); + stmt = CFunc_AppendStatement(ST_LABEL); + label1 = stmt->label = newlabel(); + label1->stmt = stmt; + + label2 = newlabel(); + label3 = newlabel(); + + subthing = *thing; + subthing.loopContinue = label2; + subthing.loopBreak = label3; + + tk = lex(); + CFunc_CompoundStatement(&subthing); + + stmt = CFunc_AppendStatement(ST_LABEL); + stmt->label = label2; + label2->stmt = stmt; + + if (tk != TK_WHILE) + CError_Error(CErrorStr105); + + if (lex() != '(') + CError_ErrorSkip(CErrorStr114); + else + tk = lex(); + + expr = CExpr_ConvertToCondition(expression()); + CExpr_CheckUnwantedAssignment(expr); + + if (tk != ')') + CError_ErrorSkip(CErrorStr115); + else + tk = lex(); + + ifstatement(1, expr, label1, 1); + + CFunc_LoopDecrement(); + + stmt = CFunc_AppendStatement(ST_LABEL); + stmt->label = label3; + label3->stmt = stmt; + break; + } + + case TK_WHILE: { + CLabel *label1; + CLabel *label2; + CLabel *label3; + + if ((tk = lex()) != '(') + CError_ErrorSkip(CErrorStr114); + else + tk = lex(); + + if (copts.cplusplus && !copts.ARMscoping && isdeclaration(1, 0, 0, '=')) { + block = CFunc_NewDeclBlock(); + expr = CFunc_ParseLocalDeclarationList(0, 1, 0, 0); + if (CScope_IsEmptyNameSpace(cscope_current)) { + CFunc_RestoreBlock(block); + block = NULL; + } + } else { + expr = expression(); + block = NULL; + CExpr_CheckUnwantedAssignment(expr); + } + expr = CExpr_ConvertToCondition(expr); + + if (tk != ')') { + CError_ErrorSkip(CErrorStr115); + } else { + if (copts.warn_possunwant) { + spaceskip = 0; + if ((tk = lex()) == ';' && !spaceskip) + CError_Warning(CErrorStr206); + } else { + tk = lex(); + } + } + + stmt = CFunc_AppendStatement(ST_GOTO); + label1 = newlabel(); + stmt->label = label1; + + CFunc_LoopIncrement(); + + stmt = CFunc_AppendStatement(ST_LABEL); + label2 = stmt->label = newlabel(); + label2->stmt = stmt; + + label3 = newlabel(); + + subthing = *thing; + subthing.loopContinue = label1; + subthing.loopBreak = label3; + + CFunc_CompoundStatement(&subthing); + + stmt = CFunc_AppendStatement(ST_LABEL); + stmt->label = label1; + label1->stmt = stmt; + + ifstatement(1, expr, label2, 1); + + CFunc_LoopDecrement(); + + stmt = CFunc_AppendStatement(ST_LABEL); + stmt->label = label3; + label3->stmt = stmt; + + if (block) + CFunc_RestoreBlock(block); + return; + } + + case TK_IF: { + CLabel *label1; + if ((tk = lex()) != '(') + CError_ErrorSkip(CErrorStr114); + else + tk = lex(); + + if (copts.cplusplus && !copts.ARMscoping && isdeclaration(1, 0, 0, '=')) { + block = CFunc_NewDeclBlock(); + expr = CFunc_ParseLocalDeclarationList(0, 1, 0, 0); + if (CScope_IsEmptyNameSpace(cscope_current)) { + CFunc_RestoreBlock(block); + block = NULL; + } + } else { + expr = expression(); + block = NULL; + CExpr_CheckUnwantedAssignment(expr); + } + + expr = CExpr_ConvertToCondition(expr); + + label1 = newlabel(); + ifstatement(0, expr, label1, 0); + + if (tk != ')') { + CError_ErrorSkip(CErrorStr115); + } else { + if (copts.warn_possunwant) { + spaceskip = 0; + if ((tk = lex()) == ';' && !spaceskip) + CError_Warning(CErrorStr206); + } else { + tk = lex(); + } + } + + CFunc_CompoundStatement(thing); + + if (tk == TK_ELSE) { + if (copts.warn_possunwant) { + spaceskip = 0; + if ((tk = lex()) == ';' && !spaceskip) + CError_Warning(CErrorStr206); + } else { + tk = lex(); + } + + stmt = CFunc_AppendStatement(ST_GOTO); + label = stmt->label = newlabel(); + + stmt = CFunc_AppendStatement(ST_LABEL); + stmt->label = label1; + label1->stmt = stmt; + + CFunc_CompoundStatement(thing); + + label1 = label; + } + + stmt = CFunc_AppendStatement(ST_LABEL); + stmt->label = label1; + label1->stmt = stmt; + + if (block) + CFunc_RestoreBlock(block); + + return; + } + + case '{': + CFunc_CompoundStatement(thing); + return; + + case TK_ASM: + if (copts.cplusplus || !copts.ANSIstrict) { + tk = lex(); + volatileasm = 0; + + if (tk == TK_VOLATILE || (tk == TK_IDENTIFIER && !strcmp(tkidentifier->name, "__volatile__"))) { + tk = lex(); + volatileasm = 1; + } + + if (tk == '(') { + InlineAsm_Assemble(); + if (tk == ')') { + tk = lex(); + break; + } else { + CError_Error(CErrorStr115); + return; + } + } + + if (tk == '{') { + InlineAsm_Assemble(); + if (tk != '}') { + CError_Error(CErrorStr130); + return; + } + if ((tk = lex()) == ';') + tk = lex(); + CError_ResetErrorSkip(); + return; + } + + CError_Error(CErrorStr114); + } else { + CError_Error(CErrorStr121); + } + return; + + case TK_TRY: + tk = lex(); + CExcept_ScanTryBlock(thing, 0); + return; + + case TK_USING: + if ((tk = lex()) == TK_NAMESPACE) { + tk = lex(); + CScope_ParseUsingDirective(cscope_current); + } else { + CScope_ParseUsingDeclaration(cscope_current, 0, 0); + } + return; + + case TK_NAMESPACE: + if ((tk = lex()) != TK_IDENTIFIER) { + CError_Error(CErrorStr107); + return; + } + name = tkidentifier; + if ((tk = lex()) != '=') { + CError_Error(CErrorStr121); + return; + } + + CScope_ParseNameSpaceAlias(name); + break; + + case ';': + break; + + case TK_IDENTIFIER: + if (checklabel()) { + stmt = CFunc_AppendStatement(ST_LABEL); + if ((stmt->label = findlabel())) { + if (stmt->label->stmt) + CError_Error(CErrorStr171, tkidentifier->name); + } else { + stmt->label = newlabel(); + stmt->label->next = Labels; + Labels = stmt->label; + stmt->label->name = tkidentifier; + } + + stmt->label->stmt = stmt; + tk = lex(); + tk = lex(); + statement(thing); + return; + } + tk = TK_IDENTIFIER; + + default: + if (copts.cplusplus && isdeclaration(1, 0, 0, 0)) { + CFunc_ParseLocalDeclarationList(0, 0, 0, 1); + tk = lex(); + return; + } + + stmt = CFunc_AppendStatement(ST_EXPRESSION); + stmt->expr = expression(); + CExpr_CheckUnusedExpression(stmt->expr); + } + + if (tk == ';') { + CPrep_TokenStreamFlush(); + tk = lex(); + CError_ResetErrorSkip(); + } else { + CError_ErrorSkip(CErrorStr123); + } +} + +void CFunc_CompoundStatement(DeclThing *thing) { + DeclBlock *block; + + block = CFunc_NewDeclBlock(); + + if (tk == '{') { + tk = lex(); + if (!copts.cplusplus && isdeclaration(0, 0, 0, 0)) + CFunc_ParseLocalDeclarationList(0, 0, 0, 0); + + while (tk != '}') + statement(thing); + + CPrep_GetFileOffsetInfo2(&cparser_fileoffset, &sourceoffset, &sourcefilepath); + tk = lex(); + } else { + statement(thing); + } + + CFunc_RestoreBlock(block); +} + +static void CFunc_InsertArgumentCopyConversion(Object *obj, Type *type1, Type *type2, Boolean flag) { + Object *newobj; + Statement *stmt; + ENode *expr; + NameSpaceObjectList *nsol; + ObjectList *list; + + newobj = lalloc(sizeof(Object)); + *newobj = *obj; + newobj->type = type2; + + CFunc_SetupLocalVarInfo(newobj); + + obj->name = CParser_GetUniqueName(); + if (flag) + obj->type = CDecl_NewPointerType(type1); + else + obj->type = type1; + + CError_ASSERT(2527, (nsol = CScope_FindName(cscope_current, newobj->name)) && nsol->object == OBJ_BASE(obj)); + nsol->object = OBJ_BASE(newobj); + + list = lalloc(sizeof(ObjectList)); + list->object = newobj; + list->next = locals; + locals = list; + + stmt = CFunc_AppendStatement(ST_EXPRESSION); + expr = create_objectnode(obj); + if (flag) { + expr->rtype = CDecl_NewPointerType(type1); + expr = makemonadicnode(expr, EINDIRECT); + } + expr->rtype = type1; + + if (type1 != type2) + expr = promote(expr, type2); + + stmt->expr = makediadicnode(create_objectnode(newobj), expr, EASS); +} + +static void CFunc_AdjustOldStyleArgs(void) { + ObjectList *list; + + for (list = arguments; list; list = list->next) { + if (IS_TYPE_FLOAT(list->object->type) && list->object->type->size < stdouble.size) + CFunc_InsertArgumentCopyConversion(list->object, TYPE(&stdouble), list->object->type, 0); + } +} + +void CFunc_SetupNewFuncArgs(Object *func, FuncArg *args) { + Object *obj; + ObjectList *newlist; + + arguments = NULL; + + if (args != &elipsis && args != &oldstyle) { + newlist = NULL; + + while (args && args != &elipsis) { + IsCompleteType(args->type); + + obj = CParser_NewLocalDataObject(NULL, 0); + obj->name = !args->name ? no_name_node : args->name; + obj->type = args->type; + obj->qual = args->qual; + obj->sclass = args->sclass; + + CFunc_SetupLocalVarInfo(obj); + + if (IS_TYPE_CLASS(obj->type) && CClass_ReferenceArgument(TYPE_CLASS(obj->type))) { + obj->type = CDecl_NewPointerType(obj->type); + TPTR_QUAL(obj->type) = Q_REFERENCE | Q_RESTRICT; + } + + if (obj->name == no_name_node && copts.ANSIstrict && !copts.cplusplus && !(func->qual & Q_MANGLE_NAME)) + CError_Error(CErrorStr127); + + if (newlist) { + newlist->next = lalloc(sizeof(ObjectList)); + newlist = newlist->next; + } else { + newlist = lalloc(sizeof(ObjectList)); + arguments = newlist; + } + + newlist->next = NULL; + newlist->object = obj; + + args = args->next; + } + } +} + +static ObjectList *CFunc_CopyObjectList(const FuncArg *args) { + Object *obj; + ObjectList *list; + ObjectList *last; + + list = NULL; + + while (args) { + if (list) { + last->next = lalloc(sizeof(ObjectList)); + last = last->next; + } else { + last = lalloc(sizeof(ObjectList)); + list = last; + } + + obj = CParser_NewLocalDataObject(NULL, 0); + obj->name = args->name; + obj->type = args->type; + obj->qual = args->qual; + obj->sclass = args->sclass; + CFunc_SetupLocalVarInfo(obj); + + last->object = obj; + last->next = NULL; + + args = args->next; + } + + return list; +} + +static void SetupFunctionArguments(Object *func, DeclInfo *di, Statement *firstStmt) { + ObjectList *list; + Object *resultobj; + Object *obj; + Type *type; + DeclInfo my_di; + + if (TYPE_FUNC(func->type)->args) { + if (di->x45) { + arguments = CFunc_CopyObjectList(di->x18); + while (1) { + if (tk == '{') + break; + + memclrw(&my_di, sizeof(my_di)); + CParser_GetDeclSpecs(&my_di, 0); + + type = my_di.thetype; + if (my_di.storageclass && my_di.storageclass != TK_REGISTER) + CError_Error(CErrorStr127); + + while (1) { + my_di.thetype = type; + my_di.name = NULL; + scandeclarator(&my_di); + if (!my_di.name) { + CError_Error(CErrorStr107); + break; + } + + adjustargumenttype(&my_di); + IsCompleteType(my_di.thetype); + + if ((obj = CFunc_IsInObjList(arguments, my_di.name))) { + if (obj->type) + CError_Error(CErrorStr333, obj); + obj->type = my_di.thetype; + obj->sclass = my_di.storageclass; + obj->qual = my_di.qual; + } else { + CError_Error(CErrorStr127); + } + + if (tk != ',') + break; + tk = lex(); + } + + if (tk != ';') + CError_ErrorSkip(CErrorStr123); + else + tk = lex(); + } + + for (list = arguments; list; list = list->next) { + if (!list->object->type) + list->object->type = TYPE(&stsignedint); + } + } else { + CFunc_SetupNewFuncArgs(func, TYPE_FUNC(func->type)->args); + } + } + + if (CMach_GetFunctionResultClass(TYPE_FUNC(func->type)) == 1) { + resultobj = CParser_NewLocalDataObject(NULL, 0); + resultobj->name = temp_argument_name; + resultobj->type = CDecl_NewPointerType(TYPE_FUNC(func->type)->functype); + CFunc_SetupLocalVarInfo(resultobj); + + list = lalloc(sizeof(ObjectList)); + list->object = resultobj; + if (CABI_GetStructResultArgumentIndex(TYPE_FUNC(func->type))) { + CError_ASSERT(2797, arguments); + list->next = arguments->next; + arguments->next = list; + } else { + list->next = arguments; + arguments = list; + } + } + + for (list = arguments; list; list = list->next) { + NameSpaceObjectList *nsol = CScope_InsertName(cscope_current, list->object->name); + nsol->object = OBJ_BASE(list->object); + } +} + +NameSpace *CFunc_FuncGenSetup(Statement *stmt, Object *func) { + NameSpace *nspace; + DeclBlock *block; + + nspace = CScope_NewListNameSpace(NULL, 0); + nspace->parent = cscope_current; + cscope_current = nspace; + + arguments = NULL; + locals = NULL; + Labels = NULL; + + localcount = 0; + cfunc_staticvarcount = 0; + + CExcept_Setup(); + + memclrw(stmt, sizeof(Statement)); + curstmt = stmt; + stmt->type = ST_NOP; + curstmtvalue = 1; + stmt->value = 1; + + blockcount = 0; + block = lalloc(sizeof(DeclBlock)); + memclrw(block, sizeof(DeclBlock)); + block->index = blockcount++; + block->parent_nspace = cscope_current; + + firstblock = block; + currentblock = block; + + return nspace; +} + +CFuncSave *CFunc_GetGlobalCompilerState(void) { + CFuncSave *state; + + if (!cscope_currentfunc && !cscope_currentclass && cscope_current == cscope_root) + return NULL; + + locklheap(); + state = lalloc(sizeof(CFuncSave)); + + CScope_SetNameSpaceScope(cscope_root, &state->scope); + + state->arguments = arguments; + arguments = NULL; + + state->locals = locals; + locals = NULL; + + state->labels = Labels; + Labels = NULL; + + state->curstmt = curstmt; + curstmt = NULL; + + state->firstblock = firstblock; + firstblock = NULL; + + state->currentblock = currentblock; + currentblock = NULL; + + state->cexcept_dobjstack = cexcept_dobjstack; + cexcept_dobjstack = NULL; + + state->sinit_label = sinit_label; + sinit_label = NULL; + + state->ainit_expr = ainit_expr; + ainit_expr = NULL; + + state->ctor_chain = ctor_chain; + ctor_chain = NULL; + + state->cinit_tempnodefunc = cinit_tempnodefunc; + cinit_tempnodefunc = NULL; + + state->trychain = trychain; + trychain = NULL; + + state->cparser_fileoffset = cparser_fileoffset; + state->symdecltoken = symdecltoken; + + state->functionbodyoffset = functionbodyoffset; + functionbodyoffset = 0; + + state->functionbodypath = functionbodypath; + functionbodypath = NULL; + + state->symdecloffset = symdecloffset; + symdecloffset = 0; + + state->symdeclend = symdeclend; + + state->sourceoffset = sourceoffset; + sourceoffset = 0; + + state->sourcefilepath = sourcefilepath; + sourcefilepath = NULL; + + state->curstmtvalue = curstmtvalue; + curstmtvalue = 0; + + state->name_obj_check = name_obj_check; + name_obj_check = NULL; + + state->check_arglist = check_arglist; + check_arglist = NULL; + + state->blockcount = blockcount; + blockcount = 0; + + state->localcount = localcount; + localcount = 0; + + state->tk = tk; + state->tkidentifier = tkidentifier; + + state->global_access = global_access; + + state->cexcept_hasdobjects = cexcept_hasdobjects; + cexcept_hasdobjects = 0; + + state->sinit_first_object = sinit_first_object; + sinit_first_object = NULL; + + state->ainit_only_one = ainit_only_one; + ainit_only_one = 0; + + state->cfunc_is_extern_c = cfunc_is_extern_c; + cfunc_is_extern_c = 0; + + state->temp_reference_init = temp_reference_init; + + return state; +} + +void CFunc_SetGlobalCompilerState(CFuncSave *state) { + if (state) { + CScope_RestoreScope(&state->scope); + + arguments = state->arguments; + locals = state->locals; + Labels = state->labels; + curstmt = state->curstmt; + firstblock = state->firstblock; + currentblock = state->currentblock; + cexcept_dobjstack = state->cexcept_dobjstack; + sinit_label = state->sinit_label; + ainit_expr = state->ainit_expr; + ctor_chain = state->ctor_chain; + cinit_tempnodefunc = state->cinit_tempnodefunc; + trychain = state->trychain; + name_obj_check = state->name_obj_check; + check_arglist = state->check_arglist; + curstmtvalue = state->curstmtvalue; + cparser_fileoffset = state->cparser_fileoffset; + symdecltoken = state->symdecltoken; + functionbodyoffset = state->functionbodyoffset; + functionbodypath = state->functionbodypath; + symdecloffset = state->symdecloffset; + symdeclend = state->symdeclend; + sourceoffset = state->sourceoffset; + sourcefilepath = state->sourcefilepath; + blockcount = state->blockcount; + tk = state->tk; + tkidentifier = state->tkidentifier; + global_access = state->global_access; + localcount = state->localcount; + cexcept_hasdobjects = state->cexcept_hasdobjects; + sinit_first_object = state->sinit_first_object; + ainit_only_one = state->ainit_only_one; + cfunc_is_extern_c = state->cfunc_is_extern_c; + temp_reference_init = state->temp_reference_init; + + unlocklheap(); + } +} + +void CFunc_Gen(Statement *stmt, Object *func, UInt8 unk) { + Boolean flag; + CI_FuncData packed; + + if ((TYPE_FUNC(func->type)->flags & FUNC_FLAGS_400000) && !anyerrors) { + CInline_PackIFunctionData(&packed, stmt, func); + flag = 1; + } else { + flag = 0; + } + + CInline_GenFunc(stmt, func, unk); + + if (flag) + CClass_DefineCovariantFuncs(func, &packed); +} + +static void CFunc_CheckCtorInitializer(TypeClass *tclass, CtorChain *chain) { + ObjMemberVar *ivar; + CtorChain *scan; + + if (tclass->mode != CLASS_MODE_UNION) { + for (ivar = tclass->ivars; ivar; ivar = ivar->next) { + if (IS_TYPE_REFERENCE(ivar->type)) { + for (scan = chain; scan; scan = scan->next) { + if (scan->what == CtorChain_MemberVar && scan->u.membervar == ivar) + break; + } + + if (!scan) + CError_Error(CErrorStr256, ivar->name->name); + } else if (CParser_IsConst(ivar->type, ivar->qual)) { + for (scan = chain; scan; scan = scan->next) { + if (scan->what == CtorChain_MemberVar && scan->u.membervar == ivar) + break; + } + + if (!scan && !IS_TYPE_CLASS(ivar->type)) + CError_Error(CErrorStr255, ivar->name->name); + } + } + } +} + +void CFunc_CheckClassCtors(TypeClass *tclass) { + CFunc_CheckCtorInitializer(tclass, NULL); +} + +static void CFunc_ParseCtorInitializer(void) { + CtorChain *chain; + ENodeList *args; + TypeClass *tclass; + ObjMemberVar *ivar; + ClassList *base; + VClassList *vbase; + ENode *expr; + Type *origtype; + + ctor_chain = NULL; + + if (tk == ':') { + do { + tclass = NULL; + switch ((tk = lex())) { + case TK_IDENTIFIER: + for (ivar = cscope_currentclass->ivars; ivar; ivar = ivar->next) { + if (ivar->name == tkidentifier && lookahead() == '(') + goto do_ivar; + } + for (base = cscope_currentclass->bases; base; base = base->next) { + if (base->base->classname == tkidentifier) { + if (lookahead() == '(') { + tclass = base->base; + tk = lex(); + } else { + tkidentifier = base->base->classname; + } + break; + } + } + break; + + case TK_COLON_COLON: + break; + + default: + CError_Error(CErrorStr212); + return; + } + + if (!tclass) + tclass = CClass_GetQualifiedClass(); + + if (tclass) { + for (vbase = cscope_currentclass->vbases; vbase; vbase = vbase->next) { + if (vbase->base == tclass) + break; + } + + if (vbase) { + for (chain = ctor_chain; chain; chain = chain->next) { + if (chain->what == CtorChain_VBase && chain->u.vbase == vbase) { + CError_Error(CErrorStr212); + return; + } + } + + chain = lalloc(sizeof(CtorChain)); + chain->what = CtorChain_VBase; + chain->u.vbase = vbase; + } else { + for (base = cscope_currentclass->bases; base; base = base->next) { + if (base->base == tclass) + break; + } + + if (base) { + for (chain = ctor_chain; chain; chain = chain->next) { + if (chain->what == CtorChain_Base && chain->u.base == base) { + CError_Error(CErrorStr212); + return; + } + } + + chain = lalloc(sizeof(CtorChain)); + chain->what = CtorChain_Base; + chain->u.base = base; + } else { + CError_Error(CErrorStr212); + return; + } + } + } else { + for (ivar = cscope_currentclass->ivars; ivar; ivar = ivar->next) { + if (ivar->name == tkidentifier) + break; + } + + if (ivar) { + do_ivar: + for (chain = ctor_chain; chain; chain = chain->next) { + if (chain->what == CtorChain_MemberVar && chain->u.membervar == ivar) + CError_Error(CErrorStr212); + } + + chain = lalloc(sizeof(CtorChain)); + chain->what = CtorChain_MemberVar; + chain->u.membervar = ivar; + } else { + CError_Error(CErrorStr212); + return; + } + + tk = lex(); + } + + if (tk != '(') { + CError_Error(CErrorStr114); + return; + } + + tk = lex(); + args = CExpr_ScanExpressionList(1); + + if (tk != ')') { + CError_Error(CErrorStr115); + return; + } + + switch (chain->what) { + case CtorChain_Base: + expr = CABI_MakeThisExpr(NULL, chain->u.base->offset); + chain->objexpr = CExpr_ConstructObject(chain->u.base->base, expr, args, 1, 0, 0, 0, 1); + break; + case CtorChain_VBase: + expr = CABI_MakeThisExpr(chain->u.vbase->base, chain->u.vbase->offset); + chain->objexpr = CExpr_ConstructObject(chain->u.vbase->base, expr, args, 1, 0, 0, 0, 1); + break; + case CtorChain_MemberVar: + expr = CABI_MakeThisExpr(cscope_currentclass, chain->u.membervar->offset); + expr->flags = chain->u.membervar->qual & ENODE_FLAG_QUALS; + switch (chain->u.membervar->type->type) { + case TYPECLASS: + chain->objexpr = CExpr_ConstructObject(TYPE_CLASS(chain->u.membervar->type), expr, args, 1, 1, 0, 1, 1); + break; + case TYPEARRAY: + if (args) { + CError_Error(CErrorStr212); + continue; + } + chain->objexpr = NULL; + break; + default: + if (!args) { + args = lalloc(sizeof(ENodeList)); + args->next = NULL; + args->node = CExpr_DoExplicitConversion(chain->u.membervar->type, chain->u.membervar->qual, NULL); + } + if (args->next) { + CError_Error(CErrorStr212); + return; + } + expr = makemonadicnode(expr, EINDIRECT); + expr->rtype = chain->u.membervar->type; + if (IS_TYPE_BITFIELD(origtype = expr->rtype)) { + expr->data.monadic = makemonadicnode(expr->data.monadic, EBITFIELD); + expr->data.monadic->rtype = origtype; + expr->rtype = TYPE_BITFIELD(origtype)->bitfieldtype; + } + + chain->objexpr = makediadicnode(expr, CExpr_AssignmentPromotion(args->node, expr->rtype, expr->flags, 1), EASS); + } + break; + default: + CError_FATAL(3286); + } + + chain->next = ctor_chain; + ctor_chain = chain; + } while ((tk = lex()) == ','); + } +} + +static void CFunc_FunctionRedefinedCheck(Object *func) { + if (TYPE_FUNC(func->type)->flags & FUNC_AUTO_GENERATED) + CError_Error(CErrorStr333, func); + + if ((TYPE_FUNC(func->type)->flags & FUNC_DEFINED) && func->datatype != DINLINEFUNC) + CError_Error(CErrorStr333, func); + + TYPE_FUNC(func->type)->flags |= FUNC_DEFINED; +} + +static Object *CFunc_DeclareFuncName(char *str, HashNameNode *name) { + Object *obj; + Object *aliasobj; + DeclInfo di; + + memclrw(&di, sizeof(di)); + di.name = name; + di.storageclass = TK_STATIC; + di.qual = Q_CONST; + di.thetype = CDecl_NewArrayType(TYPE(&stchar), strlen(str) + 1); + + obj = CParser_NewGlobalDataObject(&di); + aliasobj = CParser_NewAliasObject(obj, 0); + obj->nspace = cscope_root; + obj->datatype = DDATA; + CFunc_NameLocalStaticDataObject(obj, obj->name->name); + + return aliasobj; +} + +void CFunc_ParseFuncDef(Object *func, DeclInfo *di, TypeClass *tclass, Boolean is_method, Boolean is_static, NameSpace *nspace) { + Boolean has_try; + Object *nameobj_func; + Object *nameobj_FUNCTION; + Object *nameobj_pretty; + char *prettyname; + Statement *stmt18; + Statement *stmt16; + Statement firstStmt; + DeclThing thing; + CScopeSave scope; + + nameobj_func = NULL; + nameobj_FUNCTION = NULL; + nameobj_pretty = NULL; + prettyname = NULL; + + CError_ASSERT(3373, IS_TYPE_FUNC(func->type)); + + CFunc_FunctionRedefinedCheck(func); + CParser_UpdateObject(func, di); + + if (!is_method) { + CScope_SetFunctionScope(func, &scope); + if (tclass) + cscope_current = tclass->nspace; + } else { + CScope_SetMethodScope(func, tclass, is_static, &scope); + } + + if (nspace) + cscope_current = nspace; + + if (cscope_currentclass) + CClass_MemberDef(func, cscope_currentclass); + + cfunc_is_extern_c = di->is_extern_c; + + CError_ASSERT(3392, IS_TYPE_FUNC(func->type)); + if (di->x45 && (func->qual & Q_ASM)) + CError_Error(CErrorStr176); + + if (cparamblkptr->precompile == 1 && !(func->qual & Q_INLINE)) + CError_ErrorTerm(CErrorStr180); + + if (di->x49) + CError_Error(CErrorStr127); + + CFunc_FuncGenSetup(&firstStmt, func); + if (!IS_TYPE_VOID(TYPE_FUNC(func->type)->functype)) + IsCompleteType(TYPE_FUNC(func->type)->functype); + + SetupFunctionArguments(func, di, &firstStmt); + + stmt18 = curstmt; + CPrep_GetFileOffsetInfo2(&cparser_fileoffset, &sourceoffset, &sourcefilepath); + functionbodyoffset = sourceoffset; + firstStmt.sourceoffset = sourceoffset; + functionbodypath = sourcefilepath; + firstStmt.sourcefilepath = sourcefilepath; + + if (di->x45) + CFunc_AdjustOldStyleArgs(); + + if (di->x1C) + CScope_MergeNameSpace(cscope_current, di->x1C); + + if (tk == TK_TRY) { + tk = lex(); + has_try = 1; + } else { + has_try = 0; + } + + if (CClass_IsConstructor(func)) { + CError_ASSERT(3445, cscope_currentclass); + CFunc_ParseCtorInitializer(); + CFunc_CheckCtorInitializer(cscope_currentclass, ctor_chain); + } + + CPrep_TokenStreamFlush(); + + if (!(func->qual & Q_ASM)) { + if (tk == '{') { + if (!has_try) + tk = lex(); + } else { + CError_ErrorSkip(CErrorStr135); + has_try = 0; + } + + if (func->name) { + nameobj_func = CFunc_DeclareFuncName(func->name->name, GetHashNameNode("__func__")); + nameobj_FUNCTION = CFunc_DeclareFuncName(func->name->name, GetHashNameNode("__FUNCTION__")); + prettyname = CError_GetObjectName(func); + nameobj_pretty = CFunc_DeclareFuncName(prettyname, GetHashNameNode("__PRETTY_FUNCTION__")); + } + + if (!copts.cplusplus) + CFunc_ParseLocalDeclarationList(0, 0, 0, 0); + + thing.switchinfo = NULL; + thing.loopContinue = NULL; + thing.loopBreak = NULL; + thing.thetype = TYPE_FUNC(func->type)->functype; + thing.qual = TYPE_FUNC(func->type)->qual; + + if (has_try) { + CExcept_ScanTryBlock(&thing, CClass_IsConstructor(func) || CClass_IsDestructor(func)); + if (tk != 0) + CPrep_UnLex(); + tk = '}'; + } else { + while (tk != '}') + statement(&thing); + } + + stmt16 = curstmt; + + if (stmt16->type != ST_RETURN && stmt16->type != ST_GOTO) { + CPrep_GetFileOffsetInfo2(&cparser_fileoffset, &sourceoffset, &sourcefilepath); + CFunc_AppendStatement(ST_RETURN); + + curstmt->dobjstack = NULL; + curstmt->expr = NULL; + + if ( + (copts.cplusplus || copts.c9x) && + !strcmp(func->name->name, "main") && + TYPE_FUNC(func->type)->functype == TYPE(&stsignedint) + ) + curstmt->expr = intconstnode(TYPE(&stsignedint), 0); + + if ( + stmt16->type == ST_EXPRESSION && + stmt16->expr->type == EFUNCCALL && + stmt16->expr->rtype == &stvoid && + (stmt16->expr->flags & ENODE_FLAG_VOLATILE) + ) + curstmt->flags = curstmt->flags | StmtFlag_8; + } + + CheckCLabels(); + + if (nameobj_func && (nameobj_func->flags & OBJECT_USED)) + CInit_DeclareData(nameobj_func->u.alias.object, func->name->name, NULL, strlen(func->name->name) + 1); + if (nameobj_FUNCTION && (nameobj_FUNCTION->flags & OBJECT_USED)) + CInit_DeclareData(nameobj_FUNCTION->u.alias.object, func->name->name, NULL, strlen(func->name->name) + 1); + if (nameobj_pretty && (nameobj_pretty->flags & OBJECT_USED)) + CInit_DeclareData(nameobj_pretty->u.alias.object, prettyname, NULL, strlen(prettyname) + 1); + + if (!fatalerrors) { + if (CClass_IsConstructor(func)) + CABI_TransConstructor(func, stmt18, cscope_currentclass, NULL, has_try); + if (CClass_IsDestructor(func)) + CABI_TransDestructor(func, func, &firstStmt, cscope_currentclass, 0); + + CFunc_DestructorCleanup(&firstStmt); + CFunc_CodeCleanup(&firstStmt); + symdeclend = CPrep_GetFileOffsetInfo(&cparser_fileoffset); + CFunc_Gen(&firstStmt, func, di->x45); + } + } else { + if (tk == '{') { + in_assembler = 1; + tk = lex(); + in_assembler = 0; + } else { + CError_ErrorSkip(CErrorStr135); + } + + CFunc_ParseLocalDeclarationList(1, 0, 0, 0); + Assembler(func); + } + + if (tk != '}') + CError_Error(CErrorStr130); + + CScope_RestoreScope(&scope); +} + +void InitExpr_Register(ENode *expr, Object *object) { + InitExpr *initexpr; + InitExpr *scan; + + if ( + cparamblkptr->precompile == 1 && + object->sclass != TK_STATIC && + !(object->qual & (Q_20000 | Q_WEAK)) + ) + { + CError_Error(CErrorStr180); + return; + } + + if (copts.suppress_init_code) + return; + + initexpr = galloc(sizeof(InitExpr)); + initexpr->next = NULL; + initexpr->object = object; + initexpr->expr = CInline_CopyExpression(expr, CopyMode1); + + if (init_expressions) { + scan = init_expressions; + while (scan->next) + scan = scan->next; + scan->next = initexpr; + } else { + init_expressions = initexpr; + } +} + +void CFunc_GenerateDummyFunction(Object *func) { + NameSpace *nspace; + Boolean saveDebugInfo; + Statement firstStmt; + + if (!anyerrors) { + nspace = CFunc_FuncGenSetup(&firstStmt, NULL); + + saveDebugInfo = copts.filesyminfo; + copts.filesyminfo = 0; + + CFunc_CodeCleanup(&firstStmt); + CFunc_Gen(&firstStmt, func, 0); + + cscope_current = nspace->parent; + copts.filesyminfo = saveDebugInfo; + } +} + +void CFunc_GenerateSingleExprFunc(Object *func, ENode *expr) { + NameSpace *nspace; + Boolean saveDebugInfo; + Statement firstStmt; + Statement *stmt; + + if (cparamblkptr->precompile == 1) { + CError_Error(CErrorStr180); + return; + } + + if (!anyerrors) { + nspace = CFunc_FuncGenSetup(&firstStmt, func); + + saveDebugInfo = copts.filesyminfo; + copts.filesyminfo = 0; + + stmt = CFunc_AppendStatement(ST_EXPRESSION); + stmt->expr = expr; + + CFunc_CodeCleanup(&firstStmt); + CInline_GenFunc(&firstStmt, func, 0); + + cscope_current = nspace->parent; + copts.filesyminfo = saveDebugInfo; + } +} + +void CFunc_GenerateDummyCtorFunc(Object *func, Object *real_ctor) { + ENode *expr; + NameSpace *nspace; + FuncArg *arg1; + FuncArg *arg0; + ENodeList *list; + Boolean saveDebugInfo; + Statement firstStmt; + Statement *stmt; + + if (cparamblkptr->precompile == 1) { + CError_Error(CErrorStr180); + return; + } + + if (!anyerrors) { + cscope_currentfunc = func; + + nspace = CFunc_FuncGenSetup(&firstStmt, func); + + saveDebugInfo = copts.filesyminfo; + copts.filesyminfo = 0; + + CFunc_SetupNewFuncArgs(func, TYPE_FUNC(func->type)->args); + + expr = CExpr_NewENode(EFUNCCALL); + expr->type = EFUNCCALL; + expr->cost = 200; + expr->rtype = TYPE(&void_ptr); + expr->data.funccall.funcref = CExpr_MakeObjRefNode(real_ctor, 0); + expr->data.funccall.functype = TYPE_FUNC(func->type); + + CError_ASSERT(3716, IS_TYPE_FUNC(real_ctor->type)); + CError_ASSERT(3717, TYPE_FUNC(real_ctor->type)->flags & FUNC_METHOD); + CError_ASSERT(3718, arg0 = TYPE_FUNC(real_ctor->type)->args); + CError_ASSERT(3720, arg1 = arg0->next); + CError_ASSERT(3721, arguments); + + list = lalloc(sizeof(ENodeList)); + expr->data.funccall.args = list; + list->node = create_objectnode(arguments->object); + + if (TYPE_METHOD(real_ctor->type)->theclass->flags & CLASS_HAS_VBASES) { + CError_ASSERT(3727, arg1 = arg1->next); + CError_ASSERT(3728, arguments->next); + list->next = lalloc(sizeof(ENodeList)); + list = list->next; + list->node = create_objectnode(arguments->next->object); + } + + while (arg1) { + CError_ASSERT(3737, arg1->dexpr); + list->next = lalloc(sizeof(ENodeList)); + list = list->next; + list->node = CExpr_GetDefaultArgument(expr->data.funccall.funcref, arg1); + arg1 = arg1->next; + } + + list->next = NULL; + + stmt = CFunc_AppendStatement(ST_RETURN); + stmt->expr = expr; + + CFunc_CodeCleanup(&firstStmt); + CInline_GenFunc(&firstStmt, func, 0); + + cscope_current = nspace->parent; + cscope_currentfunc = NULL; + copts.filesyminfo = saveDebugInfo; + } +} diff --git a/compiler_and_linker/FrontEnd/C/CInit.c b/compiler_and_linker/FrontEnd/C/CInit.c new file mode 100644 index 0000000..c2d2299 --- /dev/null +++ b/compiler_and_linker/FrontEnd/C/CInit.c @@ -0,0 +1,3082 @@ +#include "compiler/CInit.h" +#include "compiler/CABI.h" +#include "compiler/CClass.h" +#include "compiler/CDecl.h" +#include "compiler/CError.h" +#include "compiler/CException.h" +#include "compiler/CExpr.h" +#include "compiler/CInline.h" +#include "compiler/CInt64.h" +#include "compiler/CMachine.h" +#include "compiler/CParser.h" +#include "compiler/CPrec.h" +#include "compiler/CPrep.h" +#include "compiler/CPrepTokenizer.h" +#include "compiler/CScope.h" +#include "compiler/CompilerTools.h" +#include "compiler/ObjGenMachO.h" +#include "compiler/objects.h" +#include "compiler/types.h" + +TempNodeCB cinit_tempnodefunc; +InitInfo *cinit_initinfo; +static PooledString *cinit_stringlist; +static PooledString *cinit_pooledstringlist; +static PooledString *cinit_pooledwstringlist; +static ObjectList *cinit_tentative; +static TypeClass *cinit_loop_class; +static ENodeList *cinit_fdtnode; +static Boolean cinit_fdtambig; + +#ifdef __MWERKS__ +#pragma options align=mac68k +#endif +typedef struct CInit_1C { + struct CInit_1C *next; + Type *type; + ENode *expr; + SInt32 offset; +} CInit_1C; + +typedef struct CInit_Stuff { + struct CInit_Stuff *x0; + struct CInit_Stuff *x4; + char *buffer; + SInt32 xC; + SInt32 size; + SInt32 bufferSize; + SInt32 x18; + CInit_1C *x1C; + OLinkList *list; + Boolean flag; +} CInit_Stuff; + +typedef enum { + Stage0, + Stage1, + Stage2, + Stage3, + Stage4 +} Stage; + +typedef struct CInit_Stuff2 { + ENode *expr; + ENode myexpr; + Stage stage; + Boolean x23; + SInt32 x24; + Type *type; +} CInit_Stuff2; +#ifdef __MWERKS__ +#pragma options align=reset +#endif + +// forward decls +static void CInit_InitType(CInit_Stuff *s, CInit_Stuff2 *s2, Type *type, UInt32 qual, Boolean flag); +static void CInit_Type(Type *type, UInt32 qual, Boolean flag); + +void CInit_Init(void) { + cinit_tempnodefunc = NULL; + cinit_initinfo = NULL; + cinit_stringlist = NULL; + cinit_pooledstringlist = NULL; + cinit_pooledwstringlist = NULL; + cinit_tentative = NULL; +} + +static void CInit_SetupInitInfo(InitInfo *info, Object *obj) { + memclrw(info, sizeof(InitInfo)); + info->obj = obj; + info->next = cinit_initinfo; + cinit_initinfo = info; +} + +static void CInit_CleanupInitInfo(InitInfo *info) { + cinit_initinfo = info->next; +} + +static void CInit_SetupInitInfoBuffer(Type *type) { + SInt32 size = type->size; + cinit_initinfo->size = size; + + if (!size) + size = 512; + else if (size & 1) + size++; + + cinit_initinfo->buffer = lalloc(size); + cinit_initinfo->bufferSize = size; + memclrw(cinit_initinfo->buffer, size); +} + +static void CInit_SetData(void *data, SInt32 offset, SInt32 size) { + SInt32 end; + char *buffer; + + end = offset + size; + if (end > cinit_initinfo->size) + cinit_initinfo->size = end; + + if (end > cinit_initinfo->bufferSize) { + if (cinit_initinfo->obj->type->size == 0) { + if (end < 8000) + end += 0x400; + else + end += 0x4000; + } + if (end & 1) + end++; + + buffer = lalloc(end); + memclrw(buffer, end); + memcpy(buffer, cinit_initinfo->buffer, cinit_initinfo->bufferSize); + cinit_initinfo->buffer = buffer; + cinit_initinfo->bufferSize = end; + } + + if (data) + memcpy(cinit_initinfo->buffer + offset, data, size); +} + +typedef struct CInit_Initializer { + struct CInit_Initializer *next; + struct CInit_Initializer *sublist; + ENode *expr; + TStreamElement element; +} CInit_Initializer; + +static CInit_Initializer *CInit_ParseInitializerList(void) { + CInit_Initializer *r30; + CInit_Initializer *r29; + CInit_Initializer *tmp; + + if ((tk = lex()) == '}') + return NULL; + + r30 = NULL; + do { + if (r30) { + tmp = lalloc(sizeof(CInit_Initializer)); + r29->next = tmp; + r29 = tmp; + } + if (!r30) { + r30 = r29 = lalloc(sizeof(CInit_Initializer)); + } + r29->next = NULL; + + if (tk == '{') { + r29->element = *CPrep_CurStreamElement(); + r29->sublist = CInit_ParseInitializerList(); + r29->expr = NULL; + tk = lex(); + } else { + r29->sublist = NULL; + r29->expr = conv_assignment_expression(); + r29->element = *CPrep_CurStreamElement(); + } + + if (tk == '}') + return r30; + + if (tk != ',') { + CError_Error(CErrorStr116); + return r30; + } + } while ((tk = lex()) != '}'); + + return r30; +} + +static CInit_Initializer *CInit_ParseInitializerClause(void) { + CInit_Initializer *init; + + init = lalloc(sizeof(CInit_Initializer)); + init->next = NULL; + if (tk != '{') { + init->sublist = NULL; + init->expr = conv_assignment_expression(); + init->element = *CPrep_CurStreamElement(); + } else { + init->element = *CPrep_CurStreamElement(); + init->expr = NULL; + init->sublist = CInit_ParseInitializerList(); + tk = lex(); + } + + return init; +} + +static ENode *CInit_ParseInitializer(ENode *expr) { + CInt64 save_int; + Float save_float; + SInt32 save_size; + short t; + + switch (tk) { + case TK_INTCONST: + case TK_FLOATCONST: + save_int = tkintconst; + save_float = tkfloatconst; + save_size = tksize; + t = lookahead(); + tkintconst = save_int; + tkfloatconst = save_float; + tksize = save_size; + + switch (t) { + case ',': + case ';': + case '}': + memclrw(expr, sizeof(ENode)); + switch (tk) { + case TK_INTCONST: + expr->type = EINTCONST; + expr->rtype = atomtype(); + expr->data.intval = tkintconst; + break; + case TK_FLOATCONST: + expr->type = EFLOATCONST; + expr->rtype = atomtype(); + expr->data.floatval = tkfloatconst; + break; + } + tk = lex(); + CPrep_TokenStreamFlush(); + return expr; + } + } + + expr = assignment_expression(); + CPrep_TokenStreamFlush(); + return expr; +} + +static Stage CInit_ParseNextInit(CInit_Stuff2 *s) { + DeclInfo di; + short t; + + s->expr = NULL; + if (tk == ';') { + s->stage = Stage4; + return Stage4; + } + switch (s->stage) { + case Stage0: + if (s->x23) { + if (tk == '(') { + tk = lex(); + CParser_GetDeclSpecs(&di, 1); + s->type = di.thetype; + if (tk == ')') + tk = lex(); + else + CError_Error(CErrorStr115); + + if (tk == '(') + tk = lex(); + else + CError_Error(CErrorStr114); + s->x24++; + t = lookahead(); + if (t == TK_UU_VECTOR || (t == TK_IDENTIFIER && !strcmp("vector", tkidentifier->name))) + CInit_ParseNextInit(s); + s->stage = Stage1; + return Stage1; + } + } else { + if (tk == '{') { + tk = lex(); + s->x24 = 0; + s->stage = Stage1; + return Stage1; + } + } + s->expr = CInit_ParseInitializer(&s->myexpr); + s->stage = Stage2; + return Stage2; + case Stage1: + break; + case Stage2: + case Stage3: + if (tk == ',') { + tk = lex(); + break; + } + if (s->x24) { + if (tk != ')') + CError_Error(CErrorStr174); + if (s->x24 > 1) { + s->x24--; + tk = lex(); + CInit_ParseNextInit(s); + } + } else { + if (tk != '}') + CError_Error(CErrorStr174); + } + s->stage = Stage3; + return Stage3; + default: + CError_FATAL(389); + } + + switch (tk) { + case '{': + tk = lex(); + s->stage = Stage1; + return Stage1; + case '}': + s->stage = Stage3; + return Stage3; + case '(': + if (s->x23) { + tk = lex(); + s->stage = Stage1; + return Stage1; + } + case ')': + if (s->x23 && s->x24) { + if (s->x24 > 1) { + s->x24--; + tk = lex(); + CInit_ParseNextInit(s); + } + s->stage = Stage3; + return Stage3; + } + default: + s->expr = CInit_ParseInitializer(&s->myexpr); + s->stage = Stage2; + return Stage2; + } +} + +static void CInit_CloseInitList(void) { + if (tk == ',' && copts.cplusplus) + tk = lex(); + + if (tk != '}') + CError_ErrorSkip(CErrorStr130); + else + tk = lex(); +} + +static Boolean CInit_IsAllZero(char *buf, SInt32 size) { + SInt32 i; + + if (copts.explicit_zero_data) + return 0; + + for (i = 0; i < size; i++) + if (buf[i]) return 0; + + return 1; +} + +static Boolean CInit_ClassNeedsConstruction(TypeClass *tclass) { + return CClass_Constructor(tclass) || CClass_Destructor(tclass); +} + +static Boolean CInit_IsSimpleStructArrayInit(Type *type) { + switch (type->type) { + case TYPESTRUCT: + return 1; + case TYPEARRAY: + while (IS_TYPE_ARRAY(type)) + type = TYPE_POINTER(type)->target; + if (!IS_TYPE_CLASS(type)) + return 1; + case TYPECLASS: + return !CInit_ClassNeedsConstruction(TYPE_CLASS(type)); + default: + return 0; + } +} + +static Boolean CInit_IsSimpleInit(Type *type) { + switch (type->type) { + case TYPEPOINTER: + return (TYPE_POINTER(type)->qual & Q_REFERENCE) == 0; + case TYPEARRAY: + while (IS_TYPE_ARRAY(type)) + type = TYPE_POINTER(type)->target; + if (!IS_TYPE_CLASS(type)) + return 1; + case TYPECLASS: + return !CInit_ClassNeedsConstruction(TYPE_CLASS(type)); + default: + return 1; + } +} + +static Object *CInit_GetInitObject(Object *obj) { + if (obj->datatype == DALIAS) { + CError_ASSERT(521, !obj->u.alias.offset); + obj = obj->u.alias.object; + } + return obj; +} + +static Object *CInit_CreateStaticDataObject(Type *type, UInt32 qual, HashNameNode *name) { + Object *obj; + DeclInfo di; + + memclrw(&di, sizeof(DeclInfo)); + di.thetype = type; + di.name = name ? name : CParser_GetUniqueName(); + di.qual = qual; + di.storageclass = TK_STATIC; + di.is_extern_c = 1; + + obj = CParser_NewGlobalDataObject(&di); + obj->nspace = cscope_root; + return obj; +} + +static Type *CInit_GetRegMemType(void) { + return CDecl_NewStructType(void_ptr.size * 3, CMach_GetTypeAlign((Type *) &void_ptr)); +} + +static Object *CInit_CreateStaticData(Type *type) { + Object *obj = CInit_CreateStaticDataObject(type, 0, NULL); + CInit_DeclareData(obj, NULL, NULL, obj->type->size); + return obj; +} + +static void CInit_InitNonConst(CInit_Stuff *s, Type *type, ENode *expr) { + CInit_1C *entry; + CInit_1C *scan; + MWVector128 *vec; + + if (s->x4->flag || IS_TYPE_VECTOR(type)) { + if (IS_TYPE_VECTOR(type) && ENODE_IS(expr, EVECTOR128CONST)) { + vec = (MWVector128 *) (s->buffer + s->size); + *vec = expr->data.vector128val; + CMach_InitVectorMem(type, *vec, vec, 1); + } + + entry = lalloc(sizeof(CInit_1C)); + memclrw(entry, sizeof(CInit_1C)); + entry->next = NULL; + entry->type = type; + entry->expr = expr; + entry->offset = s->xC + s->size; + if ((scan = s->x4->x1C)) { + while (scan->next) + scan = scan->next; + scan->next = entry; + } else { + s->x4->x1C = entry; + } + } else { + CError_Error(CErrorStr124); + } +} + +static CInit_Stuff *CInit_GrowBuffer(CInit_Stuff *s, SInt32 size) { + CInit_Stuff *newbuf; + + newbuf = lalloc(sizeof(CInit_Stuff)); + memclrw(newbuf, sizeof(CInit_Stuff)); + newbuf->x4 = s->x4; + newbuf->buffer = lalloc(size); + newbuf->xC = s->xC + s->size; + newbuf->bufferSize = size; + s->x0 = newbuf; + memset(newbuf->buffer, 0, newbuf->bufferSize); + return newbuf; +} + +Boolean CInit_RelocInitCheck(ENode *expr, Object **objptr, CInt64 *valptr, Boolean flag) { + Object *objcheck1; + Object *objcheck2; + CInt64 valcheck1; + CInt64 valcheck2; + + *objptr = NULL; + valptr->lo = 0; + valptr->hi = 0; + + while (1) { + switch (expr->type) { + case EINTCONST: + *valptr = expr->data.intval; + return 1; + case EOBJREF: + objcheck1 = CInit_GetInitObject(expr->data.objref); + if (objcheck1->datatype == DLOCAL && !flag) + return 0; + *objptr = objcheck1; + return 1; + case ESTRINGCONST: + CInit_RewriteString(expr, 0); + continue; + case ETYPCON: + do { + if (expr->rtype->size != expr->data.monadic->rtype->size) + return 0; + expr = expr->data.monadic; + if (!IS_TYPE_POINTER_ONLY(expr->rtype) && !IS_TYPE_INT(expr->rtype)) + return 0; + } while (ENODE_IS(expr, ETYPCON)); + continue; + case EADD: + if (!CInit_RelocInitCheck(expr->data.diadic.left, &objcheck1, &valcheck1, flag)) + return 0; + if (!CInit_RelocInitCheck(expr->data.diadic.right, &objcheck2, &valcheck2, flag)) + return 0; + + if (objcheck1) { + if (objcheck2) + return 0; + *objptr = objcheck1; + } else { + *objptr = objcheck1; + } + + *valptr = CMach_CalcIntDiadic(TYPE(&stunsignedlong), valcheck1, '+', valcheck2); + return 1; + case ESUB: + if (!CInit_RelocInitCheck(expr->data.diadic.left, &objcheck1, &valcheck1, flag)) + return 0; + if (!CInit_RelocInitCheck(expr->data.diadic.right, &objcheck2, &valcheck2, flag)) + return 0; + + if (objcheck2) + return 0; + + *objptr = objcheck1; + *valptr = CMach_CalcIntDiadic(TYPE(&stunsignedlong), valcheck1, '-', valcheck2); + return 1; + default: + return 0; + } + } +} + +static void CInit_InitTypePointer(CInit_Stuff *s, ENode *expr, TypePointer *tptr, UInt32 qual) { + Object *obj; + CInt64 val; + OLinkList *list; + + expr = CExpr_AssignmentPromotion(expr, TYPE(tptr), qual & (Q_CONST | Q_VOLATILE), 1); + if (IS_TYPE_POINTER_ONLY(expr->rtype) || ENODE_IS(expr, EINTCONST)) { + if (CInit_RelocInitCheck(expr, &obj, &val, 0)) { + if (obj) { + list = lalloc(sizeof(OLinkList)); + list->next = s->x4->list; + list->obj = obj; + list->somevalue = CInt64_GetULong(&val); + list->offset = s->xC + s->size; + s->x4->list = list; + } else { + CMach_InitIntMem(TYPE(&stunsignedlong), val, s->buffer + s->size); + } + } else { + CInit_InitNonConst(s, TYPE(tptr), expr); + } + } else { + CError_Error(CErrorStr174); + } +} + +static void CInit_InitTypeInt(CInit_Stuff *s, ENode *expr, TypeIntegral *tint, UInt32 qual) { + expr = CExpr_AssignmentPromotion(expr, TYPE(tint), qual & (Q_CONST | Q_VOLATILE), 1); + if (IS_TYPE_INT(expr->rtype)) { + if (ENODE_IS(expr, EINTCONST)) { + CMach_InitIntMem(TYPE(tint), expr->data.intval, s->buffer + s->size); + } else if (ENODE_IS(expr, ETYPCON) && IS_TYPE_POINTER_ONLY(expr->data.monadic->rtype) && expr->rtype->size == 4 && (copts.cplusplus || !copts.ANSIstrict)) { + CInit_InitTypePointer(s, expr->data.monadic, TYPE_POINTER(expr->data.monadic->rtype), qual); + } else { + CInit_InitNonConst(s, TYPE(tint), expr); + } + } else { + CError_Error(CErrorStr174); + } +} + +static void CInit_InitTypeFloat(CInit_Stuff *s, ENode *expr, TypeIntegral *tint, UInt32 qual) { + expr = CExpr_AssignmentPromotion(expr, TYPE(tint), qual & (Q_CONST | Q_VOLATILE), 1); + if (IS_TYPE_FLOAT(expr->rtype)) { + if (ENODE_IS(expr, EFLOATCONST)) { + CMach_InitFloatMem(TYPE(tint), expr->data.floatval, s->buffer + s->size); + } else { + CInit_InitNonConst(s, TYPE(tint), expr); + } + } else { + CError_Error(CErrorStr174); + } +} + +static void CInit_InitTypeEnum(CInit_Stuff *s, ENode *expr, TypeEnum *tenum, UInt32 qual) { + expr = CExpr_AssignmentPromotion(expr, TYPE(tenum), qual & (Q_CONST | Q_VOLATILE), 1); + if (IS_TYPE_ENUM(expr->rtype)) { + if (ENODE_IS(expr, EINTCONST)) { + CMach_InitIntMem(tenum->enumtype, expr->data.intval, s->buffer + s->size); + } else { + CInit_InitNonConst(s, TYPE(tenum), expr); + } + } else { + CError_Error(CErrorStr174); + } +} + +static void CInit_InitTypeMemberPointer(CInit_Stuff *s, ENode *expr, TypeMemberPointer *tmptr, UInt32 qual) { + expr = CExpr_AssignmentPromotion(expr, TYPE(tmptr), qual & (Q_CONST | Q_VOLATILE), 1); + if (ENODE_IS(expr, EINTCONST)) { + CMach_InitIntMem(TYPE(&stsignedlong), expr->data.intval, s->buffer + s->size); + } else { + CInit_InitNonConst(s, TYPE(tmptr), expr); + } +} + +static void CInit_SetBitfield(TypeBitfield *tbitfield, UInt8 *buffer, CInt64 val) { + int i; + int pos; + int step; + + if (copts.littleendian) { + pos = tbitfield->offset; + step = 1; + } else { + pos = tbitfield->bitlength + tbitfield->offset - 1; + step = -1; + } + for (i = 0; i < tbitfield->bitlength; i++, pos += step) { + if (CInt64_GetULong(&val) & 1) { + if (copts.littleendian) { + buffer[pos >> 3] |= 1 << (pos & 7); + } else { + buffer[pos >> 3] |= 0x80 >> (pos & 7); + } + } + val = CInt64_ShrU(val, cint64_one); + } +} + +static void CInit_InitTypeBitfield(CInit_Stuff *s, ENode *expr, TypeBitfield *tbitfield, UInt32 qual) { + Type *inner; + + inner = tbitfield->bitfieldtype; + if (IS_TYPE_ENUM(inner)) + inner = TYPE_ENUM(inner)->enumtype; + expr = CExpr_AssignmentPromotion(expr, inner, qual & (Q_CONST | Q_VOLATILE), 1); + + if (IS_TYPE_INT(expr->rtype)) { + if (ENODE_IS(expr, EINTCONST)) { + CInit_SetBitfield(tbitfield, (UInt8 *) s->buffer + s->size, expr->data.intval); + } else { + CInit_InitNonConst(s, TYPE(tbitfield), expr); + } + } else { + CError_Error(CErrorStr174); + } +} + +static void CInit_InitTypeArray(CInit_Stuff *s, CInit_Stuff2 *s2, TypePointer *tptr, UInt32 qual, Boolean errorflag) { + SInt32 targetsize; + SInt32 start; + SInt32 i; + Boolean flag; + Boolean is_zero_size; + SInt32 size; + SInt32 tmp; + Boolean is_char_ptr; + Boolean is_wchar_ptr; + + is_zero_size = tptr->size == 0; + targetsize = tptr->target->size; + if (!targetsize) { + CError_Error(CErrorStr145); + return; + } + + is_char_ptr = IS_TYPE_INT(tptr->target) && (targetsize == 1); + is_wchar_ptr = IS_TYPE_INT(tptr->target) && (targetsize == stwchar.size); + switch (s2->stage) { + case Stage1: + flag = 1; + if (CInit_ParseNextInit(s2) == Stage3) { + if (is_zero_size) + CError_Error(CErrorStr174); + tk = lex(); + return; + } + break; + case Stage2: + flag = 0; + break; + } + switch (s2->stage) { + case Stage1: + case Stage2: + break; + default: + CError_Error(CErrorStr174); + return; + } + + if (s2->stage == Stage2) + s2->expr = pointer_generation(s2->expr); + + if (s2->stage == Stage2 && ENODE_IS(s2->expr, ESTRINGCONST) && (is_char_ptr || is_wchar_ptr)) { + if (IS_TYPE_POINTER_ONLY(s2->expr->rtype) && tptr->target->size != TYPE_POINTER(s2->expr->rtype)->target->size) + CError_Warning(CErrorStr174); + size = tmp = s2->expr->data.string.size; + if (is_zero_size) { + tptr->size = s2->expr->data.string.size; + if (s->bufferSize < tmp) + s = CInit_GrowBuffer(s, tmp); + memcpy(s->buffer, s2->expr->data.string.data, size); + s->size = size; + } else { + if (s2->expr->data.string.size > tptr->size) { + if (copts.cplusplus || (s2->expr->data.string.size - 1) > tptr->size) + CError_Error(CErrorStr147); + s2->expr->data.string.size = tptr->size; + size = tptr->size; + } + memcpy(s->buffer + s->size, s2->expr->data.string.data, size); + } + } else { + if (!flag && errorflag) { + CError_Error(CErrorStr174); + return; + } + + start = s->size; + i = 0; + while (1) { + if (is_zero_size) { + size = (i + 1) * targetsize; + s->size = start + size - targetsize - s->xC; + if (s->size + targetsize > s->bufferSize) + s = CInit_GrowBuffer(s, targetsize * 16); + CInit_InitType(s, s2, tptr->target, qual, 0); + tptr->size = size; + s->size = start + size - s->xC; + } else { + if (tptr->size <= i * targetsize) { + i--; + CError_Error(CErrorStr147); + } + s->size = start + i * targetsize; + CInit_InitType(s, s2, tptr->target, qual, 0); + if (!flag && tptr->size <= (i + 1) * targetsize) + break; + } + + switch (CInit_ParseNextInit(s2)) { + case Stage1: + case Stage2: + break; + case Stage3: + if (flag) + tk = lex(); + return; + default: + CError_Error(CErrorStr130); + return; + } + + i++; + } + } + + if (flag) { + switch (CInit_ParseNextInit(s2)) { + case Stage3: + tk = lex(); + return; + case Stage2: + CError_Error(CErrorStr147); + return; + default: + CError_Error(CErrorStr130); + } + } +} + +static void CInit_InitTypeStruct(CInit_Stuff *s, CInit_Stuff2 *s2, const TypeStruct *tstruct, UInt32 qual, Boolean errorflag) { + StructMember *member; + SInt32 start; + Boolean flag; + SInt32 count; + TypePointer arraytype; + MWVector128 *vecp; + int i; + + count = 0; + if (s2->type) + tstruct = TYPE_STRUCT(s2->type); + + if (!(member = tstruct->members)) { + CError_Error(CErrorStr145); + return; + } + + switch (s2->stage) { + case Stage1: + flag = 1; + if (CInit_ParseNextInit(s2) == Stage3) { + tk = lex(); + return; + } + break; + case Stage2: + flag = 0; + break; + } + + switch (s2->stage) { + case Stage1: + case Stage2: + break; + default: + CError_Error(CErrorStr174); + return; + } + + if (!flag && s2->stage == Stage2 && (errorflag || s2->expr->rtype == TYPE(tstruct))) { + s2->expr = CExpr_AssignmentPromotion(s2->expr, TYPE(tstruct), qual, 1); + if (IS_TYPE_STRUCT(s2->expr->rtype)) + CInit_InitNonConst(s, TYPE(tstruct), s2->expr); + return; + } + + start = s->size; + while (1) { + s->size = start + member->offset; + if (!member->type->size) { + if (!errorflag || !IS_TYPE_ARRAY(member->type)) { + CError_Error(CErrorStr147); + if (!IS_TYPE_ARRAY(member->type)) + return; + } + + arraytype = *TYPE_POINTER(member->type); + CInit_InitTypeArray(s, s2, &arraytype, member->qual, 1); + s->x18 = arraytype.size; + } else { + CInit_InitType(s, s2, member->type, member->qual, 0); + } + + count++; + if (IS_TYPESTRUCT_VECTOR(tstruct) && s2->expr) + CError_ASSERT(1218, !ENODE_IS(s2->expr, EVECTOR128CONST)); + + do { + member = member->next; + } while (member && (member->qual & Q_WEAK)); + + if (!member || tstruct->stype == STRUCT_TYPE_UNION) { + if (flag) { + switch (CInit_ParseNextInit(s2)) { + case Stage3: + if (IS_TYPESTRUCT_VECTOR(tstruct)) { + vecp = (MWVector128 *) (s->buffer + start); + CMach_InitVectorMem(TYPE(tstruct), *vecp, vecp, 0); + } + tk = lex(); + return; + case Stage2: + CError_Error(CErrorStr147); + return; + default: + CError_Error(CErrorStr130); + return; + } + } + return; + } else { + switch (CInit_ParseNextInit(s2)) { + case Stage1: + case Stage2: + continue; + case Stage3: + if (flag) + tk = lex(); + if (IS_TYPESTRUCT_VECTOR(tstruct)) { + switch (TYPE_STRUCT(tstruct)->stype) { + case STRUCT_VECTOR_UCHAR: + case STRUCT_VECTOR_SCHAR: + case STRUCT_VECTOR_BCHAR: + if (count != 16) { + if (count == 1) { + UInt8 val, *p; + p = (UInt8 *) s->buffer; + val = p[0]; + for (i = 1; i < 16; i++) + p[i] = val; + } else { + CError_Error(CErrorStr174); + } + } + break; + case STRUCT_VECTOR_USHORT: + case STRUCT_VECTOR_SSHORT: + case STRUCT_VECTOR_BSHORT: + case STRUCT_VECTOR_PIXEL: + if (count != 8) { + if (count == 1) { + SInt16 val, *p; + p = (SInt16 *) s->buffer; + val = p[0]; + for (i = 1; i < 8; i++) + p[i] = val; + } else { + CError_Error(CErrorStr174); + } + } + break; + case STRUCT_VECTOR_UINT: + case STRUCT_VECTOR_SINT: + case STRUCT_VECTOR_BINT: + case STRUCT_VECTOR_FLOAT: + if (count != 4) { + if (count == 1) { + UInt32 val, *p; + p = (UInt32 *) s->buffer; + val = p[0]; + for (i = 1; i < 4; i++) + p[i] = val; + } else { + CError_Error(CErrorStr174); + } + } + break; + } + } + return; + default: + CError_Error(CErrorStr174); + return; + } + } + } +} + +static ObjMemberVar *CInit_FindNextMember(ObjMemberVar *ivar) { + ObjMemberVar *scan = ivar; + while (1) { + scan = scan->next; + if (!scan) + return NULL; + if (!scan->anonunion) + return scan; + if (scan->offset > ivar->offset) + return scan; + if (IS_TYPE_BITFIELD(scan->type) && IS_TYPE_BITFIELD(ivar->type) && TYPE_BITFIELD(scan->type)->offset != TYPE_BITFIELD(ivar->type)->offset) + return scan; + } +} + +static void CInit_InitTypeClass(CInit_Stuff *s, CInit_Stuff2 *s2, TypeClass *tclass, UInt32 qual, Boolean errorflag) { + ObjMemberVar *ivar; + SInt32 start; + Boolean flag; + SInt32 last_offset; + TypePointer arraytype; + + if (tclass->bases || tclass->vtable) { + CError_Error(CErrorStr174); + return; + } + + switch (s2->stage) { + case Stage1: + flag = 1; + if (CInit_ParseNextInit(s2) == Stage3) { + tk = lex(); + return; + } + break; + case Stage2: + flag = 0; + break; + } + + switch (s2->stage) { + case Stage1: + case Stage2: + break; + default: + CError_Error(CErrorStr174); + return; + } + + if (!flag && s2->stage == Stage2 && (errorflag || s2->expr->rtype == TYPE(tclass) || CExpr_CanImplicitlyConvert(s2->expr, TYPE(tclass), 0))) { + s2->expr = CExpr_AssignmentPromotion(s2->expr, TYPE(tclass), qual, 1); + if (IS_TYPE_CLASS(s2->expr->rtype)) + CInit_InitNonConst(s, TYPE(tclass), s2->expr); + return; + } + + for (ivar = tclass->ivars; ivar; ivar = ivar->next) { + if (ivar->access != ACCESSPUBLIC) { + CError_Error(CErrorStr174); + break; + } + } + + if (!(ivar = tclass->ivars)) { + CError_Error(CErrorStr147); + return; + } + start = s->size; + while (1) { + s->size = start + ivar->offset; + if (!ivar->type->size) { + if (!errorflag || !IS_TYPE_ARRAY(ivar->type)) { + CError_Error(CErrorStr147); + if (!IS_TYPE_ARRAY(ivar->type)) + return; + } + + arraytype = *TYPE_POINTER(ivar->type); + CInit_InitTypeArray(s, s2, &arraytype, ivar->qual, 1); + s->x18 = arraytype.size; + } else { + CInit_InitType(s, s2, ivar->type, ivar->qual, 0); + } + + last_offset = ivar->offset; + if (!(ivar = CInit_FindNextMember(ivar)) || (tclass->mode == CLASS_MODE_UNION && ivar->offset == last_offset)) { + if (flag) { + switch (CInit_ParseNextInit(s2)) { + case Stage3: + tk = lex(); + return; + case Stage2: + CError_Error(CErrorStr147); + return; + default: + CError_Error(CErrorStr130); + return; + } + } + return; + } else { + switch (CInit_ParseNextInit(s2)) { + case Stage1: + case Stage2: + continue; + case Stage3: + if (flag) + tk = lex(); + break; + default: + CError_Error(CErrorStr174); + } + return; + } + } +} + +static void CInit_InitType(CInit_Stuff *s, CInit_Stuff2 *s2, Type *type, UInt32 qual, Boolean errorflag) { + Boolean flag; + + switch (type->type) { + case TYPEVOID: + CError_Error(CErrorStr174); + break; + case TYPEINT: + case TYPEFLOAT: + case TYPEENUM: + case TYPEBITFIELD: + case TYPEMEMBERPOINTER: + case TYPEPOINTER: + switch (s2->stage) { + case Stage1: + flag = 1; + CInit_ParseNextInit(s2); + break; + case Stage2: + flag = 0; + break; + } + if (s2->stage != Stage2) { + CError_Error(CErrorStr174); + return; + } + + switch (type->type) { + case TYPEINT: + CInit_InitTypeInt(s, s2->expr, TYPE_INTEGRAL(type), qual); + break; + case TYPEFLOAT: + CInit_InitTypeFloat(s, s2->expr, TYPE_INTEGRAL(type), qual); + break; + case TYPEENUM: + CInit_InitTypeEnum(s, s2->expr, TYPE_ENUM(type), qual); + break; + case TYPEPOINTER: + CInit_InitTypePointer(s, s2->expr, TYPE_POINTER(type), qual); + break; + case TYPEMEMBERPOINTER: + CInit_InitTypeMemberPointer(s, s2->expr, TYPE_MEMBER_POINTER(type), qual); + break; + case TYPEBITFIELD: + CInit_InitTypeBitfield(s, s2->expr, TYPE_BITFIELD(type), qual); + break; + default: + CError_FATAL(1542); + } + + if (flag) { + switch (CInit_ParseNextInit(s2)) { + case Stage3: + tk = lex(); + break; + case Stage2: + CError_Error(CErrorStr147); + break; + default: + CError_Error(CErrorStr130); + } + } + break; + case TYPESTRUCT: + CInit_InitTypeStruct(s, s2, TYPE_STRUCT(type), qual, errorflag); + break; + case TYPEARRAY: + CInit_InitTypeArray(s, s2, TYPE_POINTER(type), qual, errorflag); + break; + case TYPECLASS: + CInit_InitTypeClass(s, s2, TYPE_CLASS(type), qual, errorflag); + break; + default: + CError_FATAL(1573); + } +} + +static void CInit_InitData(CInit_Stuff *s, Type *type, UInt32 qual, Boolean flag) { + CInit_Stuff2 s2; + SInt32 size; + CInit_Stuff *tmp; + char *buffer; + + locklheap(); + memclrw(s, sizeof(CInit_Stuff)); + s->x4 = s; + if (type->size == 0) { + if (IS_TYPE_ARRAY(type)) + s->bufferSize = 16 * TYPE_POINTER(type)->target->size; + else + CError_Error(CErrorStr145); + } else { + s->bufferSize = type->size; + } + + s->buffer = lalloc(s->bufferSize); + memset(s->buffer, 0, s->bufferSize); + s->flag = flag; + + s2.stage = Stage0; + s2.x23 = 0; + if (IS_TYPE_VECTOR(type)) { + s2.x23 = 1; + s->flag = 1; + } + if (IS_TYPE_ARRAY(type) && IS_TYPE_VECTOR(TYPE_POINTER(type)->target)) { + s->flag = 1; + } + + s2.type = NULL; + s2.x24 = 0; + CInit_ParseNextInit(&s2); + CInit_InitType(s, &s2, type, qual, 1); + + if ((size = type->size + s->x18)) { + if (s->x0) { + buffer = lalloc(size); + for (tmp = s; tmp; tmp = tmp->x0) { + CError_ASSERT(1647, (tmp->xC + tmp->size) <= size); + memcpy(buffer + tmp->xC, tmp->buffer, tmp->size); + } + s->buffer = buffer; + } + } else { + CError_Error(CErrorStr174); + } + + s->size = size; + s->x0 = NULL; + unlocklheap(); +} + +static ENode *CInit_InitConcat(ENode *a1, ENode *a2, SInt32 offset, Type *type, ENode *a5) { + ENode *r30; + ENode *r28; + ENode *tmp; + + r28 = lalloc(sizeof(ENode)); + *r28 = *a2; + if (offset) + r28 = makediadicnode(r28, intconstnode(TYPE(&stunsignedlong), offset), EADD); + + if (IS_TYPE_BITFIELD(type)) { + tmp = makemonadicnode(r28, EBITFIELD); + tmp->rtype = type; + tmp = makemonadicnode(tmp, EINDIRECT); + tmp->rtype = TYPE_BITFIELD(type)->bitfieldtype; + } else { + tmp = makemonadicnode(r28, EINDIRECT); + tmp->rtype = type; + } + + r30 = makediadicnode(tmp, a5, EASS); + if (!a1) { + return r30; + } else { + tmp = makediadicnode(a1, r30, ECOMMA); + tmp->rtype = r30->rtype; + return tmp; + } +} + +static ENode *CInit_RegisterDtorObject(Type *type, Object *dtor, ENode *objexpr) { + ENode *expr; + + if (copts.no_static_dtors) + return objexpr; + + expr = lalloc(sizeof(ENode)); + expr->type = EFUNCCALL; + expr->cost = 4; + expr->flags = 0; + expr->rtype = CDecl_NewPointerType(type); + expr->data.funccall.funcref = create_objectrefnode(Xgreg_func); + expr->data.funccall.functype = TYPE_FUNC(Xgreg_func->type); + expr->data.funccall.args = lalloc(sizeof(ENodeList)); + expr->data.funccall.args->node = objexpr; + expr->data.funccall.args->next = lalloc(sizeof(ENodeList)); + expr->data.funccall.args->next->node = create_objectrefnode(CABI_GetDestructorObject(dtor, CABIDestroy1)); + expr->data.funccall.args->next->next = lalloc(sizeof(ENodeList)); + expr->data.funccall.args->next->next->node = create_objectrefnode(CInit_CreateStaticData(CInit_GetRegMemType())); + expr->data.funccall.args->next->next->next = NULL; + + return expr; +} + +static Boolean CInit_ConstructGlobalObject(Object *obj, TypeClass *tclass, ENode *valueexpr, SInt32 offset, Boolean flag) { + NameSpaceObjectList *ctor; + Object *dtor; + ENodeList *list; + ENode *expr; + Boolean ctorflag; + + ctor = CClass_Constructor(tclass); + dtor = CClass_Destructor(tclass); + if (!ctor && !dtor) + return 0; + + if (flag && !ctor && tk == '=' && lookahead() == '{') + return 0; + + if (flag && tk == '(') { + tk = lex(); + list = CExpr_ScanExpressionList(1); + if (tk == ')') + tk = lex(); + else + CError_Error(CErrorStr115); + } else if (valueexpr) { + list = lalloc(sizeof(ENodeList)); + list->node = valueexpr; + list->next = NULL; + } else { + list = NULL; + } + + expr = create_objectrefnode(obj); + if (offset) + expr = makediadicnode(expr, intconstnode(TYPE(&stunsignedlong), offset), EADD); + + if (ctor) { + ctorflag = 1; + if (tk == '=') { + ctorflag = 0; + if (list) + CError_Error(CErrorStr174); + + list = lalloc(sizeof(ENodeList)); + list->next = NULL; + tk = lex(); + list->node = conv_assignment_expression(); + } + + expr = CExpr_ConstructObject(tclass, expr, list, 0, 1, 0, 1, ctorflag); + if (expr->rtype->type != TYPEPOINTER) { + CError_Error(CErrorStr174); + return 1; + } + } else { + if (list) + CError_Error(CErrorStr174); + } + + if (dtor) + expr = CInit_RegisterDtorObject(TYPE(tclass), dtor, expr); + + if (cinit_initinfo->x16) + cinit_initinfo->init_expr_register_cb(expr); + else + InitExpr_Register(expr, obj); + + return 1; +} + +static Boolean CInit_ConstructAutoObject(TypeClass *tclass, ENode *expr, SInt32 offset, Boolean flag) { + ENodeList *r30; + ENode *r29; + NameSpaceObjectList *ctor; + Object *dtor; + Boolean r24; + + ctor = CClass_Constructor(tclass); + dtor = CClass_Destructor(tclass); + if (!ctor && !dtor) + return 0; + + if (dtor) + CClass_CheckStaticAccess(NULL, tclass, dtor->access); + + if (flag && !ctor && tk == '=' && lookahead() == '{') + return 0; + + if (flag && tk == '(') { + tk = lex(); + r30 = CExpr_ScanExpressionList(1); + if (tk == ')') + tk = lex(); + else + CError_Error(CErrorStr115); + } else if (expr) { + r30 = lalloc(sizeof(ENodeList)); + r30->node = expr; + r30->next = NULL; + } else { + r30 = NULL; + } + + if (ctor) { + r24 = 1; + if (tk == '=') { + if (r30) + CError_Error(CErrorStr174); + r30 = lalloc(sizeof(ENodeList)); + r30->next = NULL; + tk = lex(); + r30->node = conv_assignment_expression(); + r24 = 0; + } + + if (!dtor) { + r29 = create_objectrefnode(cinit_initinfo->obj1C); + if (offset) + r29 = makediadicnode(r29, intconstnode(TYPE(&stunsignedlong), offset), EADD); + } else { + r29 = cinit_initinfo->register_object_cb(TYPE(tclass), cinit_initinfo->obj1C, offset, 0); + } + + r29 = CExpr_ConstructObject(tclass, r29, r30, 0, 1, 0, 1, r24); + if (!IS_TYPE_POINTER_ONLY(r29->rtype)) { + CError_Error(CErrorStr174); + return 1; + } + r29 = makemonadicnode(r29, EINDIRECT); + r29->rtype = TYPE_POINTER(r29->rtype)->target; + cinit_initinfo->insert_expr_cb(r29); + } else { + if (r30) + CError_Error(CErrorStr174); + if (dtor) + r29 = cinit_initinfo->register_object_cb(TYPE(tclass), cinit_initinfo->obj1C, offset, 0); + cinit_initinfo->insert_expr_cb(r29); + } + + return 1; +} + +static void CInit_ExprPointer(TypePointer *tptr, ENode *expr) { + Object *obj; + CInt64 val; + OLinkList *list; + + if (CInit_RelocInitCheck(expr, &obj, &val, 0)) { + if (obj) { + list = lalloc(sizeof(OLinkList)); + list->next = cinit_initinfo->list; + list->obj = obj; + list->somevalue = CInt64_GetULong(&val); + list->offset = cinit_initinfo->expr_offset; + cinit_initinfo->list = list; + } else { + CMach_InitIntMem(TYPE(&stunsignedlong), val, cinit_initinfo->buffer + cinit_initinfo->expr_offset); + } + } else if (cinit_initinfo->expr_cb) { + cinit_initinfo->expr_cb(TYPE(tptr), expr, 0); + cinit_initinfo->expr_cb_called = 1; + } else { + CError_Error(CErrorStr124); + } + + cinit_initinfo->expr_offset += 4; +} + +static void CInit_ExprInt(TypeIntegral *tint, ENode *expr) { + if (ENODE_IS(expr, EINTCONST)) { + CMach_InitIntMem(TYPE(tint), expr->data.intval, cinit_initinfo->buffer + cinit_initinfo->expr_offset); + } else if (ENODE_IS(expr, ETYPCON) && IS_TYPE_POINTER_ONLY(expr->data.monadic->rtype) && expr->rtype->size == 4 && (copts.cplusplus || !copts.ANSIstrict)) { + CInit_ExprPointer(TYPE_POINTER(expr->data.monadic->rtype), expr->data.monadic); + } else if (cinit_initinfo->expr_cb) { + cinit_initinfo->expr_cb(TYPE(tint), expr, 0); + cinit_initinfo->expr_cb_called = 1; + } else { + CError_Error(CErrorStr124); + } + + cinit_initinfo->expr_offset += tint->size; +} + +static void CInit_ExprFloat(TypeIntegral *tint, ENode *expr) { + if (ENODE_IS(expr, EFLOATCONST)) { + CMach_InitFloatMem(TYPE(tint), expr->data.floatval, cinit_initinfo->buffer + cinit_initinfo->expr_offset); + } else if (cinit_initinfo->expr_cb) { + cinit_initinfo->expr_cb(TYPE(tint), expr, 0); + cinit_initinfo->expr_cb_called = 1; + } else { + CError_Error(CErrorStr124); + } + + cinit_initinfo->expr_offset += tint->size; +} + +static void CInit_ExprEnum(TypeEnum *tenum, ENode *expr) { + if (ENODE_IS(expr, EINTCONST)) { + CMach_InitIntMem(tenum->enumtype, expr->data.intval, cinit_initinfo->buffer + cinit_initinfo->expr_offset); + } else if (cinit_initinfo->expr_cb) { + cinit_initinfo->expr_cb(TYPE(tenum), expr, 0); + cinit_initinfo->expr_cb_called = 1; + } else { + CError_Error(CErrorStr124); + } + + cinit_initinfo->expr_offset += tenum->size; +} + +static void CInit_ExprMemberPointer(TypeMemberPointer *tmptr, ENode *expr) { + if (ENODE_IS(expr, EINTCONST)) { + CMach_InitIntMem(TYPE(&stsignedlong), expr->data.intval, cinit_initinfo->buffer + cinit_initinfo->expr_offset); + } else if (cinit_initinfo->expr_cb) { + cinit_initinfo->expr_cb(TYPE(tmptr), expr, 0); + cinit_initinfo->expr_cb_called = 1; + } else { + CError_Error(CErrorStr124); + } + + cinit_initinfo->expr_offset += tmptr->size; +} + +static void CInit_TypeExpr(Type *type, ENode *expr) { + switch (type->type) { + case TYPEINT: + CInit_ExprInt(TYPE_INTEGRAL(type), expr); + break; + case TYPEFLOAT: + CInit_ExprFloat(TYPE_INTEGRAL(type), expr); + break; + case TYPEENUM: + CInit_ExprEnum(TYPE_ENUM(type), expr); + break; + case TYPEPOINTER: + CInit_ExprPointer(TYPE_POINTER(type), expr); + break; + case TYPEMEMBERPOINTER: + CInit_ExprMemberPointer(TYPE_MEMBER_POINTER(type), expr); + break; + case TYPESTRUCT: + case TYPECLASS: + if (cinit_initinfo->expr_cb) { + cinit_initinfo->expr_cb(type, expr, 0); + cinit_initinfo->expr_cb_called = 1; + } else { + CError_Error(CErrorStr124); + } + break; + case TYPEARRAY: + CError_Error(CErrorStr174); + break; + default: + CError_FATAL(2082); + } +} + +static void CInit_Bitfield(TypeBitfield *tbitfield) { + Boolean r30; + ENode *expr; + ENode myexpr; + + r30 = tk == '{'; + if (r30) + tk = lex(); + + expr = CInit_ParseInitializer(&myexpr); + expr = CExpr_AssignmentPromotion( + expr, + IS_TYPE_ENUM(tbitfield->bitfieldtype) ? TYPE_ENUM(tbitfield->bitfieldtype)->enumtype : tbitfield->bitfieldtype, + 0, + 1); + if (ENODE_IS(expr, EINTCONST)) + CInit_SetBitfield(tbitfield, (UInt8 *) cinit_initinfo->buffer + cinit_initinfo->expr_offset, expr->data.intval); + else + CError_Error(CErrorStr124); + + if (r30) + CInit_CloseInitList(); +} + +static void CInit_Array(TypePointer *tptr, UInt32 qual, Boolean flag) { + SInt32 start; + SInt32 i; + SInt32 targetsize1; + SInt32 targetsize2; + Boolean in_block; + Boolean is_char_ptr; + Boolean needs_construction; + Boolean is_wchar_ptr; + + targetsize1 = tptr->target->size; + targetsize2 = tptr->target->size; + if (!tptr->target->size) { + if (!IS_TYPE_ARRAY(tptr->target)) { + CError_Error(CErrorStr145); + return; + } + targetsize1 = tptr->target->size; + targetsize2 = tptr->target->size; + if (!tptr->target->size) { + CError_Error(CErrorStr145); + return; + } + } + + is_char_ptr = IS_TYPE_INT(tptr->target) && (tptr->target->size == 1); + is_wchar_ptr = IS_TYPE_INT(tptr->target) && (tptr->target->size == stwchar.size); + + in_block = 1; + if (flag && !(tk == TK_STRING && is_char_ptr) && !(tk == TK_STRING_WIDE && is_wchar_ptr)) { + if (tk != '{') { + CError_ErrorSkip(CErrorStr135); + return; + } + tk = lex(); + } else { + if (tk == '{') + tk = lex(); + else + in_block = 0; + } + + if ((tk == TK_STRING && is_char_ptr) || (tk == TK_STRING_WIDE && is_wchar_ptr)) { + if (tptr->size) { + if (tksize > tptr->size) { + if (copts.cplusplus || (tksize - (is_wchar_ptr ? stwchar.size : 1)) > tptr->size) + CError_Error(CErrorStr147); + tksize = tptr->size; + } + memcpy(cinit_initinfo->buffer + cinit_initinfo->expr_offset, tkstring, tksize); + } else { + tptr->size = tksize; + CInit_SetData(tkstring, cinit_initinfo->expr_offset, tptr->size); + } + cinit_initinfo->expr_offset += tptr->size; + tk = lex(); + if (in_block) + CInit_CloseInitList(); + return; + } + + if (IS_TYPE_CLASS(tptr->target) && CInit_ClassNeedsConstruction(TYPE_CLASS(tptr->target))) + needs_construction = 1; + else + needs_construction = 0; + + start = cinit_initinfo->expr_offset; + i = 0; + while (1) { + if (tk == '}') { + innerloop: + if (tptr->size) { + if (needs_construction) { + while (tptr->size > (i * targetsize1)) { + cinit_initinfo->expr_offset = start + i * targetsize2; + if (cinit_initinfo->expr_cb) { + cinit_initinfo->expr_cb(tptr->target, NULL, 1); + cinit_initinfo->expr_cb_called = 1; + } else { + CError_Error(CErrorStr174); + } + i++; + } + } + } else { + tptr->size = i * targetsize1; + } + cinit_initinfo->expr_offset = start + tptr->size; + if (in_block) + tk = lex(); + return; + } + + if (!tptr->size) { + cinit_initinfo->expr_offset = start + i * targetsize2; + CInit_SetData(NULL, cinit_initinfo->expr_offset, targetsize2); + if (needs_construction) { + if (cinit_initinfo->expr_cb) { + cinit_initinfo->expr_cb(tptr->target, conv_assignment_expression(), 1); + cinit_initinfo->expr_cb_called = 1; + } else { + CError_Error(CErrorStr174); + } + } else { + CInit_Type(tptr->target, qual, 0); + } + } else { + if (tptr->size <= i * targetsize1) { + i--; + CError_Error(CErrorStr147); + } + + cinit_initinfo->expr_offset = start + i * targetsize2; + if (needs_construction) { + if (cinit_initinfo->expr_cb) { + cinit_initinfo->expr_cb(tptr->target, conv_assignment_expression(), 1); + cinit_initinfo->expr_cb_called = 1; + } else { + CError_Error(CErrorStr174); + } + } else { + CInit_Type(tptr->target, qual, 0); + } + + if (!in_block) { + if (tptr->size <= (i + 1) * targetsize1) + return; + } + } + + if (tk != '}') { + if (tk != ',') { + CError_ErrorSkip(CErrorStr121); + in_block = 0; + i++; + goto innerloop; + } + tk = lex(); + } + i++; + } +} + +static void CInit_Struct(TypeStruct *tstruct, Boolean flag) { + StructMember *member; + SInt32 start; + Boolean in_block; + + if (!(member = tstruct->members)) { + CError_Error(CErrorStr145); + return; + } + + if (tstruct->stype == STRUCT_TYPE_UNION) { + if (tk == '{') { + tk = lex(); + CInit_Type(member->type, member->qual, 0); + if (tk == '}') + tk = lex(); + } else { + CInit_Type(member->type, member->qual, 0); + } + return; + } + + if (IS_TYPE_VECTOR(tstruct) && tk != '{') { + CInit_TypeExpr(TYPE(tstruct), CExpr_AssignmentPromotion(conv_assignment_expression(), TYPE(tstruct), 0, 1)); + return; + } + + if (tk != '{') { + if (flag) + CError_ErrorSkip(CErrorStr135); + in_block = 0; + } else { + in_block = 1; + tk = lex(); + } + + start = cinit_initinfo->expr_offset; + while (1) { + if (tk == '}') + break; + + cinit_initinfo->expr_offset = start + member->offset; + if (!member->type->size && IS_TYPE_ARRAY(member->type)) { + CError_Error(CErrorStr147); + break; + } + + CInit_Type(member->type, member->qual, 0); + if (tk == '}') + break; + + if (tk != ',') { + CError_Error(CErrorStr121); + break; + } + + do { + member = member->next; + } while (member && (member->qual & Q_WEAK)); + + if (!member) { + if (!in_block) + break; + if ((tk = lex()) != '}') { + CError_Error(CErrorStr147); + break; + } + } else { + tk = lex(); + } + } + + cinit_initinfo->expr_offset = start + tstruct->size; + if (tk == '}' && in_block) + tk = lex(); +} + +static void CInit_Class(TypeClass *tclass, Boolean flag) { + ObjMemberVar *ivar; + SInt32 start; + Boolean in_block; + + if (tk == '{') { + in_block = 1; + tk = lex(); + } else { + in_block = 0; + } + + if (tclass->bases || tclass->vtable) { + CError_Error(CErrorStr174); + return; + } + + for (ivar = tclass->ivars; ivar; ivar = ivar->next) { + if (ivar->access != ACCESSPUBLIC) + break; + } + + if (!ivar && !CClass_Constructor(tclass) && (!CClass_Destructor(tclass) || in_block)) { + if ((ivar = tclass->ivars)) { + start = cinit_initinfo->expr_offset; + while (1) { + if (tk == '}') + break; + + if (!ivar->type->size && IS_TYPE_ARRAY(ivar->type)) { + CError_Error(CErrorStr147); + break; + } + + cinit_initinfo->expr_offset = start + ivar->offset; + CInit_Type(ivar->type, ivar->qual, 0); + + if (tk == '}') + break; + + if (tk != ',') { + CError_Error(CErrorStr121); + break; + } + + do { + ivar = ivar->next; + } while (ivar && ivar->anonunion); + + if (!ivar) { + if (!in_block) + break; + if ((tk = lex()) != '}') { + CError_Error(CErrorStr147); + break; + } + } else { + tk = lex(); + } + } + } else { + if (in_block && tk != '}') + CError_Error(CErrorStr147); + } + } else { + if (in_block) + CError_Error(CErrorStr174); + CInit_TypeExpr(TYPE(tclass), CExpr_AssignmentPromotion(conv_assignment_expression(), TYPE(tclass), 0, 1)); + } + + cinit_initinfo->expr_offset = start + tclass->size; + if (tk == '}' && in_block) + tk = lex(); +} + +static void CInit_Type(Type *type, UInt32 qual, Boolean flag) { + ENode *expr; + ENode myexpr; + + switch (type->type) { + case TYPEVOID: + CError_Error(CErrorStr174); + break; + case TYPEINT: + case TYPEFLOAT: + case TYPEENUM: + case TYPEPOINTER: + case TYPEMEMBERPOINTER: + if (tk == '{') { + tk = lex(); + expr = CInit_ParseInitializer(&myexpr); + expr = CExpr_AssignmentPromotion(expr, type, qual & (Q_CONST | Q_VOLATILE), 1); + CInit_CloseInitList(); + } else { + expr = CInit_ParseInitializer(&myexpr); + expr = CExpr_AssignmentPromotion(expr, type, qual & (Q_CONST | Q_VOLATILE), 1); + } + CInit_TypeExpr(type, expr); + break; + case TYPEBITFIELD: + CInit_Bitfield(TYPE_BITFIELD(type)); + break; + case TYPEARRAY: + CInit_Array(TYPE_POINTER(type), qual, flag); + break; + case TYPESTRUCT: + CInit_Struct(TYPE_STRUCT(type), flag); + break; + case TYPECLASS: + CInit_Class(TYPE_CLASS(type), flag); + break; + default: + CError_FATAL(2482); + } +} + +static void CInit_GlobalStaticInit(Type *type, ENode *valueexpr, Boolean flag) { + ENode *expr; + ENode *tmp; + + cinit_initinfo->x15 = 1; + if (flag) { + CInit_ConstructGlobalObject(cinit_initinfo->obj, TYPE_CLASS(type), valueexpr, cinit_initinfo->expr_offset, 0); + } else { + expr = create_objectrefnode(cinit_initinfo->obj); + if (!IS_TYPE_POINTER_ONLY(expr->rtype)) { + CError_Error(CErrorStr174); + return; + } + TYPE_POINTER(expr->rtype)->target = type; + + if (cinit_initinfo->expr_offset) + expr = makediadicnode(expr, intconstnode(TYPE(&stunsignedlong), cinit_initinfo->expr_offset), EADD); + + tmp = makemonadicnode(expr, EINDIRECT); + tmp->rtype = type; + expr = makediadicnode(tmp, valueexpr, EASS); + if (cinit_initinfo->x16) + cinit_initinfo->init_expr_register_cb(expr); + else + InitExpr_Register(expr, cinit_initinfo->obj); + } +} + +static void CInit_AutoInit(Type *type, ENode *valueexpr, Boolean flag) { + ENode *expr; + ENode *tmp; + Type *copy; + SInt32 size; + + if (flag) { + CInit_ConstructAutoObject(TYPE_CLASS(type), valueexpr, cinit_initinfo->expr_offset, 0); + } else { + if (IS_TYPE_ARRAY(type) && (type->size & 1)) { + copy = galloc(sizeof(TypePointer)); + *TYPE_POINTER(copy) = *TYPE_POINTER(type); + type = copy; + copy->size++; + } + expr = create_objectrefnode(cinit_initinfo->obj1C); + if (!IS_TYPE_POINTER_ONLY(expr->rtype)) { + CError_Error(CErrorStr174); + return; + } + TYPE_POINTER(expr->rtype)->target = type; + + if (cinit_initinfo->expr_offset) + expr = makediadicnode(expr, intconstnode(TYPE(&stunsignedlong), cinit_initinfo->expr_offset), EADD); + + tmp = makemonadicnode(expr, EINDIRECT); + tmp->rtype = type; + expr = makediadicnode(tmp, valueexpr, EASS); + if (!copts.cplusplus) + CError_Error(CErrorStr124); + cinit_initinfo->insert_expr_cb(expr); + } +} + +static SInt32 CInit_AdjustObjectDataSize(Object *obj) { + if (obj->type->size <= 1) + return obj->type->size; + if (obj->type->size & 1) + return obj->type->size + 1; + else + return obj->type->size; +} + +static ENode *CInit_GenericData(Object *obj, Type *type, UInt32 qual, ExprCB expr_cb, Boolean flag) { + Object *r31; + ENode *expr; + ENode *tmpexpr; + Type *inner; + Type *copy; + SInt32 size; + Boolean lastflag; + SInt16 cv; + + cinit_initinfo->expr_cb = expr_cb; + expr = NULL; + + if (tk == '(') { + if (IS_TYPE_ARRAY(type)) + CError_Error(CErrorStr174); + tk = lex(); + expr = CExpr_AssignmentPromotion(assignment_expression(), type, qual, 1); + if (tk != ')') + CError_ErrorSkip(CErrorStr115); + else + tk = lex(); + goto jump_ahead; + } + + tk = lex(); + switch (type->type) { + case TYPECLASS: + if (tk == '{' && CClass_Constructor(TYPE_CLASS(type))) + CError_Error(CErrorStr174); + case TYPESTRUCT: + if (tk != '{') + goto generic_type; + case TYPEARRAY: + if (!obj) { + if (IS_TYPE_ARRAY(type)) { + inner = type; + while (IS_TYPE_ARRAY(inner)) + inner = TYPE_POINTER(inner)->target; + + if (IS_TYPE_CLASS(inner) && CInit_ClassNeedsConstruction(TYPE_CLASS(inner))) { + CInit_SetupInitInfoBuffer(type); + cinit_initinfo->obj = cinit_initinfo->obj1C; + CInit_Type(type, cinit_initinfo->obj->qual, 1); + return 0; + } + if (type->size & 1) { + copy = galloc(sizeof(TypePointer)); + *TYPE_POINTER(copy) = *TYPE_POINTER(type); + type = copy; + type->size++; + } + } + + obj = CInit_CreateStaticDataObject(type, qual, NULL); + cinit_initinfo->obj = obj; + expr = create_objectnode(obj); + cinit_initinfo->obj1C = obj; + } + CInit_SetupInitInfoBuffer(type); + CInit_Type(type, obj->qual, 1); + CError_ASSERT(2639, obj->type->size == (size = cinit_initinfo->size)); + if (cinit_initinfo->list || !CInit_IsAllZero(cinit_initinfo->buffer, size)) { + CInit_AdjustObjectDataSize(obj); + CInit_DeclareData(obj, cinit_initinfo->buffer, cinit_initinfo->list, obj->type->size); + } else { + CInit_AdjustObjectDataSize(obj); + CInit_DeclareData(obj, NULL, NULL, obj->type->size); + } + return expr; + case TYPEINT: + case TYPEFLOAT: + case TYPEENUM: + case TYPEPOINTER: + case TYPEMEMBERPOINTER: + generic_type: + if (obj) + cv = obj->qual & Q_CV; + else + cv = cinit_initinfo->obj1C->qual & Q_CV; + + if (tk == '{') { + tk = lex(); + expr = assignment_expression(); + CInit_CloseInitList(); + } else { + expr = assignment_expression(); + } + expr = CExpr_AssignmentPromotion(expr, type, cv, 1); + jump_ahead: + if (obj == NULL) + r31 = cinit_initinfo->obj1C; + else + r31 = obj; + + if (is_const_object(r31)) { + switch (r31->type->type) { + case TYPEINT: + case TYPEENUM: + if (ENODE_IS(expr, EINTCONST)) { + r31->u.data.u.intconst = expr->data.intval; + goto common_8068C; + } + break; + case TYPEFLOAT: + if (ENODE_IS(expr, EFLOATCONST)) { + Float fl; + r31->u.data.u.floatconst = galloc(sizeof(Float)); + fl = CMach_CalcFloatConvert(r31->type, expr->data.floatval); + *r31->u.data.u.floatconst = fl; + goto common_8068C; + } + break; + case TYPEPOINTER: + tmpexpr = expr; + while (ENODE_IS(tmpexpr, ETYPCON)) + tmpexpr = tmpexpr->data.monadic; + if (!ENODE_IS(tmpexpr, EINTCONST)) + break; + r31->u.data.u.intconst = tmpexpr->data.intval; + common_8068C: + r31->qual |= Q_INLINE_DATA; + if (!obj) { + r31->sclass = TK_STATIC; + r31->datatype = DDATA; + r31->u.data.linkname = CParser_AppendUniqueName(r31->name->name); + } else if (r31->sclass != TK_STATIC || (r31->flags & OBJECT_FLAGS_2)) { + CInit_ExportConst(r31); + } + return NULL; + } + } + + if (!obj || (flag && copts.cplusplus)) { + if (obj) { + IsCompleteType(obj->type); + CError_ASSERT(2747, obj->type->size == type->size); + CInit_DeclareData(obj, NULL, NULL, obj->type->size); + } + return expr; + } + + CInit_SetupInitInfoBuffer(type); + CInit_TypeExpr(type, expr); + CError_ASSERT(2756, obj->type->size == cinit_initinfo->size); + + IsCompleteType(obj->type); + CInit_AdjustObjectDataSize(obj); + lastflag = !cinit_initinfo->x15 && is_const_object(r31); + if (cinit_initinfo->list || !CInit_IsAllZero(cinit_initinfo->buffer, obj->type->size)) { + if (lastflag) + CInit_DeclareReadOnlyData(obj, cinit_initinfo->buffer, cinit_initinfo->list, obj->type->size); + else + CInit_DeclareData(obj, cinit_initinfo->buffer, cinit_initinfo->list, obj->type->size); + } else { + if (lastflag) + CInit_DeclareReadOnlyData(obj, NULL, NULL, obj->type->size); + else + CInit_DeclareData(obj, NULL, NULL, obj->type->size); + } + break; + + default: + CError_FATAL(2776); + } + + return NULL; +} + +void CInit_ExportConst(Object *obj) { + char buffer[64]; + + if (obj->flags & OBJECT_DEFINED) + return; + + switch (obj->type->type) { + case TYPEINT: + CMach_InitIntMem(obj->type, obj->u.data.u.intconst, buffer); + break; + case TYPEENUM: + CMach_InitIntMem(TYPE_ENUM(obj->type)->enumtype, obj->u.data.u.intconst, buffer); + break; + case TYPEPOINTER: + CMach_InitIntMem(TYPE(&stunsignedlong), obj->u.data.u.intconst, buffer); + break; + case TYPEFLOAT: + CMach_InitFloatMem(obj->type, *obj->u.data.u.floatconst, buffer); + break; + default: + CError_FATAL(2807); + } + + if (is_const_object(obj)) + CInit_DeclareReadOnlyData(obj, buffer, NULL, obj->type->size); + else + CInit_DeclareData(obj, buffer, NULL, obj->type->size); +} + +static ENode *CInit_ClassInitLoopCallBack(ENode *expr) { + return CExpr_ConstructObject(cinit_loop_class, expr, NULL, 0, 1, 0, 1, 1); +} + +Statement *CInit_ConstructClassArray(Statement *stmt, TypeClass *tclass, Object *ctor, Object *dtor, ENode *firstarg, SInt32 count) { + ENode *dtor_expr; + + if (stmt) + stmt = CFunc_InsertStatement(ST_EXPRESSION, stmt); + else + stmt = CFunc_AppendStatement(ST_EXPRESSION); + + if (dtor) + dtor_expr = create_objectrefnode(CABI_GetDestructorObject(dtor, CABIDestroy1)); + else + dtor_expr = nullnode(); + + stmt->expr = CExpr_FuncCallSix( + carr_func, + firstarg, + create_objectrefnode(ctor), + dtor_expr, + intconstnode(TYPE(&stunsignedlong), tclass->size), + intconstnode(TYPE(&stunsignedlong), count), + NULL + ); + + return stmt; +} + +static void CInit_InitializeClassArray(Object *obj, TypeClass *tclass, Boolean flag) { + Object *ctor; + Object *dtor; + SInt32 count; + SInt32 i; + ENode *expr; + SInt32 offset; + ENode *dtor_expr; + Statement *stmt; + TypeFunc *tfunc; + Object *funcobj; + + dtor = CClass_Destructor(tclass); + count = obj->type->size / tclass->size; + if (CClass_Constructor(tclass)) { + ctor = CClass_DefaultConstructor(tclass); + if (!ctor) { + ctor = CClass_DummyDefaultConstructor(tclass); + if (!ctor) { + CError_Error(CErrorStr203); + return; + } + } + } else { + ctor = NULL; + } + + if (count <= 1 || (!flag && count <= 8)) { + if (flag) { + for (i = 0; i < count; i++) { + CInit_ConstructGlobalObject(obj, tclass, NULL, i * tclass->size, 0); + } + } else { + for (i = 0; i < count; i++) { + offset = i * tclass->size; + expr = create_objectrefnode(obj); + if (offset) + expr = makediadicnode(expr, intconstnode(TYPE(&stunsignedlong), offset), EADD); + if (ctor) + expr = CExpr_ConstructObject(tclass, expr, NULL, 0, 1, 0, 1, 1); + cinit_initinfo->insert_expr_cb(expr); + if (dtor) + CExcept_RegisterDestructorObject(obj, offset, dtor, 1); + } + if (dtor) { + stmt = CFunc_AppendStatement(ST_EXPRESSION); + stmt->expr = nullnode(); + } + } + } else { + if (ctor) { + if (!flag && !dtor) { + CInit_ConstructClassArray(NULL, tclass, ctor, dtor, create_objectrefnode(obj), count); + expr = nullnode(); + } else { + if (dtor) + dtor_expr = create_objectrefnode(CABI_GetDestructorObject(dtor, CABIDestroy1)); + else + dtor_expr = nullnode(); + expr = CExpr_FuncCallSix( + carr_func, + create_objectrefnode(obj), + create_objectrefnode(ctor), + dtor_expr, + intconstnode(TYPE(&stunsignedlong), tclass->size), + intconstnode(TYPE(&stunsignedlong), count), + NULL + ); + } + } else { + expr = nullnode(); + } + + if (flag) { + if (dtor && !copts.no_static_dtors) { + tfunc = galloc(sizeof(TypeFunc)); + memclrw(tfunc, sizeof(TypeFunc)); + tfunc->type = TYPEFUNC; + tfunc->functype = &stvoid; + CDecl_SetFuncFlags(tfunc, 1); + + funcobj = CParser_NewCompilerDefFunctionObject(); + funcobj->name = CParser_AppendUniqueName("__arraydtor"); + funcobj->type = TYPE(tfunc); + funcobj->sclass = TK_STATIC; + funcobj->qual = Q_INLINE; + + CParser_RegisterSingleExprFunction(funcobj, funccallexpr( + darr_func, + create_objectrefnode(obj), + create_objectrefnode(CABI_GetDestructorObject(dtor, CABIDestroy1)), + intconstnode(TYPE(&stsignedlong), tclass->size), + intconstnode(TYPE(&stsignedlong), count) + )); + + expr = makediadicnode(expr, nullnode(), ECOMMA); + expr->rtype = TYPE(&void_ptr); + + expr = funccallexpr( + Xgreg_func, + expr, + create_objectrefnode(funcobj), + create_objectrefnode(CInit_CreateStaticData(CInit_GetRegMemType())), + NULL + ); + } + if (cinit_initinfo->x16) + cinit_initinfo->init_expr_register_cb(expr); + else + InitExpr_Register(expr, obj); + } else { + stmt = CFunc_AppendStatement(ST_EXPRESSION); + stmt->expr = expr; + if (dtor) { + CExcept_RegisterLocalArray(stmt, obj, dtor, count, tclass->size); + stmt = CFunc_AppendStatement(ST_EXPRESSION); + stmt->expr = nullnode(); + } + } + } +} + +static ENode *CInit_AutoTempNode(Type *type, Boolean flag) { + ENode *node; + node = CExpr_NewETEMPNode(type, 0); + if (IS_TYPE_CLASS(type) && CClass_Destructor(TYPE_CLASS(type))) + node->data.temp.needs_dtor = 1; + return node; +} + +static ENode *CInit_GlobalTempNode(Type *type, Boolean flag) { + Object *dtor; + ENode *node; + ENode *funcnode; + + node = create_objectrefnode(CInit_CreateStaticData(type)); + if (IS_TYPE_CLASS(type) && (dtor = CClass_Destructor(TYPE_CLASS(type))) && !copts.no_static_dtors) { + if (flag) + CError_Error(CErrorStr190); + + funcnode = galloc(sizeof(ENode)); + funcnode->type = EFUNCCALL; + funcnode->cost = 200; + funcnode->flags = 0; + funcnode->rtype = CDecl_NewPointerType(type); + funcnode->data.funccall.funcref = create_objectrefnode(Xgreg_func); + funcnode->data.funccall.functype = TYPE_FUNC(Xgreg_func->type); + funcnode->data.funccall.args = lalloc(sizeof(ENodeList)); + funcnode->data.funccall.args->node = node; + funcnode->data.funccall.args->next = lalloc(sizeof(ENodeList)); + funcnode->data.funccall.args->next->node = create_objectrefnode(CABI_GetDestructorObject(dtor, CABIDestroy1)); + funcnode->data.funccall.args->next->next = lalloc(sizeof(ENodeList)); + funcnode->data.funccall.args->next->next->node = create_objectrefnode(CInit_CreateStaticData(CInit_GetRegMemType()));; + funcnode->data.funccall.args->next->next->next = NULL; + node = funcnode; + } + return node; +} + +static void CInit_RefInit(Type *type, ENode *expr, Boolean flag) { + ENode *objexpr; + + objexpr = create_objectrefnode(cinit_initinfo->obj); + if (!IS_TYPE_POINTER_ONLY(objexpr->rtype)) { + CError_Error(CErrorStr174); + return; + } + TYPE_POINTER(objexpr->rtype)->target = type; + + if (cinit_initinfo->expr_offset) + objexpr = makediadicnode(objexpr, intconstnode(TYPE(&stunsignedlong), cinit_initinfo->expr_offset), EADD); + + objexpr = makemonadicnode(objexpr, EINDIRECT); + objexpr->rtype = type; + + expr = makediadicnode(objexpr, expr, EASS); + if (cinit_initinfo->x16) + cinit_initinfo->init_expr_register_cb(expr); + else + InitExpr_Register(expr, cinit_initinfo->obj); +} + +static Boolean CInit_IsDtorTemp(ENode *expr) { + return ENODE_IS(expr, ETEMP) && expr->data.temp.needs_dtor; +} + +static void CInit_FindDtorTemp(ENode *expr) { + ENodeList *list; + + while (ENODE_IS(expr, ECOMMA)) + expr = expr->data.diadic.right; + + if (IS_TYPE_POINTER_ONLY(expr->rtype) && IS_TYPE_CLASS(TYPE_POINTER(expr->rtype)->target)) { + switch (expr->type) { + case ETYPCON: + CInit_FindDtorTemp(expr->data.monadic); + break; + case EADD: + case ESUB: + CInit_FindDtorTemp(expr->data.diadic.left); + CInit_FindDtorTemp(expr->data.diadic.right); + break; + case EFUNCCALL: + case EFUNCCALLP: + if ((list = expr->data.funccall.args)) { + if (CInit_IsDtorTemp(list->node) || ((list = list->next) && CInit_IsDtorTemp(list->node))) { + if (!cinit_fdtnode) + cinit_fdtnode = list; + else + cinit_fdtambig = 1; + } + } + break; + } + } +} + +static void CInit_RefTempTransform(Type *type, ENode *expr) { + Object *obj; + + CError_ASSERT(3164, IS_TYPE_POINTER_ONLY(type)); + + if (IS_TYPE_CLASS(TYPE_POINTER(type)->target)) { + cinit_fdtnode = NULL; + cinit_fdtambig = 0; + CInit_FindDtorTemp(expr); + if (cinit_fdtnode) { + CError_ASSERT(3172, !cinit_fdtambig); + obj = create_temp_object(cinit_fdtnode->node->data.temp.type); + cinit_initinfo->register_object_cb(cinit_fdtnode->node->data.temp.type, obj, 0, 0); + cinit_fdtnode->node = create_objectrefnode(obj); + } + } +} + +static Boolean CInit_InitReference(Object *obj, Boolean flag) { + ENode *expr; + + if (tk == '=') { + cinit_tempnodefunc = flag ? CInit_AutoTempNode : CInit_GlobalTempNode; + tk = lex(); + expr = CExpr_AssignmentPromotion(assignment_expression(), obj->type, obj->qual & (Q_CONST | Q_VOLATILE), 1); + cinit_tempnodefunc = NULL; + + if (flag) { + CInit_RefTempTransform(obj->type, expr); + expr = makediadicnode(create_objectnode2(obj), expr, EASS); + cinit_initinfo->insert_expr_cb(expr); + } else { + cinit_initinfo->expr_cb = CInit_RefInit; + CInit_SetupInitInfoBuffer(obj->type); + CInit_ExprPointer(TYPE_POINTER(obj->type), expr); + CError_ASSERT(3213, obj->type->size == cinit_initinfo->size); + + if (cinit_initinfo->list || !CInit_IsAllZero(cinit_initinfo->buffer, obj->type->size)) { + IsCompleteType(obj->type); + CInit_AdjustObjectDataSize(obj); + CInit_DeclareData(obj, cinit_initinfo->buffer, cinit_initinfo->list, obj->type->size); + } else { + IsCompleteType(obj->type); + CInit_AdjustObjectDataSize(obj); + CInit_DeclareData(obj, NULL, NULL, obj->type->size); + } + } + + return 1; + } + + return 0; +} + +ENode *CInit_AutoObject(Object *obj, Type *type, UInt32 qual) { + CInit_Stuff s; + CInit_1C *entry; + ENode *expr; + ENode *indirect_expr; + ENode *obj_expr; + ENode *const_expr; + Type *newtype; + Object *newobj; + + CInit_InitData(&s, type, qual, copts.cplusplus || copts.gcc_extensions || copts.c9x || !obj); + if (!obj && !cscope_currentfunc) { + obj = CParser_NewCompilerDefDataObject(); + obj->name = CParser_GetUniqueName(); + obj->type = type; + obj->qual = qual; + obj->sclass = TK_STATIC; + CScope_AddGlobalObject(obj); + } + + if (IS_TYPE_VECTOR(type) && !s.x1C) { + if (obj) + obj_expr = create_objectrefnode(obj); + else + obj_expr = CExpr_NewETEMPNode(type, 1); + + const_expr = CExpr_NewENode(EVECTOR128CONST); + const_expr->rtype = type; + const_expr->data.vector128val = *((MWVector128 *) s.buffer); + + indirect_expr = makemonadicnode(obj_expr, EINDIRECT); + indirect_expr->rtype = type; + + expr = makediadicnode(indirect_expr, const_expr, EASS); + if (!obj) { + ENode *tmp = lalloc(sizeof(ENode)); + *tmp = *obj_expr; + tmp = makemonadicnode(tmp, EINDIRECT); + tmp->rtype = type; + tmp->flags = qual & ENODE_FLAG_QUALS; + expr = makecommaexpression(expr, tmp); + } + return expr; + } + + if (s.x18) { + type = CDecl_NewStructType(type->size + s.x18, CMach_GetTypeAlign(type)); + if (obj) + obj->type = type; + } + + if (obj) + obj_expr = create_objectrefnode(obj); + else + obj_expr = CExpr_NewETEMPNode(type, 1); + + newtype = type; + if (IS_TYPE_ARRAY(type)) + newtype = CDecl_NewStructType(type->size, CMach_GetTypeAlign(type)); + newobj = CInit_CreateStaticDataObject(newtype, 0, NULL); + if (s.list || !CInit_IsAllZero(s.buffer, s.size)) + CInit_DeclareReadOnlyData(newobj, s.buffer, s.list, s.size); + else + CInit_DeclareReadOnlyData(newobj, NULL, NULL, s.size); + + indirect_expr = makemonadicnode(obj_expr, EINDIRECT); + indirect_expr->rtype = newtype; + expr = makediadicnode(indirect_expr, create_objectnode(newobj), EASS); + + for (entry = s.x1C; entry; entry = entry->next) { + expr = CInit_InitConcat(expr, obj_expr, entry->offset, entry->type, entry->expr); + } + + if (!obj) { + ENode *tmp = lalloc(sizeof(ENode)); + *tmp = *obj_expr; + tmp = makemonadicnode(tmp, EINDIRECT); + tmp->rtype = type; + tmp->flags = qual & ENODE_FLAG_QUALS; + expr = makecommaexpression(expr, tmp); + } else if (IS_TYPE_ARRAY(type)) { + expr = makecommaexpression(expr, create_objectnode(obj)); + } + + return expr; +} + +static void CInit_GlobalObject(Object *obj) { + CInit_Stuff s; + CInit_1C *entry; + ENode *obj_expr; + ENode *expr; + + CInit_InitData(&s, obj->type, obj->qual, copts.cplusplus); + obj_expr = create_objectrefnode(obj); + + IsCompleteType(obj->type); + + if (!s.x1C && is_const_object(obj)) + CInit_DeclareReadOnlyData(obj, s.buffer, s.list, s.size); + else + CInit_DeclareData(obj, s.buffer, s.list, s.size); + + if (s.x1C) { + entry = s.x1C; + expr = NULL; + while (entry) { + if (!ENODE_IS(entry->expr, EVECTOR128CONST)) + expr = CInit_InitConcat(expr, obj_expr, entry->offset, entry->type, entry->expr); + entry = entry->next; + } + + if (expr) + InitExpr_Register(expr, obj); + } +} + +void CInit_InitializeAutoData(Object *obj, InsertExprCB insert_cb, RegisterObjectCB register_cb) { + ENode *expr; + Type *type; + InitInfo initinfo; + + if (CInit_IsSimpleStructArrayInit(obj->type)) { + if (tk == '=' || (tk == '(' && copts.cplusplus)) { + if (tk == '(') { + tk = lex(); + expr = conv_assignment_expression(); + if (tk != ')') + CError_Error(CErrorStr115); + tk = lex(); + } else if (tk == '=' && ((tk = lex()) == '{' || IS_TYPE_ARRAY(obj->type))) { + insert_cb(CInit_AutoObject(obj, obj->type, obj->qual)); + return; + } else { + expr = conv_assignment_expression(); + } + expr = CExpr_AssignmentPromotion(expr, obj->type, obj->qual & (Q_CONST | Q_VOLATILE), 1); + insert_cb(makediadicnode(create_objectnode2(obj), expr, EASS)); + } else if (copts.cplusplus && is_const_object(obj)) { + CError_Error(CErrorStr224); + } + + return; + } + + CInit_SetupInitInfo(&initinfo, obj); + initinfo.obj1C = obj; + initinfo.insert_expr_cb = insert_cb; + initinfo.register_object_cb = register_cb; + + if (IS_TYPE_CLASS(obj->type) && CInit_ConstructAutoObject(TYPE_CLASS(obj->type), NULL, 0, 1)) { + CInit_CleanupInitInfo(&initinfo); + return; + } + + if (IS_TYPE_REFERENCE(obj->type) && CInit_InitReference(obj, 1)) { + CInit_CleanupInitInfo(&initinfo); + return; + } + + if (tk != '=' && (tk != '(' || !copts.cplusplus)) { + if (IS_TYPE_ARRAY(obj->type)) { + type = obj->type; + while (IS_TYPE_ARRAY(type)) + type = TYPE_POINTER(type)->target; + if (IS_TYPE_CLASS(type)) { + if (CInit_ClassNeedsConstruction(TYPE_CLASS(type))) { + CInit_InitializeClassArray(obj, TYPE_CLASS(type), 0); + CInit_CleanupInitInfo(&initinfo); + return; + } + CFunc_CheckClassCtors(TYPE_CLASS(type)); + } + } + + if (IS_TYPE_CLASS(obj->type)) + CFunc_CheckClassCtors(TYPE_CLASS(obj->type)); + + if ((IS_TYPE_REFERENCE(obj->type) || is_const_object(obj)) && copts.cplusplus) + CError_Error(CErrorStr224); + } else { + if (obj->type->size || IS_TYPE_ARRAY(obj->type)) { + if ((expr = CInit_GenericData(NULL, obj->type, obj->qual, CInit_AutoInit, 0))) + insert_cb(makediadicnode(create_objectnode2(obj), expr, EASS)); + } else { + CError_Error(CErrorStr145); + } + } + + if (IS_TYPE_CLASS(obj->type) && CClass_Destructor(TYPE_CLASS(obj->type))) + register_cb(obj->type, obj, 0, 0); + + CInit_CleanupInitInfo(&initinfo); +} + +void CInit_InitializeStaticData(Object *obj, InitExprRegisterCB cb) { + ENode *expr; + Type *type; + InitInfo initinfo; + CInit_Stuff s; + CInit_1C *entry; + ENode *obj_expr; + + if (CInit_IsSimpleStructArrayInit(obj->type)) { + if (tk == '=' || (tk == '(' && copts.cplusplus)) { + if (tk == '=') + tk = lex(); + CInit_InitData(&s, obj->type, obj->qual, copts.cplusplus); + + IsCompleteType(obj->type); + + if (!s.x1C && is_const_object(obj)) + CInit_DeclareReadOnlyData(obj, s.buffer, s.list, s.size); + else + CInit_DeclareData(obj, s.buffer, s.list, s.size); + + if (s.x1C) { + obj_expr = create_objectrefnode(obj); + entry = s.x1C; + expr = NULL; + while (entry) { + expr = CInit_InitConcat(expr, obj_expr, entry->offset, entry->type, entry->expr); + entry = entry->next; + } + cb(expr); + } + } else { + if (copts.cplusplus && is_const_object(obj)) + CError_Error(CErrorStr224); + + if (is_const_object(obj)) + CInit_DeclareReadOnlyData(obj, NULL, NULL, obj->type->size); + else + CInit_DeclareData(obj, NULL, NULL, obj->type->size); + } + return; + } + + CInit_SetupInitInfo(&initinfo, obj); + initinfo.x16 = 1; + initinfo.init_expr_register_cb = cb; + + if (IS_TYPE_CLASS(obj->type) && CInit_ConstructGlobalObject(obj, TYPE_CLASS(obj->type), NULL, 0, 1)) { + IsCompleteType(obj->type); + CInit_DeclareData(obj, NULL, NULL, obj->type->size); + CInit_CleanupInitInfo(&initinfo); + return; + } + + if (IS_TYPE_REFERENCE(obj->type) && CInit_InitReference(obj, 0)) { + CInit_CleanupInitInfo(&initinfo); + return; + } + + if (tk != '=' && (tk != '(' || !copts.cplusplus)) { + if (IsCompleteType(obj->type)) + CInit_DeclareData(obj, NULL, NULL, obj->type->size); + + if (IS_TYPE_ARRAY(obj->type)) { + type = obj->type; + while (IS_TYPE_ARRAY(type)) + type = TYPE_POINTER(type)->target; + if (IS_TYPE_CLASS(type)) { + if (CInit_ClassNeedsConstruction(TYPE_CLASS(type))) { + CInit_InitializeClassArray(obj, TYPE_CLASS(type), 1); + CInit_CleanupInitInfo(&initinfo); + return; + } + CFunc_CheckClassCtors(TYPE_CLASS(type)); + } + } + + if (IS_TYPE_CLASS(obj->type)) + CFunc_CheckClassCtors(TYPE_CLASS(obj->type)); + + if ((IS_TYPE_REFERENCE(obj->type) || is_const_object(obj)) && copts.cplusplus) + CError_Error(CErrorStr224); + } else { + if (obj->type->size || IS_TYPE_ARRAY(obj->type)) { + if ((expr = CInit_GenericData(obj, obj->type, obj->qual, CInit_GlobalStaticInit, 1))) + cb(makediadicnode(create_objectnode2(obj), expr, EASS)); + } else { + CError_Error(CErrorStr145); + } + } + + CInit_CleanupInitInfo(&initinfo); +} + +void CInit_InitializeData(Object *obj) { + Object *dtor; + ObjectList *list; + CInt64 val; + InitInfo initinfo; + Boolean needs_construction; + Type *type; + + if (tk == ':') { + tk = lex(); + obj->datatype = DABSOLUTE; + val = CExpr_IntegralConstExpr(); + obj->u.address = CInt64_GetULong(&val); + return; + } + + if (tk != '=' && (tk != '(' || !copts.cplusplus)) { + if (obj->sclass != TK_EXTERN) { + if (!copts.cplusplus) { + if (IsCompleteType(obj->type)) { + for (list = cinit_tentative; list; list = list->next) { + if (list->object == obj) + break; + } + if (!list) { + list = galloc(sizeof(ObjectList)); + list->object = obj; + list->next = cinit_tentative; + cinit_tentative = list; + obj->qual |= Q_1000000; + } + } + } else { + if (obj->flags & OBJECT_DEFINED) + CError_Error(CErrorStr329, obj); + obj->flags = obj->flags | OBJECT_DEFINED; + + needs_construction = 0; + if (IS_TYPE_ARRAY(obj->type)) { + type = obj->type; + while (IS_TYPE_ARRAY(type)) + type = TYPE_POINTER(type)->target; + if (IS_TYPE_CLASS(type)) { + if (CInit_ClassNeedsConstruction(TYPE_CLASS(type))) { + CInit_SetupInitInfo(&initinfo, obj); + CInit_InitializeClassArray(obj, TYPE_CLASS(type), 1); + CInit_CleanupInitInfo(&initinfo); + needs_construction = 1; + } else { + CFunc_CheckClassCtors(TYPE_CLASS(type)); + } + } + } else { + if (IS_TYPE_CLASS(obj->type)) { + if (CInit_ClassNeedsConstruction(TYPE_CLASS(obj->type))) { + CInit_SetupInitInfo(&initinfo, obj); + CInit_ConstructGlobalObject(obj, TYPE_CLASS(obj->type), NULL, 0, 0); + CInit_CleanupInitInfo(&initinfo); + needs_construction = 1; + } else { + CFunc_CheckClassCtors(TYPE_CLASS(obj->type)); + } + } + } + + if (!needs_construction && copts.cplusplus) { + if (IS_TYPE_REFERENCE(obj->type) || is_const_object(obj)) + CError_Error(CErrorStr224); + } + if (IsCompleteType(obj->type)) + CInit_DeclareData(obj, NULL, NULL, obj->type->size); + } + } + return; + } + + if (obj->flags & OBJECT_DEFINED) + CError_Error(CErrorStr329, obj); + + if (CInit_IsSimpleStructArrayInit(obj->type)) { + if (tk == '=') + tk = lex(); + else + CError_Error(CErrorStr121); + CInit_GlobalObject(obj); + return; + } + + CInit_SetupInitInfo(&initinfo, obj); + if (IS_TYPE_CLASS(obj->type) && CInit_ConstructGlobalObject(obj, TYPE_CLASS(obj->type), NULL, 0, 1)) { + IsCompleteType(obj->type); + CInit_DeclareData(obj, NULL, NULL, obj->type->size); + CInit_CleanupInitInfo(&initinfo); + return; + } + + if (IS_TYPE_REFERENCE(obj->type) && CInit_InitReference(obj, 0)) { + CInit_CleanupInitInfo(&initinfo); + return; + } + + if (obj->type->size == 0 && !IS_TYPE_ARRAY(obj->type)) { + CError_Error(CErrorStr145); + CInit_CleanupInitInfo(&initinfo); + return; + } + + if (copts.cplusplus) + CInit_GenericData(obj, obj->type, obj->qual, &CInit_GlobalStaticInit, 0); + else + CInit_GenericData(obj, obj->type, obj->qual, NULL, 0); + + if (IS_TYPE_CLASS(obj->type) && (dtor = CClass_Destructor(TYPE_CLASS(obj->type)))) + InitExpr_Register(CInit_RegisterDtorObject(obj->type, dtor, create_objectrefnode(obj)), obj); + + CInit_CleanupInitInfo(&initinfo); +} + +Object *CInit_DeclareString(char *data, SInt32 size, Boolean ispascal, Boolean iswide) { + PooledString *str; + Object *obj; + PooledString *scan; + + if (!copts.dont_reuse_strings) { + for (scan = cinit_stringlist; scan; scan = scan->next) { + if (scan->size == size && scan->ispascal == ispascal && scan->iswide == iswide && !memcmp(scan->data, data, size)) + return scan->obj; + } + } + + obj = CParser_NewCompilerDefDataObject(); + obj->name = CParser_GetUniqueName(); + if (iswide) { + obj->type = CDecl_NewArrayType(CParser_GetWCharType(), size); + } else { + obj->type = CDecl_NewArrayType(ispascal ? TYPE(&stunsignedchar) : TYPE(&stchar), size); + } + obj->sclass = TK_STATIC; + CScope_AddGlobalObject(obj); + + if (!iswide && !ispascal && size == (strlen(data) + 1)) + obj->section = SECT_TEXT_CSTRING; + else + obj->section = SECT_CONST; + + if (copts.readonly_strings) + CInit_DeclareReadOnlyData(obj, data, NULL, obj->type->size); + else + CInit_DeclareData(obj, data, NULL, obj->type->size); + + str = galloc(sizeof(PooledString)); + str->next = cinit_stringlist; + cinit_stringlist = str; + str->obj = obj; + str->offset = 0; + str->size = size; + str->ispascal = ispascal; + str->iswide = iswide; + str->data = galloc(size); + memcpy(str->data, data, size); + + return obj; +} + +PooledString *CInit_DeclarePooledString(char *data, SInt32 size, Boolean ispascal) { + PooledString *str; + Object *obj; + PooledString *scan; + SInt32 offset; + + if (!copts.dont_reuse_strings) { + for (scan = cinit_pooledstringlist; scan; scan = scan->next) { + if (scan->size == size && scan->ispascal == ispascal && !memcmp(scan->data, data, size)) + return scan; + } + } + + if (cinit_pooledstringlist) { + obj = cinit_pooledstringlist->obj; + offset = cinit_pooledstringlist->offset + cinit_pooledstringlist->size; + } else { + obj = CInit_CreateStaticDataObject( + CDecl_NewArrayType(ispascal ? TYPE(&stunsignedchar) : TYPE(&stchar), size), + 0, GetHashNameNodeExport("@stringBase0")); + obj->section = SECT_CONST; + offset = 0; + } + + str = galloc(sizeof(PooledString)); + str->next = cinit_pooledstringlist; + cinit_pooledstringlist = str; + str->obj = obj; + str->offset = offset; + str->size = size; + str->ispascal = ispascal; + str->data = galloc(size); + memcpy(str->data, data, size); + return str; +} + +PooledString *CInit_DeclarePooledWString(char *data, SInt32 size) { + PooledString *str; + Object *obj; + PooledString *scan; + SInt32 offset; + + if (!copts.dont_reuse_strings) { + for (scan = cinit_pooledwstringlist; scan; scan = scan->next) { + if (scan->size == size && !memcmp(scan->data, data, size)) + return scan; + } + } + + if (cinit_pooledwstringlist) { + obj = cinit_pooledwstringlist->obj; + offset = cinit_pooledwstringlist->offset + cinit_pooledwstringlist->size; + } else { + obj = CInit_CreateStaticDataObject( + CDecl_NewArrayType(CParser_GetWCharType(), size), + 0, GetHashNameNodeExport("@wstringBase0")); + obj->section = SECT_CONST; + offset = 0; + } + + str = galloc(sizeof(PooledString)); + str->next = cinit_pooledwstringlist; + cinit_pooledwstringlist = str; + str->obj = obj; + str->offset = offset; + str->size = size; + str->ispascal = 0; + str->data = galloc(size); + memcpy(str->data, data, size); + return str; +} + +void CInit_RewriteString(ENode *expr, Boolean flag) { + PooledString *str; + Boolean is_wide; + + if (cparamblkptr->precompile == 1) + CError_Error(CErrorStr180); + + CError_ASSERT(4220, expr->rtype->type == TYPEPOINTER); + + is_wide = TYPE_POINTER(expr->rtype)->target->size != 1; + if (copts.poolstrings) { + if (is_wide) + str = CInit_DeclarePooledWString(expr->data.string.data, expr->data.string.size); + else + str = CInit_DeclarePooledString(expr->data.string.data, expr->data.string.size, expr->data.string.ispascal); + + if (str->offset) { + expr->type = EADD; + expr->data.diadic.right = intconstnode(TYPE(&stunsignedlong), str->offset); + expr->data.diadic.left = create_objectrefnode(str->obj); + expr->cost = 1; + } else { + expr->type = EOBJREF; + expr->data.objref = str->obj; + } + } else { + expr->type = EOBJREF; + expr->data.objref = CInit_DeclareString(expr->data.string.data, expr->data.string.size, expr->data.string.ispascal, is_wide); + } +} + +void CInit_DeclarePooledStrings(void) { + SInt32 size; + char *buffer; + PooledString *str; + + size = 0; + for (str = cinit_pooledstringlist; str; str = str->next) + size += str->size; + + if (size) { + cinit_pooledstringlist->obj->type = CDecl_NewArrayType(TYPE(&stchar), size); + buffer = galloc(size); + for (str = cinit_pooledstringlist; str; str = str->next) + memcpy(buffer + str->offset, str->data, str->size); + + if (copts.readonly_strings) + CInit_DeclareReadOnlyData(cinit_pooledstringlist->obj, buffer, NULL, size); + else + CInit_DeclareData(cinit_pooledstringlist->obj, buffer, NULL, size); + } + + size = 0; + for (str = cinit_pooledwstringlist; str; str = str->next) + size += str->size; + + if (size) { + cinit_pooledwstringlist->obj->type = CDecl_NewArrayType(CParser_GetWCharType(), size); + buffer = galloc(size); + for (str = cinit_pooledwstringlist; str; str = str->next) + memcpy(buffer + str->offset, str->data, str->size); + + if (copts.readonly_strings) + CInit_DeclareReadOnlyData(cinit_pooledwstringlist->obj, buffer, NULL, size); + else + CInit_DeclareData(cinit_pooledwstringlist->obj, buffer, NULL, size); + } +} + +static void declaredata(Object *obj, void *data, OLinkList *list, SInt32 size, Boolean is_readonly) { + OLinkList *scan; + UInt32 qual; + + qual = obj->qual; + + if (cparamblkptr->precompile == 1) { + PreComp_StaticData(obj, data, list, size); + } else { + obj->flags = obj->flags | OBJECT_DEFINED; + if (!fatalerrors) { + for (scan = list; scan; scan = scan->next) + CInline_ObjectAddrRef(scan->obj); + if (copts.filesyminfo) + CPrep_SetSourceFile(&cparser_fileoffset); + if (is_readonly) + ObjGen_DeclareReadOnlyData(obj, data, list, size); + else + ObjGen_DeclareData(obj, data, list, size); + obj->qual = qual; + } + } +} + +void CInit_DeclareData(Object *obj, void *data, OLinkList *list, SInt32 size) { + declaredata(obj, data, list, size, 0); +} + +void CInit_DeclareReadOnlyData(Object *obj, void *data, OLinkList *list, SInt32 size) { + declaredata(obj, data, list, size, 1); +} + +void CInit_DefineTentativeData(void) { + ObjectList *list; + + for (list = cinit_tentative; list; list = list->next) { + if (!(list->object->flags & OBJECT_DEFINED)) + CInit_DeclareData(list->object, NULL, NULL, list->object->type->size); + } + + cinit_tentative = NULL; +} diff --git a/compiler_and_linker/FrontEnd/C/CInline.c b/compiler_and_linker/FrontEnd/C/CInline.c new file mode 100644 index 0000000..de51ab7 --- /dev/null +++ b/compiler_and_linker/FrontEnd/C/CInline.c @@ -0,0 +1,4206 @@ +#include "compiler/CInline.h" +#include "compiler/CABI.h" +#include "compiler/CClass.h" +#include "compiler/CError.h" +#include "compiler/CException.h" +#include "compiler/CExpr.h" +#include "compiler/CFunc.h" +#include "compiler/CInit.h" +#include "compiler/CInt64.h" +#include "compiler/CMachine.h" +#include "compiler/CMangler.h" +#include "compiler/COptimizer.h" +#include "compiler/CParser.h" +#include "compiler/CPrepTokenizer.h" +#include "compiler/CTemplateNew.h" +#include "compiler/CodeGen.h" +#include "compiler/CompilerTools.h" +#include "compiler/Exceptions.h" +#include "compiler/InlineAsm.h" +#include "compiler/ObjGenMachO.h" +#include "compiler/Switch.h" +#include "compiler/enode.h" +#include "compiler/objects.h" +#include "compiler/scopes.h" +#include "compiler/templates.h" + +#ifdef __MWERKS__ +#pragma options align=mac68k +#endif +typedef struct IDTrans { + struct IDTrans *next; + SInt32 from; + SInt32 to; +} IDTrans; + +typedef struct LabelTrans { + struct LabelTrans *next; + CLabel **labelptr; + short id; +} LabelTrans; + +typedef struct UIDTemp { + struct UIDTemp *next; + Object *object; + SInt32 uid; +} UIDTemp; + +typedef struct CI_Export { + struct CI_Export *next; + Object *object; + CI_FuncData *funcdata; + Boolean xC; +} CI_Export; + +typedef struct AObject { + Object *object; + ENode *expr1; + ENode *expr2; +} AObject; + +typedef struct CI_StmtLink { + struct CI_StmtLink *next; + Statement *stmt; + CI_Statement *ciStmt; +} CI_StmtLink; +#ifdef __MWERKS__ +#pragma options align=reset +#endif + +static CInlineCopyMode enode_copymode; +static Boolean enode_globalcopy; +static IDTrans *enode_idtrans; +static Object **local_dobjects; +static AObject *local_aobjects; +static CI_Var *loc_args; +static CI_Var *loc_vars; +static Boolean inline_expanded; +static Boolean any_inline_expanded; +static short cinline_level; +static LabelTrans *cinline_label_trans; +static Statement *cinline_first_stmt; +static ENode *cinline_stmtlevelexpr[16]; +static short cinline_stmtlevelexprs; +static Boolean cinline_unconditionalpart; +static Boolean cinline_serialize_stmt; +static CI_Export *cinline_exportlist; // type? +static CI_Action *cinline_actionlist; +CI_Action *cinline_tactionlist; +static ObjectList *cinline_freflist; +static Boolean cinline_gendeps; +static Statement *cinline_serial_stmt; +static Statement *cinline_cur_serial_stmt; +static UIDTemp *cinline_uid_temps; +static Boolean cinline_has_sideeffect; +static SInt32 inline_max_size; +static Boolean recursive_inline; +static Object *expanding_function; +static Boolean cinline_funccallfound; + +// forward decls +static ENode *CInline_FoldConst(ENode *expr); +static ENode *CInline_CopyNodes(ENode *node); +static SInt32 CInline_EstimateSizeOfFunc(CI_FuncData *funcdata, SInt32 size, SInt32 level); +static ENode *CInline_SerializeExpr(ENode *expr); +static void CInline_AddFRefList_InlineFunc(CI_FuncData *data); + +void CInline_Init(void) { + cinline_exportlist = NULL; + cinline_actionlist = NULL; + cinline_tactionlist = NULL; + cinline_gendeps = 0; +} + +static ENode *CInline_MakeNotNot(ENode *expr) { + expr = CInline_FoldConst(expr); + + if (!ENODE_IS(expr, EINTCONST)) { + expr = makemonadicnode(expr, ELOGNOT); + expr->rtype = CParser_GetBoolType(); + expr = makemonadicnode(expr, ELOGNOT); + } else { + expr->data.intval = CInt64_Not(CInt64_Not(expr->data.intval)); + } + + return expr; +} + +static ENode *CInline_FoldConst(ENode *expr) { + ENode *inner; + ENode *right; + ENode *left; + ENodeList *list; + + switch (expr->type) { + case EINTCONST: + case EFLOATCONST: + case ESTRINGCONST: + case EOBJREF: + case EPRECOMP: + case ETEMP: + case ELABEL: + case EOBJLIST: + case EINSTRUCTION: + case EVECTOR128CONST: + return expr; + + case EMONMIN: + case EBINNOT: + case ELOGNOT: + expr->data.monadic = CInline_FoldConst(expr->data.monadic); + inner = expr->data.monadic; + switch (inner->type) { + case EINTCONST: + if (!ENODE_IS(expr, ELOGNOT)) { + inner->data.intval = CMach_CalcIntMonadic( + expr->rtype, CParser_GetOperator(expr->type), inner->data.intval); + } else { + inner->data.intval = CInt64_Not(inner->data.intval); + } + inner->rtype = expr->rtype; + return inner; + + case EFLOATCONST: + if (ENODE_IS(expr, ELOGNOT)) { + inner->type = EINTCONST; + CInt64_SetLong(&inner->data.intval, CMach_FloatIsZero(inner->data.floatval)); + } else { + inner->data.floatval = CMach_CalcFloatMonadic( + expr->rtype, CParser_GetOperator(expr->type), inner->data.floatval); + } + inner->rtype = expr->rtype; + return inner; + } + + return expr; + + case ETYPCON: + expr->data.monadic = CInline_FoldConst(expr->data.monadic); + switch (expr->data.monadic->type) { + case EINTCONST: + switch (expr->rtype->type) { + case TYPEFLOAT: + expr->type = EFLOATCONST; + expr->data.floatval = CMach_CalcFloatConvertFromInt( + expr->data.monadic->rtype, expr->data.monadic->data.intval); + return expr; + + case TYPEINT: + expr->type = EINTCONST; + expr->data.intval = CExpr_IntConstConvert( + expr->rtype, expr->data.monadic->rtype, expr->data.monadic->data.intval); + break; + } + break; + + case EFLOATCONST: + switch (expr->rtype->type) { + case TYPEFLOAT: + expr->type = EFLOATCONST; + expr->data.floatval = CMach_CalcFloatConvert( + expr->rtype, expr->data.monadic->data.floatval); + return expr; + + case TYPEINT: + expr->type = EINTCONST; + expr->data.intval = CMach_CalcIntConvertFromFloat( + expr->rtype, expr->data.monadic->data.floatval); + return expr; + } + break; + } + + return expr; + + case EPOSTINC: + case EPOSTDEC: + expr->data.monadic = CInline_FoldConst(expr->data.monadic); + switch (expr->data.monadic->type) { + case EINTCONST: + case EFLOATCONST: + expr->data.monadic->rtype = expr->rtype; + return expr->data.monadic; + } + + return expr; + + case EPREINC: + case EPREDEC: + case EINDIRECT: + case EFORCELOAD: + case EBITFIELD: + expr->data.monadic = CInline_FoldConst(expr->data.monadic); + return expr; + + case EMUL: + case EDIV: + case EMODULO: + case EADD: + case ESUB: + case ESHL: + case ESHR: + case EAND: + case EXOR: + case EOR: + expr->data.diadic.left = CInline_FoldConst(expr->data.diadic.left); + expr->data.diadic.right = CInline_FoldConst(expr->data.diadic.right); + if ((left = expr->data.diadic.left)->type == (right = expr->data.diadic.right)->type) { + switch (left->type) { + case EINTCONST: + left->data.intval = CMach_CalcIntDiadic( + expr->rtype, + expr->data.diadic.left->data.intval, + CParser_GetOperator(expr->type), + right->data.intval); + left->rtype = expr->rtype; + return left; + + case EFLOATCONST: + left->data.floatval = CMach_CalcFloatDiadic( + expr->rtype, + expr->data.diadic.left->data.floatval, + CParser_GetOperator(expr->type), + right->data.floatval); + left->rtype = expr->rtype; + return left; + } + } + + return expr; + + case ELESS: + case EGREATER: + case ELESSEQU: + case EGREATEREQU: + case EEQU: + case ENOTEQU: + expr->data.diadic.left = CInline_FoldConst(expr->data.diadic.left); + expr->data.diadic.right = CInline_FoldConst(expr->data.diadic.right); + if ((left = expr->data.diadic.left)->type == (right = expr->data.diadic.right)->type) { + switch (left->type) { + case EINTCONST: + left->data.intval = CMach_CalcIntDiadic( + left->rtype, + expr->data.diadic.left->data.intval, + CParser_GetOperator(expr->type), + right->data.intval); + left->rtype = expr->rtype; + return left; + + case EFLOATCONST: + CInt64_SetLong(&left->data.intval, CMach_CalcFloatDiadicBool( + left->rtype, + expr->data.diadic.left->data.floatval, + CParser_GetOperator(expr->type), + right->data.floatval + )); + left->type = EINTCONST; + left->rtype = expr->rtype; + return left; + } + } + + return expr; + + case ELAND: + expr->data.diadic.left = CInline_FoldConst(expr->data.diadic.left); + if (iszero(expr->data.diadic.left)) + return expr->data.diadic.left; + if (isnotzero(expr->data.diadic.left)) + return CInline_MakeNotNot(expr->data.diadic.right); + + expr->data.diadic.right = CInline_FoldConst(expr->data.diadic.right); + if (isnotzero(expr->data.diadic.right)) + return CInline_MakeNotNot(expr->data.diadic.left); + + return expr; + + case ELOR: + expr->data.diadic.left = CInline_FoldConst(expr->data.diadic.left); + if (iszero(expr->data.diadic.left)) + return CInline_MakeNotNot(expr->data.diadic.right); + if (isnotzero(expr->data.diadic.left)) + return CInline_MakeNotNot(expr->data.diadic.left); + + expr->data.diadic.right = CInline_FoldConst(expr->data.diadic.right); + if (iszero(expr->data.diadic.right)) + return CInline_MakeNotNot(expr->data.diadic.left); + + return expr; + + 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 = CInline_FoldConst(expr->data.diadic.left); + expr->data.diadic.right = CInline_FoldConst(expr->data.diadic.right); + return expr; + + case ECOND: + expr->data.cond.cond = CInline_FoldConst(expr->data.cond.cond); + if (isnotzero(expr->data.cond.cond)) + return CInline_FoldConst(expr->data.cond.expr1); + if (iszero(expr->data.cond.cond)) + return CInline_FoldConst(expr->data.cond.expr2); + + expr->data.cond.expr1 = CInline_FoldConst(expr->data.cond.expr1); + expr->data.cond.expr2 = CInline_FoldConst(expr->data.cond.expr2); + return expr; + + case EMFPOINTER: + expr->data.mfpointer.accessnode = CInline_FoldConst(expr->data.mfpointer.accessnode); + expr->data.mfpointer.mfpointer = CInline_FoldConst(expr->data.mfpointer.mfpointer); + return expr; + + case EFUNCCALL: + case EFUNCCALLP: + expr->data.funccall.funcref = CInline_FoldConst(expr->data.funccall.funcref); + for (list = expr->data.funccall.args; list; list = list->next) + list->node = CInline_FoldConst(list->node); + return expr; + + case ENULLCHECK: + expr->data.nullcheck.nullcheckexpr = CInline_FoldConst(expr->data.nullcheck.nullcheckexpr); + expr->data.nullcheck.condexpr = CInline_FoldConst(expr->data.nullcheck.condexpr); + return expr; + + case EMEMBER: + if (expr->data.emember->expr) + expr->data.emember->expr = CInline_FoldConst(expr->data.emember->expr); + return expr; + + default: + CError_FATAL(421); + return expr; + } +} + +// unknown name +CW_INLINE SInt32 CInline_GetLocalID2(Object *object) { + ObjectList *list; + SInt32 counter; + + for (list = locals, counter = 0; list; list = list->next) { + if (list->object->datatype == DLOCAL) { + if (list->object == object) + return counter; + counter++; + } + } + + return -1; +} + +SInt32 CInline_GetLocalID(Object *object) { + ObjectList *list; + SInt32 counter; + + if (object) { + for (list = arguments, counter = 0; list; list = list->next, counter++) { + if (list->object == object) { + loc_args[counter].xD = 1; + loc_args[counter].xE = 0; + return counter - 0x7FFFFFFF; + } + } + + counter = CInline_GetLocalID2(object); + CError_ASSERT(465, counter >= 0); + loc_vars[counter].xD = 1; + return counter + 1; + } + + return 0; +} + +static Boolean CInline_IsTrivialExpression(ENode *expr) { + while (1) { + switch (expr->type) { + case EINTCONST: + case EFLOATCONST: + case EOBJREF: + case EARGOBJ: + case ELOCOBJ: + case EOBJLIST: + case EVECTOR128CONST: + return 0; + + case ESTRINGCONST: + return copts.dont_reuse_strings; + + case EMEMBER: + if (expr->data.emember->expr) + return CInline_IsTrivialExpression(expr->data.emember->expr); + return 0; + + case EINDIRECT: + if (ENODE_IS(expr->data.monadic, EOBJREF)) { + if (expr->data.monadic->data.objref->datatype == DLOCAL && + !(expr->data.monadic->data.objref->flags & OBJECT_FLAGS_2)) + return 0; + + if (is_const_object(expr->data.monadic->data.objref)) + return 0; + + return 1; + } + + return 1; + + case EPOSTINC: + case EPOSTDEC: + case EPREINC: + case EPREDEC: + case EFORCELOAD: + case EASS: + case EMULASS: + case EDIVASS: + case EMODASS: + case EADDASS: + case ESUBASS: + case ESHLASS: + case ESHRASS: + case EANDASS: + case EXORASS: + case EORASS: + case EFUNCCALL: + case EFUNCCALLP: + case EMFPOINTER: + case ENULLCHECK: + case EPRECOMP: + case ETEMP: + case ELABEL: + case EINSTRUCTION: + return 1; + + case EMONMIN: + case EBINNOT: + case ELOGNOT: + case ETYPCON: + case EBITFIELD: + expr = expr->data.monadic; + continue; + + 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 ELAND: + case ELOR: + case ECOMMA: + case EROTL: + case EROTR: + if (CInline_IsTrivialExpression(expr->data.diadic.left)) + return 1; + expr = expr->data.diadic.right; + continue; + + case ECOND: + if (CInline_IsTrivialExpression(expr->data.cond.cond)) + return 1; + if (CInline_IsTrivialExpression(expr->data.cond.expr1)) + return 1; + expr = expr->data.cond.expr2; + continue; + + default: + CError_FATAL(582); + } + } +} + +Boolean CInline_ExpressionHasSideEffect(ENode *expr) { + while (1) { + switch (expr->type) { + case EINTCONST: + case EFLOATCONST: + case ESTRINGCONST: + case EOBJREF: + case EPRECOMP: + case ETEMP: + case EARGOBJ: + case ELOCOBJ: + case ELABEL: + case EOBJLIST: + case EVECTOR128CONST: + return 0; + + case EPOSTINC: + case EPOSTDEC: + case EPREINC: + case EPREDEC: + case EASS: + case EMULASS: + case EDIVASS: + case EMODASS: + case EADDASS: + case ESUBASS: + case ESHLASS: + case ESHRASS: + case EANDASS: + case EXORASS: + case EORASS: + case EFUNCCALL: + case EFUNCCALLP: + case EINSTRUCTION: + return 1; + + case EINDIRECT: + case EMONMIN: + case EBINNOT: + case ELOGNOT: + case EFORCELOAD: + case ETYPCON: + case EBITFIELD: + expr = expr->data.monadic; + continue; + + 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 ELAND: + case ELOR: + case ECOMMA: + case EROTL: + case EROTR: + if (CInline_ExpressionHasSideEffect(expr->data.diadic.left)) + return 1; + expr = expr->data.diadic.right; + continue; + + case EMEMBER: + if (expr->data.emember->expr) + return CInline_ExpressionHasSideEffect(expr->data.emember->expr); + return 0; + + case EMFPOINTER: + if (CInline_ExpressionHasSideEffect(expr->data.mfpointer.accessnode)) + return 1; + expr = expr->data.mfpointer.mfpointer; + continue; + + case ENULLCHECK: + if (CInline_ExpressionHasSideEffect(expr->data.nullcheck.nullcheckexpr)) + return 1; + expr = expr->data.nullcheck.condexpr; + continue; + + case ECOND: + if (CInline_ExpressionHasSideEffect(expr->data.cond.cond)) + return 1; + if (CInline_ExpressionHasSideEffect(expr->data.cond.expr1)) + return 1; + expr = expr->data.cond.expr2; + continue; + + default: + CError_FATAL(689); + } + } +} + +static ENode *CInline_CopyExpressionSave(ENode *expr) { + CInlineCopyMode save_copymode; + Boolean save_globalcopy; + IDTrans *save_idtrans; + + save_globalcopy = enode_globalcopy; + enode_globalcopy = 1; + + save_copymode = enode_copymode; + enode_copymode = CopyMode4; + + save_idtrans = enode_idtrans; + enode_idtrans = NULL; + + expr = CInline_CopyNodes(expr); + + enode_globalcopy = save_globalcopy; + enode_copymode = save_copymode; + enode_idtrans = save_idtrans; + + return expr; +} + +static SInt32 CInline_TranslateID(SInt32 id) { + IDTrans *trans; + + for (trans = enode_idtrans; trans; trans = trans->next) { + if (trans->from == id) + return trans->to; + } + + trans = lalloc(sizeof(IDTrans)); + trans->next = enode_idtrans; + enode_idtrans = trans; + + trans->from = id; + trans->to = CParser_GetUniqueID(); + + return trans->to; +} + +static short CInline_GetLabelStatementNumber(HashNameNode *name) { + Statement *stmt; + short i; + + for (stmt = cinline_first_stmt, i = 0; stmt; stmt = stmt->next, i++) { + if (stmt->type == ST_LABEL && stmt->label->uniquename == name) + return i; + } + + CError_FATAL(742); + return 0; +} + +static ENodeList *CInline_CopyNodeList(ENodeList *list) { + ENodeList *copy; + ENodeList *first; + ENodeList *last; + + first = NULL; + while (list) { + if (enode_globalcopy) + copy = galloc(sizeof(ENodeList)); + else + copy = lalloc(sizeof(ENodeList)); + + copy->node = CInline_CopyNodes(list->node); + copy->next = NULL; + + if (first) { + last->next = copy; + last = copy; + } else { + first = last = copy; + } + + list = list->next; + } + + return first; +} + +static EMemberInfo *CInline_CopyEMemberInfo(EMemberInfo *mi) { + EMemberInfo *copy; + + if (enode_globalcopy) + copy = galloc(sizeof(EMemberInfo)); + else + copy = lalloc(sizeof(EMemberInfo)); + + *copy = *mi; + if (copy->path) + copy->path = CClass_GetPathCopy(copy->path, enode_globalcopy); + if (copy->expr) + copy->expr = CInline_CopyNodes(copy->expr); + + return copy; +} + +static ENode *CInline_CopyNodes(ENode *node) { + ENode *copy; + + if (enode_globalcopy) + copy = galloc(sizeof(ENode)); + else + copy = lalloc(sizeof(ENode)); + + while (1) { + *copy = *node; + switch (copy->type) { + case ETEMPLDEP: + switch (copy->data.templdep.subtype) { + case TDE_PARAM: + case TDE_SIZEOF: + case TDE_ALIGNOF: + case TDE_QUALNAME: + case TDE_OBJ: + break; + case TDE_CAST: + copy->data.templdep.u.cast.args = CInline_CopyNodeList(copy->data.templdep.u.cast.args); + break; + case TDE_SOURCEREF: + copy->data.templdep.u.sourceref.expr = CInline_CopyNodes(copy->data.templdep.u.sourceref.expr); + break; + case TDE_ADDRESS_OF: + copy->data.templdep.u.monadic = CInline_CopyNodes(copy->data.templdep.u.monadic); + break; + default: + CError_FATAL(840); + } + break; + + case ETEMP: + if (enode_copymode == CopyMode3 && copy->data.temp.uniqueid) + copy->data.temp.uniqueid = CInline_TranslateID(copy->data.temp.uniqueid); + break; + + case ELABEL: + switch (enode_copymode) { + case CopyMode2: + copy->data.precompid = CInline_GetLabelStatementNumber(copy->data.label->uniquename); + return copy; + case CopyMode3: + case CopyMode4: { + LabelTrans *trans = lalloc(sizeof(LabelTrans)); + trans->next = cinline_label_trans; + cinline_label_trans = trans; + trans->id = copy->data.precompid; + trans->labelptr = ©->data.label; + return copy; + } + } + break; + + case EINTCONST: + case EFLOATCONST: + case ESTRINGCONST: + case EOBJLIST: + case EINSTRUCTION: + case EVECTOR128CONST: + break; + + case EPOSTINC: + case EPOSTDEC: + case EPREINC: + case EPREDEC: + case EMONMIN: + case EBINNOT: + case ELOGNOT: + case EFORCELOAD: + case ETYPCON: + case EBITFIELD: + copy->data.monadic = CInline_CopyNodes(copy->data.monadic); + break; + + ENODE_CASE_DIADIC_ALL: + copy->data.diadic.left = CInline_CopyNodes(copy->data.diadic.left); + copy->data.diadic.right = CInline_CopyNodes(copy->data.diadic.right); + break; + + case ECOND: + copy->data.cond.cond = CInline_CopyNodes(copy->data.cond.cond); + copy->data.cond.expr1 = CInline_CopyNodes(copy->data.cond.expr1); + copy->data.cond.expr2 = CInline_CopyNodes(copy->data.cond.expr2); + break; + + case EMFPOINTER: + copy->data.mfpointer.accessnode = CInline_CopyNodes(copy->data.mfpointer.accessnode); + copy->data.mfpointer.mfpointer = CInline_CopyNodes(copy->data.mfpointer.mfpointer); + break; + + case EFUNCCALL: + case EFUNCCALLP: + copy->data.funccall.funcref = CInline_CopyNodes(copy->data.funccall.funcref); + copy->data.funccall.args = CInline_CopyNodeList(copy->data.funccall.args); + break; + + case ENULLCHECK: + copy->data.nullcheck.precompid = CInline_TranslateID(copy->data.nullcheck.precompid); + copy->data.nullcheck.nullcheckexpr = CInline_CopyNodes(copy->data.nullcheck.nullcheckexpr); + copy->data.nullcheck.condexpr = CInline_CopyNodes(copy->data.nullcheck.condexpr); + break; + + case EPRECOMP: + copy->data.precompid = CInline_TranslateID(copy->data.precompid); + break; + + case EINDIRECT: + if ( + enode_copymode == CopyMode4 && + ENODE_IS(copy->data.monadic, EARGOBJ) && + local_aobjects[copy->data.monadic->data.longval].object == NULL + ) + { + CError_ASSERT(910, local_aobjects[copy->data.monadic->data.longval].expr1); + copy = CInline_CopyExpressionSave(local_aobjects[copy->data.monadic->data.longval].expr1); + if (copy->rtype != node->rtype) { + if (IS_TYPE_INT(copy->rtype) && IS_TYPE_INT(node->rtype)) + copy = makemonadicnode(copy, ETYPCON); + copy->rtype = node->rtype; + } + return copy; + } + + copy->data.monadic = CInline_CopyNodes(copy->data.monadic); + break; + + case EOBJREF: + if (enode_copymode == CopyMode2) { + ObjectList *list; + int i; + + if (node->data.objref->datatype == DALIAS) { + CExpr_AliasTransform(node); + continue; + } + + if (node->data.objref->datatype == DDATA) + return copy; + + for (list = arguments, i = 0; list; list = list->next, i++) { + if (list->object == copy->data.objref) { + copy->type = EARGOBJ; + copy->data.longval = i; + return copy; + } + } + + i = CInline_GetLocalID2(copy->data.objref); + if (i >= 0) { + copy->type = ELOCOBJ; + copy->data.longval = i; + return copy; + } + + if (node->data.objref->datatype == DLOCAL) + CError_FATAL(949); + } + break; + + case EARGOBJ: + switch (enode_copymode) { + case CopyMode4: + CError_ASSERT(957, local_aobjects[copy->data.longval].object); + copy->type = EOBJREF; + copy->data.objref = local_aobjects[copy->data.longval].object; + return copy; + + case CopyMode3: { + ObjectList *list; + int i; + for (list = arguments, i = 0; list; list = list->next, i++) { + if (i == copy->data.longval) { + copy->type = EOBJREF; + copy->data.objref = list->object; + CError_ASSERT(966, copy->data.objref); + return copy; + } + } + } + + default: + CError_FATAL(971); + } + + case ELOCOBJ: + switch (enode_copymode) { + case CopyMode4: + copy->type = EOBJREF; + copy->data.objref = local_dobjects[copy->data.longval]; + return copy; + + case CopyMode3: { + ObjectList *list; + int i; + for (list = locals, i = 0; list; list = list->next, i++) { + if (i == copy->data.longval) { + copy->type = EOBJREF; + copy->data.objref = list->object; + CError_ASSERT(986, copy->data.objref); + return copy; + } + } + } + + default: + CError_FATAL(991); + } + break; + + case ENEWEXCEPTION: + case ENEWEXCEPTIONARRAY: + copy->data.newexception.initexpr = CInline_CopyNodes(copy->data.newexception.initexpr); + copy->data.newexception.tryexpr = CInline_CopyNodes(copy->data.newexception.tryexpr); + break; + + case EINITTRYCATCH: + copy->data.itc.initexpr = CInline_CopyNodes(copy->data.itc.initexpr); + copy->data.itc.tryexpr = CInline_CopyNodes(copy->data.itc.tryexpr); + copy->data.itc.catchexpr = CInline_CopyNodes(copy->data.itc.catchexpr); + copy->data.itc.result = CInline_CopyNodes(copy->data.itc.result); + break; + + case EMEMBER: + copy->data.emember = CInline_CopyEMemberInfo(copy->data.emember); + break; + + default: + CError_FATAL(1015); + } + + return copy; + } +} + +static void CInline_CheckUsage(ENode *expr, Boolean flag) { + ENodeList *list; + ENode *inner; + + while (1) { + switch (expr->type) { + case EARGOBJ: + loc_args[expr->data.longval].xD = 1; + loc_args[expr->data.longval].xE = 0; + return; + + case ELOCOBJ: + loc_vars[expr->data.longval].xD = 1; + return; + + case EINDIRECT: + if (ENODE_IS((inner = expr->data.monadic), EARGOBJ)) { + loc_args[inner->data.longval].xD = 1; + if (flag) + loc_args[inner->data.longval].xE = 0; + return; + } + expr = expr->data.monadic; + flag = 0; + continue; + + case EMONMIN: + case EBINNOT: + case ELOGNOT: + case EFORCELOAD: + case ETYPCON: + case EBITFIELD: + expr = expr->data.monadic; + flag = 0; + continue; + + case EPOSTINC: + case EPOSTDEC: + case EPREINC: + case EPREDEC: + expr = expr->data.monadic; + flag = 1; + continue; + + case EASS: + case EMULASS: + case EDIVASS: + case EMODASS: + case EADDASS: + case ESUBASS: + case ESHLASS: + case ESHRASS: + case EANDASS: + case EXORASS: + case EORASS: + CInline_CheckUsage(expr->data.diadic.left, 1); + expr = expr->data.diadic.right; + flag = 0; + continue; + + 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 ELAND: + case ELOR: + case ECOMMA: + case EROTL: + case EROTR: + CInline_CheckUsage(expr->data.diadic.left, 0); + expr = expr->data.diadic.right; + flag = 0; + continue; + + case EINTCONST: + case EFLOATCONST: + case ESTRINGCONST: + case EOBJREF: + case EPRECOMP: + case ETEMP: + case ELABEL: + case EOBJLIST: + case EVECTOR128CONST: + return; + + case EMEMBER: + if (expr->data.emember->expr) + CInline_CheckUsage(expr->data.emember->expr, 0); + return; + + case EFUNCCALL: + case EFUNCCALLP: + CInline_CheckUsage(expr->data.funccall.funcref, 0); + for (list = expr->data.funccall.args; list; list = list->next) + CInline_CheckUsage(list->node, 0); + return; + + case ENULLCHECK: + CInline_CheckUsage(expr->data.nullcheck.nullcheckexpr, 0); + expr = expr->data.nullcheck.condexpr; + flag = 0; + continue; + + case EMFPOINTER: + CInline_CheckUsage(expr->data.mfpointer.accessnode, 0); + expr = expr->data.mfpointer.mfpointer; + flag = 0; + continue; + + case ECOND: + CInline_CheckUsage(expr->data.cond.cond, 0); + CInline_CheckUsage(expr->data.cond.expr1, 0); + expr = expr->data.cond.expr2; + flag = 0; + continue; + + case EINSTRUCTION: + return; + + default: + CError_FATAL(1146); + } + } +} + +ENode *CInline_CopyExpression(ENode *expr, CInlineCopyMode mode) { + enode_copymode = mode; + + switch (mode) { + case CopyMode0: + case CopyMode4: + enode_idtrans = NULL; + enode_globalcopy = 0; + expr = CInline_CopyNodes(expr); + break; + case CopyMode3: + enode_globalcopy = 0; + expr = CInline_CopyNodes(expr); + break; + case CopyMode1: + enode_idtrans = NULL; + enode_globalcopy = 1; + expr = CInline_CopyNodes(expr); + break; + case CopyMode2: + enode_idtrans = NULL; + enode_globalcopy = 1; + expr = CInline_CopyNodes(expr); + CInline_CheckUsage(expr, 0); + break; + } + + return expr; +} + +static UInt8 CInline_GetObjectSFlags(Object *object) { + UInt8 flags; + + switch (object->sclass) { + case 0: + flags = CI_SFLAGS_NoClass; + break; + case TK_REGISTER: + flags = CI_SFLAGS_Register; + break; + case TK_AUTO: + flags = CI_SFLAGS_Auto; + break; + default: + CError_FATAL(1204); + } + + if (object->flags & OBJECT_FLAGS_2) + flags |= CI_SFLAGS_HasObjectFlag2; + + return flags; +} + +static void CInline_SetObjectSFlags(Object *object, UInt8 sflags) { + if (sflags & CI_SFLAGS_HasObjectFlag2) { + object->flags |= OBJECT_FLAGS_2; + sflags &= ~CI_SFLAGS_HasObjectFlag2; + } + + switch (sflags) { + case CI_SFLAGS_NoClass: + object->sclass = 0; + break; + case CI_SFLAGS_Register: + object->sclass = TK_REGISTER; + break; + case CI_SFLAGS_Auto: + object->sclass = TK_AUTO; + break; + default: + CError_FATAL(1229); + } +} + +static Object *CInline_NewLocalObject(Type *type, short qual, UInt8 sflags, int unk) { + Object *object = CParser_NewLocalDataObject(NULL, 1); + object->name = CParser_GetUniqueName(); + object->type = type; + object->qual = qual; + CInline_SetObjectSFlags(object, sflags); + CFunc_SetupLocalVarInfo(object); + return object; +} + +static ENode *CInline_FuncArgConvert(ENode *expr) { + ENode *copy; + + switch (expr->type) { + case EOBJREF: + copy = lalloc(sizeof(ENode)); + *copy = *expr; + return copy; + case ETEMP: + CError_FATAL(1272); + } + + return NULL; +} + +static ENode *CInline_RefArgTransform(ENode *expr, Boolean flag) { + ENodeList *arg; + + while (ENODE_IS(expr, ECOMMA)) + expr = expr->data.diadic.right; + + switch (expr->type) { + case EOBJREF: + case ETEMP: + if (flag) + return CInline_FuncArgConvert(expr); + break; + + case EFUNCCALL: + if (IS_TYPE_POINTER_ONLY(expr->rtype) && IS_TYPE_CLASS(TPTR_TARGET(expr->rtype))) { + if ( + ENODE_IS(expr->data.funccall.funcref, EOBJREF) && + CClass_IsConstructor(expr->data.funccall.funcref->data.objref) && + expr->data.funccall.args + ) + return CInline_FuncArgConvert(expr->data.funccall.args->node); + + if ( + TPTR_TARGET(expr->rtype) == expr->data.funccall.functype->functype && + CMach_GetFunctionResultClass(expr->data.funccall.functype) == 1 && + (arg = expr->data.funccall.args) + ) + { + switch (CABI_GetStructResultArgumentIndex(expr->data.funccall.functype)) { + case 0: + break; + case 1: + if ((arg = arg->next)) + break; + CError_FATAL(1313); + default: + CError_FATAL(1314); + } + + return CInline_FuncArgConvert(arg->node); + } + } + break; + } + + return NULL; +} + +static ENode *CInline_SetupArgsExpression(Object *object, CI_FuncData *data, ENodeList *list) { + ENode *commaNodes; + CI_Var *var; + ENodeList *scan; + ENode *expr; + SInt32 i; + Boolean is_oldstyle; + + is_oldstyle = 0; + if (TYPE_FUNC(object->type)->args == &oldstyle) + is_oldstyle = 1; + + local_dobjects = lalloc(sizeof(Object *) * data->numlocals); + local_aobjects = lalloc(sizeof(AObject) * data->numarguments); + + for (i = 0, var = data->locals; i < data->numlocals; i++, var++) { + if (var->xD) { + object = CInline_NewLocalObject(var->type, var->qual, var->sflags, 0); + local_dobjects[i] = object; + if (!var->xE) + object->flags |= OBJECT_FLAGS_2; + } else { + local_dobjects[i] = NULL; + } + } + + for (i = 0, var = data->arguments, scan = list; i < data->numarguments; i++, var++) { + local_aobjects[i].expr2 = NULL; + + if (!var->xD) { + local_aobjects[i].object = NULL; + local_aobjects[i].expr1 = NULL; + } else if ( + scan && + var->xE && + !CInline_IsTrivialExpression(scan->node) && + (!is_oldstyle || scan->node->rtype->size == var->type->size) + ) + { + local_aobjects[i].object = NULL; + local_aobjects[i].expr1 = scan->node; + } else if ( + scan && + var->xE && + IS_TYPE_REFERENCE(var->type) && + (expr = CInline_RefArgTransform(scan->node, 1)) + ) + { + local_aobjects[i].object = NULL; + local_aobjects[i].expr1 = expr; + local_aobjects[i].expr2 = scan->node; + } else { + local_aobjects[i].object = CInline_NewLocalObject(var->type, var->qual, var->sflags, 0); + local_aobjects[i].expr1 = NULL; + } + + if (scan) + scan = scan->next; + } + + commaNodes = NULL; + + for (i = 0, scan = list; scan; scan = scan->next, i++) { + if (i >= data->numarguments) { + if (!commaNodes) + commaNodes = scan->node; + else + commaNodes = makecommaexpression(scan->node, commaNodes); + } else if (!local_aobjects[i].object || local_aobjects[i].expr2) { + if (local_aobjects[i].expr2) { + if (!commaNodes) + commaNodes = local_aobjects[i].expr2; + else + commaNodes = makecommaexpression(local_aobjects[i].expr2, commaNodes); + } else if (!local_aobjects[i].expr1 && CInline_IsTrivialExpression(scan->node)) { + commaNodes = !commaNodes ? scan->node : makecommaexpression(scan->node, commaNodes); + CError_ASSERT(1470, !ENODE_IS(scan->node, EPRECOMP)); + } + } else { + if (is_oldstyle && scan->node->rtype->size != local_aobjects[i].object->type->size) { + scan->node = makemonadicnode(scan->node, ETYPCON); + scan->node->rtype = local_aobjects[i].object->type; + } + + expr = makediadicnode(create_objectnode2(local_aobjects[i].object), scan->node, EASS); + if (!commaNodes) + commaNodes = expr; + else + commaNodes = makecommaexpression(expr, commaNodes); + } + } + + return commaNodes; +} + +static void CInline_ReturnCheckCB(ENode *expr) { + cinline_has_sideeffect = 1; +} + +static ENode *CInline_ReturnCheck(ENode *expr) { + ENode *copy; + + if (ENODE_IS(expr, EFORCELOAD)) + return expr; + + cinline_has_sideeffect = 0; + CExpr_SearchExprTree(expr, CInline_ReturnCheckCB, 3, EINDIRECT, EFUNCCALL, EFUNCCALLP); + + if (!cinline_has_sideeffect) + return expr; + + copy = lalloc(sizeof(ENode)); + *copy = *expr; + copy->type = EFORCELOAD; + + copy->data.monadic = expr; + return copy; +} + +static ENode *CInline_ReturnMemResult(Object *object) { + int index = CABI_GetStructResultArgumentIndex(TYPE_FUNC(object->type)); + if (local_aobjects[index].object == NULL) + return CInline_CopyExpressionSave(local_aobjects[index].expr1); + else + return create_objectnode(local_aobjects[index].object); +} + +static ENode *CInline_InlineFunctionExpression(ENode *expr) { + Object *object; + CI_FuncData *funcdata; + short i; + Boolean flag26; + ENode *argsExpr; + + object = expr->data.funccall.funcref->data.objref; + if (object->datatype == DALIAS) + object = object->u.alias.object; + + funcdata = object->u.func.u.ifuncdata; + if (!funcdata) + return expr; + + if (funcdata->can_inline < CI_CanInline6) { + if (funcdata->can_inline == CI_CanInline3) { + if (cinline_unconditionalpart && cinline_stmtlevelexprs < 16) + cinline_stmtlevelexpr[cinline_stmtlevelexprs++] = expr; + cinline_serialize_stmt = 1; + } + return expr; + } + + flag26 = CMach_GetFunctionResultClass(TYPE_FUNC(object->type)) == 1; + argsExpr = CInline_SetupArgsExpression(object, funcdata, expr->data.funccall.args); + + for (i = 0; i < funcdata->numstatements; i++) { + switch (funcdata->statements[i].type) { + case ST_RETURN: + if (funcdata->statements[i].u.expr) { + ENode *copy = CInline_CopyExpression(funcdata->statements[i].u.expr, CopyMode4); + if (flag26) { + if (argsExpr) + argsExpr = makecommaexpression(argsExpr, copy); + else + argsExpr = copy; + + argsExpr = makecommaexpression(argsExpr, CInline_ReturnMemResult(object)); + } else { + if (argsExpr) + argsExpr = makecommaexpression(argsExpr, CInline_ReturnCheck(copy)); + else + argsExpr = CInline_ReturnCheck(copy); + } + } + break; + case ST_EXPRESSION: + if (argsExpr) + argsExpr = makecommaexpression(argsExpr, CInline_CopyExpression(funcdata->statements[i].u.expr, CopyMode4)); + else + argsExpr = CInline_CopyExpression(funcdata->statements[i].u.expr, CopyMode4); + break; + + default: + CError_FATAL(1632); + } + } + + if (!argsExpr) + argsExpr = nullnode(); + if (!IS_TYPE_VOID(expr->rtype)) + argsExpr->rtype = expr->rtype; + + inline_expanded = 1; + return CInline_FoldConst(argsExpr); +} + +static Boolean CInline_CanExpand(ENode *expr) { + TypeFunc *tfunc; + Object *object; + + object = expr->data.objref; + tfunc = TYPE_FUNC(object->type); + + if ( + IS_TYPE_FUNC(tfunc) && + ((object->qual & Q_INLINE) || (tfunc->flags & FUNC_FLAGS_800)) && + (object->datatype == DFUNC || (object->datatype == DVFUNC && (expr->flags & ENODE_FLAG_80))) + ) + return 1; + + return 0; +} + +static SInt32 CInline_EstimateSizeOfExpr(ENode *expr, SInt32 size, SInt32 level) { + ENodeList *list; + + switch (expr->type) { + ENODE_CASE_MONADIC: + size = CInline_EstimateSizeOfExpr(expr->data.monadic, size, level) + 1; + break; + + ENODE_CASE_DIADIC_ALL: + size = CInline_EstimateSizeOfExpr(expr->data.diadic.left, size, level); + if (size <= inline_max_size) + size = CInline_EstimateSizeOfExpr(expr->data.diadic.right, size, level) + 1; + break; + + case EFUNCCALL: + case EFUNCCALLP: + if ( + ENODE_IS(expr->data.funccall.funcref, EOBJREF) && + expr->data.funccall.funcref->data.objref->u.func.u.ifuncdata && + CInline_CanExpand(expr->data.funccall.funcref) + ) + { + recursive_inline |= expr->data.funccall.funcref->data.objref == expanding_function; + if (level == 0) { + if (!recursive_inline) + size = inline_max_size + 1; + } else { + size = CInline_EstimateSizeOfFunc(expr->data.funccall.funcref->data.objref->u.func.u.ifuncdata, size, level - 1); + } + } else { + size++; + } + + for (list = expr->data.funccall.args; list; list = list->next) { + if (size > inline_max_size) + break; + + size = CInline_EstimateSizeOfExpr(list->node, size, level); + } + break; + + case ECOND: + size = CInline_EstimateSizeOfExpr(expr->data.cond.cond, size, level); + if (size <= inline_max_size) + size = CInline_EstimateSizeOfExpr(expr->data.cond.expr1, size, level) + 1; + if (size <= inline_max_size) + size = CInline_EstimateSizeOfExpr(expr->data.cond.expr2, size, level) + 1; + break; + + case ENULLCHECK: + size = CInline_EstimateSizeOfExpr(expr->data.nullcheck.nullcheckexpr, size, level); + if (size <= inline_max_size) + size = CInline_EstimateSizeOfExpr(expr->data.nullcheck.condexpr, size, level) + 1; + break; + + case EMFPOINTER: + size = CInline_EstimateSizeOfExpr(expr->data.mfpointer.accessnode, size, level); + if (size <= inline_max_size) + size = CInline_EstimateSizeOfExpr(expr->data.mfpointer.mfpointer, size, level) + 1; + break; + + case EMEMBER: + if (expr->data.emember->expr) + size = CInline_EstimateSizeOfExpr(expr->data.emember->expr, size, level) + 1; + break; + + default: + size++; + } + + return size; +} + +static SInt32 CInline_EstimateSizeOfFunc(CI_FuncData *funcdata, SInt32 size, SInt32 level) { + CI_Statement *stmt; + SInt32 i; + + size += funcdata->numstatements; + if (size > inline_max_size) + return size; + + for (i = 0, stmt = funcdata->statements; i < funcdata->numstatements; i++, stmt++) { + switch (stmt->type) { + case ST_NOP: + case ST_LABEL: + case ST_GOTO: + case ST_ASM: + break; + case ST_EXPRESSION: + case ST_IFGOTO: + case ST_IFNGOTO: + case ST_BEGINCATCH: + case ST_ENDCATCH: + case ST_ENDCATCHDTOR: + case ST_GOTOEXPR: + size = CInline_EstimateSizeOfExpr(stmt->u.expr, size, level); + break; + case ST_SWITCH: + size = CInline_EstimateSizeOfExpr(stmt->u.switchdata->expr, size, level); + break; + case ST_RETURN: + if (stmt->u.expr) + size = CInline_EstimateSizeOfExpr(stmt->u.expr, size, level); + break; + default: + CError_FATAL(1840); + } + + if (size > inline_max_size) + break; + } + + return size; +} + +static SInt32 EstimateExpandedSizeOfExpr(ENode *expr, SInt32 level) { + ENodeList *list; + SInt32 size; + + size = 0; + + switch (expr->type) { + ENODE_CASE_MONADIC: + size = EstimateExpandedSizeOfExpr(expr->data.monadic, level) + 1; + break; + + ENODE_CASE_DIADIC_ALL: + size = EstimateExpandedSizeOfExpr(expr->data.diadic.left, level) + 1; + size += EstimateExpandedSizeOfExpr(expr->data.diadic.right, level); + break; + + case EFUNCCALL: + case EFUNCCALLP: + if ( + ENODE_IS(expr->data.funccall.funcref, EOBJREF) && + expr->data.funccall.funcref->data.objref->u.func.u.ifuncdata && + CInline_CanExpand(expr->data.funccall.funcref) + ) + { + if (level) { + SInt32 est = CInline_EstimateSizeOfFunc(expr->data.funccall.funcref->data.objref->u.func.u.ifuncdata, size, level - 1); + if (est > inline_max_size) + size++; + else + size += est; + } else { + size++; + } + } else { + size++; + } + + for (list = expr->data.funccall.args; list; list = list->next) + size += EstimateExpandedSizeOfExpr(list->node, level); + break; + + case ECOND: + size = EstimateExpandedSizeOfExpr(expr->data.cond.cond, level) + 1; + size += EstimateExpandedSizeOfExpr(expr->data.cond.expr1, level); + size += EstimateExpandedSizeOfExpr(expr->data.cond.expr2, level); + break; + + case ENULLCHECK: + size = EstimateExpandedSizeOfExpr(expr->data.nullcheck.nullcheckexpr, level) + 1; + size += EstimateExpandedSizeOfExpr(expr->data.nullcheck.condexpr, level); + break; + + case EMFPOINTER: + size = EstimateExpandedSizeOfExpr(expr->data.mfpointer.accessnode, level) + 1; + size += EstimateExpandedSizeOfExpr(expr->data.mfpointer.mfpointer, level); + break; + + case EMEMBER: + if (expr->data.emember->expr) + size = EstimateExpandedSizeOfExpr(expr->data.emember->expr, level); + break; + + default: + size++; + } + + return size; +} + +static SInt32 EstimateExpandedSizeOfFunction(Statement *stmt) { + SInt32 size; + SInt32 level; + + level = copts.inlinelevel; + if (!level) + level = 8; + + size = 0; + + while (stmt) { + switch (stmt->type) { + case ST_NOP: + 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: + size++; + size += EstimateExpandedSizeOfExpr(stmt->expr, level); + break; + case ST_RETURN: + size++; + if (stmt->expr) + size = EstimateExpandedSizeOfExpr(stmt->expr, level); + break; + case ST_LABEL: + case ST_GOTO: + case ST_ASM: + size++; + break; + default: + CError_FATAL(2015); + } + + stmt = stmt->next; + } + + return size; +} + +static Boolean CInline_InlineFunctionCheck(ENode *expr) { + Object *object; + SInt32 level; + CI_FuncData *funcdata; + + object = expr->data.objref; + if (object->datatype == DALIAS) + object = object->u.alias.object; + + if ( + IS_TYPE_FUNC(object->type) && + ((object->qual & Q_INLINE) || (TYPE_FUNC(object->type)->flags & FUNC_FLAGS_800)) && + (object->datatype == DFUNC || (object->datatype == DVFUNC && (expr->flags & ENODE_FLAG_80))) + ) + { + if (copts.alwaysinline) + return 1; + + if (copts.inline_bottom_up) { + if (!object->u.func.u.ifuncdata) + return 0; + + level = (copts.inlinelevel == 0) ? (7 - cinline_level) : (copts.inlinelevel - cinline_level - 1); + if ((object->qual & Q_INLINE) && level == 0) + return 1; + + if (CInline_EstimateSizeOfFunc(object->u.func.u.ifuncdata, 0, level) > inline_max_size) + return 0; + } else if (cinline_level > 0 && copts.inlinelevel == 0) { + funcdata = object->u.func.u.ifuncdata; + if (!funcdata) + return 0; + + if (funcdata->numstatements > 10) + return 0; + if (cinline_level > 1 && funcdata->numstatements > 7) + return 0; + if (cinline_level > 2 && funcdata->numstatements > 3) + return 0; + } + + return 1; + } else { + return 0; + } + + return 0; +} + +static ENode *CInline_ExpandExpression(ENode *expr) { + ENodeList *list; + Boolean save; + + switch (expr->type) { + case EPOSTINC: + case EPOSTDEC: + case EPREINC: + case EPREDEC: + case EINDIRECT: + case EMONMIN: + case EBINNOT: + case ELOGNOT: + case ETYPCON: + case EBITFIELD: + expr->data.monadic = CInline_ExpandExpression(expr->data.monadic); + break; + + case EFORCELOAD: + expr->data.monadic = CInline_ExpandExpression(expr->data.monadic); + if (ENODE_IS(expr->data.monadic, EFORCELOAD)) + expr->data.monadic = expr->data.monadic->data.monadic; + break; + + 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 EPMODULO: + case EROTL: + case EROTR: + expr->data.diadic.left = CInline_ExpandExpression(expr->data.diadic.left); + expr->data.diadic.right = CInline_ExpandExpression(expr->data.diadic.right); + break; + + case ELAND: + case ELOR: + case ECOMMA: + expr->data.diadic.left = CInline_ExpandExpression(expr->data.diadic.left); + save = cinline_unconditionalpart; + cinline_unconditionalpart = 0; + expr->data.diadic.right = CInline_ExpandExpression(expr->data.diadic.right); + cinline_unconditionalpart = save; + break; + + case EFUNCCALL: + case EFUNCCALLP: + expr->data.funccall.funcref = CInline_ExpandExpression(expr->data.funccall.funcref); + for (list = expr->data.funccall.args; list; list = list->next) + list->node = CInline_ExpandExpression(list->node); + + if (ENODE_IS(expr->data.funccall.funcref, EOBJREF) && CInline_InlineFunctionCheck(expr->data.funccall.funcref)) + expr = CInline_InlineFunctionExpression(expr); + break; + + case ENULLCHECK: + expr->data.nullcheck.nullcheckexpr = CInline_ExpandExpression(expr->data.nullcheck.nullcheckexpr); + save = cinline_unconditionalpart; + cinline_unconditionalpart = 0; + expr->data.nullcheck.condexpr = CInline_ExpandExpression(expr->data.nullcheck.condexpr); + cinline_unconditionalpart = save; + break; + + case EMFPOINTER: + expr->data.mfpointer.accessnode = CInline_ExpandExpression(expr->data.mfpointer.accessnode); + expr->data.mfpointer.mfpointer = CInline_ExpandExpression(expr->data.mfpointer.mfpointer); + break; + + case ECOND: + expr->data.cond.cond = CInline_ExpandExpression(expr->data.cond.cond); + save = cinline_unconditionalpart; + cinline_unconditionalpart = 0; + expr->data.cond.expr1 = CInline_ExpandExpression(expr->data.cond.expr1); + expr->data.cond.expr2 = CInline_ExpandExpression(expr->data.cond.expr2); + cinline_unconditionalpart = save; + break; + + case EMEMBER: + if (expr->data.emember->expr) + expr = CInline_ExpandExpression(expr->data.emember->expr); + else + expr = nullnode(); + break; + + case EINTCONST: + case EFLOATCONST: + case ESTRINGCONST: + case EOBJREF: + case EPRECOMP: + case ELABEL: + case EOBJLIST: + case EINSTRUCTION: + case EVECTOR128CONST: + break; + + default: + CError_FATAL(2235); + } + + return expr; +} + +static Statement *CInline_NewStatement(StatementType sttype) { + Statement *stmt = lalloc(sizeof(Statement)); + memclrw(stmt, sizeof(Statement)); + + stmt->type = sttype; + if (cinline_serial_stmt) + cinline_cur_serial_stmt->next = stmt; + else + cinline_serial_stmt = stmt; + cinline_cur_serial_stmt = stmt; + + return stmt; +} + +static ENode *CInline_LoadToTemp(ENode *expr, Object **objectptr) { + Object *object; + + object = *objectptr; + if (!object) { + switch (expr->rtype->type) { + case TYPEVOID: + return expr; + case TYPEINT: + case TYPEFLOAT: + case TYPEENUM: + case TYPESTRUCT: + case TYPECLASS: + case TYPEMEMBERPOINTER: + case TYPEPOINTER: + object = create_temp_object(expr->rtype); + *objectptr = object; + break; + default: + CError_FATAL(2288); + } + } + + return makediadicnode(create_objectnode(object), expr, EASS); +} + +static ENode *CInline_SerializeEFORCELOAD(ENode *expr) { + Statement *stmt; + Object *temp = NULL; + + while (ENODE_IS(expr->data.monadic, EFORCELOAD)) { + expr->data.monadic = expr->data.monadic->data.monadic; + } + + expr->data.monadic = CInline_SerializeExpr(expr->data.monadic); + stmt = CInline_NewStatement(ST_EXPRESSION); + stmt->expr = CInline_LoadToTemp(expr->data.monadic, &temp); + return create_objectnode(temp); +} + +static ENode *CInline_SerializeECOMMA(ENode *expr) { + Statement *stmt; + + expr->data.diadic.left = CInline_SerializeExpr(expr->data.diadic.left); + stmt = CInline_NewStatement(ST_EXPRESSION); + stmt->expr = expr->data.diadic.left; + return CInline_SerializeExpr(expr->data.diadic.right); +} + +static ENode *CInline_SerializeELOR(ENode *expr) { + ENode *n; + Statement *stmt; + CLabel *label; + Object *temp = NULL; + + label = newlabel(); + + n = makemonadicnode(CInline_SerializeExpr(expr->data.diadic.left), ELOGNOT); + n->rtype = expr->rtype; + n = makemonadicnode(n, ELOGNOT); + n = CInline_LoadToTemp(n, &temp); + stmt = CInline_NewStatement(ST_IFGOTO); + stmt->expr = n; + stmt->label = label; + + n = makemonadicnode(CInline_SerializeExpr(expr->data.diadic.right), ELOGNOT); + n->rtype = expr->rtype; + n = makemonadicnode(n, ELOGNOT); + n = CInline_LoadToTemp(n, &temp); + stmt = CInline_NewStatement(ST_EXPRESSION); + stmt->expr = n; + + stmt = CInline_NewStatement(ST_LABEL); + stmt->label = label; + label->stmt = stmt; + + return create_objectnode(temp); +} + +static ENode *CInline_SerializeELAND(ENode *expr) { + ENode *n; + Statement *stmt; + CLabel *label; + Object *temp = NULL; + + label = newlabel(); + + n = makemonadicnode(CInline_SerializeExpr(expr->data.diadic.left), ELOGNOT); + n->rtype = expr->rtype; + n = makemonadicnode(n, ELOGNOT); + n = CInline_LoadToTemp(n, &temp); + stmt = CInline_NewStatement(ST_IFNGOTO); + stmt->expr = n; + stmt->label = label; + + n = makemonadicnode(CInline_SerializeExpr(expr->data.diadic.right), ELOGNOT); + n->rtype = expr->rtype; + n = makemonadicnode(n, ELOGNOT); + n = CInline_LoadToTemp(n, &temp); + stmt = CInline_NewStatement(ST_EXPRESSION); + stmt->expr = n; + + stmt = CInline_NewStatement(ST_LABEL); + stmt->label = label; + label->stmt = stmt; + + return create_objectnode(temp); +} + +static ENode *CInline_SerializeEPRECOMP(ENode *expr) { + UIDTemp *uidtemp; + + uidtemp = cinline_uid_temps; + while (1) { + if (!uidtemp) + CError_FATAL(2449); + if (uidtemp->uid == expr->data.precompid) + return create_objectnode(uidtemp->object); + uidtemp = uidtemp->next; + } +} + +static ENode *CInline_SerializeENULLCHECK(ENode *expr) { + Statement *stmt; + CLabel *label; + ENode *n; + Object *temp = NULL; + UIDTemp uidtemp; + + label = newlabel(); + + n = CInline_SerializeExpr(expr->data.nullcheck.nullcheckexpr); + stmt = CInline_NewStatement(ST_IFNGOTO); + stmt->expr = CInline_LoadToTemp(n, &temp); + stmt->label = label; + + uidtemp.next = cinline_uid_temps; + uidtemp.object = temp; + uidtemp.uid = expr->data.nullcheck.precompid; + cinline_uid_temps = &uidtemp; + + n = CInline_SerializeExpr(expr->data.nullcheck.condexpr); + stmt = CInline_NewStatement(ST_EXPRESSION); + stmt->expr = CInline_LoadToTemp(n, &temp); + + cinline_uid_temps = uidtemp.next; + + stmt = CInline_NewStatement(ST_LABEL); + stmt->label = label; + label->stmt = stmt; + + return create_objectnode(temp); +} + +static ENode *CInline_SerializeECOND(ENode *expr) { + Statement *stmt; + CLabel *label1; + CLabel *label2; + ENode *n; + Object *temp = NULL; + + label1 = newlabel(); + label2 = newlabel(); + + n = CInline_SerializeExpr(expr->data.cond.cond); + stmt = CInline_NewStatement(ST_IFNGOTO); + stmt->expr = n; + stmt->label = label1; + + n = CInline_SerializeExpr(expr->data.cond.expr1); + n = CInline_LoadToTemp(n, &temp); + stmt = CInline_NewStatement(ST_EXPRESSION); + stmt->expr = n; + + stmt = CInline_NewStatement(ST_GOTO); + stmt->label = label2; + + stmt = CInline_NewStatement(ST_LABEL); + stmt->label = label1; + label1->stmt = stmt; + + n = CInline_SerializeExpr(expr->data.cond.expr2); + n = CInline_LoadToTemp(n, &temp); + stmt = CInline_NewStatement(ST_EXPRESSION); + stmt->expr = n; + + stmt = CInline_NewStatement(ST_LABEL); + stmt->label = label2; + label2->stmt = stmt; + + if (!temp) { + n = nullnode(); + n->rtype = &stvoid; + return n; + } + + return create_objectnode(temp); +} + +static ENode *CInline_SerializeExpr(ENode *expr) { + ENodeList *list; + + switch (expr->type) { + case EFORCELOAD: + return CInline_SerializeEFORCELOAD(expr); + case ECOMMA: + return CInline_SerializeECOMMA(expr); + case ELAND: + return CInline_SerializeELAND(expr); + case ELOR: + return CInline_SerializeELOR(expr); + case EPRECOMP: + return CInline_SerializeEPRECOMP(expr); + case ENULLCHECK: + return CInline_SerializeENULLCHECK(expr); + case ECOND: + return CInline_SerializeECOND(expr); + + case EINITTRYCATCH: + expr->data.itc.initexpr = CInline_SerializeExpr(expr->data.itc.initexpr); + expr->data.itc.tryexpr = CInline_SerializeExpr(expr->data.itc.tryexpr); + expr->data.itc.catchexpr = CInline_SerializeExpr(expr->data.itc.catchexpr); + expr->data.itc.result = CInline_SerializeExpr(expr->data.itc.result); + 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 = CInline_SerializeExpr(expr->data.monadic); + return expr; + + 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 EPMODULO: + case EROTL: + case EROTR: + expr->data.diadic.left = CInline_SerializeExpr(expr->data.diadic.left); + expr->data.diadic.right = CInline_SerializeExpr(expr->data.diadic.right); + return expr; + + case EINTCONST: + case EFLOATCONST: + case ESTRINGCONST: + case EOBJREF: + case ELABEL: + case EOBJLIST: + case EINSTRUCTION: + case EVECTOR128CONST: + return expr; + + case EFUNCCALL: + case EFUNCCALLP: + expr->data.funccall.funcref = CInline_SerializeExpr(expr->data.funccall.funcref); + for (list = expr->data.funccall.args; list; list = list->next) + list->node = CInline_SerializeExpr(list->node); + return expr; + + case EMFPOINTER: + // bug??? + expr->data.mfpointer.accessnode = CInline_SerializeExpr(expr->data.mfpointer.accessnode); + expr->data.mfpointer.accessnode = CInline_SerializeExpr(expr->data.mfpointer.mfpointer); + return expr; + + case EMEMBER: + if (expr->data.emember->expr) + return CInline_SerializeExpr(expr->data.emember->expr); + return expr; + + default: + CError_FATAL(2684); + return expr; + } +} + +void CInline_SerializeStatement(Statement *stmt) { + Statement *scan; + Statement *copy; + + cinline_serial_stmt = NULL; + cinline_uid_temps = NULL; + stmt->expr = CInline_SerializeExpr(stmt->expr); + + if (cinline_serial_stmt) { + for (scan = cinline_serial_stmt; scan; scan = scan->next) { + scan->value = stmt->value; + scan->dobjstack = stmt->dobjstack; + scan->sourceoffset = stmt->sourceoffset; + scan->sourcefilepath = stmt->sourcefilepath; + } + + copy = CInline_NewStatement(ST_EXPRESSION); + *copy = *stmt; + + *stmt = *cinline_serial_stmt; + } +} + +static void CInline_UnpackSwitch(Statement *stmt, CI_Statement *packstmt, CLabel **labels) { + SwitchInfo *info; + SwitchCase *swcase; + short i; + + info = lalloc(sizeof(SwitchInfo)); + stmt->label = (CLabel *) info; + CError_ASSERT(2730, info->defaultlabel = labels[packstmt->u.switchdata->defaultlabelID]); + info->x8 = packstmt->u.switchdata->unkSwitch8; + + for (i = 0; i < packstmt->u.switchdata->numcases; i++) { + if (i == 0) { + swcase = lalloc(sizeof(SwitchCase)); + info->cases = swcase; + } else { + swcase->next = lalloc(sizeof(SwitchCase)); + swcase = swcase->next; + } + + swcase->next = NULL; + swcase->min = packstmt->u.switchdata->cases[i].min; + swcase->max = packstmt->u.switchdata->cases[i].max; + CError_ASSERT(2740, swcase->label = labels[packstmt->u.switchdata->cases[i].labelID]); + } +} + +Object *CInline_GetLocalObj(SInt32 id, Boolean flag) { + ObjectList *list; + + if (id) { + if (id & 0x80000000) { + id = (id & 0x7FFFFFFF) - 1; + if (flag) { + CError_ASSERT(2761, local_aobjects[id].object); + return local_aobjects[id].object; + } + + for (list = arguments; list; list = list->next, id--) { + if (id == 0) + return list->object; + } + + CError_FATAL(2765); + } else { + id--; + if (flag) { + CError_ASSERT(2772, local_dobjects[id]); + return local_dobjects[id]; + } + + for (list = locals; list; list = list->next, id--) { + if (id == 0) + return list->object; + } + + CError_FATAL(2776); + } + } + + return NULL; +} + +static ExceptionAction *CInline_UnpackActions(CI_Statement *packstmt, Boolean flag) { + ExceptionAction *packexc; + ExceptionAction *last; + ExceptionAction *exc; + + packexc = packstmt->dobjstack; + last = NULL; + + while (packexc) { + exc = galloc(sizeof(ExceptionAction)); + exc->prev = last; + last = exc; + + exc->type = packexc->type; + + switch (packexc->type) { + case EAT_DESTROYLOCAL: + exc->data.destroy_local.local = CInline_GetLocalObj((SInt32) packexc->data.destroy_local.local, flag); + exc->data.destroy_local.dtor = packexc->data.destroy_local.dtor; + break; + case EAT_DESTROYLOCALCOND: + exc->data.destroy_local_cond.local = CInline_GetLocalObj((SInt32) packexc->data.destroy_local_cond.local, flag); + exc->data.destroy_local_cond.dtor = packexc->data.destroy_local_cond.dtor; + exc->data.destroy_local_cond.cond = CInline_GetLocalObj((SInt32) packexc->data.destroy_local_cond.cond, flag); + break; + case EAT_DESTROYLOCALOFFSET: + exc->data.destroy_local_offset.local = CInline_GetLocalObj((SInt32) packexc->data.destroy_local_offset.local, flag); + exc->data.destroy_local_offset.dtor = packexc->data.destroy_local_offset.dtor; + exc->data.destroy_local_offset.offset = packexc->data.destroy_local_offset.offset; + break; + case EAT_DESTROYLOCALPOINTER: + exc->data.destroy_local_pointer.pointer = CInline_GetLocalObj((SInt32) packexc->data.destroy_local_pointer.pointer, flag); + exc->data.destroy_local_pointer.dtor = packexc->data.destroy_local_pointer.dtor; + break; + case EAT_DESTROYLOCALARRAY: + exc->data.destroy_local_array.localarray = CInline_GetLocalObj((SInt32) packexc->data.destroy_local_array.localarray, flag); + exc->data.destroy_local_array.dtor = packexc->data.destroy_local_array.dtor; + exc->data.destroy_local_array.elements = packexc->data.destroy_local_array.elements; + exc->data.destroy_local_array.element_size = packexc->data.destroy_local_array.element_size; + break; + case EAT_DESTROYPARTIALARRAY: + exc->data.destroy_partial_array.arraypointer = CInline_GetLocalObj((SInt32) packexc->data.destroy_partial_array.arraypointer, flag); + exc->data.destroy_partial_array.arraycounter = CInline_GetLocalObj((SInt32) packexc->data.destroy_partial_array.arraycounter, flag); + exc->data.destroy_partial_array.dtor = CInline_GetLocalObj((SInt32) packexc->data.destroy_partial_array.dtor, flag); + exc->data.destroy_partial_array.element_size = CInline_GetLocalObj((SInt32) packexc->data.destroy_partial_array.element_size, flag); + break; + case EAT_DESTROYMEMBER: + case EAT_DESTROYBASE: + exc->data.destroy_member.objectptr = CInline_GetLocalObj((SInt32) packexc->data.destroy_member.objectptr, flag); + exc->data.destroy_member.dtor = packexc->data.destroy_member.dtor; + exc->data.destroy_member.offset = packexc->data.destroy_member.offset; + break; + case EAT_DESTROYMEMBERCOND: + exc->data.destroy_member_cond.objectptr = CInline_GetLocalObj((SInt32) packexc->data.destroy_member_cond.objectptr, flag); + exc->data.destroy_member_cond.cond = CInline_GetLocalObj((SInt32) packexc->data.destroy_member_cond.cond, flag); + exc->data.destroy_member_cond.dtor = packexc->data.destroy_member_cond.dtor; + exc->data.destroy_member_cond.offset = packexc->data.destroy_member_cond.offset; + break; + case EAT_DESTROYMEMBERARRAY: + exc->data.destroy_member_array.objectptr = CInline_GetLocalObj((SInt32) packexc->data.destroy_member_array.objectptr, flag); + exc->data.destroy_member_array.dtor = packexc->data.destroy_member_array.dtor; + exc->data.destroy_member_array.offset = packexc->data.destroy_member_array.offset; + exc->data.destroy_member_array.elements = packexc->data.destroy_member_array.elements; + exc->data.destroy_member_array.element_size = packexc->data.destroy_member_array.element_size; + break; + case EAT_DELETEPOINTER: + case EAT_DELETELOCALPOINTER: + exc->data.delete_pointer.pointerobject = CInline_GetLocalObj((SInt32) packexc->data.delete_pointer.pointerobject, flag); + exc->data.delete_pointer.deletefunc = packexc->data.delete_pointer.deletefunc; + break; + case EAT_DELETEPOINTERCOND: + exc->data.delete_pointer_cond.pointerobject = CInline_GetLocalObj((SInt32) packexc->data.delete_pointer_cond.pointerobject, flag); + exc->data.delete_pointer_cond.deletefunc = packexc->data.delete_pointer_cond.deletefunc; + exc->data.delete_pointer_cond.cond = CInline_GetLocalObj((SInt32) packexc->data.delete_pointer_cond.cond, flag); + break; + case EAT_CATCHBLOCK: { + LabelTrans *trans; + exc->data.catch_block.catch_object = CInline_GetLocalObj((SInt32) packexc->data.catch_block.catch_object, flag); + exc->data.catch_block.catch_info_object = CInline_GetLocalObj((SInt32) packexc->data.catch_block.catch_info_object, flag); + + trans = lalloc(sizeof(LabelTrans)); + trans->next = cinline_label_trans; + cinline_label_trans = trans; + + trans->id = (SInt32) packexc->data.catch_block.catch_label; + trans->labelptr = &exc->data.catch_block.catch_label; + + exc->data.catch_block.catch_typeid = packexc->data.catch_block.catch_typeid; + exc->data.catch_block.catch_type = packexc->data.catch_block.catch_type; + exc->data.catch_block.catch_qual = packexc->data.catch_block.catch_qual; + break; + } + case EAT_ACTIVECATCHBLOCK: + exc->data.active_catch_block.catch_info_object = CInline_GetLocalObj((SInt32) packexc->data.active_catch_block.catch_info_object, flag); + break; + case EAT_SPECIFICATION: { + LabelTrans *trans; + exc->data.specification.unexp_ids = packexc->data.specification.unexp_ids; + exc->data.specification.unexp_id = packexc->data.specification.unexp_id; + + trans = lalloc(sizeof(LabelTrans)); + trans->next = cinline_label_trans; + cinline_label_trans = trans; + + trans->id = (SInt32) packexc->data.specification.unexp_label; + trans->labelptr = &exc->data.specification.unexp_label; + + exc->data.specification.unexp_info_object = CInline_GetLocalObj((SInt32) packexc->data.specification.unexp_info_object, flag); + break; + } + case EAT_TERMINATE: + break; + default: + CError_FATAL(2904); + } + + packexc = packexc->prev; + } + + return last; +} + +static Statement *CInline_ExpandStatements(Object *funcobj, Statement *stmt, CI_FuncData *funcdata, ENode *funccall, CLabel *label, Object *resultobj, Boolean flag) { + CLabel **labels; + CI_Statement *packstmt; + short i; + CI_StmtLink *stmtLinks; + CI_StmtLink *link; + ENode *setupArgs; + Boolean is_result_class_1; + Statement origStmt; + + origStmt = *stmt; + is_result_class_1 = CMach_GetFunctionResultClass(TYPE_FUNC(funcobj->type)) == 1; + + if ((setupArgs = CInline_SetupArgsExpression(funcobj, funcdata, funccall->data.funccall.args))) { + stmt->type = ST_EXPRESSION; + stmt->expr = CInline_FoldConst(setupArgs); + } else { + stmt->type = ST_NOP; + } + + stmtLinks = NULL; + cinline_label_trans = NULL; + + labels = lalloc(sizeof(CLabel *) * funcdata->numstatements); + memclrw(labels, sizeof(CLabel *) * funcdata->numstatements); + + for (i = 0, packstmt = funcdata->statements; i < funcdata->numstatements; i++, packstmt++) { + stmt->next = lalloc(sizeof(Statement)); + stmt = stmt->next; + *stmt = origStmt; + + stmt->type = packstmt->type; + stmt->flags = packstmt->flags; + stmt->value += packstmt->value; + + if (packstmt->dobjstack) { + ExceptionAction *unpacked = CInline_UnpackActions(packstmt, 1); + if (stmt->dobjstack) { + ExceptionAction *scan = unpacked; + while (scan->prev) + scan = scan->prev; + scan->prev = stmt->dobjstack; + } + stmt->dobjstack = unpacked; + } + + switch (stmt->type) { + case ST_NOP: + break; + + case ST_EXPRESSION: + case ST_BEGINCATCH: + case ST_ENDCATCH: + case ST_ENDCATCHDTOR: + case ST_GOTOEXPR: + stmt->expr = CInline_FoldConst(CInline_CopyExpression(packstmt->u.expr, CopyMode4)); + break; + + case ST_RETURN: + if (packstmt->u.expr) { + stmt->expr = CInline_FoldConst(CInline_CopyExpression(packstmt->u.expr, CopyMode4)); + if (is_result_class_1) + stmt->expr = makecommaexpression(stmt->expr, CInline_ReturnMemResult(funcobj)); + + if (resultobj) { + stmt->type = ST_EXPRESSION; + stmt->expr = makediadicnode(create_objectnode2(resultobj), stmt->expr, EASS); + } else { + stmt->type = origStmt.type; + if (stmt->type == ST_EXPRESSION && !CInline_ExpressionHasSideEffect(stmt->expr)) + stmt->type = ST_NOP; + } + + if (label) { + stmt->next = lalloc(sizeof(Statement)); + stmt = stmt->next; + *stmt = origStmt; + stmt->type = ST_GOTO; + stmt->label = label; + } + } else { + if (label) { + stmt->type = ST_GOTO; + stmt->label = label; + } else { + stmt->type = ST_NOP; + } + } + break; + + case ST_LABEL: + labels[i] = stmt->label = newlabel(); + stmt->label->stmt = stmt; + break; + + case ST_IFGOTO: + case ST_IFNGOTO: + stmt->expr = CInline_FoldConst(CInline_CopyExpression(packstmt->u.ifgoto.expr, CopyMode4)); + case ST_GOTO: + link = lalloc(sizeof(CI_StmtLink)); + link->next = stmtLinks; + stmtLinks = link; + + link->stmt = stmt; + link->ciStmt = packstmt; + break; + + case ST_SWITCH: + stmt->expr = CInline_FoldConst(CInline_CopyExpression(packstmt->u.switchdata->expr, CopyMode4)); + case ST_ASM: + link = lalloc(sizeof(CI_StmtLink)); + link->next = stmtLinks; + stmtLinks = link; + + link->stmt = stmt; + link->ciStmt = packstmt; + break; + + default: + CError_FATAL(3040); + } + } + + if (label) { + stmt->next = lalloc(sizeof(Statement)); + stmt = stmt->next; + *stmt = origStmt; + + stmt->type = ST_LABEL; + stmt->label = label; + label->stmt = stmt; + + if (flag) { + stmt->next = lalloc(sizeof(Statement)); + stmt = stmt->next; + *stmt = origStmt; + } + } + + while (stmtLinks) { + Statement *linkstmt = stmtLinks->stmt; + packstmt = stmtLinks->ciStmt; + + switch (linkstmt->type) { + case ST_GOTO: + CError_ASSERT(3060, linkstmt->label = labels[packstmt->u.statementnum]); + break; + case ST_IFGOTO: + case ST_IFNGOTO: + CError_ASSERT(3065, linkstmt->label = labels[packstmt->u.ifgoto.statementnum]); + break; + case ST_SWITCH: + CInline_UnpackSwitch(linkstmt, packstmt, labels); + break; + case ST_ASM: + InlineAsm_UnpackAsmStatement(linkstmt, labels, 1, packstmt->u.asmdata.data, packstmt->u.asmdata.size); + break; + default: + CError_FATAL(3076); + } + + stmtLinks = stmtLinks->next; + } + + while (cinline_label_trans) { + CError_ASSERT(3083, *cinline_label_trans->labelptr = labels[cinline_label_trans->id]); + cinline_label_trans = cinline_label_trans->next; + } + + return stmt; +} + +static Statement *CInline_InlineFunctionStatement(Statement *stmt, Boolean *changed) { + Object *object; + CI_FuncData *funcdata; + CLabel *label; + + *changed = 0; + + object = stmt->expr->data.funccall.funcref->data.objref; + if (object->datatype == DALIAS) + object = object->u.alias.object; + + funcdata = object->u.func.u.ifuncdata; + if (!funcdata || funcdata->can_inline < CI_CanInline3) + return stmt; + + if (stmt->type != ST_EXPRESSION) { + short i; + for (i = 0; i < (funcdata->numstatements - 1); i++) { + if (funcdata->statements[i].type == ST_RETURN) + return stmt; + } + + if (funcdata->statements[funcdata->numstatements - 1].type != ST_RETURN) + return stmt; + + label = NULL; + } else { + label = newlabel(); + } + + *changed = 1; + return CInline_ExpandStatements(object, stmt, funcdata, stmt->expr, label, NULL, 0); +} + +static Statement *CInline_ExtractInlineFunction(Statement *stmt) { + ENode *expr; + CI_FuncData *funcdata; + short i; + Object *funcObject; + Object *resultObject; + + for (i = 0; i < cinline_stmtlevelexprs; i++) { + expr = cinline_stmtlevelexpr[i]; + + funcObject = expr->data.funccall.funcref->data.objref; + if (funcObject->datatype == DALIAS) + funcObject = funcObject->u.alias.object; + + if ((funcdata = funcObject->u.func.u.ifuncdata)) { + TypeFunc *tfunc = TYPE_FUNC(funcObject->type); + CError_ASSERT(3141, IS_TYPE_FUNC(tfunc)); + + if (!IS_TYPE_VOID(tfunc->functype)) { + if (CMach_GetFunctionResultClass(TYPE_FUNC(funcObject->type)) == 1) + resultObject = CInline_NewLocalObject(CDecl_NewPointerType(tfunc->functype), 0, 0, 0); + else + resultObject = CInline_NewLocalObject(tfunc->functype, 0, 0, 0); + } else { + resultObject = NULL; + } + + stmt = CInline_ExpandStatements(funcObject, stmt, funcdata, expr, newlabel(), resultObject, 1); + + if (resultObject) + *expr = *create_objectnode2(resultObject); + else + *expr = *nullnode(); + } + } + + return stmt; +} + +static Statement *CInline_ExpandStatement(Statement *stmt) { + Boolean changed; + + do { + changed = 0; + + if ( + stmt->type == ST_EXPRESSION && + ENODE_IS(stmt->expr, EINDIRECT) && + !CParser_IsVolatile(stmt->expr->rtype, ENODE_QUALS(stmt->expr)) + ) + { + stmt->expr = stmt->expr->data.monadic; + changed = 1; + if (ENODE_IS2(stmt->expr, EOBJREF, EBITFIELD)) + stmt->expr = nullnode(); + } + + if (ENODE_IS(stmt->expr, ECOMMA)) { + Statement *newStmt = lalloc(sizeof(Statement)); + *newStmt = *stmt; + + stmt->next = newStmt; + stmt->type = ST_EXPRESSION; + stmt->expr = stmt->expr->data.diadic.left; + newStmt->expr = newStmt->expr->data.diadic.right; + + changed = 1; + } + } while (changed); + + if ( + ENODE_IS2(stmt->expr, EFUNCCALL, EFUNCCALLP) && + ENODE_IS(stmt->expr->data.funccall.funcref, EOBJREF) && + CInline_InlineFunctionCheck(stmt->expr->data.funccall.funcref) + ) + { + stmt = CInline_InlineFunctionStatement(stmt, &changed); + if (changed) { + any_inline_expanded = 1; + return stmt; + } + } + + inline_expanded = 0; + cinline_unconditionalpart = 1; + cinline_serialize_stmt = 0; + cinline_stmtlevelexprs = 0; + stmt->expr = CInline_ExpandExpression(stmt->expr); + + if (cinline_serialize_stmt) { + cinline_unconditionalpart = 1; + cinline_serialize_stmt = 0; + cinline_stmtlevelexprs = 0; + CInline_SerializeStatement(stmt); + stmt->expr = CInline_ExpandExpression(stmt->expr); + } + + if (inline_expanded) { + stmt->expr = CInline_FoldConst(stmt->expr); + any_inline_expanded = 1; + } + + if (cinline_stmtlevelexprs) { + stmt = CInline_ExtractInlineFunction(stmt); + any_inline_expanded = 1; + } + + return stmt; +} + +static void CInline_ForceReverseSearch(ENode *) { + cinline_funccallfound = 1; +} + +static ENode *CInline_ForceReverseEvaluation(ENode *expr) { + ENode *commanodes; + ENodeList *list; + int counter; + ENode *ass; + ENode *inner; + ENode *copy; + + list = expr->data.funccall.args; + counter = 0; + commanodes = NULL; + + while (list) { + cinline_funccallfound = 0; + inner = list->node; + CExpr_SearchExprTree(inner, CInline_ForceReverseSearch, 2, EFUNCCALL, EFUNCCALLP); + + if (cinline_funccallfound && ++counter > 0) { + inner = create_objectrefnode(create_temp_object(inner->rtype)); + copy = lalloc(sizeof(ENode)); + *copy = *inner; + + copy = makemonadicnode(copy, EINDIRECT); + copy->rtype = TPTR_TARGET(copy->rtype); + + inner = makemonadicnode(inner, EINDIRECT); + inner->rtype = TPTR_TARGET(inner->rtype); + + ass = makediadicnode(inner, copy, EASS); + list->node = copy; + + if (commanodes) + commanodes = makediadicnode(ass, commanodes, ECOMMA); + else + commanodes = ass; + } + + list = list->next; + } + + if (commanodes) { + commanodes = makediadicnode(commanodes, expr, ECOMMA); + commanodes->rtype = expr->rtype; + return commanodes; + } + + return expr; +} + +static void CInline_ExportCheck(ENode *expr) { + while (1) { + switch (expr->type) { + case EOBJREF: + CInline_ObjectAddrRef(expr->data.objref); + if (expr->data.objref->datatype == DALIAS) { + CExpr_AliasTransform(expr); + continue; + } + return; + + ENODE_CASE_MONADIC: + expr = expr->data.monadic; + continue; + + ENODE_CASE_DIADIC_ALL: + CInline_ExportCheck(expr->data.diadic.left); + expr = expr->data.diadic.right; + continue; + + case EINTCONST: + case EFLOATCONST: + case ESTRINGCONST: + case EPRECOMP: + case EINSTRUCTION: + case EVECTOR128CONST: + return; + + case ELABEL: + if (expr->data.label->stmt) + expr->data.label->stmt->flags |= StmtFlag_1; + return; + + case EFUNCCALL: + case EFUNCCALLP: { + ENodeList *list; + TypeClass *tclass; + SInt32 index; + + for (list = expr->data.funccall.args; list; list = list->next) + CInline_ExportCheck(list->node); + + expr = expr->data.funccall.funcref; + if ( + copts.warn_notinlined && + !copts.dontinline && + ENODE_IS(expr, EOBJREF) && + (expr->data.objref->qual & Q_INLINE) && + expr->data.objref->datatype != DINLINEFUNC && + !CParser_IsVirtualFunction(expr->data.objref, &tclass, &index) + ) + CError_Warning(CErrorStr342, expr->data.objref); + + continue; + } + + case ENULLCHECK: + CInline_ExportCheck(expr->data.nullcheck.nullcheckexpr); + expr = expr->data.nullcheck.condexpr; + continue; + + case EMFPOINTER: + *expr = *nullnode(); + continue; + + case ECOND: + CInline_ExportCheck(expr->data.cond.cond); + CInline_ExportCheck(expr->data.cond.expr1); + expr = expr->data.cond.expr2; + continue; + + case EMEMBER: + if (expr->data.emember->expr) { + *expr = *expr->data.emember->expr; + continue; + } + case EOBJLIST: + *expr = *nullnode(); + continue; + + default: + CError_FATAL(3372); + } + } +} + +static void CInline_Expand(Statement *stmt) { + Statement *scan; + + if (!copts.dontinline && copts.inlinelevel >= 0) { + if (copts.inline_bottom_up) { + inline_max_size = copts.inlinemaxsize; + while (inline_max_size > 1 && EstimateExpandedSizeOfFunction(stmt) > copts.inlinemaxtotalsize) + inline_max_size >>= 1; + } + + cinline_level = 0; + while (1) { + any_inline_expanded = 0; + for (scan = stmt; scan; scan = scan->next) { + switch (scan->type) { + case ST_NOP: + case ST_LABEL: + case ST_GOTO: + case ST_BEGINCATCH: + case ST_ENDCATCH: + case ST_ENDCATCHDTOR: + case ST_ASM: + break; + case ST_RETURN: + if (!scan->expr) + break; + case ST_EXPRESSION: + case ST_SWITCH: + case ST_IFGOTO: + case ST_IFNGOTO: + case ST_GOTOEXPR: + scan = CInline_ExpandStatement(scan); + break; + default: + CError_FATAL(3438); + } + } + + if (!copts.inline_bottom_up && !any_inline_expanded) + break; + + if (!copts.alwaysinline || copts.inline_bottom_up) { + if (copts.inlinelevel == 0) { + if (copts.inline_bottom_up) { + if ((cinline_level + 1) >= 8) + break; + } else { + if (cinline_level >= 3) + break; + } + } else { + if ((cinline_level + 1) >= copts.inlinelevel) + break; + } + } + + if (CWDisplayLines(cparamblkptr->context, lines) != cwNoErr) + CError_UserBreak(); + + cinline_level++; + } + } + + while (stmt) { + if (stmt->dobjstack) + CExcept_CheckStackRefs(stmt->dobjstack); + + switch (stmt->type) { + case ST_NOP: + case ST_LABEL: + case ST_GOTO: + case ST_BEGINCATCH: + case ST_ENDCATCH: + case ST_ENDCATCHDTOR: + 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_GOTOEXPR: + CInline_ExportCheck(stmt->expr); + break; + default: + CError_FATAL(3501); + } + + stmt = stmt->next; + } +} + +SInt16 CInline_GetStatementNumber(Statement *first, Statement *stmt) { + SInt16 number = 0; + + while (first) { + if (first == stmt) + return number; + + first = first->next; + number++; + } + + CError_FATAL(3517); + return 0; +} + +static CI_Switch *CInline_PackSwitch(Statement *start, Statement *stmt) { + SwitchInfo *info; + SwitchCase *swcase; + short numcases; + CI_Switch *packed; + + info = (SwitchInfo *) stmt->label; + swcase = info->cases; + numcases = 0; + while (swcase) { + swcase = swcase->next; + numcases++; + } + + packed = galloc(sizeof(CI_Switch) + numcases * sizeof(CI_SwitchCase)); + packed->expr = CInline_CopyExpression(stmt->expr, CopyMode2); + packed->defaultlabelID = CInline_GetStatementNumber(start, info->defaultlabel->stmt); + packed->unkSwitch8 = info->x8; + packed->numcases = numcases; + + for (swcase = info->cases, numcases = 0; swcase; swcase = swcase->next, numcases++) { + packed->cases[numcases].labelID = CInline_GetStatementNumber(start, swcase->label->stmt); + packed->cases[numcases].min = swcase->min; + packed->cases[numcases].max = swcase->max; + } + + return packed; +} + +static UInt8 CInline_CanInline(Object *object, Statement *stmt) { + UInt8 resultClass; + FuncArg *arg; + UInt8 result; + + resultClass = CMach_GetFunctionResultClass(TYPE_FUNC(object->type)); + if ( + resultClass && + (resultClass != 1 || (IS_TYPE_CLASS(TYPE_FUNC(object->type)->functype) && CClass_Destructor(TYPE_CLASS(TYPE_FUNC(object->type)->functype)))) + ) + return CI_CanInline0; + + for (arg = TYPE_FUNC(object->type)->args; arg; arg = arg->next) { + if (arg == &elipsis) + return CI_CanInline0; + if (arg == &oldstyle) + break; + + if (IS_TYPE_CLASS(arg->type) && CClass_Destructor(TYPE_CLASS(arg->type))) + return CI_CanInline0; + } + + result = CI_CanInline6; + + while (stmt) { + if (stmt->dobjstack) + return CI_CanInline3; + + switch (stmt->type) { + case ST_EXPRESSION: + break; + case ST_RETURN: + if (stmt->next || (stmt->expr == NULL && TYPE_FUNC(object->type)->functype != &stvoid)) + result = CI_CanInline3; + break; + default: + result = CI_CanInline3; + } + + stmt = stmt->next; + } + + return result; +} + +static ExceptionAction *CInline_PackActions(Statement *start, Statement *stmt) { + ExceptionAction *exc; + ExceptionAction *last; + ExceptionAction *packexc; + + exc = stmt->dobjstack; + last = NULL; + + while (exc) { + packexc = galloc(sizeof(ExceptionAction)); + packexc->prev = last; + last = packexc; + + packexc->type = exc->type; + + switch (exc->type) { + case EAT_DESTROYLOCAL: + packexc->data.destroy_local.local = (void *) CInline_GetLocalID(exc->data.destroy_local.local); + packexc->data.destroy_local.dtor = exc->data.destroy_local.dtor; + break; + case EAT_DESTROYLOCALCOND: + packexc->data.destroy_local_cond.local = (void *) CInline_GetLocalID(exc->data.destroy_local_cond.local); + packexc->data.destroy_local_cond.dtor = exc->data.destroy_local_cond.dtor; + packexc->data.destroy_local_cond.cond = (void *) CInline_GetLocalID(exc->data.destroy_local_cond.cond); + break; + case EAT_DESTROYLOCALOFFSET: + packexc->data.destroy_local_offset.local = (void *) CInline_GetLocalID(exc->data.destroy_local_offset.local); + packexc->data.destroy_local_offset.dtor = exc->data.destroy_local_offset.dtor; + packexc->data.destroy_local_offset.offset = exc->data.destroy_local_offset.offset; + break; + case EAT_DESTROYLOCALPOINTER: + packexc->data.destroy_local_pointer.pointer = (void *) CInline_GetLocalID(exc->data.destroy_local_pointer.pointer); + packexc->data.destroy_local_pointer.dtor = exc->data.destroy_local_pointer.dtor; + break; + case EAT_DESTROYLOCALARRAY: + packexc->data.destroy_local_array.localarray = (void *) CInline_GetLocalID(exc->data.destroy_local_array.localarray); + packexc->data.destroy_local_array.dtor = exc->data.destroy_local_array.dtor; + packexc->data.destroy_local_array.elements = exc->data.destroy_local_array.elements; + packexc->data.destroy_local_array.element_size = exc->data.destroy_local_array.element_size; + break; + case EAT_DESTROYPARTIALARRAY: + packexc->data.destroy_partial_array.arraypointer = (void *) CInline_GetLocalID(exc->data.destroy_partial_array.arraypointer); + packexc->data.destroy_partial_array.arraycounter = (void *) CInline_GetLocalID(exc->data.destroy_partial_array.arraycounter); + packexc->data.destroy_partial_array.dtor = (void *) CInline_GetLocalID(exc->data.destroy_partial_array.dtor); + packexc->data.destroy_partial_array.element_size = (void *) CInline_GetLocalID(exc->data.destroy_partial_array.element_size); + break; + case EAT_DESTROYMEMBER: + case EAT_DESTROYBASE: + packexc->data.destroy_member.objectptr = (void *) CInline_GetLocalID(exc->data.destroy_member.objectptr); + packexc->data.destroy_member.dtor = exc->data.destroy_member.dtor; + packexc->data.destroy_member.offset = exc->data.destroy_member.offset; + break; + case EAT_DESTROYMEMBERCOND: + packexc->data.destroy_member_cond.objectptr = (void *) CInline_GetLocalID(exc->data.destroy_member_cond.objectptr); + packexc->data.destroy_member_cond.cond = (void *) CInline_GetLocalID(exc->data.destroy_member_cond.cond); + packexc->data.destroy_member_cond.dtor = exc->data.destroy_member_cond.dtor; + packexc->data.destroy_member_cond.offset = exc->data.destroy_member_cond.offset; + break; + case EAT_DESTROYMEMBERARRAY: + packexc->data.destroy_member_array.objectptr = (void *) CInline_GetLocalID(exc->data.destroy_member_array.objectptr); + packexc->data.destroy_member_array.dtor = exc->data.destroy_member_array.dtor; + packexc->data.destroy_member_array.offset = exc->data.destroy_member_array.offset; + packexc->data.destroy_member_array.elements = exc->data.destroy_member_array.elements; + packexc->data.destroy_member_array.element_size = exc->data.destroy_member_array.element_size; + break; + case EAT_DELETEPOINTER: + case EAT_DELETELOCALPOINTER: + packexc->data.delete_pointer.pointerobject = (void *) CInline_GetLocalID(exc->data.delete_pointer.pointerobject); + packexc->data.delete_pointer.deletefunc = exc->data.delete_pointer.deletefunc; + break; + case EAT_DELETEPOINTERCOND: + packexc->data.delete_pointer_cond.pointerobject = (void *) CInline_GetLocalID(exc->data.delete_pointer_cond.pointerobject); + packexc->data.delete_pointer_cond.deletefunc = exc->data.delete_pointer_cond.deletefunc; + packexc->data.delete_pointer_cond.cond = (void *) CInline_GetLocalID(exc->data.delete_pointer_cond.cond); + break; + case EAT_CATCHBLOCK: + packexc->data.catch_block.catch_object = (void *) CInline_GetLocalID(exc->data.catch_block.catch_object); + packexc->data.catch_block.catch_info_object = (void *) CInline_GetLocalID(exc->data.catch_block.catch_info_object); + packexc->data.catch_block.catch_label = (void *) CInline_GetStatementNumber(start->next, exc->data.catch_block.catch_label->stmt); + packexc->data.catch_block.catch_typeid = exc->data.catch_block.catch_typeid; + packexc->data.catch_block.catch_type = exc->data.catch_block.catch_type; + packexc->data.catch_block.catch_qual = exc->data.catch_block.catch_qual; + break; + case EAT_ACTIVECATCHBLOCK: + packexc->data.active_catch_block.catch_info_object = (void *) CInline_GetLocalID(exc->data.active_catch_block.catch_info_object); + packexc->data.active_catch_block.call_dtor = exc->data.active_catch_block.call_dtor; + break; + case EAT_SPECIFICATION: + packexc->data.specification.unexp_ids = exc->data.specification.unexp_ids; + packexc->data.specification.unexp_id = exc->data.specification.unexp_id; + packexc->data.specification.unexp_label = (void *) CInline_GetStatementNumber(start->next, exc->data.specification.unexp_label->stmt); + packexc->data.specification.unexp_info_object = (void *) CInline_GetLocalID(exc->data.specification.unexp_info_object); + break; + case EAT_TERMINATE: + break; + default: + CError_FATAL(3720); + } + + exc = exc->prev; + } + + return last; +} + +void CInline_PackIFunctionData(CI_FuncData *funcdata, Statement *stmt, Object *object) { + ObjectList *list; + CI_Var *var; + Statement *scan; + CI_Statement *packstmt; + int i; + + cinline_first_stmt = stmt->next; + memclrw(funcdata, sizeof(CI_FuncData)); + + funcdata->can_inline = CInline_CanInline(object, stmt->next); + + if (copts.filesyminfo) { + funcdata->fileoffset = cparser_fileoffset; + funcdata->fileoffset.is_inline = 1; + funcdata->symdecloffset = symdecloffset; + funcdata->functionbodyoffset = functionbodyoffset; + funcdata->functionbodypath = functionbodypath; + funcdata->symdeclend = symdeclend; + } + + list = arguments; + i = 0; + while (list) { + list = list->next; + i++; + } + + if ((funcdata->numarguments = i) > 0) { + loc_args = funcdata->arguments = galloc(sizeof(CI_Var) * i); + memclrw(funcdata->arguments, sizeof(CI_Var) * i); + + for (list = arguments, var = funcdata->arguments; list; list = list->next, var++) { + var->name = list->object->name; + var->type = list->object->type; + var->qual = list->object->qual; + var->sflags = CInline_GetObjectSFlags(list->object); + var->xD = 0; + var->xE = 1; + } + } + + list = locals; + i = 0; + while (list) { + if (list->object->datatype == DLOCAL) + i++; + list = list->next; + } + + if ((funcdata->numlocals = i) > 0) { + loc_vars = funcdata->locals = galloc(sizeof(CI_Var) * i); + memclrw(funcdata->locals, sizeof(CI_Var) * i); + + for (list = locals, var = funcdata->locals; list; list = list->next) { + if (list->object->datatype == DLOCAL) { + var->name = list->object->name; + var->type = list->object->type; + var->qual = list->object->qual; + var->sflags = CInline_GetObjectSFlags(list->object); + var->xD = 0; + var->xE = 0; + var++; + } + } + } + + scan = stmt->next; + i = 0; + while (scan) { + scan = scan->next; + i++; + } + + funcdata->numstatements = i; + funcdata->statements = galloc(sizeof(CI_Statement) * i); + + for (scan = stmt->next, packstmt = funcdata->statements; scan; scan = scan->next, packstmt++) { + packstmt->type = scan->type; + packstmt->flags = scan->flags; + packstmt->value = scan->value; + packstmt->dobjstack = CInline_PackActions(stmt, scan); + packstmt->sourceoffset = scan->sourceoffset; + packstmt->sourcefilepath = scan->sourcefilepath; + + switch (scan->type) { + case ST_NOP: + case ST_LABEL: + break; + case ST_EXPRESSION: + case ST_BEGINCATCH: + case ST_ENDCATCH: + case ST_ENDCATCHDTOR: + case ST_GOTOEXPR: + packstmt->u.expr = CInline_CopyExpression(scan->expr, CopyMode2); + break; + case ST_RETURN: + if (scan->expr) + packstmt->u.expr = CInline_CopyExpression(scan->expr, CopyMode2); + else + packstmt->u.expr = NULL; + break; + case ST_GOTO: + packstmt->u.statementnum = CInline_GetStatementNumber(stmt->next, scan->label->stmt); + break; + case ST_IFGOTO: + case ST_IFNGOTO: + packstmt->u.ifgoto.expr = CInline_CopyExpression(scan->expr, CopyMode2); + packstmt->u.ifgoto.statementnum = CInline_GetStatementNumber(stmt->next, scan->label->stmt); + break; + case ST_SWITCH: + packstmt->u.switchdata = CInline_PackSwitch(stmt->next, scan); + break; + case ST_ASM: + InlineAsm_PackAsmStatement(scan, stmt->next, &packstmt->u.asmdata.data, &packstmt->u.asmdata.size); + break; + default: + CError_FATAL(3862); + } + } +} + +void CInline_UnpackIFunctionData(Object *object, CI_FuncData *funcdata, Statement *firstStmt) { + CLabel **labels; + CI_Var *var; + ObjectList *last; + Statement *stmt; + CI_Statement *packstmt; + int i; + + cparser_fileoffset = funcdata->fileoffset; + symdecloffset = funcdata->symdecloffset; + functionbodyoffset = funcdata->functionbodyoffset; + functionbodypath = funcdata->functionbodypath; + symdeclend = funcdata->symdeclend; + + for (i = 0, var = funcdata->arguments; i < funcdata->numarguments; i++, var++) { + if (i == 0) { + last = lalloc(sizeof(ObjectList)); + arguments = last; + } else { + last->next = lalloc(sizeof(ObjectList)); + last = last->next; + } + + object = galloc(sizeof(Object)); + memclrw(object, sizeof(Object)); + last->object = object; + last->next = NULL; + + object->otype = OT_OBJECT; + object->access = ACCESSPUBLIC; + object->datatype = DLOCAL; + object->name = var->name; + object->type = var->type; + object->qual = var->qual; + CInline_SetObjectSFlags(object, var->sflags); + CFunc_SetupLocalVarInfo(object); + + if (funcdata->fileoffset.file) { + object->u.var.info->deftoken.tokenfile = funcdata->fileoffset.file; + object->u.var.info->deftoken.tokenoffset = funcdata->functionbodyoffset; + } + } + + for (i = 0, var = funcdata->locals; i < funcdata->numlocals; i++, var++) { + if (i == 0) { + last = lalloc(sizeof(ObjectList)); + locals = last; + } else { + last->next = lalloc(sizeof(ObjectList)); + last = last->next; + } + + object = galloc(sizeof(Object)); + memclrw(object, sizeof(Object)); + last->object = object; + last->next = NULL; + + object->otype = OT_OBJECT; + object->access = ACCESSPUBLIC; + object->datatype = DLOCAL; + object->name = var->name; + object->type = var->type; + object->qual = var->qual; + CInline_SetObjectSFlags(object, var->sflags); + CFunc_SetupLocalVarInfo(object); + + if (funcdata->fileoffset.file) { + object->u.var.info->deftoken.tokenfile = funcdata->fileoffset.file; + object->u.var.info->deftoken.tokenoffset = funcdata->functionbodyoffset; + } + } + + enode_idtrans = NULL; + cinline_label_trans = NULL; + + labels = lalloc(sizeof(CLabel *) * funcdata->numstatements); + memclrw(labels, sizeof(CLabel *) * funcdata->numstatements); + + for (i = 0, stmt = firstStmt, packstmt = funcdata->statements; i < funcdata->numstatements; i++, packstmt++) { + stmt->next = lalloc(sizeof(Statement)); + stmt = stmt->next; + + stmt->type = packstmt->type; + stmt->flags = packstmt->flags; + stmt->value = packstmt->value; + stmt->sourceoffset = packstmt->sourceoffset; + stmt->sourcefilepath = packstmt->sourcefilepath; + stmt->dobjstack = CInline_UnpackActions(packstmt, 0); + stmt->next = NULL; + + switch (stmt->type) { + case ST_NOP: + case ST_GOTO: + case ST_ASM: + break; + case ST_EXPRESSION: + case ST_BEGINCATCH: + case ST_ENDCATCH: + case ST_ENDCATCHDTOR: + case ST_GOTOEXPR: + stmt->expr = CInline_CopyExpression(packstmt->u.expr, CopyMode3); + break; + case ST_RETURN: + if (packstmt->u.expr) + stmt->expr = CInline_CopyExpression(packstmt->u.expr, CopyMode3); + else + stmt->expr = NULL; + break; + case ST_LABEL: + labels[i] = stmt->label = newlabel(); + stmt->label->stmt = stmt; + break; + case ST_IFGOTO: + case ST_IFNGOTO: + stmt->expr = CInline_CopyExpression(packstmt->u.ifgoto.expr, CopyMode3); + break; + case ST_SWITCH: + stmt->expr = CInline_CopyExpression(packstmt->u.switchdata->expr, CopyMode3); + break; + default: + CError_FATAL(4017); + } + } + + for (stmt = firstStmt->next, packstmt = funcdata->statements; stmt; stmt = stmt->next, packstmt++) { + switch (stmt->type) { + case ST_GOTO: + CError_ASSERT(4024, stmt->label = labels[packstmt->u.statementnum]); + break; + case ST_IFGOTO: + case ST_IFNGOTO: + CError_ASSERT(4029, stmt->label = labels[packstmt->u.ifgoto.statementnum]); + break; + case ST_SWITCH: + CInline_UnpackSwitch(stmt, packstmt, labels); + break; + case ST_ASM: + InlineAsm_UnpackAsmStatement(stmt, labels, 0, packstmt->u.asmdata.data, packstmt->u.asmdata.size); + break; + } + } + + cinline_first_stmt = firstStmt->next; + + while (cinline_label_trans) { + CError_ASSERT(4045, *cinline_label_trans->labelptr = labels[cinline_label_trans->id]); + cinline_label_trans = cinline_label_trans->next; + } +} + +static void CInline_GenIFunctionCode(Object *object, CI_FuncData *func, UInt8 unk) { + Boolean saveDebugInfo; + CScopeSave saveScope; + Statement firstStmt; + + if (cparamblkptr->precompile != 1 && func) { + ObjGen_SetupSym(); + CScope_SetFunctionScope(object, &saveScope); + CFunc_FuncGenSetup(&firstStmt, object); + CInline_UnpackIFunctionData(object, func, &firstStmt); + + saveDebugInfo = copts.filesyminfo; + if (copts.nosyminline || (!symdecloffset && !symdeclend)) + copts.filesyminfo = 0; + + expanding_function = object; + recursive_inline = 0; + CInline_Expand(&firstStmt); + + if (!anyerrors) { + if (copts.filesyminfo) + CPrep_SetSourceFile(&cparser_fileoffset); + CodeGen_Generator(&firstStmt, object, unk, 0); + } + + CScope_RestoreScope(&saveScope); + copts.filesyminfo = saveDebugInfo; + } +} + +void CInline_AddDefaultFunctionAction(Object *object) { + CI_Action *action; + + for (action = cinline_actionlist; action; action = action->next) { + if (action->obj == object) + return; + } + + action = galloc(sizeof(CI_Action)); + memclrw(action, sizeof(CI_Action)); + + action->actiontype = CI_ActionDefaultFunc; + action->obj = object; + + action->next = cinline_actionlist; + cinline_actionlist = action; +} + +void CInline_AddInlineFunctionAction(Object *object, TypeClass *tclass, FileOffsetInfo *fileoffset, TokenStream *stream, Boolean flag) { + CI_Action *action; + + for (action = flag ? cinline_tactionlist : cinline_actionlist; action; action = action->next) { + if (action->obj == object) + return; + } + + CError_ASSERT(4132, IS_TYPE_FUNC(object->type)); + + TYPE_FUNC(object->type)->flags |= FUNC_IS_TEMPL_INSTANCE; + + action = galloc(sizeof(CI_Action)); + memclrw(action, sizeof(CI_Action)); + + action->actiontype = CI_ActionInlineFunc; + action->obj = object; + action->u.inlinefunc.tclass = tclass; + action->u.inlinefunc.fileoffset = *fileoffset; + action->u.inlinefunc.stream = *stream; + + if (flag) { + action->next = cinline_tactionlist; + cinline_tactionlist = action; + TYPE_FUNC(object->type)->flags |= FUNC_FLAGS_200000; + } else { + action->next = cinline_actionlist; + cinline_actionlist = action; + } +} + +void CInline_AddMemberFunctionAction(Object *object, TemplClass *templ, TemplClassInst *inst, TemplateMember *tmemb) { + CI_Action *action; + + for (action = cinline_tactionlist; action; action = action->next) { + if (action->obj == object) + return; + } + + action = galloc(sizeof(CI_Action)); + memclrw(action, sizeof(CI_Action)); + + action->actiontype = CI_ActionMemberFunc; + action->obj = object; + action->u.memberfunc.templ = templ; + action->u.memberfunc.inst = inst; + action->u.memberfunc.tmemb = tmemb; + + action->next = cinline_tactionlist; + cinline_tactionlist = action; + + TYPE_FUNC(object->type)->flags |= FUNC_FLAGS_200000; +} + +void CInline_AddTemplateFunctionAction(Object *object, TemplateFunction *func, TemplFuncInstance *inst) { + CI_Action *action; + + for (action = cinline_tactionlist; action; action = action->next) { + if (action->obj == object) + return; + } + + action = galloc(sizeof(CI_Action)); + memclrw(action, sizeof(CI_Action)); + + action->actiontype = CI_ActionTemplateFunc; + action->obj = object; + action->u.templatefunc.func = func; + action->u.templatefunc.inst = inst; + + action->next = cinline_tactionlist; + cinline_tactionlist = action; + + TYPE_FUNC(object->type)->flags |= FUNC_FLAGS_200000; +} + +static void CInline_AddFRefList_Object(Object *object) { + ObjectList *list; + + if ( + !(object->datatype == DFUNC || object->datatype == DVFUNC) || + (object->flags & OBJECT_DEFINED) || + IS_TEMPL_FUNC(object->type) + ) + return; + + for (list = cinline_freflist; list; list = list->next) { + if (list->object == object) + return; + } + + list = lalloc(sizeof(ObjectList)); + list->object = object; + list->next = cinline_freflist; + cinline_freflist = list; + + if ((object->qual & Q_INLINE) && object->u.func.u.ifuncdata) + CInline_AddFRefList_InlineFunc(object->u.func.u.ifuncdata); +} + +static void CInline_AddFRefList_ExAction(ExceptionAction *exc) { + while (exc) { + switch (exc->type) { + case EAT_DESTROYLOCAL: + CInline_AddFRefList_Object(exc->data.destroy_local.dtor); + break; + case EAT_DESTROYLOCALCOND: + CInline_AddFRefList_Object(exc->data.destroy_local_cond.dtor); + break; + case EAT_DESTROYLOCALOFFSET: + CInline_AddFRefList_Object(exc->data.destroy_local_offset.dtor); + break; + case EAT_DESTROYLOCALPOINTER: + CInline_AddFRefList_Object(exc->data.destroy_local_pointer.dtor); + break; + case EAT_DESTROYLOCALARRAY: + CInline_AddFRefList_Object(exc->data.destroy_local_array.dtor); + break; + case EAT_DESTROYPARTIALARRAY: + CInline_AddFRefList_Object(exc->data.destroy_partial_array.dtor); + break; + case EAT_DESTROYMEMBER: + case EAT_DESTROYBASE: + CInline_AddFRefList_Object(exc->data.destroy_member.dtor); + break; + case EAT_DESTROYMEMBERCOND: + CInline_AddFRefList_Object(exc->data.destroy_member_cond.dtor); + break; + case EAT_DESTROYMEMBERARRAY: + CInline_AddFRefList_Object(exc->data.destroy_member_array.dtor); + break; + case EAT_DELETEPOINTER: + case EAT_DELETELOCALPOINTER: + CInline_AddFRefList_Object(exc->data.delete_pointer.deletefunc); + break; + case EAT_DELETEPOINTERCOND: + CInline_AddFRefList_Object(exc->data.delete_pointer_cond.deletefunc); + break; + case EAT_CATCHBLOCK: + case EAT_ACTIVECATCHBLOCK: + case EAT_SPECIFICATION: + case EAT_TERMINATE: + break; + default: + CError_FATAL(4307); + } + exc = exc->prev; + } +} + +static void CInline_AddFRefList_ExprCB(ENode *expr) { + CInline_AddFRefList_Object(expr->data.objref); +} + +static void CInline_AddFRefList_Expr(ENode *expr) { + CExpr_SearchExprTree(expr, CInline_AddFRefList_ExprCB, 1, EOBJREF); +} + +static void CInline_AddFRefList_Statement(Statement *stmt) { + while (stmt) { + if (stmt->dobjstack) + CInline_AddFRefList_ExAction(stmt->dobjstack); + + switch (stmt->type) { + case ST_NOP: + case ST_LABEL: + case ST_GOTO: + case ST_BEGINCATCH: + case ST_ENDCATCH: + case ST_ENDCATCHDTOR: + 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_GOTOEXPR: + CInline_AddFRefList_Expr(stmt->expr); + break; + default: + CError_FATAL(4368); + } + + stmt = stmt->next; + } +} + +static void CInline_AddFRefList_InlineFunc(CI_FuncData *data) { + short i; + CI_Statement *stmt; + ExceptionAction *exc; + + for (i = 0; i < data->numstatements; i++) { + stmt = data->statements + i; + + switch (stmt->type) { + case ST_NOP: + case ST_LABEL: + case ST_GOTO: + case ST_ASM: + break; + case ST_EXPRESSION: + case ST_BEGINCATCH: + case ST_ENDCATCH: + case ST_ENDCATCHDTOR: + case ST_GOTOEXPR: + CInline_AddFRefList_Expr(stmt->u.expr); + break; + case ST_RETURN: + if (stmt->u.expr) + CInline_AddFRefList_Expr(stmt->u.expr); + break; + case ST_IFGOTO: + case ST_IFNGOTO: + CInline_AddFRefList_Expr(stmt->u.ifgoto.expr); + break; + case ST_SWITCH: + CInline_AddFRefList_Expr(stmt->u.switchdata->expr); + break; + default: + CError_FATAL(4420); + } + + for (exc = data->statements[i].dobjstack; exc; exc = exc->prev) { + switch (exc->type) { + case EAT_DESTROYLOCAL: + CInline_AddFRefList_Object(exc->data.destroy_local.dtor); + break; + case EAT_DESTROYLOCALCOND: + CInline_AddFRefList_Object(exc->data.destroy_local_cond.dtor); + break; + case EAT_DESTROYLOCALOFFSET: + CInline_AddFRefList_Object(exc->data.destroy_local_offset.dtor); + break; + case EAT_DESTROYLOCALPOINTER: + CInline_AddFRefList_Object(exc->data.destroy_local_pointer.dtor); + break; + case EAT_DESTROYLOCALARRAY: + CInline_AddFRefList_Object(exc->data.destroy_local_array.dtor); + break; + case EAT_DESTROYPARTIALARRAY: + break; + case EAT_DESTROYMEMBER: + case EAT_DESTROYBASE: + CInline_AddFRefList_Object(exc->data.destroy_member.dtor); + break; + case EAT_DESTROYMEMBERCOND: + CInline_AddFRefList_Object(exc->data.destroy_member_cond.dtor); + break; + case EAT_DESTROYMEMBERARRAY: + CInline_AddFRefList_Object(exc->data.destroy_member_array.dtor); + break; + case EAT_DELETEPOINTER: + case EAT_DELETELOCALPOINTER: + CInline_AddFRefList_Object(exc->data.delete_pointer.deletefunc); + break; + case EAT_DELETEPOINTERCOND: + CInline_AddFRefList_Object(exc->data.delete_pointer_cond.deletefunc); + break; + case EAT_CATCHBLOCK: + case EAT_ACTIVECATCHBLOCK: + case EAT_SPECIFICATION: + case EAT_TERMINATE: + break; + default: + CError_FATAL(4470); + } + } + } +} + +static void CInline_GenerateTemplateInline(Object *object) { + CI_Action **ptr; + CI_Action *action; + + ptr = &cinline_tactionlist; + while ((action = *ptr)) { + if (object == action->obj) { + *ptr = action->next; + action->next = cinline_actionlist; + cinline_actionlist = action; + + TYPE_FUNC(object->type)->flags &= ~FUNC_FLAGS_200000; + return; + } + + ptr = &action->next; + } + + CError_FATAL(4499); +} + +void CInline_ObjectAddrRef(Object *object) { + CI_FuncData *funcdata; + + object->flags |= OBJECT_FLAGS_2; + + switch (object->datatype) { + case DFUNC: + case DVFUNC: + if ( + (object->qual & Q_INLINE) && + (funcdata = object->u.func.u.ifuncdata) && + !(object->flags & OBJECT_DEFINED) && + !(TYPE_FUNC(object->type)->flags & FUNC_IS_TEMPL) + ) + { + CI_Export *export = galloc(sizeof(CI_Export)); + + export->object = object; + export->funcdata = funcdata; + export->xC = 0; + + export->next = cinline_exportlist; + cinline_exportlist = export; + + object->flags |= OBJECT_DEFINED; + return; + } + else if ( + (TYPE_FUNC(object->type)->flags & FUNC_AUTO_GENERATED) && + !(TYPE_FUNC(object->type)->flags & FUNC_DEFINED) + ) + { + CInline_AddDefaultFunctionAction(object); + return; + } + else if (TYPE_FUNC(object->type)->flags & FUNC_FLAGS_200000) + { + CInline_GenerateTemplateInline(object); + return; + } + return; + + case DALIAS: + CInline_ObjectAddrRef(object->u.alias.object); + return; + + case DDATA: + if (object->qual & Q_INLINE_DATA) + CInit_ExportConst(object); + + if (object->flags & OBJECT_LAZY) { + object->flags &= ~OBJECT_LAZY; + CParser_CallBackAction(object); + } + return; + } +} + +static Boolean CInline_CheckDependencies(ObjectList *list) { + Object *object; + Boolean result; + + result = 0; + + while (list) { + object = list->object; + + if ( + (TYPE_FUNC(object->type)->flags & FUNC_AUTO_GENERATED) && + !(TYPE_FUNC(object->type)->flags & FUNC_DEFINED) + ) + { + CInline_AddDefaultFunctionAction(object); + result = 1; + } + else if ( + (object->qual & Q_IS_TEMPLATED) && + CTempl_InlineFunctionCheck(object) + ) + { + result = 1; + } + else { + CI_Action *action; + for (action = cinline_actionlist; action; action = action->next) { + if (object == action->obj) { + result = 1; + break; + } + } + + if (TYPE_FUNC(object->type)->flags & FUNC_FLAGS_200000) { + CInline_GenerateTemplateInline(object); + result = 1; + } + } + + list = list->next; + } + + return result; +} + +static Boolean CInline_IsSmallFunction(Object *object, Statement *stmt) { + SInt32 statementCount; + ObjectList *list; + SInt32 localSize; + + statementCount = 0; + while (stmt) { + if (stmt->type != ST_NOP && stmt->type != ST_LABEL) + statementCount++; + if (statementCount > 15) + return 0; + stmt = stmt->next; + } + + for (list = locals, localSize = 0; list; list = list->next) + localSize += list->object->type->size; + + if (localSize > 1024) + return 0; + + return 1; +} + +static Boolean CInline_NoFPLocals(void) { + ObjectList *list; + + for (list = locals; list; list = list->next) { + if (IS_TYPE_FLOAT(list->object->type)) + return 0; + } + + return 1; +} + +void CInline_GenFunc(Statement *stmt, Object *object, UInt8 unk) { + CI_FuncData *funcdata; + CI_Export *export; + Boolean flag24; + Boolean flag30; + + TYPE_FUNC(object->type)->flags |= OBJECT_FLAGS_2; + + flag24 = 0; + flag30 = 0; + if (!(object->qual & Q_INLINE)) { + if ( + copts.auto_inline && + !copts.dontinline && + CInline_CanInline(object, stmt->next) && + CInline_IsSmallFunction(object, stmt->next) + ) + { + flag24 = 1; + flag30 = 1; + TYPE_FUNC(object->type)->flags |= FUNC_FLAGS_800; + } + } else { + flag30 = 1; + } + + if (flag30) { + COpt_SimpleOptimizer(object, stmt); + + funcdata = galloc(sizeof(CI_FuncData)); + CInline_PackIFunctionData(funcdata, stmt, object); + + object->u.func.u.ifuncdata = funcdata; + + if (!flag24 && !(object->flags & OBJECT_FLAGS_2)) { + if (cinline_gendeps) { + cinline_freflist = NULL; + CInline_AddFRefList_Statement(stmt); + CInline_CheckDependencies(cinline_freflist); + } + return; + } + } + + object->flags |= OBJECT_DEFINED; + + cinline_freflist = NULL; + CInline_AddFRefList_Statement(stmt); + + if (CInline_CheckDependencies(cinline_freflist) || copts.defer_codegen) { + if (!flag30) { + funcdata = galloc(sizeof(CI_FuncData)); + CInline_PackIFunctionData(funcdata, stmt, object); + } else { + funcdata = object->u.func.u.ifuncdata; + } + + export = galloc(sizeof(CI_Export)); + export->object = object; + export->funcdata = funcdata; + export->xC = unk; + + export->next = cinline_exportlist; + cinline_exportlist = export; + + return; + } + + expanding_function = object; + recursive_inline = 0; + CInline_Expand(stmt); + + if (copts.filesyminfo) + CPrep_SetSourceFile(&cparser_fileoffset); + + if (!anyerrors) + CodeGen_Generator(stmt, object, unk, 0); +} + +static void CInline_GenerateDefaultFunc(Object *object) { + TypeClass *tclass; + + CError_ASSERT(4770, TYPE_FUNC(object->type)->flags & FUNC_AUTO_GENERATED); + CError_ASSERT(4771, TYPE_FUNC(object->type)->flags & FUNC_METHOD); + + tclass = TYPE_METHOD(object->type)->theclass; + + if (object == CClass_DefaultConstructor(tclass)) { + if (object->u.func.defargdata) + CABI_MakeDefaultArgConstructor(tclass, object); + else + CABI_MakeDefaultConstructor(tclass, object); + } else if (object == CClass_CopyConstructor(tclass)) { + CABI_MakeDefaultCopyConstructor(tclass, object); + } else if (object == CClass_AssignmentOperator(tclass)) { + CABI_MakeDefaultAssignmentOperator(tclass, object); + } else if (object == CClass_Destructor(tclass)) { + CABI_MakeDefaultDestructor(tclass, object); + } else { + CError_FATAL(4805); + } +} + +static TemplClassInst *CInline_FindNestedTemplInst(TypeClass *tclass) { + NameSpace *nspace; + + while (tclass) { + if ((tclass->flags & CLASS_IS_TEMPL_INST)) + return TEMPL_CLASS_INST(tclass); + + if (!copts.template_patch) + break; + + nspace = tclass->nspace->parent; + tclass = NULL; + while (nspace) { + if (nspace->theclass) { + tclass = nspace->theclass; + break; + } + nspace = nspace->parent; + } + } + + return NULL; +} + +static void CInline_GenerateInlineFunc(CI_Action *action) { + Object *object; + TemplClassInst *inst; + DeclInfo di; + SInt32 streamState; + + object = action->obj; + + CPrep_StreamInsert(&action->u.inlinefunc.stream, &streamState); + cparser_fileoffset = action->u.inlinefunc.fileoffset; + symdecloffset = cparser_fileoffset.tokenline; + + switch ((tk = lex())) { + case ':': + case '{': + case TK_TRY: + break; + default: + CError_FATAL(4860); + } + + symdecltoken = *CPrep_CurStreamElement(); + + TYPE_FUNC(object->type)->flags &= ~FUNC_DEFINED; + if (IS_TYPE_METHOD(object->type) && (inst = CInline_FindNestedTemplInst(TYPE_METHOD(object->type)->theclass))) { + CTempl_ParseInstanceScopeFunction(object, inst, NULL); + } else { + memclrw(&di, sizeof(di)); + if (action->u.inlinefunc.tclass) { + if ((inst = CInline_FindNestedTemplInst(action->u.inlinefunc.tclass))) { + CTempl_ParseInstanceScopeFunction(object, inst, action->u.inlinefunc.tclass); + } else { + CFunc_ParseFuncDef(object, &di, action->u.inlinefunc.tclass, 0, 0, NULL); + } + } else { + CFunc_ParseFuncDef(object, &di, NULL, 0, 0, NULL); + } + } + + CPrep_StreamRemove(&action->u.inlinefunc.stream, &streamState); +} + +Boolean CInline_CanFreeLHeap(void) { + CI_Action *action; + + if (!anyerrors) { + for (action = cinline_actionlist; action; action = action->next) { + if (action->actiontype == CI_ActionInlineFunc) + return 0; + } + } + + return 1; +} + +Boolean CInline_GenerateDeferredFuncs(void) { + CI_Action *action; + CI_Export *export; + + if (!anyerrors) { + if ((action = cinline_actionlist)) { + cinline_actionlist = action->next; + cinline_gendeps = 1; + + switch (action->actiontype) { + case CI_ActionDefaultFunc: + CInline_GenerateDefaultFunc(action->obj); + break; + case CI_ActionInlineFunc: + if (!(action->obj->flags & OBJECT_DEFINED)) + CInline_GenerateInlineFunc(action); + break; + case CI_ActionMemberFunc: + if (!(TYPE_FUNC(action->obj->type)->flags & FUNC_DEFINED)) + CTempl_InstantiateMember( + action->u.memberfunc.templ, action->u.memberfunc.inst, + action->u.memberfunc.tmemb, action->obj, 0); + break; + case CI_ActionTemplateFunc: + if (!(TYPE_FUNC(action->obj->type)->flags & FUNC_DEFINED) && !action->u.templatefunc.inst->is_specialized) + CTempl_GenFuncInstance(action->u.templatefunc.func, action->u.templatefunc.inst, 0); + break; + default: + CError_FATAL(5001); + } + + cinline_gendeps = 0; + return 1; + } else { + if ((export = cinline_exportlist) && !copts.defer_codegen) { + cinline_exportlist = export->next; + CInline_GenIFunctionCode(export->object, export->funcdata, export->xC); + return 1; + } + } + } + + return 0; +} + +static InitExpr *CInline_InitTemplateData(InitExpr *init) { + Statement *stmt; + CLabel *label; + Object *object; + Object *data; + + object = init->object; + + data = CParser_NewCompilerDefDataObject(); + data->type = TYPE(&stsignedchar); + data->name = CParser_NameConcat("__init__", CMangler_GetLinkName(object)->name); + data->qual = Q_WEAK; + CInit_DeclareData(data, NULL, NULL, data->type->size); + + stmt = CFunc_AppendStatement(ST_IFGOTO); + stmt->expr = create_objectnode(data); + label = newlabel(); + stmt->label = label; + + do { + stmt = CFunc_AppendStatement(ST_EXPRESSION); + stmt->expr = CInline_CopyExpression(init->expr, CopyMode0); + init = init->next; + } while (init && init->object == object); + + stmt = CFunc_AppendStatement(ST_EXPRESSION); + stmt->expr = makediadicnode(create_objectnode(data), intconstnode(TYPE(&stsignedchar), 1), EASS); + + stmt = CFunc_AppendStatement(ST_LABEL); + stmt->label = label; + label->stmt = stmt; + + return init; +} + +void CInline_Finish(void) { + NameSpace *nspace; + Boolean saveDebugInfo; + Statement firstStmt; + Statement *stmt; + InitExpr *init; + Boolean doMore; + + if (!init_expressions || anyerrors) + return; + + cinline_freflist = NULL; + + for (init = init_expressions; init; init = init->next) + CInline_AddFRefList_Expr(init->expr); + + CInline_CheckDependencies(cinline_freflist); + + do { + doMore = CInline_GenerateDeferredFuncs(); + } while (doMore); + + nspace = CFunc_FuncGenSetup(&firstStmt, NULL); + saveDebugInfo = copts.filesyminfo; + copts.filesyminfo = 0; + + init = init_expressions; + while (init) { + if (init->object->nspace->theclass && (init->object->nspace->theclass->flags & CLASS_IS_TEMPL_INST)) { + init = CInline_InitTemplateData(init); + } else { + stmt = CFunc_AppendStatement(ST_EXPRESSION); + stmt->expr = CInline_CopyExpression(init->expr, CopyMode0); + init = init->next; + } + } + + CFunc_CodeCleanup(&firstStmt); + + expanding_function = NULL; + recursive_inline = 0; + CInline_Expand(&firstStmt); + + if (!anyerrors) { + if (copts.filesyminfo) + CPrep_SetSourceFile(&cparser_fileoffset); + CodeGen_Generator(&firstStmt, NULL, 0, 1); + } + + cscope_current = nspace->parent; + copts.filesyminfo = saveDebugInfo; +} diff --git a/compiler_and_linker/FrontEnd/C/CMangler.c b/compiler_and_linker/FrontEnd/C/CMangler.c new file mode 100644 index 0000000..615abf5 --- /dev/null +++ b/compiler_and_linker/FrontEnd/C/CMangler.c @@ -0,0 +1,713 @@ +#include "compiler/CMangler.h" +#include "compiler/CError.h" +#include "compiler/CInt64.h" +#include "compiler/CFunc.h" +#include "compiler/CParser.h" +#include "compiler/CTemplateTools.h" +#include "compiler/CompilerTools.h" +#include "compiler/enode.h" +#include "compiler/objects.h" +#include "compiler/scopes.h" +#include "compiler/templates.h" +#include "compiler/types.h" +#include "cos.h" + +HashNameNode *constructor_name_node; +HashNameNode *destructor_name_node; +HashNameNode *asop_name_node; + +// forward decls +static void CMangler_MangleClassName(TypeClass *tclass); +static void CMangler_MangleTypeAppend(Type *type, UInt32 qual); +static void CMangler_MangleArgs(FuncArg *args); + +void CMangler_Setup(void) { + constructor_name_node = GetHashNameNodeExport("__ct"); + destructor_name_node = GetHashNameNodeExport("__dt"); + asop_name_node = GetHashNameNodeExport("__as"); +} + +HashNameNode *CMangler_BasicDtorName(void) { + return GetHashNameNodeExport("__dtb"); +} + +HashNameNode *CMangler_VBaseDtorName(void) { + return GetHashNameNodeExport("__dtv"); +} + +HashNameNode *CMangler_ArrayDtorName(void) { + return GetHashNameNodeExport("__dta"); +} + +HashNameNode *CMangler_SDeleteDtorName(void) { + return GetHashNameNodeExport("__dts"); +} + +HashNameNode *CMangler_DeleteDtorName(void) { + return GetHashNameNodeExport("__dt"); +} + +char *CMangler_GetOperator(HashNameNode *name) { + char *str; + + if (name == asop_name_node) + return "operator="; + + str = name->name; + if (!strcmp(str, "__nw")) return "operator new"; + if (!strcmp(str, "__dl")) return "operator delete"; + if (!strcmp(str, "__nwa")) return "operator new[]"; + if (!strcmp(str, "__dla")) return "operator delete[]"; + if (!strcmp(str, "__pl")) return "operator+"; + if (!strcmp(str, "__mi")) return "operator-"; + if (!strcmp(str, "__ml")) return "operator*"; + if (!strcmp(str, "__dv")) return "operator/"; + if (!strcmp(str, "__md")) return "operator%"; + if (!strcmp(str, "__er")) return "operator^"; + if (!strcmp(str, "__ad")) return "operator&"; + if (!strcmp(str, "__or")) return "operator|"; + if (!strcmp(str, "__co")) return "operator~"; + if (!strcmp(str, "__nt")) return "operator!"; + if (!strcmp(str, "__lt")) return "operator<"; + if (!strcmp(str, "__gt")) return "operator>"; + if (!strcmp(str, "__apl")) return "operator+="; + if (!strcmp(str, "__ami")) return "operator-="; + if (!strcmp(str, "__amu")) return "operator*="; + if (!strcmp(str, "__adv")) return "operator/="; + if (!strcmp(str, "__amd")) return "operator%="; + if (!strcmp(str, "__aer")) return "operator^="; + if (!strcmp(str, "__aad")) return "operator&="; + if (!strcmp(str, "__aor")) return "operator|="; + if (!strcmp(str, "__ls")) return "operator<<"; + if (!strcmp(str, "__rs")) return "operator>>"; + if (!strcmp(str, "__als")) return "operator<<="; + if (!strcmp(str, "__ars")) return "operator>>="; + if (!strcmp(str, "__eq")) return "operator=="; + if (!strcmp(str, "__ne")) return "operator!="; + if (!strcmp(str, "__le")) return "operator<="; + if (!strcmp(str, "__ge")) return "operator>="; + if (!strcmp(str, "__aa")) return "operator&&"; + if (!strcmp(str, "__oo")) return "operator||"; + if (!strcmp(str, "__pp")) return "operator++"; + if (!strcmp(str, "__mm")) return "operator--"; + if (!strcmp(str, "__cm")) return "operator,"; + if (!strcmp(str, "__rm")) return "operator->*"; + if (!strcmp(str, "__rf")) return "operator*"; + if (!strcmp(str, "__cl")) return "operator()"; + if (!strcmp(str, "__vc")) return "operator[]"; + return NULL; +} + +HashNameNode *CMangler_OperatorName(short token) { + switch (token) { + case TK_NEW: return GetHashNameNodeExport("__nw"); + case TK_DELETE: return GetHashNameNodeExport("__dl"); + case TK_NEW_ARRAY: return GetHashNameNodeExport("__nwa"); + case TK_DELETE_ARRAY: return GetHashNameNodeExport("__dla"); + case '+': return GetHashNameNodeExport("__pl"); + case '-': return GetHashNameNodeExport("__mi"); + case '*': return GetHashNameNodeExport("__ml"); + case '/': return GetHashNameNodeExport("__dv"); + case '%': return GetHashNameNodeExport("__md"); + case '^': return GetHashNameNodeExport("__er"); + case '&': return GetHashNameNodeExport("__ad"); + case '|': return GetHashNameNodeExport("__or"); + case '~': return GetHashNameNodeExport("__co"); + case '!': return GetHashNameNodeExport("__nt"); + case '=': return asop_name_node; + case '<': return GetHashNameNodeExport("__lt"); + case '>': return GetHashNameNodeExport("__gt"); + case TK_ADD_ASSIGN: return GetHashNameNodeExport("__apl"); + case TK_SUB_ASSIGN: return GetHashNameNodeExport("__ami"); + case TK_MULT_ASSIGN: return GetHashNameNodeExport("__amu"); + case TK_DIV_ASSIGN: return GetHashNameNodeExport("__adv"); + case TK_MOD_ASSIGN: return GetHashNameNodeExport("__amd"); + case TK_XOR_ASSIGN: return GetHashNameNodeExport("__aer"); + case TK_AND_ASSIGN: return GetHashNameNodeExport("__aad"); + case TK_OR_ASSIGN: return GetHashNameNodeExport("__aor"); + case TK_SHL: return GetHashNameNodeExport("__ls"); + case TK_SHR: return GetHashNameNodeExport("__rs"); + case TK_SHL_ASSIGN: return GetHashNameNodeExport("__als"); + case TK_SHR_ASSIGN: return GetHashNameNodeExport("__ars"); + case TK_LOGICAL_EQ: return GetHashNameNodeExport("__eq"); + case TK_LOGICAL_NE: return GetHashNameNodeExport("__ne"); + case TK_LESS_EQUAL: return GetHashNameNodeExport("__le"); + case TK_GREATER_EQUAL: return GetHashNameNodeExport("__ge"); + case TK_LOGICAL_AND: return GetHashNameNodeExport("__aa"); + case TK_LOGICAL_OR: return GetHashNameNodeExport("__oo"); + case TK_INCREMENT: return GetHashNameNodeExport("__pp"); + case TK_DECREMENT: return GetHashNameNodeExport("__mm"); + case ',': return GetHashNameNodeExport("__cm"); + case TK_ARROW_STAR: return GetHashNameNodeExport("__rm"); + case TK_ARROW: return GetHashNameNodeExport("__rf"); + case '(': return GetHashNameNodeExport("__cl"); + case '[': return GetHashNameNodeExport("__vc"); + default: return NULL; + } +} + +HashNameNode *CMangler_VTableName(TypeClass *theclass) { + HashNameNode *name; + + name_mangle_list.size = 0; + AppendGListName(&name_mangle_list, "__vt__"); + CMangler_MangleClassName(theclass); + AppendGListByte(&name_mangle_list, 0); + COS_LockHandle(name_mangle_list.data); + name = GetHashNameNodeExport(*name_mangle_list.data); + COS_UnlockHandle(name_mangle_list.data); + return name; +} + +HashNameNode *CMangler_RTTIObjectName(Type *type, UInt32 qual) { + HashNameNode *name; + + name_mangle_list.size = 0; + AppendGListName(&name_mangle_list, "__RTTI__"); + CMangler_MangleTypeAppend(type, qual); + AppendGListByte(&name_mangle_list, 0); + COS_LockHandle(name_mangle_list.data); + name = GetHashNameNodeExport(*name_mangle_list.data); + COS_UnlockHandle(name_mangle_list.data); + return name; +} + +HashNameNode *CMangler_ThunkName(Object *vfunc, SInt32 this_delta, SInt32 return_delta, SInt32 ctoroffset) { + HashNameNode *linkname; + HashNameNode *name; + char buf[64]; + + linkname = CMangler_GetLinkName(vfunc); + name_mangle_list.size = 0; + if (return_delta == 0) { + if (ctoroffset < 0) + sprintf(buf, "_@%" PRId32 "@", -this_delta); + else + sprintf(buf, "_@%" PRId32 "@%" PRId32 "@", -this_delta, ctoroffset); + } else { + sprintf(buf, "_@%" PRId32 "@%" PRId32 "@%" PRId32 "@", -this_delta, ctoroffset, return_delta); + } + AppendGListName(&name_mangle_list, buf); + AppendGListID(&name_mangle_list, linkname->name + 1); + COS_LockHandle(name_mangle_list.data); + name = GetHashNameNodeExport(*name_mangle_list.data); + COS_UnlockHandle(name_mangle_list.data); + return name; +} + +static void CMangler_CheckTemplateArguments(TemplArg *arg) { + ENode *expr; + + while (arg) { + if (arg->pid.type == TPT_NONTYPE) { + expr = arg->data.paramdecl.expr; + CError_ASSERT(360, expr); + if (expr->rtype->type != TYPETEMPLDEPEXPR) { + switch (expr->type) { + case EINTCONST: + break; + case EOBJREF: + CMangler_GetLinkName(expr->data.objref); + break; + default: + CError_FATAL(383); + } + } + } + arg = arg->next; + } +} + +static void CMangler_AppendTemplateArgumentList(TemplArg *arg) { + ENode *expr; + char buf[32]; + + AppendGListByte(&name_mangle_list, '<'); + + while (arg) { + if (arg->pid.type == TPT_NONTYPE) { + expr = arg->data.paramdecl.expr; + CError_ASSERT(409, expr); + if (expr->rtype->type != TYPETEMPLDEPEXPR) { + switch (expr->type) { + case EINTCONST: + CInt64_PrintDec(buf, expr->data.intval); + AppendGListName(&name_mangle_list, buf); + break; + case EOBJREF: + AppendGListByte(&name_mangle_list, '&'); + AppendGListName(&name_mangle_list, CMangler_GetLinkName(expr->data.objref)->name); + break; + default: + CError_FATAL(452); + } + } else { + AppendGListByte(&name_mangle_list, 'T'); + } + } else if (arg->pid.type == TPT_TYPE) { + CMangler_MangleTypeAppend(arg->data.typeparam.type, arg->data.typeparam.qual); + } else { + CError_ASSERT(467, arg->pid.type == TPT_TEMPLATE); + CMangler_MangleTypeAppend(arg->data.ttargtype, 0); + } + + if (arg->next) + AppendGListByte(&name_mangle_list, ','); + arg = arg->next; + } + + AppendGListByte(&name_mangle_list, '>'); +} + +HashNameNode *CMangler_TemplateInstanceName(HashNameNode *basename, TemplArg *args) { + HashNameNode *name; + + CMangler_CheckTemplateArguments(args); + name_mangle_list.size = 0; + AppendGListName(&name_mangle_list, basename->name); + CMangler_AppendTemplateArgumentList(args); + AppendGListByte(&name_mangle_list, 0); + + COS_LockHandle(name_mangle_list.data); + name = GetHashNameNodeExport(*name_mangle_list.data); + COS_UnlockHandle(name_mangle_list.data); + return name; +} + +static void CMangler_MangleTypeName(char *str) { + char buf[16]; + + sprintf(buf, "%d", strlen(str)); + AppendGListName(&name_mangle_list, buf); + AppendGListName(&name_mangle_list, str); +} + +static void CMangler_MangleNameSpaceName(NameSpace *nspace, char *str) { + char *stack[10]; + int stackp; + + stack[0] = str; + stackp = 1; + while (nspace) { + if (nspace->name) { + stack[stackp++] = nspace->name->name; + if (stackp >= 9) + break; + } + nspace = nspace->parent; + } + + if (stackp > 1) { + AppendGListByte(&name_mangle_list, 'Q'); + AppendGListByte(&name_mangle_list, '0' + stackp); + } + + while (--stackp >= 0) + CMangler_MangleTypeName(stack[stackp]); +} + +static void CMangler_MangleClassName(TypeClass *tclass) { + if (!tclass->classname) + CMangler_MangleNameSpaceName(tclass->nspace->parent, "class"); + else + CMangler_MangleNameSpaceName(tclass->nspace->parent, tclass->nspace->name->name); +} + +static void CMangler_MangleQualifier(UInt32 qual) { + if (qual & Q_CONST) + AppendGListByte(&name_mangle_list, 'C'); + if (qual & Q_VOLATILE) + AppendGListByte(&name_mangle_list, 'V'); +} + +static void CMangler_MangleTypeAppend(Type *type, UInt32 qual) { + char buf[16]; + + switch (type->type) { + case TYPEVOID: + CMangler_MangleQualifier(qual); + AppendGListByte(&name_mangle_list, 'v'); + break; + case TYPEINT: + case TYPEFLOAT: + CMangler_MangleQualifier(qual); + switch (TYPE_INTEGRAL(type)->integral) { + case IT_BOOL: + AppendGListByte(&name_mangle_list, 'b'); + return; + case IT_CHAR: + AppendGListByte(&name_mangle_list, 'c'); + return; + case IT_WCHAR_T: + AppendGListByte(&name_mangle_list, 'w'); + return; + case IT_UCHAR: + AppendGListName(&name_mangle_list, "Uc"); + return; + case IT_SCHAR: + AppendGListName(&name_mangle_list, "Sc"); + return; + case IT_SHORT: + AppendGListByte(&name_mangle_list, 's'); + return; + case IT_USHORT: + AppendGListName(&name_mangle_list, "Us"); + return; + case IT_INT: + AppendGListByte(&name_mangle_list, 'i'); + return; + case IT_UINT: + AppendGListName(&name_mangle_list, "Ui"); + return; + case IT_LONG: + AppendGListByte(&name_mangle_list, 'l'); + return; + case IT_ULONG: + AppendGListName(&name_mangle_list, "Ul"); + return; + case IT_LONGLONG: + AppendGListByte(&name_mangle_list, 'x'); + return; + case IT_ULONGLONG: + AppendGListName(&name_mangle_list, "Ux"); + return; + case IT_FLOAT: + AppendGListByte(&name_mangle_list, 'f'); + return; + case IT_SHORTDOUBLE: + AppendGListByte(&name_mangle_list, 'D'); + return; + case IT_DOUBLE: + AppendGListByte(&name_mangle_list, 'd'); + return; + case IT_LONGDOUBLE: + AppendGListByte(&name_mangle_list, 'r'); + return; + default: + CError_FATAL(619); + } + case TYPEENUM: + CMangler_MangleQualifier(qual); + if (!TYPE_ENUM(type)->enumname) + CMangler_MangleNameSpaceName(TYPE_ENUM(type)->nspace, "enum"); + else + CMangler_MangleNameSpaceName(TYPE_ENUM(type)->nspace, TYPE_ENUM(type)->enumname->name); + break; + case TYPEPOINTER: + CMangler_MangleQualifier(TYPE_POINTER(type)->qual); + if (TYPE_POINTER(type)->qual & Q_REFERENCE) + AppendGListByte(&name_mangle_list, 'R'); + else + AppendGListByte(&name_mangle_list, 'P'); + CMangler_MangleTypeAppend(TYPE_POINTER(type)->target, qual); + break; + case TYPEMEMBERPOINTER: + if (TYPE_MEMBER_POINTER(type)->ty2->type != TYPECLASS) { + AppendGListName(&name_mangle_list, "3<T>"); + } else { + CMangler_MangleQualifier(TYPE_MEMBER_POINTER(type)->qual); + AppendGListByte(&name_mangle_list, 'M'); + CMangler_MangleClassName(TYPE_CLASS(TYPE_MEMBER_POINTER(type)->ty2)); + CMangler_MangleTypeAppend(TYPE_MEMBER_POINTER(type)->ty1, qual); + } + break; + case TYPEARRAY: + AppendGListByte(&name_mangle_list, 'A'); + if (TYPE_POINTER(type)->target->size) { + sprintf(buf, "%" PRId32 "", type->size / TYPE_POINTER(type)->target->size); + AppendGListName(&name_mangle_list, buf); + } else { + AppendGListByte(&name_mangle_list, '0'); + } + AppendGListByte(&name_mangle_list, '_'); + CMangler_MangleTypeAppend(TYPE_POINTER(type)->target, qual); + break; + case TYPEFUNC: + CMangler_MangleQualifier(qual); + AppendGListByte(&name_mangle_list, 'F'); + CMangler_MangleArgs(TYPE_FUNC(type)->args); + AppendGListByte(&name_mangle_list, '_'); + CMangler_MangleTypeAppend(TYPE_FUNC(type)->functype, TYPE_FUNC(type)->qual); + break; + case TYPESTRUCT: + CMangler_MangleQualifier(qual); + switch (TYPE_STRUCT(type)->stype) { + case STRUCT_VECTOR_UCHAR: + AppendGListName(&name_mangle_list, "XUc"); + return; + case STRUCT_VECTOR_SCHAR: + AppendGListName(&name_mangle_list, "Xc"); + return; + case STRUCT_VECTOR_BCHAR: + AppendGListName(&name_mangle_list, "XC"); + return; + case STRUCT_VECTOR_USHORT: + AppendGListName(&name_mangle_list, "XUs"); + return; + case STRUCT_VECTOR_SSHORT: + AppendGListName(&name_mangle_list, "Xs"); + return; + case STRUCT_VECTOR_BSHORT: + AppendGListName(&name_mangle_list, "XS"); + return; + case STRUCT_VECTOR_UINT: + AppendGListName(&name_mangle_list, "XUi"); + return; + case STRUCT_VECTOR_SINT: + AppendGListName(&name_mangle_list, "Xi"); + return; + case STRUCT_VECTOR_BINT: + AppendGListName(&name_mangle_list, "XI"); + return; + case STRUCT_VECTOR_FLOAT: + AppendGListName(&name_mangle_list, "Xf"); + return; + case STRUCT_VECTOR_PIXEL: + AppendGListName(&name_mangle_list, "Xp"); + return; + } + + if (TYPE_STRUCT(type)->name && !IsTempName(TYPE_STRUCT(type)->name)) { + CMangler_MangleTypeName(TYPE_STRUCT(type)->name->name); + return; + } + + switch (TYPE_STRUCT(type)->stype) { + case STRUCT_TYPE_STRUCT: + AppendGListName(&name_mangle_list, "struct"); + break; + case STRUCT_TYPE_UNION: + AppendGListName(&name_mangle_list, "union"); + break; + case STRUCT_TYPE_CLASS: + AppendGListName(&name_mangle_list, "class"); + break; + default: + CError_FATAL(701); + } + break; + + case TYPECLASS: + CMangler_MangleQualifier(qual); + CMangler_MangleClassName(TYPE_CLASS(type)); + break; + + case TYPETEMPLATE: + AppendGListName(&name_mangle_list, "1T"); + break; + + default: + CError_FATAL(716); + } +} + +void CMangler_MangleType(Type *type, UInt32 qual) { + name_mangle_list.size = 0; + CMangler_MangleTypeAppend(type, qual); +} + +static void CMangler_MangleArgs(FuncArg *args) { + TypePointer ptr; + + if (args) { + if (args->type) { + while (args) { + if (args != &elipsis && args != &oldstyle) { + if (args->type->type == TYPEPOINTER) { + ptr = *TYPE_POINTER(args->type); + ptr.qual &= ~(Q_CONST | Q_VOLATILE); + CMangler_MangleTypeAppend(TYPE(&ptr), args->qual); + } else { + CMangler_MangleTypeAppend(args->type, 0); + } + } else { + AppendGListByte(&name_mangle_list, 'e'); + } + args = args->next; + } + } else { + AppendGListByte(&name_mangle_list, 'e'); + } + } else { + AppendGListByte(&name_mangle_list, 'v'); + } +} + +static void CMangler_MangleFunction(Object *obj, NameSpace *nspace) { + TypeFunc *tfunc = TYPE_FUNC(obj->type); + FuncArg *arg = tfunc->args; + + AppendGListName(&name_mangle_list, obj->name->name); + if (obj->u.func.inst) { + if (tfunc->flags & FUNC_CONVERSION) + CMangler_MangleTypeAppend(tfunc->functype, tfunc->qual); + CMangler_AppendTemplateArgumentList(obj->u.func.inst->args); + } + AppendGListName(&name_mangle_list, "__"); + while (nspace && nspace->name == NULL) + nspace = nspace->parent; + + if (nspace) { + CMangler_MangleNameSpaceName(nspace->parent, nspace->name->name); + if (nspace->theclass) { + if (obj->name == destructor_name_node) { + AppendGListName(&name_mangle_list, "Fv"); + return; + } + if (arg) { + if (obj->name == constructor_name_node) { + arg = arg->next; + if (arg && (nspace->theclass->flags & CLASS_HAS_VBASES)) + arg = arg->next; + } else { + if ((tfunc->flags & FUNC_METHOD) && !TYPE_METHOD(tfunc)->is_static) { + CMangler_MangleQualifier(arg->qual); + arg = arg->next; + } + } + } + } + } + + AppendGListByte(&name_mangle_list, 'F'); + CMangler_MangleArgs(arg); + if (obj->u.func.inst && copts.new_mangler) { + AppendGListByte(&name_mangle_list, '_'); + CMangler_MangleTypeAppend(tfunc->functype, tfunc->qual); + } +} + +HashNameNode *CMangler_ConversionFuncName(Type *type, UInt32 qual) { + HashNameNode *name; + + if (CTemplTool_IsTemplateArgumentDependentType(type)) + return GetHashNameNodeExport("__op"); + + name_mangle_list.size = 0; + AppendGListName(&name_mangle_list, "__op"); + CMangler_MangleTypeAppend(type, qual); + AppendGListByte(&name_mangle_list, 0); + + COS_LockHandle(name_mangle_list.data); + name = GetHashNameNodeExport(*name_mangle_list.data); + COS_UnlockHandle(name_mangle_list.data); + return name; +} + +static HashNameNode *CMangler_MangleNameToUpper(char *str) { + HashNameNode *name; + + name_mangle_list.size = 0; + while (*str) { + AppendGListByte(&name_mangle_list, toupper(*(str++))); + } + AppendGListByte(&name_mangle_list, 0); + + COS_LockHandle(name_mangle_list.data); + name = GetHashNameNodeExport(*name_mangle_list.data); + COS_UnlockHandle(name_mangle_list.data); + return name; +} + +static HashNameNode *CMangler_FunctionLinkName(Object *obj) { + HashNameNode *name; + NameSpace *nspace; + + if (obj->u.func.inst) + CMangler_CheckTemplateArguments(obj->u.func.inst->args); + + for (nspace = obj->nspace; nspace; nspace = nspace->parent) { + if (nspace->name) + break; + } + + name_mangle_list.size = 0; + if (is_pascal_object(obj) && (!nspace || !nspace->theclass)) { + AppendGListData(&name_mangle_list, "_", 1); + AppendGListID(&name_mangle_list, obj->name->name); + } else if ((obj->qual & Q_MANGLE_NAME) && (strcmp("main", obj->name->name) || (obj->nspace != cscope_root))) { + AppendGListData(&name_mangle_list, "_", 1); + CMangler_MangleFunction(obj, nspace); + AppendGListByte(&name_mangle_list, 0); + } else { + AppendGListData(&name_mangle_list, "_", 1); + AppendGListID(&name_mangle_list, obj->name->name); + } + + COS_LockHandle(name_mangle_list.data); + name = GetHashNameNodeExport(*name_mangle_list.data); + COS_UnlockHandle(name_mangle_list.data); + return name; +} + +HashNameNode *CMangler_GetCovariantFunctionName(Object *dobj, TypeClass *theclass) { + HashNameNode *name; + + name = CMangler_GetLinkName(dobj); + name_mangle_list.size = 0; + AppendGListName(&name_mangle_list, name->name); + AppendGListName(&name_mangle_list, "@@"); + CMangler_MangleTypeAppend(TYPE(theclass), 0); + AppendGListByte(&name_mangle_list, 0); + + COS_LockHandle(name_mangle_list.data); + name = GetHashNameNodeExport(*name_mangle_list.data); + COS_UnlockHandle(name_mangle_list.data); + return name; +} + +static HashNameNode *CMangler_DataLinkName(Object *obj) { + NameSpace *nspace; + HashNameNode *name; + + nspace = obj->nspace; + while (nspace && nspace->name == NULL) + nspace = nspace->parent; + + name_mangle_list.size = 0; + AppendGListData(&name_mangle_list, "_", 1); + AppendGListName(&name_mangle_list, obj->name->name); + + while (nspace && nspace->name == NULL) + nspace = nspace->parent; + if (nspace && (obj->qual & Q_MANGLE_NAME)) { + AppendGListName(&name_mangle_list, "__"); + CMangler_MangleNameSpaceName(nspace->parent, nspace->name->name); + } + AppendGListByte(&name_mangle_list, 0); + + COS_LockHandle(name_mangle_list.data); + name = GetHashNameNodeExport(*name_mangle_list.data); + COS_UnlockHandle(name_mangle_list.data); + return name; +} + +HashNameNode *CMangler_GetLinkName(Object *obj) { + while (obj->datatype == DALIAS) + obj = obj->u.alias.object; + + switch (obj->datatype) { + case DFUNC: + case DVFUNC: + if (!obj->u.func.linkname) + obj->u.func.linkname = CMangler_FunctionLinkName(obj); + return obj->u.func.linkname; + case DDATA: + if (!obj->u.data.linkname) + obj->u.data.linkname = CMangler_DataLinkName(obj); + return obj->u.data.linkname; + case DINLINEFUNC: + return CMangler_FunctionLinkName(obj); + case DLOCAL: + case DABSOLUTE: + case DLABEL: + return obj->name; + case DNONLAZYPTR: + if (!obj->u.toc.linkname) + obj->u.toc.linkname = CMangler_DataLinkName(obj); + return obj->u.toc.linkname; + default: + CError_FATAL(1110); + return NULL; + } +} diff --git a/compiler_and_linker/FrontEnd/C/CParser.c b/compiler_and_linker/FrontEnd/C/CParser.c new file mode 100644 index 0000000..b089e47 --- /dev/null +++ b/compiler_and_linker/FrontEnd/C/CParser.c @@ -0,0 +1,3477 @@ +#include "compiler/CParser.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/CInit.h" +#include "compiler/CInline.h" +#include "compiler/CInt64.h" +#include "compiler/CIRTransform.h" +#include "compiler/CMachine.h" +#include "compiler/CMangler.h" +#include "compiler/CObjC.h" +#include "compiler/CPrep.h" +#include "compiler/CPrepTokenizer.h" +#include "compiler/CScope.h" +#include "compiler/CSOM.h" +#include "compiler/CTemplateNew.h" +#include "compiler/CTemplateTools.h" +#include "compiler/CodeGen.h" +#include "compiler/CompilerTools.h" +#include "../Optimizer/IrOptimizer.h" +#include "../Optimizer/IroPointerAnalysis.h" +#include "compiler/ObjGenMachO.h" +#include "compiler/objects.h" +#include "compiler/scopes.h" +#include "compiler/templates.h" +#include "cos.h" + +FileOffsetInfo cparser_fileoffset; +TStreamElement symdecltoken; +ParserTryBlock *trychain; +Boolean inassembler; +Boolean dont_set_references; +TypeStruct ptmstruct; +TypeStruct catchinfostruct; +Boolean in_assembler; +Boolean illegalimplicitconversion; +Boolean in_func_arglist; +NameSpaceName *newp_fobj; +NameSpaceName *newa_fobj; +NameSpaceName *delp_fobj; +NameSpaceName *dela_fobj; +Object *newh_func; +Object *delh_func; +Object *copy_func; +Object *clear_func; +Object *Rgtid_func; +Object *Rdync_func; +Object *rt_ptmf_cast; +Object *rt_ptmf_cmpr; +Object *rt_ptmf_test; +Object *rt_ptmf_call; +Object *rt_ptmf_scall; +Object *rt_ptmf_call4; +Object *rt_ptmf_scall4; +Object *rt_ptmf_null; +Object *rt_som_new; +Object *rt_som_newcheck; +Object *rt_som_check; +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 *Xgreg_func; +Object *Xthrw_func; +Object *Xicth_func; +Object *Xecth_func; +Object *Xunex_func; +CompilerLinkerOptions copts; +GList name_mangle_list; +HashNameNode *no_name_node; +HashNameNode *temp_argument_name; +HashNameNode *this_name_node; +HashNameNode *self_name_node; +HashNameNode *vptr_name_node; +CallbackAction *callbackactions; +Boolean fatalerrors; +Boolean anyerrors; +jmp_buf errorreturn; +static HashNameNode *uniquenamespacename; +static SInt32 uniqueid; + +struct ClassAction { + struct ClassAction *next; + TypeClass *tclass; +}; +static struct ClassAction *cparser_classactions; + +struct ParentCleanup { + struct ParentCleanup *next; + TypeClass *tclass; +}; +static struct ParentCleanup *cparser_parentcleanup; + +struct SFuncList { + struct SFuncList *next; + Object *func; + Object *obj; + ENode *expr; +}; +static struct SFuncList *cparser_sfunclist; + +char string[256]; +SInt32 compilererrornum; +SInt32 compilererrfile; +SInt32 compilererrline; + +Type sttemplexpr = {TYPETEMPLDEPEXPR, 0}; +Type stillegal = {TYPEILLEGAL, 1}; +Type stvoid = {TYPEVOID, 0}; +TypePointer void_ptr = {TYPEPOINTER, 0, &stvoid, 0}; +TypeFunc rt_func = {TYPEFUNC, 0, NULL, NULL, &stvoid, 0, 0}; + +// forward declarations +static void CParser_ParseDeclaration(DeclInfo *di); + +Object *CParser_NewRTFunc(Type *rettype, HashNameNode *name, Boolean flag, int argcount, ...) { + Object *obj; + FuncArg *args; + FuncArg *arg; + TypeFunc *tfunc; + va_list va; + + args = NULL; + if (argcount) { + va_start(va, argcount); + while (--argcount >= 0) { + if (args) { + arg->next = CParser_NewFuncArg(); + arg = arg->next; + } else { + arg = CParser_NewFuncArg(); + args = arg; + } + arg->type = va_arg(va, Type *); + } + va_end(va); + } + + obj = CParser_NewFunctionObject(NULL); + + tfunc = galloc(sizeof(TypeFunc)); + memclrw(tfunc, sizeof(TypeFunc)); + tfunc->type = TYPEFUNC; + tfunc->functype = rettype; + tfunc->args = args; + CDecl_SetFuncFlags(tfunc, 0); + + obj->name = name; + obj->type = TYPE(tfunc); + if (flag == 1) + obj->qual = Q_MANGLE_NAME; + + return obj; +} + +Boolean CParser_IsPublicRuntimeObject(Object *obj) { + if (newp_fobj->first.object == OBJ_BASE(obj) && !newp_fobj->first.next) + return 1; + if (newa_fobj->first.object == OBJ_BASE(obj) && !newa_fobj->first.next) + return 1; + if (delp_fobj->first.object == OBJ_BASE(obj) && !delp_fobj->first.next) + return 1; + if (dela_fobj->first.object == OBJ_BASE(obj) && !dela_fobj->first.next) + return 1; + return CodeGen_IsPublicRuntimeObject(obj); +} + +Object *CParser_FindPublicRuntimeObject(HashNameNode *name) { + NameSpaceObjectList *list = CScope_FindName(cscope_root, name); + if (list && list->object->otype == OT_OBJECT && (!list->next || list->next->object->otype == OT_TYPETAG)) + return OBJECT(list->object); + else + return NULL; +} + +Boolean CParser_ReInitRuntimeObjects(Boolean is_precompiler) { + if (!(newp_fobj = CScope_FindNameSpaceName(cscope_root, CMangler_OperatorName(TK_NEW)))) + return 0; + if (!(newa_fobj = CScope_FindNameSpaceName(cscope_root, CMangler_OperatorName(TK_NEW_ARRAY)))) + return 0; + if (!(delp_fobj = CScope_FindNameSpaceName(cscope_root, CMangler_OperatorName(TK_DELETE)))) + return 0; + if (!(dela_fobj = CScope_FindNameSpaceName(cscope_root, CMangler_OperatorName(TK_DELETE_ARRAY)))) + return 0; + + newh_func->name = GetHashNameNodeExport("__new_hdl"); + delh_func->name = GetHashNameNodeExport("__del_hdl"); + copy_func->name = GetHashNameNodeExport("__copy"); + clear_func->name = GetHashNameNodeExport("__clear"); + Rgtid_func->name = GetHashNameNodeExport("__get_typeid"); + Rdync_func->name = GetHashNameNodeExport("__dynamic_cast"); + rt_ptmf_cast->name = GetHashNameNodeExport("__ptmf_cast"); + rt_ptmf_cmpr->name = GetHashNameNodeExport("__ptmf_cmpr"); + rt_ptmf_test->name = GetHashNameNodeExport("__ptmf_test"); + rt_ptmf_call->name = GetHashNameNodeExport("__ptmf_call"); + rt_ptmf_scall->name = GetHashNameNodeExport("__ptmf_scall"); + rt_ptmf_call4->name = GetHashNameNodeExport("__ptmf_call4"); + rt_ptmf_scall4->name = GetHashNameNodeExport("__ptmf_scall4"); + rt_ptmf_null->name = GetHashNameNodeExport("__ptmf_null"); + rt_som_new->name = GetHashNameNodeExport("__som_new"); + rt_som_newcheck->name = GetHashNameNodeExport("__som_check_new"); + rt_som_check->name = GetHashNameNodeExport("__som_check_ev"); + rt_som_glue1->name = GetHashNameNodeExport("_som_ptrgl4"); + rt_som_glue2->name = GetHashNameNodeExport("_som_ptrgl5"); + rt_som_glue3->name = GetHashNameNodeExport("_som_ptrgl_"); + carr_func->name = GetHashNameNodeExport("__construct_array"); + cnar_func->name = GetHashNameNodeExport("__construct_new_array"); + darr_func->name = GetHashNameNodeExport("__destroy_arr"); + dnar_func->name = GetHashNameNodeExport("__destroy_new_array"); + dnar3_func->name = GetHashNameNodeExport("__destroy_new_array3"); + Xgreg_func->name = GetHashNameNodeExport("__register_global_object"); + Xthrw_func->name = GetHashNameNodeExport("__throw"); + Xicth_func->name = GetHashNameNodeExport("__init__catch"); + Xecth_func->name = GetHashNameNodeExport("__end__catch"); + Xunex_func->name = GetHashNameNodeExport("__unexpected"); + + CMangler_Setup(); + + no_name_node = GetHashNameNodeExport("@no_name@"); + temp_argument_name = GetHashNameNodeExport("@temp_ptr@"); + this_name_node = GetHashNameNodeExport("this"); + self_name_node = GetHashNameNodeExport("self"); + vptr_name_node = GetHashNameNodeExport("__vptr$"); + + CSOM_Setup(is_precompiler); + return CodeGen_ReInitRuntimeObjects(is_precompiler); +} + +static void CParser_SetupRuntimeObjects(void) { + ExceptSpecList *exspecs; + Type *sizet; + Object *func; + + exspecs = galloc(sizeof(ExceptSpecList)); + memclrw(exspecs, sizeof(ExceptSpecList)); + + sizet = CABI_GetSizeTType(); + + func = CParser_NewRTFunc( + TYPE(&void_ptr), CMangler_OperatorName(TK_NEW), 1, + 1, sizet); + CScope_AddGlobalObject(func); + + func = CParser_NewRTFunc( + TYPE(&void_ptr), CMangler_OperatorName(TK_NEW_ARRAY), 1, + 1, sizet); + CScope_AddGlobalObject(func); + + func = CParser_NewRTFunc( + TYPE(&stvoid), CMangler_OperatorName(TK_DELETE), 1, + 1, &void_ptr); + CError_ASSERT(379, IS_TYPE_FUNC(func->type)); + TYPE_FUNC(func->type)->exspecs = exspecs; + CScope_AddGlobalObject(func); + + func = CParser_NewRTFunc( + TYPE(&stvoid), CMangler_OperatorName(TK_DELETE_ARRAY), 1, + 1, &void_ptr); + CError_ASSERT(387, IS_TYPE_FUNC(func->type)); + TYPE_FUNC(func->type)->exspecs = exspecs; + CScope_AddGlobalObject(func); + + newh_func = CParser_NewRTFunc( + TYPE(&void_ptr), NULL, 0, + 1, sizet); + delh_func = CParser_NewRTFunc( + TYPE(&stvoid), NULL, 0, + 1, &void_ptr); + + Rgtid_func = CParser_NewRTFunc( + TYPE(&void_ptr), NULL, 0, + 2, &void_ptr, &stsignedlong); + Rdync_func = CParser_NewRTFunc( + TYPE(&void_ptr), NULL, 0, + 5, &void_ptr, &stsignedlong, &void_ptr, &void_ptr, &stsignedshort); + + copy_func = CParser_NewRTFunc( + TYPE(&void_ptr), NULL, 2, + 3, &void_ptr, &void_ptr, sizet); + clear_func = CParser_NewRTFunc( + TYPE(&void_ptr), NULL, 2, + 2, &void_ptr, sizet); + + rt_ptmf_cast = CParser_NewRTFunc( + TYPE(&void_ptr), NULL, 2, + 3, &stsignedlong, &void_ptr, &void_ptr); + rt_ptmf_cmpr = CParser_NewRTFunc( + TYPE(&stsignedlong), NULL, 2, + 2, &void_ptr, &void_ptr); + rt_ptmf_test = CParser_NewRTFunc( + TYPE(&stsignedlong), NULL, 2, + 1, &void_ptr); + + rt_ptmf_call = CParser_NewRTFunc(TYPE(&stvoid), NULL, 2, 0); + rt_ptmf_scall = CParser_NewRTFunc(TYPE(&stvoid), NULL, 2, 0); + rt_ptmf_call4 = CParser_NewRTFunc(TYPE(&stvoid), NULL, 2, 0); + rt_ptmf_scall4 = CParser_NewRTFunc(TYPE(&stvoid), NULL, 2, 0); + + rt_ptmf_null = CParser_NewGlobalDataObject(NULL); + rt_ptmf_null->type = &stvoid; + + rt_som_new = CParser_NewRTFunc( + TYPE(&void_ptr), NULL, 2, + 3, &void_ptr, &stsignedlong, &stsignedlong); + rt_som_newcheck = CParser_NewRTFunc( + TYPE(&stvoid), NULL, 0, + 1, &void_ptr); + rt_som_check = CParser_NewRTFunc( + TYPE(&stvoid), NULL, 0, + 1, &void_ptr); + rt_som_glue1 = CParser_NewRTFunc(TYPE(&stvoid), NULL, 2, 0); + rt_som_glue2 = CParser_NewRTFunc(TYPE(&stvoid), NULL, 2, 0); + rt_som_glue3 = CParser_NewRTFunc(TYPE(&stvoid), NULL, 2, 0); + + carr_func = CParser_NewRTFunc( + TYPE(&stvoid), NULL, 0, + 5, &void_ptr, &void_ptr, &void_ptr, sizet, sizet); + cnar_func = CParser_NewRTFunc( + TYPE(&void_ptr), NULL, 0, + 5, &void_ptr, &void_ptr, &void_ptr, sizet, sizet); + darr_func = CParser_NewRTFunc( + TYPE(&stvoid), NULL, 0, + 4, &void_ptr, &void_ptr, sizet, sizet); + dnar_func = CParser_NewRTFunc( + TYPE(&stvoid), NULL, 0, + 2, &void_ptr, &void_ptr); + dnar3_func = CParser_NewRTFunc( + TYPE(&stvoid), NULL, 0, + 4, &void_ptr, &void_ptr, &void_ptr, &stsignedshort); + + Xgreg_func = CParser_NewRTFunc( + TYPE(&void_ptr), NULL, 0, + 3, &void_ptr, &void_ptr, &void_ptr); + Xthrw_func = CParser_NewRTFunc( + TYPE(&stvoid), NULL, 0, + 3, &void_ptr, &void_ptr, &void_ptr); + Xicth_func = CParser_NewRTFunc( + TYPE(&stvoid), NULL, 0, + 1, &void_ptr); + Xecth_func = CParser_NewRTFunc( + TYPE(&stvoid), NULL, 0, + 1, &void_ptr); + Xunex_func = CParser_NewRTFunc( + TYPE(&stvoid), NULL, 0, + 1, &void_ptr); + + CodeGen_SetupRuntimeObjects(); + CError_ASSERT(534, CParser_ReInitRuntimeObjects(0)); +} + +void CParser_Setup(void) { + CScope_Setup(); + + name_mangle_list.data = NULL; + if (InitGList(&name_mangle_list, 256)) + CError_NoMem(); + + void_ptr.size = 4; + CError_Init(); + CInit_Init(); + CClass_Init(); + CIRTrans_Setup(); + CObjC_Setup(); + CInline_Init(); + + in_assembler = 0; + in_func_arglist = 0; + CParser_SetUniqueID(1); + dont_set_references = 0; + + copts.sideeffects = 1; + cparser_classactions = NULL; + name_obj_check = NULL; + callbackactions = NULL; + init_expressions = NULL; + cparser_sfunclist = NULL; + trychain = NULL; + cparser_parentcleanup = NULL; + + memclrw(&cparser_fileoffset, sizeof(FileOffsetInfo)); + + memclrw(&catchinfostruct, sizeof(TypeStruct)); + catchinfostruct.type = TYPESTRUCT; + catchinfostruct.size = 24; + catchinfostruct.stype = STRUCT_TYPE_STRUCT; + catchinfostruct.align = 4; + + memclrw(&ptmstruct, sizeof(TypeStruct)); + ptmstruct.type = TYPESTRUCT; + ptmstruct.size = 12; + ptmstruct.stype = STRUCT_TYPE_STRUCT; + ptmstruct.align = 4; + + CMach_Configure(); + CTempl_Setup(); + + uniquenamespacename = NULL; + disallowgreaterthan = 0; + + CParser_SetupRuntimeObjects(); +} + +void CParser_Cleanup(void) { + CTempl_Cleanup(); + CIRTrans_Cleanup(); + CObjC_Cleanup(); + CScope_Cleanup(); + FreeGList(&name_mangle_list); +} + +short GetPrec(short token) { + switch (token) { + case '%': + case '*': + case '/': + return 11; + case '+': + case '-': + return 10; + case TK_SHL: + case TK_SHR: + return 9; + case '<': + case '>': + case TK_LESS_EQUAL: + case TK_GREATER_EQUAL: + return 8; + case TK_LOGICAL_EQ: + case TK_LOGICAL_NE: + return 7; + case '&': + return 6; + case '^': + return 5; + case '|': + return 4; + case TK_LOGICAL_AND: + return 3; + case TK_LOGICAL_OR: + return 2; + default: + return 0; + } +} + +Boolean CParser_ParseOperatorName(short *token, Boolean flag1, Boolean flag2) { + HashNameNode *name; + + switch ((tk = lex())) { + case TK_NEW: + case TK_DELETE: + if (lookahead() == '[') { + lex(); + if (lex() != ']') + CError_Error(CErrorStr125); + //if (tk == TK_NEW) + // tk = TK_NEW_ARRAY; + //else + // tk = TK_DELETE_ARRAY; + tk = (tk == TK_NEW) ? TK_NEW_ARRAY : TK_DELETE_ARRAY; + } + break; + case '(': + if ((tk = lex()) != ')') { + CError_Error(CErrorStr204); + return 0; + } + tk = '('; + break; + case '[': + if ((tk = lex()) != ']') { + CError_Error(CErrorStr204); + return 0; + } + tk = '['; + break; + } + + if ((name = CMangler_OperatorName(tk))) { + if (token) + *token = tk; + tk = lex(); + tkidentifier = name; + return 1; + } + + if (flag1) { + if (flag2) { + DeclInfo declinfo; + memclrw(&declinfo, sizeof(DeclInfo)); + conversion_type_name(&declinfo); + tkidentifier = CMangler_ConversionFuncName(declinfo.thetype, declinfo.qual); + } + if (token) + *token = 0; + return 1; + } else { + CError_Error(CErrorStr204); + return 0; + } +} + +SInt32 CParser_GetUniqueID(void) { + return uniqueid++; +} + +void CParser_PrintUniqueID(char *buf) { + SInt32 id; + char mybuf[16]; + char *ptr; + + ptr = mybuf; + id = CParser_GetUniqueID(); + while (id) { + *(ptr++) = '0' + (id - ((id / 10) * 10)); + id = id / 10; + } + + while (ptr > mybuf) + *(buf++) = *(--ptr); + + *buf = 0; +} + +void CParser_SetUniqueID(SInt32 id) { + uniqueid = id; +} + +HashNameNode *CParser_GetUniqueName(void) { + char buf[20]; + buf[0] = '@'; + CParser_PrintUniqueID(buf + 1); + return GetHashNameNodeExport(buf); +} + +HashNameNode *CParser_NameConcat(const char *a, const char *b) { + char mybuf[256]; + char *buf; + char *dst; + int len; + + len = strlen(a) + strlen(b); + if (len > (sizeof(mybuf) - 1)) { + buf = lalloc(len + 1); + dst = buf; + } else { + buf = mybuf; + dst = buf; + } + + while (*a) + *(dst++) = *(a++); + while (*b) + *(dst++) = *(b++); + *dst = 0; + + return GetHashNameNodeExport(buf); +} + +HashNameNode *CParser_AppendUniqueName(char *prefix) { + char buf[256]; + char *dst; + int i; + + dst = buf; + for (i = 0; *prefix && i < 240; i++) { + *(dst++) = *(prefix++); + } + *(dst++) = '$'; + + CParser_PrintUniqueID(dst); + return GetHashNameNodeExport(buf); +} + +HashNameNode *CParser_AppendUniqueNameFile(char *prefix) { + Str255 filename; + char buf[256]; + char *src; + char *dst; + char c; + int i; + int j; + int len; + + dst = buf; + for (i = 0; *prefix && i < 200; i++) { + *(dst++) = *(prefix++); + } + *(dst++) = '$'; + + CParser_PrintUniqueID(dst); + + while (*dst) { + dst++; + i++; + } + + COS_FileGetFSSpecInfo(&cparamblkptr->sourcefile, NULL, NULL, filename); + src = (char *) &filename[1]; + len = filename[0]; + for (j = 0; j < len && i < 255; j++, i++) { + c = *(src++); + if (!(c >= 'a' && c <= 'z') && !(c >= 'A' && c <= 'Z') && !(c >= '0' && c <= '9')) + c = '_'; + *(dst++) = c; + } + + dst[0] = 0; + return GetHashNameNodeExport(buf); +} + +static HashNameNode *CParser_GetUnnamedNameSpaceName(void) { + Str255 filename; + char buf[256]; + char *src; + char *dst; + char c; + int i; + int len; + + if (!uniquenamespacename) { + strcpy(buf, "@unnamed@"); + dst = buf + strlen(buf); + + COS_FileGetFSSpecInfo(&cparamblkptr->sourcefile, NULL, NULL, filename); + src = (char *) &filename[1]; + len = filename[0]; + for (i = 0; i < len && dst < &buf[254]; i++) { + c = *(src++); + if (!(c >= 'a' && c <= 'z') && !(c >= 'A' && c <= 'Z') && !(c >= '0' && c <= '9')) + c = '_'; + *(dst++) = c; + } + + dst[0] = '@'; + dst[1] = 0; + uniquenamespacename = GetHashNameNodeExport(buf); + } + + return uniquenamespacename; +} + +Boolean IsTempName(HashNameNode *name) { + return !name || (name->name[0] == '@') || (name->name[0] == '$'); +} + +static void CParser_SetCFMFlags(Object *object, DeclInfo *declinfo) { + if (declinfo && declinfo->exportflags) + object->flags |= declinfo->exportflags; + + if (object->datatype == DDATA) { + if (copts.cfm_export) + object->flags = object->flags | OBJECT_EXPORT; + if (copts.cfm_internal) + object->flags = object->flags | OBJECT_INTERNAL; + } else if (copts.cfm_internal) { + object->flags = object->flags | OBJECT_INTERNAL; + } else { + if (copts.cfm_import) + object->flags = object->flags | OBJECT_IMPORT; + if (copts.cfm_export) + object->flags = object->flags | OBJECT_EXPORT; + if (copts.cfm_lib_export) + object->flags = object->flags | OBJECT_IMPORT | OBJECT_EXPORT; + } +} + +void CParser_UpdateObject(Object *object, DeclInfo *declinfo) { + if (declinfo && declinfo->section) + object->section = declinfo->section; + + CParser_SetCFMFlags(object, declinfo); + CodeGen_UpdateObject(object); +} + +Object *CParser_NewObject(DeclInfo *declinfo) { + Object *object = galloc(sizeof(Object)); + memclrw(object, sizeof(Object)); + CParser_SetCFMFlags(object, declinfo); + object->otype = OT_OBJECT; + object->access = ACCESSPUBLIC; + object->section = SECT_DEFAULT; + return object; +} + +Object *CParser_NewLocalDataObject(DeclInfo *declinfo, Boolean add_to_locals) { + Object *object = lalloc(sizeof(Object)); + memclrw(object, sizeof(Object)); + object->otype = OT_OBJECT; + object->access = ACCESSPUBLIC; + object->datatype = DLOCAL; + + if (declinfo) { + object->type = declinfo->thetype; + object->name = declinfo->name; + object->qual = declinfo->qual; + object->sclass = declinfo->storageclass; + } + + if (add_to_locals) { + ObjectList *list = lalloc(sizeof(ObjectList)); + list->object = object; + list->next = locals; + locals = list; + } + + return object; +} + +Object *CParser_NewGlobalDataObject(DeclInfo *declinfo) { + Object *object = galloc(sizeof(Object)); + memclrw(object, sizeof(Object)); + object->otype = OT_OBJECT; + object->access = ACCESSPUBLIC; + object->section = SECT_DEFAULT; + object->datatype = DDATA; + object->nspace = cscope_current; + + if (declinfo) { + object->type = declinfo->thetype; + object->name = declinfo->name; + object->qual = declinfo->qual; + object->sclass = declinfo->storageclass; + if (copts.cplusplus && !declinfo->is_extern_c) + object->qual |= Q_MANGLE_NAME; + } + + CParser_UpdateObject(object, declinfo); + return object; +} + +Object *CParser_NewCompilerDefDataObject(void) { + Object *object = galloc(sizeof(Object)); + memclrw(object, sizeof(Object)); + object->otype = OT_OBJECT; + object->access = ACCESSPUBLIC; + object->section = SECT_DEFAULT; + object->datatype = DDATA; + object->nspace = cscope_root; + + return object; +} + +Object *CParser_NewFunctionObject(DeclInfo *declinfo) { + Object *object = galloc(sizeof(Object)); + memclrw(object, sizeof(Object)); + object->otype = OT_OBJECT; + object->access = ACCESSPUBLIC; + object->section = SECT_DEFAULT; + object->datatype = DFUNC; + object->nspace = cscope_current; + + if (declinfo) { + object->type = declinfo->thetype; + object->name = declinfo->name; + object->qual = declinfo->qual; + object->sclass = declinfo->storageclass; + if (copts.cplusplus && !declinfo->is_extern_c) + object->qual |= Q_MANGLE_NAME; + } + + CParser_UpdateObject(object, declinfo); + return object; +} + +Object *CParser_NewCompilerDefFunctionObject(void) { + Object *object = galloc(sizeof(Object)); + memclrw(object, sizeof(Object)); + object->otype = OT_OBJECT; + object->access = ACCESSPUBLIC; + object->section = SECT_DEFAULT; + object->datatype = DFUNC; + object->nspace = cscope_root; + return object; +} + +Object *CParser_NewAliasObject(Object *object, SInt32 offset) { + Object *alias = galloc(sizeof(Object)); + *alias = *object; + alias->datatype = DALIAS; + alias->u.alias.object = object; + alias->u.alias.member = NULL; + alias->u.alias.offset = offset; + CScope_AddObject(cscope_current, alias->name, OBJ_BASE(alias)); + return alias; +} + +FuncArg *CParser_NewFuncArg(void) { + FuncArg *arg = galloc(sizeof(FuncArg)); + memclrw(arg, sizeof(FuncArg)); + return arg; +} + +Type *atomtype(void) { + switch (tksize) { + default: + CError_FATAL(1145); + case ATOM_VOID: return &stvoid; + case ATOM_CHAR: return TYPE(&stchar); + case ATOM_WCHAR: return TYPE(&stwchar); + case ATOM_UCHAR: return TYPE(&stunsignedchar); + case ATOM_SHORT: return TYPE(&stsignedshort); + case ATOM_USHORT: return TYPE(&stunsignedshort); + case ATOM_INT: return TYPE(&stsignedint); + case ATOM_UINT: return TYPE(&stunsignedint); + case ATOM_LONG: return TYPE(&stsignedlong); + case ATOM_ULONG: return TYPE(&stunsignedlong); + case ATOM_LONGLONG: return TYPE(&stsignedlonglong); + case ATOM_ULONGLONG: return TYPE(&stunsignedlonglong); + case ATOM_FLOAT: return TYPE(&stfloat); + case ATOM_SHORTDOUBLE: return TYPE(&stshortdouble); + case ATOM_DOUBLE: return TYPE(&stdouble); + case ATOM_LONGDOUBLE: return TYPE(&stlongdouble); + } +} + +Object *CParser_FindDeallocationObject(Type *type, FuncArg *args, Boolean flag1, Boolean flag2, Boolean *outflag) { + NameSpaceObjectList *list; + NameSpaceObjectList *scan; + NameSpaceObjectList mylist; + NameResult pr; + Boolean first_time; + Boolean retry_flag; + Object *obj; + Type *sizet; + + list = NULL; + *outflag = 0; + if (IS_TYPE_CLASS(type) && !flag2) { + HashNameNode *name; + name = (flag1 && copts.array_new_delete) ? dela_fobj->name : delp_fobj->name; + if (CScope_FindClassMemberObject(TYPE_CLASS(type), &pr, name)) { + if (pr.obj_10) { + mylist.next = NULL; + mylist.object = pr.obj_10; + list = &mylist; + } else { + CError_ASSERT(1202, pr.nsol_14); + list = pr.nsol_14; + } + } else if (TYPE_CLASS(type)->flags & CLASS_HANDLEOBJECT) { + CError_ASSERT(1210, !args && !flag1); + return delh_func; + } + } + + first_time = 1; + retry_flag = flag1; + while (1) { + if (!args) { + for (scan = list; scan; scan = scan->next) { + obj = OBJECT(scan->object); + if ( + obj->otype == OT_OBJECT && + IS_TYPE_FUNC(obj->type) && + TYPE_FUNC(obj->type)->args && + !TYPE_FUNC(obj->type)->args->next && + is_typesame(TYPE_FUNC(obj->type)->args->type, TYPE(&void_ptr)) + ) + return obj; + } + + CError_ASSERT(1231, first_time); + + sizet = CABI_GetSizeTType(); + for (scan = list; scan; scan = scan->next) { + obj = OBJECT(scan->object); + if ( + obj->otype == OT_OBJECT && + IS_TYPE_FUNC(obj->type) && + TYPE_FUNC(obj->type)->args && + TYPE_FUNC(obj->type)->args->next && + !TYPE_FUNC(obj->type)->args->next->next && + is_typesame(TYPE_FUNC(obj->type)->args->type, TYPE(&void_ptr)) && + TYPE_FUNC(obj->type)->args->next->type == sizet + ) { + *outflag = 1; + return obj; + } + } + } else { + for (scan = list; scan; scan = scan->next) { + obj = OBJECT(scan->object); + if ( + obj->otype == OT_OBJECT && + IS_TYPE_FUNC(obj->type) && + TYPE_FUNC(obj->type)->args && + TYPE_FUNC(obj->type)->args->next && + is_arglistsame(TYPE_FUNC(obj->type)->args->next, args) + ) { + *outflag = 1; + return obj; + } + } + + if (!first_time) + return NULL; + } + + if (list) + CError_Warning(CErrorStr375, type, 0); + + list = (retry_flag && copts.array_new_delete) ? &dela_fobj->first : &delp_fobj->first; + first_time = 0; + } +} + +static Boolean oldstylecompatible(FuncArg *arg) { + if (copts.ignore_oldstyle) + return 1; + + while (arg) { + if (arg == &elipsis) + return 0; + switch (arg->type->type) { + case TYPEINT: + if (TYPE_INTEGRAL(arg->type)->integral < IT_INT) + return 0; + break; + case TYPEFLOAT: + if (TYPE_INTEGRAL(arg->type)->integral < IT_DOUBLE) + return 0; + break; + } + arg = arg->next; + } + + return 1; +} + +static Boolean is_arglistequal(FuncArg *a, FuncArg *b) { + if (a == &oldstyle) { + if (b == &oldstyle) + return 1; + else + return oldstylecompatible(b); + } else { + if (b == &oldstyle) + return oldstylecompatible(a); + } + + while (1) { + if (a == &elipsis || b == &elipsis) + return 1; + + if (!a) + return !b; + if (!b) + return 0; + + if (copts.mpwc_relax && !copts.cplusplus) { + if (!is_typeequal(a->type, b->type)) + return 0; + } else { + if (!is_typesame(a->type, b->type)) + return 0; + } + + if (a->type->type == TYPEPOINTER && a->qual != b->qual) + return 0; + + a = a->next; + b = b->next; + } +} + +short is_memberpointerequal(Type *a, Type *b) { + FuncArg *arg_a; + FuncArg *arg_b; + + if (a->type != b->type) + return 0; + if (!IS_TYPE_FUNC(a)) + return is_typeequal(a, b); + + if (!is_typesame(TYPE_FUNC(a)->functype, TYPE_FUNC(b)->functype)) + return 0; + + if ((TYPE_FUNC(a)->flags & FUNC_CALL_CONV_MASK) != (TYPE_FUNC(b)->flags & FUNC_CALL_CONV_MASK)) + return 0; + + CError_ASSERT(1345, arg_a = TYPE_FUNC(a)->args); + CError_ASSERT(1346, arg_b = TYPE_FUNC(b)->args); + + if (TYPE_FUNC(a)->flags & FUNC_FLAGS_80) + CError_ASSERT(1351, arg_a = arg_a->next); + + if (TYPE_FUNC(b)->flags & FUNC_FLAGS_80) + CError_ASSERT(1355, arg_b = arg_b->next); + + if (arg_a->qual != arg_b->qual) + return 0; + + return is_arglistsame(arg_a->next, arg_b->next); +} + +short is_typeequal(Type *a, Type *b) { +restart: + if (a->type != b->type) + return 0; + switch (a->type) { + case TYPEVOID: + return 1; + case TYPEINT: + case TYPEFLOAT: + case TYPEENUM: + case TYPECLASS: + return a == b; + case TYPESTRUCT: + return a == b; + case TYPEPOINTER: + if (TYPE_POINTER(a)->target == &stvoid || TYPE_POINTER(b)->target == &stvoid) + return 1; + a = TYPE_POINTER(a)->target; + b = TYPE_POINTER(b)->target; + if (copts.mpwc_relax && !copts.cplusplus) + return 1; + goto restart; + case TYPEMEMBERPOINTER: + if (TYPE_MEMBER_POINTER(a)->ty2 != TYPE_MEMBER_POINTER(b)->ty2) + return 0; + return is_memberpointerequal(TYPE_MEMBER_POINTER(a)->ty1, TYPE_MEMBER_POINTER(b)->ty1); + case TYPEARRAY: + if (a->size && b->size && a->size != b->size) + return 0; + a = TYPE_POINTER(a)->target; + b = TYPE_POINTER(b)->target; + goto restart; + case TYPEFUNC: + if (copts.cplusplus || !copts.cpp_extensions) { + if (copts.mpwc_relax && !copts.cplusplus) { + if (!is_typeequal(TYPE_FUNC(a)->functype, TYPE_FUNC(b)->functype)) + return 0; + } else { + if (!is_typesame(TYPE_FUNC(a)->functype, TYPE_FUNC(b)->functype)) + return 0; + } + if ((TYPE_FUNC(a)->flags & FUNC_CALL_CONV_MASK) != (TYPE_FUNC(b)->flags & FUNC_CALL_CONV_MASK)) + return 0; + } + return is_arglistequal(TYPE_FUNC(a)->args, TYPE_FUNC(b)->args); + case TYPETEMPLATE: + return CTemplTool_TemplDepTypeCompare(TYPE_TEMPLATE(a), TYPE_TEMPLATE(b)); + default: + CError_FATAL(1441); + return 0; + } +} + +short iscpp_typeequal(Type *a, Type *b) { + restart: + if (a->type != b->type) + return 0; + switch (a->type) { + case TYPEVOID: + return 1; + case TYPEINT: + case TYPEFLOAT: + case TYPEENUM: + case TYPECLASS: + return a == b; + case TYPESTRUCT: + return a == b; + case TYPEPOINTER: + if (TYPE_POINTER(b)->target == &stvoid) { + if (TYPE_POINTER(a)->target == &stvoid) + return 1; + else + return -1; + } + if (TYPE_POINTER(a)->target == &stvoid) { + illegalimplicitconversion = 1; + return 0; + } + a = TYPE_POINTER(a)->target; + b = TYPE_POINTER(b)->target; + goto restart; + case TYPEMEMBERPOINTER: + if (TYPE_MEMBER_POINTER(a)->ty2 != TYPE_MEMBER_POINTER(b)->ty2) + return 0; + return is_memberpointerequal(TYPE_MEMBER_POINTER(a)->ty1, TYPE_MEMBER_POINTER(b)->ty1); + case TYPEARRAY: + if (a->size && b->size && a->size != b->size) + return 0; + a = TYPE_POINTER(a)->target; + b = TYPE_POINTER(b)->target; + goto restart; + case TYPEFUNC: + if (!is_typesame(TYPE_FUNC(a)->functype, TYPE_FUNC(b)->functype)) + return 0; + if ((TYPE_FUNC(a)->flags & FUNC_CALL_CONV_MASK) != (TYPE_FUNC(b)->flags & FUNC_CALL_CONV_MASK)) + return 0; + return is_arglistequal(TYPE_FUNC(a)->args, TYPE_FUNC(b)->args); + case TYPETEMPLATE: + return CTemplTool_TemplDepTypeCompare(TYPE_TEMPLATE(a), TYPE_TEMPLATE(b)); + default: + CError_FATAL(1500); + return 0; + } +} + +short CParser_CompareArgLists(FuncArg *a, FuncArg *b) { + Boolean r30; + + r30 = 0; + if (a == &oldstyle) { + if (b == &oldstyle) + return 1; + else + return 2; + } + if (b == &oldstyle) + return 2; + + while (1) { + if (a == &elipsis) { + if (b != &elipsis) + return 0; + break; + } + if (b == &elipsis) + return 0; + + if (a == NULL) { + if (b) + return 0; + break; + } + if (b == NULL) + return 0; + + if (a->type->type == TYPEPOINTER) { + if (IS_TYPEPOINTER_REFERENCE(TYPE_POINTER(a->type))) { + if (IS_TYPE_REFERENCE(b->type)) { + if (!is_typesame(TYPE_POINTER(a->type)->target, TYPE_POINTER(b->type)->target)) + return 0; + if ((a->qual & (Q_CONST | Q_VOLATILE)) != (b->qual & (Q_CONST | Q_VOLATILE))) + return 0; + } else { + if (!copts.old_argmatch) + return 0; + if (!is_typesame(TYPE_POINTER(a->type)->target, b->type)) + return 0; + if (b->type->type == TYPEPOINTER && (a->qual & (Q_CONST | Q_VOLATILE)) != (b->qual & (Q_CONST | Q_VOLATILE))) + return 0; + r30 = 1; + } + } else { + if (b->type->type == TYPEPOINTER) { + if (IS_TYPEPOINTER_REFERENCE(TYPE_POINTER(b->type))) { + if (!copts.old_argmatch) + return 0; + if (!is_typesame(a->type, TYPE_POINTER(b->type)->target)) + return 0; + if (a->type->type == TYPEPOINTER && (a->qual & (Q_CONST | Q_VOLATILE)) != (b->qual & (Q_CONST | Q_VOLATILE))) + return 0; + r30 = 1; + } else { + if (!is_typesame(TYPE_POINTER(a->type)->target, TYPE_POINTER(b->type)->target)) + return 0; + if ((a->qual & (Q_CONST | Q_VOLATILE)) != (b->qual & (Q_CONST | Q_VOLATILE))) + return 0; + } + } else { + return 0; + } + } + } else { + if (b->type->type == TYPEPOINTER) { + if (IS_TYPEPOINTER_REFERENCE(TYPE_POINTER(b->type))) { + if (!copts.old_argmatch) + return 0; + if (!is_typesame(a->type, TYPE_POINTER(b->type)->target)) + return 0; + r30 = 1; + } else { + return 0; + } + } else { + if (!is_typesame(a->type, b->type)) + return 0; + } + } + + a = a->next; + b = b->next; + } + + if (r30) + return 2; + return 1; +} + +Boolean is_arglistsame(FuncArg *a, FuncArg *b) { + if (a == &oldstyle) { + if (b == &oldstyle) + return 1; + else + return oldstylecompatible(b); + } else { + if (b == &oldstyle) + return oldstylecompatible(a); + } + + while (1) { + if (!a || !b || a == &elipsis || b == &elipsis) + return a == b; + + if (a->type->type == TYPEPOINTER) { + if (b->type->type != TYPEPOINTER || + (a->qual & (Q_CONST | Q_VOLATILE)) != (b->qual & (Q_CONST | Q_VOLATILE)) || + !is_typesame(TYPE_POINTER(a->type)->target, TYPE_POINTER(b->type)->target) || + IS_TYPEPOINTER_REFERENCE(TYPE_POINTER(a->type)) != IS_TYPEPOINTER_REFERENCE(TYPE_POINTER(b->type))) + return 0; + } else { + if (!is_typesame(a->type, b->type)) + return 0; + } + + a = a->next; + b = b->next; + } +} + +short is_typesame(Type *a, Type *b) { +restart: + if (a->type != b->type) { + if (IS_TYPE_TEMPLATE(a) && IS_TYPE_CLASS(b) && (TYPE_CLASS(b)->flags & CLASS_IS_TEMPL)) + return CTemplTool_IsSameTemplateType(b, a); + if (IS_TYPE_TEMPLATE(b) && IS_TYPE_CLASS(a) && (TYPE_CLASS(a)->flags & CLASS_IS_TEMPL)) + return CTemplTool_IsSameTemplateType(a, b); + return 0; + } + + switch (a->type) { + case TYPEVOID: + return 1; + case TYPEINT: + case TYPEFLOAT: + case TYPEENUM: + case TYPECLASS: + return a == b; + case TYPETEMPLATE: + return CTemplTool_TemplDepTypeCompare(TYPE_TEMPLATE(a), TYPE_TEMPLATE(b)); + case TYPESTRUCT: + return a == b; + case TYPEPOINTER: + if ((TYPE_POINTER(a)->qual & (Q_RESTRICT | Q_REFERENCE | Q_CONST | Q_VOLATILE)) != (TYPE_POINTER(b)->qual & (Q_RESTRICT | Q_REFERENCE | Q_CONST | Q_VOLATILE))) + return 0; + a = TYPE_POINTER(a)->target; + b = TYPE_POINTER(b)->target; + goto restart; + case TYPEMEMBERPOINTER: + if (!is_typesame(TYPE_MEMBER_POINTER(a)->ty2, TYPE_MEMBER_POINTER(b)->ty2)) + return 0; + if ((TYPE_MEMBER_POINTER(a)->qual & (Q_RESTRICT | Q_REFERENCE | Q_CONST | Q_VOLATILE)) != (TYPE_MEMBER_POINTER(b)->qual & (Q_RESTRICT | Q_REFERENCE | Q_CONST | Q_VOLATILE))) + return 0; + return is_memberpointerequal(TYPE_MEMBER_POINTER(a)->ty1, TYPE_MEMBER_POINTER(b)->ty1); + case TYPEARRAY: + if (a->size != b->size) + return 0; + a = TYPE_POINTER(a)->target; + b = TYPE_POINTER(b)->target; + goto restart; + case TYPEFUNC: + if (!is_typesame(TYPE_FUNC(a)->functype, TYPE_FUNC(b)->functype)) + return 0; + if (TYPE_FUNC(a)->qual != TYPE_FUNC(b)->qual) + return 0; + if ((TYPE_FUNC(a)->flags & FUNC_CALL_CONV_MASK) != (TYPE_FUNC(b)->flags & FUNC_CALL_CONV_MASK)) + return 0; + return is_arglistsame(TYPE_FUNC(a)->args, TYPE_FUNC(b)->args); + default: + CError_FATAL(1709); + return 0; + } +} + +Type *CParser_GetBoolType(void) { + if (copts.cplusplus && copts.booltruefalse) + return TYPE(&stbool); + else + return TYPE(&stsignedint); +} + +Type *CParser_GetWCharType(void) { + if (copts.cplusplus && copts.wchar_type) + return TYPE(&stwchar); + else + return TYPE(&stsignedint); +} + +short CParser_GetOperator(ENodeType t) { + switch (t) { + default: + CError_FATAL(1748); + case EMONMIN: return '-'; + case EBINNOT: return '~'; + case ELOGNOT: return '!'; + case EADD: return '+'; + case ESUB: return '-'; + case EMUL: return '*'; + case EDIV: return '/'; + case EMODULO: return '%'; + case EAND: return '&'; + case EXOR: return '^'; + case EOR: return '|'; + case ESHL: return TK_SHL; + case ESHR: return TK_SHR; + case ELESS: return '<'; + case EGREATER: return '>'; + case ELESSEQU: return TK_LESS_EQUAL; + case EGREATEREQU: return TK_GREATER_EQUAL; + case EEQU: return TK_LOGICAL_EQ; + case ENOTEQU: return TK_LOGICAL_NE; + } +} + +Boolean CParser_IsMoreCVQualified(UInt32 a, UInt32 b) { + if ((a & Q_CONST) && !(b & Q_CONST)) { + return ((a & Q_VOLATILE) || !(b & Q_VOLATILE)); + } else if ((a & Q_VOLATILE) && !(b & Q_VOLATILE)) { + return ((a & Q_CONST) || !(b & Q_CONST)); + } + return 0; +} + +Boolean CParser_IsSameOrMoreCVQualified(UInt32 a, UInt32 b) { + if ((a & (Q_CONST | Q_VOLATILE)) == (b & (Q_CONST | Q_VOLATILE))) + return 1; + + if ((a & Q_CONST) && !(b & Q_CONST)) { + return ((a & Q_VOLATILE) || !(b & Q_VOLATILE)); + } else if ((a & Q_VOLATILE) && !(b & Q_VOLATILE)) { + return ((a & Q_CONST) || !(b & Q_CONST)); + } + return 0; +} + +Boolean is_unsigned(Type *type) { + if (IS_TYPE_ENUM(type)) + type = TYPE_ENUM(type)->enumtype; + + if ( + (type == TYPE(&stunsignedchar)) || + (type == TYPE(&stunsignedshort)) || + (type == TYPE(&stunsignedint)) || + (type == TYPE(&stunsignedlong)) || + (type == TYPE(&stunsignedlonglong)) || + (type == TYPE(&stbool)) || + (copts.unsigned_char && (type == TYPE(&stchar))) || + (type->type == TYPEPOINTER)) + return 1; + + return 0; +} + +StructMember *ismember(TypeStruct *tstruct, HashNameNode *name) { + StructMember *member; + + for (member = tstruct->members; member; member = member->next) { + if (member->name == name) + return member; + } + + return NULL; +} + +void appendmember(TypeStruct *tstruct, StructMember *member) { + StructMember *last; + + if (!tstruct->members) { + tstruct->members = member; + return; + } + + for (last = tstruct->members; last->next; last = last->next) {} + last->next = member; +} + +static void CParser_InsertTryBlock(ParserTryBlock *block) { + block->cscope_current = cscope_current; + block->cscope_currentclass = cscope_currentclass; + block->cscope_currentfunc = cscope_currentfunc; + block->ctempl_curinstance = ctempl_curinstance; + block->cerror_locktoken = cerror_locktoken; + block->cscope_is_member_func = cscope_is_member_func; + block->next = trychain; + trychain = block; +} + +static void CParser_RemoveTryBlock(ParserTryBlock *block) { + cscope_current = block->cscope_current; + cscope_currentclass = block->cscope_currentclass; + cscope_currentfunc = block->cscope_currentfunc; + ctempl_curinstance = block->ctempl_curinstance; + cerror_locktoken = block->cerror_locktoken; + cscope_is_member_func = block->cscope_is_member_func; + trychain = block->next; +} + +static Boolean TryIsDeclaration(Boolean flag1, Boolean flag2, Boolean flag3, short token) { + Boolean result; + DeclInfo declinfo; + struct ParserTryBlock tryblock; + + switch (tk) { + case TK_IDENTIFIER: + case TK_COLON_COLON: + break; + case TK_VOID: + case TK_CHAR: + case TK_SHORT: + case TK_INT: + case TK_LONG: + case TK_FLOAT: + case TK_DOUBLE: + case TK_SIGNED: + case TK_UNSIGNED: + case TK_UNK_113: + case TK_UNK_114: + case TK_UNK_115: + case TK_UNK_116: + case TK_UNK_117: + case TK_UNK_118: + case TK_UNK_119: + case TK_UNK_11A: + case TK_BOOL: + case TK_WCHAR_T: + if (lookahead() != '(') + return 1; + break; + default: + return 1; + } + + result = 0; + CParser_InsertTryBlock(&tryblock); + if (setjmp(tryblock.jmpbuf) == 0) { + memclrw(&declinfo, sizeof(DeclInfo)); + CParser_GetDeclSpecs(&declinfo, 0); + if (!(IS_TYPE_TEMPLATE(declinfo.thetype) && TYPE_TEMPLATE(declinfo.thetype)->dtype == TEMPLDEP_QUALNAME && !declinfo.x53 && !declinfo.x49)) { + if (flag1) { + declinfo.x46 = flag3; + scandeclarator(&declinfo); + if (!(flag2 && declinfo.name)) { + if (!token) { + if (tk == ';' || tk == ',' || tk == '=' || tk == '(' || tk == ')' || tk == '>') + result = 1; + } else { + result = (tk == token); + } + } + } else { + result = 1; + } + } + } + + CParser_RemoveTryBlock(&tryblock); + return result; +} + +Boolean isdeclaration(UInt8 flag1, UInt8 flag2, UInt8 flag3, short token) { + SInt32 state; + + if (!(tk >= TK_AUTO && tk <= TK_BYREF) && tk != TK_COLON_COLON && !(tk == TK_IDENTIFIER && CScope_PossibleTypeName(tkidentifier))) { + if (!(tk == TK_IDENTIFIER && copts.altivec_model && !strcmp(tkidentifier->name, "vector"))) + return 0; + } else { + if (!copts.cplusplus) + return 1; + } + + CPrep_TokenStreamGetState(&state); + if (TryIsDeclaration(flag1, flag2, flag3, token)) { + CPrep_TokenStreamSetCurState(&state); + return 1; + } else { + CPrep_TokenStreamSetCurState(&state); + return 0; + } +} + +Boolean islookaheaddeclaration(void) { + SInt32 state; + + CPrep_TokenStreamGetState(&state); + tk = lex(); + if (!(tk >= TK_AUTO && tk <= TK_BYREF) && tk != TK_COLON_COLON && !(tk == TK_IDENTIFIER && CScope_PossibleTypeName(tkidentifier))) { + if (!(tk == TK_IDENTIFIER && copts.altivec_model && !strcmp(tkidentifier->name, "vector"))) { + CPrep_TokenStreamSetCurState(&state); + return 0; + } + } else { + if (!copts.cplusplus) { + CPrep_TokenStreamSetCurState(&state); + return 1; + } + } + + if (TryIsDeclaration(1, 1, 0, ')')) { + CPrep_TokenStreamSetCurState(&state); + return 1; + } else { + CPrep_TokenStreamSetCurState(&state); + return 0; + } +} + +Type *CParser_ParseTypeID(UInt32 *qual, Boolean *flag) { + SInt32 state; + DeclInfo di; + struct ParserTryBlock tryblock; + + memclrw(&di, sizeof(DeclInfo)); + CPrep_TokenStreamGetState(&state); + CParser_InsertTryBlock(&tryblock); + + if (setjmp(tryblock.jmpbuf) == 0) { + if (copts.cplusplus) + di.x55 = 1; + + if (flag) { + di.x56 = 1; + *flag = 0; + } + + CParser_GetDeclSpecs(&di, 0); + if (di.x57 && IS_TYPE_CLASS(di.thetype) && (TYPE_CLASS(di.thetype)->flags & CLASS_IS_TEMPL)) { + CParser_RemoveTryBlock(&tryblock); + *qual = di.qual; + *flag = 1; + return di.thetype; + } + + if (flag && IS_TYPE_TEMPLATE(di.thetype) && TYPE_TEMPLATE(di.thetype)->dtype == TEMPLDEP_ARGUMENT && + TYPE_TEMPLATE(di.thetype)->u.pid.type == TPT_TEMPLATE) { + CParser_RemoveTryBlock(&tryblock); + *qual = di.qual; + *flag = 1; + return di.thetype; + } + + scandeclarator(&di); + if (!di.name) { + CParser_RemoveTryBlock(&tryblock); + *qual = di.qual; + return di.thetype; + } + } + + CPrep_TokenStreamSetCurState(&state); + CParser_RemoveTryBlock(&tryblock); + return 0; +} + +Boolean CParser_TryFuncDecl(void) { + Boolean result; + SInt32 state; + DeclInfo di; + struct ParserTryBlock tryblock; + + result = 0; + CPrep_TokenStreamGetState(&state); + CParser_InsertTryBlock(&tryblock); + + if (setjmp(tryblock.jmpbuf) == 0) { + memclrw(&di, sizeof(DeclInfo)); + di.thetype = &stvoid; + scandeclarator(&di); + + if (IS_TYPE_FUNC(di.thetype)) + result = 1; + } + + CParser_RemoveTryBlock(&tryblock); + CPrep_TokenStreamSetCurState(&state); + return result; +} + +Boolean CParser_TryParamList(Boolean flag) { + Boolean result; + SInt32 state; + struct ParserTryBlock tryblock; + + result = 0; + CPrep_TokenStreamGetState(&state); + + switch ((tk = lex())) { + case ')': + case TK_ELLIPSIS: + result = 1; + break; + default: + CParser_InsertTryBlock(&tryblock); + if (setjmp(tryblock.jmpbuf) == 0) { + if (CFunc_ParseFakeArgList(flag) || tk == ')') + result = 1; + } + CParser_RemoveTryBlock(&tryblock); + break; + } + + CPrep_TokenStreamSetCurState(&state); + return result; +} + +Type *CParser_RemoveTopMostQualifiers(Type *type, UInt32 *qual) { + switch (type->type) { + case TYPEARRAY: + TYPE_POINTER(type)->target = CParser_RemoveTopMostQualifiers(TYPE_POINTER(type)->target, qual); + return type; + case TYPEPOINTER: + if (TYPE_POINTER(type)->qual & Q_CONST) { + TypePointer *newtype = galloc(sizeof(TypePointer)); + *newtype = *TYPE_POINTER(type); + newtype->qual = 0; + return TYPE(newtype); + } + return type; + case TYPEMEMBERPOINTER: + if (TYPE_MEMBER_POINTER(type)->qual & Q_CONST) { + TypeMemberPointer *newtype = galloc(sizeof(TypeMemberPointer)); + *newtype = *TYPE_MEMBER_POINTER(type); + newtype->qual = 0; + return TYPE(newtype); + } + return type; + default: + *qual = 0; + return type; + } +} + +UInt32 CParser_GetTypeQualifiers(Type *type, UInt32 qual) { + while (IS_TYPE_ARRAY(type)) + type = TYPE_POINTER(type)->target; + + switch (type->type) { + case TYPEPOINTER: + qual = TYPE_POINTER(type)->qual; + break; + case TYPEMEMBERPOINTER: + qual = TYPE_MEMBER_POINTER(type)->qual; + break; + } + + return qual; +} + +UInt32 CParser_GetCVTypeQualifiers(Type *type, UInt32 qual) { + while (IS_TYPE_ARRAY(type)) + type = TYPE_POINTER(type)->target; + + switch (type->type) { + case TYPEPOINTER: + qual = TYPE_POINTER(type)->qual; + break; + case TYPEMEMBERPOINTER: + qual = TYPE_MEMBER_POINTER(type)->qual; + break; + } + + return qual & (Q_CONST | Q_VOLATILE); +} + +Boolean CParser_IsConst(Type *type, UInt32 qual) { + while (IS_TYPE_ARRAY(type)) + type = TYPE_POINTER(type)->target; + + switch (type->type) { + case TYPEPOINTER: + qual = TYPE_POINTER(type)->qual; + break; + case TYPEMEMBERPOINTER: + qual = TYPE_MEMBER_POINTER(type)->qual; + break; + } + + return (qual & Q_CONST) != 0; +} + +Boolean CParser_IsVolatile(Type *type, UInt32 qual) { + while (IS_TYPE_ARRAY(type)) + type = TYPE_POINTER(type)->target; + + switch (type->type) { + case TYPEPOINTER: + qual = TYPE_POINTER(type)->qual; + break; + case TYPEMEMBERPOINTER: + qual = TYPE_MEMBER_POINTER(type)->qual; + break; + } + + return (qual & Q_VOLATILE) != 0; +} + +Boolean is_const_object(Object *obj) { + return CParser_IsConst(obj->type, obj->qual); +} + +Boolean is_volatile_object(Object *obj) { + return CParser_IsVolatile(obj->type, obj->qual); +} + +Boolean CParserIsConstExpr(ENode *expr) { + return CParser_IsConst(expr->rtype, expr->flags & ENODE_FLAG_QUALS); +} + +Boolean CParserIsVolatileExpr(ENode *expr) { + return CParser_IsVolatile(expr->rtype, expr->flags & ENODE_FLAG_QUALS); +} + +Boolean CParser_HasInternalLinkage(const Object *obj) { + NameSpace *nspace; + + for (nspace = obj->nspace; nspace; nspace = nspace->parent) { + if (nspace->is_unnamed) + return 1; + } + + if (obj->datatype == DLOCAL) + return 1; + if (obj->qual & (Q_20000 | Q_WEAK)) + return 0; + if (obj->sclass == TK_STATIC) + return 1; + + // this feels *wrong* but it's the only way to match this function that I can see + if (obj->qual & Q_INLINE) + ((Object *) obj)->qual |= Q_20000; + return 0; +} + +Boolean CParser_HasInternalLinkage2(const Object *obj) { + if (obj->datatype == DLOCAL) + return 1; + if (obj->qual & (Q_20000 | Q_WEAK)) + return 0; + if (obj->sclass == TK_STATIC) + return 1; + + // this feels *wrong* but it's the only way to match this function that I can see + if (obj->qual & Q_INLINE) + ((Object *) obj)->qual |= Q_20000; + return 0; +} + +Boolean CParser_IsVirtualFunction(Object *obj, TypeClass **tclass, SInt32 *index) { + if (obj->datatype == DVFUNC) { + *tclass = TYPE_METHOD(obj->type)->theclass; + *index = TYPE_METHOD(obj->type)->vtbl_index; + return 1; + } + + return 0; +} + +Boolean is_pascal_object(Object *obj) { + return IS_TYPE_FUNC(obj->type) && (TYPE_FUNC(obj->type)->flags & FUNC_PASCAL); +} + +Boolean is_cfm_type(Type *type) { + return 0; +} + +Boolean CParser_IsVTableObject(Object *obj) { + return + obj->datatype == DDATA && + obj->nspace && + obj->nspace->theclass && + obj->nspace->theclass->vtable && + obj->nspace->theclass->vtable->object == obj; +} + +static Type *getthetype(short token, short size, short signedness) { + switch (token) { + case 0: + case TK_INT: + if (signedness == 1) { + switch (size) { + case 1: return TYPE(&stunsignedshort); + case 2: return TYPE(&stunsignedlong); + case 3: return TYPE(&stunsignedlonglong); + default: return TYPE(&stunsignedint); + } + } else { + switch (size) { + case 1: return TYPE(&stsignedshort); + case 2: return TYPE(&stsignedlong); + case 3: return TYPE(&stsignedlonglong); + default: return TYPE(&stsignedint); + } + } + case TK_BOOL: + return TYPE(&stbool); + case TK_WCHAR_T: + return TYPE(&stwchar); + case TK_CHAR: + switch (signedness) { + case 1: return TYPE(&stunsignedchar); + default: return TYPE(&stchar); + case -1: return TYPE(&stsignedchar); + } + case TK_DOUBLE: + switch (size) { + case 1: return TYPE(&stshortdouble); + case 2: return TYPE(&stlongdouble); + default: return TYPE(&stdouble); + } + case TK_FLOAT: + return TYPE(&stfloat); + case TK_VOID: + return TYPE(&stvoid); + default: + CError_Error(CErrorStr121); + return TYPE(&stvoid); + } +} + +void TypedefDeclInfo(DeclInfo *declinfo, Type *type, UInt32 qual) { + if (type->type == TYPEPOINTER) { + if (IS_TYPEPOINTER_REFERENCE(TYPE_POINTER(type))) { + declinfo->thetype = type; + declinfo->qual &= ~(Q_RESTRICT | Q_REFERENCE | Q_VOLATILE | Q_CONST); + declinfo->qual |= qual; + return; + } + + declinfo->thetype = galloc(sizeof(TypePointer)); + *TYPE_POINTER(declinfo->thetype) = *TYPE_POINTER(type); + TYPE_POINTER(declinfo->thetype)->qual |= declinfo->qual & (Q_RESTRICT | Q_REFERENCE | Q_VOLATILE | Q_CONST); + declinfo->qual &= ~(Q_RESTRICT | Q_REFERENCE | Q_VOLATILE | Q_CONST); + declinfo->qual |= qual & (Q_ALIGNED_MASK | Q_REFERENCE | Q_PASCAL | Q_VOLATILE | Q_CONST); + } else if (type->type == TYPEMEMBERPOINTER) { + declinfo->thetype = galloc(sizeof(TypeMemberPointer)); + *TYPE_MEMBER_POINTER(declinfo->thetype) = *TYPE_MEMBER_POINTER(type); + TYPE_MEMBER_POINTER(declinfo->thetype)->qual |= declinfo->qual & (Q_RESTRICT | Q_REFERENCE | Q_VOLATILE | Q_CONST); + declinfo->qual &= ~(Q_RESTRICT | Q_REFERENCE | Q_VOLATILE | Q_CONST); + declinfo->qual |= qual & (Q_ALIGNED_MASK | Q_REFERENCE | Q_PASCAL | Q_VOLATILE | Q_CONST); + } else { + declinfo->thetype = type; + declinfo->qual |= qual & (Q_ALIGNED_MASK | Q_REFERENCE | Q_PASCAL | Q_VOLATILE | Q_CONST); + if (IS_TYPE_ARRAY(declinfo->thetype) && !declinfo->thetype->size) { + declinfo->thetype = galloc(sizeof(TypePointer)); + *TYPE_POINTER(declinfo->thetype) = *TYPE_POINTER(type); + } + } + declinfo->x49 = 1; +} + +static void CParser_ParseAttributeFunctionSummary(DeclInfo *declinfo) { + Boolean flag; + + if ((tk = lex()) != '(') { + CError_Error(CErrorStr114); + return; + } + + flag = 1; + tk = lookahead(); + while (tk == TK_IDENTIFIER) { + if (flag && !strcmp(tkidentifier->name, "entry_points_to")) { + PointerAnalysis_ParseEntryPointsToSpecifier(declinfo); + } else if (!strcmp(tkidentifier->name, "exit_points_to")) { + PointerAnalysis_ParseExitPointsToSpecifier(declinfo); + flag = 0; + } else if (!strcmp(tkidentifier->name, "function_modifies")) { + PointerAnalysis_ParseFunctionModifiesSpecifier(declinfo); + flag = 0; + } else { + lex(); + CError_Error(CErrorStr121); + return; + } + + tk = lookahead(); + if (tk == ',') { + lex(); + tk = lookahead(); + } + } + + lex(); + if (tk != ')') + CError_Error(CErrorStr121); +} + +void CParser_ParseAttribute(Type *type, DeclInfo *declinfo) { + CInt64 val64; + SInt32 val; + + do { + if ((tk = lex()) != '(') { + CError_Error(CErrorStr121); + return; + } + if ((tk = lex()) != '(') { + CError_Error(CErrorStr121); + return; + } + if ((tk = lex()) != TK_IDENTIFIER && tk != TK_CONST) { + CError_Error(CErrorStr121); + return; + } + + if (!strcmp(tkidentifier->name, "aligned") || !strcmp(tkidentifier->name, "__aligned__")) { + if ((tk = lex()) != '(') { + CError_Error(CErrorStr121); + return; + } + + tk = lex(); + val64 = CExpr_IntegralConstExpr(); + switch ((val = CInt64_GetULong(&val64))) { + case 1: + case 2: + case 4: + case 8: + case 0x10: + case 0x20: + case 0x40: + case 0x80: + case 0x100: + case 0x200: + case 0x400: + case 0x800: + case 0x1000: + case 0x2000: + break; + default: + CError_Error(CErrorStr124); + return; + } + if (type) { + if (IS_TYPE_STRUCT(type)) { + if (val > TYPE_STRUCT(type)->align) { + TYPE_STRUCT(type)->align = val; + type->size += CABI_StructSizeAlignValue(type, type->size); + } + } else if (IS_TYPE_CLASS(type)) { + if (val > TYPE_CLASS(type)->align) { + TYPE_CLASS(type)->align = val; + type->size += CABI_StructSizeAlignValue(type, type->size); + } + } else { + CError_Error(CErrorStr149); + } + } else if (declinfo) { + declinfo->qual &= ~Q_ALIGNED_MASK; + switch (val) { + case 1: + declinfo->qual |= Q_ALIGNED_1; + break; + case 2: + declinfo->qual |= Q_ALIGNED_2; + break; + case 4: + declinfo->qual |= Q_ALIGNED_4; + break; + case 8: + declinfo->qual |= Q_ALIGNED_8; + break; + case 16: + declinfo->qual |= Q_ALIGNED_16; + break; + case 32: + declinfo->qual |= Q_ALIGNED_32; + break; + case 64: + declinfo->qual |= Q_ALIGNED_64; + break; + case 128: + declinfo->qual |= Q_ALIGNED_128; + break; + case 256: + declinfo->qual |= Q_ALIGNED_256; + break; + case 512: + declinfo->qual |= Q_ALIGNED_512; + break; + case 1024: + declinfo->qual |= Q_ALIGNED_1024; + break; + case 2048: + declinfo->qual |= Q_ALIGNED_2048; + break; + case 4096: + declinfo->qual |= Q_ALIGNED_4096; + break; + case 8192: + declinfo->qual |= Q_ALIGNED_8192; + break; + default: + CError_FATAL(2779); + break; + } + } else { + CError_Error(CErrorStr359); + } + + if (tk != ')') { + CError_Error(CErrorStr121); + return; + } + } else if (!strcmp(tkidentifier->name, "nothrow") || !strcmp(tkidentifier->name, "__nothrow__")) { + if (declinfo && declinfo->thetype && IS_TYPE_FUNC(declinfo->thetype)) + TYPE_FUNC(declinfo->thetype)->flags |= FUNC_NOTHROW; + else + CError_Error(CErrorStr359); + } else if (!strcmp("function_summary", tkidentifier->name)) { + CParser_ParseAttributeFunctionSummary(declinfo); + } else if (!strcmp(tkidentifier->name, "packed") || !strcmp(tkidentifier->name, "__packed__")) { + CError_Error(CErrorStr359); + } else if (!strcmp(tkidentifier->name, "unused") || !strcmp(tkidentifier->name, "__unused__")) { + } else if (!strcmp(tkidentifier->name, "noreturn") || !strcmp(tkidentifier->name, "__noreturn__")) { + } else if (tk == TK_CONST || !strcmp(tkidentifier->name, "__const__")) { + } else if (!strcmp(tkidentifier->name, "format") || !strcmp(tkidentifier->name, "__format__")) { + CError_Warning(CErrorStr359); + if ((tk = lex()) != '(') { + CError_Warning(CErrorStr114); + return; + } + tk = lex(); + if ((tk = lex()) != ',') { + CError_Warning(CErrorStr116); + return; + } + tk = lex(); + if ((tk = lex()) != ',') { + CError_Warning(CErrorStr116); + return; + } + tk = lex(); + if ((tk = lex()) != ')') { + CError_Warning(CErrorStr115); + return; + } + } else if (!strcmp(tkidentifier->name, "mode") || !strcmp(tkidentifier->name, "__mode__")) { + CError_Warning(CErrorStr359); + if ((tk = lex()) != '(') { + CError_Warning(CErrorStr114); + return; + } + tk = lex(); + if ((tk = lex()) != ')') { + CError_Warning(CErrorStr115); + return; + } + } else { + CError_Error(CErrorStr359); + } + + if ((tk = lex()) != ')') { + CError_Error(CErrorStr121); + return; + } + if ((tk = lex()) != ')') { + CError_Error(CErrorStr121); + return; + } + tk = lex(); + } while (tk == TK_UU_ATTRIBUTE_UU); +} + +static void CParser_ParseTypeOf(DeclInfo *declinfo) { + DeclInfo subdi; + ENode *expr; + + if ((tk = lex()) == '(' && islookaheaddeclaration()) { + tk = lex(); + + memclrw(&subdi, sizeof(DeclInfo)); + CParser_GetDeclSpecs(&subdi, 0); + scandeclarator(&subdi); + if (subdi.name) + CError_Error(CErrorStr121); + + if (tk != ')') + CError_ErrorSkip(CErrorStr115); + else + tk = lex(); + + TypedefDeclInfo(declinfo, subdi.thetype, subdi.qual); + } else { + expr = unary_expression(); + if (ENODE_IS(expr, EINDIRECT) && ENODE_IS(expr->data.monadic, EBITFIELD)) + CError_Error(CErrorStr144); + TypedefDeclInfo(declinfo, expr->rtype, expr->flags & ENODE_FLAG_QUALS); + } +} + +void CParser_ParseDeclSpec(DeclInfo *declinfo, Boolean flag) { + if ((tk = lex()) != TK_IDENTIFIER) { + if (tk != TK_EXPORT) + CError_Error(CErrorStr107); + else + declinfo->exportflags = declinfo->exportflags | EXPORT_FLAGS_EXPORT; + } else if (!strcmp("internal", tkidentifier->name)) { + declinfo->exportflags = declinfo->exportflags | EXPORT_FLAGS_INTERNAL; + } else if (!strcmp("import", tkidentifier->name) || !strcmp("dllimport", tkidentifier->name)) { + declinfo->exportflags = declinfo->exportflags | EXPORT_FLAGS_IMPORT; + } else if (!strcmp("export", tkidentifier->name) || !strcmp("dllexport", tkidentifier->name)) { + declinfo->exportflags = declinfo->exportflags | EXPORT_FLAGS_EXPORT; + } else if (!strcmp("lib_export", tkidentifier->name)) { + declinfo->exportflags = declinfo->exportflags | EXPORT_FLAGS_IMPORT | EXPORT_FLAGS_EXPORT; + } else if (!strcmp("weak", tkidentifier->name)) { + declinfo->qual |= Q_WEAK; + } else { + CodeGen_ParseDeclSpec(tkidentifier, declinfo); + } +} + +static int CParser_GetVectorDeclSpec(Type **type) { + tk = lex(); + switch (tk) { + case TK_CHAR: + tk = lex(); + switch (tk) { + case TK_BOOL: + *type = TYPE(&stvectorboolchar); + tk = lex(); + return 1; + case TK_UNSIGNED: + *type = TYPE(&stvectorunsignedchar); + tk = lex(); + return 1; + case TK_SIGNED: + *type = TYPE(&stvectorsignedchar); + tk = lex(); + return 1; + case TK_IDENTIFIER: + if (tkidentifier == GetHashNameNode("bool")) { + *type = TYPE(&stvectorboolchar); + tk = lex(); + return 1; + } + default: + CError_Error(CErrorStr121); + } + break; + case TK_SIGNED: + tk = lex(); + switch (tk) { + case TK_CHAR: + *type = TYPE(&stvectorsignedchar); + tk = lex(); + return 1; + case TK_SHORT: + *type = TYPE(&stvectorsignedshort); + tk = lex(); + if (tk == TK_INT) + tk = lex(); + return 1; + case TK_LONG: + *type = TYPE(&stvectorsignedlong); + tk = lex(); + if (tk == TK_INT) + tk = lex(); + return 1; + case TK_INT: + tk = lex(); + switch (tk) { + case TK_SHORT: + *type = TYPE(&stvectorsignedshort); + tk = lex(); + return 1; + case TK_LONG: + *type = TYPE(&stvectorsignedlong); + tk = lex(); + return 1; + default: + *type = TYPE(&stvectorsignedlong); + return 1; + } + default: + CError_Error(CErrorStr121); + } + break; + case TK_UNSIGNED: + tk = lex(); + switch (tk) { + case TK_CHAR: + *type = TYPE(&stvectorunsignedchar); + tk = lex(); + return 1; + case TK_SHORT: + *type = TYPE(&stvectorunsignedshort); + tk = lex(); + if (tk == TK_INT) + tk = lex(); + return 1; + case TK_LONG: + *type = TYPE(&stvectorunsignedlong); + tk = lex(); + if (tk == TK_INT) + tk = lex(); + return 1; + case TK_INT: + tk = lex(); + switch (tk) { + case TK_SHORT: + *type = TYPE(&stvectorunsignedshort); + tk = lex(); + return 1; + case TK_LONG: + *type = TYPE(&stvectorunsignedlong); + tk = lex(); + return 1; + default: + *type = TYPE(&stvectorunsignedlong); + return 1; + } + default: + CError_Error(CErrorStr121); + } + break; + case TK_BOOL: + tk = lex(); + switch (tk) { + case TK_CHAR: + *type = TYPE(&stvectorboolchar); + tk = lex(); + return 1; + case TK_SHORT: + *type = TYPE(&stvectorboolshort); + tk = lex(); + if (tk == TK_INT) + tk = lex(); + return 1; + case TK_LONG: + *type = TYPE(&stvectorboollong); + tk = lex(); + if (tk == TK_INT) + tk = lex(); + return 1; + case TK_INT: + tk = lex(); + switch (tk) { + case TK_SHORT: + *type = TYPE(&stvectorboolshort); + tk = lex(); + return 1; + case TK_LONG: + *type = TYPE(&stvectorboollong); + tk = lex(); + return 1; + default: + *type = TYPE(&stvectorboollong); + return 1; + } + default: + CError_Error(CErrorStr121); + } + break; + case TK_SHORT: + tk = lex(); + switch (tk) { + case TK_BOOL: + *type = TYPE(&stvectorboolshort); + tk = lex(); + if (tk == TK_INT) + tk = lex(); + return 1; + case TK_SIGNED: + *type = TYPE(&stvectorsignedshort); + tk = lex(); + if (tk == TK_INT) + tk = lex(); + return 1; + case TK_UNSIGNED: + *type = TYPE(&stvectorunsignedshort); + tk = lex(); + if (tk == TK_INT) + tk = lex(); + return 1; + case TK_INT: + tk = lex(); + switch (tk) { + case TK_BOOL: + *type = TYPE(&stvectorboolshort); + tk = lex(); + if (tk == TK_INT) + tk = lex(); + return 1; + case TK_SIGNED: + *type = TYPE(&stvectorsignedshort); + tk = lex(); + return 1; + case TK_UNSIGNED: + *type = TYPE(&stvectorunsignedshort); + tk = lex(); + return 1; + case TK_IDENTIFIER: + if (tkidentifier == GetHashNameNode("bool")) { + *type = TYPE(&stvectorboolshort); + tk = lex(); + if (tk == TK_INT) + tk = lex(); + return 1; + } + default: + CError_Error(CErrorStr121); + } + break; + case TK_IDENTIFIER: + if (tkidentifier == GetHashNameNode("bool")) { + *type = TYPE(&stvectorboolshort); + tk = lex(); + if (tk == TK_INT) + tk = lex(); + return 1; + } + default: + CError_Error(CErrorStr121); + } + break; + case TK_LONG: + tk = lex(); + switch (tk) { + case TK_BOOL: + *type = TYPE(&stvectorboollong); + tk = lex(); + if (tk == TK_INT) + tk = lex(); + return 1; + case TK_SIGNED: + *type = TYPE(&stvectorsignedlong); + tk = lex(); + if (tk == TK_INT) + tk = lex(); + return 1; + case TK_UNSIGNED: + *type = TYPE(&stvectorunsignedlong); + tk = lex(); + if (tk == TK_INT) + tk = lex(); + return 1; + case TK_INT: + tk = lex(); + switch (tk) { + case TK_BOOL: + *type = TYPE(&stvectorboollong); + tk = lex(); + return 1; + case TK_SIGNED: + *type = TYPE(&stvectorsignedlong); + tk = lex(); + return 1; + case TK_UNSIGNED: + *type = TYPE(&stvectorunsignedlong); + tk = lex(); + return 1; + case TK_IDENTIFIER: + if (tkidentifier == GetHashNameNode("bool")) { + *type = TYPE(&stvectorboollong); + tk = lex(); + return 1; + } + default: + CError_Error(CErrorStr121); + } + break; + case TK_IDENTIFIER: + if (tkidentifier == GetHashNameNode("bool")) { + *type = TYPE(&stvectorboollong); + tk = lex(); + if (tk == TK_INT) + tk = lex(); + return 1; + } + default: + CError_Error(CErrorStr121); + } + break; + case TK_INT: + tk = lex(); + switch (tk) { + case TK_BOOL: + tk = lex(); + switch (tk) { + case TK_SHORT: + *type = TYPE(&stvectorboolshort); + tk = lex(); + return 1; + case TK_LONG: + *type = TYPE(&stvectorboollong); + tk = lex(); + return 1; + default: + *type = TYPE(&stvectorboollong); + return 1; + } + case TK_SIGNED: + tk = lex(); + switch (tk) { + case TK_SHORT: + *type = TYPE(&stvectorsignedshort); + tk = lex(); + return 1; + case TK_LONG: + *type = TYPE(&stvectorsignedlong); + tk = lex(); + return 1; + default: + *type = TYPE(&stvectorsignedlong); + return 1; + } + case TK_UNSIGNED: + tk = lex(); + switch (tk) { + case TK_SHORT: + *type = TYPE(&stvectorunsignedshort); + tk = lex(); + return 1; + case TK_LONG: + *type = TYPE(&stvectorunsignedlong); + tk = lex(); + return 1; + default: + *type = TYPE(&stvectorunsignedlong); + return 1; + } + case TK_SHORT: + tk = lex(); + switch (tk) { + case TK_BOOL: + *type = TYPE(&stvectorboolshort); + tk = lex(); + return 1; + case TK_SIGNED: + *type = TYPE(&stvectorsignedshort); + tk = lex(); + return 1; + case TK_UNSIGNED: + *type = TYPE(&stvectorunsignedshort); + tk = lex(); + return 1; + case TK_IDENTIFIER: + if (tkidentifier == GetHashNameNode("bool")) { + *type = TYPE(&stvectorboolshort); + tk = lex(); + return 1; + } + default: + CError_Error(CErrorStr121); + } + break; + case TK_LONG: + tk = lex(); + switch (tk) { + case TK_BOOL: + *type = TYPE(&stvectorboollong); + tk = lex(); + return 1; + case TK_SIGNED: + *type = TYPE(&stvectorsignedlong); + tk = lex(); + return 1; + case TK_UNSIGNED: + *type = TYPE(&stvectorunsignedlong); + tk = lex(); + return 1; + case TK_IDENTIFIER: + if (tkidentifier == GetHashNameNode("bool")) { + *type = TYPE(&stvectorboollong); + tk = lex(); + return 1; + } + } + case TK_IDENTIFIER: + if (tkidentifier == GetHashNameNode("bool")) { + tk = lex(); + switch (tk) { + case TK_LONG: + *type = TYPE(&stvectorboollong); + tk = lex(); + return 1; + case TK_SHORT: + *type = TYPE(&stvectorboolshort); + tk = lex(); + return 1; + default: + *type = TYPE(&stvectorboolshort); + return 1; + } + } + default: + CError_Error(CErrorStr121); + } + break; + case TK_FLOAT: + *type = TYPE(&stvectorfloat); + tk = lex(); + return 1; + case TK_IDENTIFIER: + if (tkidentifier == GetHashNameNode("pixel") || tkidentifier == GetHashNameNode("__pixel")) { + *type = TYPE(&stvectorpixel); + tk = lex(); + return 1; + } + if (tkidentifier == GetHashNameNode("bool")) { + tk = lex(); + switch (tk) { + case TK_CHAR: + *type = TYPE(&stvectorboolchar); + tk = lex(); + return 1; + case TK_SHORT: + *type = TYPE(&stvectorboolshort); + tk = lex(); + if (tk == TK_INT) + tk = lex(); + return 1; + case TK_LONG: + *type = TYPE(&stvectorboollong); + tk = lex(); + if (tk == TK_INT) + tk = lex(); + return 1; + case TK_INT: + tk = lex(); + switch (tk) { + case TK_SHORT: + *type = TYPE(&stvectorboolshort); + tk = lex(); + return 1; + case TK_LONG: + *type = TYPE(&stvectorboollong); + tk = lex(); + return 1; + default: + *type = TYPE(&stvectorboollong); + return 1; + } + } + } + default: + CError_Error(CErrorStr121); + } + + return 0; +} + +Boolean CParser_CheckTemplateClassUsage(TemplClass *tmclass, Boolean flag) { + NameSpace *nspace; + + if (tmclass->templ__params) { + nspace = cscope_current; + while (1) { + if (!nspace) { + if (flag) + CError_Error(CErrorStr230); + return 0; + } + if (nspace->theclass == TYPE_CLASS(tmclass)) + break; + nspace = nspace->parent; + } + } + + return 1; +} + +static Boolean CParser_IsAltiVecPrefix(void) { + HashNameNode *save = tkidentifier; + + switch (lookahead()) { + case TK_CHAR: + case TK_SHORT: + case TK_INT: + case TK_LONG: + case TK_FLOAT: + case TK_SIGNED: + case TK_UNSIGNED: + case TK_BOOL: + return 1; + case TK_IDENTIFIER: + if (!strcmp(tkidentifier->name, "bool") || !strcmp(tkidentifier->name, "pixel") || !strcmp(tkidentifier->name, "__pixel")) + return 1; + } + + tkidentifier = save; + return 0; +} + +void CParser_GetDeclSpecs(DeclInfo *di, Boolean flag) { + short typesize; + short signedness; + short typetoken; + Boolean r24; + Boolean r23; + SInt32 state; + NameResult pr; + + di->file = CPrep_BrowserCurrentFile(); + CPrep_BrowserFilePosition(&di->file2, &di->sourceoffset); + + r24 = 1; + r23 = copts.cplusplus; + typetoken = 0; + signedness = 0; + typesize = 0; + +restart: + switch (tk) { + case TK_AUTO: + case TK_REGISTER: + case TK_STATIC: + case TK_EXTERN: + case TK_TYPEDEF: + case TK_MUTABLE: + if (di->storageclass) + CError_Error(CErrorStr121); + di->storageclass = tk; + break; + case TK_CONST: + if (di->thetype) { + if (di->thetype->type == TYPEPOINTER) { + if (TYPE_POINTER(di->thetype)->qual & Q_CONST) + CError_QualifierCheck(Q_CONST); + TYPE_POINTER(di->thetype)->qual |= Q_CONST; + break; + } else if (di->thetype->type == TYPEMEMBERPOINTER) { + if (TYPE_MEMBER_POINTER(di->thetype)->qual & Q_CONST) + CError_QualifierCheck(Q_CONST); + TYPE_MEMBER_POINTER(di->thetype)->qual |= Q_CONST; + break; + } + } + if (di->qual & Q_CONST) + CError_QualifierCheck(Q_CONST); + di->qual |= Q_CONST; + break; + case TK_VOLATILE: + if (di->thetype) { + if (di->thetype->type == TYPEPOINTER) { + if (TYPE_POINTER(di->thetype)->qual & Q_VOLATILE) + CError_QualifierCheck(Q_VOLATILE); + TYPE_POINTER(di->thetype)->qual |= Q_VOLATILE; + break; + } else if (di->thetype->type == TYPEMEMBERPOINTER) { + if (TYPE_MEMBER_POINTER(di->thetype)->qual & Q_VOLATILE) + CError_QualifierCheck(Q_VOLATILE); + TYPE_MEMBER_POINTER(di->thetype)->qual |= Q_VOLATILE; + break; + } + } + if (di->qual & Q_VOLATILE) + CError_QualifierCheck(Q_VOLATILE); + di->qual |= Q_VOLATILE; + break; + case TK_PASCAL: + if (di->qual & Q_PASCAL) + CError_QualifierCheck(Q_PASCAL); + di->qual |= Q_PASCAL; + break; + case TK_EXPLICIT: + CError_QualifierCheck(di->qual & Q_EXPLICIT); + di->qual |= Q_EXPLICIT; + break; + case TK_VIRTUAL: + CError_QualifierCheck(di->qual & Q_VIRTUAL); + di->qual |= Q_VIRTUAL; + break; + case TK_IN: + CError_QualifierCheck(di->qual & Q_IN); + di->qual |= Q_IN; + break; + case TK_OUT: + CError_QualifierCheck(di->qual & Q_OUT); + di->qual |= Q_OUT; + break; + case TK_INOUT: + CError_QualifierCheck(di->qual & Q_INOUT); + di->qual |= Q_INOUT; + break; + case TK_BYCOPY: + CError_QualifierCheck(di->qual & Q_BYCOPY); + di->qual |= Q_BYCOPY; + break; + case TK_BYREF: + CError_QualifierCheck(di->qual & Q_BYREF); + di->qual |= Q_BYREF; + break; + case TK_ONEWAY: + CError_QualifierCheck(di->qual & Q_ONEWAY); + di->qual |= Q_ONEWAY; + break; + case TK_UU_DECLSPEC: + if ((tk = lex()) != '(') + CError_Error(CErrorStr114); + CParser_ParseDeclSpec(di, 0); + if ((tk = lex()) != ')') + CError_Error(CErrorStr115); + break; + case TK_ASM: + if (di->qual & Q_ASM) + CError_QualifierCheck(Q_ASM); + di->qual |= Q_ASM; + break; + case TK_INLINE: + if (di->qual & Q_INLINE) + CError_QualifierCheck(Q_INLINE); + di->qual |= Q_INLINE; + break; + case TK_SHORT: + if (typesize || (typetoken && typetoken != TK_INT && typetoken != TK_DOUBLE)) + CError_Error(CErrorStr121); + typesize = 1; + break; + case TK_LONG: + if (copts.longlong) { + if (typetoken && typetoken != TK_INT && typetoken != TK_DOUBLE) + CError_Error(CErrorStr121); + if (typesize) { + if (typesize != 2 || typetoken == TK_DOUBLE) + CError_Error(CErrorStr121); + typesize = 3; + } else { + typesize = 2; + } + } else { + if (typesize || (typetoken && typetoken != TK_INT && typetoken != TK_DOUBLE)) + CError_Error(CErrorStr121); + typesize = 2; + } + break; + case TK_SIGNED: + if (signedness || (typetoken && typetoken != TK_INT && typetoken != TK_CHAR)) + CError_Error(CErrorStr121); + signedness = -1; + break; + case TK_UNSIGNED: + if (signedness || (typetoken && typetoken != TK_INT && typetoken != TK_CHAR)) + CError_Error(CErrorStr121); + signedness = 1; + break; + case TK_VOID: + if (typetoken || typesize || signedness) + CError_Error(CErrorStr121); + typetoken = TK_VOID; + break; + case TK_FLOAT: + if (typetoken || typesize || signedness) + CError_Error(CErrorStr121); + typetoken = TK_FLOAT; + break; + case TK_BOOL: + if (typetoken || typesize) + CError_Error(CErrorStr121); + typetoken = TK_BOOL; + break; + case TK_CHAR: + if (typetoken || typesize) + CError_Error(CErrorStr121); + typetoken = TK_CHAR; + break; + case TK_WCHAR_T: + if (typetoken || typesize || signedness) + CError_Error(CErrorStr121); + typetoken = TK_WCHAR_T; + break; + case TK_INT: + if (typetoken) + CError_Error(CErrorStr121); + typetoken = TK_INT; + break; + case TK_DOUBLE: + if (typetoken || signedness) + CError_Error(CErrorStr121); + typetoken = TK_DOUBLE; + break; + case TK_STRUCT: + if (typetoken || signedness || typesize) + CError_Error(CErrorStr121); + tk = lex(); + scanstruct(di, STRUCT_TYPE_STRUCT); + if (tk == TK_UU_ATTRIBUTE_UU) + CParser_ParseAttribute(di->thetype, NULL); + if (!(tk != TK_CONST && tk != TK_VOLATILE && tk != TK_UU_FAR && tk != TK_UU_DECLSPEC)) { + typetoken = -1; + goto restart; + } + return; + case TK_CLASS: + if (typetoken || signedness || typesize) + CError_Error(CErrorStr121); + tk = lex(); + CDecl_ParseClass(di, CLASS_MODE_CLASS, 1, 0); + if (tk == TK_UU_ATTRIBUTE_UU) + CParser_ParseAttribute(di->thetype, NULL); + if (!(tk != TK_CONST && tk != TK_VOLATILE && tk != TK_UU_FAR && tk != TK_UU_DECLSPEC)) { + typetoken = -1; + goto restart; + } + return; + case TK_UNION: + if (typetoken || signedness || typesize) + CError_Error(CErrorStr121); + tk = lex(); + scanstruct(di, STRUCT_TYPE_UNION); + if (tk == TK_UU_ATTRIBUTE_UU) + CParser_ParseAttribute(di->thetype, NULL); + if (!(tk != TK_CONST && tk != TK_VOLATILE && tk != TK_UU_FAR && tk != TK_UU_DECLSPEC)) { + typetoken = -1; + goto restart; + } + return; + case TK_ENUM: + if (typetoken || signedness || typesize) + CError_Error(CErrorStr121); + tk = lex(); + scanenum(di); + if (tk == TK_UU_ATTRIBUTE_UU) + CParser_ParseAttribute(di->thetype, NULL); + if (!(tk != TK_CONST && tk != TK_VOLATILE && tk != TK_UU_FAR && tk != TK_UU_DECLSPEC)) { + typetoken = -1; + goto restart; + } + return; + case TK_TYPENAME: + if (typetoken || signedness || typesize || di->x53) + CError_Error(CErrorStr121); + di->x53 = 1; + tk = lex(); + if (tk != TK_COLON_COLON && tk != TK_IDENTIFIER) { + CError_Error(CErrorStr121); + break; + } + goto some_shared_label; + case TK_COLON_COLON: + if (typetoken || signedness || typesize) + goto switchDefault; + goto some_shared_label; + case TK_UU_VECTOR: + if (typetoken || signedness || typesize) + CError_Error(CErrorStr121); + handle_vector: + if (CParser_GetVectorDeclSpec(&di->thetype)) { + if (tk == TK_CONST) { + if (di->qual == 0) { + di->qual |= Q_CONST; + tk = lex(); + } else { + CError_Error(CErrorStr121); + } + } + if (tk == TK_VOLATILE) { + if (di->qual == 0) { + di->qual |= Q_VOLATILE; + tk = lex(); + } else { + CError_Error(CErrorStr121); + } + } + return; + } + break; + case TK_UU_TYPEOF_UU: + if (typetoken || signedness || typesize) + CError_Error(CErrorStr121); + CParser_ParseTypeOf(di); + typetoken = -1; + goto bailOut; + case TK_IDENTIFIER: + if (copts.altivec_model && !typetoken && !signedness && !typesize && !strcmp(tkidentifier->name, "vector")) { + if (CParser_IsAltiVecPrefix()) + goto handle_vector; + } + if (!typetoken && !signedness && !typesize) { + if (copts.objective_c && !strcmp(tkidentifier->name, "id")) { + di->thetype = CObjC_ParseID(); + typetoken = -1; + goto bailOut; + } + some_shared_label: + CPrep_TokenStreamGetState(&state); + if (CScope_ParseDeclName(&pr)) { + if (pr.type) { + if (IS_TYPE_TEMPLATE(pr.type)) { + switch (TYPE_TEMPLATE(pr.type)->dtype) { + case TEMPLDEP_ARGUMENT: + switch (TYPE_TEMPLATE(pr.type)->u.pid.type) { + case TPT_TYPE: + break; + case TPT_NONTYPE: + CError_Error(CErrorStr348); + pr.type = TYPE(&stsignedint); + break; + case TPT_TEMPLATE: + CError_Error(CErrorStr230); + pr.type = TYPE(&stsignedint); + break; + default: + CError_FATAL(4109); + } + break; + case TEMPLDEP_QUALNAME: + if (!di->x53 && !pr.x20 && di->x55) + CError_Error(CErrorStr355); + break; + case TEMPLDEP_TEMPLATE: + case TEMPLDEP_ARRAY: + case TEMPLDEP_QUALTEMPL: + case TEMPLDEP_BITFIELD: + break; + default: + CError_FATAL(4136); + } + } + + if (IS_TYPE_CLASS(pr.type) && (TYPE_CLASS(pr.type)->flags & CLASS_IS_TEMPL)) { + if (!CParser_CheckTemplateClassUsage(TEMPL_CLASS(pr.type), 0)) { + if (di->x56) { + if (di->qual) + CError_Error(CErrorStr121); + di->thetype = pr.type; + di->x57 = 1; + tk = lex(); + return; + } else { + CError_Error(CErrorStr230); + pr.type = TYPE(&stsignedint); + } + } + } + + TypedefDeclInfo(di, pr.type, pr.qual); + di->x49 = pr.x20; + typetoken = -1; + tk = lex(); + if (tk == '<' && copts.objective_c && IS_TYPE_CLASS(di->thetype) && TYPE_CLASS(di->thetype)->objcinfo) + di->thetype = CObjC_ParseTypeProtocol(TYPE_CLASS(di->thetype)); + goto bailOut; + } else if (pr.nsol_14) { + if (pr.x1D) { + if (flag && (OBJECT(pr.nsol_14->object)->nspace == pr.nspace_0 || di->in_friend_decl)) { + di->x14 = pr.nsol_14; + if (IS_TYPE_FUNC(OBJECT(di->x14->object)->type) && ((TYPE_FUNC(OBJECT(di->x14->object)->type)->flags & FUNC_IS_CTOR) | FUNC_IS_DTOR)) + r23 = 0; + } else { + CError_Error(CErrorStr121); + } + } + } else if (pr.obj_10) { + switch (pr.obj_10->otype) { + case OT_OBJECT: + if (pr.x1D) { + if (flag && (OBJECT(pr.obj_10)->nspace == pr.nspace_0 || di->in_friend_decl)) { + di->x10 = OBJECT(pr.obj_10); + if (IS_TYPE_FUNC(di->x10->type) && ((TYPE_FUNC(di->x10->type)->flags & FUNC_IS_CTOR) | FUNC_IS_DTOR)) + r23 = 0; + } else { + CError_Error(CErrorStr121); + } + } + break; + case OT_ENUMCONST: + case OT_MEMBERVAR: + CError_Error(CErrorStr121); + break; + default: + CError_FATAL(4217); + } + } else if (pr.name_4) { + if (copts.cplusplus) + CError_Error(CErrorStr121); + } else if (pr.x21) { + CPrep_TokenStreamSetState(&state); + CPrep_UnLex(); + tk = lex(); + r23 = 0; + } else { + CError_FATAL(4234); + } + } + } + default: + switchDefault: + if (!typetoken && !signedness && !typesize) { + di->x4A = 1; + if (r23) { + if (!di->storageclass && !di->qual && !di->exportflags) + CError_Error(CErrorStr121); + else + CError_Warning(CErrorStr349); + } + } + if (typetoken >= 0) + di->thetype = getthetype(typetoken, typesize, signedness); + if (r24) + di->x48 = 1; + if (tk == TK_UU_ATTRIBUTE_UU) + CParser_ParseAttribute(NULL, di); + return; + case ';': + if (!typetoken && !signedness && !typesize && copts.warn_emptydecl) + CError_Warning(CErrorStr216); + if (typetoken >= 0) + di->thetype = getthetype(typetoken, typesize, signedness); + return; + } + + tk = lex(); +bailOut: + r24 = 0; + goto restart; +} + +void CParser_RegisterNonGlobalClass(TypeClass *tclass) { + struct ParentCleanup *p = lalloc(sizeof(struct ParentCleanup)); + p->next = cparser_parentcleanup; + p->tclass = tclass; + cparser_parentcleanup = p; +} + +void CParser_RegisterSingleExprFunction(Object *func, ENode *expr) { + struct SFuncList *p = lalloc(sizeof(struct SFuncList)); + p->next = cparser_sfunclist; + p->func = func; + p->obj = NULL; + p->expr = expr; + cparser_sfunclist = p; +} + +void CParser_RegisterDummyCtorFunction(Object *func, Object *obj) { + struct SFuncList *p = lalloc(sizeof(struct SFuncList)); + p->next = cparser_sfunclist; + p->func = func; + p->obj = obj; + p->expr = NULL; + cparser_sfunclist = p; +} + +static void CParser_FreeLocalHeap(void) { + struct SFuncList *s; + struct ParentCleanup *p; + + while ((s = cparser_sfunclist)) { + cparser_sfunclist = s->next; + if (s->expr) + CFunc_GenerateSingleExprFunc(s->func, s->expr); + else + CFunc_GenerateDummyCtorFunc(s->func, s->obj); + } + + if (cparser_parentcleanup) { + if (!CInline_CanFreeLHeap()) + return; + + for (p = cparser_parentcleanup; p; p = p->next) { + while (!p->tclass->nspace->parent->is_global) + p->tclass->nspace->parent = p->tclass->nspace->parent->parent; + } + + cparser_parentcleanup = NULL; + } + + freelheap(); +} + +static void CParser_GlobalCleanup(Boolean flag) { + Boolean working; + + do { + CParser_FreeLocalHeap(); + working = 0; + + if (flag) { + if (cparser_classactions) { + CClass_ClassAction(cparser_classactions->tclass); + cparser_classactions = cparser_classactions->next; + working = 1; + } else if (CTempl_Instantiate()) { + working = 1; + } + } + + while (CInline_GenerateDeferredFuncs()) { + CParser_FreeLocalHeap(); + working = 1; + } + } while (working); +} + +Boolean CParser_IsAnonymousUnion(DeclInfo *di, Boolean flag) { + return IS_TYPE_CLASS(di->thetype) && + ((TYPE_CLASS(di->thetype)->mode == CLASS_MODE_UNION || (flag && copts.cpp_extensions))) && + IsTempName(TYPE_CLASS(di->thetype)->classname); +} + +void CParser_CheckAnonymousUnion(DeclInfo *di, Boolean flag) { + ObjMemberVar *ivar; + Object *obj; + Object *ivar_obj; + + if (!CParser_IsAnonymousUnion(di, 0)) { + if (copts.warn_emptydecl) { + switch (di->thetype->type) { + case TYPEENUM: + case TYPESTRUCT: + case TYPECLASS: + if (!di->storageclass && !di->qual) + return; + } + CError_Warning(CErrorStr216); + } + return; + } + + if (!flag && di->storageclass != TK_STATIC) + CError_Error(CErrorStr177); + + if (flag && di->storageclass != TK_STATIC) { + obj = CParser_NewLocalDataObject(di, 1); + obj->name = CParser_GetUniqueName(); + CFunc_SetupLocalVarInfo(obj); + obj->u.var.info->noregister = 1; + } else { + obj = CParser_NewGlobalDataObject(di); + obj->name = CParser_GetUniqueName(); + obj->nspace = cscope_root; + obj->sclass = TK_STATIC; + CInit_DeclareData(obj, NULL, NULL, obj->type->size); + } + + for (ivar = TYPE_CLASS(di->thetype)->ivars; ivar; ivar = ivar->next) { + ivar_obj = galloc(sizeof(Object)); + *ivar_obj = *obj; + ivar_obj->name = ivar->name; + ivar_obj->type = ivar->type; + ivar_obj->qual = ivar->qual; + ivar_obj->datatype = DALIAS; + ivar_obj->u.alias.object = obj; + ivar_obj->u.alias.offset = ivar->offset; + ivar_obj->u.alias.member = NULL; + CScope_AddObject(cscope_current, ivar_obj->name, OBJ_BASE(ivar_obj)); + } +} + +void CParser_NewCallBackAction(Object *obj, TypeClass *tclass) { + CallbackAction *act = galloc(sizeof(CallbackAction)); + act->next = callbackactions; + act->obj = obj; + act->tclass = tclass; + callbackactions = act; + obj->flags = obj->flags | OBJECT_LAZY; +} + +void CParser_NewClassAction(TypeClass *tclass) { + struct ClassAction *act = galloc(sizeof(struct ClassAction)); + act->next = cparser_classactions; + act->tclass = tclass; + cparser_classactions = act; +} + +void CParser_CallBackAction(Object *obj) { + CallbackAction *act; + + for (act = callbackactions; act; act = act->next) { + if (act->obj == obj) { + CParser_NewClassAction(act->tclass); + return; + } + } + + CError_FATAL(4551); +} + +static Object *CParser_FindOverloadFunc(NameSpaceObjectList *list, TypeFunc *tfunc) { + while (list) { + if (list->object->otype == OT_OBJECT && IS_TYPE_FUNC(OBJECT(list->object)->type)) + if (CParser_CompareArgLists(tfunc->args, TYPE_FUNC(OBJECT(list->object)->type)->args) == 1) + return OBJECT(list->object); + list = list->next; + } + + return NULL; +} + +Object *CParser_ParseObject(void) { + DeclInfo di; + NameResult pr; + NameSpaceObjectList *list; + Object *obj; + + memclrw(&di, sizeof(DeclInfo)); + CParser_GetDeclSpecs(&di, 1); + scandeclarator(&di); + + if (di.name && (list = CScope_FindObjectList(&pr, di.name))) { + if (list->object->otype == OT_OBJECT) { + if (IS_TYPE_FUNC(di.thetype)) + return CParser_FindOverloadFunc(list, TYPE_FUNC(di.thetype)); + + if (is_typesame(di.thetype, OBJECT(list->object)->type) && OBJECT(list->object)->qual == di.qual) + return OBJECT(list->object); + + obj = OBJECT(list->object); + CError_Error(CErrorStr249, CError_GetObjectName(obj), obj->type, obj->qual, di.thetype, di.qual); + } + } + + return NULL; +} + +void CParser_ParseGlobalDeclaration(void) { + DeclInfo di; + + if (tk) { + CPrep_NewFileOffsetInfo(&cparser_fileoffset, NULL); + symdecloffset = cparser_fileoffset.tokenline; + symdecltoken = *CPrep_CurStreamElement(); + + memclrw(&di, sizeof(DeclInfo)); + CParser_GetDeclSpecs(&di, 1); + if (di.storageclass == TK_REGISTER || di.storageclass == TK_AUTO) { + CError_Error(CErrorStr177); + di.storageclass = 0; + } + + if (tk != ';') + scandeclaratorlist(&di); + else + CParser_CheckAnonymousUnion(&di, 0); + + tk = lex(); + } else { + CError_Error(CErrorStr102); + } +} + +static void CParser_ParseLinkageSpecification(DeclInfo *di) { + UInt32 qual; + UInt8 r28; + + if (!strcmp(tkstring, "C") || !strcmp(tkstring, "Objective C")) { + qual = 0; + r28 = 1; + } else if (!strcmp(tkstring, "C++")) { + qual = 0; + r28 = 0; + } else if (!strcmp(tkstring, "Pascal")) { + qual = Q_PASCAL; + r28 = 1; + } else { + CError_Error(CErrorStr121); + qual = 0; + r28 = 1; + } + + if ((tk = lex()) == '{') { + while (1) { + if ((tk = lex()) == 0) { + CError_Error(CErrorStr130); + return; + } + + if (tk == '}') + break; + + CPrep_NewFileOffsetInfo(&cparser_fileoffset, NULL); + symdecloffset = cparser_fileoffset.tokenline; + symdecltoken = *CPrep_CurStreamElement(); + + memclrw(di, sizeof(DeclInfo)); + di->is_extern_c = r28; + di->qual = qual; + CParser_ParseDeclaration(di); + } + } else if (tk == TK_EXTERN && copts.cpp_extensions && lookahead() == TK_STRING) { + tk = lex(); + CParser_ParseLinkageSpecification(di); + } else { + memclrw(di, sizeof(DeclInfo)); + di->is_extern_c = r28; + di->qual = qual; + CParser_GetDeclSpecs(di, 1); + + if (di->storageclass != TK_TYPEDEF) { + if (di->storageclass && copts.pedantic) + CError_Warning(CErrorStr177); + if (!di->storageclass) + di->storageclass = TK_EXTERN; + } + if (copts.cpp_extensions) + di->x48 = 0; + if (tk != ';') + scandeclaratorlist(di); + } +} + +static void CParser_ParseNameSpace(DeclInfo *di) { + NameSpace *nspace; + ObjNameSpace *objns; + HashNameNode *name; + Boolean flag; + CScopeSave save; + NameSpaceObjectList *list; + NameSpaceList *nsl; + + if ((tk = lex()) == TK_IDENTIFIER) { + name = tkidentifier; + flag = 0; + if ((tk = lex()) == '=') { + CScope_ParseNameSpaceAlias(name); + return; + } + } else { + if (tk != '{') { + CError_Error(CErrorStr107); + return; + } + name = CParser_GetUnnamedNameSpaceName(); + flag = 1; + } + + nspace = cscope_current; + if (!(list = CScope_FindName(nspace, name))) { + objns = galloc(sizeof(ObjNameSpace)); + memclrw(objns, sizeof(ObjNameSpace)); + objns->otype = OT_NAMESPACE; + objns->access = ACCESSPUBLIC; + if (flag) { + nspace = CScope_NewListNameSpace(name, 1); + nspace->is_unnamed = 1; + nsl = galloc(sizeof(NameSpaceList)); + nsl->next = cscope_current->usings; + nsl->nspace = nspace; + cscope_current->usings = nsl; + } else { + nspace = CScope_NewHashNameSpace(name); + if (cscope_current->is_unnamed) + nspace->is_unnamed = 1; + } + + nspace->parent = cscope_current; + objns->nspace = nspace; + CScope_AddObject(cscope_current, name, OBJ_BASE(objns)); + } else { + if (list->object->otype != OT_NAMESPACE) + CError_Error(CErrorStr320); + else + nspace = OBJ_NAMESPACE(list->object)->nspace; + } + + if (tk != '{') { + CError_Error(CErrorStr135); + return; + } + + CScope_SetNameSpaceScope(nspace, &save); + while (1) { + if ((tk = lex()) == 0) { + CError_Error(CErrorStr130); + break; + } + + if (tk == '}') + break; + + CPrep_NewFileOffsetInfo(&cparser_fileoffset, NULL); + symdecloffset = cparser_fileoffset.tokenline; + symdecltoken = *CPrep_CurStreamElement(); + + memclrw(di, sizeof(DeclInfo)); + CParser_ParseDeclaration(di); + } + CScope_RestoreScope(&save); +} + +static void CParser_ParseDeclaration(DeclInfo *di) { + switch (tk) { + case TK_AT_INTERFACE: + CObjC_ParseInterface(); + break; + case TK_AT_IMPLEMENTATION: + CObjC_ParseImplementation(); + break; + case TK_AT_PROTOCOL: + CObjC_ParseProtocol(); + break; + case TK_AT_CLASS: + CObjC_ParseClassDeclaration(); + break; + case TK_NAMESPACE: + CParser_ParseNameSpace(di); + break; + case TK_EXPORT: + CError_Error(CErrorStr190); + if ((tk = lex()) != TK_TEMPLATE) { + CError_Error(CErrorStr121); + return; + } + case TK_TEMPLATE: + CTempl_Parse(NULL, 0); + break; + case TK_USING: + if ((tk = lex()) == TK_NAMESPACE) { + tk = lex(); + CScope_ParseUsingDirective(cscope_current); + } else { + CScope_ParseUsingDeclaration(cscope_current, 0, 0); + } + break; + case TK_EXTERN: + if (copts.cplusplus) { + di->storageclass = TK_EXTERN; + if ((tk = lex()) == TK_STRING) { + CParser_ParseLinkageSpecification(di); + break; + } + } + default: + CParser_GetDeclSpecs(di, 1); + if ((di->storageclass == TK_REGISTER || di->storageclass == TK_AUTO) != 0) { + CError_Error(CErrorStr177); + di->storageclass = 0; + } + if (tk != ';') + scandeclaratorlist(di); + else + CParser_CheckAnonymousUnion(di, 0); + CParser_GlobalCleanup(0); + } +} + +void cparser(void) { + DeclInfo di; + + if (copts.crippled && copts.optimizationlevel > 1) { + CError_Warning(CErrorStr385); + copts.optimizationlevel = 1; + CodeGen_UpdateOptimizerOptions(); + CodeGen_UpdateBackEndOptions(); + } + + if ((tk = lex())) { + do { + CPrep_NewFileOffsetInfo(&cparser_fileoffset, NULL); + symdecloffset = cparser_fileoffset.tokenline; + symdecltoken = *CPrep_CurStreamElement(); + + memclrw(&di, sizeof(DeclInfo)); + CParser_ParseDeclaration(&di); + } while (tk && (tk = lex())); + } else { + if (!copts.cplusplus && copts.ANSIstrict) + CError_Error(CErrorStr102); + } + + CInit_DefineTentativeData(); + copts.defer_codegen = 0; + CParser_GlobalCleanup(1); + + if (cparamblkptr->precompile != 1) { + CInline_Finish(); + CParser_GlobalCleanup(1); + } + + CClass_GenThunks(); + if (cparamblkptr->precompile != 1) + CObjC_GenerateModule(); + + CSOM_Cleanup(); + CInit_DefineTentativeData(); +} diff --git a/compiler_and_linker/FrontEnd/C/CPrec.c b/compiler_and_linker/FrontEnd/C/CPrec.c new file mode 100644 index 0000000..e61b96e --- /dev/null +++ b/compiler_and_linker/FrontEnd/C/CPrec.c @@ -0,0 +1,3482 @@ +#include "compiler/CPrec.h" +#include "compiler/CError.h" +#include "compiler/CFunc.h" +#include "compiler/CInit.h" +#include "compiler/CInline.h" +#include "compiler/CMachine.h" +#include "compiler/CObjC.h" +#include "compiler/CParser.h" +#include "compiler/CPrep.h" +#include "compiler/CScope.h" +#include "compiler/CSOM.h" +#include "compiler/CTemplateNew.h" +#include "compiler/CompilerTools.h" +#include "compiler/Exceptions.h" +#include "compiler/enode.h" +#include "compiler/objc.h" +#include "compiler/objects.h" +#include "compiler/scopes.h" +#include "compiler/som.h" +#include "compiler/templates.h" +#include "compiler/types.h" +#include "cos.h" +#include "compiler/CCompiler.h" +#include "compiler/InlineAsm.h" + +#define RESOLVE_BUFFER(offset) ((void *) (((char *) cprec_buffer) + ((uintptr_t) (offset)))) +#define RESOLVE_RAW_BUFFER(offset) ((void *) (((char *) cprec_rawbuffer) + ((uintptr_t) (offset)))) +#define RESOLVE_SAFE(offset) (!(offset) ? NULL : ((void *) (((char *) cprec_rawbuffer) + ((uintptr_t) (offset))))) + +#ifdef __MWERKS__ +#pragma options align=mac68k +#endif +typedef struct StaticData { + struct StaticData *next; + Object *object; + void *buffer; + OLinkList *links; + SInt32 size; +} StaticData; + +typedef struct Header { + UInt32 magic; + UInt16 version; + UInt16 x6; + char target; + Boolean check_header_flags; + Boolean cplusplus; + UInt32 xC; + UInt32 x10; + UInt32 x14; + UInt32 x18; + UInt32 x1C; + UInt32 x20; + UInt32 x24; + UInt32 x28; + UInt32 x2C; + UInt32 x30; + UInt32 compressedPatchCount; + UInt32 compressedPatchSize; + UInt32 compressedPatchOffset; + UInt32 builtinPatchSize; + UInt32 builtinPatchOffset; + UInt32 tokenStreamPatchSize; + UInt32 tokenStreamPatchOffset; + UInt32 root_names; + NameSpaceList *usings; + TemplClass *ctempl_templates; + CSOMStub *csom_stubs; + StaticData *cprec_staticdata; + UInt32 uniqueID; + CallbackAction *callbackactions; + Type *cobjc_type_class; + Type *cobjc_type_id; + Type *cobjc_type_sel; + ObjCSelector **cobjc_selhashtable; + BClassList *cobjc_classdefs; + ObjCProtocol *cobjc_protocols; + UInt32 cobjc_selrefcount; + UInt32 cobjc_classrefcount; + UInt32 cobjc_stringcount; + InitExpr *init_expressions; + CI_Action *cinline_tactionlist; + TemplateFunction *ctempl_templatefuncs; + UInt32 x9C; + UInt32 xA0; + UInt32 xA4; + UInt32 xA8; + UInt32 xAC; + UInt32 xB0; + UInt32 xB4; + UInt32 xB8; + UInt32 xBC; + UInt32 xC0; + UInt32 xC4; + UInt32 xC8; + UInt32 xCC; + UInt32 xD0; + UInt32 xD4; + UInt32 xD8; + UInt32 xDC; + UInt32 xE0; + UInt32 xE4; + HashNameNode *nametable[0x800]; + Macro *macrotable[0x800]; + NameSpaceName *root_nametable[0x400]; +} Header; + +typedef struct Patch { + struct Patch *next; + SInt32 offset; +} Patch; + +typedef struct AddrPatch { + struct AddrPatch *next; + void *addr; + void *value; +} AddrPatch; + +typedef struct BuiltIn { + void *target; + SInt32 idx; + Patch *patches; +} BuiltIn; + +static Boolean cprec_exportargnames; +static Boolean cprec_dowrite; +static OSErr cprec_ioerror; +static void *cprec_rawbuffer; +static void *cprec_buffer; +static SInt32 cprec_zero_offset; +static SInt32 cprec_offset; +static int cprec_builtins; +static void **cprec_builtin_array; + +typedef struct TokenPatch { + struct TokenPatch *next; + TStreamElement *tokens; + SInt32 count; +} TokenPatch; +static TokenPatch *cprec_tokenpatches; +static StaticData *cprec_staticdata; + +typedef struct PointerHash { + struct PointerHash *next; + TypePointer *tptr; + TypePointer *prec_tptr; +} PointerHash; +static PointerHash **cprec_pointerhash; + +static BuiltIn *cprec_builtin; +static Patch *cprec_patch_list; +static AddrPatch **cprec_addrhash; +static Header *cprec_header; +static GList cprec_glist; +static short cprec_refnum; +char *precomp_target_str; +#ifdef __MWERKS__ +#pragma options align=reset +#endif + +// Assorted forward declarations +static NameSpace *CPrec_GetNameSpacePatch(NameSpace *nspace); +static ObjEnumConst *CPrec_GetObjEnumConstPatch(ObjEnumConst *obj); +static Object *CPrec_GetObjectPatch(Object *obj); +static ObjBase *CPrec_GetObjBasePatch(ObjBase *obj); +static ObjMemberVar *CPrec_GetObjMemberVarPatch(ObjMemberVar *ivar); +static Type *CPrec_GetTypePatch(Type *type); +static ENode *CPrec_GetExpressionPatch(ENode *expr); +static ObjCMethod *CPrec_GetObjCMethodPatch(ObjCMethod *meth); +static ObjCProtocolList *CPrec_GetObjCProtocolListPatch(ObjCProtocolList *lst); +static TemplArg *CPrec_GetTemplateArgPatch(TemplArg *arg); +static NameSpaceObjectList *CPrec_GetNameSpaceObjectListPatch(NameSpaceObjectList *nsol); +static OSErr CPrec_FlushBufferCheck(void); + +void SetupPrecompiler(Boolean isPrecompiling) { + cprec_refnum = 0; + cprec_glist.data = NULL; + cprec_header = NULL; + cprec_staticdata = NULL; + cprec_ioerror = noErr; +} + +void CleanupPrecompiler(void) { + if (cprec_refnum) { + COS_FileClose(cprec_refnum); + cprec_refnum = 0; + } + + if (cprec_glist.data) + FreeGList(&cprec_glist); +} + +static OLinkList *CPrec_OLinkListCopy(OLinkList *list) { + OLinkList *copy; + + if (!list) + return NULL; + + copy = galloc(sizeof(OLinkList)); + *copy = *list; + copy->next = CPrec_OLinkListCopy(copy->next); + return copy; +} + +void PreComp_StaticData(Object *obj, const void *data, OLinkList *links, SInt32 size) { + StaticData *entry; + + if (obj->sclass != TK_STATIC && !(obj->qual & (Q_20000 | Q_WEAK))) + CError_Error(CErrorStr180); + + entry = galloc(sizeof(StaticData)); + entry->object = obj; + entry->size = size; + + entry->next = cprec_staticdata; + cprec_staticdata = entry; + + if (data) { + entry->buffer = galloc(obj->type->size); + memcpy(entry->buffer, data, obj->type->size); + } else { + entry->buffer = NULL; + } + + entry->links = CPrec_OLinkListCopy(links); +} + +static void CPrec_InitAddressHashTable(void) { + cprec_addrhash = lalloc(0x4000 * sizeof(AddrPatch *)); + memclrw(cprec_addrhash, 0x4000 * sizeof(AddrPatch *)); +} + +static void CPrec_InitPointerHashTable(void) { + cprec_pointerhash = lalloc(0x400 * sizeof(PointerHash *)); + memclrw(cprec_pointerhash, 0x400 * sizeof(PointerHash *)); +} + +static int CPrec_AddressHashVal(void *addr) { + UInt32 v = (UInt32) addr; + return ( + v + + ((unsigned char *) &v)[0] + + ((unsigned char *) &v)[1] + + ((unsigned char *) &v)[2] + + ((unsigned char *) &v)[3] + ) & 0x3FFF; +} + +static AddrPatch *CPrec_FindAddrPatch(void *addr) { + AddrPatch *scan; + + for (scan = cprec_addrhash[CPrec_AddressHashVal(addr)]; scan; scan = scan->next) { + if (scan->addr == addr) + return scan; + } + + return NULL; +} + +static AddrPatch *CPrec_NewAddrPatch(void *addr, void *value) { + AddrPatch **loc; + AddrPatch *patch; + + loc = cprec_addrhash + CPrec_AddressHashVal(addr); + patch = lalloc(sizeof(AddrPatch)); + patch->addr = addr; + patch->value = value; + patch->next = *loc; + *loc = patch; + return patch; +} + +static void CPrec_SetupBuiltInArray(void) { + int count1, count2; + Boolean flag; + void **array; + +#define REG_BUILTIN(a) \ + if (!flag) { array[count2++] = (a); } else { count1++; } + + for (count2 = count1 = 0, flag = 1; ;) { + REG_BUILTIN(cscope_root); + REG_BUILTIN(&stvoid); + REG_BUILTIN(&stbool); + REG_BUILTIN(&stchar); + REG_BUILTIN(&stsignedchar); + REG_BUILTIN(&stunsignedchar); + REG_BUILTIN(&stwchar); + REG_BUILTIN(&stsignedshort); + REG_BUILTIN(&stunsignedshort); + REG_BUILTIN(&stsignedint); + REG_BUILTIN(&stunsignedint); + REG_BUILTIN(&stsignedlong); + REG_BUILTIN(&stunsignedlong); + REG_BUILTIN(&stsignedlonglong); + REG_BUILTIN(&stunsignedlonglong); + REG_BUILTIN(&stfloat); + REG_BUILTIN(&stshortdouble); + REG_BUILTIN(&stdouble); + REG_BUILTIN(&stlongdouble); + REG_BUILTIN(&elipsis); + REG_BUILTIN(&oldstyle); + REG_BUILTIN(&stillegal); + REG_BUILTIN(&sttemplexpr); + REG_BUILTIN(&stvoid); + REG_BUILTIN(&void_ptr); + REG_BUILTIN(&rt_func); + REG_BUILTIN(&catchinfostruct); + REG_BUILTIN(newh_func); + REG_BUILTIN(delh_func); + REG_BUILTIN(copy_func); + REG_BUILTIN(clear_func); + REG_BUILTIN(Rgtid_func); + REG_BUILTIN(Rdync_func); + REG_BUILTIN(rt_ptmf_cast); + REG_BUILTIN(rt_ptmf_cmpr); + REG_BUILTIN(rt_ptmf_test); + REG_BUILTIN(rt_ptmf_call); + REG_BUILTIN(rt_ptmf_scall); + REG_BUILTIN(rt_ptmf_null); + REG_BUILTIN(rt_som_glue1); + REG_BUILTIN(rt_som_glue2); + REG_BUILTIN(rt_som_glue3); + REG_BUILTIN(rt_som_check); + REG_BUILTIN(rt_som_new); + REG_BUILTIN(rt_som_newcheck); + REG_BUILTIN(rt_ptmf_call4); + REG_BUILTIN(rt_ptmf_scall4); + REG_BUILTIN(carr_func); + REG_BUILTIN(cnar_func); + REG_BUILTIN(darr_func); + REG_BUILTIN(dnar_func); + REG_BUILTIN(dnar3_func); + REG_BUILTIN(Xgreg_func); + REG_BUILTIN(Xthrw_func); + REG_BUILTIN(Xicth_func); + REG_BUILTIN(Xecth_func); + REG_BUILTIN(Xunex_func); + REG_BUILTIN(&stvectorunsignedchar); + REG_BUILTIN(&stvectorsignedchar); + REG_BUILTIN(&stvectorboolchar); + REG_BUILTIN(&stvectorunsignedshort); + REG_BUILTIN(&stvectorsignedshort); + REG_BUILTIN(&stvectorboolshort); + REG_BUILTIN(&stvectorunsignedlong); + REG_BUILTIN(&stvectorsignedlong); + REG_BUILTIN(&stvectorboollong); + REG_BUILTIN(&stvectorfloat); + REG_BUILTIN(&stvectorpixel); + + if (flag) { + array = lalloc(sizeof(void *) * count1); + cprec_builtin_array = array; + cprec_builtins = count1; + flag = 0; + } else { + return; + } + } +} + +static void CPrec_SetupBuiltIn(void) { + int x; + + CPrec_SetupBuiltInArray(); + cprec_builtin = lalloc(sizeof(BuiltIn) * cprec_builtins); + memclrw(cprec_builtin, sizeof(BuiltIn) * cprec_builtins); + + for (x = 0; x < cprec_builtins; x++) { + cprec_builtin[x].target = cprec_builtin_array[x]; + cprec_builtin[x].idx = ~x; + CPrec_NewAddrPatch(cprec_builtin[x].target, (void *) cprec_builtin[x].idx); + } +} + +static void CPrec_NewPointerPatch(void *src, void *ptr) { + if (cprec_dowrite) { + Patch *patch = lalloc(sizeof(Patch)); + patch->offset = (SInt32) src; + CError_ASSERT(507, (patch->offset & 0x80000001) == 0); + + if ((SInt32) ptr < 0) { + ptr = (void *) ~((SInt32) ptr); + CError_ASSERT(513, (SInt32) ptr < cprec_builtins); + + patch->next = cprec_builtin[(SInt32) ptr].patches; + cprec_builtin[(SInt32) ptr].patches = patch; + ptr = NULL; + } else { + patch->next = cprec_patch_list; + cprec_patch_list = patch; + } + + src = (void *)((char *) src - cprec_zero_offset); + CError_ASSERT(525, (SInt32) src >= 0 && (SInt32) src <= cprec_glist.size); + *((void **) (*cprec_glist.data + (SInt32) src)) = ptr; + } +} + +static void CPrec_ExistingPointerPatch(void *src, void *ptr) { + if (cprec_dowrite) { + AddrPatch *addrPatch; + Patch *patch; + + CError_ASSERT(543, addrPatch = CPrec_FindAddrPatch(ptr)); + + patch = lalloc(sizeof(Patch)); + patch->offset = (SInt32) src; + patch->next = cprec_patch_list; + cprec_patch_list = patch; + + CError_ASSERT(548, (patch->offset & 0x80000001) == 0); + + src = (void *)((char *) src - cprec_zero_offset); + CError_ASSERT(552, (SInt32) src >= 0 && (SInt32) src <= cprec_glist.size); + *((void **) (*cprec_glist.data + (SInt32) src)) = addrPatch->value; + } +} + +static void CPrec_NamePatch(void *src, HashNameNode *name) { + name->id = 1; + CPrec_ExistingPointerPatch(src, name); +} + +static void *CPrec_AppendAlign(void) { + if (cprec_dowrite) { + while (cprec_offset & 3) { + AppendGListByte(&cprec_glist, 0); + ++cprec_offset; + } + } + + return (void *) cprec_offset; +} + +static UInt32 CPrec_AppendByte(UInt8 v) { + if (cprec_dowrite) + AppendGListByte(&cprec_glist, v); + return cprec_offset++; +} + +static UInt32 CPrec_AppendWord16(UInt16 v) { + UInt32 offset; + if (cprec_dowrite) + AppendGListWord(&cprec_glist, v); + offset = cprec_offset; + cprec_offset += 2; + return offset; +} + +static UInt32 CPrec_AppendWord32(UInt32 v) { + UInt32 offset; + if (cprec_dowrite) + AppendGListLong(&cprec_glist, v); + offset = cprec_offset; + cprec_offset += 4; + return offset; +} + +static UInt32 CPrec_AppendPointer(void *v) { + UInt32 offset; + if (cprec_dowrite) + AppendGListLong(&cprec_glist, (SInt32) v); + offset = cprec_offset; + cprec_offset += 4; + return offset; +} + +static UInt32 CPrec_AppendPointerPatch(void *v) { + AddrPatch *addrPatch; + + if (v) { + CError_ASSERT(644, addrPatch = CPrec_FindAddrPatch(v)); + + if (cprec_dowrite) { + Patch *patch = lalloc(sizeof(Patch)); + patch->offset = cprec_offset; + patch->next = cprec_patch_list; + cprec_patch_list = patch; + CError_ASSERT(651, (patch->offset & 0x80000001) == 0); + } + + return CPrec_AppendPointer(addrPatch->value); + } else { + return CPrec_AppendPointer(NULL); + } +} + +static void CPrec_AppendNamePatch(HashNameNode *name) { + if (name) { + CPrec_AppendPointerPatch(name); + name->id = 1; + } +} + +static void CPrec_AppendString(const char *str) { + int len = strlen(str) + 1; + if (cprec_dowrite) + AppendGListData(&cprec_glist, str, len); + cprec_offset += len; +} + +static void CPrec_AppendData(const void *data, int len) { + if (cprec_dowrite) + AppendGListData(&cprec_glist, data, len); + cprec_offset += len; +} + +static void CPrec_RawMemPatch(void *source, const void *data, int len) { + void *ptr = CPrec_AppendAlign(); + CPrec_AppendData(data, len); + CPrec_NewPointerPatch(source, ptr); +} + +static void CPrec_DumpNameTable(void) { + HashNameNode *name; + int i; + HashNameNode *p; + HashNameNode *next; + + if (cprec_dowrite) { + i = 0; + do { + name = name_hash_nodes[i]; + while (name && name->id == 0) + name = name->next; + + if (name) { + p = CPrec_AppendAlign(); + cprec_header->nametable[i] = p; + + while (1) { + CPrec_NewAddrPatch(name, p); + CPrec_AppendPointer(NULL); + CPrec_AppendWord32(0); + CPrec_AppendWord16(name->hashval); + CPrec_AppendString(name->name); + + name = name->next; + while (name && name->id == 0) + name = name->next; + + if (!name) + break; + + next = CPrec_AppendAlign(); + CPrec_NewPointerPatch(&p->next, next); + p = next; + } + } + } while (++i < 0x800); + } else { + i = 0; + do { + if ((name = name_hash_nodes[i])) { + p = CPrec_AppendAlign(); + while (1) { + CPrec_NewAddrPatch(name, p); + CPrec_AppendPointer(NULL); + CPrec_AppendWord32(0); + CPrec_AppendWord16(name->hashval); + CPrec_AppendString(name->name); + + name = name->next; + if (!name) + break; + + next = CPrec_AppendAlign(); + CPrec_NewPointerPatch(&p->next, next); + p = next; + } + } + } while (++i < 0x800); + } +} + +static void CPrec_DumpMacroTable(void) { + Macro *macro; + int i; + int j; + Macro *p; + Macro *next; + + i = 0; + do { + for (macro = macrohashtable[i]; macro; macro = macro->next) { + if (macro->c) { + CPrec_NewAddrPatch(macro->c, (void *) cprec_offset); + CPrec_AppendString(macro->c); + } + } + } while (++i < 0x800); + + i = 0; + do { + macro = macrohashtable[i]; + + if (macro) { + p = CPrec_AppendAlign(); + if (cprec_dowrite) + cprec_header->macrotable[i] = p; + + while (1) { + CPrec_AppendPointer(NULL); + CPrec_AppendNamePatch(macro->name); + CPrec_AppendPointerPatch(macro->c); + CPrec_AppendWord16(macro->xC); + CPrec_AppendByte(macro->is_special); + CPrec_AppendByte(macro->xF); + + for (j = 1; j < (macro->xC & 0x7FFF); j++) + CPrec_AppendNamePatch(macro->names[j - 1]); + + macro = macro->next; + if (!macro) + break; + + next = CPrec_AppendAlign(); + CPrec_NewPointerPatch(&p->next, next); + p = next; + } + } + } while (++i < 0x800); +} + +static BClassList *CPrec_GetClassAccessPatch(BClassList *path) { + AddrPatch *addrPatch; + BClassList *first, *current, *next; + + if ((addrPatch = CPrec_FindAddrPatch(path))) + return addrPatch->value; + + first = current = CPrec_AppendAlign(); + CPrec_NewAddrPatch(path, first); + + while (1) { + CPrec_AppendData(path, sizeof(BClassList)); + CPrec_NewPointerPatch(¤t->type, CPrec_GetTypePatch(path->type)); + if (!path->next) + break; + + next = CPrec_AppendAlign(); + CPrec_NewPointerPatch(¤t->next, next); + current = next; + path = path->next; + } + + return first; +} + +static int CPrec_PointerHash(TypePointer *type) { + Type *target; + int work; + FuncArg *arg; + + work = type->qual; + target = type->target; + +restart: + switch (target->type) { + case TYPECLASS: + if (TYPE_CLASS(target)->classname) + work += TYPE_CLASS(target)->classname->hashval; + break; + case TYPEENUM: + if (TYPE_ENUM(target)->enumname) + work += TYPE_ENUM(target)->enumname->hashval; + target = TYPE_ENUM(target)->enumtype; + work += 3; + case TYPEINT: + case TYPEFLOAT: + work += TYPE_INTEGRAL(target)->integral; + break; + case TYPEPOINTER: + work += TYPE_POINTER(target)->qual; + target = TYPE_POINTER(target)->target; + goto restart; + case TYPEARRAY: + work += target->size; + target = TYPE_POINTER(target)->target; + goto restart; + case TYPEFUNC: + work += TYPE_FUNC(target)->functype->type; + work += TYPE_FUNC(target)->functype->size; + for (arg = TYPE_FUNC(target)->args; arg; arg = arg->next) { + if (arg->type) { + work += arg->type->type; + work += arg->type->size; + } + } + break; + } + + work += target->type + target->size; + return (work + (work >> 24) + (work >> 16) + (work >> 8)) & 0x3FF; +} + +static TypePointer *CPrec_GetTypePointerPatch(TypePointer *tptr) { + TypePointer *p; + int hash; + PointerHash *phash; + TypePointer *scan1; + TypePointer *scan2; + + if (tptr->qual & Q_IS_OBJC_ID) { + p = CPrec_AppendAlign(); + CPrec_NewAddrPatch(tptr, p); + CPrec_AppendData(tptr, sizeof(TypeObjCID)); + if (TYPE_OBJC_ID(tptr)->protocols) + CPrec_NewPointerPatch(&TYPE_OBJC_ID(p)->protocols, CPrec_GetObjCProtocolListPatch(TYPE_OBJC_ID(tptr)->protocols)); + } else { + if (!copts.faster_pch_gen && cprec_dowrite && tptr->size > 0) { + hash = CPrec_PointerHash(tptr); + for (phash = cprec_pointerhash[hash]; phash; phash = phash->next) { + scan1 = tptr; + scan2 = phash->tptr; + check_again: + if (scan1->type == scan2->type && scan1->size == scan2->size && scan1->qual == scan2->qual) { + scan1 = TYPE_POINTER(TPTR_TARGET(scan1)); + scan2 = TYPE_POINTER(TPTR_TARGET(scan2)); + if (scan1->type == TYPEPOINTER && scan1->type == TYPEARRAY) + goto check_again; + if (scan1 == scan2) + return phash->prec_tptr; + } + } + + p = CPrec_AppendAlign(); + CPrec_NewAddrPatch(tptr, p); + + phash = lalloc(sizeof(PointerHash)); + phash->tptr = tptr; + phash->prec_tptr = p; + phash->next = cprec_pointerhash[hash]; + cprec_pointerhash[hash] = phash; + } else { + p = CPrec_AppendAlign(); + CPrec_NewAddrPatch(tptr, p); + } + + CPrec_AppendData(tptr, sizeof(TypePointer)); + } + + CPrec_NewPointerPatch(&p->target, CPrec_GetTypePatch(tptr->target)); + return p; +} + +static TypeEnum *CPrec_GetTypeEnumPatch(TypeEnum *type) { + TypeEnum *p = CPrec_AppendAlign(); + + CPrec_NewAddrPatch(type, p); + CPrec_AppendData(type, sizeof(TypeEnum)); + + if (type->nspace) + CPrec_NewPointerPatch(&p->nspace, CPrec_GetNameSpacePatch(type->nspace)); + if (type->enumlist) + CPrec_NewPointerPatch(&p->enumlist, CPrec_GetObjEnumConstPatch(type->enumlist)); + + CPrec_NewPointerPatch(&p->enumtype, CPrec_GetTypePatch(type->enumtype)); + if (type->enumname) + CPrec_NamePatch(&p->enumname, type->enumname); + + return p; +} + +static TypeBitfield *CPrec_GetTypeBitfieldPatch(TypeBitfield *type) { + TypeBitfield *p = CPrec_AppendAlign(); + + CPrec_NewAddrPatch(type, p); + CPrec_AppendData(type, sizeof(TypeBitfield)); + CPrec_NewPointerPatch(&p->bitfieldtype, CPrec_GetTypePatch(type->bitfieldtype)); + + return p; +} + +static TypeStruct *CPrec_GetTypeStructPatch(TypeStruct *tstruct) { + StructMember *member; + TypeStruct *p; + StructMember *current, *next; + + p = CPrec_AppendAlign(); + CPrec_NewAddrPatch(tstruct, p); + CPrec_AppendData(tstruct, sizeof(TypeStruct)); + + if (tstruct->name) + CPrec_NamePatch(&p->name, tstruct->name); + + if ((member = tstruct->members)) { + current = CPrec_AppendAlign(); + CPrec_NewPointerPatch(&p->members, current); + + while (1) { + CPrec_AppendData(member, sizeof(StructMember)); + CPrec_NewPointerPatch(¤t->type, CPrec_GetTypePatch(member->type)); + CPrec_NamePatch(¤t->name, member->name); + + if (!member->next) + break; + + next = CPrec_AppendAlign(); + CPrec_NewPointerPatch(¤t->next, next); + current = next; + + member = member->next; + } + } + + return p; +} + +static ExceptSpecList *CPrec_GetExceptSpecPatch(ExceptSpecList *exspec) { + ExceptSpecList *first, *current, *next; + + first = current = CPrec_AppendAlign(); + while (exspec) { + CPrec_AppendData(exspec, sizeof(ExceptSpecList)); + if (exspec->type) + CPrec_NewPointerPatch(¤t->type, CPrec_GetTypePatch(exspec->type)); + + if (!exspec->next) + break; + next = CPrec_AppendAlign(); + CPrec_NewPointerPatch(¤t->next, next); + current = next; + exspec = exspec->next; + } + + return first; +} + +static FuncArg *CPrec_GetArgListPatch(FuncArg *lst, Boolean includeNames) { + FuncArg *first, *current, *next; + AddrPatch *addrPatch; + + if ((addrPatch = CPrec_FindAddrPatch(lst))) + return addrPatch->value; + + first = current = CPrec_AppendAlign(); + while (1) { + if (!includeNames) + lst->name = NULL; + CPrec_AppendData(lst, sizeof(FuncArg)); + if (includeNames && lst->name) + CPrec_NamePatch(¤t->name, lst->name); + + if (lst->dexpr) + CPrec_NewPointerPatch(¤t->dexpr, CPrec_GetExpressionPatch(lst->dexpr)); + if (lst->type) + CPrec_NewPointerPatch(¤t->type, CPrec_GetTypePatch(lst->type)); + else + CError_FATAL(1167); + + if (!lst->next) + break; + + if ((addrPatch = CPrec_FindAddrPatch(lst->next))) { + CPrec_NewPointerPatch(¤t->next, addrPatch->value); + break; + } + + next = CPrec_AppendAlign(); + CPrec_NewPointerPatch(¤t->next, next); + current = next; + lst = lst->next; + CPrec_NewAddrPatch(lst, next); + } + + return first; +} + +static TypeFunc *CPrec_GetTypeFuncPatch(TypeFunc *type) { + TypeFunc *p = CPrec_AppendAlign(); + CPrec_NewAddrPatch(type, p); + + CPrec_AppendData(type, (type->flags & FUNC_METHOD) ? sizeof(TypeMemberFunc) : sizeof(TypeFunc)); + + CPrec_NewPointerPatch(&p->functype, CPrec_GetTypePatch(type->functype)); + if (type->args) + CPrec_NewPointerPatch(&p->args, CPrec_GetArgListPatch(type->args, (type->flags & FUNC_IS_TEMPL_ANY) != 0)); + if (type->exspecs) + CPrec_NewPointerPatch(&p->exspecs, CPrec_GetExceptSpecPatch(type->exspecs)); + if (type->flags & FUNC_METHOD) + CPrec_NewPointerPatch(&TYPE_METHOD(p)->theclass, CPrec_GetTypePatch((Type *) TYPE_METHOD(type)->theclass)); + + return p; +} + +static TypeMemberPointer *CPrec_GetTypeMemberPointerPatch(TypeMemberPointer *type) { + TypeMemberPointer *p = CPrec_AppendAlign(); + CPrec_NewAddrPatch(type, p); + + CPrec_AppendData(type, sizeof(TypeMemberPointer)); + + CPrec_NewPointerPatch(&p->ty1, CPrec_GetTypePatch(type->ty1)); + CPrec_NewPointerPatch(&p->ty2, CPrec_GetTypePatch(type->ty2)); + + return p; +} + +static TypeTemplDep *CPrec_GetTypeTemplDepPatch(TypeTemplDep *type) { + TypeTemplDep *p = CPrec_AppendAlign(); + CPrec_NewAddrPatch(type, p); + + CPrec_AppendData(type, sizeof(TypeTemplDep)); + + switch (type->dtype) { + case TEMPLDEP_ARGUMENT: + break; + case TEMPLDEP_QUALNAME: + CPrec_NewPointerPatch(&p->u.qual.type, CPrec_GetTypeTemplDepPatch(type->u.qual.type)); + CPrec_NamePatch(&p->u.qual.name, type->u.qual.name); + break; + case TEMPLDEP_TEMPLATE: + CPrec_NewPointerPatch(&p->u.templ.templ, CPrec_GetTypePatch((Type *) type->u.templ.templ)); + CPrec_NewPointerPatch(&p->u.templ.args, CPrec_GetTemplateArgPatch(type->u.templ.args)); + break; + case TEMPLDEP_ARRAY: + CPrec_NewPointerPatch(&p->u.array.type, CPrec_GetTypePatch(type->u.array.type)); + CPrec_NewPointerPatch(&p->u.array.index, CPrec_GetExpressionPatch(type->u.array.index)); + break; + case TEMPLDEP_QUALTEMPL: + CPrec_NewPointerPatch(&p->u.qualtempl.type, CPrec_GetTypeTemplDepPatch(type->u.qualtempl.type)); + CPrec_NewPointerPatch(&p->u.qualtempl.args, CPrec_GetTemplateArgPatch(type->u.qualtempl.args)); + break; + case TEMPLDEP_BITFIELD: + CPrec_NewPointerPatch(&p->u.bitfield.type, CPrec_GetTypePatch(type->u.bitfield.type)); + CPrec_NewPointerPatch(&p->u.bitfield.size, CPrec_GetExpressionPatch(type->u.bitfield.size)); + break; + default: + CError_FATAL(1295); + } + + return p; +} + +static ClassList *CPrec_GetClassListPatch(ClassList *cl) { + AddrPatch *addrPatch; + ClassList *first, *current, *next; + + if ((addrPatch = CPrec_FindAddrPatch(cl))) + return addrPatch->value; + + first = current = CPrec_AppendAlign(); + CPrec_NewAddrPatch(cl, first); + + do { + CPrec_AppendData(cl, sizeof(ClassList)); + CPrec_NewPointerPatch(¤t->base, CPrec_GetTypePatch((Type *) cl->base)); + + if (!cl->next) + break; + + if ((addrPatch = CPrec_FindAddrPatch(cl->next))) { + CPrec_NewPointerPatch(¤t->next, addrPatch->value); + break; + } else { + next = CPrec_AppendAlign(); + CPrec_NewPointerPatch(¤t->next, next); + current = next; + cl = cl->next; + } + } while (1); + + return first; +} + +static VClassList *CPrec_GetVClassListPatch(VClassList *vcl) { + VClassList *first, *current, *next; + first = current = CPrec_AppendAlign(); + + do { + CPrec_AppendData(vcl, sizeof(VClassList)); + CPrec_NewPointerPatch(¤t->base, CPrec_GetTypePatch((Type *) vcl->base)); + + if (!vcl->next) + break; + next = CPrec_AppendAlign(); + CPrec_NewPointerPatch(¤t->next, next); + current = next; + vcl = vcl->next; + } while (1); + + return first; +} + +static ClassFriend *CPrec_GetClassFriendPatch(ClassFriend *cf) { + ClassFriend *first, *current, *next; + first = current = CPrec_AppendAlign(); + + do { + CPrec_AppendData(cf, sizeof(ClassFriend)); + if (cf->isclass) + CPrec_NewPointerPatch(¤t->u.theclass, CPrec_GetTypePatch((Type *) cf->u.theclass)); + else + CPrec_NewPointerPatch(¤t->u.theclass, CPrec_GetObjectPatch(cf->u.obj)); + + if (!cf->next) + break; + next = CPrec_AppendAlign(); + CPrec_NewPointerPatch(¤t->next, next); + current = next; + cf = cf->next; + } while (1); + + return first; +} + +static BClassList *CPrec_GetBClassListPatch(BClassList *bcl) { + BClassList *first, *current, *next; + first = current = CPrec_AppendAlign(); + + do { + CPrec_AppendData(bcl, sizeof(BClassList)); + CPrec_NewPointerPatch(¤t->type, CPrec_GetTypePatch((Type *) bcl->type)); + + if (!bcl->next) + break; + next = CPrec_AppendAlign(); + CPrec_NewPointerPatch(¤t->next, next); + current = next; + bcl = bcl->next; + } while (1); + + return first; +} + +static VTable *CPrec_GetVTablePatch(VTable *vtbl) { + VTable *p = CPrec_AppendAlign(); + CPrec_AppendData(vtbl, sizeof(VTable)); + + if (vtbl->object) + CPrec_NewPointerPatch(&p->object, CPrec_GetObjectPatch(vtbl->object)); + if (vtbl->owner) + CPrec_NewPointerPatch(&p->owner, CPrec_GetTypePatch((Type *) vtbl->owner)); + + return p; +} + +static SOMReleaseOrder *CPrec_GetSOMReleaseOrderPatch(SOMReleaseOrder *sro) { + SOMReleaseOrder *first, *current, *next; + first = current = CPrec_AppendAlign(); + + do { + CPrec_AppendData(sro, sizeof(SOMReleaseOrder)); + CPrec_NamePatch(¤t->name, sro->name); + if (!sro->next) + break; + next = CPrec_AppendAlign(); + CPrec_NewPointerPatch(¤t->next, next); + current = next; + sro = sro->next; + } while (1); + + return first; +} + +static SOMInfo *CPrec_GetSOMInfoPatch(SOMInfo *som) { + SOMInfo *p = CPrec_AppendAlign(); + CPrec_AppendData(som, sizeof(SOMInfo)); + + if (som->metaclass) + CPrec_NewPointerPatch(&p->metaclass, CPrec_GetTypePatch((Type *) som->metaclass)); + if (som->classdataobject) + CPrec_NewPointerPatch(&p->classdataobject, CPrec_GetObjectPatch(som->classdataobject)); + if (som->order) + CPrec_NewPointerPatch(&p->order, CPrec_GetSOMReleaseOrderPatch(som->order)); + + return p; +} + +static ObjCMethodArg *CPrec_GetObjCMethodArgPatch(ObjCMethodArg *arg) { + ObjCMethodArg *first, *current, *next; + first = current = CPrec_AppendAlign(); + + do { + CPrec_AppendData(arg, sizeof(ObjCMethod)); + if (arg->selector) + CPrec_NamePatch(¤t->selector, arg->selector); + if (arg->name) + CPrec_NamePatch(¤t->name, arg->name); + if (arg->type) + CPrec_NewPointerPatch(¤t->type, CPrec_GetTypePatch(arg->type)); + + if (!arg->next) + break; + next = CPrec_AppendAlign(); + CPrec_NewPointerPatch(¤t->next, next); + current = next; + arg = arg->next; + } while (1); + + return first; +} + +static ObjCMethodList *CPrec_GetObjCMethodListPatch(ObjCMethodList *lst) { + AddrPatch *addrPatch; + ObjCMethodList *first, *current, *next; + + if ((addrPatch = CPrec_FindAddrPatch(lst))) + return addrPatch->value; + + first = current = CPrec_AppendAlign(); + CPrec_NewAddrPatch(lst, first); + + do { + CPrec_AppendData(lst, sizeof(ObjCMethodList)); + if (lst->method) + CPrec_NewPointerPatch(¤t->method, CPrec_GetObjCMethodPatch(lst->method)); + + if (!lst->next) + break; + + if ((addrPatch = CPrec_FindAddrPatch(lst->next))) { + CPrec_NewPointerPatch(¤t->next, addrPatch->value); + break; + } else { + next = CPrec_AppendAlign(); + CPrec_NewPointerPatch(¤t->next, next); + current = next; + lst = lst->next; + CPrec_NewAddrPatch(lst, next); + } + } while (1); + + return first; +} + +static ObjCSelector *CPrec_GetObjCSelectorPatch(ObjCSelector *sel) { + AddrPatch *addrPatch; + ObjCSelector *current, *first, *next; + + if ((addrPatch = CPrec_FindAddrPatch(sel))) + return addrPatch->value; + + first = current = CPrec_AppendAlign(); + CPrec_NewAddrPatch(sel, first); + + do { + CPrec_AppendData(sel, sizeof(ObjCSelector)); + if (sel->selobject) + CPrec_NewPointerPatch(¤t->selobject, CPrec_GetObjectPatch(sel->selobject)); + CPrec_NamePatch(¤t->name, sel->name); + if (sel->methods) + CPrec_NewPointerPatch(¤t->methods, CPrec_GetObjCMethodListPatch(sel->methods)); + + if (!sel->next) + break; + + if ((addrPatch = CPrec_FindAddrPatch(sel->next))) { + CPrec_NewPointerPatch(¤t->next, addrPatch->value); + break; + } else { + next = CPrec_AppendAlign(); + CPrec_NewPointerPatch(¤t->next, next); + current = next; + sel = sel->next; + CPrec_NewAddrPatch(sel, next); + } + } while (1); + + return first; +} + +static ObjCMethod *CPrec_GetObjCMethodPatch(ObjCMethod *meth) { + // does not match - affected by weirdness where the arg goes into r31 instead of r28 + AddrPatch *addrPatch; + ObjCMethod *current, *first, *next; + + if ((addrPatch = CPrec_FindAddrPatch(meth))) + return addrPatch->value; + + first = current = CPrec_AppendAlign(); + CPrec_NewAddrPatch(meth, first); + + do { + CPrec_AppendData(meth, sizeof(ObjCMethod)); + if (meth->object) + CPrec_NewPointerPatch(¤t->object, CPrec_GetObjectPatch(meth->object)); + if (meth->functype) + CPrec_NewPointerPatch(¤t->functype, CPrec_GetTypePatch((Type *) meth->functype)); + if (meth->selector) + CPrec_NewPointerPatch(¤t->selector, CPrec_GetObjCSelectorPatch(meth->selector)); + if (meth->return_type) + CPrec_NewPointerPatch(¤t->return_type, CPrec_GetTypePatch(meth->return_type)); + if (meth->selector_args) + CPrec_NewPointerPatch(¤t->selector_args, CPrec_GetObjCMethodArgPatch(meth->selector_args)); + + if (!meth->next) + break; + + if ((addrPatch = CPrec_FindAddrPatch(meth->next))) { + CPrec_NewPointerPatch(¤t->next, addrPatch->value); + break; + } else { + next = CPrec_AppendAlign(); + CPrec_NewPointerPatch(¤t->next, next); + current = next; + meth = meth->next; + CPrec_NewAddrPatch(meth, next); + } + } while (1); + + return first; +} + +static ObjCProtocol *CPrec_GetObjCProtocolPatch(ObjCProtocol *prot) { + AddrPatch *addrPatch; + ObjCProtocol *current, *first, *next; + + if ((addrPatch = CPrec_FindAddrPatch(prot))) + return addrPatch->value; + + first = current = CPrec_AppendAlign(); + CPrec_NewAddrPatch(prot, first); + + do { + CPrec_AppendData(prot, sizeof(ObjCProtocol)); + CPrec_NamePatch(¤t->name, prot->name); + if (prot->protocols) + CPrec_NewPointerPatch(¤t->protocols, CPrec_GetObjCProtocolListPatch(prot->protocols)); + if (prot->methods) + CPrec_NewPointerPatch(¤t->methods, CPrec_GetObjCMethodPatch(prot->methods)); + if (prot->object) + CPrec_NewPointerPatch(¤t->object, CPrec_GetObjectPatch(prot->object)); + + if (!prot->next) + break; + + if ((addrPatch = CPrec_FindAddrPatch(prot->next))) { + CPrec_NewPointerPatch(¤t->next, addrPatch->value); + break; + } else { + next = CPrec_AppendAlign(); + CPrec_NewPointerPatch(¤t->next, next); + current = next; + prot = prot->next; + CPrec_NewAddrPatch(prot, next); + } + } while (1); + + return first; +} + +static ObjCProtocolList *CPrec_GetObjCProtocolListPatch(ObjCProtocolList *lst) { + AddrPatch *addrPatch; + ObjCProtocolList *first, *current, *next; + + if ((addrPatch = CPrec_FindAddrPatch(lst))) + return addrPatch->value; + + first = current = CPrec_AppendAlign(); + CPrec_NewAddrPatch(lst, first); + + do { + CPrec_AppendData(lst, sizeof(ObjCProtocolList)); + CPrec_NewPointerPatch(¤t->protocol, CPrec_GetObjCProtocolPatch(lst->protocol)); + + if (!lst->next) + break; + + next = CPrec_AppendAlign(); + CPrec_NewPointerPatch(¤t->next, next); + current = next; + lst = lst->next; + } while (1); + + return first; +} + +static ObjCCategory *CPrec_GetObjCCategoryPatch(ObjCCategory *cat) { + AddrPatch *addrPatch; + ObjCCategory *current, *first, *next; + + if ((addrPatch = CPrec_FindAddrPatch(cat))) + return addrPatch->value; + + first = current = CPrec_AppendAlign(); + CPrec_NewAddrPatch(cat, first); + + do { + CPrec_AppendData(cat, sizeof(ObjCCategory)); + CPrec_NamePatch(¤t->name, cat->name); + if (cat->protocols) + CPrec_NewPointerPatch(¤t->protocols, CPrec_GetObjCProtocolListPatch(cat->protocols)); + if (cat->methods) + CPrec_NewPointerPatch(¤t->methods, CPrec_GetObjCMethodPatch(cat->methods)); + + if (!cat->next) + break; + + if ((addrPatch = CPrec_FindAddrPatch(cat->next))) { + CPrec_NewPointerPatch(¤t->next, addrPatch->value); + break; + } else { + next = CPrec_AppendAlign(); + CPrec_NewPointerPatch(¤t->next, next); + current = next; + cat = cat->next; + CPrec_NewAddrPatch(cat, next); + } + } while (1); + + return first; +} + +static ObjCInfo *CPrec_GetObjCInfoPatch(ObjCInfo *info) { + ObjCInfo *p = CPrec_AppendAlign(); + CPrec_AppendData(info, sizeof(ObjCInfo)); + + if (info->classobject) + CPrec_NewPointerPatch(&p->classobject, CPrec_GetObjectPatch(info->classobject)); + if (info->metaobject) + CPrec_NewPointerPatch(&p->metaobject, CPrec_GetObjectPatch(info->metaobject)); + if (info->classrefobj) + CPrec_NewPointerPatch(&p->classrefobj, CPrec_GetObjectPatch(info->classrefobj)); + if (info->methods) + CPrec_NewPointerPatch(&p->methods, CPrec_GetObjCMethodPatch(info->methods)); + if (info->protocols) + CPrec_NewPointerPatch(&p->protocols, CPrec_GetObjCProtocolListPatch(info->protocols)); + if (info->categories) + CPrec_NewPointerPatch(&p->categories, CPrec_GetObjCCategoryPatch(info->categories)); + + return p; +} + +static TemplArg *CPrec_GetTemplateArgPatch(TemplArg *arg) { + TemplArg *first, *current, *next; + first = current = CPrec_AppendAlign(); + + do { + CPrec_AppendData(arg, sizeof(TemplArg)); + switch (arg->pid.type) { + case TPT_TYPE: + if (arg->data.typeparam.type) + CPrec_NewPointerPatch(¤t->data.typeparam.type, CPrec_GetTypePatch(arg->data.typeparam.type)); + break; + case TPT_NONTYPE: + if (arg->data.paramdecl.expr) + CPrec_NewPointerPatch(¤t->data.paramdecl.expr, CPrec_GetExpressionPatch(arg->data.paramdecl.expr)); + break; + case TPT_TEMPLATE: + if (arg->data.ttargtype) + CPrec_NewPointerPatch(¤t->data.ttargtype, CPrec_GetTypePatch(arg->data.ttargtype)); + break; + default: + CError_FATAL(1879); + } + + if (!arg->next) + break; + next = CPrec_AppendAlign(); + CPrec_NewPointerPatch(¤t->next, next); + current = next; + arg = arg->next; + } while (1); + + return first; +} + +static TemplParam *CPrec_GetTemplateParamPatch(TemplParam *param) { + // register swap issues + TemplParam *first, *current, *next; + first = current = CPrec_AppendAlign(); + + do { + CPrec_AppendData(param, sizeof(TemplParam)); + if (param->name) + CPrec_NamePatch(¤t->name, param->name); + + switch (param->pid.type) { + case TPT_TYPE: + if (param->data.typeparam.type) + CPrec_NewPointerPatch(¤t->data.typeparam.type, CPrec_GetTypePatch(param->data.typeparam.type)); + break; + case TPT_NONTYPE: + CPrec_NewPointerPatch(¤t->data.paramdecl.type, CPrec_GetTypePatch(param->data.paramdecl.type)); + if (param->data.paramdecl.defaultarg) + CPrec_NewPointerPatch(¤t->data.paramdecl.defaultarg, CPrec_GetExpressionPatch(param->data.paramdecl.defaultarg)); + break; + case TPT_TEMPLATE: + if (param->data.templparam.plist) + CPrec_NewPointerPatch(¤t->data.templparam.plist, CPrec_GetTemplateParamPatch(param->data.templparam.plist)); + CError_ASSERT(1953, !param->data.templparam.defaultarg); + break; + default: + CError_FATAL(1958); + } + + if (!param->next) + break; + next = CPrec_AppendAlign(); + CPrec_NewPointerPatch(¤t->next, next); + current = next; + param = param->next; + } while (1); + + return first; +} + +static TStreamElement *CPrec_GetTStreamPatch(TStreamElement *tokens, SInt32 count) { + TStreamElement elem; + TStreamElement *first, *current, *scan; + SInt32 x; + + scan = tokens; + x = 0; + while (x < count) { + elem = *scan; + memclrw(scan, sizeof(TStreamElement)); + + scan->tokentype = elem.tokentype; + switch (elem.tokentype) { + case TK_IDENTIFIER: + scan->data.tkidentifier = elem.data.tkidentifier; + break; + case TK_INTCONST: + scan->subtype = elem.subtype; + scan->data.tkintconst = elem.data.tkintconst; + break; + case TK_FLOATCONST: + scan->subtype = elem.subtype; + scan->data.tkfloatconst = elem.data.tkfloatconst; + break; + case TK_STRING: + case TK_STRING_WIDE: + scan->subtype = elem.subtype; + scan->data.tkstring = elem.data.tkstring; + break; + } + x++; + scan++; + } + + first = current = CPrec_AppendAlign(); + CPrec_AppendData(tokens, count * sizeof(TStreamElement)); + + if (cprec_dowrite) { + TokenPatch *tp = lalloc(sizeof(TokenPatch)); + tp->tokens = current; + tp->count = count; + tp->next = cprec_tokenpatches; + cprec_tokenpatches = tp; + } + + x = 0; + while (x < count) { + switch (tokens->tokentype) { + case TK_IDENTIFIER: + CPrec_NamePatch(¤t->data.tkidentifier, tokens->data.tkidentifier); + break; + case TK_INTCONST: + case TK_FLOATCONST: + break; + case TK_STRING: + case TK_STRING_WIDE: + CPrec_RawMemPatch(¤t->data.tkstring.data, tokens->data.tkstring.data, tokens->data.tkstring.size); + break; + case TK_EOL: + break; + default: + if (tokens->tokentype < 0) + CError_FATAL(2063); + } + x++; + tokens++; + current++; + } + + return first; +} + +static TemplFuncInstance *CPrec_GetTemplFuncInstancePatch(TemplFuncInstance *inst) { + AddrPatch *addrPatch; + TemplFuncInstance *first, *current, *next; + + if ((addrPatch = CPrec_FindAddrPatch(inst))) + return addrPatch->value; + + first = current = CPrec_AppendAlign(); + CPrec_NewAddrPatch(inst, first); + + do { + CPrec_AppendData(inst, sizeof(TemplFuncInstance)); + CPrec_NewPointerPatch(¤t->object, CPrec_GetObjectPatch(inst->object)); + CPrec_NewPointerPatch(¤t->args, CPrec_GetTemplateArgPatch(inst->args)); + + if (!inst->next) + break; + + if ((addrPatch = CPrec_FindAddrPatch(inst->next))) { + CPrec_NewPointerPatch(¤t->next, addrPatch->value); + break; + } else { + next = CPrec_AppendAlign(); + CPrec_NewPointerPatch(¤t->next, next); + current = next; + inst = inst->next; + CPrec_NewAddrPatch(inst, next); + } + } while (1); + + return first; +} + +static TemplateMember *CPrec_GetTemplateMemberPatch(TemplateMember *memb) { + TemplateMember *current, *first, *next; + first = current = CPrec_AppendAlign(); + + do { + memclrw(&memb->fileoffset, sizeof(FileOffsetInfo)); + memb->srcfile = NULL; + memb->startoffset = 0; + memb->endoffset = 0; + + CPrec_AppendData(memb, sizeof(TemplateMember)); + if (memb->params) + CPrec_NewPointerPatch(¤t->params, CPrec_GetTemplateParamPatch(memb->params)); + CPrec_NewPointerPatch(¤t->object, CPrec_GetObjectPatch(memb->object)); + if (memb->stream.firsttoken) + CPrec_NewPointerPatch(¤t->stream.firsttoken, CPrec_GetTStreamPatch(memb->stream.firsttoken, memb->stream.tokens)); + + if (!memb->next) + break; + next = CPrec_AppendAlign(); + CPrec_NewPointerPatch(¤t->next, next); + current = next; + memb = memb->next; + } while (1); + + return first; +} + +static TemplPartialSpec *CPrec_GetTemplPartialSpecPatch(TemplPartialSpec *pspec) { + TemplPartialSpec *first, *current, *next; + first = current = CPrec_AppendAlign(); + + do { + CPrec_AppendData(pspec, sizeof(TemplPartialSpec)); + if (pspec->templ) + CPrec_NewPointerPatch(¤t->templ, CPrec_GetTypePatch((Type *) pspec->templ)); + if (pspec->args) + CPrec_NewPointerPatch(¤t->args, CPrec_GetTemplateArgPatch(pspec->args)); + + if (!pspec->next) + break; + next = CPrec_AppendAlign(); + CPrec_NewPointerPatch(¤t->next, next); + current = next; + pspec = pspec->next; + } while (1); + + return first; +} + +static TemplateFriend *CPrec_GetTemplateFriendPatch(TemplateFriend *frnd) { + TemplateFriend *p; + + memclrw(&frnd->fileoffset, sizeof(FileOffsetInfo)); + p = CPrec_AppendAlign(); + CPrec_AppendData(frnd, sizeof(TemplateFriend)); + + if (frnd->decl.thetype) + CPrec_NewPointerPatch(&p->decl.thetype, CPrec_GetTypePatch(frnd->decl.thetype)); + if (frnd->decl.nspace) + CPrec_NewPointerPatch(&p->decl.nspace, CPrec_GetNameSpacePatch(frnd->decl.nspace)); + if (frnd->decl.name) + CPrec_NamePatch(&p->decl.name, frnd->decl.name); + if (frnd->decl.expltargs) + CPrec_NewPointerPatch(&p->decl.expltargs, CPrec_GetTemplateArgPatch(frnd->decl.expltargs)); + if (frnd->stream.firsttoken) + CPrec_NewPointerPatch(&p->stream.firsttoken, CPrec_GetTStreamPatch(frnd->stream.firsttoken, frnd->stream.tokens)); + + return p; +} + +static TemplateAction *CPrec_GetTemplateActionPatch(TemplateAction *act) { + // register swap issue + TemplateAction *current, *first, *next; + first = current = CPrec_AppendAlign(); + + do { + memclrw(&act->source_ref, sizeof(TStreamElement)); + CPrec_AppendData(act, sizeof(TemplateAction)); + + switch (act->type) { + case TAT_NESTEDCLASS: + CPrec_NewPointerPatch(¤t->u.tclasstype, CPrec_GetTypePatch((Type *) act->u.tclasstype)); + break; + case TAT_ENUMTYPE: + CPrec_NewPointerPatch(¤t->u.enumtype, CPrec_GetTypePatch((Type *) act->u.enumtype)); + break; + case TAT_FRIEND: + CPrec_NewPointerPatch(¤t->u.tfriend, CPrec_GetTemplateFriendPatch(act->u.tfriend)); + break; + case TAT_ENUMERATOR: + CPrec_NewPointerPatch(¤t->u.enumerator.objenumconst, CPrec_GetObjEnumConstPatch(act->u.enumerator.objenumconst)); + if (act->u.enumerator.initexpr) + CPrec_NewPointerPatch(¤t->u.enumerator.initexpr, CPrec_GetExpressionPatch(act->u.enumerator.initexpr)); + break; + case TAT_BASE: + CPrec_NewPointerPatch(¤t->u.base.type, CPrec_GetTypePatch(act->u.base.type)); + if (act->u.base.insert_after) + CPrec_NewPointerPatch(¤t->u.base.insert_after, CPrec_GetClassListPatch(act->u.base.insert_after)); + break; + case TAT_OBJECTINIT: + CPrec_NewPointerPatch(¤t->u.objectinit.object, CPrec_GetObjectPatch(act->u.objectinit.object)); + CPrec_NewPointerPatch(¤t->u.objectinit.initexpr, CPrec_GetExpressionPatch(act->u.objectinit.initexpr)); + break; + case TAT_USINGDECL: + CPrec_NewPointerPatch(¤t->u.usingdecl.type, CPrec_GetTypeTemplDepPatch(act->u.usingdecl.type)); + break; + case TAT_OBJECTDEF: + CPrec_NewPointerPatch(¤t->u.refobj, CPrec_GetObjBasePatch(act->u.refobj)); + break; + default: + CError_FATAL(2410); + } + + if (!act->next) + break; + next = CPrec_AppendAlign(); + CPrec_NewPointerPatch(¤t->next, next); + current = next; + act = act->next; + } while (1); + + return first; +} + +static TemplateFunction *CPrec_GetTemplateFunctionPatch(TemplateFunction *tf) { + // the same cursed register swaps + AddrPatch *addrPatch; + TemplateFunction *first, *current, *next; + + if ((addrPatch = CPrec_FindAddrPatch(tf))) + return addrPatch->value; + + first = current = CPrec_AppendAlign(); + CPrec_NewAddrPatch(tf, first); + + do { + memclrw(&tf->deftoken, sizeof(TStreamElement)); + tf->srcfile = NULL; + tf->startoffset = 0; + tf->endoffset = 0; + + CPrec_AppendData(tf, sizeof(TemplateFunction)); + if (tf->unk4) + CPrec_NewPointerPatch(¤t->unk4, CPrec_GetTemplateFunctionPatch(tf->unk4)); + CPrec_NamePatch(¤t->name, tf->name); + if (tf->params) + CPrec_NewPointerPatch(¤t->params, CPrec_GetTemplateParamPatch(tf->params)); + if (tf->stream.firsttoken) + CPrec_NewPointerPatch(¤t->stream.firsttoken, CPrec_GetTStreamPatch(tf->stream.firsttoken, tf->stream.tokens)); + CPrec_NewPointerPatch(¤t->tfunc, CPrec_GetObjectPatch(tf->tfunc)); + if (tf->instances) + CPrec_NewPointerPatch(¤t->instances, CPrec_GetTemplFuncInstancePatch(tf->instances)); + + if (!tf->next) + break; + + if ((addrPatch = CPrec_FindAddrPatch(tf->next))) { + CPrec_NewPointerPatch(¤t->next, addrPatch->value); + break; + } else { + next = CPrec_AppendAlign(); + CPrec_NewPointerPatch(¤t->next, next); + current = next; + tf = tf->next; + CPrec_NewAddrPatch(tf, next); + } + } while (1); + + return first; +} + +static TypeClass *CPrec_GetTypeClassPatch(TypeClass *tclass) { + TypeClass *first, *current, *next; + Boolean hasNextTempl, hasNextTemplInst; + first = current = CPrec_AppendAlign(); + + do_over: + hasNextTempl = hasNextTemplInst = 0; + CPrec_NewAddrPatch(tclass, current); + + if (tclass->flags & CLASS_IS_TEMPL) { + // template class + CPrec_AppendData(tclass, sizeof(TemplClass)); + if (TEMPL_CLASS(tclass)->next) + hasNextTempl = 1; + if (TEMPL_CLASS(tclass)->templ_parent) + CPrec_NewPointerPatch(&TEMPL_CLASS(current)->templ_parent, CPrec_GetTypePatch((Type *) TEMPL_CLASS(tclass)->templ_parent)); + if (TEMPL_CLASS(tclass)->inst_parent) + CPrec_NewPointerPatch(&TEMPL_CLASS(current)->inst_parent, CPrec_GetTypePatch((Type *) TEMPL_CLASS(tclass)->inst_parent)); + if (TEMPL_CLASS(tclass)->templ__params) + CPrec_NewPointerPatch(&TEMPL_CLASS(current)->templ__params, CPrec_GetTemplateParamPatch(TEMPL_CLASS(tclass)->templ__params)); + if (TEMPL_CLASS(tclass)->members) + CPrec_NewPointerPatch(&TEMPL_CLASS(current)->members, CPrec_GetTemplateMemberPatch(TEMPL_CLASS(tclass)->members)); + if (TEMPL_CLASS(tclass)->instances) + CPrec_NewPointerPatch(&TEMPL_CLASS(current)->instances, CPrec_GetTypePatch((Type *) TEMPL_CLASS(tclass)->instances)); + if (TEMPL_CLASS(tclass)->pspec_owner) + CPrec_NewPointerPatch(&TEMPL_CLASS(current)->pspec_owner, CPrec_GetTypePatch((Type *) TEMPL_CLASS(tclass)->pspec_owner)); + if (TEMPL_CLASS(tclass)->pspecs) + CPrec_NewPointerPatch(&TEMPL_CLASS(current)->pspecs, CPrec_GetTemplPartialSpecPatch(TEMPL_CLASS(tclass)->pspecs)); + if (TEMPL_CLASS(tclass)->actions) + CPrec_NewPointerPatch(&TEMPL_CLASS(current)->actions, CPrec_GetTemplateActionPatch(TEMPL_CLASS(tclass)->actions)); + } else if (tclass->flags & CLASS_IS_TEMPL_INST) { + // template class instance + CPrec_AppendData(tclass, sizeof(TemplClassInst)); + if (TEMPL_CLASS_INST(tclass)->next) + hasNextTemplInst = 1; + if (TEMPL_CLASS_INST(tclass)->parent) + CPrec_NewPointerPatch(&TEMPL_CLASS_INST(current)->parent, CPrec_GetTypePatch((Type *) TEMPL_CLASS_INST(tclass)->parent)); + if (TEMPL_CLASS_INST(tclass)->templ) + CPrec_NewPointerPatch(&TEMPL_CLASS_INST(current)->templ, CPrec_GetTypePatch((Type *) TEMPL_CLASS_INST(tclass)->templ)); + if (TEMPL_CLASS_INST(tclass)->inst_args) + CPrec_NewPointerPatch(&TEMPL_CLASS_INST(current)->inst_args, CPrec_GetTemplateArgPatch(TEMPL_CLASS_INST(tclass)->inst_args)); + if (TEMPL_CLASS_INST(tclass)->oargs) + CPrec_NewPointerPatch(&TEMPL_CLASS_INST(current)->oargs, CPrec_GetTemplateArgPatch(TEMPL_CLASS_INST(tclass)->oargs)); + } else { + // base + CPrec_AppendData(tclass, sizeof(TypeClass)); + } + + if (tclass->nspace) + CPrec_NewPointerPatch(¤t->nspace, CPrec_GetNameSpacePatch(tclass->nspace)); + if (tclass->classname) + CPrec_NamePatch(¤t->classname, tclass->classname); + if (tclass->bases) + CPrec_NewPointerPatch(¤t->bases, CPrec_GetClassListPatch(tclass->bases)); + if (tclass->vbases) + CPrec_NewPointerPatch(¤t->vbases, CPrec_GetVClassListPatch(tclass->vbases)); + if (tclass->ivars) + CPrec_NewPointerPatch(¤t->ivars, CPrec_GetObjMemberVarPatch(tclass->ivars)); + if (tclass->friends) + CPrec_NewPointerPatch(¤t->friends, CPrec_GetClassFriendPatch(tclass->friends)); + if (tclass->vtable) + CPrec_NewPointerPatch(¤t->vtable, CPrec_GetVTablePatch(tclass->vtable)); + if (tclass->sominfo) + CPrec_NewPointerPatch(¤t->sominfo, CPrec_GetSOMInfoPatch(tclass->sominfo)); + if (tclass->objcinfo) + CPrec_NewPointerPatch(¤t->objcinfo, CPrec_GetObjCInfoPatch(tclass->objcinfo)); + + if (hasNextTempl) { + AddrPatch *addrPatch = CPrec_FindAddrPatch(TEMPL_CLASS(tclass)->next); + if (!addrPatch) { + next = CPrec_AppendAlign(); + CPrec_NewPointerPatch(&TEMPL_CLASS(current)->next, next); + current = next; + tclass = (TypeClass *) TEMPL_CLASS(tclass)->next; + goto do_over; + } else { + CPrec_NewPointerPatch(&TEMPL_CLASS(current)->next, addrPatch->value); + } + } + + if (hasNextTemplInst) { + AddrPatch *addrPatch = CPrec_FindAddrPatch(TEMPL_CLASS_INST(tclass)->next); + if (!addrPatch) { + next = CPrec_AppendAlign(); + CPrec_NewPointerPatch(&TEMPL_CLASS_INST(current)->next, next); + current = next; + tclass = (TypeClass *) TEMPL_CLASS_INST(tclass)->next; + goto do_over; + } else { + CPrec_NewPointerPatch(&TEMPL_CLASS_INST(current)->next, addrPatch->value); + } + } + + return first; +} + +static Type *CPrec_GetTypePatch(Type *type) { + AddrPatch *addrPatch = CPrec_FindAddrPatch(type); + if (addrPatch) + return addrPatch->value; + + switch (type->type) { + case TYPEPOINTER: + case TYPEARRAY: + return (Type *) CPrec_GetTypePointerPatch(TYPE_POINTER(type)); + case TYPEENUM: + return (Type *) CPrec_GetTypeEnumPatch(TYPE_ENUM(type)); + case TYPEBITFIELD: + return (Type *) CPrec_GetTypeBitfieldPatch(TYPE_BITFIELD(type)); + case TYPESTRUCT: + return (Type *) CPrec_GetTypeStructPatch(TYPE_STRUCT(type)); + case TYPEFUNC: + return (Type *) CPrec_GetTypeFuncPatch(TYPE_FUNC(type)); + case TYPEMEMBERPOINTER: + return (Type *) CPrec_GetTypeMemberPointerPatch(TYPE_MEMBER_POINTER(type)); + case TYPETEMPLATE: + return (Type *) CPrec_GetTypeTemplDepPatch(TYPE_TEMPLATE(type)); + case TYPECLASS: + return (Type *) CPrec_GetTypeClassPatch(TYPE_CLASS(type)); + case TYPEVOID: + case TYPEINT: + case TYPEFLOAT: + case TYPELABEL: + case TYPEOBJCID: + case TYPETEMPLDEPEXPR: + default: + CError_FATAL(2796); + return NULL; + } +} + +static ExceptionAction *CPrec_GetExceptionPatch(ExceptionAction *exc) { + ExceptionAction *first, *current, *next; + + first = current = CPrec_AppendAlign(); +repeat: + CPrec_AppendData(exc, sizeof(ExceptionAction)); + switch (exc->type) { + case EAT_DESTROYLOCAL: + CPrec_NewPointerPatch(¤t->data.destroy_local.dtor, CPrec_GetObjectPatch(exc->data.destroy_local.dtor)); + break; + case EAT_DESTROYLOCALCOND: + CPrec_NewPointerPatch(¤t->data.destroy_local_cond.dtor, CPrec_GetObjectPatch(exc->data.destroy_local_cond.dtor)); + break; + case EAT_DESTROYLOCALOFFSET: + CPrec_NewPointerPatch(¤t->data.destroy_local_offset.dtor, CPrec_GetObjectPatch(exc->data.destroy_local_offset.dtor)); + break; + case EAT_DESTROYLOCALPOINTER: + CPrec_NewPointerPatch(¤t->data.destroy_local_pointer.dtor, CPrec_GetObjectPatch(exc->data.destroy_local_pointer.dtor)); + break; + case EAT_DESTROYLOCALARRAY: + CPrec_NewPointerPatch(¤t->data.destroy_local_array.dtor, CPrec_GetObjectPatch(exc->data.destroy_local_array.dtor)); + break; + case EAT_DESTROYPARTIALARRAY: + break; + case EAT_DESTROYMEMBER: + case EAT_DESTROYBASE: + CPrec_NewPointerPatch(¤t->data.destroy_member.dtor, CPrec_GetObjectPatch(exc->data.destroy_member.dtor)); + break; + case EAT_DESTROYMEMBERCOND: + CPrec_NewPointerPatch(¤t->data.destroy_member_cond.dtor, CPrec_GetObjectPatch(exc->data.destroy_member_cond.dtor)); + break; + case EAT_DESTROYMEMBERARRAY: + CPrec_NewPointerPatch(¤t->data.destroy_member_array.dtor, CPrec_GetObjectPatch(exc->data.destroy_member_array.dtor)); + break; + case EAT_DELETEPOINTER: + case EAT_DELETELOCALPOINTER: + CPrec_NewPointerPatch(¤t->data.delete_pointer.deletefunc, CPrec_GetObjectPatch(exc->data.delete_pointer.deletefunc)); + break; + case EAT_DELETEPOINTERCOND: + CPrec_NewPointerPatch(¤t->data.delete_pointer_cond.deletefunc, CPrec_GetObjectPatch(exc->data.delete_pointer_cond.deletefunc)); + break; + case EAT_CATCHBLOCK: + if (exc->data.catch_block.catch_typeid) { + CPrec_NewPointerPatch(¤t->data.catch_block.catch_typeid, CPrec_GetObjectPatch(exc->data.catch_block.catch_typeid)); + CPrec_NewPointerPatch(¤t->data.catch_block.catch_type, CPrec_GetTypePatch(exc->data.catch_block.catch_type)); + } + break; + case EAT_ACTIVECATCHBLOCK: + break; + case EAT_SPECIFICATION: + if (exc->data.specification.unexp_id) { + int x; + char *ptrs; + ptrs = CPrec_AppendAlign(); + CPrec_NewPointerPatch(¤t->data.specification.unexp_id, ptrs); + CPrec_AppendData(exc->data.specification.unexp_id, sizeof(Object *) * exc->data.specification.unexp_ids); + for (x = 0; x < exc->data.specification.unexp_ids; x++) { + CPrec_NewPointerPatch(ptrs + x * sizeof(Object *), CPrec_GetObjectPatch(exc->data.specification.unexp_id[x])); + } + } + break; + case EAT_TERMINATE: + break; + default: + CError_FATAL(2905); + } + + if (exc->prev) { + next = CPrec_AppendAlign(); + CPrec_NewPointerPatch(¤t->prev, next); + current = next; + exc = exc->prev; + goto repeat; + } + return first; +} + +static ENodeList *CPrec_GetExpressionListPatch(ENodeList *lst) { + ENodeList *first, *current, *next; + first = current = CPrec_AppendAlign(); + + do { + CPrec_AppendData(lst, sizeof(ENodeList)); + CPrec_NewPointerPatch(¤t->node, CPrec_GetExpressionPatch(lst->node)); + + if (!lst->next) + break; + next = CPrec_AppendAlign(); + CPrec_NewPointerPatch(¤t->next, next); + current = next; + lst = lst->next; + } while (1); + + return first; +} + +static EMemberInfo *CPrec_GetEMemberInfoPatch(EMemberInfo *emember) { + EMemberInfo *p; + + CError_FATAL(2953); + + p = CPrec_AppendAlign(); + CPrec_AppendData(emember, sizeof(EMemberInfo)); + + if (emember->path) + CPrec_NewPointerPatch(&p->path, CPrec_GetClassAccessPatch(emember->path)); + if (emember->expr) + CPrec_NewPointerPatch(&p->expr, CPrec_GetExpressionPatch(emember->expr)); + CError_ASSERT(2968, !emember->templargs); + CPrec_NewPointerPatch(&p->list, CPrec_GetNameSpaceObjectListPatch(emember->list)); + + return p; +} + +static ENode *CPrec_GetExpressionPatch(ENode *expr) { + ENode *p; + + if (ENODE_IS(expr, ETEMPLDEP) && expr->data.templdep.subtype == TDE_SOURCEREF) + expr->data.templdep.u.sourceref.token = NULL; + + p = CPrec_AppendAlign(); + CPrec_AppendData(expr, sizeof(ENode)); + + CPrec_NewPointerPatch(&p->rtype, CPrec_GetTypePatch(expr->rtype)); + + switch (expr->type) { + ENODE_CASE_MONADIC: + CPrec_NewPointerPatch(&p->data.monadic, CPrec_GetExpressionPatch(expr->data.monadic)); + break; + ENODE_CASE_DIADIC_ALL: + CPrec_NewPointerPatch(&p->data.diadic.left, CPrec_GetExpressionPatch(expr->data.diadic.left)); + CPrec_NewPointerPatch(&p->data.diadic.right, CPrec_GetExpressionPatch(expr->data.diadic.right)); + break; + case ECOND: + CPrec_NewPointerPatch(&p->data.cond.cond, CPrec_GetExpressionPatch(expr->data.cond.cond)); + CPrec_NewPointerPatch(&p->data.cond.expr1, CPrec_GetExpressionPatch(expr->data.cond.expr1)); + CPrec_NewPointerPatch(&p->data.cond.expr2, CPrec_GetExpressionPatch(expr->data.cond.expr2)); + break; + case ESTRINGCONST: + CPrec_RawMemPatch(&p->data.string.data, expr->data.string.data, expr->data.string.size); + break; + case EOBJREF: + CPrec_NewPointerPatch(&p->data.objref, CPrec_GetObjectPatch(expr->data.objref)); + break; + case EOBJLIST: + CPrec_NewPointerPatch(&p->data.objlist.list, CPrec_GetNameSpaceObjectListPatch(expr->data.objlist.list)); + CError_ASSERT(3043, !expr->data.objlist.templargs); + if (expr->data.objlist.name) + CPrec_NamePatch(&p->data.objlist.name, expr->data.objlist.name); + break; + case EMFPOINTER: + CPrec_NewPointerPatch(&p->data.mfpointer.accessnode, CPrec_GetExpressionPatch(expr->data.mfpointer.accessnode)); + CPrec_NewPointerPatch(&p->data.mfpointer.mfpointer, CPrec_GetExpressionPatch(expr->data.mfpointer.mfpointer)); + break; + case ENULLCHECK: + CPrec_NewPointerPatch(&p->data.nullcheck.nullcheckexpr, CPrec_GetExpressionPatch(expr->data.nullcheck.nullcheckexpr)); + CPrec_NewPointerPatch(&p->data.nullcheck.condexpr, CPrec_GetExpressionPatch(expr->data.nullcheck.condexpr)); + break; + case ETEMP: + CPrec_NewPointerPatch(&p->data.temp.type, CPrec_GetTypePatch(expr->data.temp.type)); + break; + case EFUNCCALL: + case EFUNCCALLP: + CPrec_NewPointerPatch(&p->data.funccall.funcref, CPrec_GetExpressionPatch(expr->data.funccall.funcref)); + CPrec_NewPointerPatch(&p->data.funccall.functype, CPrec_GetTypePatch(TYPE(expr->data.funccall.functype))); + if (expr->data.funccall.args) + CPrec_NewPointerPatch(&p->data.funccall.args, CPrec_GetExpressionListPatch(expr->data.funccall.args)); + break; + case EMEMBER: + CPrec_NewPointerPatch(&p->data.emember, CPrec_GetEMemberInfoPatch(expr->data.emember)); + break; + case ETEMPLDEP: + switch (expr->data.templdep.subtype) { + case TDE_PARAM: + break; + case TDE_SIZEOF: + case TDE_ALIGNOF: + CPrec_NewPointerPatch(&p->data.templdep.u.typeexpr.type, CPrec_GetTypePatch(expr->data.templdep.u.typeexpr.type)); + break; + case TDE_CAST: + if (expr->data.templdep.u.cast.args) + CPrec_NewPointerPatch(&p->data.templdep.u.cast.args, CPrec_GetExpressionListPatch(expr->data.templdep.u.cast.args)); + CPrec_NewPointerPatch(&p->data.templdep.u.cast.type, CPrec_GetTypePatch(expr->data.templdep.u.cast.type)); + break; + case TDE_QUALNAME: + CPrec_NamePatch(&p->data.templdep.u.qual.name, expr->data.templdep.u.qual.name); + CPrec_NewPointerPatch(&p->data.templdep.u.qual.type, CPrec_GetTypePatch(TYPE(expr->data.templdep.u.qual.type))); + break; + case TDE_OBJ: + CPrec_NewPointerPatch(&p->data.templdep.u.obj, CPrec_GetObjectPatch(expr->data.templdep.u.obj)); + break; + case TDE_SOURCEREF: + CPrec_NewPointerPatch(&p->data.templdep.u.sourceref.expr, CPrec_GetExpressionPatch(expr->data.templdep.u.sourceref.expr)); + break; + case TDE_ADDRESS_OF: + CPrec_NewPointerPatch(&p->data.templdep.u.monadic, CPrec_GetExpressionPatch(expr->data.templdep.u.monadic)); + break; + default: + CError_FATAL(3136); + } + break; + case EINTCONST: + case EFLOATCONST: + case EPRECOMP: + case EARGOBJ: + case ELOCOBJ: + case ELABEL: + case EINSTRUCTION: + case EVECTOR128CONST: + break; + default: + CError_FATAL(3142); + } + + return p; +} + +static CI_Switch *CPrec_GetSwitchInfoPatch(CI_Switch *si) { + CI_Switch *p = CPrec_AppendAlign(); + CPrec_AppendData(si, sizeof(CI_Switch) + sizeof(CI_SwitchCase) * (si->numcases - 1)); + + CPrec_NewPointerPatch(&p->expr, CPrec_GetExpressionPatch(si->expr)); + CPrec_NewPointerPatch(&p->unkSwitch8, CPrec_GetTypePatch(si->unkSwitch8)); + return p; +} + +static InlineAsm *CPrec_GetInlineAsmPatch(InlineAsm *ia, SInt32 size) { + InlineAsm *p; + SInt32 index; + SInt32 offset; + Object *object; + + p = CPrec_AppendAlign(); + CPrec_AppendData(ia, size); + + index = 0; + while (1) { + object = InlineAsm_GetObjectOffset(ia, index, &offset); + if (!object) + break; + + object = CPrec_GetObjectPatch(object); + CPrec_NewPointerPatch((char *) p + offset, object); + index++; + } + + return p; +} + +static CI_Statement *CPrec_GetStatementPatch(CI_Statement *stmt, short count) { + short i; + CI_Statement *first, *current; + + for (i = 0; i < count; i++) { + stmt[i].sourcefilepath = NULL; + stmt[i].sourceoffset = -1; + } + + first = current = CPrec_AppendAlign(); + CPrec_AppendData(stmt, sizeof(CI_Statement) * count); + + for (i = 0; i < count; i++) { + if (stmt->dobjstack) + CPrec_NewPointerPatch(¤t->dobjstack, CPrec_GetExceptionPatch(stmt->dobjstack)); + + switch (stmt->type) { + case ST_EXPRESSION: + case ST_RETURN: + case ST_BEGINCATCH: + case ST_ENDCATCH: + case ST_ENDCATCHDTOR: + if (stmt->u.expr) + CPrec_NewPointerPatch(¤t->u.expr, CPrec_GetExpressionPatch(stmt->u.expr)); + break; + case ST_IFGOTO: + case ST_IFNGOTO: + CPrec_NewPointerPatch(¤t->u.ifgoto.expr, CPrec_GetExpressionPatch(stmt->u.ifgoto.expr)); + break; + case ST_SWITCH: + CPrec_NewPointerPatch(¤t->u.switchdata, CPrec_GetSwitchInfoPatch(stmt->u.switchdata)); + break; + case ST_ASM: + CPrec_NewPointerPatch(¤t->u.asmdata.data, CPrec_GetInlineAsmPatch(stmt->u.asmdata.data, stmt->u.asmdata.size)); + break; + case ST_NOP: + case ST_LABEL: + case ST_GOTO: + break; + default: + CError_FATAL(3261); + } + + current++; + stmt++; + } + + return first; +} + +static CI_Var *CPrec_GetLocObjectPatch(CI_Var *obj, short count) { + CI_Var *first, *current; + short i; + + first = current = CPrec_AppendAlign(); + CPrec_AppendData(obj, sizeof(CI_Var) * count); + + for (i = 0; i < count; i++) { + CPrec_NamePatch(¤t->name, obj->name); + CPrec_NewPointerPatch(¤t->type, CPrec_GetTypePatch(obj->type)); + current++; + obj++; + } + + return first; +} + +static CI_FuncData *CPrec_GetInlineFuncPatch(CI_FuncData *ifunc) { + CI_FuncData *p; + + memclrw(&ifunc->fileoffset, sizeof(FileOffsetInfo)); + ifunc->symdecloffset = 0; + ifunc->functionbodyoffset = 0; + ifunc->functionbodypath = NULL; + ifunc->symdeclend = 0; + + p = CPrec_AppendAlign(); + CPrec_AppendData(ifunc, sizeof(CI_FuncData)); + + if (ifunc->numarguments) + CPrec_NewPointerPatch(&p->arguments, CPrec_GetLocObjectPatch(ifunc->arguments, ifunc->numarguments)); + if (ifunc->numlocals) + CPrec_NewPointerPatch(&p->locals, CPrec_GetLocObjectPatch(ifunc->locals, ifunc->numlocals)); + if (ifunc->numstatements) + CPrec_NewPointerPatch(&p->statements, CPrec_GetStatementPatch(ifunc->statements, ifunc->numstatements)); + + return p; +} + +static ObjEnumConst *CPrec_GetObjEnumConstPatch(ObjEnumConst *obj) { + AddrPatch *addrPatch; + ObjEnumConst *first, *current, *next; + + if ((addrPatch = CPrec_FindAddrPatch(obj))) + return addrPatch->value; + + first = current = CPrec_AppendAlign(); + CPrec_NewAddrPatch(obj, first); + + do { + CPrec_AppendData(obj, sizeof(ObjEnumConst)); + if (cprec_dowrite) { + CError_ASSERT(3349, obj->access != 255); + obj->access = 255; + } + CPrec_NamePatch(¤t->name, obj->name); + CPrec_NewPointerPatch(¤t->type, CPrec_GetTypePatch( obj->type)); + + if (!obj->next) + break; + + if ((addrPatch = CPrec_FindAddrPatch(obj->next))) { + CPrec_NewPointerPatch(¤t->next, addrPatch->value); + break; + } else { + next = CPrec_AppendAlign(); + CPrec_NewPointerPatch(¤t->next, next); + current = next; + obj = obj->next; + CPrec_NewAddrPatch(obj, next); + } + } while (1); + + return first; +} + +static ObjType *CPrec_GetObjTypePatch(ObjType *obj) { + AddrPatch *addrPatch; + ObjType *p; + + if ((addrPatch = CPrec_FindAddrPatch(obj))) + return addrPatch->value; + + p = CPrec_AppendAlign(); + CPrec_NewAddrPatch(obj, p); + CPrec_AppendData(obj, sizeof(ObjType)); + CPrec_NewPointerPatch(&p->type, CPrec_GetTypePatch(obj->type)); + return p; +} + +static ObjTypeTag *CPrec_GetObjTypeTagPatch(ObjTypeTag *obj) { + AddrPatch *addrPatch; + ObjTypeTag *p; + + if ((addrPatch = CPrec_FindAddrPatch(obj))) + return addrPatch->value; + + p = CPrec_AppendAlign(); + CPrec_NewAddrPatch(obj, p); + CPrec_AppendData(obj, sizeof(ObjTypeTag)); + CPrec_NewPointerPatch(&p->type, CPrec_GetTypePatch(obj->type)); + return p; +} + +static ObjNameSpace *CPrec_GetObjNameSpacePatch(ObjNameSpace *obj) { + AddrPatch *addrPatch; + ObjNameSpace *p; + + if ((addrPatch = CPrec_FindAddrPatch(obj))) + return addrPatch->value; + + p = CPrec_AppendAlign(); + CPrec_NewAddrPatch(obj, p); + CPrec_AppendData(obj, sizeof(ObjNameSpace)); + CPrec_NewPointerPatch(&p->nspace, CPrec_GetNameSpacePatch(obj->nspace)); + return p; +} + +static ObjMemberVar *CPrec_GetObjMemberVarPatch(ObjMemberVar *ivar) { + AddrPatch *addrPatch; + ObjMemberVar *first, *current, *next; + + if ((addrPatch = CPrec_FindAddrPatch(ivar))) + return addrPatch->value; + + first = current = CPrec_AppendAlign(); + CPrec_NewAddrPatch(ivar, first); + + while (1) { + if (ivar->has_path) { + CPrec_AppendData(ivar, sizeof(ObjMemberVarPath)); + if (OBJ_MEMBER_VAR_PATH(ivar)->path) + CPrec_NewPointerPatch( + &OBJ_MEMBER_VAR_PATH(current)->path, + CPrec_GetClassAccessPatch(OBJ_MEMBER_VAR_PATH(ivar)->path)); + } else { + CPrec_AppendData(ivar, sizeof(ObjMemberVar)); + } + + if (ivar->name) + CPrec_NamePatch(¤t->name, ivar->name); + CPrec_NewPointerPatch(¤t->type, CPrec_GetTypePatch(ivar->type)); + + if (!ivar->next) + break; + + if ((addrPatch = CPrec_FindAddrPatch(ivar->next))) { + CPrec_NewPointerPatch(¤t->next, addrPatch->value); + break; + } + + next = CPrec_AppendAlign(); + CPrec_NewPointerPatch(¤t->next, next); + + current = next; + ivar = ivar->next; + CPrec_NewAddrPatch(ivar, current); + } + + return first; +} + +static DefArgCtorInfo *CPrec_GetDefArgCtorInfoPatch(DefArgCtorInfo *dac) { + DefArgCtorInfo *p = CPrec_AppendAlign(); + CPrec_AppendData(dac, sizeof(DefArgCtorInfo)); + CPrec_NewPointerPatch(&p->default_func, CPrec_GetObjectPatch(dac->default_func)); + CPrec_NewPointerPatch(&p->default_arg, CPrec_GetExpressionPatch(dac->default_arg)); + return p; +} + +static InlineXRef *CPrec_GetInlineXRefPatch(InlineXRef *ix) { + InlineXRef *first, *current, *next; + first = current = CPrec_AppendAlign(); + + do { + CPrec_AppendData(ix, sizeof(InlineXRef) + sizeof(XRefOffset) * (ix->numxrefs - 1)); + CPrec_NewPointerPatch(¤t->object, CPrec_GetObjectPatch(ix->object)); + + if (!ix->next) + break; + next = CPrec_AppendAlign(); + CPrec_NewPointerPatch(¤t->next, next); + current = next; + ix = ix->next; + } while (1); + + return first; +} + +static Object *CPrec_GetObjectPatch(Object *obj) { + AddrPatch *addrPatch; + Object *p; + + if (CWUserBreak(cparams.context) != cwNoErr) + CError_UserBreak(); + + if ((addrPatch = CPrec_FindAddrPatch(obj))) + return addrPatch->value; + + p = CPrec_AppendAlign(); + CPrec_NewAddrPatch(obj, p); + + obj->toc = NULL; + + if ((obj->qual & Q_IS_TEMPLATED) && obj->datatype != DALIAS) { + CPrec_AppendData(obj, sizeof(ObjectTemplated)); + CPrec_NewPointerPatch(&OBJECT_TEMPL(p)->parent, CPrec_GetObjectPatch(OBJECT_TEMPL(obj)->parent)); + } else { + CPrec_AppendData(obj, sizeof(Object)); + } + + if (obj->nspace) + CPrec_NewPointerPatch(&p->nspace, CPrec_GetNameSpacePatch(obj->nspace)); + if (obj->name) + CPrec_NamePatch(&p->name, obj->name); + CPrec_NewPointerPatch(&p->type, CPrec_GetTypePatch(obj->type)); + + switch (obj->datatype) { + case DABSOLUTE: + break; + + case DLOCAL: + CError_FATAL(3580); + break; + + case DFUNC: + case DVFUNC: + if (IS_TEMPL_FUNC(obj->type)) + CPrec_NewPointerPatch(&p->u.func.u.templ, CPrec_GetTemplateFunctionPatch(obj->u.func.u.templ)); + else if ((obj->qual & Q_INLINE) && obj->u.func.u.ifuncdata) + CPrec_NewPointerPatch(&p->u.func.u.ifuncdata, CPrec_GetInlineFuncPatch(obj->u.func.u.ifuncdata)); + + if (obj->u.func.defargdata) + CPrec_NewPointerPatch(&p->u.func.defargdata, CPrec_GetDefArgCtorInfoPatch(obj->u.func.defargdata)); + if (obj->u.func.linkname) + CPrec_NamePatch(&p->u.func.linkname, obj->u.func.linkname); + if (obj->u.func.inst) + CPrec_NewPointerPatch(&p->u.func.inst, CPrec_GetTemplFuncInstancePatch(obj->u.func.inst)); + break; + + case DDATA: + CError_ASSERT(3622, !obj->u.data.info); + if (obj->qual & Q_INLINE_DATA) { + switch (obj->type->type) { + case TYPEINT: + case TYPEENUM: + case TYPEPOINTER: + break; + case TYPEFLOAT: + CPrec_RawMemPatch(&p->u.data.u.floatconst, obj->u.data.u.floatconst, sizeof(Float)); + break; + default: + CError_FATAL(3638); + } + } + if (obj->u.data.linkname) + CPrec_NamePatch(&p->u.data.linkname, obj->u.data.linkname); + break; + + case DINLINEFUNC: + CPrec_RawMemPatch(&p->u.ifunc.data, obj->u.ifunc.data, obj->u.ifunc.size); + if (obj->u.ifunc.xrefs) + CPrec_NewPointerPatch(&p->u.ifunc.xrefs, CPrec_GetInlineXRefPatch(obj->u.ifunc.xrefs)); + break; + + case DALIAS: + CPrec_NewPointerPatch(&p->u.alias.object, CPrec_GetObjectPatch(obj->u.alias.object)); + if (obj->u.alias.member) + CPrec_NewPointerPatch(&p->u.alias.member, CPrec_GetClassAccessPatch(obj->u.alias.member)); + break; + + default: + CError_FATAL(3677); + } + + if (cprec_dowrite) + obj->datatype = -1; + + return p; +} + +static ObjBase *CPrec_GetObjBasePatch(ObjBase *obj) { + switch (obj->otype) { + default: + CError_FATAL(3694); + case OT_ENUMCONST: + return (ObjBase *) CPrec_GetObjEnumConstPatch((ObjEnumConst *) obj); + case OT_TYPE: + return (ObjBase *) CPrec_GetObjTypePatch((ObjType *) obj); + case OT_TYPETAG: + return (ObjBase *) CPrec_GetObjTypeTagPatch((ObjTypeTag *) obj); + case OT_NAMESPACE: + return (ObjBase *) CPrec_GetObjNameSpacePatch((ObjNameSpace *) obj); + case OT_MEMBERVAR: + return (ObjBase *) CPrec_GetObjMemberVarPatch((ObjMemberVar *) obj); + case OT_OBJECT: + return (ObjBase *) CPrec_GetObjectPatch((Object *) obj); + } +} + +static ObjectList *CPrec_GetObjectListPatch(ObjectList *ol) { + AddrPatch *addrPatch; + ObjectList *first, *current, *next; + + if ((addrPatch = CPrec_FindAddrPatch(ol))) + return addrPatch->value; + + first = current = CPrec_AppendAlign(); + CPrec_NewAddrPatch(ol, first); +restart: + CPrec_AppendData(ol, sizeof(ObjectList)); + CPrec_NewPointerPatch(¤t->object, CPrec_GetObjectPatch(ol->object)); + if (ol->next) { + next = CPrec_AppendAlign(); + CPrec_NewPointerPatch(¤t->next, next); + current = next; + ol = ol->next; + goto restart; + } + + return first; +} + +static NameSpaceObjectList *CPrec_GetNameSpaceObjectListPatch(NameSpaceObjectList *nsol) { + AddrPatch *addrPatch; + NameSpaceObjectList *first, *current, *next; + + if ((addrPatch = CPrec_FindAddrPatch(nsol))) + return addrPatch->value; + + first = current = CPrec_AppendAlign(); + CPrec_NewAddrPatch(nsol, first); + + do { + CPrec_AppendData(nsol, sizeof(NameSpaceObjectList)); + CPrec_NewPointerPatch(¤t->object, CPrec_GetObjBasePatch(nsol->object)); + + if (!nsol->next) + break; + + if ((addrPatch = CPrec_FindAddrPatch(nsol->next))) { + CPrec_NewPointerPatch(¤t->next, addrPatch->value); + break; + } else { + next = CPrec_AppendAlign(); + CPrec_NewPointerPatch(¤t->next, next); + current = next; + nsol = nsol->next; + CPrec_NewAddrPatch(nsol, next); + } + } while (1); + + return first; +} + +static NameSpaceName *CPrec_GetNameSpaceNamePatch(NameSpaceName *nsn, Boolean flag) { + AddrPatch *addrPatch; + NameSpaceName *first, *current, *next; + + if ((addrPatch = CPrec_FindAddrPatch(nsn))) + return addrPatch->value; + + first = current = CPrec_AppendAlign(); + CPrec_NewAddrPatch(nsn, first); + + do { + CPrec_AppendData(nsn, sizeof(NameSpaceName)); + CPrec_NamePatch(¤t->name, nsn->name); + CPrec_NewPointerPatch(¤t->first.object, CPrec_GetObjBasePatch(nsn->first.object)); + if (nsn->first.next) + CPrec_NewPointerPatch(¤t->first.next, CPrec_GetNameSpaceObjectListPatch(nsn->first.next)); + + if (!nsn->next) + break; + + if ((addrPatch = CPrec_FindAddrPatch(nsn->next))) { + CPrec_NewPointerPatch(¤t->next, addrPatch->value); + break; + } else { + next = CPrec_AppendAlign(); + CPrec_NewPointerPatch(¤t->next, next); + current = next; + nsn = nsn->next; + CPrec_NewAddrPatch(nsn, next); + } + } while (!flag || !cprec_dowrite || CPrec_FlushBufferCheck() == noErr); + + return first; +} + +static NameSpaceList *CPrec_GetNameSpaceListPatch(NameSpaceList *nsl) { + NameSpaceList *first, *current, *next; + first = current = CPrec_AppendAlign(); + + do { + CPrec_AppendData(nsl, sizeof(NameSpaceList)); + CPrec_NewPointerPatch(¤t->nspace, CPrec_GetNameSpacePatch(nsl->nspace)); + + if (!nsl->next) + break; + next = CPrec_AppendAlign(); + CPrec_NewPointerPatch(¤t->next, next); + current = next; + nsl = nsl->next; + } while (1); + + return first; +} + +static NameSpace *CPrec_GetNameSpacePatch(NameSpace *nspace) { + NameSpace *p; + AddrPatch *addrPatch; + + if ((addrPatch = CPrec_FindAddrPatch(nspace))) + return addrPatch->value; + + p = CPrec_AppendAlign(); + CPrec_NewAddrPatch(nspace, p); + CPrec_AppendData(nspace, sizeof(NameSpace)); + + if (nspace->parent) + CPrec_NewPointerPatch(&p->parent, CPrec_GetNameSpacePatch(nspace->parent)); + if (nspace->name) + CPrec_NamePatch(&p->name, nspace->name); + if (nspace->usings) + CPrec_NewPointerPatch(&p->usings, CPrec_GetNameSpaceListPatch(nspace->usings)); + if (nspace->theclass) + CPrec_NewPointerPatch(&p->theclass, CPrec_GetTypePatch((Type *) nspace->theclass)); + + if (nspace->is_hash) { + char *hash; + int i; + hash = CPrec_AppendAlign(); + CPrec_NewPointerPatch(&p->data.hash, hash); + CPrec_AppendData(nspace->data.hash, sizeof(NameSpaceName *) * 1024); + for (i = 0; i < 1024; i++) { + if (nspace->data.hash[i]) + CPrec_NewPointerPatch(hash + (i * sizeof(NameSpaceName *)), CPrec_GetNameSpaceNamePatch(nspace->data.hash[i], 0)); + } + } else if (nspace->data.list) { + CPrec_NewPointerPatch(&p->data.list, CPrec_GetNameSpaceNamePatch(nspace->data.list, 0)); + } + + return p; +} + +static void CPrec_DumpRootNameSpace(void) { + NameSpaceList *nslist; + NameSpaceName *nsname; + int i; + + CError_ASSERT(3905, cscope_root->is_hash); + + if (cscope_root->usings) { + nslist = CPrec_GetNameSpaceListPatch(cscope_root->usings); + if (cprec_dowrite) + cprec_header->usings = nslist; + } + + if (cprec_dowrite) + cprec_header->root_names = cscope_root->names; + + i = 0; + do { + if (cscope_root->data.hash[i]) { + nsname = CPrec_GetNameSpaceNamePatch(cscope_root->data.hash[i], 1); + if (cprec_dowrite) { + if (cprec_ioerror != noErr) + break; + cprec_header->root_nametable[i] = nsname; + } + } + } while (++i < 0x400); +} + +static CSOMStub *CPrec_GetSOMPatch(CSOMStub *stub) { + CSOMStub *first, *current, *next; + + first = current = CPrec_AppendAlign(); + while (1) { + CPrec_AppendData(stub, sizeof(CSOMStub)); + + CPrec_NewPointerPatch(¤t->object, CPrec_GetObjectPatch(stub->object)); + CPrec_NewPointerPatch(¤t->tclass, CPrec_GetTypePatch(TYPE(stub->tclass))); + + if (!stub->next) + break; + + next = CPrec_AppendAlign(); + CPrec_NewPointerPatch(¤t->next, next); + current = next; + stub = stub->next; + } + + return first; +} + +static OLinkList *CPrec_GetOLinkPatch(OLinkList *olink) { + OLinkList *first, *current, *next; + + first = current = CPrec_AppendAlign(); + while (1) { + CPrec_AppendData(olink, sizeof(OLinkList)); + + CPrec_NewPointerPatch(¤t->obj, CPrec_GetObjectPatch(olink->obj)); + + if (!olink->next) + break; + + next = CPrec_AppendAlign(); + CPrec_NewPointerPatch(¤t->next, next); + current = next; + olink = olink->next; + } + + return first; +} + +static StaticData *CPrec_GetStaticDataPatch(StaticData *sd) { + StaticData *current, *first, *next; + + first = current = CPrec_AppendAlign(); + while (1) { + CPrec_AppendData(sd, sizeof(StaticData)); + + CPrec_NewPointerPatch(¤t->object, CPrec_GetObjectPatch(sd->object)); + if (sd->buffer) + CPrec_RawMemPatch(¤t->buffer, sd->buffer, sd->object->type->size); + if (sd->links) + CPrec_NewPointerPatch(¤t->links, CPrec_GetOLinkPatch(sd->links)); + + if (!sd->next) + break; + + next = CPrec_AppendAlign(); + CPrec_NewPointerPatch(¤t->next, next); + current = next; + sd = sd->next; + } + + return first; +} + +static CallbackAction *CPrec_GetCallbackPatch(CallbackAction *ca) { + CallbackAction *first, *current, *next; + + first = current = CPrec_AppendAlign(); + while (1) { + CPrec_AppendData(ca, sizeof(CallbackAction)); + + CPrec_NewPointerPatch(¤t->obj, CPrec_GetObjectPatch(ca->obj)); + CPrec_NewPointerPatch(¤t->tclass, CPrec_GetTypePatch(TYPE(ca->tclass))); + + if (!ca->next) + break; + + next = CPrec_AppendAlign(); + CPrec_NewPointerPatch(¤t->next, next); + current = next; + ca = ca->next; + } + + return first; +} + +static ObjCSelector **CPrec_GetSelHashTablePatch(ObjCSelector **table) { + ObjCSelector **first, **current; + int i; + + first = current = CPrec_AppendAlign(); + CPrec_AppendData(table, sizeof(ObjCSelector *) * 0x400); + + for (i = 0; i < 0x400; i++) { + if (*table) + CPrec_NewPointerPatch(current, CPrec_GetObjCSelectorPatch(*table)); + table++; + current++; + } + + return first; +} + +static InitExpr *CPrec_GetIExpressionPatch(InitExpr *initexpr) { + InitExpr *first, *current, *next; + + first = current = CPrec_AppendAlign(); + while (1) { + CPrec_AppendData(initexpr, sizeof(InitExpr)); + + CPrec_NewPointerPatch(¤t->object, CPrec_GetObjectPatch(initexpr->object)); + CPrec_NewPointerPatch(¤t->expr, CPrec_GetExpressionPatch(initexpr->expr)); + + if (!initexpr->next) + break; + + next = CPrec_AppendAlign(); + CPrec_NewPointerPatch(¤t->next, next); + current = next; + initexpr = initexpr->next; + } + + return first; +} + +static CI_Action *CPrec_GetInlineActionPatch(CI_Action *act) { + CI_Action *current, *first, *next; + + first = current = CPrec_AppendAlign(); + while (1) { + if (act->actiontype == CI_ActionInlineFunc) + memclrw(&act->u.inlinefunc.fileoffset, sizeof(FileOffsetInfo)); + + CPrec_AppendData(act, sizeof(CI_Action)); + + CPrec_NewPointerPatch(¤t->obj, CPrec_GetObjectPatch(act->obj)); + + switch (act->actiontype) { + case CI_ActionInlineFunc: + if (act->u.inlinefunc.stream.firsttoken) + CPrec_NewPointerPatch( + ¤t->u.inlinefunc.stream.firsttoken, + CPrec_GetTStreamPatch(act->u.inlinefunc.stream.firsttoken, act->u.inlinefunc.stream.tokens)); + if (act->u.inlinefunc.tclass) + CPrec_NewPointerPatch(¤t->u.inlinefunc.tclass, CPrec_GetTypePatch(TYPE(act->u.inlinefunc.tclass))); + break; + + case CI_ActionMemberFunc: + CPrec_NewPointerPatch(¤t->u.memberfunc.templ, CPrec_GetTypePatch(TYPE(act->u.memberfunc.templ))); + CPrec_NewPointerPatch(¤t->u.memberfunc.inst, CPrec_GetTypePatch(TYPE(act->u.memberfunc.inst))); + CPrec_NewPointerPatch(¤t->u.memberfunc.tmemb, CPrec_GetTemplateMemberPatch(act->u.memberfunc.tmemb)); + break; + + case CI_ActionTemplateFunc: + CPrec_NewPointerPatch(¤t->u.templatefunc.func, CPrec_GetTemplateFunctionPatch(act->u.templatefunc.func)); + CPrec_NewPointerPatch(¤t->u.templatefunc.inst, CPrec_GetTemplFuncInstancePatch(act->u.templatefunc.inst)); + break; + + case CI_ActionDefaultFunc: + break; + + default: + CError_FATAL(4177); + } + + if (!act->next) + break; + + next = CPrec_AppendAlign(); + CPrec_NewPointerPatch(¤t->next, next); + current = next; + act = act->next; + } + + return first; +} + +static void CPrec_GenerateBuiltinPatches(void) { + int x; + int y; + Patch *scan; + + for (x = 0; x < cprec_builtins; x++) { + y = 0; + for (scan = cprec_builtin[x].patches; scan; scan = scan->next) + ++y; + + if (y) { + CPrec_AppendWord32(y); + CPrec_AppendWord32(x); + for (scan = cprec_builtin[x].patches; scan; scan = scan->next) + CPrec_AppendWord32(scan->offset); + } + } + + CPrec_AppendWord32(0); +} + +static void CPrec_GenerateTokenStreamPatches(void) { + TokenPatch *scan; + + for (scan = cprec_tokenpatches; scan; scan = scan->next) { + CPrec_AppendWord32((UInt32) scan->tokens); + CPrec_AppendWord32((UInt32) scan->count); + } + CPrec_AppendWord32(0); +} + +static OSErr CPrec_CompressWrite(const char *data, SInt32 size) { + char buf[2048 + 256]; + OSErr err; + int bufpos = 0; + int blockstart; + int c; + const char *p = data; + const char *end = data + size; + + for (;;) { + if (p < end) { + if (!*p) { + c = 224; + while (!*p && p < end && c < 256) { + c++; + p++; + } + buf[bufpos++] = c - 1; + } else { + blockstart = bufpos++; + c = 0; + while (p < end && c < 224) { + if (!p[0] && !p[1]) { + break; + } else { + buf[bufpos++] = *(p++); + c++; + } + } + buf[blockstart] = c - 1; + } + } + + if (p >= end || bufpos > 2048) { + if ((err = COS_FileWrite(cprec_refnum, buf, bufpos))) + return err; + + if (p >= end) + break; + else + bufpos = 0; + } + } + + return noErr; +} + +static OSErr CPrec_FlushRawBuffer(void) { + OSErr err; + + if (cprec_dowrite) { + CPrec_AppendAlign(); + cprec_zero_offset += cprec_glist.size; + COS_LockHandle(cprec_glist.data); + err = CPrec_CompressWrite(*cprec_glist.data, cprec_glist.size); + COS_UnlockHandle(cprec_glist.data); + cprec_glist.size = 0; + + return err; + } else { + return noErr; + } +} + +static OSErr CPrec_FlushBufferCheck(void) { + static SInt32 flushmax; + OSErr err; + + if (cprec_glist.size > flushmax) + flushmax = cprec_glist.size; + + if (cprec_glist.size > 10000) { + err = CPrec_FlushRawBuffer(); + if (err) { + cprec_ioerror = err; + return err; + } + } + + return noErr; +} + +static int CPrec_CompressPatches(void) { + Patch *scan; + int count; + SInt32 last; + + cprec_glist.size = 0; + + scan = cprec_patch_list; + last = 0; + count = 0; + while (scan) { + CError_ASSERT(4339, (scan->offset & 0x80000001) == 0); + + if ((scan->offset - last) >= -128 && (scan->offset - last) <= 126) + CPrec_AppendByte(((scan->offset - last) >> 1) | 0x80); + else + CPrec_AppendWord32(scan->offset); + + last = scan->offset; + scan = scan->next; + count++; + } + + return count; +} + +static OSErr CPrec_DumpColorSymbolTable(Boolean doWrite) { + OSErr err; + + freelheap(); + + CPrec_InitAddressHashTable(); + CPrec_InitPointerHashTable(); + + cprec_patch_list = NULL; + cprec_tokenpatches = NULL; + cprec_offset = 0; + cprec_zero_offset = 0; + cprec_dowrite = doWrite; + cprec_ioerror = noErr; + + CPrec_SetupBuiltIn(); + CPrec_AppendWord32(0); + + CPrec_DumpNameTable(); + if ((err = CPrec_FlushRawBuffer()) != noErr) + return err; + + CPrec_DumpMacroTable(); + if ((err = CPrec_FlushRawBuffer()) != noErr) + return err; + + CPrec_DumpRootNameSpace(); + if (doWrite) { + if (cprec_ioerror != noErr) + return cprec_ioerror; + if ((err = CPrec_FlushRawBuffer()) != noErr) + return err; + } + + if (ctempl_templates) { + TemplClass *p = TEMPL_CLASS(CPrec_GetTypePatch(TYPE(ctempl_templates))); + if (doWrite) + cprec_header->ctempl_templates = p; + if ((err = CPrec_FlushRawBuffer()) != noErr) + return err; + } + + if (ctempl_templatefuncs) { + TemplateFunction *p = CPrec_GetTemplateFunctionPatch(ctempl_templatefuncs); + if (doWrite) + cprec_header->ctempl_templatefuncs = p; + if ((err = CPrec_FlushRawBuffer()) != noErr) + return err; + } + + if (csom_stubs) { + CSOMStub *p = CPrec_GetSOMPatch(csom_stubs); + if (doWrite) + cprec_header->csom_stubs = p; + if ((err = CPrec_FlushRawBuffer()) != noErr) + return err; + } + + if (cprec_staticdata) { + StaticData *p = CPrec_GetStaticDataPatch(cprec_staticdata); + if (doWrite) + cprec_header->cprec_staticdata = p; + if ((err = CPrec_FlushRawBuffer()) != noErr) + return err; + } + + if (callbackactions) { + CallbackAction *p = CPrec_GetCallbackPatch(callbackactions); + if (doWrite) + cprec_header->callbackactions = p; + if ((err = CPrec_FlushRawBuffer()) != noErr) + return err; + } + + if (cobjc_type_class) { + Type *p = CPrec_GetTypePatch(cobjc_type_class); + if (doWrite) + cprec_header->cobjc_type_class = p; + if ((err = CPrec_FlushRawBuffer()) != noErr) + return err; + } + + if (cobjc_type_id) { + Type *p = CPrec_GetTypePatch(cobjc_type_id); + if (doWrite) + cprec_header->cobjc_type_id = p; + if ((err = CPrec_FlushRawBuffer()) != noErr) + return err; + } + + if (cobjc_type_sel) { + Type *p = CPrec_GetTypePatch(cobjc_type_sel); + if (doWrite) + cprec_header->cobjc_type_sel = p; + if ((err = CPrec_FlushRawBuffer()) != noErr) + return err; + } + + if (cobjc_selhashtable) { + ObjCSelector **p = CPrec_GetSelHashTablePatch(cobjc_selhashtable); + if (doWrite) + cprec_header->cobjc_selhashtable = p; + if ((err = CPrec_FlushRawBuffer()) != noErr) + return err; + } + + if (cobjc_classdefs) { + BClassList *p = CPrec_GetBClassListPatch(cobjc_classdefs); + if (doWrite) + cprec_header->cobjc_classdefs = p; + if ((err = CPrec_FlushRawBuffer()) != noErr) + return err; + } + + if (cobjc_protocols) { + ObjCProtocol *p = CPrec_GetObjCProtocolPatch(cobjc_protocols); + if (doWrite) + cprec_header->cobjc_protocols = p; + if ((err = CPrec_FlushRawBuffer()) != noErr) + return err; + } + + if (init_expressions) { + InitExpr *p = CPrec_GetIExpressionPatch(init_expressions); + if (doWrite) + cprec_header->init_expressions = p; + if ((err = CPrec_FlushRawBuffer()) != noErr) + return err; + } + + if (cinline_tactionlist) { + CI_Action *p = CPrec_GetInlineActionPatch(cinline_tactionlist); + if (doWrite) + cprec_header->cinline_tactionlist = p; + if ((err = CPrec_FlushRawBuffer()) != noErr) + return err; + } + + return noErr; +} + +static OSErr CPrec_FileAlign(short refnum, SInt32 *len) { + OSErr err; + SInt32 n; + char buf[8]; + + n = *len; + if ((n & 7) == 0) + return noErr; + + memclrw(buf, 8); + err = COS_FileWrite(refnum, buf, n = 8 - (n & 7)); + *len += n; + + return err; +} + +static OSErr CPrec_WriteFile(void) { + char str[128]; + int i; + HashNameNode *name; + OSErr err; + SInt32 offset; + + if (InitGList(&cprec_glist, 0x40000)) + CError_NoMem(); + + CompilerGetCString(10, str); + CWShowStatus(cparams.context, str, ""); + CPrep_RemoveSpecialMacros(); + + for (i = 0; i < 0x800; i++) { + for (name = name_hash_nodes[i]; name; name = name->next) + name->id = 0; + } + + if ((err = CPrec_DumpColorSymbolTable(0)) != noErr) + return err; + + CompilerGetCString(11, str); + CWShowStatus(cparams.context, str, ""); + + cprec_header = galloc(sizeof(Header)); + memclrw(cprec_header, sizeof(Header)); + + cprec_header->magic = 0xBEEFFACE; + cprec_header->version = 1047; + cprec_header->target = 2; + cprec_header->check_header_flags = copts.checkprecompflags; + cprec_header->cplusplus = copts.cplusplus; + cprec_header->uniqueID = CParser_GetUniqueID(); + cprec_header->cobjc_selrefcount = cobjc_selrefcount; + cprec_header->cobjc_classrefcount = cobjc_classrefcount; + cprec_header->cobjc_stringcount = cobjc_stringcount; + + if ((err = COS_FileWrite(cprec_refnum, cprec_header, sizeof(Header))) != noErr) + return err; + + offset = sizeof(Header); + + if ((err = CPrec_DumpColorSymbolTable(1)) != noErr) + return err; + + cprec_header->x28 = cprec_offset; + cprec_header->x30 = offset; + + if ((err = COS_FileGetPos(cprec_refnum, &offset)) != noErr) + return err; + + cprec_header->x2C = offset - cprec_header->x30; + + cprec_header->compressedPatchCount = CPrec_CompressPatches(); + cprec_header->compressedPatchSize = cprec_glist.size; + cprec_header->compressedPatchOffset = offset; + + if (cprec_header->compressedPatchCount) { + if ((err = COS_FileWrite(cprec_refnum, *cprec_glist.data, cprec_glist.size)) != noErr) + return err; + offset += cprec_glist.size; + } + + if ((err = CPrec_FileAlign(cprec_refnum, &offset)) != noErr) + return err; + + cprec_glist.size = 0; + CPrec_GenerateBuiltinPatches(); + cprec_header->builtinPatchSize = cprec_glist.size; + cprec_header->builtinPatchOffset = offset; + + if ((err = COS_FileWrite(cprec_refnum, *cprec_glist.data, cprec_glist.size)) != noErr) + return err; + offset += cprec_glist.size; + + if (cprec_tokenpatches) { + cprec_glist.size = 0; + CPrec_GenerateTokenStreamPatches(); + cprec_header->tokenStreamPatchSize = cprec_glist.size; + cprec_header->tokenStreamPatchOffset = offset; + + if ((err = COS_FileWrite(cprec_refnum, *cprec_glist.data, cprec_glist.size)) != noErr) + return err; + offset += cprec_glist.size; + } + + if ((err = COS_FileSetPos(cprec_refnum, 0)) != noErr) + return err; + + if ((err = COS_FileWrite(cprec_refnum, cprec_header, sizeof(Header))) != noErr) + return err; + + return noErr; +} + +void PrecompilerWrite(void) { + OSErr err; + short strindex; + char str[128]; + FSSpec spec; + + spec = cparamblkptr->sourcefile; + if (CWGetPrecompiledHeaderSpec(cparamblkptr->context, &spec, precomp_target_str) == cwNoErr) { + strindex = 3; + err = COS_FileNew(&spec, &cprec_refnum, copts.appltype, copts.headtype); + if (err == noErr) { + strindex = 4; + err = CPrec_WriteFile(); + } + CleanupPrecompiler(); + + if (err != noErr) { + CompilerGetCString(strindex, str); + sprintf(string, str, err); + CWReportMessage(cparamblkptr->context, NULL, string, NULL, messagetypeError, 0); + } else { + CWFileTime time = 0; + CWSetModDate(cparamblkptr->context, &spec, &time, 1); + } + } +} + +static void CPrec_ReadData(SInt32 offset, void *buffer, SInt32 size) { + if ( + COS_FileSetPos(cprec_refnum, offset) != noErr || + COS_FileRead(cprec_refnum, buffer, size) != noErr + ) + CError_ErrorTerm(CErrorStr181); +} + +static void CPrec_ReadRawBuffer(void) { + UInt8 *buffer; + UInt8 *work; + UInt8 *end; + UInt32 size; + int ch; + + if (!cprec_buffer) { + size = cprec_header->x28 + (cprec_header->x28 >> 7) + 64; + buffer = galloc(size); + cprec_rawbuffer = buffer; + + work = buffer + size - cprec_header->x2C; + CPrec_ReadData(cprec_header->x30, work, cprec_header->x2C); + } else { + buffer = galloc(cprec_header->x28); + cprec_rawbuffer = buffer; + work = (UInt8 *) cprec_buffer + cprec_header->x30; + } + + end = work + cprec_header->x2C; + + while (work < end) { + if ((ch = *(work++)) >= 0xE0) { + ch -= 0xE0; + do { + *(buffer++) = 0; + } while (--ch >= 0); + } else { + do { + *(buffer++) = *(work++); + } while (--ch >= 0); + } + } + + if (work != end || buffer != RESOLVE_RAW_BUFFER(cprec_header->x28)) + CError_ErrorTerm(CErrorStr181); +} + +static void CPrec_RelocateRawBuffer(void) { + UInt8 *patches; + UInt32 offset; + UInt8 *dest; + SInt32 count; + UInt8 *patch; + UInt32 var; + + if ((count = cprec_header->compressedPatchCount)) { + if (!cprec_buffer) { + patches = lalloc(cprec_header->compressedPatchSize); + CPrec_ReadData(cprec_header->compressedPatchOffset, patches, cprec_header->compressedPatchSize); + } else { + patches = RESOLVE_BUFFER(cprec_header->compressedPatchOffset); + } + + offset = 0; + patch = patches; + dest = cprec_rawbuffer; + do { + if (!(*patch & 0x80)) { + ((UInt8 *) &var)[0] = *(patch++); + ((UInt8 *) &var)[1] = *(patch++); + ((UInt8 *) &var)[2] = *(patch++); + ((UInt8 *) &var)[3] = *(patch++); + offset = var; + } else { + offset += (char) (*(patch++) * 2); + } + *((uintptr_t *) (dest + offset)) += (uintptr_t) dest; + } while (--count > 0); + + freelheap(); + + if (patch != (patches + cprec_header->compressedPatchSize)) + CError_ErrorTerm(CErrorStr181); + } +} + +static void CPrec_RelocateBuiltins(void) { + UInt32 *patches; + void *builtin; + UInt32 count; + UInt8 *buffer; + + if (cprec_header->builtinPatchSize) { + CPrec_SetupBuiltInArray(); + if (!cprec_buffer) { + patches = lalloc(cprec_header->builtinPatchSize); + CPrec_ReadData(cprec_header->builtinPatchOffset, patches, cprec_header->builtinPatchSize); + } else { + patches = RESOLVE_BUFFER(cprec_header->builtinPatchOffset); + } + + buffer = cprec_rawbuffer; + while (1) { + if (!(count = *(patches++))) + break; + + builtin = cprec_builtin_array[*(patches++)]; + do { + *((void **) (buffer + *(patches++))) = builtin; + } while (--count); + } + } +} + +static void CPrec_RelocateTokenStreams(void) { + UInt32 *patches; + UInt32 count; + TStreamElement *tokens; + UInt8 *buffer; + CPrepFileInfo *file; + SInt32 pos; + + if (cprec_header->tokenStreamPatchSize) { + CPrep_GetPrepPos(&file, &pos); + + if (!cprec_buffer) { + patches = lalloc(cprec_header->tokenStreamPatchSize); + CPrec_ReadData(cprec_header->tokenStreamPatchOffset, patches, cprec_header->tokenStreamPatchSize); + } else { + patches = RESOLVE_BUFFER(cprec_header->tokenStreamPatchOffset); + } + + buffer = cprec_rawbuffer; + while (1) { + if (!*patches) + break; + + tokens = (TStreamElement *) (buffer + *(patches++)); + count = *(patches++); + + while (count--) { + tokens->tokenfile = file; + tokens->tokenoffset = pos; + tokens++; + } + } + } +} + +static void CPrec_RelocateMacroTable(void) { + int i; + int j; + int count; + UInt8 *buffer; + Macro **prec_table; + Macro **table; + Macro *macro; + uintptr_t offset; + + buffer = cprec_rawbuffer; + prec_table = cprec_header->macrotable; + table = macrohashtable; + + i = 0; + do { + for (macro = *table; macro; macro = macro->next) { + macro->name = GetHashNameNodeExport(macro->name->name); + count = macro->xC & 0x7FFF; + for (j = 1; j < count; j++) + macro->names[j - 1] = GetHashNameNodeExport(macro->names[j - 1]->name); + } + + if ((offset = (uintptr_t) *prec_table)) { + if (*table) { + macro = (Macro *) (buffer + offset); + while (macro->next) + macro = macro->next; + macro->next = *table; + } + *table = (Macro *) (buffer + offset); + } + + prec_table++; + table++; + } while (++i < 0x800); +} + +static void CPrec_RelocateTable(void **table, int size, void **dest) { + int i; + void *buffer = cprec_rawbuffer; + + for (i = 0; i < size; i++) { + if (*table) + *dest = (char *) buffer + (uintptr_t) *table; + else + *dest = NULL; + table++; + dest++; + } +} + +static void CPrec_RelocateRootNameSpace(void) { + CError_ASSERT(4981, cscope_root->is_hash); + + cscope_root->names = cprec_header->root_names; + CPrec_RelocateTable( + (void **) cprec_header->root_nametable, + 0x400, + (void **) cscope_root->data.hash); +} + +static void CPrec_FixNameIds(void) { + int i; + HashNameNode *node; + + for (i = 0; i < 2048; i++) { + for (node = name_hash_nodes[i]; node; node = node->next) + node->id = -1; + } +} + +static void CPrec_DefineStaticData(void) { + StaticData *sd = cprec_staticdata; + cprec_staticdata = NULL; + + while (sd) { + CInit_DeclareData(sd->object, sd->buffer, sd->links, sd->size); + sd = sd->next; + } +} + +void PrecompilerRead(short refnum, void *buffer) { + cprec_refnum = refnum; + cprec_buffer = buffer; + + CPrep_RemoveSpecialMacros(); + + if (!CScope_IsEmptySymTable()) + CError_ErrorTerm(CErrorStr180); + + if (!cprec_buffer) { + cprec_header = galloc(sizeof(Header)); + CPrec_ReadData(0, cprec_header, sizeof(Header)); + } else { + cprec_header = cprec_buffer; + } + + if (cprec_header->magic != 0xBEEFFACE) + CError_ErrorTerm(CErrorStr181); + if (cprec_header->version != 1047) + CError_ErrorTerm(CErrorStr222); + if (cprec_header->target != 2) + CError_ErrorTerm(CErrorStr223); + + copts.checkprecompflags = cprec_header->check_header_flags; + + CPrec_ReadRawBuffer(); + CPrec_RelocateRawBuffer(); + CPrec_RelocateBuiltins(); + CPrec_RelocateTable((void **) cprec_header->nametable, 0x800, (void **) name_hash_nodes); + CPrec_FixNameIds(); + CPrec_RelocateMacroTable(); + CPrec_RelocateTokenStreams(); + CPrec_RelocateRootNameSpace(); + + if (!cprec_header->usings) + cscope_root->usings = NULL; + else + cscope_root->usings = RESOLVE_RAW_BUFFER(cprec_header->usings); + + ctempl_templates = RESOLVE_SAFE(cprec_header->ctempl_templates); + ctempl_templatefuncs = RESOLVE_SAFE(cprec_header->ctempl_templatefuncs); + csom_stubs = RESOLVE_SAFE(cprec_header->csom_stubs); + cprec_staticdata = RESOLVE_SAFE(cprec_header->cprec_staticdata); + callbackactions = RESOLVE_SAFE(cprec_header->callbackactions); + cobjc_type_class = RESOLVE_SAFE(cprec_header->cobjc_type_class); + cobjc_type_id = RESOLVE_SAFE(cprec_header->cobjc_type_id); + cobjc_type_sel = RESOLVE_SAFE(cprec_header->cobjc_type_sel); + cobjc_selhashtable = RESOLVE_SAFE(cprec_header->cobjc_selhashtable); + cobjc_classdefs = RESOLVE_SAFE(cprec_header->cobjc_classdefs); + cobjc_protocols = RESOLVE_SAFE(cprec_header->cobjc_protocols); + init_expressions = RESOLVE_SAFE(cprec_header->init_expressions); + cinline_tactionlist = RESOLVE_SAFE(cprec_header->cinline_tactionlist); + CParser_SetUniqueID(cprec_header->uniqueID); + cobjc_selrefcount = cprec_header->cobjc_selrefcount; + cobjc_classrefcount = cprec_header->cobjc_classrefcount; + cobjc_stringcount = cprec_header->cobjc_stringcount; + + cprec_refnum = 0; + + CleanupPrecompiler(); + cscope_current = cscope_root; + + if (!CParser_ReInitRuntimeObjects(1)) + CError_ErrorTerm(CErrorStr181); + + CPrep_InsertSpecialMacros(); + + if (cparamblkptr->precompile != 1) + CPrec_DefineStaticData(); +} diff --git a/compiler_and_linker/FrontEnd/C/CPrep.c b/compiler_and_linker/FrontEnd/C/CPrep.c index a2ac9e2..904e72a 100644 --- a/compiler_and_linker/FrontEnd/C/CPrep.c +++ b/compiler_and_linker/FrontEnd/C/CPrep.c @@ -14,7 +14,7 @@ #include "compiler/CodeGen.h" #include "compiler/CompilerTools.h" #include "compiler/FuncLevelAsmPPC.h" -#include "compiler/IroPointerAnalysis.h" +#include "../Optimizer/IroPointerAnalysis.h" #include "compiler/ObjGenMachO.h" #include "compiler/objects.h" #include "compiler/scopes.h" diff --git a/compiler_and_linker/FrontEnd/C/CPreprocess.c b/compiler_and_linker/FrontEnd/C/CPreprocess.c new file mode 100644 index 0000000..4e6b3c0 --- /dev/null +++ b/compiler_and_linker/FrontEnd/C/CPreprocess.c @@ -0,0 +1,676 @@ +#include "compiler/CPreprocess.h" +#include "compiler/CError.h" +#include "compiler/CMachine.h" +#include "compiler/CParser.h" +#include "compiler/CPrep.h" +#include "compiler/CPrepTokenizer.h" +#include "compiler/CompilerTools.h" +#include "cos.h" + +void CPrep_PreprocessDumpNewLine(void) { + if (copts.line_prepdump && pplist.data && filesp >= 0) + AppendGListData(&pplist, "\r", 1); +} + +void CPrep_PreprocessDumpFileInfo(Boolean flag) { + char linebuf[512]; + int size; + SInt16 tmp16; + SInt32 tmp32; + Str255 filename; + + if (pplist.data && filesp >= 0) { + if (nlflag && flag && pplist.size > 0) + AppendGListName(&pplist, "\r"); + + if (copts.line_prepdump) + size = sprintf(linebuf, "#line % " PRId32 "\t\"", linenumber); + else + size = sprintf(linebuf, "/* #line % " PRId32 "\t\"", linenumber); + AppendGListData(&pplist, linebuf, size); + + if (copts.fullpath_prepdump) { + if (prep_file->nameNode) { + AppendGListData(&pplist, prep_file->nameNode->name, strlen(prep_file->nameNode->name)); + } else { + COS_FileGetPathName(linebuf, &prep_file->textfile, &tmp32); + AppendGListData(&pplist, linebuf, strlen(linebuf)); + } + } else { + if (prep_file->nameNode) { + char *work = prep_file->nameNode->name + strlen(prep_file->nameNode->name); + while (work > prep_file->nameNode->name && !strchr("/\\:", work[-1])) + work--; + + AppendGListData(&pplist, work, strlen(work)); + } else { + COS_FileGetFSSpecInfo(&prep_file->textfile, &tmp16, &tmp32, filename); + AppendGListData(&pplist, &filename[1], filename[0]); + } + } + + size = sprintf(linebuf, "\"\t/* stack depth % " PRId32 " */", filesp); + AppendGListData(&pplist, linebuf, size); + + if (copts.line_prepdump && flag) + CPrep_PreprocessDumpNewLine(); + + nlflag = 1; + } +} + +static void CPrep_DumpWString(UInt16 *str, short len) { + int divisor; + int i; + + while (len--) { + if (*str < 32) { + AppendGListByte(&pplist, '\\'); + switch (*str) { + case 7: + AppendGListByte(&pplist, 'a'); + break; + case 8: + AppendGListByte(&pplist, 'b'); + break; + case 27: + AppendGListByte(&pplist, 'e'); + break; + case 12: + AppendGListByte(&pplist, 'f'); + break; + case 10: + AppendGListByte(&pplist, 'n'); + break; + case 13: + AppendGListByte(&pplist, 'r'); + break; + case 9: + AppendGListByte(&pplist, 't'); + break; + case 11: + AppendGListByte(&pplist, 'v'); + break; + default: + if (*str >= 8) + AppendGListByte(&pplist, '0' + (*str / 8)); + AppendGListByte(&pplist, '0' + (*str % 8)); + } + } else if (*str > 255) { + AppendGListByte(&pplist, '\\'); + AppendGListByte(&pplist, 'x'); + + divisor = 0x1000; + for (i = 0; i < 4; i++) { + AppendGListByte(&pplist, "0123456789ABCDEF"[(*str / divisor) % 16]); + divisor /= 16; + } + } else { + switch (*str) { + case '"': + case '\\': + AppendGListByte(&pplist, '\\'); + default: + AppendGListByte(&pplist, *str); + } + } + str++; + } +} + +static void CPrep_DumpString(UInt8 *str, short len) { + while (len--) { + if (*str < 32) { + AppendGListByte(&pplist, '\\'); + switch (*str) { + case 7: + AppendGListByte(&pplist, 'a'); + break; + case 8: + AppendGListByte(&pplist, 'b'); + break; + case 12: + AppendGListByte(&pplist, 'f'); + break; + case 10: + AppendGListByte(&pplist, 'n'); + break; + case 13: + AppendGListByte(&pplist, 'r'); + break; + case 9: + AppendGListByte(&pplist, 't'); + break; + case 11: + AppendGListByte(&pplist, 'v'); + break; + default: + if (*str >= 8) + AppendGListByte(&pplist, '0' + (*str / 8)); + AppendGListByte(&pplist, '0' + (*str % 8)); + } + } else { + switch (*str) { + case '"': + case '\\': + AppendGListByte(&pplist, '\\'); + default: + AppendGListByte(&pplist, *str); + } + } + str++; + } +} + +void CPrep_Preprocess(void) { + short innertoken; + short token; + char startToken; + char endToken; + int depth; + Boolean save_asmpoundcomment; // r16 + Boolean save_cplusplus; // r15 + char *p; + + startToken = 0; + depth = 0; + + if (InitGList(&pplist, 10000)) + CError_NoMem(); + + nlflag = 0; + spaceskip = 0; + + if ((token = lex())) { + do { + if (nlflag) { + if (!copts.line_prepdump) + AppendGListData(&pplist, "\r", 1); + } else { + if (spaceskip) + AppendGListByte(&pplist, ' '); + } + + while (1) { + switch ((innertoken = token)) { + case '(': + case ')': + case '{': + case '}': + AppendGListByte(&pplist, token); + if (cprep_nostring) { + if (innertoken == startToken) { + depth++; + } else if (innertoken == endToken) { + if (--depth == 0) { + cprep_nostring = 0; + in_assembler = 0; + copts.cplusplus = save_cplusplus; + copts.asmpoundcomment = save_asmpoundcomment; + } + } + } + break; + + case TK_INTCONST: + case TK_FLOATCONST: + if (tokenstacklevel > 0) + p = macropos; + else + p = prep_file_start + ts_current[-1].tokenoffset; + AppendGListData(&pplist, p, pos - p); + break; + + case TK_IDENTIFIER: + AppendGListData(&pplist, tkidentifier->name, strlen(tkidentifier->name)); + break; + + case TK_AUTO: + AppendGListData(&pplist, "auto", 4); + break; + case TK_REGISTER: + AppendGListData(&pplist, "register", 8); + break; + case TK_STATIC: + AppendGListData(&pplist, "static", 6); + break; + case TK_EXTERN: + AppendGListData(&pplist, "extern", 6); + break; + case TK_TYPEDEF: + AppendGListData(&pplist, "typedef", 7); + break; + case TK_INLINE: + AppendGListData(&pplist, "inline", 6); + break; + case TK_VOID: + AppendGListData(&pplist, "void", 4); + break; + case TK_CHAR: + AppendGListData(&pplist, "char", 4); + break; + case TK_SHORT: + AppendGListData(&pplist, "short", 5); + break; + case TK_INT: + AppendGListData(&pplist, "int", 3); + break; + case TK_LONG: + AppendGListData(&pplist, "long", 4); + break; + case TK_FLOAT: + AppendGListData(&pplist, "float", 5); + break; + case TK_DOUBLE: + AppendGListData(&pplist, "double", 6); + break; + case TK_SIGNED: + AppendGListData(&pplist, "signed", 6); + break; + case TK_UNSIGNED: + AppendGListData(&pplist, "unsigned", 8); + break; + case TK_STRUCT: + AppendGListData(&pplist, "struct", 6); + break; + case TK_UNION: + AppendGListData(&pplist, "union", 5); + break; + case TK_ENUM: + AppendGListData(&pplist, "enum", 4); + break; + case TK_CLASS: + AppendGListData(&pplist, "class", 5); + break; + case TK_CONST: + AppendGListData(&pplist, "const", 5); + break; + case TK_VOLATILE: + AppendGListData(&pplist, "volatile", 8); + break; + case TK_PASCAL: + AppendGListData(&pplist, "pascal", 6); + break; + case TK_UU_FAR: + AppendGListData(&pplist, "__far", 5); + break; + case TK_ONEWAY: + AppendGListData(&pplist, "oneway", 6); + break; + case TK_IN: + AppendGListData(&pplist, "in", 2); + break; + case TK_OUT: + AppendGListData(&pplist, "out", 3); + break; + case TK_INOUT: + AppendGListData(&pplist, "inout", 5); + break; + case TK_BYCOPY: + AppendGListData(&pplist, "bycopy", 6); + break; + case TK_BYREF: + AppendGListData(&pplist, "byref", 5); + break; + case TK_ASM: + AppendGListData(&pplist, "asm", 3); + endToken = 0; + startToken = 0; + AppendGListByte(&pplist, ' '); + token = lex(); + if (token == TK_VOLATILE || (token == TK_IDENTIFIER && !strcmp(tkidentifier->name, "__volatile__"))) { + AppendGListData(&pplist, "volatile", 8); + token = lex(); + } + if (token) { + if (token < ' ' || token > 255) + continue; + AppendGListByte(&pplist, token); + + if (token == '(') { + startToken = '('; + endToken = ')'; + } else if (token == '{') { + startToken = '{'; + endToken = '}'; + } else { + continue; + } + + cprep_nostring = 1; + in_assembler = 1; + depth = 1; + save_asmpoundcomment = copts.asmpoundcomment; + save_cplusplus = copts.cplusplus; + + token = lex(); + if (token == '"') { + AppendGListByte(&pplist, token); + copts.cplusplus = 0; + copts.asmpoundcomment = 1; + break; + } else if (token == 0) { + break; + } + continue; + } + break; + + case TK_CASE: + AppendGListData(&pplist, "case", 4); + break; + case TK_DEFAULT: + AppendGListData(&pplist, "default", 7); + break; + case TK_IF: + AppendGListData(&pplist, "if", 2); + break; + case TK_ELSE: + AppendGListData(&pplist, "else", 4); + break; + case TK_SWITCH: + AppendGListData(&pplist, "switch", 6); + break; + case TK_WHILE: + AppendGListData(&pplist, "while", 5); + break; + case TK_DO: + AppendGListData(&pplist, "do", 2); + break; + case TK_FOR: + AppendGListData(&pplist, "for", 3); + break; + case TK_GOTO: + AppendGListData(&pplist, "goto", 4); + break; + case TK_CONTINUE: + AppendGListData(&pplist, "continue", 8); + break; + case TK_BREAK: + AppendGListData(&pplist, "break", 5); + break; + case TK_RETURN: + AppendGListData(&pplist, "return", 6); + break; + case TK_SIZEOF: + AppendGListData(&pplist, "sizeof", 6); + break; + case TK_CATCH: + AppendGListData(&pplist, "catch", 5); + break; + case TK_DELETE: + AppendGListData(&pplist, "delete", 6); + break; + case TK_FRIEND: + AppendGListData(&pplist, "friend", 6); + break; + case TK_NEW: + AppendGListData(&pplist, "new", 3); + break; + case TK_OPERATOR: + AppendGListData(&pplist, "operator", 8); + break; + case TK_PRIVATE: + AppendGListData(&pplist, "private", 7); + break; + case TK_PROTECTED: + AppendGListData(&pplist, "protected", 9); + break; + case TK_PUBLIC: + AppendGListData(&pplist, "public", 6); + break; + case TK_TEMPLATE: + AppendGListData(&pplist, "template", 8); + break; + case TK_THIS: + AppendGListData(&pplist, "this", 4); + break; + case TK_THROW: + AppendGListData(&pplist, "throw", 5); + break; + case TK_TRY: + AppendGListData(&pplist, "try", 3); + break; + case TK_VIRTUAL: + AppendGListData(&pplist, "virtual", 7); + break; + case TK_INHERITED: + AppendGListData(&pplist, "inherited", 9); + break; + case TK_CONST_CAST: + AppendGListData(&pplist, "const_cast", 10); + break; + case TK_DYNAMIC_CAST: + AppendGListData(&pplist, "dynamic_cast", 12); + break; + case TK_EXPLICIT: + AppendGListData(&pplist, "explicit", 8); + break; + case TK_MUTABLE: + AppendGListData(&pplist, "mutable", 7); + break; + case TK_NAMESPACE: + AppendGListData(&pplist, "namespace", 9); + break; + case TK_REINTERPRET_CAST: + AppendGListData(&pplist, "reinterpret_cast", 16); + break; + case TK_STATIC_CAST: + AppendGListData(&pplist, "static_cast", 11); + break; + case TK_USING: + AppendGListData(&pplist, "using", 5); + break; + case TK_WCHAR_T: + AppendGListData(&pplist, "wchar_t", 7); + break; + case TK_TYPENAME: + AppendGListData(&pplist, "typename", 8); + break; + case TK_TRUE: + AppendGListData(&pplist, "true", 4); + break; + case TK_FALSE: + AppendGListData(&pplist, "false", 5); + break; + case TK_TYPEID: + AppendGListData(&pplist, "typeid", 6); + break; + case TK_EXPORT: + AppendGListData(&pplist, "export", 6); + break; + case TK_UU_STDCALL: + AppendGListData(&pplist, "__stdcall", 9); + break; + case TK_UU_CDECL: + AppendGListData(&pplist, "__cdecl", 7); + break; + case TK_UU_FASTCALL: + AppendGListData(&pplist, "__fastcall", 10); + break; + case TK_UU_DECLSPEC: + AppendGListData(&pplist, "__declspec", 10); + break; + case TK_MULT_ASSIGN: + AppendGListData(&pplist, "*=", 2); + break; + case TK_DIV_ASSIGN: + AppendGListData(&pplist, "/=", 2); + break; + case TK_MOD_ASSIGN: + AppendGListData(&pplist, "%=", 2); + break; + case TK_ADD_ASSIGN: + AppendGListData(&pplist, "+=", 2); + break; + case TK_SUB_ASSIGN: + AppendGListData(&pplist, "-=", 2); + break; + case TK_SHL_ASSIGN: + AppendGListData(&pplist, "<<=", 3); + break; + case TK_SHR_ASSIGN: + AppendGListData(&pplist, ">>=", 3); + break; + case TK_AND_ASSIGN: + AppendGListData(&pplist, "&=", 2); + break; + case TK_XOR_ASSIGN: + AppendGListData(&pplist, "^=", 2); + break; + case TK_OR_ASSIGN: + AppendGListData(&pplist, "|=", 2); + break; + case TK_LOGICAL_OR: + AppendGListData(&pplist, "||", 2); + break; + case TK_LOGICAL_AND: + AppendGListData(&pplist, "&&", 2); + break; + case TK_LOGICAL_EQ: + AppendGListData(&pplist, "==", 2); + break; + case TK_LOGICAL_NE: + AppendGListData(&pplist, "!=", 2); + break; + case TK_LESS_EQUAL: + AppendGListData(&pplist, "<=", 2); + break; + case TK_GREATER_EQUAL: + AppendGListData(&pplist, ">=", 2); + break; + case TK_SHL: + AppendGListData(&pplist, "<<", 2); + break; + case TK_SHR: + AppendGListData(&pplist, ">>", 2); + break; + case TK_INCREMENT: + AppendGListData(&pplist, "++", 2); + break; + case TK_DECREMENT: + AppendGListData(&pplist, "--", 2); + break; + case TK_ARROW: + AppendGListData(&pplist, "->", 2); + break; + case TK_ELLIPSIS: + AppendGListData(&pplist, "...", 3); + break; + case TK_DOT_STAR: + AppendGListData(&pplist, ".*", 2); + break; + case TK_ARROW_STAR: + AppendGListData(&pplist, "->*", 3); + break; + case TK_COLON_COLON: + AppendGListData(&pplist, "::", 2); + break; + case TK_AT_INTERFACE: + AppendGListData(&pplist, "@interface", 10); + break; + case TK_AT_IMPLEMENTATION: + AppendGListData(&pplist, "@implementation", 15); + break; + case TK_AT_PROTOCOL: + AppendGListData(&pplist, "@protocol", 9); + break; + case TK_AT_END: + AppendGListData(&pplist, "@end", 4); + break; + case TK_AT_PRIVATE: + AppendGListData(&pplist, "@private", 8); + break; + case TK_AT_PROTECTED: + AppendGListData(&pplist, "@protected", 10); + break; + case TK_AT_PUBLIC: + AppendGListData(&pplist, "@public", 7); + break; + case TK_AT_CLASS: + AppendGListData(&pplist, "@class", 6); + break; + case TK_AT_SELECTOR: + AppendGListData(&pplist, "@selector", 9); + break; + case TK_AT_ENCODE: + AppendGListData(&pplist, "@encode", 7); + break; + case TK_AT_DEFS: + AppendGListData(&pplist, "@defs", 5); + break; + case TK_SELF: + AppendGListData(&pplist, "self", 4); + break; + case TK_SUPER: + AppendGListData(&pplist, "super", 5); + break; + case TK_BOOL: + if (!copts.cplusplus && copts.c9x) + AppendGListData(&pplist, "_Bool", 5); + else + AppendGListData(&pplist, "bool", 4); + break; + case TK_RESTRICT: + if (copts.c9x) + AppendGListData(&pplist, "restrict", 8); + else + AppendGListData(&pplist, "__restrict", 10); + break; + case TK_UU_VECTOR: + AppendGListData(&pplist, "__vector", 8); + break; + case TK_UU_TYPEOF_UU: + AppendGListData(&pplist, "__typeof__", 10); + break; + case TK_UU_ATTRIBUTE_UU: + AppendGListData(&pplist, "__attribute__", 13); + break; + case TK_UU_ALIGNOF_UU: + AppendGListData(&pplist, "__alignof__", 11); + break; + case TK_UU_UUIDOF: + AppendGListData(&pplist, "__uuidof", 8); + break; + case TK_U_COMPLEX: + AppendGListData(&pplist, "_Complex", 8); + break; + case TK_U_IMAGINARY: + AppendGListData(&pplist, "_Imaginary", 10); + break; + + case TK_STRING: + if (ispascalstring) { + AppendGListData(&pplist, "\"\\p", 3); + CPrep_DumpString((UInt8 *) tkstring + 1, tksize - 1); + } else { + AppendGListByte(&pplist, '"'); + CPrep_DumpString((UInt8 *) tkstring, tksize - 1); + } + AppendGListByte(&pplist, '"'); + break; + + case TK_STRING_WIDE: + AppendGListData(&pplist, "L\"", 2); + CPrep_DumpWString((UInt16 *) tkstring, (tksize / stwchar.size) - 1); + AppendGListByte(&pplist, '"'); + break; + + default: + if (token >= 32 && token <= 255) + AppendGListByte(&pplist, token); + else + CError_FATAL(563); + } + break; + } + + CPrep_TokenStreamFlush(); + nlflag = 0; + spaceskip = 0; + } while ((token = lex())); + } + + AppendGListByte(&pplist, 0); + COS_ResizeHandle(pplist.data, pplist.size); +} diff --git a/compiler_and_linker/FrontEnd/C/CRTTI.c b/compiler_and_linker/FrontEnd/C/CRTTI.c new file mode 100644 index 0000000..3881153 --- /dev/null +++ b/compiler_and_linker/FrontEnd/C/CRTTI.c @@ -0,0 +1,940 @@ +#include "compiler/CRTTI.h" +#include "compiler/CClass.h" +#include "compiler/CDecl.h" +#include "compiler/CError.h" +#include "compiler/CExpr.h" +#include "compiler/CInit.h" +#include "compiler/CInt64.h" +#include "compiler/CMachine.h" +#include "compiler/CMangler.h" +#include "compiler/CParser.h" +#include "compiler/CScope.h" +#include "compiler/CompilerTools.h" +#include "compiler/objects.h" +#include "compiler/scopes.h" +#include "compiler/types.h" +#include "compiler/CPrepTokenizer.h" +#include "compiler/CPrep.h" + +typedef struct Offset { + struct Offset *next; + SInt32 offset; +} Offset; + +static Offset *crtti_offsets; +static OLinkList *crtti_olinks; + +// forward decls +static Object *CRTTI_ConstructTypeInfoObject(Type *type, UInt32 qual); + +typedef struct RTTISubClassList { + struct RTTISubClassList *next; + TypeClass *base; + SInt32 voffset; +} RTTISubClassList; + +typedef struct RTTIBaseList { + struct RTTIBaseList *next; + TypeClass *base; + RTTISubClassList *subclasses; + SInt32 voffset; + short numsubclasses; + Boolean x12; + Boolean x13; +} RTTIBaseList; + +static RTTIBaseList *CRTTI_CreateBaseList(TypeClass *tclass, TypeClass *tclassbase, RTTIBaseList *list, SInt32 voffset, Boolean flag) { + RTTIBaseList *scan; + ClassList *base; + Boolean flag27; + SInt32 newvoffset; + + if (tclass != tclassbase) { + flag27 = 0; + + for (scan = list; scan; scan = scan->next) { + if (scan->base == tclassbase) { + if (scan->voffset == voffset) { + if (!flag) + scan->x12 = 0; + flag27 = 0; + } else { + scan->x13 = 1; + flag27 = 1; + } + break; + } + } + + if (!scan || flag27) { + scan = lalloc(sizeof(RTTIBaseList)); + memclrw(scan, sizeof(RTTIBaseList)); + + scan->next = list; + list = scan; + scan->base = tclassbase; + scan->voffset = voffset; + scan->x12 = flag; + scan->x13 = flag27; + } + } + + for (base = tclassbase->bases; base; base = base->next) { + if (base->is_virtual) + newvoffset = CClass_VirtualBaseOffset(tclass, base->base); + else + newvoffset = voffset + base->offset; + + list = CRTTI_CreateBaseList(tclass, base->base, list, newvoffset, flag || base->access == ACCESSPRIVATE); + } + + return list; +} + +static void CRTTI_CreateSubClassList(TypeClass *tclass, RTTIBaseList *baselist, TypeClass *tclassbase, SInt32 voffset, Boolean flag) { + ClassList *base; + RTTISubClassList *scan; + SInt32 newvoffset; + + if (baselist->base != tclassbase) { + for (scan = baselist->subclasses; scan; scan = scan->next) { + if (scan->base == tclassbase && scan->voffset == voffset) + break; + } + + if (!scan) { + scan = lalloc(sizeof(RTTISubClassList)); + scan->next = baselist->subclasses; + baselist->subclasses = scan; + + scan->base = tclassbase; + scan->voffset = voffset; + baselist->numsubclasses++; + } + } + + for (base = tclassbase->bases; base; base = base->next) { + if (base->access == ACCESSPUBLIC) { + if (base->is_virtual) { + if (!flag) + continue; + newvoffset = CClass_VirtualBaseOffset(tclass, base->base); + } else { + newvoffset = voffset + base->offset; + } + + CRTTI_CreateSubClassList(tclass, baselist, base->base, newvoffset, flag); + } + } +} + +static Object *CRTTI_CreateBaseListObject(TypeClass *tclass) { + RTTIBaseList *baselist; + OLinkList *refs; + Object *object; + SInt32 *buf; + SInt32 size; + short count1; + short count2; + short total; + OLinkList *ref; + RTTIBaseList *scan; + RTTISubClassList *subclass; + SInt32 *work; + SInt32 *work2; + + baselist = CRTTI_CreateBaseList(tclass, tclass, NULL, 0, 0); + if (!baselist) + return NULL; + + count1 = 0; + count2 = 0; + total = 0; + + for (scan = baselist; scan; scan = scan->next) { + if (scan->x13 || scan->x12) { + CRTTI_CreateSubClassList(tclass, scan, scan->base, scan->voffset, scan->x13 == 0); + if (scan->numsubclasses) { + total += scan->numsubclasses; + count2++; + } + } else { + count1++; + } + } + + if (!count1 && !count2) + return NULL; + + size = (count1 + total) * 8 + count2 * 12 + 4; + buf = lalloc(size); + memclrw(buf, size); + + object = CParser_NewCompilerDefDataObject(); + object->name = CParser_GetUniqueName(); + object->type = CDecl_NewStructType(size, 4); + object->qual = Q_CONST; + object->sclass = TK_STATIC; + refs = NULL; + + work = buf; + + if (count1) { + for (scan = baselist; scan; scan = scan->next) { + if (!scan->x12 && !scan->x13) { + ref = lalloc(sizeof(OLinkList)); + ref->next = refs; + refs = ref; + + ref->obj = CRTTI_ConstructTypeInfoObject(TYPE(scan->base), 0); + ref->offset = ((char *) work) - ((char *) buf); + ref->somevalue = 0; + + work[1] = CTool_EndianConvertWord32(scan->voffset); + work += 2; + } + } + } + + if (count2) { + for (scan = baselist; scan; scan = scan->next) { + if (scan->numsubclasses) { + ref = lalloc(sizeof(OLinkList)); + ref->next = refs; + refs = ref; + + ref->obj = CRTTI_ConstructTypeInfoObject(TYPE(scan->base), 0); + ref->offset = ((char *) work) - ((char *) buf); + ref->somevalue = 0; + + work[1] = CTool_EndianConvertWord32(scan->voffset | 0x80000000); + work[2] = CTool_EndianConvertWord32(scan->numsubclasses); + work2 = work + 3; + + for (subclass = scan->subclasses; subclass; subclass = subclass->next) { + ref = lalloc(sizeof(OLinkList)); + ref->next = refs; + refs = ref; + + ref->obj = CRTTI_ConstructTypeInfoObject(TYPE(subclass->base), 0); + ref->offset = ((char *) work2) - ((char *) buf); + ref->somevalue = 0; + + work2[1] = CTool_EndianConvertWord32(subclass->voffset); + work2 += 2; + } + + work = work2; + } + } + } + + CInit_DeclareData(object, buf, refs, object->type->size); + return object; +} + +static Object *CRTTI_ConstructTypeInfoObject(Type *type, UInt32 qual) { + Object *baselistobj; + Object *nameobj; + HashNameNode *rttiname; + OLinkList *refs; + char *namestr; + int namelen; + Object *object; + NameSpaceObjectList *list; + TypePointer tptr_copy; + TypeMemberPointer tmemptr_copy; + UInt32 data[2]; + + switch (type->type) { + case TYPEPOINTER: + if (TPTR_QUAL(type) & (Q_CONST | Q_VOLATILE)) { + tptr_copy = *TYPE_POINTER(type); + tptr_copy.qual &= ~(Q_CONST | Q_VOLATILE); + type = TYPE(&tptr_copy); + } + break; + case TYPEMEMBERPOINTER: + if (TYPE_MEMBER_POINTER(type)->qual & (Q_CONST | Q_VOLATILE)) { + tmemptr_copy = *TYPE_MEMBER_POINTER(type); + tmemptr_copy.qual &= ~(Q_CONST | Q_VOLATILE); + type = TYPE(&tmemptr_copy); + } + break; + default: + qual = 0; + } + + if (IS_TYPE_CLASS(type) && type->size == 0) { + CDecl_CompleteType(type); + if (!(TYPE_CLASS(type)->flags & CLASS_COMPLETED)) + CError_Error(CErrorStr136, type, 0); + } + + rttiname = CMangler_RTTIObjectName(type, qual); + list = CScope_FindName(cscope_root, rttiname); + + if (!list || (object = OBJECT(list->object))->otype != OT_OBJECT || object->datatype != DDATA) { + namestr = CError_GetTypeName(type, qual, 0); + namelen = strlen(namestr) + 1; + nameobj = CInit_DeclareString(namestr, namelen, 0, 0); + + baselistobj = NULL; + if (IS_TYPE_CLASS(type)) + baselistobj = CRTTI_CreateBaseListObject(TYPE_CLASS(type)); + + memclrw(data, sizeof(data)); + + object = CParser_NewCompilerDefDataObject(); + object->name = rttiname; + object->type = CDecl_NewStructType(sizeof(data), 4); + object->qual = Q_CONST; + object->sclass = TK_STATIC; + + refs = lalloc(sizeof(OLinkList)); + refs->next = NULL; + refs->obj = nameobj; + refs->offset = 0; + refs->somevalue = 0; + + if (baselistobj) { + refs->next = lalloc(sizeof(OLinkList)); + refs->next->next = NULL; + refs->next->obj = baselistobj; + refs->next->offset = 4; + refs->next->somevalue = 0; + } + + CScope_AddGlobalObject(object); + CInit_DeclareData(object, data, refs, object->type->size); + } + + return object; +} + +static void CRTTI_ConstructVTableHeader(TypeClass *tclass1, TypeClass *tclass2, Object *typeinfoObj, char *data, SInt32 offset, SInt32 voffset) { + ClassList *base; + Offset *o; + OLinkList *olink; + SInt32 tmp; + SInt32 newoffset; + SInt32 newvoffset; + + if (tclass2->vtable->owner == tclass2) { + for (o = crtti_offsets; o; o = o->next) { + if (o->offset == voffset) + break; + } + + if (!o) { + o = lalloc(sizeof(Offset)); + o->next = crtti_offsets; + o->offset = voffset; + crtti_offsets = o; + + olink = lalloc(sizeof(OLinkList)); + olink->next = crtti_olinks; + olink->obj = typeinfoObj; + olink->offset = voffset; + olink->somevalue = 0; + crtti_olinks = olink; + + *((SInt32 *) (data + voffset + 4)) = CTool_EndianConvertWord32(-offset); + } else { + tmp = *((SInt32 *) (data + voffset + 4)); + CError_ASSERT(404, tmp == CTool_EndianConvertWord32(-offset)); + } + } + + for (base = tclass2->bases; base; base = base->next) { + if (base->base->vtable) { + if (base->is_virtual) { + newoffset = CClass_VirtualBaseOffset(tclass1, base->base); + newvoffset = CClass_VirtualBaseVTableOffset(tclass1, base->base); + } else { + newoffset = offset + base->offset; + newvoffset = voffset + base->voffset; + } + + CRTTI_ConstructVTableHeader(tclass1, base->base, typeinfoObj, data, newoffset, newvoffset); + } + } +} + +OLinkList *CRTTI_ConstructVTableHeaders(TypeClass *tclass, void *data, OLinkList *links) { + crtti_offsets = NULL; + crtti_olinks = links; + + CRTTI_ConstructVTableHeader( + tclass, tclass, + CRTTI_ConstructTypeInfoObject(TYPE(tclass), 0), + data, 0, 0); + + return crtti_olinks; +} + +static Type *CRTTI_FindTypeInfoType(void) { + NameSpace *nspace; + NameSpaceObjectList *list; + Type *type; + + if ((list = CScope_FindName(cscope_root, GetHashNameNodeExport("std"))) && list->object->otype == OT_NAMESPACE) + nspace = OBJ_NAMESPACE(list->object)->nspace; + else + nspace = cscope_root; + + type = CScope_GetLocalTagType(nspace, GetHashNameNodeExport("type_info")); + if (type && IS_TYPE_CLASS(type) && type->size) + return type; + + CError_Error(CErrorStr140, "::std::type_info"); + return TYPE(&stchar); +} + +ENode *CRTTI_ParseTypeID(void) { + ENode *expr; + Type *type; + Type *typeinfoType; + UInt32 qual; + + if (!copts.RTTI) + CError_Warning(CErrorStr257); + + typeinfoType = CRTTI_FindTypeInfoType(); + + if (lex() != '(') { + CError_Error(CErrorStr114); + return nullnode(); + } + + tk = lex(); + if ((type = CParser_ParseTypeID(&qual, NULL))) { + if (tk != ')') + CError_ErrorSkip(CErrorStr115); + else + tk = lex(); + + if (IS_TYPE_REFERENCE(type)) + type = TPTR_TARGET(type); + } else { + expr = s_expression(); + + if (tk != ')') + CError_ErrorSkip(CErrorStr115); + else + tk = lex(); + + type = expr->rtype; + qual = ENODE_QUALS(expr); + + if (IS_TYPE_REFERENCE(type)) + type = TPTR_TARGET(type); + + if (IS_TYPE_CLASS(type) && TYPE_CLASS(type)->vtable) { + expr = funccallexpr( + Rgtid_func, + getnodeaddress(expr, 0), + intconstnode(TYPE(&stsignedlong), TYPE_CLASS(type)->vtable->offset), + NULL, + NULL); + expr->rtype = CDecl_NewPointerType(typeinfoType); + + expr = makemonadicnode(expr, EINDIRECT); + expr->rtype = typeinfoType; + expr->flags = ENODE_FLAG_CONST; + return expr; + } + } + + expr = create_objectrefnode(CRTTI_ConstructTypeInfoObject(type, qual)); + expr = makemonadicnode(expr, EINDIRECT); + expr->rtype = typeinfoType; + expr->flags = ENODE_FLAG_CONST; + return expr; +} + +static void CRTTI_ConstCastQualCheck(UInt32 qual1, UInt32 qual2) { + if ( + ((qual1 & Q_CONST) && !(qual2 & Q_CONST)) || + ((qual1 & Q_VOLATILE) && !(qual2 & Q_VOLATILE)) + ) + CError_Error(CErrorStr258); +} + +static void CRTTI_ConstCastCheck(Type *type1, UInt32 qual1, Type *type2, UInt32 qual2) { + Boolean flag = 1; + if (IS_TYPE_REFERENCE(type2)) { + type2 = TPTR_TARGET(type2); + flag = 0; + } + + while (1) { + if (type1->type != type2->type) + break; + + switch (type1->type) { + case TYPEPOINTER: + if (!flag) + CRTTI_ConstCastQualCheck(TPTR_QUAL(type1), TPTR_QUAL(type2)); + type1 = TPTR_TARGET(type1); + type2 = TPTR_TARGET(type2); + flag = 0; + continue; + + case TYPEMEMBERPOINTER: + if (!flag) + CRTTI_ConstCastQualCheck(TYPE_MEMBER_POINTER(type1)->qual, TYPE_MEMBER_POINTER(type2)->qual); + type1 = TYPE_MEMBER_POINTER(type1)->ty1; + type2 = TYPE_MEMBER_POINTER(type2)->ty1; + flag = 0; + continue; + } + + break; + } + + if (!flag && !IS_TYPE_FUNC(type1) && !IS_TYPE_FUNC(type2)) + CRTTI_ConstCastQualCheck(CParser_GetCVTypeQualifiers(type1, qual1), CParser_GetCVTypeQualifiers(type2, qual2)); +} + +static ENode *CRTTI_ParseCast(DeclInfo *di) { + ENode *expr; + + if (lex() != '<') { + CError_Error(CErrorStr230); + return NULL; + } + + tk = lex(); + + memclrw(di, sizeof(DeclInfo)); + CParser_GetDeclSpecs(di, 0); + scandeclarator(di); + + if (di->name) + CError_Error(CErrorStr164); + + if (tk != '>') { + CError_Error(CErrorStr231); + return NULL; + } + + if (lex() != '(') { + CError_Error(CErrorStr114); + return NULL; + } + + tk = lex(); + expr = s_expression(); + if (!IS_TYPE_REFERENCE(di->thetype)) + expr = pointer_generation(expr); + + if (tk != ')') { + CError_Error(CErrorStr115); + return NULL; + } + + tk = lex(); + return expr; +} + +static void CRTTI_IncompleteCheck(Type *type) { + if (IS_TYPE_POINTER_ONLY(type)) + type = TPTR_TARGET(type); + + if (IS_TYPE_CLASS(type) && type->size == 0) { + CDecl_CompleteType(type); + if (!(TYPE_CLASS(type)->flags & CLASS_COMPLETED)) + CError_Error(CErrorStr136, type, 0); + } +} + +static Boolean CRTTI_IsSameType(Type *a, Type *b) { + while (1) { + if (a->type != b->type) + return 0; + + switch (a->type) { + case TYPEVOID: + return 1; + case TYPEINT: + case TYPEFLOAT: + case TYPEENUM: + case TYPESTRUCT: + return a == b; + case TYPEPOINTER: + a = TPTR_TARGET(a); + b = TPTR_TARGET(b); + continue; + default: + return is_typesame(a, b); + } + } +} + +static ENode *CRTTI_UniversalCast(ENode *expr, Type *type, UInt32 qual, UInt8 mode) { + // type/qual are the target type + Boolean isSimpleCast; + Boolean needsTypcon; + Boolean failed; + + if (ENODE_IS(expr, EOBJLIST)) + return CExpr_AssignmentPromotion(expr, type, qual & (Q_CONST | Q_VOLATILE), 1); + + isSimpleCast = needsTypcon = failed = 0; + + switch (type->type) { + case TYPEINT: + case TYPEENUM: + if (mode == 2 && IS_TYPE_POINTER_ONLY(expr->rtype) && type != TYPE(&stbool)) + failed = 1; + break; + + case TYPEPOINTER: + if (TPTR_QUAL(type) & Q_REFERENCE) { + if ( + !CRTTI_IsSameType(TPTR_TARGET(type), expr->rtype) && + mode == 2 && + !( + IS_TYPE_CLASS(TPTR_TARGET(type)) && + IS_TYPE_CLASS(expr->rtype) && + ( + CClass_IsBaseClass(TYPE_CLASS(TPTR_TARGET(type)), TYPE_CLASS(expr->rtype), NULL, 0, 1) || + CClass_IsBaseClass(TYPE_CLASS(expr->rtype), TYPE_CLASS(TPTR_TARGET(type)), NULL, 0, 1) + ) + ) + ) + { + failed = 1; + } + } else if (IS_TYPE_POINTER_ONLY(expr->rtype)) { + if ( + mode == 3 || + CRTTI_IsSameType(type, expr->rtype) || + IS_TYPE_VOID(TPTR_TARGET(type)) || + IS_TYPE_VOID(TPTR_TARGET(expr->rtype)) + ) + { + isSimpleCast = needsTypcon = 1; + } + else if ( + mode == 2 && + !( + IS_TYPE_CLASS(TPTR_TARGET(type)) && + IS_TYPE_CLASS(TPTR_TARGET(expr->rtype)) && + ( + CClass_IsBaseClass(TYPE_CLASS(TPTR_TARGET(type)), TYPE_CLASS(TPTR_TARGET(expr->rtype)), NULL, 0, 1) || + CClass_IsBaseClass(TYPE_CLASS(TPTR_TARGET(expr->rtype)), TYPE_CLASS(TPTR_TARGET(type)), NULL, 0, 1) + ) + ) + ) + { + failed = 1; + } + } else { + if (IS_TYPE_ENUM(expr->rtype)) + expr->rtype = TYPE_ENUM(expr->rtype)->enumtype; + + if (IS_TYPE_INT(expr->rtype)) { + if (ENODE_IS(expr, EINTCONST) && CInt64_IsZero(&expr->data.intval)) { + isSimpleCast = 1; + break; + } + + if (mode != 2) + break; + } + + if (IS_TYPE_CLASS(expr->rtype)) { + if (mode == 2) + break; + } + + failed = 1; + } + break; + } + + if (failed) { + CError_Error(CErrorStr247, expr->rtype, ENODE_QUALS(expr), type, qual); + return expr; + } + + if (isSimpleCast) { + if (needsTypcon && ENODE_IS(expr, EINDIRECT) && (copts.pointercast_lvalue || !copts.ANSIstrict)) + expr = makemonadicnode(expr, ETYPCON); + + expr->rtype = type; + expr->flags = qual & ENODE_FLAG_QUALS; + return expr; + } + + if (copts.old_argmatch) + return do_typecast(expr, type, qual); + + return CExpr_Convert(expr, type, qual, 1, 1); +} + +ENode *CRTTI_Parse_dynamic_cast(void) { + Boolean isRef; + ENode *expr; + TypeClass *srcclass; + TypeClass *destclass; + ENode *typeinfo; + DeclInfo di; + + expr = CRTTI_ParseCast(&di); + if (!expr) + return nullnode(); + + if (!copts.RTTI) + CError_Warning(CErrorStr257); + + CRTTI_ConstCastCheck(expr->rtype, expr->flags, di.thetype, di.qual); + if (!IS_TYPE_POINTER_ONLY(di.thetype)) { + CError_Error(CErrorStr164); + return expr; + } + + isRef = (TPTR_QUAL(di.thetype) & Q_REFERENCE) != 0; + + if (IS_TYPE_CLASS(TPTR_TARGET(di.thetype))) { + destclass = TYPE_CLASS(TPTR_TARGET(di.thetype)); + CDecl_CompleteType(TYPE(destclass)); + if (!(destclass->flags & CLASS_COMPLETED)) { + CError_Error(CErrorStr136, destclass, 0); + return expr; + } + } else if (!IS_TYPE_VOID(TPTR_TARGET(di.thetype))) { + CError_Error(CErrorStr164); + return expr; + } else { + destclass = NULL; + } + + if (isRef) { + if (!IS_TYPE_CLASS(expr->rtype)) { + CError_Error(CErrorStr164); + return expr; + } + + srcclass = TYPE_CLASS(expr->rtype); + if (destclass) { + if (srcclass == destclass || CClass_IsBaseClass(srcclass, destclass, NULL, 0, 1)) + return do_typecast(expr, di.thetype, di.qual); + } + + expr = getnodeaddress(expr, 1); + } else { + if (!IS_TYPE_POINTER_ONLY(expr->rtype) || !IS_TYPE_CLASS(TPTR_TARGET(expr->rtype))) { + CError_Error(CErrorStr164); + return expr; + } + + srcclass = TYPE_CLASS(TPTR_TARGET(expr->rtype)); + if (destclass) { + if (srcclass == destclass || CClass_IsBaseClass(srcclass, destclass, NULL, 0, 1)) + return do_typecast(expr, di.thetype, di.qual); + } + } + + if (!(srcclass->flags & CLASS_COMPLETED)) { + CError_Error(CErrorStr136, srcclass, 0); + return expr; + } + + if (!srcclass->vtable) { + CError_Error(CErrorStr164); + return expr; + } + + if (srcclass->sominfo) { + CError_Error(CErrorStr164); + return expr; + } + + if (destclass) { + typeinfo = create_objectrefnode(CRTTI_ConstructTypeInfoObject(TYPE(destclass), 0)); + if (destclass->sominfo) { + CError_Error(CErrorStr164); + return expr; + } + } else { + typeinfo = nullnode(); + } + + expr = CExpr_FuncCallSix( + Rdync_func, + expr, + intconstnode(TYPE(&stsignedlong), srcclass->vtable->offset), + typeinfo, + create_objectrefnode(CRTTI_ConstructTypeInfoObject(TYPE(srcclass), 0)), + intconstnode(TYPE(&stsignedshort), isRef), + NULL + ); + + if (isRef) { + expr->rtype = CDecl_NewPointerType(TYPE(destclass)); + expr = makemonadicnode(expr, EINDIRECT); + expr->rtype = TYPE(destclass); + } else { + expr->rtype = di.thetype; + } + expr->flags = di.qual & ENODE_FLAG_QUALS; + return expr; +} + +ENode *CRTTI_Parse_static_cast(void) { + ENode *expr; + DeclInfo di; + + expr = CRTTI_ParseCast(&di); + if (!expr) + return nullnode(); + + CRTTI_ConstCastCheck(expr->rtype, expr->flags, di.thetype, di.qual); + + if (IS_TYPE_REFERENCE(di.thetype)) { + if (IS_TYPE_CLASS(expr->rtype) && CExpr_CanImplicitlyConvert(expr, di.thetype, di.qual)) { + expr = CExpr_Convert(expr, di.thetype, di.qual, 0, 1); + CError_ASSERT(959, IS_TYPE_POINTER_ONLY(expr->rtype)); + + expr = makemonadicnode(expr, EINDIRECT); + expr->rtype = TPTR_TARGET(di.thetype); + expr->flags = di.qual & ENODE_FLAG_QUALS; + return expr; + } + } else { + if (CExpr_CanImplicitlyConvert(expr, di.thetype, di.qual)) + return CExpr_Convert(expr, di.thetype, di.qual, 1, 1); + } + + if (!IS_TYPE_VOID(di.thetype) && !(IS_TYPE_POINTER_ONLY(expr->rtype) && IS_TYPE_VOID(TPTR_TARGET(expr->rtype)))) { + CRTTI_IncompleteCheck(di.thetype); + CRTTI_IncompleteCheck(expr->rtype); + } + + return CRTTI_UniversalCast(expr, di.thetype, di.qual, 2); +} + +ENode *CRTTI_Parse_reinterpret_cast(void) { + ENode *expr; + Type *origtype; + ENode *lvalue; + DeclInfo di; + + expr = CRTTI_ParseCast(&di); + if (!expr) + return nullnode(); + + CRTTI_ConstCastCheck(expr->rtype, expr->flags, di.thetype, di.qual); + + if (IS_TYPE_REFERENCE(di.thetype)) { + lvalue = CExpr_LValue(expr, 0, 1); + if (!ENODE_IS(lvalue, EINDIRECT)) + return lvalue; + + lvalue->data.monadic->rtype = CDecl_NewPointerType(lvalue->rtype); + expr = lvalue->data.monadic; + origtype = di.thetype; + di.thetype = CDecl_NewPointerType(TPTR_TARGET(di.thetype)); + } else { + origtype = NULL; + } + + switch (di.thetype->type) { + case TYPEINT: + switch (expr->rtype->type) { + case TYPEMEMBERPOINTER: + case TYPEPOINTER: + expr = do_typecast(expr, di.thetype, di.qual); + break; + default: + CError_Error(CErrorStr164); + } + break; + case TYPEPOINTER: + switch (expr->rtype->type) { + case TYPEINT: + case TYPEENUM: + if (origtype) + di.thetype = origtype; + expr = do_typecast(expr, di.thetype, di.qual); + break; + case TYPEPOINTER: + expr = makemonadicnode(expr, ETYPCON); + expr->rtype = di.thetype; + expr->flags = di.qual & ENODE_FLAG_QUALS; + break; + default: + CError_Error(CErrorStr164); + } + break; + case TYPEMEMBERPOINTER: + if (IS_TYPE_MEMBERPOINTER(expr->rtype)) { + if (IS_TYPE_FUNC(TYPE_MEMBER_POINTER(di.thetype)->ty1)) { + if (IS_TYPE_FUNC(TYPE_MEMBER_POINTER(expr->rtype)->ty1)) { + expr->rtype = di.thetype; + expr->flags = di.qual & ENODE_FLAG_QUALS; + break; + } + } else { + if (!IS_TYPE_FUNC(TYPE_MEMBER_POINTER(expr->rtype)->ty1)) { + expr->rtype = di.thetype; + expr->flags = di.qual & ENODE_FLAG_QUALS; + break; + } + } + } + expr = do_typecast(expr, di.thetype, di.qual); + break; + default: + CError_Error(CErrorStr164); + } + + if (origtype && IS_TYPE_POINTER_ONLY(expr->rtype)) { + expr = makemonadicnode(expr, EINDIRECT); + expr->rtype = TPTR_TARGET(di.thetype); + } + + return expr; +} + +ENode *CRTTI_Parse_const_cast(void) { + DeclInfo di; + ENode *expr; + + if (!(expr = CRTTI_ParseCast(&di))) + return nullnode(); + + if (IS_TYPE_POINTER_ONLY(di.thetype)) { + if (TPTR_QUAL(di.thetype) & Q_REFERENCE) { + if (!iscpp_typeequal(TPTR_TARGET(di.thetype), expr->rtype)) + CError_Error(CErrorStr164); + + if (ENODE_IS(expr, EINDIRECT)) { + expr->rtype = TPTR_TARGET(di.thetype); + expr->flags = di.qual & ENODE_FLAG_QUALS; + } else { + CError_Error(CErrorStr142); + } + } else { + if (!iscpp_typeequal(di.thetype, expr->rtype)) + CError_Error(CErrorStr164); + + expr = do_typecast(expr, di.thetype, di.qual); + } + } else if (IS_TYPE_MEMBERPOINTER(di.thetype)) { + if (!iscpp_typeequal(di.thetype, expr->rtype)) + CError_Error(CErrorStr164); + + expr = do_typecast(expr, di.thetype, di.qual); + } else { + if (!is_typesame(di.thetype, expr->rtype)) + CError_Error(CErrorStr164); + else + expr = do_typecast(expr, di.thetype, di.qual); + } + + return expr; +} diff --git a/compiler_and_linker/FrontEnd/C/CSOM.c b/compiler_and_linker/FrontEnd/C/CSOM.c new file mode 100644 index 0000000..7e80e32 --- /dev/null +++ b/compiler_and_linker/FrontEnd/C/CSOM.c @@ -0,0 +1,2068 @@ +#include "compiler/CSOM.h" +#include "compiler/CClass.h" +#include "compiler/CDecl.h" +#include "compiler/CError.h" +#include "compiler/CException.h" +#include "compiler/CExpr.h" +#include "compiler/CFunc.h" +#include "compiler/CInit.h" +#include "compiler/CInt64.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/CodeGen.h" +#include "compiler/CompilerTools.h" +#include "compiler/objects.h" +#include "compiler/scopes.h" +#include "compiler/types.h" +#include "cos.h" + +// all pointers have been converted to UInt32 for the sake of maintaining 32-bit compat + +typedef struct { + SInt32 zero; + /* struct somStaticClassInfo * */ UInt32 sci; + /* void * */ UInt32 instanceDataToken; + SInt32 reserved[3]; + /* void * */ UInt32 tokens[1]; +} somClassDataStructure; + +enum { + mtVirtualMethod = 0, + mtProcedure = 1, + mtNonStatic = 2, + mtEmpty = 3, + mtDToken = 4 +}; + +enum { + pdUByte = 0, + pdSByte = 1, + pdUHalf = 2, + pdSHalf = 3, + pdULong = 4, + pdSLong = 5, + pdVLong = 6, + pdVoid = 7, + pdSFlt = 8, + pdDFlt = 9, + pdLFlt = 10, + pdVSAgg = 11, + pdNPtr = 12, + pdLPtr = 13, + pdSAgg = 14, + pdLAgg = 15 +}; + +enum { + fgShortOrChars = 1, + fgShortFloats = 2, + fgAnyFloats = 4, + fgAnyNon4Bytes = 8 +}; + +enum { + cfSharedStrings = 1, + cfTempClass = 2, + cfProxyClass = 4, + cfClassAllocate = 0x100, + cfClassDeallocate = 0x200, + cfClassInit = 0x400, + cfClassUninit = 0x800 +}; + +typedef struct { + UInt32 majorVersion; + UInt32 minorVersion; + UInt32 flags; + UInt16 dataAlignment; + UInt16 classTokenCount; + UInt16 numDirectParents; + UInt16 numMetaClasses; + UInt16 numOverriddenAncestors; + UInt16 numMigratedMethods; + UInt16 numSelectInherited; + UInt16 numUnused; + UInt16 dummy2a[4]; +} somStaticClassCounts; + +typedef UInt8 somSlotUsage; +typedef UInt8 somSignatureInfo; +typedef UInt16 somOverrideData; +typedef UInt16 somMigratedMethods; +typedef UInt16 somSelectedInherited; +typedef UInt32 somParentVersions; + +typedef struct { + /* const char * */ UInt32 className; + UInt32 instanceDataSize; + /* const somParentVersions * */ UInt32 parentVersions; + /* const somSlotUsage * */ UInt32 ttSlotUsage; + /* const somSignatureInfo * */ UInt32 signatureInfo; + /* const char * */ UInt32 methodNames; + /* const somOverrideData * */ UInt32 overrideData; + /* const somMigratedMethods * */ UInt32 migratedMethods; + /* const somSelectedInherited * */ UInt32 selectedInherited; + /* const void * */ UInt32 unused; + /* const void * */ UInt32 dummy4b[4]; +} somStaticClassDescription; + +typedef struct somStaticClassInfo { + UInt32 layoutVersion; + /* somClassDataStructure * */ UInt32 tokenTable; + /* somMethodPtr * */ UInt32 overrideMethods; + /* somClassDataStructure ** */ UInt32 specifiedAncestry; + /* somOpaque */ UInt32 DLLDesignator; + /* somMethodPtr * */ UInt32 specialProcs; + /* somRuntimeClassInfo * */ UInt32 runtimeClassInfo; + SInt32 interesting; + /* somClassDataStructure ** */ UInt32 actualAncestry; + /* void * */ UInt32 extra[4]; + /* const somStaticClassCounts * */ UInt32 classCounts; + somStaticClassDescription classDescription; +} somStaticClassInfo; + +CSOMStub *csom_stubs; +static HashNameNode *csom_initname; +static HashNameNode *csom_uninitname; +static HashNameNode *csom_envname; +static HashNameNode *csom_selfname; + +static FuncArg SOMIDT_arg1 = { + NULL, + NULL, + NULL, + TYPE(&void_ptr), + 0, + 0, + 0 +}; + +static TypeFunc SOMIDT_type = { + TYPEFUNC, + 0, + &SOMIDT_arg1, + NULL, + TYPE(&void_ptr), + 0, + 0 +}; + +void CSOM_Setup(Boolean flag) { + if (!flag) + csom_stubs = NULL; + + csom_initname = GetHashNameNodeExport("somInit"); + csom_uninitname = GetHashNameNodeExport("somUninit"); + csom_envname = GetHashNameNodeExport("Environment"); + csom_selfname = GetHashNameNodeExport("__somself"); +} + +void CSOM_Cleanup(void) { + CSOMStub *stub; + + if (cparamblkptr->precompile != 1) { + for (stub = csom_stubs; stub; stub = stub->next) { + switch (stub->x10) { + case 0: + CodeGen_SOMStub(stub->object, rt_som_glue1, stub->tclass->sominfo->classdataobject, stub->offset); + break; + case 1: + CodeGen_SOMStub(stub->object, rt_som_glue2, stub->tclass->sominfo->classdataobject, stub->offset); + break; + case 2: + CodeGen_SOMStub(stub->object, rt_som_glue3, stub->tclass->sominfo->classdataobject, stub->offset); + break; + default: + CError_FATAL(132); + } + } + } +} + +static HashNameNode *CSOM_NameTranslate(HashNameNode *name) { + if (name == constructor_name_node) + name = csom_initname; + else if (name == destructor_name_node) + name = csom_uninitname; + return name; +} + +static Type *CSOM_FindClassType(HashNameNode *name) { + Type *type; + + type = CScope_GetTagType(cscope_current, name); + if (!type) { + CPrep_ErrorName(CErrorStr281, name->name); + type = &stvoid; + } + + return type; +} + +CW_INLINE UInt16 CSOM_GetTokenTableIndex(const Object *object) { + CError_ASSERT(173, IS_TYPE_METHOD(object->type)); + return TYPE_METHOD(object->type)->vtbl_index; +} + +static SInt32 CSOM_GetTokenOffset(Object *object) { + return 24 + 4 * CSOM_GetTokenTableIndex(object); +} + +typedef struct TypeSig { + UInt8 x0; + UInt8 x1; + UInt8 x2; +} TypeSig; + +static int CSOM_GetTypeSig(TypeSig *sig, Type *type, Boolean flag) { + if (type->size > 4) + sig->x1 |= fgAnyNon4Bytes; + + switch (type->type) { + case TYPEVOID: + if (flag) + return pdVoid; + break; + case TYPEINT: + case TYPEENUM: + if (is_unsigned(type)) { + switch (type->size) { + case 1: + sig->x1 |= fgShortOrChars; + return pdUByte; + case 2: + sig->x1 |= fgShortOrChars; + return pdUHalf; + case 4: + return pdULong; + case 8: + return pdVLong; + } + } else { + switch (type->size) { + case 1: + sig->x1 |= fgShortOrChars; + return pdSByte; + case 2: + sig->x1 |= fgShortOrChars; + return pdSHalf; + case 4: + return pdSLong; + case 8: + return pdVLong; + } + } + break; + case TYPEFLOAT: + sig->x1 |= fgAnyFloats; + switch (type->size) { + case 4: + sig->x1 |= fgShortFloats; + return pdSFlt; + case 8: + return pdDFlt; + case 12: + case 16: + return pdLFlt; + } + break; + case TYPEPOINTER: + return pdNPtr; + case TYPESTRUCT: + case TYPECLASS: + if (flag) { + if (type->size <= 2) { + sig->x1 |= fgShortOrChars; + return pdVSAgg; + } else if (type->size <= 4) { + return pdSAgg; + } else { + return pdLAgg; + } + } + break; + } + + CError_Error(CErrorStr273); + return 5; +} + +static void CSOM_GetFuncSig(TypeFunc *tfunc, Boolean flag) { + FuncArg *arg; + Boolean pendingData; + UInt8 work; + TypeSig sig; + + sig.x2 = CSOM_GetTypeSig(&sig, tfunc->functype, 1); + sig.x1 = 0; + sig.x0 = 0; + + for (arg = tfunc->args; arg; arg = arg->next) { + if (arg == &elipsis || arg == &oldstyle || (++sig.x0 == 0)) { + CError_Error(CErrorStr273); + break; + } + + CSOM_GetTypeSig(&sig, arg->type, 0); + } + + if (flag) { + if ((arg = tfunc->args)) { + if (TYPE_METHOD(tfunc)->is_static == 0) + arg = arg->next; + if (arg && CMach_GetFunctionResultClass(tfunc) != 0) + arg = arg->next; + } + + AppendGListByte(&name_mangle_list, sig.x0); + AppendGListByte(&name_mangle_list, (sig.x1 << 4) | sig.x2); + if (sig.x1) { + pendingData = 0; + work = 0; + while (arg) { + work = (work << 4) | CSOM_GetTypeSig(&sig, arg->type, 0); + if (pendingData) { + AppendGListByte(&name_mangle_list, work); + pendingData = 0; + work = 0; + } else { + pendingData = 1; + } + arg = arg->next; + } + + if (pendingData) + AppendGListByte(&name_mangle_list, work << 4); + } + } +} + +void CSOM_CheckFuncType(TypeFunc *tfunc) { + CSOM_GetFuncSig(tfunc, 0); +} + +static Object *CSOM_MakeObject(char *name1, char *name2, SInt32 size) { + Object *object = CParser_NewCompilerDefDataObject(); + object->name = CParser_NameConcat(name1, name2); + object->type = CDecl_NewStructType(size, 4); + CScope_AddObject(object->nspace, object->name, OBJ_BASE(object)); + return object; +} + +void CSOM_MakeSOMClass(TypeClass *tclass) { + ClassList *base; + + for (base = tclass->bases; base; base = base->next) { + if (!base->base->sominfo) { + CError_Error(CErrorStr267); + break; + } + } + + if (!tclass->sominfo) { + SOMInfo *info = galloc(sizeof(SOMInfo)); + memclrw(info, sizeof(SOMInfo)); + tclass->sominfo = info; + + info->classdataobject = CSOM_MakeObject(tclass->classname->name, "ClassData", 28); + info->classdataobject->flags = info->classdataobject->flags | OBJECT_EXPORT; + } +} + +static Boolean CSOM_IsTokenListFunc(Object *object) { + Type *type = object->type; + if ( + IS_TYPE_FUNC(type) && + !(TYPE_FUNC(type)->flags & FUNC_FLAGS_20) && + !TYPE_METHOD(type)->is_static && + (!(object->qual & Q_INLINE) || object->datatype == DVFUNC) + ) + return 1; + + return 0; +} + +static Object **CSOM_GetLexicalOrderMethodArray(TypeClass *tclass, int *resultCount) { + Object *object; + int count; + Object **array; + CScopeObjectIterator iter; + + count = 0; + CScope_InitObjectIterator(&iter, tclass->nspace); + while (1) { + if (!(object = OBJECT(CScope_NextObjectIteratorObject(&iter)))) + break; + + if (IS_TYPE_METHOD(object->type)) { + if (CSOM_IsTokenListFunc(object)) { + if (TYPE_METHOD(object->type)->vtbl_index > count) + count = TYPE_METHOD(object->type)->vtbl_index; + } else { + TYPE_METHOD(object->type)->vtbl_index = 0; + } + } + } + + *resultCount = ++count; + + array = lalloc(sizeof(Object *) * count); + memclrw(array, sizeof(Object *) * count); + + CScope_InitObjectIterator(&iter, tclass->nspace); + while (1) { + if (!(object = OBJECT(CScope_NextObjectIteratorObject(&iter)))) + break; + + if (CSOM_IsTokenListFunc(object)) + array[TYPE_METHOD(object->type)->vtbl_index] = object; + } + + return array; +} + +void CSOM_ClassComplete(TypeClass *tclass) { + Object *object; + CScopeObjectIterator iter; + SInt32 counter; + SOMReleaseOrder *order; + + if (tclass->sominfo->order) { + CScope_InitObjectIterator(&iter, tclass->nspace); + while (1) { + if (!(object = OBJECT(CScope_NextObjectIteratorObject(&iter)))) + break; + + if (CSOM_IsTokenListFunc(object)) { + HashNameNode *name; + + name = CSOM_NameTranslate(object->name); + for (order = tclass->sominfo->order, counter = 0; order; order = order->next, counter++) { + if (order->name == name) { + order->state = SOMMS_Method; + TYPE_METHOD(object->type)->vtbl_index = counter; + break; + } + } + + if (!order) + CError_Error(CErrorStr278, object); + } + } + + for (order = tclass->sominfo->order; order; order = order->next) { + if (order->state == SOMMS_Deleted) { + SOMReleaseOrder *order2; + VClassList *vbase; + for (vbase = tclass->vbases; vbase; vbase = vbase->next) { + for (order2 = vbase->base->sominfo->order; order2; order2 = order2->next) { + if (order->name == order2->name && order2->state == SOMMS_Method) { + order->state = SOMMS_Migrated; + break; + } + } + } + } + } + } else { + Object **array; + int arrayCount; + SInt32 i; + + array = CSOM_GetLexicalOrderMethodArray(tclass, &arrayCount); + for (i = counter = 0; i < arrayCount; i++) { + object = array[i]; + if (object) { + if (counter == 0 && copts.pedantic) + CError_Warning(CErrorStr291); + TYPE_METHOD(object->type)->vtbl_index = counter++; + } + } + } + + CScope_InitObjectIterator(&iter, tclass->nspace); + while (1) { + NameSpaceObjectList *nsol; + if (!(nsol = CScope_NextObjectIteratorObjectList(&iter))) + break; + + if (nsol->object->otype == OT_OBJECT && nsol->next && nsol->next->object->otype == OT_OBJECT) { + while (nsol) { + if ( + nsol->object->otype == OT_OBJECT && + (!(OBJECT(nsol->object)->qual & Q_INLINE) || OBJECT(nsol->object)->datatype == DVFUNC) + ) + CError_Error(CErrorStr270, nsol->object); + nsol = nsol->next; + } + } + } + + CScope_InitObjectIterator(&iter, tclass->nspace); + while (1) { + if (!(object = OBJECT(CScope_NextObjectIteratorObject(&iter)))) + break; + + if (!(object->qual & Q_INLINE)) { + CError_ASSERT(529, IS_TYPE_FUNC(object->type)); + + TYPE_FUNC(object->type)->flags |= FUNC_FLAGS_4; + tclass->action = CLASS_ACTION_1; + while (1) { + if (!(object = OBJECT(CScope_NextObjectIteratorObject(&iter)))) + break; + + if (IS_TYPE_FUNC(object->type)) + TYPE_FUNC(object->type)->flags &= ~FUNC_FLAGS_4; + } + break; + } + } + + if (tclass->sominfo->oidl_callstyle == 0) { + Type *envType; + envType = CSOM_FindClassType(csom_envname); + + CScope_InitObjectIterator(&iter, tclass->nspace); + while (1) { + if (!(object = OBJECT(CScope_NextObjectIteratorObject(&iter)))) + break; + + if ( + IS_TYPE_FUNC(object->type) && + TYPE_METHOD(object->type)->is_static == 0 && + !(TYPE_FUNC(object->type)->flags & FUNC_FLAGS_20) && + !( + TYPE_FUNC(object->type)->args && + TYPE_FUNC(object->type)->args->next && + IS_TYPE_POINTER_ONLY(TYPE_FUNC(object->type)->args->next->type) && + TPTR_TARGET(TYPE_FUNC(object->type)->args->next->type) == envType + ) + ) + { + CError_Error(CErrorStr282, object); + } + } + } + + if (tclass->action == CLASS_ACTION_0) + CError_Error(CErrorStr280); +} + +#ifdef __MWERKS__ +#pragma options align=mac68k +#endif +typedef struct SOMOverride { + struct SOMOverride *next; + Object *a; + Object *b; +} SOMOverride; + +typedef struct SOMAncestor { + struct SOMAncestor *next; + TypeClass *tclass; + SOMOverride *overrides; + Boolean xC; + Boolean xD; +} SOMAncestor; + +typedef struct SOMMethod { + struct SOMMethod *next; + HashNameNode *name; + union { + Object *object; + struct { + UInt16 a; + UInt16 b; + } pair; + } u; + SOMMethodState state; +} SOMMethod; + +typedef struct SOMGenerator { + SOMMethod *methods; + SOMAncestor *ancestors; + Object *sciObj; + Object *classAncestorsObj; + Object *overrideProcsObj; + Object *dlldFunc; + Object *specialProcsObj; + somStaticClassCounts counts; + int overrideProcsCount; + Boolean hasNew; + Boolean hasDelete; +} SOMGenerator; +#ifdef __MWERKS__ +#pragma options align=reset +#endif + +static SOMAncestor *CSOM_FindAddAncestor(SOMGenerator *gen, TypeClass *tclass, TypeClass *ancestorClass, UInt16 *resultIndex) { + SOMAncestor *ancestor; + SOMAncestor *scan; + UInt16 index; + + ancestor = gen->ancestors; + for (scan = ancestor, index = 0; scan; scan = scan->next, index++) { + if (scan->tclass == ancestorClass) { + if (resultIndex) + *resultIndex = index; + return scan; + } + } + + if (ancestor) { + index = 1; + while (ancestor->next) { + index++; + ancestor = ancestor->next; + } + + ancestor->next = lalloc(sizeof(SOMAncestor)); + memclrw(ancestor->next, sizeof(SOMAncestor)); + ancestor = ancestor->next; + } else { + index = 0; + ancestor = lalloc(sizeof(SOMAncestor)); + memclrw(ancestor, sizeof(SOMAncestor)); + gen->ancestors = ancestor; + } + + ancestor->tclass = ancestorClass; + if (resultIndex) + *resultIndex = index; + return ancestor; +} + +static void CSOM_GenerateOverrideIntroLists(SOMGenerator *gen, TypeClass *tclass) { + Object *object; + VClassList *vbase; + ClassList *base; + SOMMethod *method; + SOMMethod **ptr; + CScopeObjectIterator iter; + + for (base = tclass->bases; base; base = base->next) { + SOMAncestor *ancestor = CSOM_FindAddAncestor(gen, tclass, base->base, NULL); + ancestor->xD = 1; + gen->counts.numDirectParents++; + } + + if (tclass->sominfo->metaclass && tclass->sominfo->metaclass->sominfo) { + SOMAncestor *ancestor = CSOM_FindAddAncestor(gen, tclass, tclass->sominfo->metaclass, NULL); + ancestor->xC = 1; + gen->counts.numMetaClasses++; + } + + CScope_InitObjectIterator(&iter, tclass->nspace); + while (1) { + if (!(object = OBJECT(CScope_NextObjectIteratorObject(&iter)))) + break; + + if (IS_TYPE_FUNC(object->type) && (TYPE_FUNC(object->type)->flags & FUNC_FLAGS_20)) { + for (vbase = tclass->vbases; vbase; vbase = vbase->next) { + Object *object2; + CScopeObjectIterator iter2; + CScope_InitObjectIterator(&iter2, vbase->base->nspace); + while (1) { + if (!(object2 = OBJECT(CScope_NextObjectIteratorObject(&iter2)))) + break; + + if ( + IS_TYPE_FUNC(object2->type) && + object->name == object2->name && + object2->datatype == DVFUNC && + !(TYPE_FUNC(object2->type)->flags & FUNC_FLAGS_20) && + CClass_GetOverrideKind(TYPE_FUNC(object->type), TYPE_FUNC(object2->type), 0) != 0 + ) + { + SOMAncestor *ancestor; + SOMOverride *override; + ancestor = CSOM_FindAddAncestor(gen, tclass, vbase->base, NULL); + if (ancestor->overrides) { + override = lalloc(sizeof(SOMOverride)); + memclrw(override, sizeof(SOMOverride)); + override->next = ancestor->overrides; + ancestor->overrides = override; + } else { + override = lalloc(sizeof(SOMOverride)); + memclrw(override, sizeof(SOMOverride)); + ancestor->overrides = override; + gen->counts.numOverriddenAncestors++; + } + override->a = object; + override->b = object2; + break; + } + } + } + gen->overrideProcsCount++; + } + } + + ptr = &gen->methods; + if (tclass->sominfo->order) { + SOMReleaseOrder *order; + SOMReleaseOrder *order2; + SInt32 index; + UInt16 index2; + + for (order = tclass->sominfo->order, index = 0; order; order = order->next, index++) { + method = lalloc(sizeof(SOMMethod)); + memclrw(method, sizeof(SOMMethod)); + *ptr = method; + ptr = &method->next; + + method->name = order->name; + method->state = order->state; + switch (order->state) { + case SOMMS_Migrated: + for (vbase = tclass->vbases; vbase; vbase = vbase->next) { + for (order2 = vbase->base->sominfo->order, index2 = 0; order2; order2 = order2->next, index2++) { + if (order->name == order2->name && order2->state == SOMMS_Method) { + CSOM_FindAddAncestor(gen, tclass, vbase->base, &method->u.pair.a); + method->u.pair.b = index2; + break; + } + } + + if (order2) + break; + } + gen->counts.numMigratedMethods++; + break; + + case SOMMS_Method: + CScope_InitObjectIterator(&iter, tclass->nspace); + while (1) { + if (!(object = OBJECT(CScope_NextObjectIteratorObject(&iter)))) + break; + + if ( + IS_TYPE_FUNC(object->type) && + CSOM_NameTranslate(object->name) == order->name + ) + { + CError_ASSERT(733, TYPE_METHOD(object->type)->vtbl_index == index); + method->u.object = object; + break; + } + } + + CError_ASSERT(737, object != NULL); + break; + } + + gen->counts.classTokenCount++; + } + } else { + Object **array; + int arrayCount; + SInt32 i; + + array = CSOM_GetLexicalOrderMethodArray(tclass, &arrayCount); + for (i = 0; i < arrayCount; i++) { + object = array[i]; + if (object) { + method = lalloc(sizeof(SOMMethod)); + memclrw(method, sizeof(SOMMethod)); + *ptr = method; + ptr = &method->next; + + method->u.object = object; + method->name = object->name; + method->state = SOMMS_Method; + gen->counts.classTokenCount++; + } + } + } +} + +static void CSOM_GenerateClassAncestors(SOMGenerator *gen, TypeClass *tclass) { + SOMAncestor *ancestor; + Object *object; + OLinkList *relocs; + SInt32 size; + char *buf; + + if (gen->ancestors) { + object = CSOM_MakeObject(tclass->classname->name, "ClassAncestors", 4); + object->sclass = TK_STATIC; + + relocs = NULL; + size = 0; + for (ancestor = gen->ancestors; ancestor; ancestor = ancestor->next) { + OLinkList *reloc = lalloc(sizeof(OLinkList)); + reloc->next = relocs; + relocs = reloc; + reloc->obj = ancestor->tclass->sominfo->classdataobject; + reloc->offset = size; + reloc->somevalue = 0; + size += 4; + } + + buf = lalloc(size); + memclrw(buf, size); + object->type->size = size; + CInit_DeclareData(object, buf, relocs, object->type->size); + gen->classAncestorsObj = object; + } +} + +static void CSOM_GenerateOverrideProcs(SOMGenerator *gen, TypeClass *tclass) { + SOMOverride *override; + SOMAncestor *ancestor; + Object *object; + OLinkList *relocs; + SInt32 size; + SInt32 offset; + char *buf; + + if (gen->overrideProcsCount) { + size = gen->overrideProcsCount * 4; + object = CSOM_MakeObject(tclass->classname->name, "OverrideProcs", size); + object->sclass = TK_STATIC; + + relocs = NULL; + offset = 0; + for (ancestor = gen->ancestors; ancestor; ancestor = ancestor->next) { + if (ancestor->overrides) { + for (override = ancestor->overrides; override; override = override->next) { + OLinkList *reloc = lalloc(sizeof(OLinkList)); + reloc->next = relocs; + relocs = reloc; + reloc->obj = override->a; + reloc->offset = offset; + reloc->somevalue = 0; + offset += 4; + } + } + } + + buf = lalloc(size); + memclrw(buf, size); + CInit_DeclareData(object, buf, relocs, object->type->size); + gen->overrideProcsObj = object; + } +} + +static Object *CSOM_GenerateOverrideData(SOMGenerator *gen) { + SOMAncestor *ancestor; + Object *object; + short ancestorIndex; + + name_mangle_list.size = 0; + for (ancestor = gen->ancestors, ancestorIndex = 0; ancestor; ancestor = ancestor->next, ancestorIndex++) { + if (ancestor->overrides) { + SOMOverride *override; + short overrideCount; + + AppendGListWord(&name_mangle_list, CTool_EndianConvertWord16(ancestorIndex)); + + override = ancestor->overrides; + overrideCount = 0; + while (override) { + overrideCount++; + override = override->next; + } + AppendGListWord(&name_mangle_list, CTool_EndianConvertWord16(overrideCount)); + + for (override = ancestor->overrides; override; override = override->next) { + AppendGListWord(&name_mangle_list, CTool_EndianConvertWord16(CSOM_GetTokenTableIndex(override->b))); + } + } + } + + COS_LockHandle(name_mangle_list.data); + object = CInit_DeclareString(*name_mangle_list.data, name_mangle_list.size, 0, 0); + COS_UnlockHandle(name_mangle_list.data); + return object; +} + +static Object *CSOM_GenerateMigrateData(SOMGenerator *gen) { + SOMMethod *method; + Object *object; + int index; + + name_mangle_list.size = 0; + for (method = gen->methods, index = 0; method; method = method->next, index++) { + if (method->state == SOMMS_Migrated) { + AppendGListWord(&name_mangle_list, CTool_EndianConvertWord16(method->u.pair.a)); + AppendGListWord(&name_mangle_list, CTool_EndianConvertWord16(method->u.pair.b)); + AppendGListWord(&name_mangle_list, CTool_EndianConvertWord16(index)); + } + } + + COS_LockHandle(name_mangle_list.data); + object = CInit_DeclareString(*name_mangle_list.data, name_mangle_list.size, 0, 0); + COS_UnlockHandle(name_mangle_list.data); + return object; +} + +static void CSOM_GenerateDLLDFunc(SOMGenerator *gen, TypeClass *tclass) { + TypeFunc *tfunc; + Object *object; + + tfunc = galloc(sizeof(TypeFunc)); + memclrw(tfunc, sizeof(TypeFunc)); + tfunc->type = TYPEFUNC; + tfunc->functype = &stvoid; + + object = CParser_NewCompilerDefFunctionObject(); + object->type = TYPE(tfunc); + object->sclass = TK_STATIC; + object->name = CParser_NameConcat(tclass->classname->name, "DLLD"); + + if (CScope_GetLocalObject(cscope_root, object->name)) + CError_Error(CErrorStr333, object); + + gen->dlldFunc = object; + CFunc_GenerateDummyFunction(object); +} + +static void CSOM_GenerateSpecialProcs(SOMGenerator *gen, TypeClass *tclass) { + Object *newFunc; + Object *deleteFunc; + Object *object; + OLinkList *relocs; + SInt32 size; + CScopeObjectIterator iter; + char buf[16]; + + newFunc = deleteFunc = NULL; + CScope_InitObjectIterator(&iter, tclass->nspace); + while (1) { + if (!(object = OBJECT(CScope_NextObjectIteratorObject(&iter)))) + break; + + if (IS_TYPE_FUNC(object->type)) { + if (object->name == CMangler_OperatorName(TK_NEW)) { + newFunc = object; + gen->hasNew = 1; + } else if (object->name == CMangler_OperatorName(TK_DELETE)) { + deleteFunc = object; + gen->hasDelete = 1; + } + } + } + + if (newFunc || deleteFunc) { + object = CSOM_MakeObject(tclass->classname->name, "SpecialProcs", 4); + object->sclass = TK_STATIC; + + relocs = NULL; + size = 0; + + if (newFunc) { + OLinkList *reloc = lalloc(sizeof(OLinkList)); + reloc->next = relocs; + relocs = reloc; + reloc->obj = newFunc; + reloc->offset = size; + reloc->somevalue = 0; + size += 4; + } + + if (deleteFunc) { + OLinkList *reloc = lalloc(sizeof(OLinkList)); + reloc->next = relocs; + relocs = reloc; + reloc->obj = deleteFunc; + reloc->offset = size; + reloc->somevalue = 0; + size += 4; + } + + memclrw(buf, sizeof(buf)); + object->type->size = size; + CInit_DeclareData(object, buf, relocs, object->type->size); + gen->specialProcsObj = object; + } +} + +static Object *CSOM_GenerateParentVersion(SOMGenerator *gen) { + SInt32 size; + UInt32 *buf; + SOMAncestor *ancestor; + SInt32 offset; + + size = 8 * (gen->counts.numDirectParents + gen->counts.numMetaClasses); + buf = lalloc(size); + + for (ancestor = gen->ancestors, offset = 0; ancestor; ancestor = ancestor->next) { + if (ancestor->xC || ancestor->xD) { + buf[offset++] = CTool_EndianConvertWord32(ancestor->tclass->sominfo->majorversion); + buf[offset++] = CTool_EndianConvertWord32(ancestor->tclass->sominfo->minorversion); + } + } + + return CInit_DeclareString((char *) buf, size, 0, 0); +} + +static void CSOM_SetNibble(char *buf, int offset, UInt8 value) { + int i = offset >> 1; + if (offset & 1) { + int left = buf[i] & 0xF0; + int right = value & 0xF; + buf[i] = left | right; + } else { + int left = value << 4; + int right = buf[i] & 0xF; + buf[i] = left | right; + } +} + +static Object *CSOM_GenerateSlotUsage(SOMGenerator *gen) { + SInt32 size; + SOMMethod *method; + char *buf; + int offset; + + size = (gen->counts.classTokenCount + 1) / 2; + buf = lalloc(size); + memclrw(buf, size); + + for (method = gen->methods, offset = 0; method; method = method->next, offset++) { + switch (method->state) { + case SOMMS_Deleted: + case SOMMS_Migrated: + CSOM_SetNibble(buf, offset, mtEmpty); + break; + case SOMMS_Method: + CSOM_SetNibble(buf, offset, mtVirtualMethod); + break; + default: + CError_FATAL(1048); + } + } + + return CInit_DeclareString(buf, size, 0, 0); +} + +static Object *CSOM_GenerateSignature(SOMGenerator *gen) { + Object *object; + SOMMethod *method; + + name_mangle_list.size = 0; + + for (method = gen->methods; method; method = method->next) { + if (method->state == SOMMS_Method) + CSOM_GetFuncSig(TYPE_FUNC(method->u.object->type), 1); + } + + COS_LockHandle(name_mangle_list.data); + object = CInit_DeclareString(*name_mangle_list.data, name_mangle_list.size, 0, 0); + COS_UnlockHandle(name_mangle_list.data); + return object; +} + +static Object *CSOM_GenerateMethodNames(SOMGenerator *gen) { + Object *object; + SOMMethod *method; + HashNameNode *name; + + name_mangle_list.size = 0; + + for (method = gen->methods; method; method = method->next) { + if (method->name) { + name = CSOM_NameTranslate(method->name); + AppendGListID(&name_mangle_list, name->name); + } + } + + COS_LockHandle(name_mangle_list.data); + object = CInit_DeclareString(*name_mangle_list.data, name_mangle_list.size, 0, 0); + COS_UnlockHandle(name_mangle_list.data); + return object; +} + +static void CSOM_SetupClassCounts(SOMGenerator *gen, TypeClass *tclass, somStaticClassCounts *counts) { + gen->counts.majorVersion = tclass->sominfo->majorversion; + gen->counts.minorVersion = tclass->sominfo->minorversion; + gen->counts.flags = cfSharedStrings; + if (gen->hasNew) + gen->counts.flags |= cfClassAllocate; + if (gen->hasDelete) + gen->counts.flags |= cfClassDeallocate; + + switch (tclass->align) { + case 1: + gen->counts.dataAlignment = 0; + break; + case 2: + gen->counts.dataAlignment = 1; + break; + case 4: + gen->counts.dataAlignment = 2; + break; + case 8: + gen->counts.dataAlignment = 3; + break; + default: + gen->counts.dataAlignment = 4; + break; + } + + gen->counts.numSelectInherited = 0; + + memclrw(counts, sizeof(somStaticClassCounts)); + counts->majorVersion = CTool_EndianConvertWord32(gen->counts.majorVersion); + counts->minorVersion = CTool_EndianConvertWord32(gen->counts.minorVersion); + counts->flags = CTool_EndianConvertWord32(gen->counts.flags); + counts->dataAlignment = CTool_EndianConvertWord16(gen->counts.dataAlignment); + counts->classTokenCount = CTool_EndianConvertWord16(gen->counts.classTokenCount); + counts->numDirectParents = CTool_EndianConvertWord16(gen->counts.numDirectParents); + counts->numMetaClasses = CTool_EndianConvertWord16(gen->counts.numMetaClasses); + counts->numOverriddenAncestors = CTool_EndianConvertWord16(gen->counts.numOverriddenAncestors); + counts->numMigratedMethods = CTool_EndianConvertWord16(gen->counts.numMigratedMethods); + counts->numSelectInherited = CTool_EndianConvertWord16(gen->counts.numSelectInherited); +} + +static void CSOM_GenerateSCIObject(SOMGenerator *gen, TypeClass *tclass) { + Object *object; + OLinkList *relocs; + OLinkList *reloc; + somStaticClassInfo sci; + somStaticClassCounts classCounts; + + object = CSOM_MakeObject(tclass->classname->name, "SCI", sizeof(sci)); + object->sclass = TK_STATIC; + + memclrw(&sci, sizeof(sci)); + sci.layoutVersion = CTool_EndianConvertWord32(70); + + reloc = lalloc(sizeof(OLinkList)); + reloc->next = NULL; + relocs = reloc; + reloc->obj = tclass->sominfo->classdataobject; + reloc->offset = 4; + reloc->somevalue = 0; + + if (gen->overrideProcsObj) { + reloc = lalloc(sizeof(OLinkList)); + reloc->next = relocs; + relocs = reloc; + reloc->obj = gen->overrideProcsObj; + reloc->offset = 8; + reloc->somevalue = 0; + } + + if (gen->classAncestorsObj) { + reloc = lalloc(sizeof(OLinkList)); + reloc->next = relocs; + relocs = reloc; + reloc->obj = gen->classAncestorsObj; + reloc->offset = 12; + reloc->somevalue = 0; + } + + if (gen->dlldFunc) { + reloc = lalloc(sizeof(OLinkList)); + reloc->next = relocs; + relocs = reloc; + reloc->obj = gen->dlldFunc; + reloc->offset = 16; + reloc->somevalue = 0; + } + + if (gen->specialProcsObj) { + reloc = lalloc(sizeof(OLinkList)); + reloc->next = relocs; + relocs = reloc; + reloc->obj = gen->specialProcsObj; + reloc->offset = 20; + reloc->somevalue = 0; + } + + CSOM_SetupClassCounts(gen, tclass, &classCounts); + + reloc = lalloc(sizeof(OLinkList)); + reloc->next = relocs; + relocs = reloc; + reloc->obj = CInit_DeclareString((char *) &classCounts, sizeof(classCounts), 0, 0); + reloc->offset = 52; + reloc->somevalue = 0; + + reloc = lalloc(sizeof(OLinkList)); + reloc->next = relocs; + relocs = reloc; + reloc->obj = CInit_DeclareString(tclass->classname->name, strlen(tclass->classname->name) + 1, 0, 0); + reloc->offset = 56; + reloc->somevalue = 0; + + sci.classDescription.instanceDataSize = CTool_EndianConvertWord32(tclass->size); + + reloc = lalloc(sizeof(OLinkList)); + reloc->next = relocs; + relocs = reloc; + reloc->obj = CSOM_GenerateParentVersion(gen); + reloc->offset = 64; + reloc->somevalue = 0; + + if (gen->methods) { + reloc = lalloc(sizeof(OLinkList)); + reloc->next = relocs; + relocs = reloc; + reloc->obj = CSOM_GenerateSlotUsage(gen); + reloc->offset = 68; + reloc->somevalue = 0; + + reloc = lalloc(sizeof(OLinkList)); + reloc->next = relocs; + relocs = reloc; + reloc->obj = CSOM_GenerateSignature(gen); + reloc->offset = 72; + reloc->somevalue = 0; + + reloc = lalloc(sizeof(OLinkList)); + reloc->next = relocs; + relocs = reloc; + reloc->obj = CSOM_GenerateMethodNames(gen); + reloc->offset = 76; + reloc->somevalue = 0; + } + + if (gen->overrideProcsObj) { + reloc = lalloc(sizeof(OLinkList)); + reloc->next = relocs; + relocs = reloc; + reloc->obj = CSOM_GenerateOverrideData(gen); + reloc->offset = 80; + reloc->somevalue = 0; + } + + if (gen->counts.numMigratedMethods) { + reloc = lalloc(sizeof(OLinkList)); + reloc->next = relocs; + relocs = reloc; + reloc->obj = CSOM_GenerateMigrateData(gen); + reloc->offset = 84; + reloc->somevalue = 0; + } + + sci.classDescription.selectedInherited = 0; + + CInit_DeclareData(object, &sci, relocs, object->type->size); + gen->sciObj = object; +} + +static void CSOM_GenerateClassDataObject(SOMGenerator *gen, TypeClass *tclass) { + void *buf; + OLinkList *relocs; + OLinkList *reloc; + SInt32 size; + SOMMethod *method; + + relocs = NULL; + for (size = 24, method = gen->methods; method; method = method->next) { + if (method->state == SOMMS_Method) { + reloc = lalloc(sizeof(OLinkList)); + reloc->next = relocs; + relocs = reloc; + reloc->obj = method->u.object; + reloc->offset = size; + reloc->somevalue = 0; + } + size += 4; + } + + buf = lalloc(size); + memclrw(buf, size); + + reloc = lalloc(sizeof(OLinkList)); + reloc->next = relocs; + relocs = reloc; + reloc->obj = gen->sciObj; + reloc->offset = 4; + reloc->somevalue = 0; + + tclass->sominfo->classdataobject->type->size = size; + CInit_DeclareData(tclass->sominfo->classdataobject, buf, relocs, tclass->sominfo->classdataobject->type->size); +} + +void CSOM_GenerateClassStructures(TypeClass *tclass) { + SOMGenerator gen; + + memclrw(&gen, sizeof(gen)); + CSOM_GenerateOverrideIntroLists(&gen, tclass); + CSOM_GenerateClassAncestors(&gen, tclass); + CSOM_GenerateOverrideProcs(&gen, tclass); + CSOM_GenerateDLLDFunc(&gen, tclass); + CSOM_GenerateSpecialProcs(&gen, tclass); + CSOM_GenerateSCIObject(&gen, tclass); + CSOM_GenerateClassDataObject(&gen, tclass); +} + +static TypeClass *CSOM_GetCurrentSOMClass(void) { + if (cscope_current->theclass && cscope_current->theclass->sominfo) + return cscope_current->theclass; + + CError_Error(CErrorStr277); + return NULL; +} + +void CSOM_PragmaReleaseOrder(void) { + TypeClass *tclass; + SOMReleaseOrder *firstOrder; + SOMReleaseOrder *order; + SOMReleaseOrder **ptr; + Boolean flag; + short token; + + if (!(tclass = CSOM_GetCurrentSOMClass())) + return; + + token = CPrep_PragmaLex(0); + if (token != '(') { + if (token != TK_IDENTIFIER) { + CPrep_Error(CErrorStr114); + return; + } + + if (!strcmp(tkidentifier->name, "list")) { + token = CPrep_PragmaLex(0); + if (token != TK_IDENTIFIER) { + CPrep_Error(CErrorStr107); + return; + } + } + + flag = 1; + } else { + flag = 0; + token = CPrep_PragmaLex(0); + } + + firstOrder = NULL; + if (flag || token != ')') { + ptr = &firstOrder; + while (1) { + if (token != TK_IDENTIFIER) { + CPrep_Error(CErrorStr107); + return; + } + + for (order = firstOrder; order; order = order->next) { + if (order->name == tkidentifier) { + CError_Error(CErrorStr122, tkidentifier->name); + return; + } + } + + order = galloc(sizeof(SOMReleaseOrder)); + *ptr = order; + ptr = &order->next; + + order->next = NULL; + order->name = tkidentifier; + order->state = SOMMS_Deleted; + + if (flag) { + token = CPrep_PragmaLex(1); + if (!token) + break; + } else { + token = CPrep_PragmaLex(0); + if (token == ')') + break; + } + + if (token != ',') { + CPrep_Error(CErrorStr116); + return; + } + + token = CPrep_PragmaLex(flag); + } + } + + tclass->sominfo->order = firstOrder; +} + +void CSOM_PragmaClassVersion(void) { + Type *type; + + if (CPrep_PragmaLex(0) != '(') { + CPrep_Error(CErrorStr114); + return; + } + + if (CPrep_PragmaLex(0) != TK_IDENTIFIER) { + CPrep_Error(CErrorStr107); + return; + } + + type = CScope_GetTagType(cscope_current, tkidentifier); + if (!(type && IS_TYPE_CLASS(type) && TYPE_CLASS(type)->sominfo)) { + CPrep_ErrorName(CErrorStr276, tkidentifier->name); + return; + } + + if (CPrep_PragmaLex(0) != ',') { + CPrep_Error(CErrorStr116); + return; + } + + if (CPrep_PragmaLex(0) != TK_INTCONST) { + CPrep_Error(CErrorStr186); + return; + } + + TYPE_CLASS(type)->sominfo->majorversion = CInt64_GetULong(&tkintconst); + + if (CPrep_PragmaLex(0) != ',') { + CPrep_Error(CErrorStr116); + return; + } + + if (CPrep_PragmaLex(0) != TK_INTCONST) { + CPrep_Error(CErrorStr186); + return; + } + + TYPE_CLASS(type)->sominfo->minorversion = CInt64_GetULong(&tkintconst); + + if (CPrep_PragmaLex(0) != ')') { + CPrep_Error(CErrorStr115); + return; + } +} + +void CSOM_PragmaMetaClass(void) { + Type *type; + Type *type2; + + if (CPrep_PragmaLex(0) != '(') { + CPrep_Error(CErrorStr114); + return; + } + + if (CPrep_PragmaLex(0) != TK_IDENTIFIER) { + CPrep_Error(CErrorStr107); + return; + } + + type = CScope_GetTagType(cscope_current, tkidentifier); + if (!(type && IS_TYPE_CLASS(type) && TYPE_CLASS(type)->sominfo)) { + CPrep_ErrorName(CErrorStr276, tkidentifier->name); + return; + } + + if (CPrep_PragmaLex(0) != ',') { + CPrep_Error(CErrorStr116); + return; + } + + if (CPrep_PragmaLex(0) != TK_IDENTIFIER) { + CPrep_Error(CErrorStr107); + return; + } + + type2 = CScope_GetTagType(cscope_current, tkidentifier); + if (!(type2 && IS_TYPE_CLASS(type2) && TYPE_CLASS(type2)->sominfo)) { + CPrep_ErrorName(CErrorStr276, tkidentifier->name); + return; + } + + TYPE_CLASS(type)->sominfo->metaclass = TYPE_CLASS(type2); + + if (CPrep_PragmaLex(0) != ')') { + CPrep_Error(CErrorStr115); + return; + } +} + +void CSOM_PragmaCallStyle(void) { + TypeClass *tclass; + + if (!(tclass = CSOM_GetCurrentSOMClass())) + return; + + if (CPrep_PragmaLex(0) != TK_IDENTIFIER) { + CPrep_Error(CErrorStr107); + return; + } + + if (!strcmp(tkidentifier->name, "IDL")) { + tclass->sominfo->oidl_callstyle = 0; + return; + } + + if (!strcmp(tkidentifier->name, "OIDL")) { + tclass->sominfo->oidl_callstyle = 1; + return; + } + + CPrep_Error(CErrorStr186); +} + +void CSOM_FixNewDeleteFunctype(TypeFunc *tfunc) { + FuncArg *arg = CParser_NewFuncArg(); + arg->name = GetHashNameNodeExport("__theclass"); + arg->type = CDecl_NewPointerType(CSOM_FindClassType(GetHashNameNodeExport("SOMClass"))); + arg->next = tfunc->args; + tfunc->args = arg; +} + +static Object *CSOM_FindRTFunc(char *namestr, char *sig) { + NameSpaceObjectList *nsol; + Object *object; + FuncArg *arg; + + if ( + (nsol = CScope_GetLocalObject(cscope_root, GetHashNameNodeExport(namestr))) && + nsol->object->otype == OT_OBJECT + ) + { + object = OBJECT(nsol->object); + if ( + IS_TYPE_FUNC(object->type) && + *(sig++) == 'p' && + IS_TYPE_POINTER_ONLY(TYPE_FUNC(object->type)->functype) + ) + { + for (arg = TYPE_FUNC(object->type)->args; arg; arg = arg->next) { + switch (*(sig++)) { + case 'p': + if (IS_TYPE_POINTER_ONLY(arg->type)) + continue; + break; + case 'i': + if (arg->type == TYPE(&stsignedint)) + continue; + break; + case 'I': + if (arg->type == TYPE(&stunsignedint)) + continue; + break; + case 'l': + if (arg->type == TYPE(&stsignedlong)) + continue; + break; + case 'L': + if (arg->type == TYPE(&stunsignedlong)) + continue; + break; + } + break; + } + + if (arg == NULL && *sig == 0) + return object; + } + + CError_Error(CErrorStr275, namestr); + } else { + CError_Error(CErrorStr274, namestr); + } + + return NULL; +} + +static ENode *CSOM_MakeTempCondition(ENode *left, ENode *cond, ENode *expr1, ENode *right) { + ENode *expr; + + expr = lalloc(sizeof(ENode)); + expr->type = ECOND; + expr->cost = 0; + expr->flags = 0; + expr->rtype = &stvoid; + expr->data.cond.cond = cond; + expr->data.cond.expr1 = expr1; + expr->data.cond.expr2 = nullnode(); + expr->data.cond.expr2->rtype = &stvoid; + + if (left) + expr = makediadicnode(left, expr, ECOMMA); + + if (right) { + expr = makediadicnode(expr, right, ECOMMA); + expr->rtype = right->rtype; + } + + return expr; +} + +ENode *CSOM_New(TypeClass *tclass) { + Object *newFunc; + ENode *expr; + + if (tk == '(') { + if ((tk = lex()) == ')') { + tk = lex(); + } else { + CError_Error(CErrorStr272); + } + } + + if (!copts.som_env_check || !copts.som_call_optimize) { + newFunc = CSOM_FindRTFunc("somNewObjectInstance", "ppll"); + if (!newFunc) + return nullnode(); + } else { + newFunc = rt_som_new; + } + + expr = funccallexpr( + newFunc, + create_objectrefnode(tclass->sominfo->classdataobject), + intconstnode(TYPE(&stunsignedlong), tclass->sominfo->majorversion), + intconstnode(TYPE(&stunsignedlong), tclass->sominfo->minorversion), + NULL + ); + expr->rtype = CDecl_NewPointerType(TYPE(tclass)); + + if (copts.som_env_check && !copts.som_call_optimize) { + ENode *tempExpr; + ENode *checkExpr; + ENode *notExpr; + tempExpr = CExpr_GetETEMPCopy(expr); + checkExpr = funccallexpr(rt_som_newcheck, nullnode(), NULL, NULL, NULL); + notExpr = makemonadicnode(tempExpr, ELOGNOT); + notExpr->rtype = CParser_GetBoolType(); + expr = CSOM_MakeTempCondition(NULL, notExpr, checkExpr, tempExpr); + } + + return expr; +} + +ENode *CSOM_Delete(TypeClass *tclass, ENode *objExpr) { + Object *func; + + if ((func = CSOM_FindRTFunc("somReleaseObjectReference", "pp"))) + return funccallexpr(func, objExpr, NULL, NULL, NULL); + + return nullnode(); +} + +void CSOM_InitAutoClass(Object *object) { + Type *type; + Statement *stmt; + Object *func; + + if ((func = CSOM_FindRTFunc("somReleaseObjectReference", "pp"))) { + type = object->type; + object->type = CDecl_NewPointerType(type); + TPTR_QUAL(object->type) = Q_REFERENCE; + + stmt = CFunc_AppendStatement(ST_EXPRESSION); + stmt->expr = makediadicnode(create_objectnode2(object), CSOM_New(TYPE_CLASS(type)), EASS); + CExcept_RegisterDeleteObject(stmt, object, func); + } +} + +static void CSOM_FindIntroClassOffset(TypeClass *tclass, Object *func, TypeClass **resultClass, SInt32 *resultOffset) { + Object *scan; + VClassList *vbase; + CScopeObjectIterator iter; + + if (!(TYPE_FUNC(func->type)->flags & FUNC_FLAGS_20)) { + CScope_InitObjectIterator(&iter, tclass->nspace); + while (1) { + if (!(scan = OBJECT(CScope_NextObjectIteratorObject(&iter)))) + break; + + if (scan == func) { + *resultClass = tclass; + *resultOffset = CSOM_GetTokenOffset(scan); + return; + } + } + + for (vbase = tclass->vbases; vbase; vbase = vbase->next) { + CScope_InitObjectIterator(&iter, vbase->base->nspace); + while (1) { + if (!(scan = OBJECT(CScope_NextObjectIteratorObject(&iter)))) + break; + + if (scan == func) { + *resultClass = vbase->base; + *resultOffset = CSOM_GetTokenOffset(scan); + return; + } + } + } + } else { + for (vbase = tclass->vbases; vbase; vbase = vbase->next) { + CScope_InitObjectIterator(&iter, vbase->base->nspace); + while (1) { + if (!(scan = OBJECT(CScope_NextObjectIteratorObject(&iter)))) + break; + + if (scan->name == func->name) { + if ( + IS_TYPE_FUNC(scan->type) && + scan->datatype == DVFUNC && + !(TYPE_FUNC(scan->type)->flags & FUNC_FLAGS_20) && + CClass_GetOverrideKind(TYPE_FUNC(func->type), TYPE_FUNC(scan->type), 0) + ) + { + *resultClass = vbase->base; + *resultOffset = CSOM_GetTokenOffset(scan); + return; + } + break; + } + } + } + } + + CError_FATAL(1731); +} + +static ENode *CSOM_ComputeSOMSelf(TypeClass *tclass, ENode *selfExpr) { + ENode *expr; + Object obj; + + expr = create_objectrefnode(tclass->sominfo->classdataobject); + expr = makediadicnode(expr, intconstnode(TYPE(&stsignedlong), 8), EADD); + expr->rtype = CDecl_NewPointerType(TYPE(&SOMIDT_type)); + expr = makemonadicnode(expr, EINDIRECT); + + memclrw(&obj, sizeof(Object)); + obj.otype = OT_OBJECT; + obj.type = TYPE(&SOMIDT_type); + obj.name = no_name_node; + obj.datatype = DFUNC; + selfExpr = funccallexpr(&obj, selfExpr, NULL, NULL, NULL); + + CError_ASSERT(1761, ENODE_IS(selfExpr, EFUNCCALL)); + + selfExpr->data.funccall.funcref = expr; + + return selfExpr; +} + +ENode *CSOM_SOMSelfObjectExpr(TypeClass *tclass) { + ObjectList *list; + Object *obj; + + for (list = locals; list; list = list->next) { + if (list->object->name == csom_selfname) + return create_objectnode(list->object); + } + + obj = CParser_NewLocalDataObject(NULL, 1); + obj->name = csom_selfname; + obj->type = CDecl_NewPointerType(TYPE(tclass)); + CFunc_SetupLocalVarInfo(obj); + return create_objectnode(obj); +} + +void CSOM_InitSOMSelf(TypeClass *tclass, Statement *stmt) { + ObjectList *list; + HashNameNode *name; + ENode *selfExpr; + + name = GetHashNameNodeExport("__somself"); + for (list = locals; list; list = list->next) { + if (list->object->name == name) { + selfExpr = CClass_CreateThisSelfExpr(); + CError_ASSERT(1811, selfExpr); + + selfExpr = CSOM_ComputeSOMSelf(tclass, selfExpr); + + stmt = CFunc_InsertStatement(ST_EXPRESSION, stmt); + stmt->expr = makediadicnode(create_objectnode(list->object), selfExpr, EASS); + break; + } + } +} + +ENode *CSOM_EnvCheck(ENode *funccall, ENodeList *checkArg) { + ENodeList *arg; // r26 + ENodeList *arg2; // r28 + ENode *expr26; // r26 + ENode *expr27; // r27 + ENode *expr28; // r28 + Type *returnType; // r31 + + returnType = funccall->rtype; + CError_ASSERT(1842, arg = funccall->data.funccall.args); + + if (arg == checkArg) + CError_ASSERT(1845, arg = arg->next); + + CError_ASSERT(1847, arg2 = arg->next); + + if (arg2 == checkArg) + CError_ASSERT(1850, arg2 = arg2->next); + + CError_ASSERT(1852, IS_TYPE_POINTER_ONLY(arg2->node->rtype)); + + if (!IS_TYPE_VOID(funccall->data.funccall.functype->functype)) { + if (checkArg) { + if (ENODE_IS(checkArg->node, ETEMP)) { + if (checkArg->node->data.temp.uniqueid == 0) + checkArg->node->data.temp.uniqueid = CParser_GetUniqueID(); + + expr26 = lalloc(sizeof(ENode)); + *expr26 = *checkArg->node; + expr26->data.temp.needs_dtor = 0; + } else { + expr26 = CExpr_GetETEMPCopy(checkArg->node); + } + } else { + expr26 = CExpr_GetETEMPCopy(funccall); + } + } else { + expr26 = NULL; + } + + if (!ENODE_IS(arg2->node, EOBJREF)) { + if (ENODE_IS_INDIRECT_TO(arg2->node, EOBJREF) && arg2->node->data.monadic->data.objref->datatype == DLOCAL) { + expr27 = lalloc(sizeof(ENode)); + *expr27 = *arg2->node; + } else { + expr27 = CExpr_GetETEMPCopy(arg2->node); + } + } else { + expr27 = lalloc(sizeof(ENode)); + *expr27 = *arg2->node; + } + + if (copts.som_call_optimize) { + funccall = makediadicnode(funccall, funccallexpr(rt_som_check, expr27, NULL, NULL, NULL), ECOMMA); + if (expr26) + funccall = makediadicnode(funccall, expr26, ECOMMA); + } else { + expr28 = lalloc(sizeof(ENode)); + *expr28 = *expr27; + expr28 = makemonadicnode(expr28, EINDIRECT); + expr28->rtype = TYPE(&stsignedlong); + + funccall = CSOM_MakeTempCondition( + funccall, + expr28, + funccallexpr(rt_som_check, expr27, NULL, NULL, NULL), + expr26); + } + + funccall->rtype = returnType; + return funccall; +} + +static Boolean CSOM_CanUseGlueCall(TypeFunc *tfunc) { + int gprCounter; + int fprCounter; + FuncArg *arg; + + gprCounter = 8; + fprCounter = 13; + if (CMach_GetFunctionResultClass(tfunc) != 0) + gprCounter = 7; + + for (arg = tfunc->args; arg; arg = arg->next) { + if (arg == &elipsis || arg == &oldstyle) + return 0; + + switch (arg->type->type) { + case TYPEINT: + case TYPEENUM: + case TYPEPOINTER: + if (--gprCounter < 0) + return 0; + break; + case TYPEFLOAT: + if (--fprCounter < 0) + return 0; + break; + default: + return 0; + } + } + + return 1; +} + +static char *CSOM_AppendString(char *dst, char *src) { + int ch; + while ((ch = *(src++))) + *(dst++) = ch; + return dst; +} + +static ENode *CSOM_SOMGlueCall(TypeClass *tclass, SInt32 offset, Object *object) { + UInt8 funcResultClass; + UInt32 bufsize; + char *buf; + char *ptr; + Object *stubObj; + CSOMStub *stub; + ENode *expr; + char mybuf[256]; + char numberbuf[16]; + + for (stub = csom_stubs; stub; stub = stub->next) { + if (stub->tclass == tclass && stub->offset == offset) + break; + } + + if (!stub) { + funcResultClass = CMach_GetFunctionResultClass(TYPE_FUNC(object->type)); + + bufsize = strlen(tclass->sominfo->classdataobject->name->name) + 32; + buf = (bufsize > sizeof(mybuf)) ? lalloc(bufsize) : mybuf; + + ptr = CSOM_AppendString(buf, "___glue_"); + if (tclass->sominfo->oidl_callstyle == 0) { + if (funcResultClass == 0) { + *(ptr++) = '4'; + } else { + *(ptr++) = '5'; + } + } else { + *(ptr++) = '_'; + } + *(ptr++) = '_'; + + sprintf(numberbuf, "%ld", strlen(tclass->sominfo->classdataobject->name->name)); + ptr = CSOM_AppendString(ptr, numberbuf); + ptr = CSOM_AppendString(ptr, tclass->sominfo->classdataobject->name->name); + *(ptr++) = '_'; + sprintf(numberbuf, "%" PRId32, offset); + ptr = CSOM_AppendString(ptr, numberbuf); + *ptr = 0; + + stubObj = CParser_NewCompilerDefFunctionObject(); + stubObj->nspace = cscope_root; + stubObj->name = GetHashNameNodeExport(buf); + stubObj->u.func.linkname = stubObj->name; + stubObj->type = object->type; + stubObj->qual = object->qual | Q_20000; + stubObj->flags = OBJECT_INTERNAL; + CScope_AddObject(stubObj->nspace, stubObj->name, OBJ_BASE(stubObj)); + + stub = galloc(sizeof(CSOMStub)); + stub->next = csom_stubs; + stub->object = stubObj; + stub->tclass = tclass; + stub->offset = offset; + csom_stubs = stub; + + if (tclass->sominfo->oidl_callstyle == 0) { + if (funcResultClass == 0) + stub->x10 = 0; + else + stub->x10 = 1; + } else { + stub->x10 = 2; + } + } + + expr = create_objectrefnode(stub->object); + expr->rtype = CDecl_NewPointerType(object->type); + return expr; +} + +ENode *CSOM_MemberVarAccess(BClassList *path, ObjMemberVar *ivar, ENode *thisExpr) { + if (!thisExpr) { + if ( + !cscope_currentfunc || + !cscope_currentclass || + !cscope_is_member_func || + !(thisExpr = CClass_CreateThisSelfExpr()) + ) + { + CError_Error(CErrorStr221); + return NULL; + } + } + + CError_ASSERT(2069, ENODE_IS(thisExpr, EINDIRECT)); + + thisExpr = thisExpr->data.monadic; + + if ( + path->next == NULL && + cscope_currentclass == TYPE_CLASS(path->type) && + ENODE_IS(thisExpr, EOBJREF) && + thisExpr->data.objref->name == this_name_node + ) + { + thisExpr = CSOM_SOMSelfObjectExpr(cscope_currentclass); + } + else + { + CClass_CheckPathAccess(path, NULL, ivar->access); + if (ivar->has_path) + path = OBJ_MEMBER_VAR_PATH(ivar)->path; + while (path->next) + path = path->next; + thisExpr = CSOM_ComputeSOMSelf(TYPE_CLASS(path->type), thisExpr); + } + + thisExpr = makemonadicnode(thisExpr, EINDIRECT); + thisExpr->rtype = path->type; + return CClass_AccessMember(thisExpr, ivar->type, ivar->qual, ivar->offset); +} + +ENode *CSOM_MethodAccess(BClassList *path, Object *func, Boolean flag) { + TypeClass *tclass; + TypeClass *tclass2; + TypeClass *tclass3; + ENode *expr; + SInt32 offset; + ClassList *base; + + CError_ASSERT(2107, path != NULL); + + tclass = TYPE_CLASS(path->type); + if (path->next) + path = path->next; + tclass2 = TYPE_CLASS(path->type); + + if (flag) { + SInt32 counter; + ENode *indirectExpr; + Object *resolveFunc; + + counter = 0; + if (tclass != tclass2) { + for (base = tclass->bases; base; base = base->next) { + counter++; + if (base->base == tclass2) + break; + } + + if (!base) + CError_Error(CErrorStr279); + } + + CSOM_FindIntroClassOffset(tclass2, func, &tclass3, &offset); + expr = create_objectrefnode(tclass3->sominfo->classdataobject); + expr = makediadicnode(expr, intconstnode(TYPE(&stsignedlong), offset), EADD); + indirectExpr = makemonadicnode(expr, EINDIRECT); + indirectExpr->rtype = CDecl_NewPointerType(func->type); + + resolveFunc = CSOM_FindRTFunc("somParentNumResolve", "ppip"); + if (!resolveFunc) + return nullnode(); + + expr = funccallexpr( + resolveFunc, + create_objectrefnode(tclass->sominfo->classdataobject), + intconstnode(TYPE(&stsignedint), counter), + indirectExpr, + NULL); + expr->rtype = indirectExpr->rtype; + if (copts.som_env_check && tclass3->sominfo->oidl_callstyle == 0) + expr->flags = expr->flags | ENODE_FLAG_10; + } else { + CSOM_FindIntroClassOffset(tclass2, func, &tclass3, &offset); + if (copts.som_call_optimize && CSOM_CanUseGlueCall(TYPE_FUNC(func->type))) + return CSOM_SOMGlueCall(tclass3, offset, func); + + expr = create_objectrefnode(tclass3->sominfo->classdataobject); + expr = makediadicnode(expr, intconstnode(TYPE(&stsignedlong), offset), EADD); + expr = makemonadicnode(expr, EINDIRECT); + expr->rtype = CDecl_NewPointerType(func->type); + if (copts.som_env_check && tclass3->sominfo->oidl_callstyle == 0) + expr->flags = expr->flags | ENODE_FLAG_10; + } + + return expr; +} diff --git a/compiler_and_linker/FrontEnd/C/CTemplateClass.c b/compiler_and_linker/FrontEnd/C/CTemplateClass.c new file mode 100644 index 0000000..8b3b889 --- /dev/null +++ b/compiler_and_linker/FrontEnd/C/CTemplateClass.c @@ -0,0 +1,1632 @@ +#include "compiler/CTemplateClass.h" +#include "compiler/CABI.h" +#include "compiler/CBrowse.h" +#include "compiler/CClass.h" +#include "compiler/CDecl.h" +#include "compiler/CError.h" +#include "compiler/CInline.h" +#include "compiler/CInt64.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/CTemplateFunc.h" +#include "compiler/CTemplateNew.h" +#include "compiler/CTemplateTools.h" +#include "compiler/CompilerTools.h" +#include "compiler/objects.h" +#include "compiler/scopes.h" +#include "compiler/templates.h" + +TemplClass *CTemplClass_GetMasterTemplate(TemplClass *tmclass) { + if (tmclass->inst_parent) { + tmclass = TEMPL_CLASS(tmclass->theclass.nspace->theclass); + CError_ASSERT(42, tmclass->theclass.flags & CLASS_IS_TEMPL); + } + + return tmclass; +} + +static void CTemplClass_SetupActionErrorRef(TemplateAction *action, TStreamElement **saved) { + CError_ResetErrorSkip(); + CError_LockErrorPos(&action->source_ref, saved); +} + +static void CTemplClass_RestoreActionErrorRef(TStreamElement **saved) { + CError_ResetErrorSkip(); + CError_UnlockErrorPos(saved); +} + +static void CTemplClass_AppendTemplateAction(TemplClass *tmclass, TemplateAction *action) { + TemplateAction *last; + + action->source_ref = *CPrep_CurStreamElement(); + + if ((last = tmclass->actions)) { + while (last->next) + last = last->next; + last->next = action; + } else { + tmclass->actions = action; + } +} + +static DefAction *CTemplClass_NewDefAction(TypeDeduce *deduce, TemplateAction *action) { + DefAction *defAction = lalloc(sizeof(DefAction)); + defAction->next = deduce->defActions; + defAction->action = action; + deduce->defActions = defAction; + return defAction; +} + +static void CTemplClass_InsertTemplateAction(TemplClass *tmclass, TemplateAction *action) { + action->source_ref = *CPrep_CurStreamElement(); + action->next = tmclass->actions; + tmclass->actions = action; +} + +void CTemplClass_RegisterUsingDecl(TemplClass *tmclass, TypeTemplDep *type, AccessType access) { + TemplateAction *action; + + action = galloc(sizeof(TemplateAction)); + memclrw(action, sizeof(TemplateAction)); + + action->type = TAT_USINGDECL; + action->u.usingdecl.type = type; + action->u.usingdecl.access = access; + + CTemplClass_AppendTemplateAction(tmclass, action); +} + +void CTemplClass_RegisterFriend(TemplClass *tmclass, DeclInfo *di) { + TemplateFriend *tfriend; + TemplateAction *action; + + tfriend = galloc(sizeof(TemplateFriend)); + memclrw(tfriend, sizeof(TemplateFriend)); + + if (tk == '{' && IS_TYPE_FUNC(di->thetype)) { + di->qual |= Q_INLINE; + TYPE_FUNC(di->thetype)->flags |= FUNC_DEFINED | FUNC_IS_TEMPL_INSTANCE; + tfriend->fileoffset = cparser_fileoffset; + + CPrep_StreamGetBlock(&tfriend->stream, NULL, 1); + + if (lookahead() == ';') + tk = lex(); + else + tk = ';'; + } + + CDecl_PackDeclInfo(&tfriend->decl, di); + + action = galloc(sizeof(TemplateAction)); + memclrw(action, sizeof(TemplateAction)); + + action->type = TAT_FRIEND; + action->u.tfriend = tfriend; + + CTemplClass_AppendTemplateAction(tmclass, action); +} + +void CTemplClass_RegisterBaseClass(TemplClass *tmclass, Type *type, AccessType access, Boolean is_virtual) { + TemplateAction *action; + ClassList *insert_after; + + if ((insert_after = tmclass->theclass.bases)) { + while (insert_after->next) + insert_after = insert_after->next; + } + + action = galloc(sizeof(TemplateAction)); + memclrw(action, sizeof(TemplateAction)); + + action->type = TAT_BASE; + action->u.base.type = type; + action->u.base.insert_after = insert_after; + action->u.base.access = access; + action->u.base.is_virtual = is_virtual; + + CTemplClass_InsertTemplateAction(tmclass, action); +} + +void CTemplClass_RegisterEnumType(TemplClass *tmclass, TypeEnum *enumtype) { + TemplateAction *action; + + action = galloc(sizeof(TemplateAction)); + memclrw(action, sizeof(TemplateAction)); + + action->type = TAT_ENUMTYPE; + action->u.enumtype = enumtype; + + CTemplClass_AppendTemplateAction(tmclass, action); +} + +void CTemplClass_RegisterEnumerator(TemplClass *tmclass, ObjEnumConst *objenumconst, ENode *initexpr) { + TemplateAction *action; + + action = galloc(sizeof(TemplateAction)); + memclrw(action, sizeof(TemplateAction)); + + action->type = TAT_ENUMERATOR; + action->u.enumerator.objenumconst = objenumconst; + action->u.enumerator.initexpr = initexpr ? CInline_CopyExpression(initexpr, CopyMode1) : NULL; + + CTemplClass_AppendTemplateAction(tmclass, action); +} + +void CTemplClass_RegisterObjectInit(TemplClass *tmclass, Object *object, ENode *initexpr) { + TemplateAction *action; + + action = galloc(sizeof(TemplateAction)); + memclrw(action, sizeof(TemplateAction)); + + action->type = TAT_OBJECTINIT; + action->u.objectinit.object = object; + action->u.objectinit.initexpr = CInline_CopyExpression(initexpr, CopyMode1); + + CTemplClass_AppendTemplateAction(tmclass, action); +} + +void CTemplClass_RegisterObjectDef(TemplClass *tmclass, ObjBase *refobj) { + TemplateAction *action; + + action = galloc(sizeof(TemplateAction)); + memclrw(action, sizeof(TemplateAction)); + + action->type = TAT_OBJECTDEF; + action->u.refobj = refobj; + + CTemplClass_AppendTemplateAction(tmclass, action); +} + +void CTemplClass_CompleteClass(TemplClass *templ, ClassLayout *de) { + templ->lex_order_count = de->lex_order_count; + if (de->has_vtable) + templ->flags |= TEMPLCLASS_HAS_VTABLE; + templ->theclass.flags |= CLASS_COMPLETED; +} + +static TemplClassInst *CTemplClass_NewInstance(TemplClass *templ, TemplArg *inst_args, TemplArg *oargs) { + TemplClassInst *inst; + ObjTypeTag *tag; + NameSpace *nspace; + HashNameNode *name; + + CError_ASSERT(288, !templ->pspec_owner); + + inst = galloc(sizeof(TemplClassInst)); + memclrw(inst, sizeof(TemplClassInst)); + + inst->next = templ->instances; + templ->instances = inst; + + if (templ->templ__params) + name = CMangler_TemplateInstanceName(templ->theclass.classname, oargs ? oargs : inst_args); + else + name = templ->theclass.classname; + + inst->inst_args = inst_args; + inst->oargs = oargs; + inst->parent = templ->inst_parent; + + nspace = CScope_NewListNameSpace(name, 1); + nspace->theclass = TYPE_CLASS(inst); + if (templ->templ_parent && templ->inst_parent) { + nspace->parent = TYPE_CLASS(templ->inst_parent)->nspace; + } else { + NameSpace *scan = templ->theclass.nspace->parent; + while (scan->is_templ) + scan = scan->parent; + nspace->parent = scan; + } + + inst->theclass.type = TYPECLASS; + inst->theclass.flags = CLASS_IS_TEMPL_INST; + inst->theclass.nspace = nspace; + inst->theclass.classname = templ->theclass.classname; + inst->theclass.mode = templ->theclass.mode; + inst->theclass.eflags = templ->theclass.eflags; + inst->templ = templ; + + tag = galloc(sizeof(ObjTypeTag)); + memclrw(tag, sizeof(ObjTypeTag)); + + tag->otype = OT_TYPETAG; + tag->access = ACCESSPUBLIC; + tag->type = TYPE(inst); + CScope_AddObject(nspace, templ->theclass.classname, OBJ_BASE(tag)); + + return inst; +} + +TemplClassInst *CTemplClass_GetInstance(TemplClass *tmclass, TemplArg *inst_args, TemplArg *oargs) { + TemplClassInst *inst; + + for (inst = tmclass->instances; inst; inst = inst->next) { + CError_ASSERT(353, !oargs); + + if (CTemplTool_EqualArgs(inst_args, inst->oargs ? inst->oargs : inst->inst_args)) + return inst; + } + + return CTemplClass_NewInstance(tmclass, inst_args, oargs); +} + +TemplateMember *CTemplClass_DefineMember(TemplClass *tmclass, Object *object, FileOffsetInfo *foi, TokenStream *stream) { + TemplateMember *member; + + for (member = tmclass->members; member; member = member->next) { + if (member->object == object) { + CError_Error(CErrorStr333, object); + return member; + } + } + + member = galloc(sizeof(TemplateMember)); + memclrw(member, sizeof(TemplateMember)); + member->next = tmclass->members; + tmclass->members = member; + + member->params = NULL; + member->object = object; + member->fileoffset = *foi; + member->stream = *stream; + + return member; +} + +static void CTemplClass_ParseBody(TemplClass *templ, short mode, SInt32 *offset) { + DeclInfo di; + + templ->align = copts.structalignment; + + memclrw(&di, sizeof(di)); + di.file = CPrep_BrowserCurrentFile(); + CPrep_BrowserFilePosition(&di.file2, &di.sourceoffset); + di.sourceoffset = *offset; + di.x28 = templ; + + CDecl_ParseClass(&di, mode, 1, 0); + + if (tk == TK_UU_ATTRIBUTE_UU) + CParser_ParseAttribute(di.thetype, NULL); + if (tk != ';') + CError_Error(CErrorStr123); + + CBrowse_NewTemplateClass(templ, di.file2, di.sourceoffset, CPrep_BrowserFileOffset() + 1); +} + +void CTemplClass_ParsePartialSpecialization(DeclFucker *what_is_this, TemplParam *params, short mode, SInt32 *offset) { + Type *type; + NameSpace *nspace; + TemplArg *args; + TemplPartialSpec *pspec; + TemplClass *templ; + TemplArg *arg; + TemplParam *param; + + nspace = what_is_this->nspace; + + if ((tk = lex()) != TK_IDENTIFIER) { + CError_Error(CErrorStr107); + return; + } + + if (!(type = CScope_GetLocalTagType(nspace, tkidentifier))) { + CError_Error(CErrorStr140, tkidentifier->name); + return; + } + + if (!IS_TEMPL_CLASS(type)) { + CError_Error(CErrorStr132, tkidentifier->name); + return; + } + + if ((tk = lex()) != '<') + CError_FATAL(469); + + for (param = params; param; param = param->next) { + switch (param->pid.type) { + case TPT_TYPE: + if (!param->data.typeparam.type) + continue; + CError_Error(CErrorStr344); + break; + + case TPT_NONTYPE: + if (!param->data.paramdecl.defaultarg) + continue; + CError_Error(CErrorStr344); + break; + + case TPT_TEMPLATE: + if (!param->data.templparam.defaultarg) + continue; + CError_Error(CErrorStr344); + break; + + default: + CError_FATAL(501); + } + + break; + } + + args = CTempl_ParseUncheckTemplArgs(TEMPL_CLASS(type)->templ__params, 0); + tk = lex(); + + arg = args; + param = TEMPL_CLASS(type)->templ__params; + while (1) { + if (!arg) { + if (!param) + break; + CError_Error(CErrorStr344); + return; + } + if (!param) { + CError_Error(CErrorStr344); + return; + } + if (param->pid.type != arg->pid.type) { + CError_Error(CErrorStr344); + return; + } + arg = arg->next; + param = param->next; + } + + if (CTemplTool_IsSameTemplate(TEMPL_CLASS(type)->templ__params, args)) + CError_Error(CErrorStr344); + + for (pspec = TEMPL_CLASS(type)->pspecs; pspec; pspec = pspec->next) { + if (CTemplTool_EqualParams(pspec->templ->templ__params, params, 0) && CTemplTool_EqualArgs(pspec->args, args)) + break; + } + + if (!pspec) { + templ = galloc(sizeof(TemplClass)); + memclrw(templ, sizeof(TemplClass)); + + templ->templ__params = params; + CDecl_DefineClass(nspace, TEMPL_CLASS(type)->theclass.classname, TYPE_CLASS(templ), mode, 0, 0); + + templ->theclass.flags = CLASS_IS_TEMPL; + templ->pspec_owner = TEMPL_CLASS(type); + + pspec = galloc(sizeof(TemplPartialSpec)); + memclrw(pspec, sizeof(TemplPartialSpec)); + + pspec->templ = templ; + pspec->args = CTemplTool_MakeGlobalTemplArgCopy(args); + pspec->next = TEMPL_CLASS(type)->pspecs; + TEMPL_CLASS(type)->pspecs = pspec; + } else { + if ((pspec->templ->theclass.flags & CLASS_COMPLETED) && tk != ';') { + CError_Error(CErrorStr132, TEMPL_CLASS(type)->theclass.classname->name); + return; + } + + if (tk == ':' || tk == '{') + CTemplTool_EqualParams(pspec->templ->templ__params, params, 1); + } + + switch (tk) { + case ':': + case '{': + CTemplClass_ParseBody(pspec->templ, mode, offset); + break; + case ';': + break; + default: + CError_Error(CErrorStr121); + } +} + +void CTemplClass_ParseClass(DeclFucker *what_is_this, TemplParam *params, short mode, SInt32 *offset) { + TemplClass *templ; + NameSpace *nspace; + Type *type; + UInt8 classDeclSpec = 0; + + nspace = what_is_this->nspace; + if ((tk = lex()) == TK_UU_DECLSPEC) + CDecl_ParseClassDeclSpec(&classDeclSpec); + + if (tk != TK_IDENTIFIER) { + CError_Error(CErrorStr107); + return; + } + + type = CScope_GetLocalTagType(nspace, tkidentifier); + if (!type) { + templ = galloc(sizeof(TemplClass)); + memclrw(templ, sizeof(TemplClass)); + + templ->next = ctempl_templates; + ctempl_templates = templ; + + templ->templ__params = params; + CDecl_DefineClass(nspace, tkidentifier, TYPE_CLASS(templ), mode, 0, 1); + templ->theclass.flags = CLASS_IS_TEMPL; + templ->theclass.eflags = classDeclSpec; + + tk = lex(); + if (nspace->theclass && (nspace->theclass->flags & CLASS_IS_TEMPL)) { + TemplateAction *action; + + templ->templ_parent = TEMPL_CLASS(nspace->theclass); + + action = galloc(sizeof(TemplateAction)); + memclrw(action, sizeof(TemplateAction)); + + action->type = TAT_NESTEDCLASS; + action->u.tclasstype = templ; + CTemplClass_AppendTemplateAction(templ->templ_parent, action); + } + } else { + if (!IS_TEMPL_CLASS(type)) { + CError_Error(CErrorStr132, tkidentifier->name); + return; + } + + templ = TEMPL_CLASS(type); + if (!CTemplTool_EqualParams(templ->templ__params, params, 0)) { + CError_Error(CErrorStr132, templ->theclass.classname->name); + return; + } + + CTemplTool_MergeDefaultArgs(templ->templ__params, params); + templ->theclass.eflags |= classDeclSpec; + + tk = lex(); + + if ((templ->theclass.flags & CLASS_COMPLETED) && tk != ';') { + CError_Error(CErrorStr132, templ->theclass.classname->name); + return; + } + + if (tk != ';') + CTemplTool_EqualParams(templ->templ__params, params, 1); + } + + switch (tk) { + case ':': + case '{': + CTemplClass_ParseBody(templ, mode, offset); + break; + case ';': + break; + default: + CError_Error(CErrorStr121); + } +} + +static Boolean CTemplClass_TypeParamCompare(TemplArg *arg, Type *type, UInt32 qual) { + return is_typesame(type, arg->data.typeparam.type) && arg->data.typeparam.qual == qual; +} + +static TemplArg *CTemplClass_PartialTemplateArgMatch(TemplPartialSpec *pspec, TemplArg *args, Boolean flag) { + TemplArg *argA; + TemplArg *argB; + int i; + DeduceInfo info; + + if (!CTemplTool_InitDeduceInfo(&info, pspec->templ->templ__params, NULL, 1)) + return NULL; + + argA = pspec->args; + argB = args; + while (1) { + if (!argA) { + if (argB) + return NULL; + + for (i = 0; i < info.maxCount; i++) { + if (!info.args[i].is_deduced) + return NULL; + } + + if (flag) + return CTemplTool_MakeTemplArgList(&info); + else + return args; + } + + if (!argB) + return NULL; + + if (argA->pid.type != argB->pid.type) + return NULL; + + switch (argA->pid.type) { + case TPT_TYPE: + if (CTemplTool_IsTemplateArgumentDependentType(argA->data.typeparam.type)) { + if (!CTempl_DeduceType( + argA->data.typeparam.type, argA->data.typeparam.qual, + argB->data.typeparam.type, argB->data.typeparam.qual, + info.args, 0, 0 + )) + return NULL; + } else { + if ( + !is_typesame(argA->data.typeparam.type, argB->data.typeparam.type) || + argA->data.typeparam.qual != argB->data.typeparam.qual + ) + return NULL; + } + break; + + case TPT_NONTYPE: + if (CTemplTool_IsTemplateArgumentDependentExpression(argA->data.paramdecl.expr)) { + i = CTempl_GetTemplateArgumentExpressionIndex(argA); + CError_ASSERT(789, i >= 0); + + if (info.args[i].is_deduced) { + if (!CTemplTool_EqualExprTypes(argB->data.paramdecl.expr, info.args[i].data.paramdecl.expr)) + return NULL; + } else { + info.args[i].data.paramdecl.expr = argB->data.paramdecl.expr; + info.args[i].pid.type = TPT_NONTYPE; + info.args[i].is_deduced = 1; + } + } else { + if (!CTemplTool_EqualExprTypes(argB->data.paramdecl.expr, argA->data.paramdecl.expr)) + return NULL; + } + break; + + case TPT_TEMPLATE: + if (CTemplTool_IsTemplateArgumentDependentType(argA->data.ttargtype)) { + if (!CTempl_DeduceType( + argA->data.ttargtype, 0, + argB->data.ttargtype, 0, + info.args, 0, 0 + )) + return NULL; + } else { + if (!is_typesame(argA->data.ttargtype, argB->data.ttargtype)) + return NULL; + } + break; + + default: + CError_FATAL(830); + } + + argA = argA->next; + argB = argB->next; + } +} + +static Boolean CTemplClass_PartialClassIsAtLeastAsSpecialized(TemplPartialSpec *pspec1, TemplPartialSpec *pspec2) { + TemplArg *argA; + TemplArg *argB; + int i; + DeduceInfo info; + + if (!CTemplTool_InitDeduceInfo(&info, pspec2->templ->templ__params, NULL, 1)) + return 0; + + argA = pspec1->args; + argB = pspec2->args; + + while (1) { + if (!argA) { + CError_ASSERT(856, !argB); + + for (i = 0; i < info.maxCount; i++) { + if (!info.args[i].is_deduced) + return 0; + } + + return 1; + } + + CError_ASSERT(865, argB); + CError_ASSERT(866, argA->pid.type == argB->pid.type); + + switch (argA->pid.type) { + case TPT_TYPE: + if (!CTempl_DeduceType( + argB->data.typeparam.type, argB->data.typeparam.qual, + argA->data.typeparam.type, argA->data.typeparam.qual, + info.args, 0, 0 + )) + return 0; + break; + + case TPT_NONTYPE: + if (CTemplTool_IsTemplateArgumentDependentExpression(argB->data.paramdecl.expr)) { + i = CTempl_GetTemplateArgumentExpressionIndex(argB); + CError_ASSERT(907, i >= 0); + + if (info.args[i].is_deduced) { + if (argA->data.paramdecl.expr) { + if (!info.args[i].data.paramdecl.expr || !CTemplTool_EqualExprTypes(argA->data.paramdecl.expr, info.args[i].data.paramdecl.expr)) + return 0; + } else { + if (info.args[i].data.paramdecl.expr || argA->pid.index != info.args[i].pid.index) + return 0; + } + } else { + info.args[i].data.paramdecl.expr = argA->data.paramdecl.expr; + info.args[i].pid.index = argA->pid.index; + info.args[i].pid.type = TPT_NONTYPE; + info.args[i].is_deduced = 1; + } + } else { + if ( + !argA->data.paramdecl.expr || + !CTemplTool_EqualExprTypes(argA->data.paramdecl.expr, argB->data.paramdecl.expr) + ) + return 0; + } + break; + + case TPT_TEMPLATE: + if (!CTempl_DeduceType( + argB->data.ttargtype, 0, + argA->data.ttargtype, 0, + info.args, 0, 0 + )) + return 0; + break; + + default: + CError_FATAL(955); + } + + argA = argA->next; + argB = argB->next; + } +} + +static Boolean CTemplClass_PartialClassIsMoreSpecialized(TemplPartialSpec *pspec1, TemplPartialSpec *pspec2) { + return CTemplClass_PartialClassIsAtLeastAsSpecialized(pspec1, pspec2) && + !CTemplClass_PartialClassIsAtLeastAsSpecialized(pspec2, pspec1); +} + +typedef struct PSpecList { + struct PSpecList *next; + TemplPartialSpec *pspec; +} PSpecList; + +static PSpecList *CTemplClass_FindMostSpecializedPartialSpecializations(PSpecList *list) { + PSpecList **array; + PSpecList *scan; + int i; + int j; + int count; + + scan = list; + count = 0; + while (scan) { + scan = scan->next; + count++; + } + + array = lalloc(sizeof(PSpecList *) * count); + for (i = 0, scan = list; scan; scan = scan->next) + array[i++] = scan; + + for (i = 0; i < count; i++) { + if (array[i]) { + for (j = 0; j < count; j++) { + if (array[j] && i != j && CTemplClass_PartialClassIsMoreSpecialized(array[i]->pspec, array[j]->pspec)) + array[j] = NULL; + } + } + } + + for (i = 0, list = NULL; i < count; i++) { + if (array[i]) { + if (!list) + list = array[i]; + else + array[j]->next = array[i]; + array[i]->next = NULL; + j = i; + } + } + + return list; +} + +Boolean CTemplClass_FindPartialTemplate(TemplArg *args, TemplClass **resultTempl, TemplArg **resultArgs) { + TemplPartialSpec *pspec; + PSpecList *list; + TemplClassInst *inst; + + for (inst = (*resultTempl)->instances; inst; inst = inst->next) { + if (inst->is_instantiated || inst->is_specialized) { + if (CTemplTool_EqualArgs(args, inst->oargs ? inst->oargs : inst->inst_args)) + return 0; + } + } + + list = NULL; + for (pspec = (*resultTempl)->pspecs; pspec; pspec = pspec->next) { + if (CTemplClass_PartialTemplateArgMatch(pspec, args, 0)) { + PSpecList *entry = lalloc(sizeof(PSpecList)); + entry->next = list; + entry->pspec = pspec; + list = entry; + } + } + + if (list) { + if (list->next) { + list = CTemplClass_FindMostSpecializedPartialSpecializations(list); + if (list->next) + CError_Error(CErrorStr346); + } + + if (!list->pspec->templ->templ__params) { + *resultTempl = list->pspec->templ; + *resultArgs = NULL; + return 1; + } + + *resultTempl = list->pspec->templ; + *resultArgs = CTemplClass_PartialTemplateArgMatch(list->pspec, args, 1); + return *resultArgs != NULL; + } else { + return 0; + } +} + +TemplClass *CTemplClass_DefineNestedClass(TemplClass *parent, HashNameNode *name, short mode) { + TemplateAction *action; + TemplClass *templ; + + templ = galloc(sizeof(TemplClass)); + memclrw(templ, sizeof(TemplClass)); + + templ->next = ctempl_templates; + ctempl_templates = templ; + + templ->templ_parent = parent; + templ->templ__params = NULL; + CDecl_DefineClass(parent->theclass.nspace, name, TYPE_CLASS(templ), mode, 0, 1); + + templ->theclass.flags = CLASS_IS_TEMPL; + templ->align = copts.structalignment; + + action = galloc(sizeof(TemplateAction)); + memclrw(action, sizeof(TemplateAction)); + + action->type = TAT_NESTEDCLASS; + action->u.tclasstype = templ; + CTemplClass_AppendTemplateAction(parent, action); + + return templ; +} + +static void CTemplClass_CopyNestedClass(TypeDeduce *deduce, TemplClass *templ) { + ObjTypeTag *tag; + + tag = galloc(sizeof(ObjTypeTag)); + memclrw(tag, sizeof(ObjTypeTag)); + + tag->otype = OT_TYPETAG; + tag->access = ACCESSPUBLIC; + + if (!templ->templ__params) { + TemplClassInst *inst = CTemplClass_NewInstance(templ, NULL, NULL); + inst->parent = deduce->inst; + inst->theclass.nspace->parent = deduce->inst->theclass.nspace; + + tag->type = TYPE(inst); + } else { + TemplClass *copy = galloc(sizeof(TemplClass)); + memclrw(copy, sizeof(TemplClass)); + + copy->next = ctempl_templates; + ctempl_templates = copy; + + copy->theclass = templ->theclass; + copy->templ_parent = deduce->tmclass; + copy->inst_parent = deduce->inst; + copy->templ__params = templ->templ__params; + copy->members = NULL; + copy->instances = NULL; + copy->pspecs = NULL; + copy->actions = templ->actions; + copy->lex_order_count = templ->lex_order_count; + copy->align = templ->align; + copy->flags = templ->flags; + + tag->type = TYPE(copy); + } + + CScope_AddObject(deduce->inst->theclass.nspace, templ->theclass.classname, OBJ_BASE(tag)); +} + +static void CTemplClass_CopyBaseClasses(TypeDeduce *deduce, TemplClassInst *inst, TemplClass *templ) { + TemplateAction *action; + ClassList *newBase; + ClassList *templbase; + ClassList *instbase; + ClassList *base; + UInt32 qual = 0; + + for (base = templ->theclass.bases; base; base = base->next) { + ClassList *scan; + newBase = galloc(sizeof(ClassList)); + *newBase = *base; + newBase->next = NULL; + + if ((scan = inst->theclass.bases)) { + while (1) { + if (scan->base == newBase->base) { + CError_Error(CErrorStr131); + break; + } + if (!scan->next) { + scan->next = newBase; + break; + } + scan = scan->next; + } + } else { + inst->theclass.bases = newBase; + } + } + + for (action = deduce->tmclass->actions; action; action = action->next) { + if (action->type == TAT_BASE) { + TStreamElement *save; + + CTemplClass_SetupActionErrorRef(action, &save); + + newBase = galloc(sizeof(ClassList)); + memclrw(newBase, sizeof(ClassList)); + + newBase->base = TYPE_CLASS(CTemplTool_DeduceTypeCopy(deduce, action->u.base.type, &qual)); + newBase->access = action->u.base.access; + newBase->is_virtual = action->u.base.is_virtual; + + if (IS_TYPE_CLASS(newBase->base)) { + if (newBase->base->size == 0) { + CDecl_CompleteType(TYPE(newBase->base)); + IsCompleteType(TYPE(newBase->base)); + } + + if (CDecl_CheckNewBase(TYPE_CLASS(inst), newBase->base, newBase->is_virtual)) { + if (action->u.base.insert_after) { + templbase = templ->theclass.bases; + instbase = inst->theclass.bases; + while (1) { + CError_ASSERT(1222, templbase && instbase); + + if (templbase == action->u.base.insert_after) { + newBase->next = instbase->next; + instbase->next = newBase; + break; + } + + templbase = templbase->next; + instbase = instbase->next; + } + } else { + newBase->next = inst->theclass.bases; + inst->theclass.bases = newBase; + } + } + } else { + CError_Error(CErrorStr131); + } + + CTemplClass_RestoreActionErrorRef(&save); + } + } + + if (inst->theclass.flags & CLASS_HAS_VBASES) + CDecl_MakeVBaseList(TYPE_CLASS(inst)); +} + +static void CTemplClass_CopyEnum(TypeDeduce *deduce, TemplateAction *action) { + TypeEnum *destenum; + TypeEnum *srcenum; + ObjEnumConst **destptr; + ObjEnumConst *src; + TemplateAction *scanaction; + + srcenum = action->u.enumtype; + destenum = galloc(sizeof(TypeEnum)); + memclrw(destenum, sizeof(TypeEnum)); + + destenum->type = TYPEENUM; + destenum->size = srcenum->size; + destenum->nspace = deduce->inst->theclass.nspace; + destenum->enumtype = srcenum->enumtype; + destenum->enumname = srcenum->enumname; + + if (destenum->enumname) + CScope_DefineTypeTag(destenum->nspace, destenum->enumname, TYPE(destenum)); + + src = srcenum->enumlist; + destptr = &destenum->enumlist; + while (src) { + ObjEnumConst *dest; + + dest = galloc(sizeof(ObjEnumConst)); + *dest = *src; + + *destptr = dest; + dest->next = NULL; + dest->type = TYPE(destenum); + CScope_AddObject(deduce->inst->theclass.nspace, dest->name, OBJ_BASE(dest)); + + src = src->next; + destptr = &(*destptr)->next; + } + + for (scanaction = deduce->tmclass->actions; scanaction; scanaction = scanaction->next) { + if (scanaction->type == TAT_ENUMERATOR && scanaction->u.enumerator.objenumconst->type == TYPE(srcenum)) { + CTemplClass_NewDefAction(deduce, action)->enumtype = destenum; + return; + } + } +} + +static void CTemplClass_CompleteEnumType(TypeDeduce *deduce, TemplateAction *action, TypeEnum *destenum) { + TypeEnum *srcenum; + ObjEnumConst *dest; + TemplateAction *scanaction; + ENode *expr; + ObjEnumConst *src; + + srcenum = action->u.enumtype; + + for (scanaction = deduce->tmclass->actions; scanaction; scanaction = scanaction->next) { + if (scanaction->type == TAT_ENUMERATOR) { + src = scanaction->u.enumerator.objenumconst; + if (src->type == TYPE(srcenum)) { + TStreamElement *save; + + CTemplClass_SetupActionErrorRef(scanaction, &save); + + dest = destenum->enumlist; + while (dest) { + if (dest->name == src->name) + break; + dest = dest->next; + } + + CError_ASSERT(1332, dest); + + if (scanaction->u.enumerator.initexpr) { + expr = CTemplTool_DeduceExpr(deduce, scanaction->u.enumerator.initexpr); + if (!ENODE_IS(expr, EINTCONST)) { + CError_Error(CErrorStr124); + CTemplClass_RestoreActionErrorRef(&save); + break; + } + } else { + CError_ASSERT(1347, expr); + expr->data.intval = CInt64_Add(expr->data.intval, cint64_one); + } + + dest->val = expr->data.intval; + dest->type = expr->rtype; + CTemplClass_RestoreActionErrorRef(&save); + } + } + } + + CDecl_ComputeUnderlyingEnumType(destenum); +} + +static void CTemplClass_CopyObjMemberVarPath(TypeDeduce *deduce, ObjMemberVarPath *ivar) { + ObjMemberVarPath *copy; + + copy = galloc(sizeof(ObjMemberVarPath)); + *copy = *ivar; + + if (copy->path && copy->path->type == TYPE(deduce->tmclass)) { + copy->path = CClass_GetPathCopy(copy->path, 1); + copy->path->type = TYPE(deduce->inst); + } + + CScope_AddObject(deduce->inst->theclass.nspace, copy->name, OBJ_BASE(copy)); +} + +static void CTemplClass_CopyIVars(TypeDeduce *deduce, TemplClassInst *inst, TemplClass *templ) { + ObjMemberVar *src; + ObjMemberVar *dest; + ObjMemberVar **destptr; + TemplateAction *scanaction; + + src = templ->theclass.ivars; + destptr = &inst->theclass.ivars; + + while (src) { + CError_ASSERT(1397, !src->has_path); + + dest = galloc(sizeof(ObjMemberVar)); + *dest = *src; + + for (scanaction = deduce->tmclass->actions; scanaction; scanaction = scanaction->next) { + if (scanaction->type == TAT_OBJECTDEF && scanaction->u.refobj == OBJ_BASE(src)) { + CTemplClass_NewDefAction(deduce, scanaction)->refobj = OBJ_BASE(dest); + break; + } + } + + if (!scanaction) { + dest->type = CTemplTool_DeduceTypeCopy(deduce, dest->type, &dest->qual); + if (dest->type->size == 0) { + CDecl_CompleteType(dest->type); + IsCompleteType(dest->type); + } + } + + if (dest->name && dest->name != no_name_node) + CScope_AddObject(inst->theclass.nspace, dest->name, OBJ_BASE(dest)); + + *destptr = dest; + destptr = &dest->next; + src = src->next; + } +} + +static void CTemplClass_CopyObjType(TypeDeduce *deduce, ObjType *src, HashNameNode *name) { + TemplateAction *scanaction; + NameSpaceObjectList *list; + NameSpaceObjectList *newlist; + ObjType *dest; + + for (scanaction = deduce->tmclass->actions; scanaction; scanaction = scanaction->next) { + if (scanaction->type == TAT_OBJECTDEF && scanaction->u.refobj == OBJ_BASE(src)) + break; + } + + dest = galloc(sizeof(ObjType)); + *dest = *src; + + if (scanaction) + CTemplClass_NewDefAction(deduce, scanaction)->refobj = OBJ_BASE(dest); + else + dest->type = CTemplTool_DeduceTypeCopy(deduce, dest->type, &dest->qual); + + if ((list = CScope_FindName(deduce->inst->theclass.nspace, name)) && list->object->otype == OT_TYPETAG) { + CError_ASSERT(1470, list->next == NULL); + + newlist = galloc(sizeof(NameSpaceObjectList)); + newlist->object = list->object; + newlist->next = NULL; + + list->object = OBJ_BASE(dest); + list->next = newlist; + } else { + CScope_AddObject(deduce->inst->theclass.nspace, name, OBJ_BASE(dest)); + } +} + +static void CTemplClass_CopyObjTypeTag(TypeDeduce *deduce, ObjTypeTag *src, HashNameNode *name) { + UInt32 qual = 0; + ObjTypeTag *dest = galloc(sizeof(ObjTypeTag)); + + *dest = *src; + dest->type = CTemplTool_DeduceTypeCopy(deduce, dest->type, &qual); + + CScope_AddObject(deduce->inst->theclass.nspace, name, OBJ_BASE(dest)); +} + +static void CTemplClass_CopyMemberTemplate(TypeDeduce *deduce, Object *src) { + TemplateFunction *desttempl; + Object *dest; + TemplateFunction *srctempl; + TemplateAction *action; + + srctempl = src->u.func.u.templ; + CError_ASSERT(1516, srctempl && srctempl->params); + + for (action = deduce->tmclass->actions; action; action = action->next) { + if (action->type == TAT_OBJECTDEF && action->u.refobj == OBJ_BASE(src)) + break; + } + + desttempl = galloc(sizeof(TemplateFunction)); + *desttempl = *srctempl; + + desttempl->next = ctempl_templatefuncs; + ctempl_templatefuncs = desttempl; + + desttempl->unk4 = srctempl; + + dest = galloc(sizeof(Object)); + *dest = *src; + + dest->u.func.u.templ = desttempl; + dest->nspace = deduce->inst->theclass.nspace; + + CError_ASSERT(1541, !deduce->x15); + deduce->x15 = 1; + deduce->nindex = srctempl->params->pid.nindex; + + if (action) + CTemplClass_NewDefAction(deduce, action)->refobj = OBJ_BASE(dest); + else + dest->type = CTemplTool_DeduceTypeCopy(deduce, dest->type, &dest->qual); + + deduce->x15 = 0; + + CError_ASSERT(1553, IS_TYPE_FUNC(dest->type)); + + TYPE_FUNC(dest->type)->flags |= FUNC_IS_TEMPL; + + if ( + (TYPE_FUNC(dest->type)->flags & FUNC_IS_CTOR) && + deduce->x17 && + !action + ) + { + FuncArg *arg; + CError_ASSERT(1560, TYPE_FUNC(dest->type)->args); + arg = CParser_NewFuncArg(); + arg->type = TYPE(&stsignedshort); + arg->next = TYPE_FUNC(dest->type)->args->next; + TYPE_FUNC(dest->type)->args->next = arg; + } + + CScope_AddObject(deduce->inst->theclass.nspace, dest->name, OBJ_BASE(dest)); +} + +static void CTemplClass_CopyObject(TypeDeduce *deduce, Object *src) { + ObjectTemplated *dest; + TemplateAction *action; + TemplateAction *action2; + Boolean flag; + + flag = 1; + if (src->nspace != deduce->tmclass->theclass.nspace) { + CError_ASSERT(1587, src->datatype == DALIAS); + flag = 0; + } + + if (IS_TEMPL_FUNC(src->type)) { + CTemplClass_CopyMemberTemplate(deduce, src); + return; + } + + for (action = deduce->tmclass->actions; action; action = action->next) { + if (action->type == TAT_OBJECTDEF && action->u.refobj == OBJ_BASE(src)) + break; + } + + dest = galloc(sizeof(ObjectTemplated)); + dest->object = *src; + + if (action) + CTemplClass_NewDefAction(deduce, action)->refobj = OBJ_BASE(dest); + else + dest->object.type = CTemplTool_DeduceTypeCopy(deduce, dest->object.type, &dest->object.qual); + + if (flag) + dest->object.nspace = deduce->inst->theclass.nspace; + + dest->object.qual |= Q_IS_TEMPLATED; + dest->parent = src; + + if (IS_TYPE_FUNC(dest->object.type)) + TYPE_FUNC(dest->object.type)->flags &= ~FUNC_DEFINED; + + switch (dest->object.datatype) { + case DDATA: + dest->object.u.data.linkname = NULL; + for (action2 = deduce->tmclass->actions; action2; action2 = action2->next) { + if (action2->type == TAT_OBJECTINIT && action2->u.objectinit.object == src) { + CTemplClass_NewDefAction(deduce, action2)->refobj = OBJ_BASE(dest); + break; + } + } + break; + + case DABSOLUTE: + break; + + case DFUNC: + case DVFUNC: + dest->object.u.func.linkname = NULL; + CError_ASSERT(1650, IS_TYPE_FUNC(dest->object.type)); + CError_ASSERT(1651, !dest->object.u.func.u.templ && !dest->object.u.func.defargdata); + + if ( + (TYPE_FUNC(dest->object.type)->flags & FUNC_IS_CTOR) && + deduce->x17 && + !action + ) + { + FuncArg *arg; + CError_ASSERT(1657, TYPE_FUNC(dest->object.type)->args); + arg = CParser_NewFuncArg(); + arg->type = TYPE(&stsignedshort); + arg->next = TYPE_FUNC(dest->object.type)->args->next; + TYPE_FUNC(dest->object.type)->args->next = arg; + } + + if (TYPE_FUNC(dest->object.type)->flags & FUNC_CONVERSION) { + CError_ASSERT(1665, IS_TYPE_FUNC(src->type)); + if (CTemplTool_IsTemplateArgumentDependentType(TYPE_FUNC(src->type)->functype)) { + CError_ASSERT(1668, action); + return; + } + } + + break; + + case DINLINEFUNC: + break; + + case DALIAS: + if (dest->object.u.alias.member && dest->object.u.alias.member->type == TYPE(deduce->tmclass)) { + dest->object.u.alias.member = CClass_GetPathCopy(dest->object.u.alias.member, 1); + dest->object.u.alias.member->type = TYPE(deduce->inst); + } + break; + + case DLOCAL: + case DEXPR: + CError_FATAL(1688); + + default: + CError_FATAL(1691); + } + + CScope_AddObject(deduce->inst->theclass.nspace, dest->object.name, OBJ_BASE(dest)); +} + +static void CTemplClass_CompleteObject(TypeDeduce *deduce, TemplateAction *action, ObjBase *refobj) { + if (refobj->otype == OT_MEMBERVAR) { + ObjMemberVar *ivar = OBJ_MEMBER_VAR(refobj); + ivar->type = CTemplTool_DeduceTypeCopy(deduce, ivar->type, &ivar->qual); + + if (ivar->type->size == 0) { + CDecl_CompleteType(ivar->type); + if (copts.experimental) { + if (ivar->next || ivar->type->size != 0 || !IS_TYPE_ARRAY(ivar->type)) + IsCompleteType(ivar->type); + } else { + IsCompleteType(ivar->type); + } + } + } else if (refobj->otype == OT_TYPE) { + ObjType *obj = OBJ_TYPE(refobj); + obj->type = CTemplTool_DeduceTypeCopy(deduce, obj->type, &obj->qual); + } else { + Object *dest; + Object *src; + + CError_ASSERT(1737, refobj->otype == OT_OBJECT); + + dest = OBJECT(refobj); + src = OBJECT(action->u.refobj); + + if (IS_TEMPL_FUNC(src->type)) { + TemplateFunction *templ = src->u.func.u.templ; + CError_ASSERT(1747, templ); + CError_ASSERT(1748, !deduce->x15); + + deduce->x15 = 1; + deduce->nindex = templ->params->pid.nindex; + dest->type = CTemplTool_DeduceTypeCopy(deduce, dest->type, &dest->qual); + deduce->x15 = 0; + + CError_ASSERT(1753, IS_TYPE_FUNC(dest->type)); + TYPE_FUNC(dest->type)->flags |= FUNC_IS_TEMPL; + } else { + dest->type = CTemplTool_DeduceTypeCopy(deduce, dest->type, &dest->qual); + dest->qual |= Q_IS_TEMPLATED; + + if (IS_TYPE_FUNC(dest->type)) + TYPE_FUNC(dest->type)->flags &= ~FUNC_DEFINED; + + switch (dest->datatype) { + case DFUNC: + case DVFUNC: + CError_ASSERT(1769, IS_TYPE_FUNC(dest->type)); + if (TYPE_FUNC(dest->type)->flags & FUNC_CONVERSION) { + CError_ASSERT(1772, IS_TYPE_FUNC(dest->type)); + if (CTemplTool_IsTemplateArgumentDependentType(TYPE_FUNC(src->type)->functype)) { + dest->name = CMangler_ConversionFuncName( + TYPE_FUNC(dest->type)->functype, TYPE_FUNC(dest->type)->qual); + CScope_AddObject(deduce->inst->theclass.nspace, dest->name, OBJ_BASE(dest)); + } + } + + if ((TYPE_FUNC(dest->type)->flags & FUNC_IS_CTOR) && deduce->x17) { + FuncArg *arg; + CError_ASSERT(1786, TYPE_FUNC(dest->type)->args); + arg = CParser_NewFuncArg(); + arg->type = TYPE(&stsignedshort); + arg->next = TYPE_FUNC(dest->type)->args->next; + TYPE_FUNC(dest->type)->args->next = arg; + } + + break; + } + } + } +} + +static void CTemplClass_CompleteObjectInit(TypeDeduce *deduce, TemplateAction *action, Object *object) { + ENode *expr = CTemplTool_DeduceExpr(deduce, action->u.objectinit.initexpr); + + if (ENODE_IS(expr, EINTCONST) && (object->qual & Q_CONST) && IS_TYPE_INT_OR_ENUM(object->type)) { + object->u.data.u.intconst = expr->data.intval; + object->qual |= Q_INLINE_DATA | Q_20000; + } else { + CError_Error(CErrorStr354, object->name->name); + } +} + +static void CTemplClass_CopyNameSpace(TypeDeduce *deduce, TemplClassInst *inst, TemplClass *templ) { + NameSpaceName *nsname; + NameSpaceObjectList *list; + + CError_ASSERT(1830, !templ->theclass.nspace->is_hash); + + for (nsname = templ->theclass.nspace->data.list; nsname; nsname = nsname->next) { + for (list = &nsname->first; list; list = list->next) { + switch (list->object->otype) { + case OT_ENUMCONST: + break; + case OT_MEMBERVAR: + if (OBJ_MEMBER_VAR(list->object)->has_path) + CTemplClass_CopyObjMemberVarPath(deduce, OBJ_MEMBER_VAR_PATH(list->object)); + break; + case OT_TYPE: + CTemplClass_CopyObjType(deduce, OBJ_TYPE(list->object), nsname->name); + break; + case OT_TYPETAG: + break; + case OT_NAMESPACE: + CError_FATAL(1854); + case OT_OBJECT: + CTemplClass_CopyObject(deduce, OBJECT(list->object)); + break; + default: + CError_FATAL(1861); + } + } + } +} + +static void CTemplClass_CopyUsingDecl(TypeDeduce *deduce, TypeTemplDep *type, AccessType access) { + TypeClass *tclass; + UInt32 qual = 0; + + CError_ASSERT(1878, IS_TYPE_TEMPLATE(type) && type->dtype == TEMPLDEP_QUALNAME); + + tclass = TYPE_CLASS(CTemplTool_DeduceTypeCopy(deduce, TYPE(type->u.qual.type), &qual)); + if (!IS_TYPE_CLASS(tclass)) { + CError_Error(CErrorStr340, type->u.qual.name->name); + return; + } + + CDecl_CompleteType(TYPE(tclass)); + CScope_AddClassUsingDeclaration(TYPE_CLASS(deduce->inst), tclass, type->u.qual.name, access); +} + +static void CTemplClass_CopyFriend(TypeDeduce *deduce, TemplateFriend *tfriend) { + TemplArg *arg; + Object *funcobj; + Boolean flag; + CScopeSave saveScope; + DeclInfo di; + + CDecl_UnpackDeclInfo(&di, &tfriend->decl); + + if (CTemplTool_IsTemplateArgumentDependentType(di.thetype)) + di.thetype = CTemplTool_DeduceTypeCopy(deduce, di.thetype, &di.qual); + + if (di.expltargs) { + di.expltargs = CTemplTool_MakeGlobalTemplArgCopy(di.expltargs); + for (arg = di.expltargs; arg; arg = arg->next) { + switch (arg->pid.type) { + case TPT_TYPE: + if (CTemplTool_IsTemplateArgumentDependentType(arg->data.typeparam.type)) + arg->data.typeparam.type = CTemplTool_DeduceTypeCopy(deduce, arg->data.typeparam.type, &arg->data.typeparam.qual); + break; + case TPT_NONTYPE: + if (CTemplTool_IsTemplateArgumentDependentExpression(arg->data.paramdecl.expr)) + arg->data.paramdecl.expr = CTemplTool_DeduceExpr(deduce, arg->data.paramdecl.expr); + break; + case TPT_TEMPLATE: + default: + CError_FATAL(1930); + } + } + } + + if (IS_TYPE_FUNC(di.thetype)) { + CScope_SetNameSpaceScope(CScope_FindGlobalNS(deduce->inst->theclass.nspace), &saveScope); + funcobj = CDecl_GetFunctionObject(&di, NULL, &flag, 0); + CScope_RestoreScope(&saveScope); + + if (funcobj) { + CDecl_AddFriend(TYPE_CLASS(deduce->inst), funcobj, NULL); + if (tfriend->stream.tokens) + CInline_AddInlineFunctionAction(funcobj, TYPE_CLASS(deduce->inst), &tfriend->fileoffset, &tfriend->stream, 0); + } else { + CError_Error(CErrorStr201); + } + } else { + CError_ASSERT(1963, IS_TYPE_CLASS(di.thetype)); + CDecl_AddFriend(TYPE_CLASS(deduce->inst), NULL, TYPE_CLASS(di.thetype)); + } +} + +Boolean CTempl_InstantiateTemplateClass(TypeClass *tclass) { + TemplClassInst *inst; + ParserTryBlock *tryBlock; + TemplateAction *action; + DefAction *defAction; + UInt8 saveAlignMode; + + TypeDeduce deduce; + TemplStack stack; + CScopeSave saveScope; + ClassLayout layout; + TemplClass *templ; + TStreamElement *saveErrorRef; + TemplArg *inst_args; + + CError_ASSERT(1989, tclass->flags & CLASS_IS_TEMPL_INST); + + if (tclass->flags & CLASS_COMPLETED) + return 1; + + inst = TEMPL_CLASS_INST(tclass); + if (inst->is_specialized) + return 0; + + templ = inst->templ; + if (!(templ->flags & TEMPLCLASS_FLAGS_2)) + templ = CTemplClass_GetMasterTemplate(templ); + + if (templ->pspecs && CTemplClass_FindPartialTemplate(inst->inst_args, &templ, &inst_args)) { + CError_ASSERT(2013, !inst->oargs); + inst->templ = templ; + inst->oargs = inst->inst_args; + inst->inst_args = inst_args; + } + + if (!(templ->theclass.flags & CLASS_COMPLETED)) + return 0; + + if (inst->is_instantiated) + return 0; + + inst->is_instantiated = 1; + CScope_SetClassScope(tclass, &saveScope); + CTemplTool_PushInstance(&stack, tclass, NULL); + + tryBlock = trychain; + trychain = NULL; + + memclrw(&deduce, sizeof(deduce)); + deduce.tmclass = templ; + deduce.inst = inst; + deduce.params = templ->templ__params; + deduce.args = inst->inst_args; + + CError_ASSERT(2045, !templ->theclass.sominfo); + CError_ASSERT(2047, !templ->theclass.objcinfo); + CError_ASSERT(2049, !templ->theclass.vtable); + + inst->theclass.flags |= templ->theclass.flags & + (CLASS_ABSTRACT | CLASS_SINGLE_OBJECT | CLASS_HAS_VBASES | CLASS_IS_CONVERTIBLE | CLASS_COM_OBJECT); + + CTemplClass_CopyBaseClasses(&deduce, inst, templ); + + deduce.x17 = (inst->theclass.flags & CLASS_HAS_VBASES) && !(templ->theclass.flags & CLASS_HAS_VBASES); + + for (action = templ->actions; action; action = action->next) { + switch (action->type) { + case TAT_NESTEDCLASS: + CTemplClass_SetupActionErrorRef(action, &saveErrorRef); + CTemplClass_CopyNestedClass(&deduce, action->u.tclasstype); + CTemplClass_RestoreActionErrorRef(&saveErrorRef); + break; + case TAT_ENUMTYPE: + CTemplClass_SetupActionErrorRef(action, &saveErrorRef); + CTemplClass_CopyEnum(&deduce, action); + CTemplClass_RestoreActionErrorRef(&saveErrorRef); + break; + case TAT_FRIEND: + case TAT_ENUMERATOR: + case TAT_BASE: + case TAT_OBJECTINIT: + case TAT_USINGDECL: + case TAT_OBJECTDEF: + break; + default: + CError_FATAL(2094); + } + } + + CTemplClass_CopyIVars(&deduce, inst, templ); + CTemplClass_CopyNameSpace(&deduce, inst, templ); + + CError_ASSERT(2105, !templ->theclass.friends); + + for (action = templ->actions; action; action = action->next) { + switch (action->type) { + case TAT_NESTEDCLASS: + break; + case TAT_ENUMTYPE: + for (defAction = deduce.defActions; defAction; defAction = defAction->next) { + if (defAction->action == action) { + CTemplClass_SetupActionErrorRef(action, &saveErrorRef); + CTemplClass_CompleteEnumType(&deduce, action, defAction->enumtype); + CTemplClass_RestoreActionErrorRef(&saveErrorRef); + break; + } + } + break; + case TAT_FRIEND: + CTemplClass_SetupActionErrorRef(action, &saveErrorRef); + CTemplClass_CopyFriend(&deduce, action->u.tfriend); + CTemplClass_RestoreActionErrorRef(&saveErrorRef); + break; + case TAT_ENUMERATOR: + break; + case TAT_BASE: + break; + case TAT_OBJECTINIT: + for (defAction = deduce.defActions; ; defAction = defAction->next) { + CError_ASSERT(2136, defAction); + if (defAction->action == action) { + CTemplClass_SetupActionErrorRef(action, &saveErrorRef); + CTemplClass_CompleteObjectInit(&deduce, action, OBJECT(defAction->refobj)); + CTemplClass_RestoreActionErrorRef(&saveErrorRef); + break; + } + } + break; + case TAT_USINGDECL: + CTemplClass_SetupActionErrorRef(action, &saveErrorRef); + CTemplClass_CopyUsingDecl(&deduce, action->u.usingdecl.type, action->u.usingdecl.access); + CTemplClass_RestoreActionErrorRef(&saveErrorRef); + break; + case TAT_OBJECTDEF: + for (defAction = deduce.defActions; ; defAction = defAction->next) { + CError_ASSERT(2156, defAction); + if (defAction->action == action) { + CTemplClass_SetupActionErrorRef(action, &saveErrorRef); + CTemplClass_CompleteObject(&deduce, action, defAction->refobj); + CTemplClass_RestoreActionErrorRef(&saveErrorRef); + break; + } + } + break; + } + } + + memclrw(&layout, sizeof(layout)); + layout.lex_order_count = templ->lex_order_count; + layout.has_vtable = templ->flags & TEMPLCLASS_HAS_VTABLE; + + saveAlignMode = copts.structalignment; + copts.structalignment = templ->align; + CDecl_CompleteClass(&layout, TYPE_CLASS(inst)); + copts.structalignment = saveAlignMode; + + if (templ->theclass.align > inst->theclass.align) { + inst->theclass.align = templ->theclass.align; + inst->theclass.size += CABI_StructSizeAlignValue(TYPE(inst), inst->theclass.size); + } + + CTemplTool_PopInstance(&stack); + CScope_RestoreScope(&saveScope); + trychain = tryBlock; + + return 1; +} diff --git a/compiler_and_linker/FrontEnd/C/CTemplateFunc.c b/compiler_and_linker/FrontEnd/C/CTemplateFunc.c new file mode 100644 index 0000000..3c5de98 --- /dev/null +++ b/compiler_and_linker/FrontEnd/C/CTemplateFunc.c @@ -0,0 +1,1383 @@ +#include "compiler/CTemplateFunc.h" +#include "compiler/CABI.h" +#include "compiler/CDecl.h" +#include "compiler/CError.h" +#include "compiler/CExpr.h" +#include "compiler/CInline.h" +#include "compiler/CInt64.h" +#include "compiler/CParser.h" +#include "compiler/CTemplateTools.h" +#include "compiler/CompilerTools.h" +#include "compiler/objects.h" +#include "compiler/scopes.h" +#include "compiler/templates.h" +#include "compiler/types.h" + +static Boolean ctempl_conversion_deduction; +static UInt8 ctempl_explicitargs_nindex; +static int ctempl_explicitargs_num; +static Boolean ctempl_explicitargs_all; + +// forward decls +static Boolean CTempl_DeduceTypeTemplDep(TypeTemplDep *type1, UInt32 qual1, Type *type2, UInt32 qual2, TemplArg *argArray, Boolean flag); +static Boolean CTempl_DeduceType1(Type *type1, UInt32 qual1, Type *type2, UInt32 qual2, TemplArg *argArray, Boolean flag); + +static void CTemplFunc_SetupTypeDeduce(TypeDeduce *deduce, TemplateFunction *templ, TemplArg *args) { + memclrw(deduce, sizeof(TypeDeduce)); + if (templ->tfunc->nspace->theclass && (templ->tfunc->nspace->theclass->flags & CLASS_IS_TEMPL)) + deduce->tmclass = TEMPL_CLASS(templ->tfunc->nspace->theclass); + deduce->params = templ->params; + deduce->args = args; +} + +Boolean CTempl_CanDeduceFunc(Object *object, TypeFunc *tfunc, TemplArg *args) { + DeduceInfo info; + int i; + + if (CTemplTool_InitDeduceInfo(&info, CTemplTool_GetFuncTempl(object)->params, args, 0)) { + if (CTempl_DeduceType(object->type, 0, TYPE(tfunc), 0, info.args, 0, 0)) { + for (i = 0; i < info.maxCount; i++) { + if (!info.args[i].is_deduced) + return 0; + } + return 1; + } + } + + return 0; +} + +static TemplFuncInstance *CTempl_GetCreateFuncInstance(Object *funcobj, TemplArg *args, Object *object2) { + TemplFuncInstance *inst; + TemplateFunction *templ; + Object *instobj; + TemplParam *param; + TemplArg *arg; + TemplArg *last; + short paramCount; + short i; + TypeDeduce deduce; + + templ = CTemplTool_GetFuncTempl(funcobj); + + paramCount = 0; + param = templ->params; + while (param) { + param = param->next; + paramCount++; + } + + for (i = 1, arg = args; i < paramCount; i++, arg++) + arg->next = arg + 1; + arg->next = NULL; + + for (inst = templ->instances; inst; inst = inst->next) { + if (CTemplTool_EqualArgs(inst->args, args)) { + if (object2) + inst->object = object2; + return inst; + } + } + + inst = galloc(sizeof(TemplFuncInstance)); + memclrw(inst, sizeof(TemplFuncInstance)); + + for (i = 0, arg = NULL; i < paramCount; i++) { + if (arg) { + last->next = galloc(sizeof(TemplArg)); + last = last->next; + } else { + last = galloc(sizeof(TemplArg)); + arg = last; + } + + *last = *args; + last->next = NULL; + args++; + + if (last->pid.type == TPT_NONTYPE) { + CError_ASSERT(114, last->data.paramdecl.expr); + last->data.paramdecl.expr = CInline_CopyExpression(last->data.paramdecl.expr, CopyMode1); + } + } + + inst->args = arg; + inst->next = templ->instances; + templ->instances = inst; + + if (!object2) { + instobj = CParser_NewFunctionObject(NULL); + instobj->access = funcobj->access; + instobj->nspace = funcobj->nspace; + instobj->sclass = funcobj->sclass; + instobj->qual = funcobj->qual | Q_MANGLE_NAME; + instobj->name = templ->name; + instobj->u.func.inst = inst; + + CTemplFunc_SetupTypeDeduce(&deduce, templ, inst->args); + if (funcobj->nspace->theclass && (funcobj->nspace->theclass->flags & CLASS_IS_TEMPL_INST)) { + deduce.tmclass = TEMPL_CLASS_INST(funcobj->nspace->theclass)->templ; + deduce.inst = TEMPL_CLASS_INST(funcobj->nspace->theclass); + } + + instobj->type = CTemplTool_DeduceTypeCopy(&deduce, funcobj->type, &instobj->qual); + inst->object = instobj; + + if (IS_TYPE_FUNC(instobj->type)) { + TYPE_FUNC(instobj->type)->flags &= ~FUNC_DEFINED; + if (TYPE_FUNC(instobj->type)->flags & FUNC_IS_CTOR) { + FuncArg *funcarg; + CError_ASSERT(152, TYPE_FUNC(instobj->type)->flags & FUNC_METHOD); + CError_ASSERT(153, funcarg = TYPE_FUNC(instobj->type)->args); + + if (TYPE_METHOD(instobj->type)->theclass->flags & CLASS_HAS_VBASES) + CError_ASSERT(156, funcarg = funcarg->next); + + if (funcarg->next) + CDecl_CheckCtorIntegrity(funcarg->next, TYPE_METHOD(instobj->type)->theclass); + } + } + + if ((instobj->qual & Q_INLINE) && templ->stream.tokens) + CInline_AddTemplateFunctionAction(instobj, templ, inst); + + } else { + inst->object = object2; + } + + return inst; +} + +TemplFuncInstance *CTempl_CheckFuncInstance(Object *object1, TypeFunc *tfunc, TemplArg *args, Object *object2) { + DeduceInfo info; + int i; + + if (!CTemplTool_InitDeduceInfo(&info, CTemplTool_GetFuncTempl(object1)->params, args, 1)) + return NULL; + + if (!CTempl_DeduceType(object1->type, 0, TYPE(tfunc), 0, info.args, 0, 0)) + return NULL; + + i = 0; + while (i < info.maxCount) { + if (!info.args[i++].is_deduced) + return NULL; + } + + return CTempl_GetCreateFuncInstance(object1, info.args, object2); +} + +TemplFuncInstance *CTempl_DeduceFunc(Object *object1, TypeFunc *tfunc, TemplArg *args, Object *object2, Boolean flag) { + return CTempl_CheckFuncInstance(object1, tfunc, args, object2); +} + +static Boolean CTempl_FuncIsAtLeastAsSpecialized(Object *func1, Object *func2) { + int i; + FuncArg *arg1; + FuncArg *arg2; + Type *type1; + Type *type2; + UInt32 qual1; + UInt32 qual2; + DeduceInfo info; + + arg1 = TYPE_FUNC(func2->type)->args; + if (IS_TYPEFUNC_NONSTATIC_METHOD(TYPE_FUNC(func2->type))) + arg1 = arg1->next; + + i = 0; + while (1) { + if (!arg1) + break; + CError_ASSERT(231, arg1->type != &stvoid); + if (arg1 == &elipsis) + break; + if (arg1 == &oldstyle) + break; + arg1 = arg1->next; + i++; + } + + if (!CTemplTool_InitDeduceInfo(&info, CTemplTool_GetFuncTempl(func2)->params, NULL, 0)) + return 0; + + arg1 = TYPE_FUNC(func1->type)->args; + if (IS_TYPEFUNC_NONSTATIC_METHOD(TYPE_FUNC(func1->type))) + arg1 = arg1->next; + + arg2 = TYPE_FUNC(func2->type)->args; + if (IS_TYPEFUNC_NONSTATIC_METHOD(TYPE_FUNC(func2->type))) + arg2 = arg2->next; + + while (i > 0) { + if (!arg1) + break; + if (arg1 == &elipsis) + break; + if (arg1 == &oldstyle) + break; + + CError_ASSERT(255, arg2); + + type1 = arg1->type; + qual1 = arg1->qual & (Q_CONST | Q_VOLATILE); + qual2 = arg2->qual & (Q_CONST | Q_VOLATILE); + type2 = arg2->type; + + if (!CTemplTool_IsTemplateArgumentDependentType(type2)) { + if (IS_TYPE_REFERENCE(type1)) + type1 = TPTR_TARGET(type1); + type1 = CParser_RemoveTopMostQualifiers(type1, &qual1); + + if (IS_TYPE_REFERENCE(type2)) + type2 = TPTR_TARGET(type2); + type2 = CParser_RemoveTopMostQualifiers(type2, &qual2); + + if (!is_typesame(type1, type2) || qual1 != qual2) + return 0; + } else { + if (!CTempl_DeduceType(type2, qual2, type1, qual1, info.args, 0, 0)) + return 0; + } + + arg1 = arg1->next; + arg2 = arg2->next; + i--; + } + + return 1; +} + +Boolean CTempl_FuncIsMoreSpecialized(Object *object1, Object *object2) { + return CTempl_FuncIsAtLeastAsSpecialized(object1, object2) && !CTempl_FuncIsAtLeastAsSpecialized(object2, object1); +} + +Object *CTempl_PartialOrdering(Object *object, ObjectList *list, int count) { + int i; + int j; + Object **array; + ObjectList *scan; + Object *arrayBuffer[16]; + + for (count = 1, scan = list; scan; scan = scan->next) { + if (IS_TEMPL_FUNC(scan->object->type)) + count++; + } + + if (count > 16) + array = lalloc(sizeof(Object *) * count); + else + array = arrayBuffer; + + array[0] = object; + for (i = 1, scan = list; scan; scan = scan->next) { + if (IS_TEMPL_FUNC(scan->object->type)) + array[i++] = scan->object; + } + + for (i = 0; i < count; i++) { + if (array[i]) { + for (j = 0; j < count; j++) { + if (array[j] && i != j && CTempl_FuncIsMoreSpecialized(array[i], array[j])) + array[j] = NULL; + } + } + } + + object = NULL; + + for (i = 0; i < count; i++) { + if (array[i]) { + if (object) + return NULL; + object = array[i]; + } + } + + return object; +} + +int CTempl_GetTemplateArgumentExpressionIndex(TemplArg *arg) { + CError_ASSERT(529, arg->data.paramdecl.expr); + + if (ENODE_IS(arg->data.paramdecl.expr, ETEMPLDEP) && arg->data.paramdecl.expr->data.templdep.subtype == TDE_PARAM) + return arg->data.paramdecl.expr->data.templdep.u.pid.index; + + return -1; +} + +static Type *CTempl_GetSpecifiedType(TemplateFunction *templ, Type *type, UInt32 qual, TemplArg *args, UInt32 *resultQual) { + TypeDeduce deduce; + + CTemplFunc_SetupTypeDeduce(&deduce, templ, args); + *resultQual = qual; + return CTemplTool_DeduceTypeCopy(&deduce, type, resultQual); +} + +static Boolean CTempl_DeduceTemplateArgs(TemplArg *args1, TemplArg *args2, TemplArg *argArray) { + int index; + + while (1) { + if (!args1) + return !args2; + if (!args2) + return 0; + + if (args1->pid.type != args2->pid.type) + return 0; + + switch (args1->pid.type) { + case TPT_TYPE: + if (!CTempl_DeduceType1( + args1->data.typeparam.type, args1->data.typeparam.qual, + args2->data.typeparam.type, args2->data.typeparam.qual, + argArray, 1 + )) + return 0; + break; + + case TPT_NONTYPE: + if (CTemplTool_IsTemplateArgumentDependentExpression(args1->data.paramdecl.expr)) { + index = CTempl_GetTemplateArgumentExpressionIndex(args1); + if (index < 0) + return 1; + + if (argArray[index].is_deduced) { + if (!CTemplTool_EqualExprTypes(args2->data.paramdecl.expr, argArray[index].data.paramdecl.expr)) + return 0; + } else { + argArray[index].data.paramdecl.expr = args2->data.paramdecl.expr; + argArray[index].pid.type = TPT_NONTYPE; + argArray[index].is_deduced = 1; + } + } else { + if (!CTemplTool_EqualExprTypes(args2->data.paramdecl.expr, args1->data.paramdecl.expr)) + return 0; + } + break; + + case TPT_TEMPLATE: + if (!IS_TEMPL_CLASS(args2->data.ttargtype)) + return 0; + + index = args1->pid.index; + if (argArray[index].is_deduced) { + if (args2->data.ttargtype != argArray[index].data.ttargtype) + return 0; + } else { + argArray[index].data.ttargtype = args2->data.ttargtype; + argArray[index].pid.type = TPT_TEMPLATE; + argArray[index].is_deduced = 1; + } + break; + + default: + CError_FATAL(640); + } + + args1 = args1->next; + args2 = args2->next; + } +} + +static Boolean CTempl_DeduceTemplDepTemplate(TemplClass *templ1, TemplArg *args1, TemplClass *templ2, TemplArg *args2, TemplArg *argArray) { + if (templ1 != templ2) + return 0; + + return CTempl_DeduceTemplateArgs(args2, args1, argArray); +} + +static Boolean CTempl_DeduceTemplateType(TemplClass *templ, TemplArg *args, TemplClassInst *inst, TemplArg *argArray) { + TemplClassInst *scan; + + for (scan = templ->instances; scan; scan = scan->next) { + if (scan == inst) + return CTempl_DeduceTemplateArgs(args, scan->oargs ? scan->oargs : scan->inst_args, argArray); + } + + return 0; +} + +static Boolean CTempl_DeduceTemplateTypeBase(TemplClass *templ, TemplArg *args, TemplClassInst *inst, TemplArg *argArray, Boolean flag) { + ClassList *base; + + if (CTempl_DeduceTemplateType(templ, args, inst, argArray)) + return 1; + + if (flag) { + for (base = inst->theclass.bases; base; base = base->next) { + if (CTempl_DeduceTemplateType(templ, args, TEMPL_CLASS_INST(base->base), argArray)) { + ctempl_conversion_deduction = 1; + return 1; + } + } + + for (base = inst->theclass.bases; base; base = base->next) { + if (CTempl_DeduceTemplateTypeBase(templ, args, TEMPL_CLASS_INST(base->base), argArray, 1)) { + ctempl_conversion_deduction = 1; + return 1; + } + } + } + + return 0; +} + +static Boolean CTempl_DeduceQualTemplate(TypeTemplDep *type1, TemplArg *args1, Type *type2, TemplArg *argArray) { + int index; + + if (type1->dtype == TEMPLDEP_ARGUMENT && type1->u.pid.type == TPT_TEMPLATE) { + index = type1->u.pid.index; + if (IS_TEMPL_CLASS_INST(type2)) { + if (argArray[index].is_deduced) { + if (argArray[index].data.ttargtype != TYPE(TEMPL_CLASS_INST(type2)->templ)) + return 0; + } else { + argArray[index].data.ttargtype = TYPE(TEMPL_CLASS_INST(type2)->templ); + argArray[index].pid.type = TPT_TEMPLATE; + argArray[index].is_deduced = 1; + } + + return CTempl_DeduceTemplateArgs(args1, TEMPL_CLASS_INST(type2)->inst_args, argArray); + } + + if (IS_TYPE_TEMPLATE(type2)) { + if (TYPE_TEMPLATE(type2)->dtype == TEMPLDEP_TEMPLATE) { + if (argArray[index].is_deduced) { + if (argArray[index].data.ttargtype != TYPE(TYPE_TEMPLATE(type2)->u.templ.templ)) + return 0; + } else { + argArray[index].data.ttargtype = TYPE(TYPE_TEMPLATE(type2)->u.templ.templ); + argArray[index].pid.type = TPT_TEMPLATE; + argArray[index].is_deduced = 1; + } + + return CTempl_DeduceTemplateArgs(args1, TYPE_TEMPLATE(type2)->u.templ.args, argArray); + } + + if (TYPE_TEMPLATE(type2)->dtype == TEMPLDEP_QUALTEMPL) { + return + CTempl_DeduceTypeTemplDep(type1, 0, TYPE(TYPE_TEMPLATE(type2)->u.qualtempl.type), 0, argArray, 1) && + CTempl_DeduceTemplateArgs(args1, TYPE_TEMPLATE(type2)->u.qualtempl.args, argArray); + } + } + } + + return 0; +} + +static Boolean CTempl_DeduceTypeTemplDep(TypeTemplDep *type1, UInt32 qual1, Type *type2, UInt32 qual2, TemplArg *argArray, Boolean flag) { + Type *tmptype; + UInt32 tmpqual; + short index; + Boolean f; + UInt32 modqual; + + switch (type1->dtype) { + case TEMPLDEP_ARGUMENT: + index = type1->u.pid.index; + tmptype = type2; + if (type1->u.pid.type == TPT_TEMPLATE) { + if (argArray[index].is_deduced) { + if (!is_typesame(tmptype, argArray[index].data.ttargtype)) + return 0; + } else { + argArray[index].data.ttargtype = type2; + argArray[index].pid.type = TPT_TEMPLATE; + argArray[index].is_deduced = 1; + } + return 1; + } + + switch (type2->type) { + case TYPEPOINTER: + tmpqual = qual2; + f = 0; + qual2 = TPTR_QUAL(type2); + modqual = qual2; + + if ((modqual & Q_CONST) && (qual1 & Q_CONST)) { + modqual &= ~Q_CONST; + f = 1; + } + if ((modqual & Q_VOLATILE) && (qual1 & Q_VOLATILE)) { + modqual &= ~Q_VOLATILE; + f = 1; + } + + if (f) { + tmptype = galloc(sizeof(TypePointer)); + *TYPE_POINTER(tmptype) = *TYPE_POINTER(type2); + TPTR_QUAL(tmptype) = modqual; + } + + if (flag && (qual2 | modqual) != (qual1 | modqual)) + return 0; + + break; + + case TYPEMEMBERPOINTER: + tmpqual = qual2; + f = 0; + qual2 = TYPE_MEMBER_POINTER(type2)->qual; + modqual = qual2; + + if ((modqual & Q_CONST) && (qual1 & Q_CONST)) { + modqual &= ~Q_CONST; + f = 1; + } + if ((modqual & Q_VOLATILE) && (qual1 & Q_VOLATILE)) { + modqual &= ~Q_VOLATILE; + f = 1; + } + + if (f) { + tmptype = galloc(sizeof(TypeMemberPointer)); + *TYPE_MEMBER_POINTER(tmptype) = *TYPE_MEMBER_POINTER(type2); + TYPE_MEMBER_POINTER(tmptype)->qual = modqual; + } + + if (flag && (qual2 | modqual) != (qual1 | modqual)) + return 0; + + break; + + default: + tmpqual = 0; + if ((qual2 & Q_CONST) && !(qual1 & Q_CONST)) + tmpqual |= Q_CONST; + if ((qual2 & Q_VOLATILE) && !(qual1 & Q_VOLATILE)) + tmpqual |= Q_VOLATILE; + + if (flag && (qual2 | tmpqual) != (qual1 | tmpqual)) + return 0; + } + + if (argArray[index].is_deduced) { + if (!is_typesame(tmptype, argArray[index].data.typeparam.type) || tmpqual != argArray[index].data.typeparam.qual) + return 0; + } else { + argArray[index].data.typeparam.type = tmptype; + argArray[index].data.typeparam.qual = tmpqual; + argArray[index].pid.type = TPT_TYPE; + argArray[index].is_deduced = 1; + } + return 1; + + case TEMPLDEP_QUALNAME: + return 1; + + case TEMPLDEP_TEMPLATE: + if (IS_TYPE_CLASS(type2)) + return CTempl_DeduceTemplateTypeBase( + type1->u.templ.templ, type1->u.templ.args, + TEMPL_CLASS_INST(type2), argArray, 0); + + if (IS_TYPE_TEMPLATE(type2) && TYPE_TEMPLATE(type2)->dtype == TEMPLDEP_TEMPLATE) + return CTempl_DeduceTemplDepTemplate( + TYPE_TEMPLATE(type2)->u.templ.templ, TYPE_TEMPLATE(type2)->u.templ.args, + type1->u.templ.templ, type1->u.templ.args, + argArray + ); + + return 0; + + case TEMPLDEP_ARRAY: + if (IS_TYPE_ARRAY(type2)) { + SInt32 elements; + + if (!CTempl_DeduceType1(type1->u.array.type, qual1, TPTR_TARGET(type2), qual2, argArray, flag)) + return 0; + + if (ENODE_IS(type1->u.array.index, EINTCONST)) { + CError_ASSERT(961, TPTR_TARGET(type2)->size); + return (type2->size / TPTR_TARGET(type2)->size) == CInt64_GetULong(&type1->u.array.index->data.intval); + } + + if (!ENODE_IS(type1->u.array.index, ETEMPLDEP) || type1->u.array.index->data.templdep.subtype != TDE_PARAM) + return 1; + + CError_ASSERT(970, TPTR_TARGET(type2)->size); + + elements = type2->size / TPTR_TARGET(type2)->size; + index = type1->u.array.index->data.templdep.u.pid.index; + if (argArray[index].is_deduced) { + CError_ASSERT(976, ENODE_IS(argArray[index].data.paramdecl.expr, EINTCONST)); + return elements == CInt64_GetULong(&argArray[index].data.paramdecl.expr->data.intval); + } else { + argArray[index].data.paramdecl.expr = intconstnode(CABI_GetPtrDiffTType(), elements); + argArray[index].pid.type = TPT_NONTYPE; + argArray[index].is_deduced = 1; + return 1; + } + } else if (IS_TYPE_TEMPLATE(type2) && TYPE_TEMPLATE(type2)->dtype == TEMPLDEP_ARRAY) { + if (!CTempl_DeduceType1(type1->u.array.type, qual1, TYPE_TEMPLATE(type2)->u.array.type, qual2, argArray, flag)) + return 0; + + if (ENODE_IS(type1->u.array.index, EINTCONST)) { + return ENODE_IS(TYPE_TEMPLATE(type2)->u.array.index, EINTCONST) && + CInt64_Equal(type1->u.array.index->data.intval, TYPE_TEMPLATE(type2)->u.array.index->data.intval); + } + + if (!ENODE_IS(type1->u.array.index, ETEMPLDEP) || type1->u.array.index->data.templdep.subtype != TDE_PARAM) + return 1; + + index = type1->u.array.index->data.templdep.u.pid.index; + if (argArray[index].is_deduced) { + return CTemplTool_EqualExprTypes(TYPE_TEMPLATE(type2)->u.array.index, argArray[index].data.paramdecl.expr); + } else { + argArray[index].data.paramdecl.expr = TYPE_TEMPLATE(type2)->u.array.index; + argArray[index].pid.type = TPT_NONTYPE; + argArray[index].is_deduced = 1; + return 1; + } + } + + return 0; + + case TEMPLDEP_QUALTEMPL: + return CTempl_DeduceQualTemplate(type1->u.qualtempl.type, type1->u.qualtempl.args, type2, argArray); + + case TEMPLDEP_BITFIELD: + default: + CError_FATAL(1022); + return 1; + } +} + +static Boolean CTempl_DeduceFuncType(TypeFunc *tfunc1, TypeFunc *tfunc2, TemplArg *argArray) { + FuncArg *arg1; + FuncArg *arg2; + Type *type2; + Type *type1; + UInt32 qual2; + UInt32 qual1; + + arg1 = tfunc1->args; + arg2 = tfunc2->args; + + if (IS_TYPEFUNC_NONSTATIC_METHOD(tfunc1) && !IS_TYPEFUNC_METHOD(tfunc2)) { + CError_ASSERT(1045, arg1); + arg1 = arg1->next; + } + + while (1) { + if (arg1 == NULL) + return !arg2; + if (arg1 == &oldstyle) + return arg2 == &oldstyle; + if (arg1 == &elipsis) + return arg2 == &elipsis; + + if (arg2 == NULL || arg2 == &oldstyle || arg2 == &elipsis) + return 0; + + qual2 = arg2->qual; + type2 = CParser_RemoveTopMostQualifiers(arg2->type, &qual2); + + qual1 = arg1->qual; + type1 = CParser_RemoveTopMostQualifiers(arg1->type, &qual1); + + if (!CTempl_DeduceType1(type1, qual1, type2, qual2, argArray, 1)) + return 0; + + arg1 = arg1->next; + arg2 = arg2->next; + } +} + +static Boolean CTempl_DeduceType1(Type *type1, UInt32 qual1, Type *type2, UInt32 qual2, TemplArg *argArray, Boolean flag) { + while (1) { + switch (type1->type) { + case TYPETEMPLATE: + return CTempl_DeduceTypeTemplDep(TYPE_TEMPLATE(type1), qual1, type2, qual2, argArray, flag); + + case TYPEVOID: + case TYPEINT: + case TYPEFLOAT: + case TYPEENUM: + case TYPESTRUCT: + case TYPECLASS: + return type1 == type2; + + case TYPEMEMBERPOINTER: + if (type1->type != type2->type || TYPE_MEMBER_POINTER(type1)->qual != TYPE_MEMBER_POINTER(type2)->qual) + return 0; + if (!CTempl_DeduceType1(TYPE_MEMBER_POINTER(type1)->ty1, qual1, TYPE_MEMBER_POINTER(type2)->ty1, qual2, argArray, flag)) + return 0; + type1 = TYPE_MEMBER_POINTER(type1)->ty2; + type2 = TYPE_MEMBER_POINTER(type2)->ty2; + continue; + + case TYPEARRAY: + if (type2->type != TYPEARRAY) + return 0; + type1 = TPTR_TARGET(type1); + type2 = TPTR_TARGET(type2); + continue; + + case TYPEPOINTER: + if (type2->type != TYPEPOINTER || TPTR_QUAL(type1) != TPTR_QUAL(type2)) + return 0; + type1 = TPTR_TARGET(type1); + type2 = TPTR_TARGET(type2); + continue; + + case TYPEFUNC: + if (type1->type != type2->type) + return 0; + + if (CTempl_DeduceType1(TYPE_FUNC(type1)->functype, TYPE_FUNC(type1)->qual, TYPE_FUNC(type2)->functype, TYPE_FUNC(type2)->qual, argArray, flag)) + return CTempl_DeduceFuncType(TYPE_FUNC(type1), TYPE_FUNC(type2), argArray); + + return 0; + + default: + CError_FATAL(1124); + } + } +} + +static Boolean CTempl_DeduceType2(Type *type1, UInt32 qual1, Type *type2, UInt32 qual2, TemplArg *argArray) { + while (1) { + switch (type1->type) { + case TYPEPOINTER: + if (type2->type != TYPEPOINTER) + return 0; + if (!CParser_IsSameOrMoreCVQualified(TPTR_QUAL(type2), TPTR_QUAL(type1))) + return 0; + type1 = TPTR_TARGET(type1); + type2 = TPTR_TARGET(type2); + continue; + + case TYPEMEMBERPOINTER: + if (type2->type != TYPEMEMBERPOINTER) + return 0; + if (!CParser_IsSameOrMoreCVQualified(TYPE_MEMBER_POINTER(type2)->qual, TYPE_MEMBER_POINTER(type1)->qual)) + return 0; + if (!CTempl_DeduceType2(TYPE_MEMBER_POINTER(type1)->ty1, qual1, TYPE_MEMBER_POINTER(type2)->ty1, qual2, argArray)) + return 0; + type1 = TYPE_MEMBER_POINTER(type1)->ty2; + type2 = TYPE_MEMBER_POINTER(type2)->ty2; + continue; + + default: + if (CParser_IsSameOrMoreCVQualified(qual2, qual1)) + return CTempl_DeduceType1(type1, qual2, type2, qual2, argArray, 0); + return 0; + } + } +} + +static Boolean CTempl_DeduceType3(Type *type1, UInt32 qual1, Type *type2, UInt32 qual2, TemplArg *argArray) { + Boolean flag = 0; + + while (1) { + switch (type1->type) { + case TYPEPOINTER: + flag = 1; + if (type2->type != TYPEPOINTER) + return 0; + if (!CParser_IsSameOrMoreCVQualified(TPTR_QUAL(type2), TPTR_QUAL(type1))) + return 0; + type1 = TPTR_TARGET(type1); + type2 = TPTR_TARGET(type2); + continue; + + case TYPEMEMBERPOINTER: + flag = 1; + if (type2->type != TYPEMEMBERPOINTER) + return 0; + if (!CParser_IsSameOrMoreCVQualified(TYPE_MEMBER_POINTER(type2)->qual, TYPE_MEMBER_POINTER(type1)->qual)) + return 0; + if (!CTempl_DeduceType2(TYPE_MEMBER_POINTER(type1)->ty1, qual1, TYPE_MEMBER_POINTER(type2)->ty1, qual2, argArray)) + return 0; + type1 = TYPE_MEMBER_POINTER(type1)->ty2; + type2 = TYPE_MEMBER_POINTER(type2)->ty2; + continue; + + default: + if (!flag) + return 0; + if (CParser_IsSameOrMoreCVQualified(qual2, qual1)) + return CTempl_DeduceType1(type1, qual2, type2, qual2, argArray, 0); + return 0; + } + } +} + +static Boolean CTempl_DeduceType4(Type *type1, UInt32 qual1, Type *type2, UInt32 qual2, TemplArg *argArray) { + if (IS_TYPE_POINTER_ONLY(type1)) { + if (!IS_TYPE_POINTER_ONLY(type2)) + return 0; + + if (!CParser_IsSameOrMoreCVQualified(TPTR_QUAL(type1), TPTR_QUAL(type2))) + return 0; + + type1 = TPTR_TARGET(type1); + type2 = TPTR_TARGET(type2); + } + + if (IS_TYPE_TEMPLATE(type1) && TYPE_TEMPLATE(type1)->dtype == TEMPLDEP_TEMPLATE && IS_TYPE_CLASS(type2)) { + if (CParser_IsSameOrMoreCVQualified(qual1, qual2)) + return CTempl_DeduceTemplateTypeBase( + TYPE_TEMPLATE(type1)->u.templ.templ, + TYPE_TEMPLATE(type1)->u.templ.args, + TEMPL_CLASS_INST(type2), + argArray, + 1); + else + return 0; + } + + return 0; +} + +Boolean CTempl_DeduceType(Type *type1, UInt32 qual1, Type *type2, UInt32 qual2, TemplArg *argArray, Boolean flag1, Boolean flag2) { + Boolean flag31; + Boolean flag8; + + flag31 = 0; + flag8 = 1; + + if (flag1 || flag2) { + if (IS_TYPE_REFERENCE(type1)) { + type1 = TPTR_TARGET(type1); + flag31 = 1; + } else { + switch (type2->type) { + case TYPEFUNC: + type2 = CDecl_NewPointerType(type2); + break; + case TYPEARRAY: + type2 = CDecl_NewPointerType(TPTR_TARGET(type2)); + break; + } + + type1 = CParser_RemoveTopMostQualifiers(type1, &qual1); + type2 = CParser_RemoveTopMostQualifiers(type2, &qual2); + } + flag8 = 0; + } + + if (CTempl_DeduceType1(type1, qual1, type2, qual2, argArray, flag8)) + return 1; + + if (flag1 || flag2) { + if (flag31 && CTempl_DeduceType2(type1, qual1, type2, qual2, argArray)) + return 1; + if (CTempl_DeduceType3(type1, qual1, type2, qual2, argArray)) + return 1; + if (flag1 && CTempl_DeduceType4(type1, qual1, type2, qual2, argArray)) + return 1; + } + + return 0; +} + +static Boolean CTempl_TypeNeedsDeduction(Type *type) { + FuncArg *arg; + Boolean result; + + while (1) { + switch (type->type) { + case TYPETEMPLATE: + switch (TYPE_TEMPLATE(type)->dtype) { + case TEMPLDEP_ARGUMENT: + if ( + TYPE_TEMPLATE(type)->u.pid.index >= ctempl_explicitargs_num || + TYPE_TEMPLATE(type)->u.pid.nindex != ctempl_explicitargs_nindex + ) + ctempl_explicitargs_all = 0; + return 1; + + case TEMPLDEP_QUALNAME: + CTempl_TypeNeedsDeduction(TYPE(TYPE_TEMPLATE(type)->u.qual.type)); + return 1; + + case TEMPLDEP_TEMPLATE: + ctempl_explicitargs_all = 0; + return 1; + + case TEMPLDEP_ARRAY: + CTempl_TypeNeedsDeduction(TYPE_TEMPLATE(type)->u.array.type); + ctempl_explicitargs_all = 0; + return 1; + + case TEMPLDEP_QUALTEMPL: + CTempl_TypeNeedsDeduction(TYPE(TYPE_TEMPLATE(type)->u.qualtempl.type)); + ctempl_explicitargs_all = 0; + return 1; + + case TEMPLDEP_BITFIELD: + default: + CError_FATAL(1357); + } + + case TYPEVOID: + case TYPEINT: + case TYPEFLOAT: + case TYPEENUM: + case TYPESTRUCT: + case TYPECLASS: + return 0; + + case TYPEMEMBERPOINTER: + result = 0; + if (CTempl_TypeNeedsDeduction(TYPE_MEMBER_POINTER(type)->ty1)) + result = 1; + if (CTempl_TypeNeedsDeduction(TYPE_MEMBER_POINTER(type)->ty2)) + result = 1; + return result; + + case TYPEPOINTER: + case TYPEARRAY: + type = TPTR_TARGET(type); + continue; + + case TYPEFUNC: + result = 0; + for (arg = TYPE_FUNC(type)->args; arg && arg != &elipsis; arg = arg->next) { + if (CTempl_TypeNeedsDeduction(arg->type)) + result = 1; + } + + if (CTempl_TypeNeedsDeduction(TYPE_FUNC(type)->functype)) + result = 1; + return result; + + default: + CError_FATAL(1389); + } + } +} + +static Boolean CTempl_MatchTemplFunc(Object *object, DeduceInfo *info, FuncArg *args, ENodeList *exprs, Match13 *match13ptr) { + Match13 match13; + int i; + + memclrw(&match13, sizeof(match13)); + + while (1) { + if (!args || args->type == &stvoid) { + if (!exprs) + break; + return 0; + } + + if (args == &elipsis) + break; + if (args == &oldstyle) + break; + + if (!exprs) { + if (args->dexpr) + break; + return 0; + } + + ctempl_explicitargs_nindex = info->x12C; + ctempl_explicitargs_num = info->count; + ctempl_explicitargs_all = 1; + + if (CTempl_TypeNeedsDeduction(args->type)) { + if (!ctempl_explicitargs_all) { + UInt32 cv2; + UInt32 cv1; + Type *type2; + Type *type1; + UInt32 qual2; + UInt32 qual1; + + type1 = args->type; + qual1 = args->qual & (Q_CONST | Q_VOLATILE); + + type2 = exprs->node->rtype; + qual2 = ENODE_QUALS(exprs->node); + + if (IS_TYPE_REFERENCE(type1)) { + type1 = TPTR_TARGET(type1); + cv1 = CParser_GetCVTypeQualifiers(type1, qual1); + cv2 = CParser_GetCVTypeQualifiers(type2, qual2); + if ( + (!(cv1 & Q_CONST) && (cv2 & Q_CONST)) || + (!(cv1 & Q_VOLATILE) && (cv2 & Q_VOLATILE)) + ) + return 0; + + if (!(cv1 & Q_CONST) && !CExpr_IsLValue(exprs->node)) + return 0; + } + + type1 = CParser_RemoveTopMostQualifiers(type1, &qual1); + type2 = CParser_RemoveTopMostQualifiers(type2, &qual2); + + if (ENODE_IS(exprs->node, EOBJREF) && IS_TEMPL_FUNC(exprs->node->data.objref->type)) + return 0; + + if (ENODE_IS(exprs->node, EOBJLIST)) { + NameSpaceObjectList *list; + + for (list = exprs->node->data.objlist.list; list; list = list->next) { + if (list->object->otype == OT_OBJECT && IS_TEMPL_FUNC(OBJECT(list->object)->type)) + break; + } + + if (list) + return 0; + + if (IS_TYPE_FUNC(type2)) + type2 = CDecl_NewPointerType(type2); + } + + ctempl_conversion_deduction = 0; + if (!CTempl_DeduceType(type1, qual1, type2, qual2, info->args, 1, 0)) + return 0; + + if (ctempl_conversion_deduction) + match13.anotherm5.x4++; + else + match13.anotherm5.x0++; + + if (IS_TYPE_POINTER_ONLY(args->type)) + CExpr_MatchCV(type2, qual2, args->type, args->qual, &match13); + + } else { + Type *type; + UInt32 qual; + + type = CTempl_GetSpecifiedType(CTemplTool_GetFuncTempl(object), args->type, args->qual, info->args, &qual); + if (type && !CExpr_MatchAssign(type, qual, exprs->node, &match13)) + return 0; + } + } else { + if (copts.old_argmatch && !CExpr_MatchAssign(args->type, args->qual, exprs->node, &match13)) + return 0; + } + + exprs = exprs->next; + args = args->next; + } + + for (i = 0; i < info->maxCount; i++) { + if (!info->args[i].is_deduced) + return 0; + info->args[i].next = &info->args[i + 1]; + } + info->args[info->maxCount].next = NULL; + + return CExpr_MatchCompare(object, match13ptr, &match13); +} + +void CTempl_FuncMatch(NameSpaceObjectList *list, TemplArg *args, ENodeList *argexprs, Match13 *match13ptr, ENode *expr) { + Object *obj; + Object *success; + Object *object1; + FuncMatchArgs funcMatchArgs; + DeduceInfo info; + DeduceInfo info2; + + object1 = match13ptr->obj; + success = NULL; + while (list) { + obj = OBJECT(list->object); + if ( + obj->otype == OT_OBJECT && + IS_TEMPL_FUNC(obj->type) && + CExpr_GetFuncMatchArgs(obj, argexprs, expr, &funcMatchArgs) && + CTemplTool_InitDeduceInfo(&info, CTemplTool_GetFuncTempl(obj)->params, args, 0) && + CTempl_MatchTemplFunc(obj, &info, funcMatchArgs.args, funcMatchArgs.exprs, match13ptr) + ) + { + info2 = info; + if (info.args == info.argBuffer) + info2.args = info2.argBuffer; + success = obj; + } + list = list->next; + } + + if (success) { + if (match13ptr->list) { + ENodeList *argexpr = argexprs; + int argexprcount = 0; + while (argexpr) { + argexpr = argexpr->next; + argexprcount++; + } + + obj = CTempl_PartialOrdering(match13ptr->obj, match13ptr->list, argexprcount); + if (!obj) { + CError_OverloadedFunctionError(match13ptr->obj, match13ptr->list); + match13ptr->list = NULL; + if (object1) + match13ptr->obj = object1; + else + match13ptr->obj = CTempl_GetCreateFuncInstance(success, info2.args, NULL)->object; + } else { + NameSpaceObjectList mylist; + mylist.next = NULL; + mylist.object = OBJ_BASE(obj); + memclrw(match13ptr, sizeof(Match13)); + CTempl_FuncMatch(&mylist, args, argexprs, match13ptr, expr); + } + } else { + match13ptr->obj = CTempl_GetCreateFuncInstance(success, info2.args, NULL)->object; + } + } else { + match13ptr->obj = object1; + } +} + +static Boolean CExpr_DeduceFromObjList(FuncArg *arg, NameSpaceObjectList *list, DeduceInfo *info) { + TemplArg *savebuf; + NameSpaceObjectList *scan; + SInt32 size; + + for (scan = list; scan; scan = scan->next) { + if (scan->object->otype == OT_OBJECT && IS_TEMPL_FUNC(OBJECT(scan->object)->type)) + return 0; + } + + size = sizeof(TemplArg) * info->maxCount; + savebuf = lalloc(size); + + for (scan = list; scan; scan = scan->next) { + if (scan->object->otype == OT_OBJECT && IS_TYPE_FUNC(OBJECT(scan->object)->type)) { + Object *obj; + + memcpy(savebuf, info->args, size); + + obj = OBJECT(scan->object); + if (CTempl_DeduceType( + arg->type, arg->qual & (Q_CONST | Q_VOLATILE), + obj->type, obj->qual, + savebuf, 1, 0 + )) + { + memcpy(info->args, savebuf, size); + return 1; + } + } + } + + return 0; +} + +Object *CTempl_DeduceFromFunctionCall(Object *funcobj, TemplArg *templargs, ENodeList *argexprs) { + DeduceInfo info; + FuncArg *arg; + int i; + + CError_ASSERT(1655, IS_TEMPL_FUNC(funcobj->type)); + + if (CTemplTool_InitDeduceInfo(&info, CTemplTool_GetFuncTempl(funcobj)->params, templargs, 0)) { + arg = TYPE_FUNC(funcobj->type)->args; + if (IS_TYPEFUNC_NONSTATIC_METHOD(TYPE_FUNC(funcobj->type))) { + CError_ASSERT(1664, arg); + arg = arg->next; + } + + while (1) { + if (!arg || arg->type == &stvoid) { + if (argexprs) + return NULL; + break; + } + + if (arg == &elipsis) + break; + if (arg == &oldstyle) + break; + + if (!argexprs) { + if (arg->dexpr) + break; + return NULL; + } + + ctempl_explicitargs_nindex = info.x12C; + ctempl_explicitargs_num = info.count; + ctempl_explicitargs_all = 1; + + if (CTempl_TypeNeedsDeduction(arg->type) && !ctempl_explicitargs_all) { + ENode *node = argexprs->node; + + if (ENODE_IS(node, EOBJREF) && IS_TEMPL_FUNC(node->data.objref->type)) + return NULL; + + if (ENODE_IS(node, EOBJLIST)) { + if (!CExpr_DeduceFromObjList(arg, node->data.objlist.list, &info)) + return NULL; + } else { + if (!CTempl_DeduceType( + arg->type, arg->qual & (Q_CONST | Q_VOLATILE), + node->rtype, ENODE_QUALS(node), + info.args, 1, 0)) + return NULL; + } + } + + argexprs = argexprs->next; + arg = arg->next; + } + + for (i = 0; i < info.maxCount; i++) { + if (!info.args[i].is_deduced) + return 0; + info.args[i].next = &info.args[i + 1]; + } + info.args[info.maxCount].next = NULL; + + return CTempl_GetCreateFuncInstance(funcobj, info.args, NULL)->object; + } else { + return NULL; + } +} + +Object *CTempl_DeduceFromConversion(Object *funcobj, Type *type, UInt32 qual) { + DeduceInfo info; + int i; + + CError_ASSERT(1745, IS_TEMPL_FUNC(funcobj->type)); + + if (!CTemplTool_InitDeduceInfo(&info, CTemplTool_GetFuncTempl(funcobj)->params, NULL, 0)) + return NULL; + + ctempl_explicitargs_nindex = info.x12C; + ctempl_explicitargs_num = info.count; + ctempl_explicitargs_all = 1; + + if (!CTempl_TypeNeedsDeduction(TYPE_FUNC(funcobj->type)->functype)) + return NULL; + + if (!CTempl_DeduceType(TYPE_FUNC(funcobj->type)->functype, TYPE_FUNC(funcobj->type)->qual, type, qual, info.args, 0, 1)) + return NULL; + + for (i = 0; i < info.maxCount; i++) { + if (!info.args[i].is_deduced) + return 0; + info.args[i].next = &info.args[i + 1]; + } + info.args[info.maxCount].next = NULL; + + return CTempl_GetCreateFuncInstance(funcobj, info.args, NULL)->object; +} + +static int CTemplFunc_TemplateNestLevel(NameSpace *nspace) { + int level = 0; + + while (nspace) { + if (nspace->theclass && (nspace->theclass->flags & CLASS_IS_TEMPL_ANY)) + level++; + nspace = nspace->parent; + } + + return level; +} + +static Boolean CTemplFunc_SameFuncType(TypeFunc *a, TypeFunc *b) { + FuncArg *arg1; + FuncArg *arg2; + + CError_ASSERT(1800, IS_TYPE_FUNC(a) && IS_TYPE_FUNC(b)); + + if (!is_typesame(a->functype, b->functype)) + return 0; + + if (a->qual != b->qual) + return 0; + + if ((a->flags & FUNC_CALL_CONV_MASK) != (b->flags & FUNC_CALL_CONV_MASK)) + return 0; + + arg1 = a->args; + if ((a->flags & FUNC_METHOD) && !TYPE_METHOD(a)->is_static) { + CError_ASSERT(1808, arg1); + arg1 = arg1->next; + } + + arg2 = b->args; + if ((b->flags & FUNC_METHOD) && !TYPE_METHOD(b)->is_static) { + CError_ASSERT(1814, arg2); + arg2 = arg2->next; + } + + return is_arglistsame(arg1, arg2); +} + +Object *CTempl_TemplateFunctionCheck(DeclInfo *di, NameSpaceObjectList *nsol) { + TemplArg *arg; + TemplFuncInstance *inst; + Object *object; + + for (arg = di->expltargs; arg; arg = arg->next) { + switch (arg->pid.type) { + case TPT_TYPE: + if (CTemplTool_IsTemplateArgumentDependentType(arg->data.typeparam.type)) + break; + continue; + case TPT_NONTYPE: + if (CTemplTool_IsTemplateArgumentDependentExpression(arg->data.paramdecl.expr)) + break; + continue; + default: + CError_FATAL(1844); + } + + break; + } + + if (arg) { + while (nsol) { + object = OBJECT(nsol->object); + if ( + object->otype == OT_OBJECT && + IS_TEMPL_FUNC(object->type) && + CTemplTool_IsSameTemplate(CTemplTool_GetFuncTempl(object)->params, di->expltargs) && + CTemplFunc_SameFuncType(TYPE_FUNC(OBJECT(nsol->object)->type), TYPE_FUNC(di->thetype)) + ) + return OBJECT(nsol->object); + + nsol = nsol->next; + } + } else { + while (nsol) { + object = OBJECT(nsol->object); + if ( + object->otype == OT_OBJECT && + IS_TEMPL_FUNC(object->type) && + (inst = CTempl_DeduceFunc(object, TYPE_FUNC(di->thetype), di->expltargs, NULL, 1)) + ) + { + if (di->x3C) { + if (!(di->qual & Q_INLINE)) { + if (!inst->is_specialized) + inst->object->qual &= ~Q_INLINE; + } else { + inst->object->qual |= Q_INLINE; + } + + if (!inst->is_specialized && inst->is_instantiated) + CError_Error(CErrorStr335); + + if (di->x3C != (CTemplFunc_TemplateNestLevel(inst->object->nspace) + 1)) + CError_Warning(CErrorStr335); + + inst->is_specialized = 1; + di->x3C = 0; + } + + CTemplTool_MergeArgNames(TYPE_FUNC(di->thetype), TYPE_FUNC(inst->object->type)); + di->x38 = CTemplTool_GetFuncTempl(OBJECT(nsol->object)); + return inst->object; + } + nsol = nsol->next; + } + } + + CError_ResetErrorSkip(); + CError_Error(CErrorStr335); + di->x3C = 0; + return NULL; +} diff --git a/compiler_and_linker/FrontEnd/C/CTemplateNew.c b/compiler_and_linker/FrontEnd/C/CTemplateNew.c new file mode 100644 index 0000000..c33534a --- /dev/null +++ b/compiler_and_linker/FrontEnd/C/CTemplateNew.c @@ -0,0 +1,1880 @@ +#include "compiler/CTemplateNew.h" +#include "compiler/CBrowse.h" +#include "compiler/CDecl.h" +#include "compiler/CError.h" +#include "compiler/CExpr.h" +#include "compiler/CFunc.h" +#include "compiler/CInit.h" +#include "compiler/CInline.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/CTemplateClass.h" +#include "compiler/CTemplateTools.h" +#include "compiler/CompilerTools.h" +#include "compiler/ObjGenMachO.h" +#include "compiler/objects.h" +#include "compiler/scopes.h" +#include "compiler/templates.h" + +TemplClass *ctempl_templates; +TemplateFunction *ctempl_templatefuncs; +TemplStack *ctempl_curinstance; +static jmp_buf ctempl_parseparse; +static Boolean ctempl_scanfuncparams; + +// forward decls +static TemplParam *CTempl_ParseParamList(NameSpace *nspace, UInt8 nindex); +static Boolean CTempl_GenClassInstance(TemplClassInst *inst, Boolean flag); + +void CTempl_Setup(void) { + ctempl_curinstance = NULL; + ctempl_templates = NULL; + ctempl_templatefuncs = NULL; + ctempl_instdepth = 0; + ctempl_scanfuncparams = 0; +} + +void CTempl_Cleanup(void) { +} + +static short CTempl_MemberParseLex(void) { + switch ((tk = lex())) { + case ';': + case '=': + case '{': + case '}': + longjmp(ctempl_parseparse, 1); + } + + return tk; +} + +static void CTempl_MemberParseTemplArgList(void) { + struct { + char ch; + char flag; + } stack[256]; + int pos; + + stack[0].ch = '>'; + stack[0].flag = 1; + pos = 0; + while (1) { + switch (CTempl_MemberParseLex()) { + case '<': + if (stack[pos].flag) { + if (pos >= 255) + longjmp(ctempl_parseparse, 1); + stack[++pos].ch = '>'; + stack[pos].flag = 1; + } + continue; + case '(': + if (pos >= 255) + longjmp(ctempl_parseparse, 1); + stack[++pos].ch = ')'; + stack[pos].flag = 0; + continue; + case '[': + if (pos >= 255) + longjmp(ctempl_parseparse, 1); + stack[++pos].ch = ']'; + stack[pos].flag = 0; + continue; + case '>': + if (!(stack[pos].flag)) + continue; + case ')': + case ']': + break; + default: + continue; + } + + if (tk != stack[pos].ch) + longjmp(ctempl_parseparse, 1); + if (--pos < 0) + break; + } +} + +static Type *CTempl_MemberParseTempl(HashNameNode *name) { + Type *type; + + type = CScope_GetTagType(cscope_current, name); + if (!type || !IS_TEMPL_CLASS(type)) + longjmp(ctempl_parseparse, 1); + + CTempl_MemberParseTemplArgList(); + if (lookahead() != TK_COLON_COLON) + return NULL; + CTempl_MemberParseLex(); + + while (1) { + switch (CTempl_MemberParseLex()) { + case TK_IDENTIFIER: + switch (lookahead()) { + case '(': + case ')': + case ';': + case '=': + case '[': + return type; + case TK_COLON_COLON: + CTempl_MemberParseLex(); + continue; + default: + return NULL; + } + break; + case '~': + case TK_OPERATOR: + return type; + default: + return NULL; + } + } +} + +static Boolean CTempl_ParseTemplateMember(void) { + HashNameNode *name; + SInt32 state; + + CPrep_UnLex(); + CPrep_TokenStreamGetState(&state); + + if (setjmp(ctempl_parseparse) == 0) { + while (1) { + switch (CTempl_MemberParseLex()) { + case TK_IDENTIFIER: + name = tkidentifier; + switch (lookahead()) { + case '<': + CTempl_MemberParseLex(); + if (CTempl_MemberParseTempl(name)) { + CError_FATAL(228); + return 1; + } + break; + case TK_COLON_COLON: + CTempl_MemberParseLex(); + while (1) { + if (CTempl_MemberParseLex() != TK_IDENTIFIER) + break; + if (lookahead() != TK_COLON_COLON) + break; + CTempl_MemberParseLex(); + } + break; + } + break; + case 0: + return 0; + default: + continue; + } + break; + } + + while (1) { + switch (CTempl_MemberParseLex()) { + case TK_IDENTIFIER: + name = tkidentifier; + if (CTempl_MemberParseLex() == '<') { + if (CTempl_MemberParseTempl(name)) { + CError_FATAL(265); + return 1; + } + } + break; + case 0: + return 0; + default: + continue; + } + break; + } + } + + CPrep_TokenStreamSetState(&state); + tk = lex(); + return 0; +} + +static Type *CTempl_ParseTemplArgType(UInt32 *resultQual) { + DeclInfo di; + + memclrw(&di, sizeof(di)); + CParser_GetDeclSpecs(&di, 0); + + if (di.storageclass) + CError_Error(CErrorStr177); + if (di.x48) + CError_Error(CErrorStr121); + + CError_QualifierCheck(di.qual & ~(Q_CONST | Q_VOLATILE | Q_PASCAL | Q_REFERENCE | Q_ALIGNED_MASK)); + + scandeclarator(&di); + if (di.name) + CError_Error(CErrorStr121); + + CTemplTool_CheckTemplArgType(di.thetype); + + *resultQual = di.qual; + return di.thetype; +} + +static ENode *CTempl_ParseTemplArgExpr(Type *type, UInt32 qual) { + ENode *expr; + ENode *copy; + + disallowgreaterthan = 1; + if (copts.old_argmatch) + expr = conv_assignment_expression(); + else + expr = assignment_expression(); + disallowgreaterthan = 0; + + if (type && !CTemplTool_IsTemplateArgumentDependentType(type) && !IS_TYPE_TEMPLDEPEXPR(expr->rtype)) { + expr = argumentpromotion(expr, type, qual, 1); + if (IS_TYPE_POINTER_ONLY(type)) { + if (ENODE_IS(expr, ETYPCON) && ENODE_IS(expr->data.monadic, EINTCONST)) + expr = expr->data.monadic; + if (ENODE_IS(expr, EINTCONST)) + expr->rtype = type; + } + } + + if (!IS_TYPE_TEMPLDEPEXPR(expr->rtype)) { + if (!copts.old_argmatch) + expr = pointer_generation(expr); + + switch (expr->type) { + case EINTCONST: + break; + case EOBJREF: + if (CParser_HasInternalLinkage2(expr->data.objref)) + CError_Error(CErrorStr357); + break; + case EOBJLIST: + CError_Error(CErrorStr199); + expr = nullnode(); + break; + default: + CError_Error(CErrorStr371); + expr = nullnode(); + } + + copy = galloc(sizeof(ENode)); + *copy = *expr; + return copy; + } else { + return CInline_CopyExpression(expr, CopyMode1); + } +} + +static Type *CTempl_ParseTemplArgTempl(TemplParam *params) { + NameResult pr; + + if ( + (tk != TK_IDENTIFIER && tk != TK_COLON_COLON) || + !CScope_ParseDeclName(&pr) || + !pr.type + ) + { + CError_Error(CErrorStr121); + tk = lex(); + return NULL; + } + + if (IS_TEMPL_CLASS(pr.type)) { + if (params && !CTemplTool_EqualParams(params->data.templparam.plist, TEMPL_CLASS(pr.type)->templ__params, 0)) { + CError_Error(CErrorStr235); + tk = lex(); + return NULL; + } + } else { + if (!CTemplTool_IsTemplateArgumentDependentType(pr.type)) + CError_Error(CErrorStr146); + } + + tk = lex(); + return pr.type; +} + +static UInt8 CTempl_GetTemplateNestIndex(NameSpace *nspace) { + UInt8 count = 0; + + while (nspace) { + if (nspace->theclass && (nspace->theclass->flags & CLASS_IS_TEMPL_ANY)) + count++; + nspace = nspace->parent; + } + + return count; +} + +static TemplParam *CTempl_ParseParam(NameSpace *nspace, TemplParam *param, UInt16 index, UInt8 nindex) { + DeclInfo di; + SInt32 savedState; + short startToken; + + param = galloc(sizeof(TemplParam)); + memclrw(param, sizeof(TemplParam)); + + param->pid.index = index; + param->pid.nindex = nindex; + + CPrep_TokenStreamGetState(&savedState); + + switch ((startToken = tk)) { + case TK_CLASS: + case TK_TYPENAME: + if ((tk = lex()) == TK_IDENTIFIER) { + param->name = tkidentifier; + tk = lex(); + } + + switch (tk) { + case ',': + case '>': + break; + case '=': + tk = lex(); + param->data.typeparam.type = CTempl_ParseTemplArgType(¶m->data.typeparam.qual); + break; + default: + param->name = NULL; + CPrep_TokenStreamSetState(&savedState); + tk = startToken; + goto defaultProc; + } + + param->pid.type = TPT_TYPE; + break; + + case TK_TEMPLATE: + if ((tk = lex()) != '<') { + CError_Error(CErrorStr230); + return NULL; + } + + tk = lex(); + param->data.templparam.plist = CTempl_ParseParamList(nspace, 0); + + if (tk == '>') + tk = lex(); + else + CError_Error(CErrorStr231); + + if (tk == TK_CLASS) + tk = lex(); + else + CError_Error(CErrorStr121); + + if (tk == TK_IDENTIFIER) { + param->name = tkidentifier; + tk = lex(); + } + + if (tk == '=') { + tk = lex(); + param->data.templparam.defaultarg = CTempl_ParseTemplArgTempl(param); + } + + param->pid.type = TPT_TEMPLATE; + break; + + default: + defaultProc: + 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_REFERENCE | Q_ALIGNED_MASK)); + + scandeclarator(&di); + + switch (di.thetype->type) { + case TYPEARRAY: + di.thetype = CDecl_NewPointerType(TPTR_TARGET(di.thetype)); + break; + case TYPEFUNC: + di.thetype = CDecl_NewPointerType(di.thetype); + break; + case TYPEMEMBERPOINTER: + CError_Error(CErrorStr190); + di.thetype = TYPE(&stsignedint); + break; + case TYPEINT: + case TYPEENUM: + case TYPETEMPLATE: + case TYPEPOINTER: + break; + default: + CError_Error(CErrorStr229); + di.thetype = TYPE(&stsignedint); + } + + di.thetype = CParser_RemoveTopMostQualifiers(di.thetype, &di.qual); + param->name = di.name; + param->data.paramdecl.type = di.thetype; + param->data.paramdecl.qual = di.qual; + if (tk == '=') { + tk = lex(); + param->data.paramdecl.defaultarg = CTempl_ParseTemplArgExpr(di.thetype, di.qual); + } + + param->pid.type = TPT_NONTYPE; + break; + } + + if (param->name) + CTemplTool_InsertTemplateParameter(nspace, param); + + return param; +} + +static TemplParam *CTempl_ParseParamList(NameSpace *nspace, UInt8 nindex) { + TemplParam *params; + TemplParam **ptr; + TemplParam *param; + TemplParam *scan; + UInt16 index; + + params = NULL; + index = 0; + ptr = ¶ms; + + while (1) { + param = CTempl_ParseParam(nspace, params, index, nindex); + if (!param) + break; + + if (param->name) { + for (scan = params; scan; scan = scan->next) { + if (scan->name == param->name) + CError_Error(CErrorStr122, param->name->name); + } + } + + *ptr = param; + ptr = ¶m->next; + + if (tk != ',') + break; + + tk = lex(); + index++; + } + + if (!params) + CError_Error(CErrorStr229); + + return params; +} + +TemplArg *CTempl_ParseUncheckTemplArgs(TemplParam *params, Boolean is_global) { + TemplArg *args; + TemplArg *last; + UInt16 index; + + if (tk != '<') { + CError_Error(CErrorStr230); + return NULL; + } + + if ((tk = lex()) == '>') + return NULL; + + args = NULL; + index = 0; + while (1) { + if (is_global) { + if (args) { + last->next = galloc(sizeof(TemplArg)); + last = last->next; + } else { + last = galloc(sizeof(TemplArg)); + args = last; + } + } else { + if (args) { + last->next = lalloc(sizeof(TemplArg)); + last = last->next; + } else { + last = galloc(sizeof(TemplArg)); + args = last; + } + } + + last->next = NULL; + + if (!params) { + Type *type; + UInt32 qual; + Boolean flag; + + last->pid.index = index; + last->pid.nindex = 0; + + if ((type = CParser_ParseTypeID(&qual, &flag))) { + if (flag) { + last->data.ttargtype = type; + last->pid.type = TPT_TEMPLATE; + } else { + last->data.typeparam.type = type; + last->data.typeparam.qual = qual; + last->pid.type = TPT_TYPE; + } + } else { + last->data.paramdecl.expr = CTempl_ParseTemplArgExpr(NULL, 0); + last->pid.type = TPT_NONTYPE; + } + } else { + last->pid = params->pid; + switch (last->pid.type) { + case TPT_TYPE: + last->data.typeparam.type = CTempl_ParseTemplArgType(&last->data.typeparam.qual); + break; + case TPT_NONTYPE: + last->data.paramdecl.expr = CTempl_ParseTemplArgExpr(NULL, 0); + break; + case TPT_TEMPLATE: + if (!(last->data.ttargtype = CTempl_ParseTemplArgTempl(params))) + return NULL; + break; + default: + CError_FATAL(674); + } + params = params->next; + } + + if (tk == '>') + return args; + + if (tk != ',') { + CError_Error(CErrorStr116); + return NULL; + } + + tk = lex(); + index++; + } +} + +static TemplArg *CTempl_ParseTemplArgs(TemplClass **resultTempl, TemplArg **resultArgs) { + TemplParam *param; + TemplParam *params; + TemplArg *args; + TemplArg **ptr; + TemplArg *arg; + + params = (*resultTempl)->templ__params; + *resultArgs = NULL; + + if (tk != '<') { + CError_Error(CErrorStr230); + return NULL; + } + + tk = lex(); + + param = params; + args = NULL; + ptr = &args; + + while (param) { + arg = galloc(sizeof(TemplArg)); + memclrw(arg, sizeof(TemplArg)); + + *ptr = arg; + ptr = &arg->next; + + arg->pid = param->pid; + + if (tk != '>') { + switch (arg->pid.type) { + case TPT_TYPE: + arg->data.typeparam.type = CTempl_ParseTemplArgType(&arg->data.typeparam.qual); + break; + + case TPT_NONTYPE: + if (CTemplTool_IsTemplateArgumentDependentType(param->data.paramdecl.type)) { + Type *type; + UInt32 qual; + + type = CTemplTool_DeduceArgDepType(args, param->data.paramdecl.type, param->data.paramdecl.qual, &qual); + arg->data.paramdecl.expr = CTempl_ParseTemplArgExpr(type, qual); + } else { + arg->data.paramdecl.expr = CTempl_ParseTemplArgExpr(param->data.paramdecl.type, param->data.paramdecl.qual); + } + break; + + case TPT_TEMPLATE: + if (!(arg->data.ttargtype = CTempl_ParseTemplArgTempl(param))) + return NULL; + break; + + default: + CError_FATAL(742); + } + + if (tk != '>') { + if (tk != ',') { + CError_Error(CErrorStr232); + return NULL; + } + + if ((tk = lex()) == '>') { + CError_Error(CErrorStr232); + return NULL; + } + } + } else { + switch (arg->pid.type) { + case TPT_TYPE: + if (!param->data.typeparam.type) { + CError_Error(CErrorStr232); + return NULL; + } + + arg->data.typeparam.type = param->data.typeparam.type; + arg->data.typeparam.qual = param->data.typeparam.qual; + + if (CTemplTool_IsTemplateArgumentDependentType(param->data.typeparam.type)) { + TypeDeduce deduce; + memclrw(&deduce, sizeof(deduce)); + deduce.tmclass = *resultTempl; + deduce.inst = NULL; + deduce.params = params; + deduce.args = args; + + arg->data.typeparam.qual = param->data.typeparam.qual; + arg->data.typeparam.type = CTemplTool_DeduceTypeCopy(&deduce, arg->data.typeparam.type, &arg->data.typeparam.qual); + } + break; + + case TPT_NONTYPE: + if (!param->data.paramdecl.defaultarg) { + CError_Error(CErrorStr232); + return NULL; + } + + if (IS_TYPE_TEMPLDEPEXPR(param->data.paramdecl.defaultarg->rtype)) { + TypeDeduce deduce; + memclrw(&deduce, sizeof(deduce)); + deduce.tmclass = *resultTempl; + deduce.inst = NULL; + deduce.params = params; + deduce.args = args; + + arg->data.paramdecl.expr = CInline_CopyExpression( + CTemplTool_DeduceExpr(&deduce, param->data.paramdecl.defaultarg), CopyMode1); + } else { + arg->data.paramdecl.expr = param->data.paramdecl.defaultarg; + } + break; + + case TPT_TEMPLATE: + if (!param->data.templparam.defaultarg) { + CError_Error(CErrorStr232); + return NULL; + } + + if (IS_TEMPL_CLASS(param->data.templparam.defaultarg)) { + arg->data.ttargtype = param->data.templparam.defaultarg; + break; + } + + if (CTemplTool_IsTemplateArgumentDependentType(param->data.templparam.defaultarg)) { + CError_Error(CErrorStr190); + return NULL; + } + + CError_FATAL(817); + + default: + CError_FATAL(820); + } + } + + param = param->next; + } + + if (tk != '>') { + CError_Error(CErrorStr231); + return NULL; + } + + if ((*resultTempl)->pspecs) + return args; + + return args; +} + +Type *CTempl_ParseTemplTemplParam(TypeTemplDep *type) { + TemplArg *args; + Type *newType; + + tk = lex(); + if (!(args = CTempl_ParseUncheckTemplArgs(NULL, 1))) { + CError_Error(CErrorStr121); + return TYPE(&stsignedint); + } + + newType = CDecl_NewTemplDepType(TEMPLDEP_QUALTEMPL); + TYPE_TEMPLATE(newType)->u.qualtempl.type = type; + TYPE_TEMPLATE(newType)->u.qualtempl.args = args; + return newType; +} + +Type *CTempl_ClassGetType(TemplClass *templ) { + TemplClass *owner; + TemplArg *ownerArgs; + TemplArg *args; + Type *type; + + owner = templ; + if (templ->pspec_owner) + owner = templ->pspec_owner; + + if (!(args = CTempl_ParseTemplArgs(&owner, &ownerArgs))) + return &stvoid; + + if ((type = CTemplTool_IsDependentTemplate(owner, args))) + return type; + + return TYPE(CTemplClass_GetInstance(owner, args, ownerArgs)); +} + +static void CTempl_SetupClassParamNameSpace(DeclFucker *what_is_this, TypeClass *tclass) { + cscope_current = tclass->nspace; +} + +Boolean CTempl_IsQualifiedMember(DeclInfo *di, Type *type, NameSpace **resultnspace) { + if ( + TYPE_TEMPLATE(type)->dtype == TEMPLDEP_QUALNAME && + (type = CTemplTool_GetSelfRefTemplate(TYPE(TYPE_TEMPLATE(type)->u.qual.type))) + ) + { + *resultnspace = TYPE_CLASS(type)->nspace; + CError_ASSERT(948, di->fucker34 && (*resultnspace)->theclass); + + CTempl_SetupClassParamNameSpace(di->fucker34, (*resultnspace)->theclass); + di->fucker34 = NULL; + return 1; + } + + return 0; +} + +static void *CTempl_ParseMemberFunction(int unk1, int unk2, int unk3, Object *func) { + // no idea what should've been here, it's not called + + CError_ASSERT(974, TYPE_FUNC(func->type)->flags & FUNC_METHOD); + + return NULL; +} + +static void CTempl_ParseMember(TemplParam *params, TemplClass *templ, DeclInfo *di, SInt32 *startOffset) { + Object *object; + NameSpaceObjectList *nsol; + TokenStream stream; + CPrepFileInfo *file; + SInt32 offset; + Boolean saveForceLoc; + TemplateMember *member; + + if (templ->theclass.flags & CLASS_IS_TEMPL) + di->thetype = CTemplTool_ResolveMemberSelfRefs(templ, di->thetype, &di->qual); + + if (IS_TYPE_FUNC(di->thetype)) { + Boolean flag; + if (!(object = CDecl_GetFunctionObject(di, NULL, &flag, 0))) { + CError_Error(CErrorStr140, di->name->name); + return; + } + + if (tk != '{' && tk != TK_TRY && tk != ':') { + if (tk != ';') + CError_Error(CErrorStr123); + else + tk = lex(); + return; + } + + if ( + (TYPE_FUNC(object->type)->flags & FUNC_DEFINED) && + (!(TYPE_FUNC(object->type)->flags & FUNC_IS_TEMPL) || object->u.func.u.templ->instances) + ) + CError_Error(CErrorStr333, object); + + TYPE_FUNC(object->type)->flags |= FUNC_IS_TEMPL_INSTANCE | FUNC_DEFINED; + + CPrep_StreamGetBlock(&stream, NULL, 1); + saveForceLoc = gForceSourceLoc; + gForceSourceLoc = 1; + CPrep_BrowserFilePosition(&file, &offset); + gForceSourceLoc = saveForceLoc; + + if (file && file->recordbrowseinfo && *startOffset >= 0 && offset > *startOffset) + CBrowse_NewFunction(object, file, file, *startOffset, offset + 1); + } else { + if (!(nsol = CScope_GetLocalObject(templ->theclass.nspace, di->name))) { + CError_Error(CErrorStr140, di->name->name); + return; + } + + object = OBJECT(nsol->object); + if (object->otype != OT_OBJECT) { + CError_Error(CErrorStr122, di->name->name); + return; + } + + if ( + !is_typesame(di->thetype, object->type) || + (object->qual & (Q_CONST | Q_VOLATILE | Q_PASCAL)) != (di->qual & (Q_CONST | Q_VOLATILE | Q_PASCAL)) + ) + { + CError_Error(CErrorStr249, CError_GetObjectName(object), object->type, object->qual, di->thetype, di->qual); + return; + } + + CError_ASSERT(1070, object->datatype == DDATA); + + CPrep_StreamGetSemicolon(&stream, NULL); + } + + if (stream.tokens) { + if (IS_TEMPL_FUNC(object->type) != 0) { + if (!CTemplTool_EqualParams(object->u.func.u.templ->params, params, 0)) + CError_Error(CErrorStr235); + + object->u.func.u.templ->stream = stream; + } else { + if (!(templ->theclass.flags & CLASS_IS_TEMPL)) { + CError_Error(CErrorStr190); + return; + } + + member = CTemplClass_DefineMember(templ, object, &cparser_fileoffset, &stream); + if (templ->templ__params) { + if (!CTemplTool_EqualParams(templ->templ__params, params, 0)) { + CError_Error(CErrorStr235); + return; + } + + member->params = params; + } + } + } +} + +static TemplateFunction *CTempl_DeclareTemplateFunction(DeclInfo *di, TemplParam *params, TypeClass *tclass, AccessType access, Boolean flag) { + TemplateFunction *templ; + Object *object; + + if (tclass) { + CError_ASSERT(1122, cscope_current->theclass); + di->thetype = TYPE(CDecl_MakeTypeMemberFunc(TYPE_FUNC(di->thetype), cscope_current->theclass, flag)); + } else { + access = ACCESSPUBLIC; + } + + templ = galloc(sizeof(TemplateFunction)); + memclrw(templ, sizeof(TemplateFunction)); + + templ->next = ctempl_templatefuncs; + ctempl_templatefuncs = templ; + + templ->params = params; + templ->name = di->name; + templ->deftoken = symdecltoken; + + object = CParser_NewFunctionObject(NULL); + object->access = access; + object->name = di->name; + object->u.func.linkname = CParser_GetUniqueName(); + object->type = di->thetype; + object->qual = di->qual | Q_MANGLE_NAME; + object->sclass = di->storageclass; + TYPE_FUNC(object->type)->flags |= FUNC_IS_TEMPL; + object->u.func.u.templ = templ; + + if (di->qual & Q_INLINE) + object->sclass = TK_STATIC; + + templ->tfunc = object; + CScope_AddObject(cscope_current, di->name, OBJ_BASE(object)); + + return templ; +} + +static void CTempl_ParseTemplateFunction(TemplateFunction *templ, TypeClass *tclass, SInt32 *startOffset) { + Object *object; + CPrepFileInfo *file; + SInt32 offset; + Boolean saveForceLoc; + + object = templ->tfunc; + + if (tk == '{' || tk == ':' || tk == TK_TRY) { + if (tclass) { + object->qual |= Q_INLINE; + object->sclass = TK_STATIC; + } + + if (TYPE_FUNC(object->type)->flags & FUNC_DEFINED) + CError_Error(CErrorStr333, object); + + TYPE_FUNC(object->type)->flags |= FUNC_DEFINED | FUNC_IS_TEMPL_INSTANCE; + + CPrep_StreamGetBlock(&templ->stream, NULL, 0); + + if (lookahead() == ';') + tk = lex(); + else + tk = ';'; + + saveForceLoc = gForceSourceLoc; + gForceSourceLoc = 1; + CPrep_BrowserFilePosition(&file, &offset); + gForceSourceLoc = saveForceLoc; + + if (file && *startOffset >= 0 && offset > *startOffset) { + templ->srcfile = file; + templ->startoffset = *startOffset; + templ->endoffset = offset + 1; + if (cparamblkptr->browseoptions.recordTemplates && file->recordbrowseinfo) + CBrowse_NewTemplateFunc(templ); + } + + } else { + if (tk != ';') + CError_Error(CErrorStr121); + } +} + +static HashNameNode *CTempl_FindConversionFuncName(TypeClass *tclass, Type *type, UInt32 qual) { + Object *object; + CScopeObjectIterator iter; + + CScope_InitObjectIterator(&iter, tclass->nspace); + do { + if (!(object = OBJECT(CScope_NextObjectIteratorObject(&iter)))) + return NULL; + } while ( + !IS_TYPE_FUNC(object->type) || + !(TYPE_FUNC(object->type)->flags & FUNC_CONVERSION) || + (TYPE_FUNC(object->type)->qual & (Q_CONST | Q_VOLATILE)) != (qual & (Q_CONST | Q_VOLATILE)) || + !is_typesame(TYPE_FUNC(object->type)->functype, type) + ); + + return object->name; +} + +static void CTempl_ParseConversionFunctionTemplate(DeclInfo *di, DeclFucker *what_is_this, TemplParam *params, TypeClass *tclass, SInt32 *startOffset, AccessType access) { + tk = lex(); + if (!tclass) { + CError_Error(CErrorStr121); + return; + } + + tclass->flags = tclass->flags | CLASS_IS_CONVERTIBLE; + CError_QualifierCheck(di->qual & ~Q_INLINE); + + conversion_type_name(di); + CDecl_NewConvFuncType(di); + + if (cscope_current->is_templ) { + CError_ASSERT(1260, cscope_current == what_is_this->nspace); + cscope_current = what_is_this->nspace->parent; + } + + CTempl_ParseTemplateFunction(CTempl_DeclareTemplateFunction(di, params, tclass, access, 0), tclass, startOffset); +} + +static void CTempl_ParseFunctionOrMemberTemplate(DeclFucker *what_is_this, TemplParam *params, TypeClass *tclass, SInt32 *startOffset, AccessType access, Boolean mysteryFlag) { + NameSpaceObjectList *nsol; + Object *object; + TemplParam *param; + TemplateFunction *templfunc; + Boolean disallowCVFlag; + TypeClass *tclass2; + Type *type; + UInt32 qual; + DeclInfo di; + + for (param = params; param; param = param->next) { + switch (param->pid.type) { + case TPT_TYPE: + if (param->data.typeparam.type) { + CError_Error(CErrorStr378); + param->data.typeparam.type = NULL; + } + break; + case TPT_NONTYPE: + if (param->data.paramdecl.defaultarg) { + CError_Error(CErrorStr378); + param->data.paramdecl.defaultarg = NULL; + } + break; + case TPT_TEMPLATE: + if (param->data.templparam.defaultarg) { + CError_Error(CErrorStr378); + param->data.templparam.defaultarg = NULL; + } + break; + default: + CError_FATAL(1317); + } + } + + disallowCVFlag = 0; + ctempl_scanfuncparams = 1; + + memclrw(&di, sizeof(di)); + di.x51 = mysteryFlag; + + if (tk == TK_OPERATOR) { + CTempl_ParseConversionFunctionTemplate(&di, what_is_this, params, tclass, startOffset, access); + return; + } + + CParser_GetDeclSpecs(&di, 1); + if (tk == ';' && IS_TEMPL_CLASS(di.thetype)) + return; + + if (di.x10 || di.x14) { + TypeFunc *tfunc; + + if (di.x14) { + di.x10 = OBJECT(di.x14->object); + CError_ASSERT(1342, di.x10->otype == OT_OBJECT); + } + + CError_ASSERT(1344, IS_TYPE_FUNC(di.x10->type)); + + tfunc = TYPE_FUNC(di.x10->type); + if (tfunc->flags & FUNC_CONVERSION) { + di.thetype = tfunc->functype; + di.qual |= tfunc->qual; + di.nspace = di.x10->nspace; + di.name = di.x10->name; + } else if (tfunc->flags & FUNC_IS_CTOR) { + di.thetype = TYPE(&void_ptr); + di.nspace = di.x10->nspace; + di.name = di.x10->name; + } else { + CError_Error(CErrorStr121); + return; + } + + if ((tk = lex()) == '(') { + tk = lex(); + CDecl_ParseDirectFuncDecl(&di); + if (IS_TYPE_FUNC(di.thetype)) + goto skipPastStuff; + } else { + CError_Error(CErrorStr114); + } + } + + if (di.storageclass) { + if (tclass) { + if (di.storageclass == TK_STATIC) + disallowCVFlag = 1; + else + CError_Error(CErrorStr177); + di.storageclass = 0; + } else { + if (di.storageclass != TK_STATIC && di.storageclass != TK_EXTERN) { + CError_Error(CErrorStr177); + di.storageclass = 0; + } + } + } + + CError_QualifierCheck(di.qual & ~(Q_CONST | Q_VOLATILE | Q_ASM | Q_PASCAL | Q_INLINE | Q_EXPLICIT | Q_20000 | Q_WEAK | Q_ALIGNED_MASK)); + + if (tk == TK_OPERATOR && di.x4A) { + CTempl_ParseConversionFunctionTemplate(&di, what_is_this, params, tclass, startOffset, access); + return; + } + + if (!di.x53) { + if (tclass && IS_TYPE_CLASS(di.thetype) && TYPE_CLASS(di.thetype) == tclass && tk == '(') { + CError_ASSERT(1418, cscope_current == tclass->nspace); + CError_QualifierCheck(di.qual & ~(Q_INLINE | Q_EXPLICIT)); + + di.thetype = TYPE(&void_ptr); + di.x4B = 1; + + tk = lex(); + CDecl_ParseDirectFuncDecl(&di); + + if (IS_TYPE_FUNC(di.thetype)) { + if (TYPE_FUNC(di.thetype)->args && !TYPE_FUNC(di.thetype)->args->next && TYPE_FUNC(di.thetype)->args->type == TYPE(tclass)) { + CError_Error(CErrorStr239); + TYPE_FUNC(di.thetype)->args = NULL; + } + + if (tclass->flags & CLASS_HAS_VBASES) + CDecl_AddArgument(TYPE_FUNC(di.thetype), TYPE(&stsignedshort)); + + TYPE_FUNC(di.thetype)->flags |= FUNC_IS_CTOR; + di.name = constructor_name_node; + + what_is_this->nspace->tparams = NULL; + + CTempl_ParseTemplateFunction( + CTempl_DeclareTemplateFunction(&di, params, tclass, access, disallowCVFlag), + tclass, startOffset); + + return; + } else { + CError_Error(CErrorStr241); + } + } + + if (IS_TYPE_TEMPLATE(di.thetype)) { + if ( + tk == '(' && + TYPE_TEMPLATE(di.thetype)->dtype == TEMPLDEP_QUALNAME && + (tclass2 = TYPE_CLASS(CTemplTool_GetSelfRefTemplate(TYPE(TYPE_TEMPLATE(di.thetype)->u.qual.type)))) && + TYPE_TEMPLATE(di.thetype)->u.qual.name == tclass2->classname + ) + { + if (tclass) + CError_Error(CErrorStr229); + + di.thetype = TYPE(&void_ptr); + di.x4B = 1; + + CTempl_SetupClassParamNameSpace(what_is_this, tclass2); + + tk = lex(); + CDecl_ParseDirectFuncDecl(&di); + + if (IS_TYPE_FUNC(di.thetype)) { + di.name = constructor_name_node; + if (tclass2->flags & CLASS_HAS_VBASES) + CDecl_AddArgument(TYPE_FUNC(di.thetype), TYPE(&stsignedshort)); + + TYPE_FUNC(di.thetype)->flags |= FUNC_IS_CTOR; + CTempl_ParseMember(params, TEMPL_CLASS(tclass2), &di, startOffset); + } else { + CError_Error(CErrorStr241); + } + + return; + } + + if ( + tk == TK_COLON_COLON && + TYPE_TEMPLATE(di.thetype)->dtype == TEMPLDEP_TEMPLATE && + (tclass2 = TYPE_CLASS(CTemplTool_GetSelfRefTemplate(di.thetype))) + ) + { + if (tclass) + CError_Error(CErrorStr229); + + if ((tk = lex()) == '~') { + if ( + (tk = lex()) != TK_IDENTIFIER || + tkidentifier != tclass2->classname || + (tk = lex()) != '(' + ) + { + if (tk == '<') { + DeclInfo di2; + + CPrep_UnLex(); + tk = TK_IDENTIFIER; + tkidentifier = tclass2->classname; + + memclrw(&di2, sizeof(di2)); + CParser_GetDeclSpecs(&di2, 0); + if (tk != '(') + CError_Error(CErrorStr241); + + if (di2.thetype != TYPE(tclass2) && (!IS_TYPE_TEMPLATE(di2.thetype) || CTemplTool_IsTemplate( + TYPE_TEMPLATE(di2.thetype)) != TEMPL_CLASS(tclass2))) + { + CError_Error(CErrorStr241); + } + } else { + CError_Error(CErrorStr241); + } + } + + di.thetype = TYPE(&void_ptr); + + CTempl_SetupClassParamNameSpace(what_is_this, tclass2); + tk = lex(); + CDecl_ParseDirectFuncDecl(&di); + + if (IS_TYPE_FUNC(di.thetype)) { + if (tclass2->sominfo) + di.qual |= Q_VIRTUAL; + else + CDecl_AddArgument(TYPE_FUNC(di.thetype), TYPE(&stsignedshort)); + + di.name = destructor_name_node; + TYPE_FUNC(di.thetype)->flags |= FUNC_IS_DTOR; + CTempl_ParseMember(params, TEMPL_CLASS(tclass2), &di, startOffset); + } else { + CError_Error(CErrorStr241); + } + } else if (tk == TK_OPERATOR) { + CTempl_SetupClassParamNameSpace(what_is_this, tclass2); + if (CMangler_OperatorName((tk = lex()))) { + CError_Error(CErrorStr349); + return; + } + + CError_QualifierCheck(di.qual & ~(Q_INLINE | Q_VIRTUAL)); + conversion_type_name(&di); + + type = di.thetype; + qual = di.qual; + CDecl_NewConvFuncType(&di); + + if (CTemplTool_IsTemplateArgumentDependentType(type)) { + di.name = CTempl_FindConversionFuncName(tclass2, type, qual); + if (!di.name) { + CError_Error(CErrorStr150, "conversion function"); + return; + } + } + CTempl_ParseMember(params, TEMPL_CLASS(tclass2), &di, startOffset); + } else { + CError_Error(CErrorStr121); + } + + return; + } + + if (TYPE_TEMPLATE(di.thetype)->dtype == TEMPLDEP_QUALNAME && !di.x49) + CError_Warning(CErrorStr355); + } + } + + di.x30 = params; + di.fucker34 = what_is_this; + scandeclarator(&di); + ctempl_scanfuncparams = 0; + +skipPastStuff: + if (cscope_current->is_templ) { + CError_ASSERT(1589, cscope_current == what_is_this->nspace); + what_is_this->nspace->tparams = NULL; + } + + if (!di.name) { + CError_Error(CErrorStr229); + return; + } + + if (di.nspace) { + if (di.nspace->theclass) { + if (tclass) + CError_Error(CErrorStr229); + CTempl_ParseMember(params, TEMPL_CLASS(di.nspace->theclass), &di, startOffset); + return; + } + + if (!IS_TYPE_FUNC(di.thetype)) { + CError_Error(CErrorStr229); + return; + } + + CScope_FindName(di.nspace, di.name); + } else { + if (!IS_TYPE_FUNC(di.thetype)) { + CError_Error(CErrorStr229); + return; + } + + CScope_FindName(cscope_current, di.name); + } + + nsol = CScope_FindName(di.nspace ? di.nspace : cscope_current, di.name); + while (nsol) { + object = OBJECT(nsol->object); + if (object->otype == OT_OBJECT && IS_TEMPL_FUNC(object->type)) { + templfunc = CTemplTool_GetFuncTempl(object); + if (CTemplTool_EqualParams(templfunc->params, params, 0) && is_typesame(object->type, di.thetype)) { + if (tk != ';' && templfunc->stream.tokens) + CError_Error(CErrorStr234); + + if (tk == '{' || tk == ':' || tk == TK_TRY) + CError_ASSERT(1654, CTemplTool_EqualParams(templfunc->params, params, 1)); + + if (di.qual & Q_INLINE) + object->qual |= Q_INLINE; + TYPE_FUNC(object->type)->args = TYPE_FUNC(di.thetype)->args; + break; + } + } + nsol = nsol->next; + } + + if (!nsol) { + if (di.nspace) + CError_Error(CErrorStr229); + templfunc = CTempl_DeclareTemplateFunction(&di, params, tclass, access, disallowCVFlag); + } + + CTempl_ParseTemplateFunction(templfunc, tclass, startOffset); +} + +static void CTempl_ExplicitInstantiation(void) { + Boolean flag; + short saveToken; + Object *object; + DeclInfo di; + + memclrw(&di, sizeof(di)); + di.x51 = 1; + flag = 1; + + if (tk == TK_IDENTIFIER && !strcmp(tkidentifier->name, "__dont_instantiate")) { + flag = 0; + tk = lex(); + } + + switch (tk) { + case TK_STRUCT: + case TK_UNION: + case TK_CLASS: + memclrw(&di, sizeof(di)); + CParser_GetDeclSpecs(&di, 0); + if (tk == ';') { + if (IS_TEMPL_CLASS_INST(di.thetype)) { + CTempl_InstantiateTemplateClass(TYPE_CLASS(di.thetype)); + if ((TYPE_CLASS(di.thetype)->flags & CLASS_COMPLETED) && !(TYPE_CLASS(di.thetype)->eflags & CLASS_EFLAGS_IMPORT)) { + if (flag) + CTempl_GenClassInstance(TEMPL_CLASS_INST(di.thetype), 1); + else + TEMPL_CLASS_INST(di.thetype)->is_extern = 1; + } else { + CError_Error(CErrorStr136, TYPE_CLASS(di.thetype), 0); + } + } else { + CError_Error(CErrorStr238); + } + return; + } + break; + default: + memclrw(&di, sizeof(di)); + CParser_GetDeclSpecs(&di, 0); + } + + di.x51 = 1; + + scandeclarator(&di); + + saveToken = tk; + + di.x38 = NULL; + if ( + di.name && + IS_TYPE_FUNC(di.thetype) && + (object = CDecl_GetFunctionObject(&di, di.nspace, NULL, 1)) && + IS_TYPE_FUNC(object->type) && + object->u.func.inst && + di.x38 + ) + { + if (!flag) + object->u.func.inst->is_extern = 1; + else + CTempl_GenFuncInstance(di.x38, object->u.func.inst, 1); + } else { + CError_Error(CErrorStr238); + } + + if (saveToken != ';') + CError_Error(CErrorStr123); +} + +static void CTempl_ExplicitSpecialization(void) { + Boolean flag; + TemplParam *params; + int counter; + DeclFucker what_is_this; + DeclInfo di; + + flag = 0; + counter = 1; + while (tk == TK_TEMPLATE) { + if ((tk = lex()) != '<') { + CError_Error(CErrorStr230); + break; + } + + if ((tk = lex()) != '>') { + if (!flag) { + what_is_this.nspace = cscope_current; + what_is_this.mystery4 = NULL; + cscope_current->tparams = NULL; + flag = 1; + } + + params = CTempl_ParseParamList(what_is_this.nspace, counter); + if (tk != '>') + CError_Error(CErrorStr231); + } else { + if (flag) + CError_Error(CErrorStr335); + } + + counter++; + tk = lex(); + } + + if (flag) { + SInt32 startOffset = -1; + CTempl_ParseFunctionOrMemberTemplate(&what_is_this, params, NULL, &startOffset, ACCESSPUBLIC, 1); + return; + } + + memclrw(&di, sizeof(di)); + di.x3C = counter; + di.x51 = 1; + CParser_GetDeclSpecs(&di, 1); + + if (tk == ';') { + if (IS_TEMPL_CLASS_INST(di.thetype)) + TEMPL_CLASS_INST(di.thetype)->is_specialized = 1; + else + CError_Error(CErrorStr335); + } else { + scandeclaratorlist(&di); + if ((tk != ';' && tk != '}') || di.x3C) + CError_Error(CErrorStr335); + } + + if (flag) + what_is_this.nspace->tparams = NULL; +} + +void CTempl_Parse(TemplClass *templ, AccessType access) { + TemplParam *params; + UInt8 i; + short mode; + Boolean flag; + UInt8 classDeclSpec; + SInt32 startOffset; + SInt32 savedState; + CScopeSave savedScope; + DeclFucker what_is_this; + + startOffset = CPrep_BrowserFileOffset(); + CScope_GetScope(&savedScope); + + if ((tk = lex()) != '<') { + if (templ) + CError_Error(CErrorStr238); + CTempl_ExplicitInstantiation(); + CScope_RestoreScope(&savedScope); + return; + } + + if ((tk = lex()) == '>') { + if (templ) + CError_Error(CErrorStr335); + tk = lex(); + CTempl_ExplicitSpecialization(); + CScope_RestoreScope(&savedScope); + return; + } + + what_is_this.nspace = cscope_current; + what_is_this.mystery4 = NULL; + cscope_current->tparams = NULL; + i = CTempl_GetTemplateNestIndex(what_is_this.nspace); + + while (1) { + params = CTempl_ParseParamList(what_is_this.nspace, i); + if (tk != '>') + CError_Error(CErrorStr231); + + if ((tk = lex()) != TK_TEMPLATE) + break; + + if (templ) + CError_Error(CErrorStr121); + + if ((tk = lex()) != '<') + CError_Error(CErrorStr230); + else + tk = lex(); + + i++; + } + + switch (tk) { + case TK_CLASS: + mode = CLASS_MODE_CLASS; + break; + case TK_UNION: + mode = CLASS_MODE_UNION; + break; + case TK_STRUCT: + mode = CLASS_MODE_STRUCT; + break; + default: + mode = -1; + } + + if (mode >= 0) { + classDeclSpec = 0; + flag = 0; + + CPrep_TokenStreamGetState(&savedState); + if ((tk = lex()) == TK_UU_DECLSPEC) + CDecl_ParseClassDeclSpec(&classDeclSpec); + + if (tk == TK_IDENTIFIER) { + if ((tk = lex()) == '<') { + if (setjmp(ctempl_parseparse) == 0) { + CTempl_MemberParseTemplArgList(); + flag = 1; + tk = lex(); + } + } + + switch (tk) { + case ':': + case ';': + case '{': + CPrep_TokenStreamSetCurState(&savedState); + if (flag) + CTemplClass_ParsePartialSpecialization(&what_is_this, params, mode, &startOffset); + else + CTemplClass_ParseClass(&what_is_this, params, mode, &startOffset); + goto done; + } + } + + CPrep_TokenStreamSetCurState(&savedState); + } + + CTempl_ParseFunctionOrMemberTemplate(&what_is_this, params, TYPE_CLASS(templ), &startOffset, access, 0); + +done: + what_is_this.nspace->tparams = NULL; + CScope_RestoreScope(&savedScope); +} + +void CTempl_ParseInstanceScopeFunction(Object *funcobj, TemplClassInst *inst, TypeClass *tclass) { + TemplParam *params; + NameSpace *nspace; + TemplateMember *member; + Object *parent; + DeclInfo di; + CScopeSave savedScope; + TemplStack stack; + + params = inst->templ->templ__params; + if (funcobj->qual & Q_IS_TEMPLATED) { + for (member = CTemplClass_GetMasterTemplate(inst->templ)->members, parent = OBJECT_TEMPL(funcobj)->parent; member; member = member->next) { + if (member->object == parent) { + if (member->params) + params = member->params; + break; + } + } + } + + CTemplTool_PushInstance(&stack, NULL, funcobj); + nspace = CTemplTool_InsertTemplateArgumentNameSpace(params, inst, &savedScope); + if (tclass) + cscope_current = tclass->nspace; + + memclrw(&di, sizeof(di)); + CFunc_ParseFuncDef(funcobj, &di, NULL, 0, 0, tclass ? cscope_current : NULL); + + CTemplTool_RemoveTemplateArgumentNameSpace(nspace, inst, &savedScope); + CTemplTool_PopInstance(&stack); +} + +Boolean CTempl_GenFuncInstance(TemplateFunction *templ, TemplFuncInstance *inst, Boolean flag) { + Boolean saveDebugInfo; + NameSpace *nspace; + SInt32 streamState; + TemplStack stack; + DeclInfo di; + + if (!flag && copts.no_implicit_templates && inst->object->sclass != TK_STATIC) + return 0; + + if (inst->is_extern && !flag) + return 0; + + while (1) { + if (templ->stream.tokens) + break; + if (!templ->unk4) + break; + templ = templ->unk4; + } + + if (!templ->stream.tokens) { + if (flag) { + CError_SetErrorToken(&templ->deftoken); + CError_Error(CErrorStr233, inst->object); + } + return 0; + } + + inst->is_instantiated = 1; + + CPrep_StreamInsert(&templ->stream, &streamState); + + saveDebugInfo = copts.filesyminfo; + if (copts.nosyminline || !templ->deftoken.tokenfile) + copts.filesyminfo = 0; + + CError_ASSERT(2112, (tk = lex()) == '{' || tk == ':' || tk == TK_TRY); + + symdecltoken = *CPrep_CurStreamElement(); + + if (copts.filesyminfo) { + CPrep_NewFileOffsetInfo(&cparser_fileoffset, &templ->deftoken); + symdecloffset = cparser_fileoffset.tokenline; + } + + if (inst->object->sclass != TK_STATIC) + inst->object->qual |= Q_WEAK; + + memclrw(&di, sizeof(di)); + di.file2 = templ->srcfile; + di.file = CPrep_BrowserCurrentFile(); + di.sourceoffset = templ->startoffset; + + CTemplTool_PushInstance(&stack, NULL, inst->object); + CTemplTool_MergeArgNames(TYPE_FUNC(templ->tfunc->type), TYPE_FUNC(inst->object->type)); + + nspace = CTemplTool_SetupTemplateArgumentNameSpace(templ->params, inst->args, 0); + nspace->parent = inst->object->nspace; + inst->object->nspace = nspace; + + CTemplTool_SetupOuterTemplateArgumentNameSpace(nspace); + CFunc_ParseFuncDef(inst->object, &di, NULL, 0, 0, nspace); + CTemplTool_RemoveOuterTemplateArgumentNameSpace(nspace); + + inst->object->nspace = nspace->parent; + + CTemplTool_PopInstance(&stack); + + CPrep_StreamRemove(&templ->stream, &streamState); + copts.filesyminfo = saveDebugInfo; + + if (di.file->recordbrowseinfo) + CBrowse_NewFunction(inst->object, di.file, di.file2, di.sourceoffset, templ->endoffset); + + return 1; +} + +void CTempl_InstantiateMember(TemplClass *templ, TemplClassInst *inst, TemplateMember *tmemb, Object *object, Boolean flag) { + Boolean saveDebugInfo; + NameSpace *nspace; + Boolean saveSourceLoc; + + DeclInfo di; + CScopeSave savedScope; + TemplStack stack; + SInt32 savedState; + + if (!flag && copts.no_implicit_templates) + return; + + CTemplTool_PushInstance(&stack, NULL, object); + nspace = CTemplTool_InsertTemplateArgumentNameSpace( + tmemb->params ? tmemb->params : templ->templ__params, inst, &savedScope); + CPrep_StreamInsert(&tmemb->stream, &savedState); + + saveSourceLoc = gForceSourceLoc; + gForceSourceLoc = 1; + symdecltoken.tokenoffset = tmemb->startoffset; + tk = lex(); + + symdecltoken = *CPrep_CurStreamElement(); + + saveDebugInfo = copts.filesyminfo; + if (copts.filesyminfo) { + CPrep_NewFileOffsetInfo(&cparser_fileoffset, &symdecltoken); + symdecloffset = cparser_fileoffset.tokenline; + } + + if (object->sclass != TK_STATIC) + object->qual |= Q_WEAK; + + memclrw(&di, sizeof(di)); + di.file2 = tmemb->srcfile; + di.file = CPrep_BrowserCurrentFile(); + di.sourceoffset = tmemb->startoffset; + + switch (object->datatype) { + case DFUNC: + case DVFUNC: + CTemplTool_MergeArgNames(TYPE_FUNC(tmemb->object->type), TYPE_FUNC(object->type)); + CFunc_ParseFuncDef(object, &di, TYPE_CLASS(inst), 0, 0, NULL); + break; + + case DDATA: + CDecl_CompleteType(object->type); + CInit_InitializeData(object); + break; + + default: + CError_FATAL(2227); + } + + CTemplTool_PopInstance(&stack); + CTemplTool_RemoveTemplateArgumentNameSpace(nspace, inst, &savedScope); + CPrep_StreamRemove(&tmemb->stream, &savedState); + copts.filesyminfo = saveDebugInfo; + gForceSourceLoc = saveSourceLoc; +} + +static Boolean CTempl_GenMemberInstance(TemplClassInst *inst, ObjectTemplated *objtempl, Boolean flag) { + TemplateMember *member; + Object *parent = objtempl->parent; + + for (member = CTemplClass_GetMasterTemplate(inst->templ)->members; member; member = member->next) { + if (member->object == parent) { + CTempl_InstantiateMember(inst->templ, inst, member, OBJECT(objtempl), flag); + return 1; + } + } + + if (flag) + CError_Warning(CErrorStr233, objtempl); + return 0; +} + +static Boolean CTempl_GenClassInstance(TemplClassInst *inst, Boolean flag) { + Object *object; + Boolean result; + CScopeObjectIterator iter; + + result = 0; + + if (!flag && copts.no_implicit_templates) + return 0; + if (!flag && inst->is_extern) + return 0; + + CScope_InitObjectIterator(&iter, inst->theclass.nspace); + while ((object = OBJECT(CScope_NextObjectIteratorObject(&iter)))) { + if (IS_TYPE_FUNC(object->type) && object->datatype != DALIAS) { + if ( + (flag || (object->flags & OBJECT_FLAGS_2)) && + !(TYPE_FUNC(object->type)->flags & (FUNC_DEFINED | FUNC_AUTO_GENERATED)) && + CTempl_GenMemberInstance(inst, OBJECT_TEMPL(object), flag) && + (TYPE_FUNC(object->type)->flags & FUNC_DEFINED) + ) + result = 1; + } else { + if ( + !inst->static_instantiated && + object->datatype == DDATA && + !(object->qual & Q_INLINE_DATA) && + !(object->flags & OBJECT_DEFINED) && + CTempl_GenMemberInstance(inst, OBJECT_TEMPL(object), flag) + ) + result = 1; + } + } + + inst->static_instantiated = 1; + return result; +} + +Boolean CTempl_Instantiate(void) { + Boolean result = 0; + TemplClass *templ; + TemplClassInst *inst; + TemplPartialSpec *pspec; + TemplFuncInstance *instf; + TemplateFunction *templf; + + for (templ = ctempl_templates; templ; templ = templ->next) { + for (inst = templ->instances; inst; inst = inst->next) { + if ( + (inst->theclass.flags & CLASS_IS_TEMPL_INST) && + !inst->is_specialized && + CTempl_GenClassInstance(inst, 0) + ) + result = 1; + } + + for (pspec = templ->pspecs; pspec; pspec = pspec->next) { + for (inst = pspec->templ->instances; inst; inst = inst->next) { + if ( + (inst->theclass.flags & CLASS_IS_TEMPL_INST) && + !inst->is_specialized && + CTempl_GenClassInstance(inst, 0) + ) + result = 1; + } + } + } + + for (templf = ctempl_templatefuncs; templf; templf = templf->next) { + for (instf = templf->instances; instf; instf = instf->next) { + if ( + !instf->is_instantiated && + !instf->is_specialized && + (instf->object->flags & OBJECT_FLAGS_2) && + !(TYPE_FUNC(instf->object->type)->flags & FUNC_DEFINED) + ) + { + instf->is_instantiated = 1; + if (CTempl_GenFuncInstance(templf, instf, 0)) + result = 1; + } + } + } + + return result; +} + +Boolean CTempl_InlineFunctionCheck(Object *funcobj) { + TemplClassInst *inst; + TemplateMember *member; + Object *parent; + + CError_ASSERT(2422, IS_TYPE_FUNC(funcobj->type) && (funcobj->qual & Q_IS_TEMPLATED)); + + if (!(TYPE_FUNC(funcobj->type)->flags & FUNC_DEFINED)) { + inst = TEMPL_CLASS_INST(TYPE_METHOD(funcobj->type)->theclass); + if (!inst->is_specialized) { + parent = OBJECT_TEMPL(funcobj)->parent; + if (parent->qual & Q_INLINE) { + for (member = CTemplClass_GetMasterTemplate(inst->templ)->members; member; member = member->next) { + funcobj->qual |= Q_INLINE; + if (member->object == parent) { + CTemplTool_MergeArgNames(TYPE_FUNC(member->object->type), TYPE_FUNC(funcobj->type)); + CInline_AddInlineFunctionAction(funcobj, TYPE_CLASS(inst), &member->fileoffset, &member->stream, 0); + return 1; + } + } + } + } + } + + return 0; +} diff --git a/compiler_and_linker/FrontEnd/C/CTemplateTools.c b/compiler_and_linker/FrontEnd/C/CTemplateTools.c new file mode 100644 index 0000000..0e77e74 --- /dev/null +++ b/compiler_and_linker/FrontEnd/C/CTemplateTools.c @@ -0,0 +1,1962 @@ +#include "compiler/CTemplateTools.h" +#include "compiler/CABI.h" +#include "compiler/CDecl.h" +#include "compiler/CError.h" +#include "compiler/CExpr.h" +#include "compiler/CFunc.h" +#include "compiler/CInline.h" +#include "compiler/CInt64.h" +#include "compiler/CMachine.h" +#include "compiler/CParser.h" +#include "compiler/CScope.h" +#include "compiler/CTemplateClass.h" +#include "compiler/CTemplateNew.h" +#include "compiler/CompilerTools.h" +#include "compiler/enode.h" +#include "compiler/objects.h" +#include "compiler/scopes.h" +#include "compiler/templates.h" +#include "compiler/types.h" + +short ctempl_instdepth; + +void CTemplTool_PushInstance(TemplStack *stack, TypeClass *tmclass, Object *func) { + if (tmclass) { + stack->u.theclass = tmclass; + stack->is_func = 0; + } else { + stack->u.func = func; + stack->is_func = 1; + } + stack->next = ctempl_curinstance; + ctempl_curinstance = stack; + + if (++ctempl_instdepth >= 64) + CError_ErrorTerm(CErrorStr314); +} + +void CTemplTool_PopInstance(TemplStack *stack) { + CError_ASSERT(53, ctempl_curinstance == stack); + + ctempl_curinstance = stack->next; + if (--ctempl_instdepth < 0) + ctempl_instdepth = 0; +} + +ENode *CTempTool_GetPTMTemplArgExpr(ENode *expr, Type *type) { + NameSpaceObjectList *list; + + CError_ASSERT(69, ENODE_IS(expr, EMEMBER)); + CError_ASSERT(70, IS_TYPE_MEMBERPOINTER(type)); + + if (!copts.cpp_extensions) { + if (!expr->data.emember->x11 || !expr->data.emember->pr_1D) + CError_Warning(CErrorStr331); + } + + type = TYPE_MEMBER_POINTER(type)->ty1; + for (list = expr->data.emember->list; list; list = list->next) { + if (list->object->otype == OT_MEMBERVAR) { + if (!is_typeequal(OBJ_MEMBER_VAR(list->object)->type, type)) + CError_Error(CErrorStr146); + return expr; + } + + if (list->object->otype == OT_OBJECT && is_memberpointerequal(OBJECT(list->object)->type, type)) { + if (expr->data.emember->list != list || list->next) { + // rewrite the EMEMBER to contain just one node + expr->data.emember->list = galloc(sizeof(NameSpaceObjectList)); + *expr->data.emember->list = *list; + expr->data.emember->list->next = NULL; + } + break; + } + } + + if (!list) + CError_Error(CErrorStr146); + + return expr; +} + +Boolean CTemplTool_InitDeduceInfo(DeduceInfo *info, TemplParam *params, TemplArg *args, Boolean flag) { + int i; + TemplArg *buffer; + TemplParam *param; + + if (!params) { + info->args = info->argBuffer; + info->maxCount = 0; + info->x12C = 0xFF; + return 1; + } + + memclrw(info, sizeof(DeduceInfo)); + + i = 0; + param = params; + while (param) { + param = param->next; + i++; + } + + if (i > 16) { + buffer = lalloc(i * sizeof(TemplArg)); + memclrw(buffer, i * sizeof(TemplArg)); + } else { + buffer = info->argBuffer; + } + info->args = buffer; + info->maxCount = i; + info->x12C = params->pid.nindex; + + for (param = params, i = 0; param; param = param->next, i++) + buffer[i].pid = param->pid; + + i = 0; + param = params; + while (args) { + if (!param || param->pid.type != args->pid.type) + return 0; + + buffer[i].data = args->data; + if (i > 0) + buffer[i - 1].next = &buffer[i]; + buffer[i].next = NULL; + buffer[i].is_deduced = 1; + info->count++; + + if (param->pid.type == TPT_NONTYPE && !CTemplTool_IsTemplateArgumentDependentType(param->data.paramdecl.type)) { + if (CExpr_CanImplicitlyConvert(buffer[i].data.paramdecl.expr, param->data.paramdecl.type, param->data.paramdecl.qual)) { + buffer[i].data.paramdecl.expr = CExpr_AssignmentPromotion( + buffer[i].data.paramdecl.expr, param->data.paramdecl.type, param->data.paramdecl.qual, 0); + } else { + return 0; + } + } + + args = args->next; + param = param->next; + i++; + } + + if (flag) { + for (param = params, i = 0; param; param = param->next, i++) { + if (!buffer[i].is_deduced && !param->name) { + switch (param->pid.type) { + case TPT_TYPE: + buffer[i].data.typeparam.type = &stvoid; + break; + case TPT_NONTYPE: + buffer[i].data.paramdecl.expr = nullnode(); + break; + case TPT_TEMPLATE: + default: + CError_FATAL(208); + } + buffer[i].is_deduced = 1; + } + } + } + + return 1; +} + +void CTemplTool_InsertTemplateParameter(NameSpace *nspace, TemplParam *param) { + Type *type; + ObjType *obj; + NameSpaceName *nsn; + + type = CDecl_NewTemplDepType(TEMPLDEP_ARGUMENT); + TYPE_TEMPLATE(type)->u.pid = param->pid; + + obj = galloc(sizeof(ObjType)); + memclrw(obj, sizeof(ObjType)); + obj->otype = OT_TYPE; + obj->access = ACCESSPUBLIC; + obj->type = type; + + for (nsn = nspace->tparams; nsn; nsn = nsn->next) { + if (nsn->name == param->name) { + CError_Error(CErrorStr122, param->name->name); + return; + } + } + + nsn = galloc(sizeof(NameSpaceName)); + memclrw(nsn, sizeof(NameSpaceName)); + + nsn->name = param->name; + nsn->first.object = OBJ_BASE(obj); + + nsn->next = nspace->tparams; + nspace->tparams = nsn; +} + +TemplArg *CTemplTool_MakeTemplArgList(DeduceInfo *info) { + TemplArg *args; + TemplArg *last; + int i; + + for (i = 0; i < info->maxCount; i++) { + if (i) { + last->next = galloc(sizeof(TemplArg)); + last = last->next; + } else { + args = last = galloc(sizeof(TemplArg)); + } + + *last = info->args[i]; + } + + last->next = NULL; + return args; +} + +Boolean CTemplTool_IsIdenticalTemplArgList(TemplArg *args, TemplParam *params) { + while (args) { + if (!params) + return 0; + + CError_ASSERT(297, params->pid.type == args->pid.type); + + switch (args->pid.type) { + case TPT_TYPE: + if ( + !IS_TYPE_TEMPLATE(args->data.typeparam.type) || + TYPE_TEMPLATE(args->data.typeparam.type)->dtype != TEMPLDEP_ARGUMENT || + TYPE_TEMPLATE(args->data.typeparam.type)->u.pid.index != params->pid.index || + TYPE_TEMPLATE(args->data.typeparam.type)->u.pid.nindex != params->pid.nindex + ) + return 0; + break; + case TPT_NONTYPE: + if ( + !ENODE_IS(args->data.paramdecl.expr, ETEMPLDEP) || + args->data.paramdecl.expr->data.templdep.subtype != TDE_PARAM || + args->data.paramdecl.expr->data.templdep.u.pid.index != params->pid.index || + args->data.paramdecl.expr->data.templdep.u.pid.nindex != params->pid.nindex + ) + return 0; + break; + case TPT_TEMPLATE: + if ( + !IS_TYPE_TEMPLATE(args->data.ttargtype) || + TYPE_TEMPLATE(args->data.ttargtype)->dtype != TEMPLDEP_ARGUMENT || + TYPE_TEMPLATE(args->data.ttargtype)->u.pid.index != params->pid.index || + TYPE_TEMPLATE(args->data.ttargtype)->u.pid.nindex != params->pid.nindex + ) + return 0; + break; + default: + CError_FATAL(331); + } + + args = args->next; + params = params->next; + } + + return !params; +} + +Type *CTemplTool_GetSelfRefTemplate(Type *type) { + TemplClass *templ; + TemplArg *args; + + CError_ASSERT(347, IS_TYPE_TEMPLATE(type)); + + if (TYPE_TEMPLATE(type)->dtype == TEMPLDEP_TEMPLATE) { + if (CTemplTool_IsIdenticalTemplArgList( + TYPE_TEMPLATE(type)->u.templ.args, + TYPE_TEMPLATE(type)->u.templ.templ->templ__params)) + return TYPE(TYPE_TEMPLATE(type)->u.templ.templ); + + if (TYPE_TEMPLATE(type)->u.templ.templ->pspecs) { + templ = TYPE_TEMPLATE(type)->u.templ.templ; + if ( + CTemplClass_FindPartialTemplate(TYPE_TEMPLATE(type)->u.templ.args, &templ, &args) && + CTemplTool_IsIdenticalTemplArgList(args, templ->templ__params) + ) + return TYPE(templ); + } + + return NULL; + } + + if (TYPE_TEMPLATE(type)->dtype == TEMPLDEP_QUALNAME) { + Type *t = CTemplTool_GetSelfRefTemplate(TYPE(TYPE_TEMPLATE(type)->u.qual.type)); + if ( + t && + (t = CScope_GetLocalTagType(TYPE_CLASS(t)->nspace, TYPE_TEMPLATE(type)->u.qual.name)) && + IS_TEMPL_CLASS(t) && + !TEMPL_CLASS(t)->templ__params + ) + return t; + + return NULL; + } + + if (TYPE_TEMPLATE(type)->dtype == TEMPLDEP_QUALTEMPL) { + Type *t; + + CError_ASSERT(389, TYPE_TEMPLATE(TYPE_TEMPLATE(type)->u.qualtempl.type)->dtype == TEMPLDEP_QUALNAME); + + t = CTemplTool_GetSelfRefTemplate(TYPE(TYPE_TEMPLATE(TYPE_TEMPLATE(type)->u.qualtempl.type)->u.qual.type)); + if ( + t && + (t = CScope_GetLocalTagType(TYPE_CLASS(t)->nspace, TYPE_TEMPLATE(TYPE_TEMPLATE(type)->u.qualtempl.type)->u.qual.name)) && + IS_TEMPL_CLASS(t) + ) + { + TemplClass *tm = TEMPL_CLASS(t); + if (CTemplTool_IsIdenticalTemplArgList(TYPE_TEMPLATE(type)->u.qualtempl.args, tm->templ__params)) + return TYPE(tm); + } + } + + return NULL; +} + +TemplateFunction *CTemplTool_GetFuncTempl(Object *object) { + while (object->datatype == DALIAS) + object = object->u.alias.object; + + CError_ASSERT(416, IS_TEMPL_FUNC(object->type)); + return object->u.func.u.templ; +} + +Boolean CTemplTool_ParamHasDefaultArg(TemplParam *param) { + switch (param->pid.type) { + case TPT_TYPE: + return param->data.typeparam.type != NULL; + case TPT_NONTYPE: + return param->data.paramdecl.defaultarg != NULL; + case TPT_TEMPLATE: + default: + CError_FATAL(438); + return 0; + } +} + +void CTemplTool_MergeDefaultArgs(TemplParam *dest, TemplParam *src) { + while (1) { + if (!dest) { + CError_ASSERT(455, !src); + return; + } + + CError_ASSERT(458, src); + CError_ASSERT(459, dest->pid.type == src->pid.type); + + switch (dest->pid.type) { + case TPT_TYPE: + if (!dest->data.typeparam.type && src->data.typeparam.type) + dest->data = src->data; + break; + case TPT_NONTYPE: + if (!dest->data.paramdecl.defaultarg && src->data.paramdecl.defaultarg) + dest->data = src->data; + break; + case TPT_TEMPLATE: + if (!dest->data.templparam.defaultarg && src->data.templparam.defaultarg) + dest->data = src->data; + break; + default: + CError_FATAL(484); + } + + dest = dest->next; + src = src->next; + } +} + +static FuncArg *CTemplTool_GetFirstRealArg(TypeFunc *tfunc) { + FuncArg *arg = tfunc->args; + + if (IS_TYPEFUNC_NONSTATIC_METHOD(tfunc)) { + CError_ASSERT(502, arg); + arg = arg->next; + if ((tfunc->flags & FUNC_IS_CTOR) && (TYPE_METHOD(tfunc)->theclass->flags & CLASS_HAS_VBASES)) { + CError_ASSERT(507, arg); + arg = arg->next; + } + } + + return arg; +} + +void CTemplTool_MergeArgNames(TypeFunc *src, TypeFunc *dest) { + FuncArg *destArg; + FuncArg *srcArg; + + CError_ASSERT(524, IS_TYPE_FUNC(dest) && IS_TYPE_FUNC(src)); + + srcArg = CTemplTool_GetFirstRealArg(src); + destArg = CTemplTool_GetFirstRealArg(dest); + + while (1) { + if (!srcArg || !destArg || srcArg == &elipsis || destArg == &elipsis) { + CError_ASSERT(531, srcArg == destArg); + break; + } + + destArg->name = srcArg->name; + srcArg = srcArg->next; + destArg = destArg->next; + } + + if (IS_TYPEFUNC_NONSTATIC_METHOD(dest)) { + CError_ASSERT(538, destArg = dest->args); + if (!destArg->name) + destArg->name = this_name_node; + } +} + +Boolean CTemplTool_EqualParams(TemplParam *a, TemplParam *b, Boolean copyNames) { + while (1) { + if (!a) + return !b; + if (!b) + return 0; + + if (a->pid.type != b->pid.type) + return 0; + + if (copyNames) + a->name = b->name; + + switch (a->pid.type) { + case TPT_TYPE: + break; + case TPT_NONTYPE: + if ( + !is_typesame(a->data.paramdecl.type, b->data.paramdecl.type) || + a->data.paramdecl.qual != b->data.paramdecl.qual + ) + return 0; + break; + case TPT_TEMPLATE: + break; + default: + CError_FATAL(576); + } + + a = a->next; + b = b->next; + } +} + +NameSpace *CTemplTool_SetupTemplateArgumentNameSpace(TemplParam *params, TemplArg *args, Boolean is_global) { + NameSpace *nspace; + Boolean clear_global; + ObjType *objType; + Object *object; + + clear_global = 0; + if (!is_global && trychain) { + clear_global = 1; + is_global = 1; + } + + nspace = CScope_NewListNameSpace(NULL, is_global); + nspace->is_templ = 1; + + if (clear_global) + nspace->is_global = 0; + + if (!params) + return nspace; + + while (params) { + CError_ASSERT(607, args); + + if (params->name) { + switch (args->pid.type) { + case TPT_TYPE: + if (is_global) { + objType = galloc(sizeof(ObjType)); + memclrw(objType, sizeof(ObjType)); + } else { + objType = lalloc(sizeof(ObjType)); + memclrw(objType, sizeof(ObjType)); + } + objType->otype = OT_TYPE; + objType->access = ACCESSPUBLIC; + objType->type = args->data.typeparam.type; + objType->qual = args->data.typeparam.qual; + CScope_AddObject(nspace, params->name, OBJ_BASE(objType)); + break; + case TPT_NONTYPE: + if (is_global) { + object = galloc(sizeof(Object)); + memclrw(object, sizeof(Object)); + } else { + object = lalloc(sizeof(Object)); + memclrw(object, sizeof(Object)); + } + object->otype = OT_OBJECT; + object->access = ACCESSPUBLIC; + object->nspace = nspace; + object->name = params->name; + object->type = args->data.paramdecl.expr->rtype; + object->qual = ENODE_QUALS(args->data.paramdecl.expr); + object->datatype = DEXPR; + object->u.expr = args->data.paramdecl.expr; + if (IS_TYPE_REFERENCE(params->data.paramdecl.type)) { + CError_ASSERT(652, IS_TYPE_POINTER_ONLY(object->u.expr->rtype)); + object->u.expr = makemonadicnode(object->u.expr, EINDIRECT); + object->u.expr->rtype = TPTR_TARGET(params->data.paramdecl.type); + } + if (is_global) + object->u.expr = CInline_CopyExpression(object->u.expr, CopyMode1); + CScope_AddObject(nspace, params->name, OBJ_BASE(object)); + break; + case TPT_TEMPLATE: + if (is_global) { + objType = galloc(sizeof(ObjType)); + memclrw(objType, sizeof(ObjType)); + } else { + objType = lalloc(sizeof(ObjType)); + memclrw(objType, sizeof(ObjType)); + } + objType->otype = OT_TYPE; + objType->access = ACCESSPUBLIC; + objType->type = args->data.ttargtype; + objType->qual = 0; + CScope_AddObject(nspace, params->name, OBJ_BASE(objType)); + break; + default: + CError_FATAL(681); + } + } + + params = params->next; + args = args->next; + } + + CError_ASSERT(685, !args); + + return nspace; +} + +void CTemplTool_SetupOuterTemplateArgumentNameSpace(NameSpace *nspace) { + NameSpace *newns; + + while (nspace) { + if (nspace->theclass && (nspace->theclass->flags & CLASS_IS_TEMPL_INST)) { + newns = CTemplTool_SetupTemplateArgumentNameSpace( + TEMPL_CLASS_INST(nspace->theclass)->templ->templ__params, + TEMPL_CLASS_INST(nspace->theclass)->inst_args, + 0); + newns->parent = nspace->parent; + nspace->parent = newns; + } + + nspace = nspace->parent; + } +} + +NameSpace *CTemplTool_InsertTemplateArgumentNameSpace(TemplParam *params, TemplClassInst *inst, CScopeSave *save) { + NameSpace *nspace = CTemplTool_SetupTemplateArgumentNameSpace(params, inst->inst_args, 0); + + nspace->parent = inst->theclass.nspace->parent; + inst->theclass.nspace->parent = nspace; + + CTemplTool_SetupOuterTemplateArgumentNameSpace(nspace); + CScope_SetNameSpaceScope(inst->theclass.nspace, save); + + return nspace; +} + +void CTemplTool_RemoveOuterTemplateArgumentNameSpace(NameSpace *nspace) { + while (nspace->parent) { + if (nspace->theclass && (nspace->theclass->flags & CLASS_IS_TEMPL_INST) && nspace->parent->is_templ) + nspace->parent = nspace->parent->parent; + nspace = nspace->parent; + } +} + +void CTemplTool_RemoveTemplateArgumentNameSpace(NameSpace *nspace, TemplClassInst *inst, CScopeSave *save) { + CTemplTool_RemoveOuterTemplateArgumentNameSpace(inst->theclass.nspace); + CScope_RestoreScope(save); +} + +Boolean CTemplTool_IsTemplateArgumentDependentType(Type *type) { + FuncArg *arg; + + while (1) { + switch (type->type) { + case TYPETEMPLATE: + return 1; + case TYPEVOID: + case TYPEINT: + case TYPEFLOAT: + case TYPEENUM: + case TYPESTRUCT: + return 0; + case TYPECLASS: + return (TYPE_CLASS(type)->flags & CLASS_IS_TEMPL) ? 1 : 0; + case TYPEMEMBERPOINTER: + if (CTemplTool_IsTemplateArgumentDependentType(TYPE_MEMBER_POINTER(type)->ty1)) + return 1; + type = TYPE_MEMBER_POINTER(type)->ty2; + continue; + case TYPEPOINTER: + case TYPEARRAY: + type = TPTR_TARGET(type); + continue; + case TYPEFUNC: + for (arg = TYPE_FUNC(type)->args; arg && arg != &elipsis && arg != &oldstyle; arg = arg->next) { + if (CTemplTool_IsTemplateArgumentDependentType(arg->type)) + return 1; + } + type = TYPE_FUNC(type)->functype; + continue; + case TYPEBITFIELD: + type = TYPE_BITFIELD(type)->bitfieldtype; + continue; + case TYPETEMPLDEPEXPR: + return 1; + default: + CError_FATAL(822); + } + } +} + +Boolean CTemplTool_IsTemplateArgumentDependentExpression(ENode *expr) { + if (!expr) + return 0; + + if (IS_TYPE_TEMPLDEPEXPR(expr->rtype)) + return 1; + + return 0; +} + +Boolean CTemplTool_IsSameTemplate(TemplParam *params, TemplArg *args) { + while (1) { + if (!args) { + CError_ASSERT(850, !params); + return 1; + } + + CError_ASSERT(853, params && args->pid.type == params->pid.type); + + switch (args->pid.type) { + case TPT_TYPE: + if ( + !IS_TYPE_TEMPLATE(args->data.typeparam.type) || + TYPE_TEMPLATE(args->data.typeparam.type)->dtype != TEMPLDEP_ARGUMENT || + TYPE_TEMPLATE(args->data.typeparam.type)->u.pid.nindex != params->pid.nindex || + TYPE_TEMPLATE(args->data.typeparam.type)->u.pid.index != params->pid.index || + args->data.typeparam.qual != 0 + ) + return 0; + break; + case TPT_NONTYPE: + if ( + !ENODE_IS(args->data.paramdecl.expr, ETEMPLDEP) || + args->data.paramdecl.expr->data.templdep.subtype != TDE_PARAM || + args->data.paramdecl.expr->data.templdep.u.pid.nindex != params->pid.nindex || + args->data.paramdecl.expr->data.templdep.u.pid.index != params->pid.index + ) + return 0; + break; + case TPT_TEMPLATE: + if (!IS_TYPE_TEMPLATE(args->data.ttargtype)) + return 0; + break; + default: + CError_FATAL(886); + } + + args = args->next; + params = params->next; + } +} + +TemplClass *CTemplTool_IsTemplate(TypeTemplDep *ttd) { + if (ttd->dtype == TEMPLDEP_QUALNAME && ttd->u.qual.type->dtype == TEMPLDEP_TEMPLATE) + ttd = ttd->u.qual.type; + else if (ttd->dtype != TEMPLDEP_TEMPLATE) + return NULL; + + if (CTemplTool_IsSameTemplate(ttd->u.templ.templ->templ__params, ttd->u.templ.args)) + return ttd->u.templ.templ; + else + return NULL; +} + +Type *CTemplTool_IsDependentTemplate(TemplClass *tmclass, TemplArg *args) { + TemplParam *param; + TemplArg *arg; + Type *type; + + if (!tmclass->templ_parent || tmclass->inst_parent) { + arg = args; + param = tmclass->templ__params; + while (1) { + if (!arg) { + CError_ASSERT(988, !param); + return NULL; + } + + CError_ASSERT(991, param && arg->pid.type == param->pid.type); + + switch (arg->pid.type) { + case TPT_TYPE: + if (CTemplTool_IsTemplateArgumentDependentType(arg->data.typeparam.type)) + goto done; + break; + case TPT_NONTYPE: + if (CTemplTool_IsTemplateArgumentDependentExpression(arg->data.paramdecl.expr)) + goto done; + break; + case TPT_TEMPLATE: + if (!IS_TYPE_CLASS(arg->data.ttargtype) && CTemplTool_IsTemplateArgumentDependentType(arg->data.ttargtype)) + goto done; + break; + default: + CError_FATAL(1008); + goto done; + } + + arg = arg->next; + param = param->next; + } + } +done: + if (cscope_current->theclass == TYPE_CLASS(tmclass) && CTemplTool_IsSameTemplate(tmclass->templ__params, args)) + return TYPE(tmclass); + + type = CDecl_NewTemplDepType(TEMPLDEP_TEMPLATE); + TYPE_TEMPLATE(type)->u.templ.templ = tmclass; + TYPE_TEMPLATE(type)->u.templ.args = args; + return type; +} + +Boolean CTemplTool_EqualExprTypes(ENode *a, ENode *b) { + Object *objA; + Object *objB; + + if (!a || !b) + return 0; + if (a->type != b->type) + return 0; + + switch (a->type) { + case EINTCONST: + return CInt64_Equal(a->data.intval, b->data.intval); + case EOBJREF: + objA = a->data.objref; + while (objA->datatype == DALIAS) + objA = objA->u.alias.object; + objB = b->data.objref; + while (objB->datatype == DALIAS) + objB = objB->u.alias.object; + return objA == objB; + case EMEMBER: + return a->data.emember->list == b->data.emember->list; + case ETEMPLDEP: + if (a->data.templdep.subtype != b->data.templdep.subtype) + return 0; + + switch (a->data.templdep.subtype) { + case TDE_PARAM: + return a->data.templdep.u.pid.nindex == b->data.templdep.u.pid.nindex && + a->data.templdep.u.pid.index == b->data.templdep.u.pid.index; + case TDE_SIZEOF: + case TDE_ALIGNOF: + return is_typesame(a->data.templdep.u.typeexpr.type, b->data.templdep.u.typeexpr.type); + case TDE_CAST: + return is_typesame(a->data.templdep.u.cast.type, b->data.templdep.u.cast.type) && + a->data.templdep.u.cast.qual == b->data.templdep.u.cast.qual; + case TDE_QUALNAME: + return is_typesame(TYPE(a->data.templdep.u.qual.type), TYPE(b->data.templdep.u.qual.type)) && + a->data.templdep.u.qual.name == b->data.templdep.u.qual.name; + case TDE_OBJ: + return a->data.templdep.u.obj == b->data.templdep.u.obj; + case TDE_ADDRESS_OF: + return CTemplTool_EqualExprTypes(a->data.templdep.u.monadic, b->data.templdep.u.monadic); + default: + CError_FATAL(1086); + } + 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 ELAND: + case ELOR: + case EROTL: + case EROTR: + return CTemplTool_EqualExprTypes(a->data.diadic.left, b->data.diadic.left) && + CTemplTool_EqualExprTypes(a->data.diadic.right, b->data.diadic.right); + case EMONMIN: + case EBINNOT: + case ELOGNOT: + return CTemplTool_EqualExprTypes(a->data.monadic, b->data.monadic); + case ECOND: + return CTemplTool_EqualExprTypes(a->data.cond.cond, b->data.cond.cond) && + CTemplTool_EqualExprTypes(a->data.cond.expr1, b->data.cond.expr1) && + CTemplTool_EqualExprTypes(a->data.cond.expr2, b->data.cond.expr2); + default: + CError_FATAL(1122); + return 0; + } +} + +ENode *CTempl_MakeTemplDepExpr(ENode *left, ENodeType nt, ENode *right) { + if (!IS_TYPE_TEMPLDEPEXPR(right->rtype)) { + right = pointer_generation(right); + if (!ENODE_IS(right, EINTCONST)) { + CError_Error(CErrorStr348); + right = nullnode(); + } + } + + if (left) { + if (!IS_TYPE_TEMPLDEPEXPR(left->rtype)) { + left = pointer_generation(left); + if (!ENODE_IS(left, EINTCONST)) { + CError_Error(CErrorStr348); + left = nullnode(); + } + } + + left = makediadicnode(left, right, nt); + } else { + left = makemonadicnode(right, nt); + } + + left->rtype = &sttemplexpr; + return left; +} + +void CTemplTool_CheckTemplArgType(Type *type) { + while (IS_TYPE_POINTER_ONLY(type)) + type = TPTR_TARGET(type); + + if (IS_TYPE_CLASS(type)) { + if (IsTempName(TYPE_CLASS(type)->classname) || CScope_IsInLocalNameSpace(TYPE_CLASS(type)->nspace)) + CError_Error(CErrorStr232); + } +} + +Boolean CTemplTool_EqualArgs(TemplArg *a, TemplArg *b) { + while (a) { + if (!b || a->pid.type != b->pid.type) + return 0; + + switch (a->pid.type) { + case TPT_TYPE: + if ( + !is_typesame(a->data.typeparam.type, b->data.typeparam.type) || + a->data.typeparam.qual != b->data.typeparam.qual + ) + return 0; + break; + case TPT_NONTYPE: + if (!CTemplTool_EqualExprTypes(a->data.paramdecl.expr, b->data.paramdecl.expr)) + return 0; + break; + case TPT_TEMPLATE: + if (!is_typesame(a->data.ttargtype, b->data.ttargtype)) + return 0; + break; + default: + CError_FATAL(1215); + } + + a = a->next; + b = b->next; + } + + if (b) + return 0; + + return 1; +} + +TemplArg *CTemplTool_MakeGlobalTemplArgCopy(TemplArg *args) { + TemplArg *firstCopy; + TemplArg *copy; + + firstCopy = NULL; + while (args) { + if (firstCopy) { + copy->next = galloc(sizeof(TemplArg)); + copy = copy->next; + } else { + copy = galloc(sizeof(TemplArg)); + firstCopy = copy; + } + + *copy = *args; + if (copy->pid.type == TPT_NONTYPE && copy->data.paramdecl.expr) + copy->data.paramdecl.expr = CInline_CopyExpression(copy->data.paramdecl.expr, CopyMode1); + + args = args->next; + } + + return firstCopy; +} + +Boolean CTemplTool_TemplDepTypeCompare(TypeTemplDep *a, TypeTemplDep *b) { + if (a == b) + return 1; + if (a->dtype != b->dtype) + return 0; + + switch (a->dtype) { + case TEMPLDEP_ARGUMENT: + return a->u.pid.nindex == b->u.pid.nindex && + a->u.pid.index == b->u.pid.index; + case TEMPLDEP_QUALNAME: + return CTemplTool_TemplDepTypeCompare(a->u.qual.type, b->u.qual.type) && + a->u.qual.name == b->u.qual.name; + case TEMPLDEP_TEMPLATE: + return a->u.templ.templ == b->u.templ.templ && + CTemplTool_EqualArgs(a->u.templ.args, b->u.templ.args); + case TEMPLDEP_ARRAY: + return is_typesame(a->u.array.type, b->u.array.type) && + CTemplTool_EqualExprTypes(a->u.array.index, b->u.array.index); + case TEMPLDEP_QUALTEMPL: + return CTemplTool_TemplDepTypeCompare(a->u.qualtempl.type, b->u.qualtempl.type) && + CTemplTool_EqualArgs(a->u.qualtempl.args, b->u.qualtempl.args); + case TEMPLDEP_BITFIELD: + return is_typesame(a->u.bitfield.type, b->u.bitfield.type) && + CTemplTool_EqualExprTypes(a->u.bitfield.size, b->u.bitfield.size); + default: + CError_FATAL(1286); + return 0; + } +} + +Type *CTemplTool_DeduceArgDepType(TemplArg *args, Type *type, UInt32 qual, UInt32 *resultQual) { + TemplArg *arg; + + *resultQual = qual; + + if (IS_TYPE_TEMPLATE(type) && TYPE_TEMPLATE(type)->dtype == TEMPLDEP_ARGUMENT) { + arg = args; + while (1) { + if (!arg) + return NULL; + + if ( + arg->pid.index == TYPE_TEMPLATE(type)->u.pid.index && + arg->pid.nindex == TYPE_TEMPLATE(type)->u.pid.nindex + ) + break; + + arg = arg->next; + } + + CError_ASSERT(1314, arg->pid.type == TPT_TYPE); + *resultQual |= arg->data.typeparam.qual; + return arg->data.typeparam.type; + } + + return NULL; +} + +static TemplClassInst *CTemplTool_FindNestedClassInstance(TemplClass *a, TemplClass *b, TemplClassInst *c) { + TemplClass *array[32]; + TemplClassInst *inst; + int i; + + array[0] = a; + i = 0; + while (1) { + CError_ASSERT(1338, i < 32); + CError_ASSERT(1339, a = a->templ_parent); + + if (a == b) + break; + + CError_ASSERT(1341, a->templ__params == NULL); + + array[++i] = a; + } + + while (1) { + inst = array[i--]->instances; + while (1) { + CError_ASSERT(1350, inst); + if (inst->parent == c) + break; + inst = inst->next; + } + + c = inst; + if (i < 0) + break; + + if ((inst->theclass.flags & (CLASS_COMPLETED | CLASS_IS_TEMPL_INST)) == CLASS_IS_TEMPL_INST) + CTempl_InstantiateTemplateClass(TYPE_CLASS(inst)); + } + + return inst; +} + +static TemplClassInst *CTemplTool_FindNestedClass(TemplClass *a, TemplClassInst *b, TemplClass *c) { + TemplClass *scan; + + while (1) { + for (scan = c->templ_parent; scan; scan = scan->templ_parent) { + if (scan == a) + return CTemplTool_FindNestedClassInstance(c, a, b); + } + + a = a->templ_parent; + if (!a) + break; + + b = b->parent; + CError_ASSERT(1377, b); + } + + return NULL; +} + +static Type *CTemplTool_FindTemplateInstance(TypeDeduce *deduce, TemplClass *templ) { + TemplClass *scantempl; + TemplClass *dtempl; + TemplClassInst *scaninst; + TemplClassInst *dinst; + + dtempl = deduce->tmclass; + CError_ASSERT(1393, dtempl); + + dinst = deduce->inst; + if (!dinst) { + if (!dtempl->templ_parent || !dtempl->inst_parent) + return TYPE(templ); + + dtempl = dtempl->templ_parent; + dinst = deduce->tmclass->inst_parent; + } + + scantempl = dtempl; + scaninst = dinst; + while (1) { + if (scantempl == templ) + return TYPE(scaninst); + + if (!scantempl->templ_parent && scantempl->pspec_owner) + scantempl = scantempl->pspec_owner; + + scantempl = scantempl->templ_parent; + if (!scantempl) + break; + + CError_ASSERT(1416, scaninst = scaninst->parent); + } + + if (dtempl->flags & TEMPLCLASS_FLAGS_2) { + scantempl = TEMPL_CLASS(dtempl->theclass.nspace->theclass); + CError_ASSERT(1422, scantempl->theclass.flags & CLASS_IS_TEMPL); + scaninst = dinst; + + while (1) { + if (scantempl == templ) + return TYPE(scaninst); + + scantempl = scantempl->templ_parent; + if (!scantempl) + break; + + CError_ASSERT(1430, scaninst = scaninst->parent); + } + } + + if (!templ->templ__params && (scaninst = CTemplTool_FindNestedClass(dtempl, dinst, templ))) + return TYPE(scaninst); + + CError_FATAL(1477); + return NULL; +} + +static ENode *CTemplTool_DeduceExprCheck(ENode *expr) { + if (expr->type != EINTCONST) { + CError_Error(CErrorStr348); + expr = nullnode(); + } + + return expr; +} + +static ENodeList *CTemplTool_DeduceExprList(TypeDeduce *deduce, ENodeList *list) { + ENodeList *resultList; + ENodeList *last; + + resultList = NULL; + while (list) { + if (resultList) { + last->next = lalloc(sizeof(ENodeList)); + last = last->next; + } else { + last = lalloc(sizeof(ENodeList)); + resultList = last; + } + + *last = *list; + last->node = CTemplTool_DeduceExpr(deduce, last->node); + + list = list->next; + } + + return resultList; +} + +ENode *CTemplTool_DeduceExpr(TypeDeduce *deduce, ENode *expr) { + TemplArg *arg; + TemplClassInst *inst; + ENode *newExpr; + NameSpaceObjectList *nsObjectList; + TStreamElement *saved; + NameResult pr; + Type *type; + UInt32 qual; + + if (!CTemplTool_IsTemplateArgumentDependentExpression(expr)) { + newExpr = lalloc(sizeof(ENode)); + *newExpr = *expr; + return newExpr; + } + + switch (expr->type) { + case ETEMPLDEP: + switch (expr->data.templdep.subtype) { + case TDE_PARAM: + if (deduce->x15 && expr->data.templdep.u.pid.nindex == deduce->nindex) { + newExpr = lalloc(sizeof(ENode)); + *newExpr = *expr; + return newExpr; + } + + for (arg = deduce->args; arg; arg = arg->next) { + if ( + arg->pid.index == expr->data.templdep.u.pid.index && + arg->pid.nindex == expr->data.templdep.u.pid.nindex + ) + { + CError_ASSERT(1562, arg->pid.type == TPT_NONTYPE && arg->data.paramdecl.expr); + newExpr = lalloc(sizeof(ENode)); + *newExpr = *arg->data.paramdecl.expr; + return newExpr; + } + } + + for (inst = deduce->inst; inst; inst = inst->parent) { + for (arg = inst->inst_args; arg; arg = arg->next) { + if ( + arg->pid.index == expr->data.templdep.u.pid.index && + arg->pid.nindex == expr->data.templdep.u.pid.nindex + ) + { + CError_ASSERT(1575, arg->pid.type == TPT_NONTYPE && arg->data.paramdecl.expr); + newExpr = lalloc(sizeof(ENode)); + *newExpr = *arg->data.paramdecl.expr; + return newExpr; + } + } + } + + CError_FATAL(1582); + + case TDE_SIZEOF: + qual = 0; + type = CTemplTool_DeduceTypeCopy(deduce, TYPE(expr->data.templdep.u.typeexpr.type), &qual); + CDecl_CompleteType(type); + + if (CTemplTool_IsTemplateArgumentDependentType(type)) { + newExpr = lalloc(sizeof(ENode)); + *newExpr = *expr; + newExpr->data.templdep.u.typeexpr.type = type; + return newExpr; + } + + return intconstnode(CABI_GetSizeTType(), type->size); + + case TDE_ALIGNOF: + qual = 0; + type = CTemplTool_DeduceTypeCopy(deduce, TYPE(expr->data.templdep.u.typeexpr.type), &qual); + CDecl_CompleteType(type); + + if (CTemplTool_IsTemplateArgumentDependentType(type)) { + newExpr = lalloc(sizeof(ENode)); + *newExpr = *expr; + newExpr->data.templdep.u.typeexpr.type = type; + return newExpr; + } + + return intconstnode(CABI_GetSizeTType(), CMach_GetTypeAlign(type)); + + case TDE_CAST: + qual = expr->data.templdep.u.cast.qual; + type = CTemplTool_DeduceTypeCopy(deduce, expr->data.templdep.u.cast.type, &qual); + return CExpr_DoExplicitConversion(type, qual, CTemplTool_DeduceExprList(deduce, expr->data.templdep.u.cast.args)); + + case TDE_QUALNAME: + qual = 0; + type = CTemplTool_DeduceTypeCopy(deduce, TYPE(expr->data.templdep.u.qual.type), &qual); + + if (IS_TYPE_CLASS(type)) { + CDecl_CompleteType(type); + if (CScope_FindQualifiedClassMember(&pr, TYPE_CLASS(type), expr->data.templdep.u.qual.name)) + return pointer_generation(CExpr_MakeNameLookupResultExpr(&pr)); + + CError_Error(CErrorStr150, expr->data.templdep.u.qual.name->name); + } else if (IS_TYPE_TEMPLATE(type) && !deduce->inst) { + newExpr = lalloc(sizeof(ENode)); + *newExpr = *expr; + newExpr->data.templdep.u.qual.type = TYPE_TEMPLATE(type); + return newExpr; + } else { + CError_Error(CErrorStr340, expr->data.templdep.u.qual.name->name); + } + + return nullnode(); + + case TDE_OBJ: + type = CTemplTool_FindTemplateInstance(deduce, TEMPL_CLASS(expr->data.templdep.u.obj->nspace->theclass)); + CError_ASSERT(1651, type && IS_TYPE_CLASS(type)); + + nsObjectList = CScope_GetLocalObject(TYPE_CLASS(type)->nspace, expr->data.templdep.u.obj->name); + CError_ASSERT(1654, nsObjectList); + + memclrw(&pr, sizeof(pr)); + pr.obj_10 = nsObjectList->object; + return pointer_generation(CExpr_MakeNameLookupResultExpr(&pr)); + + case TDE_SOURCEREF: + CError_LockErrorPos(expr->data.templdep.u.sourceref.token, &saved); + newExpr = CTemplTool_DeduceExpr(deduce, expr->data.templdep.u.sourceref.expr); + CError_UnlockErrorPos(&saved); + return newExpr; + + case TDE_ADDRESS_OF: + return getnodeaddress(CTemplTool_DeduceExpr(deduce, expr->data.templdep.u.monadic), 1); + + default: + CError_FATAL(1671); + } + case EFUNCCALL: + newExpr = CExpr_PointerGeneration(CTemplTool_DeduceExpr(deduce, expr->data.funccall.funcref)); + return CExpr_MakeFunctionCall(newExpr, CTemplTool_DeduceExprList(deduce, expr->data.funccall.args)); + case ELOGNOT: + return CExpr_New_ELOGNOT_Node(CTemplTool_DeduceExpr(deduce, expr->data.monadic)); + case EMONMIN: + return CExpr_New_EMONMIN_Node(CTemplTool_DeduceExpr(deduce, expr->data.monadic)); + case EBINNOT: + return CExpr_New_EBINNOT_Node(CTemplTool_DeduceExpr(deduce, expr->data.monadic)); + 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 ELAND: + case ELOR: + case EROTL: + case EROTR: + return CExpr_NewDyadicNode( + CTemplTool_DeduceExpr(deduce, expr->data.diadic.left), + expr->type, + CTemplTool_DeduceExpr(deduce, expr->data.diadic.right)); + case ECOND: + return CExpr_New_ECOND_Node( + CTemplTool_DeduceExpr(deduce, expr->data.cond.cond), + CTemplTool_DeduceExpr(deduce, expr->data.cond.expr1), + CTemplTool_DeduceExpr(deduce, expr->data.cond.expr2)); + default: + CError_FATAL(1727); + case EINTCONST: + newExpr = lalloc(sizeof(ENode)); + *newExpr = *expr; + return newExpr; + } +} + +ENode *CTemplTool_DeduceDefaultArg(Object *func, ENode *expr) { + TypeDeduce deduce; + + memclrw(&deduce, sizeof(deduce)); + CError_ASSERT(1747, IS_TYPE_FUNC(func->type)); + + if (func->u.func.inst) + deduce.args = func->u.func.inst->args; + + if ((TYPE_FUNC(func->type)->flags & FUNC_METHOD) && (TYPE_METHOD(func->type)->theclass->flags & CLASS_IS_TEMPL_INST)) { + deduce.inst = TEMPL_CLASS_INST(TYPE_METHOD(func->type)->theclass); + deduce.tmclass = TEMPL_CLASS_INST(TYPE_METHOD(func->type)->theclass)->templ; + } + + return CTemplTool_DeduceExpr(&deduce, expr); +} + +static TemplClass *CTemplTool_FindNestedTemplateInstance(TypeDeduce *deduce, TemplClass *templ) { + TemplClass *dtempl; + TemplClassInst *dinst; + Type *type; + + if (templ->inst_parent) + return templ; + + CError_ASSERT(1776, (dtempl = deduce->tmclass) && (dinst = deduce->inst)); + + while (1) { + if ( + templ->templ_parent == dtempl && + (type = CScope_GetLocalTagType(dinst->theclass.nspace, templ->theclass.classname)) && + IS_TEMPL_CLASS(type) && + TEMPL_CLASS(type)->templ_parent == templ->templ_parent + ) + return TEMPL_CLASS(type); + + dtempl = dtempl->templ_parent; + if (!dtempl) + break; + + dinst = dinst->parent; + CError_ASSERT(1790, dinst); + } + + return templ; +} + +static Type *CTemplTool_DeduceClassInstanceCopy(TypeDeduce *deduce, TemplClass *templ, TemplArg *args) { + TemplArg *arg; + TemplArg *deducedArgs; + TemplArg *last; + TemplParam *param; + UInt32 qual; + Type *type; + + if (templ->templ_parent) + templ = CTemplTool_FindNestedTemplateInstance(deduce, templ); + + arg = args; + deducedArgs = NULL; + param = templ->templ__params; + + while (arg) { + if (deducedArgs) { + last->next = galloc(sizeof(TemplArg)); + last = last->next; + } else { + last = galloc(sizeof(TemplArg)); + deducedArgs = last; + } + + *last = *arg; + + if (!param || param->pid.type != last->pid.type) { + CError_Error(CErrorStr374); + return &stvoid; + } + + last->pid = param->pid; + param = param->next; + + switch (last->pid.type) { + case TPT_TYPE: + last->data.typeparam.type = CTemplTool_DeduceTypeCopy(deduce, last->data.typeparam.type, &last->data.typeparam.qual); + break; + + case TPT_NONTYPE: + if (!last->data.paramdecl.expr) { + CError_FATAL(1873); + } else if (CTemplTool_IsTemplateArgumentDependentExpression(last->data.paramdecl.expr)) { + last->data.paramdecl.expr = pointer_generation(CTemplTool_DeduceExpr(deduce, last->data.paramdecl.expr)); + last->data.paramdecl.expr = CInline_CopyExpression(last->data.paramdecl.expr, CopyMode1); + } + break; + + case TPT_TEMPLATE: + qual = 0; + last->data.ttargtype = CTemplTool_DeduceTypeCopy(deduce, last->data.ttargtype, &qual); + break; + + default: + CError_FATAL(1891); + } + + arg = arg->next; + } + + for (arg = deducedArgs; arg; arg = arg->next) { + switch (arg->pid.type) { + case TPT_TYPE: + if (CTemplTool_IsTemplateArgumentDependentType(arg->data.typeparam.type)) + break; + continue; + + case TPT_NONTYPE: + if (CTemplTool_IsTemplateArgumentDependentExpression(arg->data.paramdecl.expr)) + break; + + switch (arg->data.paramdecl.expr->type) { + case EINTCONST: + case EOBJLIST: + case EMEMBER: + break; + case EOBJREF: + if (CParser_HasInternalLinkage2(arg->data.paramdecl.expr->data.objref)) + CError_Error(CErrorStr357); + break; + default: + CError_Error(CErrorStr371); + arg->data.paramdecl.expr = nullnode(); + break; + } + continue; + + case TPT_TEMPLATE: + if (!IS_TYPE_CLASS(arg->data.ttargtype) && CTemplTool_IsTemplateArgumentDependentType(arg->data.ttargtype)) + break; + continue; + + default: + CError_FATAL(1937); + } + + break; + } + + if (arg) { + type = CDecl_NewTemplDepType(TEMPLDEP_TEMPLATE); + TYPE_TEMPLATE(type)->u.templ.templ = templ; + TYPE_TEMPLATE(type)->u.templ.args = deducedArgs; + return type; + } + + if ((type = CTemplTool_IsDependentTemplate(templ, deducedArgs))) + return type; + + return TYPE(CTemplClass_GetInstance(templ, deducedArgs, NULL)); +} + +static TemplArg *CTemplTool_FindTemplArg(TemplArg *args, TemplParamID pid) { + while (args) { + if (args->pid.index == pid.index && args->pid.nindex == pid.nindex) { + CError_ASSERT(1984, pid.type == args->pid.type); + return args; + } + args = args->next; + } + + return NULL; +} + +static TemplArg *CTemplTool_DeduceTemplArg(TypeDeduce *deduce, TemplParamID pid) { + TemplClass *tmclass; + TemplClassInst *inst; + TemplArg *arg; + + if ((arg = CTemplTool_FindTemplArg(deduce->args, pid))) + return arg; + + tmclass = deduce->tmclass; + CError_ASSERT(2008, tmclass); + + inst = deduce->inst; + if (!inst) { + CError_ASSERT(2011, tmclass->templ_parent && tmclass->inst_parent); + inst = deduce->tmclass->inst_parent; + } + + while (1) { + if ((arg = CTemplTool_FindTemplArg(inst->inst_args, pid))) + return arg; + + inst = inst->parent; + CError_ASSERT(2022, inst); + } +} + +static Type *CTemplTool_DeduceArrayCopy(TypeDeduce *deduce, Type *type, ENode *index, UInt32 *resultQual) { + if (CTemplTool_IsTemplateArgumentDependentType(type)) + type = CTemplTool_DeduceTypeCopy(deduce, type, resultQual); + + index = CTemplTool_DeduceExpr(deduce, index); + + if (ENODE_IS(index, EINTCONST)) { + if (CInt64_IsNegative(&index->data.intval)) { + CError_Error(CErrorStr124); + index->data.intval = cint64_one; + } + + if (!CDecl_CheckArrayIntegr(type)) + type = TYPE(&stsignedchar); + + type = CDecl_NewArrayType(type, type->size * CInt64_GetULong(&index->data.intval)); + } else { + if (!deduce->x16) + CError_Error(CErrorStr124); + } + + return type; +} + +static Type *CTemplTool_DeduceBitfieldCopy(TypeDeduce *deduce, Type *type, ENode *size, UInt32 *resultQual) { + TypeBitfield *tbitfield; + short sizeval; + short maxsize; + + if (CTemplTool_IsTemplateArgumentDependentType(type)) { + UInt32 qual = 0; + type = CTemplTool_DeduceTypeCopy(deduce, type, &qual); + } + + if (!IS_TYPE_INT_OR_ENUM(type)) { + CError_Error(CErrorStr138); + type = TYPE(&stunsignedint); + } + + switch (type->size) { + case 1: + maxsize = 8; + break; + case 2: + maxsize = 16; + break; + case 4: + maxsize = 32; + break; + default: + CError_Error(CErrorStr138); + return type; + } + + if (!ENODE_IS(size, EINTCONST)) { + size = CTemplTool_DeduceExpr(deduce, size); + if (!ENODE_IS(size, EINTCONST)) { + CError_Error(CErrorStr124); + return type; + } + } + + sizeval = CInt64_GetULong(&size->data.intval); + if (sizeval > maxsize || CInt64_IsNegative(&size->data.intval)) { + CError_Error(CErrorStr138); + sizeval = 1; + } + + tbitfield = galloc(sizeof(TypeBitfield)); + memclrw(tbitfield, sizeof(TypeBitfield)); + + tbitfield->type = TYPEBITFIELD; + tbitfield->size = type->size; + tbitfield->bitfieldtype = type; + tbitfield->bitlength = sizeval; + + return TYPE(tbitfield); +} + +static Type *CTemplTool_DeduceTemplDepType(TypeDeduce *deduce, TypeTemplDep *tdt, UInt32 *resultQual) { + Type *type; + UInt32 qual; + TemplArg *arg; + + qual = 0; + + if (deduce->x14) { + type = CTemplTool_GetSelfRefTemplate(TYPE(tdt)); + if (type && type == TYPE(deduce->tmclass)) + return type; + + switch (tdt->dtype) { + case TEMPLDEP_ARGUMENT: + return TYPE(tdt); + + case TEMPLDEP_QUALNAME: + type = CTemplTool_DeduceTypeCopy(deduce, TYPE(tdt->u.qual.type), &qual); + if (type == TYPE(tdt->u.qual.type)) + return TYPE(tdt); + + if (!IS_TYPE_CLASS(type)) { + TypeTemplDep *tdtCopy; + CError_ASSERT(2157, IS_TYPE_TEMPLATE(type)); + tdtCopy = galloc(sizeof(TypeTemplDep)); + *tdtCopy = *tdt; + tdtCopy->u.qual.type = TYPE_TEMPLATE(type); + return TYPE(tdtCopy); + } else if ((type = CScope_GetType(TYPE_CLASS(type)->nspace, tdt->u.qual.name, resultQual))) { + return type; + } else { + CError_Error(CErrorStr150, tdt->u.qual.name->name); + return TYPE(tdt); + } + + case TEMPLDEP_TEMPLATE: + for (arg = tdt->u.templ.args; arg; arg = arg->next) { + if (arg->pid.type == TPT_TYPE) + arg->data.typeparam.type = CTemplTool_DeduceTypeCopy(deduce, arg->data.typeparam.type, &arg->data.typeparam.qual); + } + return TYPE(tdt); + + case TEMPLDEP_ARRAY: + tdt->u.array.type = CTemplTool_DeduceTypeCopy(deduce, tdt->u.array.type, &qual); + return TYPE(tdt); + + case TEMPLDEP_QUALTEMPL: + tdt->u.qualtempl.type = TYPE_TEMPLATE(CTemplTool_DeduceTemplDepType(deduce, tdt->u.qualtempl.type, &qual)); + for (arg = tdt->u.qualtempl.args; arg; arg = arg->next) { + if (arg->pid.type == TPT_TYPE) + arg->data.typeparam.type = CTemplTool_DeduceTypeCopy(deduce, arg->data.typeparam.type, &arg->data.typeparam.qual); + } + return TYPE(tdt); + + case TEMPLDEP_BITFIELD: + tdt->u.bitfield.type = CTemplTool_DeduceTypeCopy(deduce, tdt->u.bitfield.type, &qual); + return TYPE(tdt); + } + } else { + switch (tdt->dtype) { + case TEMPLDEP_ARGUMENT: + if (deduce->x15 && tdt->u.pid.nindex == deduce->nindex) + return TYPE(tdt); + + arg = CTemplTool_DeduceTemplArg(deduce, tdt->u.pid); + if (arg->pid.type == TPT_TEMPLATE) { + CError_ASSERT(2222, IS_TEMPL_CLASS(arg->data.typeparam.type)); + *resultQual = arg->data.typeparam.qual; + return arg->data.typeparam.type; + } + + CError_ASSERT(2226, arg->pid.type == TPT_TYPE); + *resultQual = arg->data.typeparam.qual; + return arg->data.typeparam.type; + + case TEMPLDEP_QUALNAME: + type = CTemplTool_DeduceTypeCopy(deduce, TYPE(tdt->u.qual.type), &qual); + if (IS_TYPE_CLASS(type)) { + CDecl_CompleteType(type); + if ((type = CScope_GetType(TYPE_CLASS(type)->nspace, tdt->u.qual.name, resultQual))) { + return type; + } else { + CError_Error(CErrorStr150, tdt->u.qual.name->name); + } + } else { + if ((deduce->x15 || !deduce->inst) && IS_TYPE_TEMPLATE(type)) { + TypeTemplDep *tdtCopy = galloc(sizeof(TypeTemplDep)); + *tdtCopy = *tdt; + tdtCopy->u.qual.type = TYPE_TEMPLATE(type); + return TYPE(tdtCopy); + } else { + CError_Error(CErrorStr340, tdt->u.qual.name->name); + } + } + return TYPE(&stsignedint); + + case TEMPLDEP_TEMPLATE: + return CTemplTool_DeduceClassInstanceCopy(deduce, tdt->u.templ.templ, tdt->u.templ.args); + + case TEMPLDEP_ARRAY: + return CTemplTool_DeduceArrayCopy(deduce, tdt->u.array.type, tdt->u.array.index, resultQual); + + case TEMPLDEP_QUALTEMPL: + type = CTemplTool_DeduceTypeCopy(deduce, TYPE(tdt->u.qualtempl.type), &qual); + if (!IS_TEMPL_CLASS(type)) { + CError_Error(CErrorStr121); + return TYPE(&stsignedint); + } + return CTemplTool_DeduceClassInstanceCopy(deduce, TEMPL_CLASS(type), tdt->u.qualtempl.args); + + case TEMPLDEP_BITFIELD: + return CTemplTool_DeduceBitfieldCopy(deduce, tdt->u.bitfield.type, tdt->u.bitfield.size, resultQual); + } + } + + CError_FATAL(2275); + return NULL; +} + +static Type *CTemplTool_DeduceTypeQualCopy(TypeDeduce *deduce, Type *type, UInt32 *resultQual) { + Type *innerType; + UInt32 qual; + UInt32 innerQual; + TypePointer *newPtr; + + qual = *resultQual; + + if (IS_TYPE_POINTER_ONLY(type) && IS_TYPE_TEMPLATE(TPTR_TARGET(type))) { + innerQual = 0; + innerType = CTemplTool_DeduceTemplDepType(deduce, TYPE_TEMPLATE(TPTR_TARGET(type)), &innerQual); + + newPtr = galloc(sizeof(TypePointer)); + *newPtr = *TYPE_POINTER(type); + + if (IS_TYPE_POINTER_ONLY(innerType)) { + newPtr->target = galloc(sizeof(TypePointer)); + *TYPE_POINTER(newPtr->target) = *TYPE_POINTER(innerType); + *resultQual = innerQual & (Q_CONST | Q_VOLATILE); + TPTR_QUAL(newPtr->target) |= qual & (Q_CONST | Q_VOLATILE); + } else if (IS_TYPE_MEMBERPOINTER(innerType)) { + newPtr->target = galloc(sizeof(TypeMemberPointer)); + *TYPE_MEMBER_POINTER(newPtr->target) = *TYPE_MEMBER_POINTER(innerType); + *resultQual = innerQual & (Q_CONST | Q_VOLATILE); + TYPE_MEMBER_POINTER(newPtr->target)->qual |= qual & (Q_CONST | Q_VOLATILE); + } else { + newPtr->target = innerType; + *resultQual = (qual | innerQual) & (Q_CONST | Q_VOLATILE); + } + + return TYPE(newPtr); + } + + return CTemplTool_DeduceTypeCopy(deduce, type, resultQual); +} + +FuncArg *CTemplTool_DeduceArgCopy(TypeDeduce *deduce, FuncArg *args) { + FuncArg *resultArgs; + FuncArg *last; + + if (args == &oldstyle || args == &elipsis) + return args; + + resultArgs = NULL; + + while (args) { + if (args == &elipsis) { + last->next = args; + break; + } + + if (resultArgs) { + last->next = galloc(sizeof(FuncArg)); + last = last->next; + } else { + last = galloc(sizeof(FuncArg)); + resultArgs = last; + } + + *last = *args; + last->type = CTemplTool_DeduceTypeQualCopy(deduce, last->type, &last->qual); + CanCreateObject(last->type); + + args = args->next; + } + + return resultArgs; +} + +static ExceptSpecList *CTemplTool_DeduceExSpecCopy(TypeDeduce *deduce, ExceptSpecList *exspec) { + ExceptSpecList *copy; + + copy = galloc(sizeof(ExceptSpecList)); + *copy = *exspec; + + if (copy->type && CTemplTool_IsTemplateArgumentDependentType(copy->type)) + copy->type = CTemplTool_DeduceTypeCopy(deduce, copy->type, ©->qual); + + if (copy->next) + copy->next = CTemplTool_DeduceExSpecCopy(deduce, copy->next); + + return copy; +} + +Type *CTemplTool_DeduceTypeCopy(TypeDeduce *deduce, Type *type, UInt32 *resultQual) { + TemplClassInst *inst; + Type *deduced; + UInt32 qual2; + UInt32 qual; + + switch (type->type) { + case TYPETEMPLATE: + qual = 0; + deduced = CTemplTool_DeduceTemplDepType(deduce, TYPE_TEMPLATE(type), &qual); + if (*resultQual & (Q_CONST | Q_VOLATILE)) { + if (IS_TYPE_POINTER_ONLY(deduced)) { + TypePointer *newPtr = galloc(sizeof(TypePointer)); + *newPtr = *TYPE_POINTER(deduced); + newPtr->qual |= *resultQual & (Q_CONST | Q_VOLATILE); + *resultQual &= ~(Q_CONST | Q_VOLATILE); + deduced = TYPE(newPtr); + } else if (IS_TYPE_MEMBERPOINTER(deduced)) { + TypeMemberPointer *newPtr = galloc(sizeof(TypeMemberPointer)); + *newPtr = *TYPE_MEMBER_POINTER(deduced); + newPtr->qual |= *resultQual & (Q_CONST | Q_VOLATILE); + *resultQual &= ~(Q_CONST | Q_VOLATILE); + deduced = TYPE(newPtr); + } + } + *resultQual |= qual; + return deduced; + + case TYPEVOID: + case TYPEINT: + case TYPEFLOAT: + case TYPESTRUCT: + return type; + + case TYPEENUM: + if ( + TYPE_ENUM(type)->nspace->theclass && + (TYPE_ENUM(type)->nspace->theclass->flags & CLASS_IS_TEMPL) && + !deduce->x14 + ) + { + CError_ASSERT(2471, TYPE_ENUM(type)->enumname); + inst = TEMPL_CLASS_INST(CTemplTool_FindTemplateInstance(deduce, TEMPL_CLASS(TYPE_ENUM(type)->nspace->theclass))); + CError_ASSERT(2473, inst && inst->theclass.type == TYPECLASS); + + CDecl_CompleteType(TYPE(inst)); + type = CScope_GetLocalTagType(inst->theclass.nspace, TYPE_ENUM(type)->enumname); + CError_ASSERT(2477, type); + return type; + } + return type; + + case TYPECLASS: + if (!deduce->x14) { + if (TYPE_CLASS(type)->flags & CLASS_IS_TEMPL) + return CTemplTool_FindTemplateInstance(deduce, TEMPL_CLASS(type)); + + if (TYPE_CLASS(type)->nspace->theclass && (TYPE_CLASS(type)->nspace->theclass->flags & CLASS_IS_TEMPL)) { + CError_ASSERT(2492, deduce->inst); + CError_ASSERT(2493, TYPE_CLASS(type)->classname); + + type = CScope_GetLocalTagType(deduce->inst->theclass.nspace, TYPE_CLASS(type)->classname); + CError_ASSERT(2496, type); + return type; + } + } + + return type; + + case TYPEARRAY: { + SInt32 elements; + + elements = TPTR_TARGET(type)->size; + if (elements > 0) + elements = type->size / elements; + + deduced = galloc(sizeof(TypePointer)); + *TYPE_POINTER(deduced) = *TYPE_POINTER(type); + TPTR_TARGET(deduced) = CTemplTool_DeduceTypeCopy(deduce, TPTR_TARGET(type), resultQual); + + do { + type = TPTR_TARGET(type); + } while (IS_TYPE_ARRAY(type)); + + if (IS_TYPE_TEMPLATE(type)) { + CDecl_CompleteType(TPTR_TARGET(deduced)); + deduced->size = TPTR_TARGET(deduced)->size * elements; + } + + return deduced; + } + + case TYPEPOINTER: + deduced = galloc(sizeof(TypePointer)); + *TYPE_POINTER(deduced) = *TYPE_POINTER(type); + TPTR_TARGET(deduced) = CTemplTool_DeduceTypeCopy(deduce, TPTR_TARGET(type), resultQual); + return deduced; + + case TYPEBITFIELD: + deduced = galloc(sizeof(TypeBitfield)); + *TYPE_BITFIELD(deduced) = *TYPE_BITFIELD(type); + TYPE_BITFIELD(deduced)->bitfieldtype = CTemplTool_DeduceTypeCopy(deduce, TYPE_BITFIELD(type)->bitfieldtype, resultQual); + return deduced; + + case TYPEMEMBERPOINTER: + deduced = galloc(sizeof(TypeMemberPointer)); + *TYPE_MEMBER_POINTER(deduced) = *TYPE_MEMBER_POINTER(type); + TYPE_MEMBER_POINTER(deduced)->ty1 = CTemplTool_DeduceTypeCopy(deduce, TYPE_MEMBER_POINTER(type)->ty1, resultQual); + qual2 = 0; + TYPE_MEMBER_POINTER(deduced)->ty2 = CTemplTool_DeduceTypeCopy(deduce, TYPE_MEMBER_POINTER(type)->ty2, &qual2); + + if ( + !IS_TYPE_CLASS(TYPE_MEMBER_POINTER(deduced)->ty2) && + !deduce->x14 && + !deduce->x15 && + !deduce->x16 + ) + { + CError_Error(CErrorStr232); + return TYPE_MEMBER_POINTER(deduced)->ty1; + } + return deduced; + + case TYPEFUNC: + if (TYPE_FUNC(type)->flags & FUNC_METHOD) { + qual2 = 0; + deduced = galloc(sizeof(TypeMemberFunc)); + *TYPE_METHOD(deduced) = *TYPE_METHOD(type); + TYPE_METHOD(deduced)->funcid = 0; + TYPE_METHOD(deduced)->theclass = TYPE_CLASS(CTemplTool_DeduceTypeQualCopy(deduce, TYPE(TYPE_METHOD(type)->theclass), &qual2)); + CError_ASSERT(2556, IS_TYPE_CLASS(TYPE_METHOD(deduced)->theclass)); + } else { + deduced = galloc(sizeof(TypeFunc)); + *TYPE_FUNC(deduced) = *TYPE_FUNC(type); + } + + TYPE_FUNC(deduced)->flags &= ~FUNC_IS_TEMPL; + + qual2 = TYPE_FUNC(type)->qual; + TYPE_FUNC(deduced)->functype = CTemplTool_DeduceTypeQualCopy(deduce, TYPE_FUNC(type)->functype, &qual2); + TYPE_FUNC(deduced)->qual = qual2; + + TYPE_FUNC(deduced)->args = CTemplTool_DeduceArgCopy(deduce, TYPE_FUNC(type)->args); + if (TYPE_FUNC(type)->exspecs) + TYPE_FUNC(deduced)->exspecs = CTemplTool_DeduceExSpecCopy(deduce, TYPE_FUNC(type)->exspecs); + + CDecl_SetResultReg(TYPE_FUNC(deduced)); + return deduced; + + case TYPETEMPLDEPEXPR: + CError_Error(CErrorStr190); + return &stvoid; + + default: + CError_FATAL(2580); + return NULL; + } +} + +Type *CTemplTool_ResolveMemberSelfRefs(TemplClass *templ, Type *type, UInt32 *resultQual) { + TypeDeduce deduce; + + memclrw(&deduce, sizeof(deduce)); + deduce.tmclass = templ; + deduce.x14 = 1; + + if (IS_TYPE_FUNC(type)) { + TYPE_FUNC(type)->functype = CTemplTool_DeduceTypeCopy(&deduce, TYPE_FUNC(type)->functype, &TYPE_FUNC(type)->qual); + TYPE_FUNC(type)->args = CTemplTool_DeduceArgCopy(&deduce, TYPE_FUNC(type)->args); + CDecl_SetResultReg(TYPE_FUNC(type)); + } else { + type = CTemplTool_DeduceTypeCopy(&deduce, type, resultQual); + } + + return type; +} + +Boolean CTemplTool_IsSameTemplateType(Type *a, Type *b) { + return CTemplTool_GetSelfRefTemplate(b) == a; +} |