#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; } }