diff options
Diffstat (limited to 'compiler_and_linker/FrontEnd/C/CExpr2.c')
-rw-r--r-- | compiler_and_linker/FrontEnd/C/CExpr2.c | 4206 |
1 files changed, 4206 insertions, 0 deletions
diff --git a/compiler_and_linker/FrontEnd/C/CExpr2.c b/compiler_and_linker/FrontEnd/C/CExpr2.c new file mode 100644 index 0000000..fc26c7e --- /dev/null +++ b/compiler_and_linker/FrontEnd/C/CExpr2.c @@ -0,0 +1,4206 @@ +#include "compiler/CExpr.h" +#include "compiler/CABI.h" +#include "compiler/CClass.h" +#include "compiler/CDecl.h" +#include "compiler/CInit.h" +#include "compiler/CInt64.h" +#include "compiler/CError.h" +#include "compiler/CFunc.h" +#include "compiler/CInline.h" +#include "compiler/CMachine.h" +#include "compiler/CMangler.h" +#include "compiler/CObjC.h" +#include "compiler/CObjCModern.h" +#include "compiler/CParser.h" +#include "compiler/CPrepTokenizer.h" +#include "compiler/CScope.h" +#include "compiler/CSOM.h" +#include "compiler/CTemplateFunc.h" +#include "compiler/CTemplateTools.h" +#include "compiler/CodeGen.h" +#include "compiler/CompilerTools.h" +#include "compiler/enode.h" +#include "compiler/objects.h" +#include "compiler/scopes.h" +#include "compiler/templates.h" + +#ifdef __MWERKS__ +#undef va_start +#undef va_arg +#define va_start(ap, parm) ap = __va_start(parm) +#define __va_start(parm) (va_list) (&parm + 1) +//#define va_arg(ap, type) ((((type *) (ap = (va_list) (( ((long) ap + sizeof(type) - 1) & ~(sizeof(type)) ) + sizeof(type) ) ))[-1])) +#define va_arg(ap, type) (*(((type *) (ap = (char *)((((unsigned long)ap + __builtin_align(type) - 1) & ~(__builtin_align(type) - 1) ) + sizeof(type)))) - 1)) +#endif + +ENode *assign_node; +Boolean temp_reference_init; +static SInt32 assign_value; // type? +static ENode *firstarrayexpr; +static Match5 user_std_match; +static Boolean cexpr_hascall; +static Boolean cexpr_esearch_bool[MAXEXPR]; +static Boolean cexpr_rsearch_bool[MAXEXPR]; +static CExprSearchCB cexpr_esearch_callback; +static CExprReplaceCB cexpr_rsearch_callback; +static Type *cexpr_left_conversion_type; +static Type *cexpr_right_conversion_type; + +static FuncArg mon_arg = {NULL, NULL, NULL, NULL, 0, 0, 0}; +static FuncArg diadic_arg2 = {NULL, NULL, NULL, NULL, 0, 0, 0}; +static FuncArg diadic_arg1 = {&diadic_arg1, NULL, NULL, NULL, 0, 0, 0}; + +static void CExpr_RecSearchExprTree(ENode *expr) { + ENodeList *list; + +restart: + if (cexpr_esearch_bool[expr->type]) + cexpr_esearch_callback(expr); + + switch (expr->type) { + case EPOSTINC: + case EPOSTDEC: + case EPREINC: + case EPREDEC: + case EINDIRECT: + case EMONMIN: + case EBINNOT: + case ELOGNOT: + case EFORCELOAD: + case ETYPCON: + case EBITFIELD: + expr = expr->data.monadic; + goto restart; + case EMUL: + case EMULV: + case EDIV: + case EMODULO: + case EADDV: + case ESUBV: + case EADD: + case ESUB: + case ESHL: + case ESHR: + case ELESS: + case EGREATER: + case ELESSEQU: + case EGREATEREQU: + case EEQU: + case ENOTEQU: + case EAND: + case EXOR: + case EOR: + case ELAND: + case ELOR: + case EASS: + case EMULASS: + case EDIVASS: + case EMODASS: + case EADDASS: + case ESUBASS: + case ESHLASS: + case ESHRASS: + case EANDASS: + case EXORASS: + case EORASS: + case ECOMMA: + case EPMODULO: + case EROTL: + case EROTR: + case EBCLR: + case EBTST: + case EBSET: + CExpr_RecSearchExprTree(expr->data.diadic.left); + expr = expr->data.diadic.right; + goto restart; + case EINTCONST: + case EFLOATCONST: + case ESTRINGCONST: + case EOBJREF: + case EPRECOMP: + case ETEMP: + case EARGOBJ: + case ELOCOBJ: + case ELABEL: + case EOBJLIST: + case EMEMBER: + case EINSTRUCTION: + case EVECTOR128CONST: + return; + case EFUNCCALL: + case EFUNCCALLP: + for (list = expr->data.funccall.args; list; list = list->next) + CExpr_RecSearchExprTree(list->node); + expr = expr->data.funccall.funcref; + goto restart; + case ENULLCHECK: + CExpr_RecSearchExprTree(expr->data.nullcheck.nullcheckexpr); + expr = expr->data.nullcheck.condexpr; + goto restart; + case EMFPOINTER: + CExpr_RecSearchExprTree(expr->data.mfpointer.accessnode); + expr = expr->data.mfpointer.mfpointer; + goto restart; + case ECOND: + CExpr_RecSearchExprTree(expr->data.cond.cond); + CExpr_RecSearchExprTree(expr->data.cond.expr1); + expr = expr->data.cond.expr2; + goto restart; + case ENEWEXCEPTION: + case ENEWEXCEPTIONARRAY: + CExpr_RecSearchExprTree(expr->data.newexception.initexpr); + expr = expr->data.newexception.tryexpr; + goto restart; + case EINITTRYCATCH: + if (expr->data.itc.initexpr) + CExpr_RecSearchExprTree(expr->data.itc.initexpr); + if (expr->data.itc.tryexpr) + CExpr_RecSearchExprTree(expr->data.itc.tryexpr); + if (expr->data.itc.catchexpr) + CExpr_RecSearchExprTree(expr->data.itc.catchexpr); + if (expr->data.itc.result) + CExpr_RecSearchExprTree(expr->data.itc.result); + return; + default: + CError_FATAL(128); + } +} + +void CExpr_SearchExprTree(ENode *expr, CExprSearchCB callback, int count, ...) { + va_list ap; + short i; + + cexpr_esearch_callback = callback; + + va_start(ap, count); + for (i = 0; i < MAXEXPR; i++) + cexpr_esearch_bool[i] = 0; + i = 0; + while ((short) i < count) { + cexpr_esearch_bool[va_arg(ap, int)] = 1; + ++i; + } + va_end(ap); + + CExpr_RecSearchExprTree(expr); +} + +static ENode *CExpr_RecSearchExprTreeReplace(ENode *expr) { + ENodeList *list; + ENode *replaced; + + if (cexpr_rsearch_bool[expr->type]) { + replaced = cexpr_rsearch_callback(expr); + if (!replaced) + return expr; + expr = replaced; + } + + switch (expr->type) { + case EPOSTINC: + case EPOSTDEC: + case EPREINC: + case EPREDEC: + case EINDIRECT: + case EMONMIN: + case EBINNOT: + case ELOGNOT: + case EFORCELOAD: + case ETYPCON: + case EBITFIELD: + expr->data.monadic = CExpr_RecSearchExprTreeReplace(expr->data.monadic); + return expr; + case EMUL: + case EMULV: + case EDIV: + case EMODULO: + case EADDV: + case ESUBV: + case EADD: + case ESUB: + case ESHL: + case ESHR: + case ELESS: + case EGREATER: + case ELESSEQU: + case EGREATEREQU: + case EEQU: + case ENOTEQU: + case EAND: + case EXOR: + case EOR: + case ELAND: + case ELOR: + case EASS: + case EMULASS: + case EDIVASS: + case EMODASS: + case EADDASS: + case ESUBASS: + case ESHLASS: + case ESHRASS: + case EANDASS: + case EXORASS: + case EORASS: + case ECOMMA: + case EPMODULO: + case EROTL: + case EROTR: + case EBCLR: + case EBTST: + case EBSET: + expr->data.diadic.left = CExpr_RecSearchExprTreeReplace(expr->data.diadic.left); + expr->data.diadic.right = CExpr_RecSearchExprTreeReplace(expr->data.diadic.right); + return expr; + case EINTCONST: + case EFLOATCONST: + case ESTRINGCONST: + case EOBJREF: + case EPRECOMP: + case ETEMP: + case EARGOBJ: + case ELOCOBJ: + case ELABEL: + case EMEMBER: + case EINSTRUCTION: + case EVECTOR128CONST: + return expr; + case EFUNCCALL: + case EFUNCCALLP: + for (list = expr->data.funccall.args; list; list = list->next) + list->node = CExpr_RecSearchExprTreeReplace(list->node); + expr->data.funccall.funcref = CExpr_RecSearchExprTreeReplace(expr->data.funccall.funcref); + return expr; + case ENULLCHECK: + expr->data.nullcheck.nullcheckexpr = CExpr_RecSearchExprTreeReplace(expr->data.nullcheck.nullcheckexpr); + expr->data.nullcheck.condexpr = CExpr_RecSearchExprTreeReplace(expr->data.nullcheck.condexpr); + return expr; + case EMFPOINTER: + expr->data.mfpointer.accessnode = CExpr_RecSearchExprTreeReplace(expr->data.mfpointer.accessnode); + expr->data.mfpointer.mfpointer = CExpr_RecSearchExprTreeReplace(expr->data.mfpointer.mfpointer); + return expr; + case ECOND: + expr->data.cond.cond = CExpr_RecSearchExprTreeReplace(expr->data.cond.cond); + expr->data.cond.expr1 = CExpr_RecSearchExprTreeReplace(expr->data.cond.expr1); + expr->data.cond.expr2 = CExpr_RecSearchExprTreeReplace(expr->data.cond.expr2); + return expr; + default: + CError_FATAL(220); + return NULL; + } +} + +ENode *CExpr_SearchExprTreeReplace(ENode *expr, CExprReplaceCB callback, int count, ...) { + va_list ap; + short i; + + cexpr_rsearch_callback = callback; + + va_start(ap, count); + for (i = 0; i < MAXEXPR; i++) + cexpr_rsearch_bool[i] = 0; + i = 0; + while ((short) i < count) { + cexpr_rsearch_bool[va_arg(ap, int)] = 1; + ++i; + } + va_end(ap); + + return CExpr_RecSearchExprTreeReplace(expr); +} + +static void CExpr_HasFuncCallCallBack(ENode *expr) { + cexpr_hascall = 1; +} + +Boolean CExpr_HasFuncCall(ENode *expr) { + cexpr_hascall = 0; + CExpr_SearchExprTree(expr, CExpr_HasFuncCallCallBack, 2, EFUNCCALL, EFUNCCALLP); + return cexpr_hascall; +} + +void CExpr_AliasTransform(ENode *expr) { + ENode *n; + + Object *obj = expr->data.objref; + if (obj->u.alias.offset) { + n = makediadicnode( + create_objectrefnode(obj->u.alias.object), + intconstnode(TYPE(&stunsignedlong), obj->u.alias.offset), + EADD); + *expr = *n; + } else { + expr->data.objref = obj->u.alias.object; + } +} + +ENode *CExpr_UnaryFloatExpression(ENode *expr) { + return expr; +} + +ENode *CExpr_BinaryFloatExpression(ENode *expr) { + return expr; +} + +ENode *CExpr_NewENode(ENodeType ty) { + ENode *expr = lalloc(sizeof(ENode)); + memclrw(expr, sizeof(ENode)); + expr->type = ty; + return expr; +} + +ENode *CExpr_NewTemplDepENode(TemplDepSubType t) { + ENode *expr = CExpr_NewENode(ETEMPLDEP); + expr->rtype = &sttemplexpr; + expr->data.templdep.subtype = t; + return expr; +} + +ENode *nullnode(void) { + ENode *expr = CExpr_NewENode(EINTCONST); + expr->rtype = (Type *) &stsignedlong; + return expr; +} + +ENode *intconstnode(Type *type, SInt32 value) { + ENode *expr = CExpr_NewENode(EINTCONST); + expr->rtype = type; + CInt64_SetLong(&expr->data.intval, value); + return expr; +} + +ENode *stringconstnode(char *str) { + ENode *expr; + SInt32 size; + + size = strlen(str) + 1; + expr = CExpr_NewENode(ESTRINGCONST); + expr->rtype = CDecl_NewArrayType((Type *) &stchar, size); + expr->data.string.size = size; + expr->data.string.data = str; + expr->data.string.ispascal = 0; + if (copts.const_strings) + expr->flags = Q_CONST; + + expr = makemonadicnode(expr, EINDIRECT); + expr->data.monadic->rtype = CDecl_NewPointerType(expr->rtype); + return expr; +} + +ENode *forceintegral(ENode *expr) { + if (!IS_TYPE_ENUM(expr->rtype)) { + CError_Error(CErrorStr144); + return nullnode(); + } else { + expr->rtype = TYPE_ENUM(expr->rtype)->enumtype; + return expr; + } +} + +ENode *makemonadicnode(ENode *inner, ENodeType ty) { + ENode *expr = lalloc(sizeof(ENode)); + expr->type = ty; + if ((expr->cost = inner->cost) == 0) + expr->cost = 1; + expr->flags = inner->flags & ENODE_FLAG_QUALS; + expr->rtype = inner->rtype; + expr->data.monadic = inner; + return expr; +} + +ENode *makediadicnode(ENode *left, ENode *right, ENodeType ty) { + ENode *expr = lalloc(sizeof(ENode)); + expr->type = ty; + expr->rtype = left->rtype; + expr->data.diadic.left = left; + expr->data.diadic.right = right; + + if (left->cost != right->cost) { + expr->cost = right->cost; + if (left->cost > expr->cost) + expr->cost = left->cost; + } else { + expr->cost = right->cost + 1; + if (expr->cost > 200) + expr->cost = 200; + } + + expr->flags = (left->flags | right->flags) & ENODE_FLAG_QUALS; + return expr; +} + +ENode *makecommaexpression(ENode *left, ENode *right) { + ENode *expr; + + if (ENODE_IS(right, EINDIRECT) && !ENODE_IS(right->data.monadic, EBITFIELD)) { + Boolean savecpp = copts.cplusplus; + copts.cplusplus = 1; + expr = makediadicnode(left, getnodeaddress(right, 0), ECOMMA); + copts.cplusplus = savecpp; + expr->rtype = expr->data.diadic.right->rtype; + expr = makemonadicnode(expr, EINDIRECT); + } else { + expr = makediadicnode(left, right, ECOMMA); + } + + expr->rtype = right->rtype; + expr->flags = right->flags; + return expr; +} + +short iszero(ENode *expr) { + switch (expr->type) { + case EINTCONST: + return CInt64_IsZero(&expr->data.intval); + case EFLOATCONST: + return CMach_FloatIsZero(expr->data.floatval); + default: + return 0; + } +} + +short isnotzero(ENode *expr) { + Object *obj; + + switch (expr->type) { + case EINTCONST: + return !CInt64_IsZero(&expr->data.intval); + case EFLOATCONST: + return !CMach_FloatIsZero(expr->data.floatval); + case ESTRINGCONST: + case ETEMP: + return 1; + case EOBJREF: + obj = expr->data.objref; + break; + case EADD: + case ESUB: + if (ENODE_IS(expr->data.diadic.left, EOBJREF) && ENODE_IS(expr->data.diadic.right, EINTCONST)) { + obj = expr->data.diadic.left->data.objref; + break; + } + if (ENODE_IS(expr->data.diadic.left, EINTCONST) && ENODE_IS(expr->data.diadic.right, EOBJREF)) { + obj = expr->data.diadic.right->data.objref; + break; + } + return 0; + default: + return 0; + } + + switch (obj->datatype) { + case DLOCAL: + return 1; + default: + return 0; + } +} + +Boolean CExpr_IsOne(ENode *expr) { + if (ENODE_IS(expr, EINTCONST)) + return CInt64_Equal(expr->data.intval, cint64_one); + else if (ENODE_IS(expr, EFLOATCONST)) + return CMach_FloatIsOne(expr->data.floatval); + else + return 0; +} + +Boolean CExpr_AllBitsSet(ENode *expr) { + SInt32 v; + + if (ENODE_IS(expr, EINTCONST)) { + switch (expr->rtype->size) { + case 1: + v = CInt64_GetULong(&expr->data.intval) & 0xFF; + return v == 0xFF; + case 2: + v = CInt64_GetULong(&expr->data.intval) & 0xFFFF; + return v == 0xFFFF; + case 3: + v = CInt64_GetULong(&expr->data.intval) & 0xFFFFFF; + return v == 0xFFFFFF; + case 4: + v = CInt64_GetULong(&expr->data.intval) & 0xFFFFFFFF; + return v == 0xFFFFFFFF; + default: + return CInt64_Equal(expr->data.intval, cint64_negone); + } + } + + return 0; +} + +ENode *CExpr_NewETEMPNode(Type *type, Boolean assign_id) { + ENode *expr = lalloc(sizeof(ENode)); + expr->type = ETEMP; + expr->cost = 0; + expr->flags = 0; + expr->rtype = CDecl_NewPointerType(type); + expr->data.temp.type = type; + expr->data.temp.uniqueid = assign_id ? CParser_GetUniqueID() : 0; + expr->data.temp.needs_dtor = 0; + return expr; +} + +static ENode *CExpr_DerefETEMPCopy(ENode *expr) { + ENode *copy; + + CError_ASSERT(636, IS_TYPE_POINTER_ONLY(expr->rtype)); + + copy = lalloc(sizeof(ENode)); + *copy = *expr; + copy = makemonadicnode(copy, EINDIRECT); + copy->rtype = TYPE_POINTER(copy->rtype)->target; + return copy; +} + +ENode *CExpr_GetETEMPCopy(ENode *expr) { + ENode *newnode; + ENode *assnode; + ENode *finalnode; + + newnode = CExpr_NewETEMPNode(expr->rtype, 1); + newnode->flags = expr->flags; + + assnode = makediadicnode(CExpr_DerefETEMPCopy(newnode), expr, EASS); + assnode->data.diadic.right = lalloc(sizeof(ENode)); + *assnode->data.diadic.right = *expr; + *expr = *assnode; + + finalnode = makemonadicnode(newnode, EINDIRECT); + finalnode->rtype = expr->rtype; + return finalnode; +} + +ENode *integralpromote(ENode *expr) { + if (!IS_TYPE_INT(expr->rtype)) + expr = forceintegral(expr); + + if (TYPE_INTEGRAL(expr->rtype)->integral >= IT_INT) + return expr; + + if (!ENODE_IS(expr, EINTCONST)) + expr = makemonadicnode(expr, ETYPCON); + expr->rtype = (Type *) &stsignedint; + + return expr; +} + +CInt64 CExpr_IntConstConvert(Type *a, Type *b, CInt64 val) { + if (a == (Type *) &stbool) + return CMach_CalcIntDiadic(b, val, TK_LOGICAL_NE, cint64_zero); + else + return CMach_CalcIntDiadic(a, val, '+', cint64_zero); +} + +ENode *promote(ENode *expr, Type *type) { + if (ENODE_IS(expr, EINTCONST)) { + if (IS_TYPE_FLOAT(type)) { + expr->type = EFLOATCONST; + expr->data.floatval = CMach_CalcFloatConvertFromInt(expr->rtype, expr->data.intval); + } else { + expr->data.intval = CExpr_IntConstConvert(type, expr->rtype, expr->data.intval); + } + expr->rtype = type; + return expr; + } + if (ENODE_IS(expr, EFLOATCONST)) { + if (IS_TYPE_FLOAT(type)) { + expr->data.floatval = CMach_CalcFloatConvert(type, expr->data.floatval); + expr->rtype = type; + return expr; + } else if (IS_TYPE_INT(type)) { + expr->data.intval = CMach_CalcIntConvertFromFloat(type, expr->data.floatval); + expr->type = EINTCONST; + expr->rtype = type; + return expr; + } + } + + expr = makemonadicnode(expr, ETYPCON); + expr->rtype = type; + return expr; +} + +void CExpr_ArithmeticConversion(ENode **left, ENode **right) { + switch ((*left)->rtype->type) { + case TYPEINT: + case TYPEFLOAT: + break; + case TYPEENUM: + (*left)->rtype = TYPE_ENUM((*left)->rtype)->enumtype; + break; + default: + CError_Error(CErrorStr144); + (*left) = nullnode(); + } + + switch ((*right)->rtype->type) { + case TYPEINT: + case TYPEFLOAT: + break; + case TYPEENUM: + (*right)->rtype = TYPE_ENUM((*right)->rtype)->enumtype; + break; + default: + CError_Error(CErrorStr144); + (*right) = nullnode(); + } + + if (IS_TYPE_FLOAT((*left)->rtype) || IS_TYPE_FLOAT((*right)->rtype)) { + if ((*left)->rtype != (*right)->rtype) { + if (TYPE_INTEGRAL((*left)->rtype)->integral > TYPE_INTEGRAL((*right)->rtype)->integral) + *right = promote(*right, (*left)->rtype); + else + *left = promote(*left, (*right)->rtype); + } + return; + } + + *left = integralpromote(*left); + *right = integralpromote(*right); + if ((*left)->rtype != (*right)->rtype) { + if (TYPE_INTEGRAL((*left)->rtype)->integral < TYPE_INTEGRAL((*right)->rtype)->integral) { + ENode **tmp = left; + left = right; + right = tmp; + } + + if ((*left)->rtype->size == (*right)->rtype->size && !is_unsigned((*left)->rtype) && is_unsigned((*right)->rtype)) { + if ((*left)->rtype == (Type *) &stsignedlong) { + *left = promote(*left, (Type *) &stunsignedlong); + } else { + CError_ASSERT(838, (*left)->rtype == (Type *) &stsignedlonglong); + *left = promote(*left, (Type *) &stunsignedlonglong); + } + } + + *right = promote(*right, (*left)->rtype); + } +} + +static ENode *CExpr_GetEA(ENode *expr) { + ENode *copy; + + for (;;) { + switch (expr->type) { + case EINDIRECT: + expr = expr->data.monadic; + for (;;) { + switch (expr->type) { + case EOBJREF: + copy = lalloc(sizeof(ENode)); + *copy = *expr; + return copy; + case ECOMMA: + expr = expr->data.diadic.right; + continue; + default: + return CExpr_GetETEMPCopy(expr); + } + } + break; + case EPOSTINC: + case EPOSTDEC: + case EPREINC: + case EPREDEC: + expr = expr->data.monadic; + continue; + case EASS: + case EMULASS: + case EDIVASS: + case EMODASS: + case EADDASS: + case ESUBASS: + case ESHLASS: + case ESHRASS: + case EANDASS: + case EXORASS: + case EORASS: + expr = expr->data.monadic; + continue; + case ECOMMA: + expr = expr->data.diadic.right; + continue; + default: + return NULL; + } + } +} + +ENode *CExpr_TempModifyExpr(ENode *expr) { + Type *type; + ENode *left; + ENode *right; + ENode *eanode; + ENode *tempnode; + ENode *indnode; + ENode *truenode; + + type = expr->rtype; + tempnode = CExpr_NewETEMPNode(type, 1); + eanode = CExpr_GetEA(expr); + if (!eanode) { + CError_Error(CErrorStr142); + return expr; + } + + // tempnode = expr + left = makemonadicnode(tempnode, EINDIRECT); + left->rtype = type; + left = makediadicnode(left, expr, EASS); + + // eanode = true + indnode = makemonadicnode(eanode, EINDIRECT); + indnode->rtype = type; + truenode = nullnode(); + truenode->rtype = (Type *) &stbool; + CInt64_SetLong(&truenode->data.intval, 1); + right = makediadicnode(indnode, truenode, EASS); + + expr = makediadicnode(left, right, ECOMMA); + + indnode = makemonadicnode(tempnode, EINDIRECT); + indnode->rtype = type; + return makediadicnode(expr, indnode, ECOMMA); +} + +Boolean CExpr_IsLValue(ENode *expr) { + while (!ENODE_IS(expr, EINDIRECT)) { + switch (expr->type) { + case EPREINC: + case EPREDEC: + return copts.cplusplus; + case EASS: + case EMULASS: + case EDIVASS: + case EMODASS: + case EADDASS: + case ESUBASS: + case ESHLASS: + case ESHRASS: + case EANDASS: + case EXORASS: + case EORASS: + if (!copts.cplusplus) + return 0; + expr = expr->data.diadic.left; + continue; + case ECOMMA: + if (!copts.cplusplus) + return 0; + expr = expr->data.diadic.right; + continue; + case ECOND: + if ( + copts.cplusplus && + is_typesame(expr->data.cond.expr1->rtype, expr->data.cond.expr2->rtype) && + (expr->data.cond.expr1->rtype->type != TYPEPOINTER || (UInt32) (expr->data.cond.expr1->flags & ENODE_FLAG_QUALS) == (expr->data.cond.expr2->flags & ENODE_FLAG_QUALS)) + ) { + return CExpr_IsLValue(expr->data.cond.expr1) && CExpr_IsLValue(expr->data.cond.expr2); + } + return 0; + default: + return 0; + } + } + + expr = expr->data.monadic; + switch (expr->type) { + case ETEMP: + return 0; + case EFUNCCALL: + if (expr->data.funccall.functype->functype->type != TYPEPOINTER || (expr->data.funccall.functype->flags & FUNC_IS_CTOR)) + return 0; + default: + return 1; + } +} + +ENode *CExpr_LValue(ENode *expr, Boolean flag1, Boolean flag2) { + ENode *eanode; + ENode *tmpnode; + +loop: + switch (expr->type) { + case ETYPCON: + if (copts.pointercast_lvalue || !copts.ANSIstrict) { + if (expr->rtype->type == TYPEPOINTER && expr->data.monadic->rtype->type == TYPEPOINTER) { + switch (expr->data.monadic->type) { + case EINDIRECT: + case ETYPCON: + expr->data.monadic->rtype = expr->rtype; + expr->data.monadic->flags = expr->flags; + expr = expr->data.monadic; + goto loop; + } + } + } + break; + case EINDIRECT: + if (flag2) { + if (!CExpr_IsLValue(expr)) + CError_Warning(CErrorStr142); + + if ( + ENODE_IS(expr->data.monadic, EOBJREF) && + expr->data.monadic->data.objref->name == this_name_node && + cscope_currentfunc && + cscope_currentclass && + expr->data.monadic->data.objref == CClass_ThisSelfObject()) + CError_Error(CErrorStr189); + } + if (flag1) { + if (CParser_IsConst(expr->rtype, expr->flags & ENODE_FLAG_QUALS)) + CError_Error(CErrorStr179); + } + return expr; + case EPREINC: + case EPREDEC: + case EASS: + case EMULASS: + case EDIVASS: + case EMODASS: + case EADDASS: + case ESUBASS: + case ESHLASS: + case ESHRASS: + case EANDASS: + case EXORASS: + case EORASS: + case ECOMMA: + if (copts.cplusplus) { + if ((eanode = CExpr_GetEA(expr))) { + tmpnode = makediadicnode(expr, eanode, ECOMMA); + tmpnode->rtype = tmpnode->data.diadic.right->rtype; + tmpnode = makemonadicnode(tmpnode, EINDIRECT); + tmpnode->rtype = expr->rtype; + return tmpnode; + } + CError_Error(CErrorStr190); + return expr; + } + break; + case ECOND: + if ( + copts.cplusplus && + is_typesame(expr->data.cond.expr1->rtype, expr->data.cond.expr2->rtype) && + (expr->data.cond.expr1->rtype->type != TYPEPOINTER || (UInt32) (expr->data.cond.expr1->flags & ENODE_FLAG_QUALS) == (expr->data.cond.expr2->flags & ENODE_FLAG_QUALS)) + ) { + expr->data.cond.expr1 = CExpr_LValue(expr->data.cond.expr1, flag1, flag2); + expr->data.cond.expr2 = CExpr_LValue(expr->data.cond.expr2, flag1, flag2); + if (ENODE_IS(expr->data.cond.expr1, EINDIRECT) && ENODE_IS(expr->data.cond.expr2, EINDIRECT)) { + if (!ENODE_IS(expr->data.cond.expr1->data.monadic, EBITFIELD) && !ENODE_IS(expr->data.cond.expr2->data.monadic, EBITFIELD)) { + expr->data.cond.expr1 = getnodeaddress(expr->data.cond.expr1, 0); + expr->data.cond.expr2 = getnodeaddress(expr->data.cond.expr2, 0); + expr->rtype = expr->data.cond.expr1->rtype; + tmpnode = makemonadicnode(expr, EINDIRECT); + tmpnode->rtype = TYPE_POINTER(tmpnode->rtype)->target; + return tmpnode; + } + } + } + break; + } + + if (flag2) + CError_Error(CErrorStr142); + return expr; +} + +ENode *CExpr_MakeObjRefNode(Object *obj, Boolean flag) { + ENode *expr; + + if (obj->sclass == TK_TYPEDEF) { + CError_Error(CErrorStr141); + return intconstnode((Type *) &void_ptr, 0); + } + + expr = lalloc(sizeof(ENode)); + memclrw(expr, sizeof(ENode)); + expr->type = EOBJREF; + expr->data.objref = obj; + expr->rtype = CDecl_NewPointerType(obj->type); + + if (!IS_TYPE_FUNC(obj->type)) + expr->flags = obj->qual & ENODE_FLAG_QUALS; + if (flag) + obj->flags |= OBJECT_USED; + + return expr; +} + +ENode *create_objectrefnode(Object *obj) { + if (name_obj_check && !name_obj_check(NULL, obj)) + return intconstnode((Type *) &void_ptr, 0); + return CExpr_MakeObjRefNode(obj, 1); +} + +ENode *create_objectnode2(Object *obj) { + ENode *expr; + + if (name_obj_check && !name_obj_check(NULL, obj)) + return nullnode(); + + expr = makemonadicnode(CExpr_MakeObjRefNode(obj, 1), EINDIRECT); + expr->rtype = TYPE_POINTER(expr->rtype)->target; + return expr; +} + +ENode *create_objectnode(Object *obj) { + return checkreference(create_objectnode2(obj)); +} + +static ENode *CExpr_ExpandArg(ENode *expr, Type *type) { + if (ENODE_IS(expr, ETYPCON) && IS_TYPE_FLOAT(type)) { + expr->rtype = type; + return expr; + } else { + return promote(expr, type); + } +} + +ENode *CExpr_IsTempConstruction(ENode *expr, Type *type, ENode **resultexpr) { + ENodeList *args; + ENode *funccall; + ENode *funcref; + + if ( + !ENODE_IS(expr, EINDIRECT) || + expr->rtype != type || + !ENODE_IS((funccall = expr->data.monadic), EFUNCCALL) || + !(args = funccall->data.funccall.args) + ) + return NULL; + + if (!ENODE_IS((funcref = funccall->data.funccall.funcref), EOBJREF) || !CClass_IsConstructor(funcref->data.objref)) { + if (expr->data.monadic->data.funccall.functype->functype != type) + return NULL; + if (CABI_GetStructResultArgumentIndex(expr->data.monadic->data.funccall.functype) == 1) { + args = args->next; + CError_ASSERT(1277, args); + } + } + + if (resultexpr) + *resultexpr = args->node; + return expr->data.monadic; +} + +ENode *CExpr_AdjustFunctionCall(ENode *expr) { + ENodeList *list; + + switch (expr->data.funccall.functype->functype->type) { + case TYPECLASS: + CDecl_CompleteType(expr->data.funccall.functype->functype); + case TYPESTRUCT: + if (!expr->data.funccall.functype->functype->size) + CError_Error(CErrorStr136, expr->data.funccall.functype->functype, 0); + } + + if (CMach_GetFunctionResultClass(expr->data.funccall.functype)) { + list = lalloc(sizeof(ENodeList)); + if (IS_TYPE_CLASS(expr->data.funccall.functype->functype)) { + CDecl_CompleteType(expr->data.funccall.functype->functype); + if (CClass_Destructor(TYPE_CLASS(expr->data.funccall.functype->functype))) + list->node = create_temp_node2(expr->rtype); + else + list->node = create_temp_node(expr->rtype); + } else { + list->node = create_temp_node(expr->rtype); + } + list->next = expr->data.funccall.args; + expr->data.funccall.args = list; + + if (expr->data.funccall.funcref->flags & ENODE_FLAG_10) + expr = CSOM_EnvCheck(expr, list); + + expr = makemonadicnode(expr, EINDIRECT); + expr->data.monadic->rtype = CDecl_NewPointerType(expr->rtype); + return expr; + } + + if (expr->data.funccall.funcref->flags & ENODE_FLAG_10) + expr = CSOM_EnvCheck(expr, NULL); + return expr; +} + +ENode *funccallexpr(Object *func, ENode *arg1, ENode *arg2, ENode *arg3, ENode *arg4) { + ENode *expr; + TypeFunc *tfunc; + ENodeList *list; + + tfunc = TYPE_FUNC(func->type); + CError_ASSERT(1411, IS_TYPE_FUNC(tfunc)); + + expr = lalloc(sizeof(ENode)); + expr->type = EFUNCCALL; + expr->cost = 4; + expr->rtype = tfunc->functype; + expr->flags = tfunc->qual & ENODE_FLAG_QUALS; + expr->data.funccall.funcref = create_objectrefnode(func); + expr->data.funccall.functype = tfunc; + + if (arg1) { + list = lalloc(sizeof(ENodeList)); + expr->data.funccall.args = list; + list->node = arg1; + if (arg2) { + list->next = lalloc(sizeof(ENodeList)); + list = list->next; + list->node = arg2; + if (arg3) { + list->next = lalloc(sizeof(ENodeList)); + list = list->next; + list->node = arg3; + if (arg4) { + list->next = lalloc(sizeof(ENodeList)); + list = list->next; + list->node = arg4; + } + } + } + list->next = NULL; + } else { + expr->data.funccall.args = NULL; + } + + return CExpr_AdjustFunctionCall(expr); +} + +ENode *CExpr_FuncCallSix(Object *func, ENode *arg1, ENode *arg2, ENode *arg3, ENode *arg4, ENode *arg5, ENode *arg6) { + ENode *expr; + TypeFunc *tfunc; + ENodeList *list; + + tfunc = TYPE_FUNC(func->type); + CError_ASSERT(1460, IS_TYPE_FUNC(tfunc)); + + expr = lalloc(sizeof(ENode)); + expr->type = EFUNCCALL; + expr->cost = 4; + expr->rtype = tfunc->functype; + expr->flags = tfunc->qual & ENODE_FLAG_QUALS; + expr->data.funccall.funcref = create_objectrefnode(func); + expr->data.funccall.functype = tfunc; + + list = lalloc(sizeof(ENodeList)); + expr->data.funccall.args = list; + list->node = arg1; + list->next = lalloc(sizeof(ENodeList)); + list = list->next; + list->node = arg2; + list->next = lalloc(sizeof(ENodeList)); + list = list->next; + list->node = arg3; + list->next = lalloc(sizeof(ENodeList)); + list = list->next; + list->node = arg4; + list->next = lalloc(sizeof(ENodeList)); + list = list->next; + list->node = arg5; + if (arg6) { + list->next = lalloc(sizeof(ENodeList)); + list = list->next; + list->node = arg6; + } + list->next = NULL; + + return CExpr_AdjustFunctionCall(expr); +} + +static void CExpr_CalcStdAssign(short checkresult, Match5 *match, Type *t1, UInt32 q1, Type *t2, UInt32 q2, Boolean flag) { + memclrw(match, sizeof(Match5)); + switch (checkresult) { + case CheckResult1: + match->x0++; + break; + case CheckResult2: + match->x2++; + break; + case CheckResult3: + match->x4++; + match->x6 += assign_value; + break; + default: + CError_FATAL(1504); + } + + if (flag || (IS_TYPE_POINTER_ONLY(t2) && (IS_TYPE_POINTER_ONLY(t1) || IS_TYPEPOINTER_REFERENCE(TYPE_POINTER(t2))) != 0)) { + if ((q2 & Q_CONST) == (q1 & Q_CONST)) + match->x8++; + if ((q2 & Q_VOLATILE) == (q1 & Q_VOLATILE)) + match->x8++; + } +} + +void CExpr_MatchCV(Type *t1, UInt32 q1, Type *t2, UInt32 q2, Match13 *match) { + Boolean r8; + + if (IS_TYPEPOINTER_REFERENCE(TYPE_POINTER(t2))) { + t2 = TYPE_POINTER(t2)->target; + r8 = 1; + } else { + r8 = 0; + } + + while (IS_TYPE_POINTER_ONLY(t2) && IS_TYPE_POINTER_ONLY(t1)) { + if (r8) { + if ((TYPE_POINTER(t1)->qual & Q_CONST) != (TYPE_POINTER(t2)->qual & Q_CONST)) + match->anotherm5.x8--; + if ((TYPE_POINTER(t1)->qual & Q_VOLATILE) != (TYPE_POINTER(t2)->qual & Q_VOLATILE)) + match->anotherm5.x8--; + } + t2 = TYPE_POINTER(t2)->target; + t1 = TYPE_POINTER(t1)->target; + r8 = 1; + } + + if ((q1 & Q_CONST) != (q2 & Q_CONST)) + match->anotherm5.x8--; + if ((q1 & Q_VOLATILE) != (q2 & Q_VOLATILE)) + match->anotherm5.x8--; +} + +Boolean CExpr_MatchAssign(Type *type, UInt32 qual, ENode *expr, Match13 *match) { + switch (assign_check(expr, type, qual, 0, 0, 1)) { + case CheckResult0: + return 0; + case CheckResult1: + match->anotherm5.x0++; + break; + case CheckResult2: + match->anotherm5.x2++; + break; + case CheckResult3: + match->anotherm5.x4++; + match->anotherm5.x6 += assign_value; + break; + case CheckResult4: + match->xE++; + match->match5.x0 += user_std_match.x0; + match->match5.x2 += user_std_match.x2; + match->match5.x4 += user_std_match.x4; + match->match5.x6 += user_std_match.x6; + match->match5.x8 += user_std_match.x8; + break; + default: + CError_FATAL(1585); + } + + if (IS_TYPE_POINTER_ONLY(type)) + CExpr_MatchCV(expr->rtype, expr->flags & ENODE_FLAG_QUALS, type, qual, match); + + return 1; +} + +static short CExpr_StdMatchCompare(Match5 *a, Match5 *b, Boolean flag) { + if (a->x0 > b->x0) return 1; + if (a->x0 == b->x0) { + if (a->x2 > b->x2) return 1; + if (a->x2 == b->x2) { + if (a->x4 > b->x4) return 1; + if (a->x4 == b->x4) { + if (a->x6 > b->x6) return 1; + if (a->x6 == b->x6) { + if (!flag) + return 0; + if (a->x8 > b->x8) return 1; + if (a->x8 == b->x8) return 0; + } + } + } + } + return -1; +} + +static short CExpr2_MemberPointerConversion(Type *type, ENode *expr, Boolean flag1) { + ENode *newnode; + short depth; + + newnode = lalloc(sizeof(ENode)); + *newnode = *expr; + if (!IS_TYPE_MEMBERPOINTER(newnode->rtype)) { + newnode = CExpr_MemberPointerConversion(newnode, TYPE_MEMBER_POINTER(type), flag1); + if (iscpp_typeequal(newnode->rtype, type)) { + if (flag1) + assign_node = newnode; + return CheckResult3; + } + } + + if (IS_TYPE_MEMBERPOINTER(newnode->rtype)) { + CError_ASSERT(1656, IS_TYPE_CLASS(TYPE_MEMBER_POINTER(type)->ty2)); + CError_ASSERT(1657, IS_TYPE_CLASS(TYPE_MEMBER_POINTER(newnode->rtype)->ty2)); + + if (CClass_IsBaseClass(TYPE_CLASS(TYPE_MEMBER_POINTER(type)->ty2), TYPE_CLASS(TYPE_MEMBER_POINTER(newnode->rtype)->ty2), &depth, 0, 0)) { + assign_value = 1000 - depth; + if (flag1) + assign_node = PointerToMemberCast(newnode, TYPE_MEMBER_POINTER(newnode->rtype), TYPE_MEMBER_POINTER(type), 1); + return CheckResult3; + } + } + + return CheckResult0; +} + +ENode *CExpr_ClassPointerCast(BClassList *cls, ENode *origexpr, Boolean nullcheckflag) { + ENode *expr; + ClassList *base; + Boolean do_nullcheck; + TypeClass *tclass; + SInt32 offset; + ENode *tmp; + + expr = origexpr; + tclass = TYPE_CLASS(cls->type); + do_nullcheck = 0; + CError_ASSERT(1691, cls); + + if (!IS_TYPE_POINTER_ONLY(origexpr->rtype)) { + CError_Error(CErrorStr141); + return origexpr; + } + + cls = cls->next; + while (cls) { + for (base = tclass->bases; base; base = base->next) { + if (base->base == TYPE_CLASS(cls->type)) + break; + } + + if (!base) { + CError_Error(CErrorStr221); + while (cls->next) + cls = cls->next; + + tmp = nullnode(); + tmp->rtype = CDecl_NewPointerType(cls->type); + return tmp; + } + + if (base->is_virtual) { + if (!base->base->sominfo) { + do_nullcheck = 1; + if ((offset = base->offset) && !canadd(expr, offset)) { + expr = makediadicnode(expr, intconstnode(TYPE(&stunsignedlong), offset), EADD); + optimizecomm(expr); + } + expr->rtype = CDecl_NewPointerType(CDecl_NewPointerType(TYPE(base->base))); + expr = makemonadicnode(expr, EINDIRECT); + } + } else { + if ((offset = base->offset)) { + do_nullcheck = 1; + if (!canadd(expr, offset)) { + expr = makediadicnode(expr, intconstnode(TYPE(&stunsignedlong), offset), EADD); + optimizecomm(expr); + } + } + } + + switch (expr->type) { + case EPOSTINC: + case EPOSTDEC: + case EPREINC: + case EPREDEC: + expr = makemonadicnode(expr, ETYPCON); + } + + expr->rtype = CDecl_NewPointerType(TYPE(base->base)); + tclass = TYPE_CLASS(cls->type); + cls = cls->next; + } + + if (nullcheckflag && do_nullcheck) + expr = do_castnullcheck(expr, origexpr); + return expr; +} + +ENode *CExpr_GetClassAccessNode(BClassList *a, BClassList *b, ENode *expr, Object *obj, AccessType access, Boolean flag) { + TypeClass *tclass; + ENode *tmp; + + if (!expr) { + if (!cscope_currentfunc || !cscope_currentclass || !cscope_is_member_func || !(expr = CClass_CreateThisSelfExpr())) { + CError_Error(CErrorStr221); + return NULL; + } + expr = makemonadicnode(expr, EINDIRECT); + expr->rtype = TYPE(cscope_currentclass); + } + + CError_ASSERT(1786, a); + CError_ASSERT(1787, IS_TYPE_CLASS(expr->rtype)); + + tclass = TYPE_CLASS(expr->rtype); + a = CScope_GetClassAccessPath(a, tclass); + if (!a || a->type != TYPE(tclass)) { + CError_Error(CErrorStr221); + return NULL; + } + + if (flag) + CClass_CheckPathAccess(a, obj, access); + + if (!TYPE_CLASS(a->type)->sominfo) { + if (b) + a = CClass_AppendPath(a, b); + + if (!ENODE_IS(expr, EINDIRECT)) + expr = CExpr_LValue(expr, 0, 0); + + if (ENODE_IS(expr, EINDIRECT)) { + expr->data.monadic->flags = expr->flags; + tmp = expr->data.monadic; + switch (tmp->type) { + case EPOSTINC: + case EPOSTDEC: + case EPREINC: + case EPREDEC: + tmp = makemonadicnode(tmp, ETYPCON); + } + expr = makemonadicnode(CExpr_ClassPointerCast(a, tmp, 0), EINDIRECT); + expr->rtype = TYPE(tclass); + } + } + + return expr; +} + +static short std_assign_check_overload(NameSpaceObjectList *list, TemplArg *templargs, Type *type, Boolean flag1) { + Object *obj; + Object *used_obj; + Boolean found_non_template_func; + Boolean is_ambig; + TemplFuncInstance *instance; + ENode *expr; + Object *cmp1; + Object *cmp2; + + if (!IS_TYPE_POINTER_ONLY(type) || !IS_TYPE_FUNC(TYPE_POINTER(type)->target)) + return CheckResult0; + + used_obj = NULL; + type = TYPE_POINTER(type)->target; + found_non_template_func = 0; + is_ambig = 0; + for (; list; list = list->next) { + obj = OBJECT(list->object); + if (obj->otype != OT_OBJECT) + continue; + + if (IS_TYPE_FUNC(obj->type) && (TYPE_FUNC(obj->type)->flags & FUNC_IS_TEMPL)) { + if (!found_non_template_func && CTempl_CanDeduceFunc(obj, TYPE_FUNC(type), templargs)) { + instance = CTempl_DeduceFunc(obj, TYPE_FUNC(type), templargs, NULL, 0); + CError_ASSERT(1861, instance); + if (is_typesame(instance->object->type, type)) { + if (used_obj && used_obj != instance->object) + is_ambig = 1; + else + used_obj = instance->object; + } + } + } else { + if (is_typesame(obj->type, type)) { + if (used_obj && found_non_template_func) { + cmp1 = obj; + if (obj->datatype == DALIAS) + cmp1 = obj->u.alias.object; + cmp2 = used_obj; + if (used_obj->datatype == DALIAS) + cmp2 = used_obj->u.alias.object; + if (cmp1 != cmp2) + is_ambig = 1; + } else { + is_ambig = 0; + used_obj = obj; + } + found_non_template_func = 1; + } + } + } + + if (used_obj) { + if (flag1) { + if (is_ambig) + CError_Error(CErrorStr199); + expr = CExpr_MakeObjRefNode(used_obj, 1); + assign_node = expr; + expr->rtype = CDecl_NewPointerType(used_obj->type); + expr->flags = obj->qual & ENODE_FLAG_QUALS; + used_obj->flags |= OBJECT_USED; + if (used_obj->datatype == DINLINEFUNC) + CError_Error(CErrorStr175); + } + return CheckResult1; + } else { + return CheckResult0; + } +} + +ENode *CExpr_ConvertToBool(ENode *expr, Boolean isExplicit) { + if (IS_TYPE_MEMBERPOINTER(expr->rtype)) + expr = CExpr_ConvertToCondition(expr); + + switch (expr->rtype->type) { + case TYPEINT: + case TYPEFLOAT: + case TYPEENUM: + case TYPEPOINTER: + if (IS_TYPE_ENUM(expr->rtype)) + expr = forceintegral(expr); + switch (expr->type) { + case EINTCONST: + CInt64_SetLong(&expr->data.intval, !CInt64_IsZero(&expr->data.intval)); + break; + case EFLOATCONST: + CInt64_SetLong(&expr->data.intval, !CMach_FloatIsZero(expr->data.floatval)); + expr->type = EINTCONST; + break; + default: + expr = makemonadicnode(expr, ELOGNOT); + expr->rtype = TYPE(&stbool); + expr = makemonadicnode(expr, ELOGNOT); + } + break; + default: + CError_Error( + isExplicit ? CErrorStr247 : CErrorStr209, + expr->rtype, + expr->flags & ENODE_FLAG_QUALS, + &stbool, + 0); + expr = nullnode(); + } + + expr->rtype = TYPE(&stbool); + return expr; +} + +static short std_assign_check(ENode *expr, Type *type, Boolean flag1, Boolean flag2) { + short result; + + if (copts.cplusplus) { + illegalimplicitconversion = 0; + + if ((result = iscpp_typeequal(expr->rtype, type))) { + assign_node = expr; + if (result == -1) { + assign_value = 1; + return CheckResult3; + } else { + return CheckResult1; + } + } + + if (flag1 && illegalimplicitconversion) { + CError_Error(CErrorStr209, expr->rtype, expr->flags & ENODE_FLAG_QUALS, type, 0); + return CheckResult0; + } + } else { + if (is_typeequal(expr->rtype, type)) { + assign_node = expr; + return CheckResult1; + } + } + + if (type == TYPE(&stbool)) { + switch (expr->rtype->type) { + case TYPEPOINTER: + case TYPEMEMBERPOINTER: + assign_value = 0; + case TYPEINT: + case TYPEFLOAT: + case TYPEENUM: + if (flag1) + assign_node = CExpr_ConvertToBool(expr, 0); + return CheckResult3; + default: + return CheckResult0; + } + } + + if (IS_TYPE_ENUM(expr->rtype) && (IS_TYPE_INT(type) || IS_TYPE_FLOAT(type))) { + result = CheckResult3; + if (IS_TYPE_INT(type)) { + if (TYPE_ENUM(expr->rtype)->enumtype == type) { + result = CheckResult2; + } else if (TYPE_INTEGRAL(TYPE_ENUM(expr->rtype)->enumtype)->integral < IT_INT) { + switch (TYPE_INTEGRAL(type)->integral) { + case IT_INT: + if (expr->rtype->size < stsignedint.size || TYPE_ENUM(expr->rtype)->enumtype == TYPE(&stsignedshort)) + result = CheckResult2; + break; + case IT_UINT: + if (expr->rtype->size >= stsignedint.size && TYPE_ENUM(expr->rtype)->enumtype != TYPE(&stsignedshort)) + result = CheckResult2; + break; + } + } + } + if (flag1) { + expr->rtype = TYPE_ENUM(expr->rtype)->enumtype; + assign_node = promote(expr, type); + } + return result; + } + + if (IS_TYPE_INT(expr->rtype) && (IS_TYPE_INT(type) || IS_TYPE_FLOAT(type))) { + result = CheckResult3; + if (TYPE_INTEGRAL(expr->rtype)->integral <= IT_INT) { + if (type == TYPE(&stsignedint) || type == TYPE(&stunsignedint)) { + switch (TYPE_INTEGRAL(type)->integral) { + case IT_INT: + if (expr->rtype->size < stsignedint.size || type != TYPE(&stunsignedshort)) + result = CheckResult2; + break; + case IT_UINT: + if (expr->rtype->size == stsignedint.size && type == TYPE(&stunsignedshort)) + result = CheckResult2; + break; + } + } + } + + if (flag1 && type != expr->rtype) + assign_node = promote(expr, type); + else + assign_node = expr; + return result; + } + + if (IS_TYPE_FLOAT(expr->rtype) && (IS_TYPE_INT(type) || IS_TYPE_FLOAT(type))) { + if (type == TYPE(&stdouble) && (expr->rtype == TYPE(&stfloat) || expr->rtype == TYPE(&stshortdouble))) + result = CheckResult2; + else + result = CheckResult3; + + if (flag1 && (!IS_TYPE_FLOAT(type) || type->size != expr->rtype->size)) + assign_node = promote(expr, type); + else + assign_node = expr; + return result; + } + + if (IS_TYPE_POINTER_ONLY(type)) { + if (ENODE_IS(expr, EINTCONST) && CInt64_IsZero(&expr->data.intval) && (IS_TYPE_INT(expr->rtype) || (!copts.cplusplus && IS_TYPE_ENUM(expr->rtype)))) { + if (flag1) + expr->rtype = TYPE(&stunsignedlong); + assign_node = expr; + return CheckResult3; + } + if (ENODE_IS(expr, EOBJLIST)) { + return std_assign_check_overload(expr->data.objlist.list, expr->data.objlist.templargs, type, flag1); + } + if (IS_TYPE_POINTER_ONLY(expr->rtype)) { + if (ENODE_IS(expr, EOBJREF) && IS_TYPE_FUNC(expr->data.objref->type) && (TYPE_FUNC(expr->data.objref->type)->flags & FUNC_IS_TEMPL)) { + NameSpaceObjectList list; + list.next = NULL; + list.object = OBJ_BASE(expr->data.objref); + return std_assign_check_overload(&list, NULL, type, flag1); + } + if (copts.objective_c && CObjC_IsCompatibleType(expr->rtype, type)) { + assign_value = 1; + return CheckResult3; + } + if (IS_TYPE_CLASS(TYPE_POINTER(expr->rtype)->target) && IS_TYPE_CLASS(TYPE_POINTER(type)->target)) { + short depth; + Boolean isambig; + BClassList *path; + path = CClass_GetBasePath( + TYPE_CLASS(TYPE_POINTER(expr->rtype)->target), + TYPE_CLASS(TYPE_POINTER(type)->target), + &depth, &isambig + ); + if (path) { + assign_value = 1000 - depth; + if (flag1) { + if (isambig) + CError_Error(CErrorStr188); + if (flag2) + CClass_CheckPathAccess(path, NULL, ACCESSPUBLIC); + assign_node = CExpr_ClassPointerCast(path, expr, 1); + } + return CheckResult3; + } else { + if (flag1) { + if (isambig) + CError_Error(CErrorStr188); + else + CError_Error( + CErrorStr244, + expr->rtype, + expr->flags & ENODE_FLAG_QUALS, + type, + 0); + } + return CheckResult0; + } + } + } + } + + if (IS_TYPE_MEMBERPOINTER(type) && !IS_TYPE_CLASS(expr->rtype)) { + return CExpr2_MemberPointerConversion(type, expr, flag1); + } + + if (IS_TYPE_CLASS(expr->rtype) && IS_TYPE_CLASS(type)) { + short depth; + Boolean isambig; + BClassList *path; + path = CClass_GetBasePath( + TYPE_CLASS(expr->rtype), + TYPE_CLASS(type), + &depth, &isambig + ); + if (path) { + assign_value = 1000 - depth; + if (flag1) { + if (isambig) + CError_Error(CErrorStr188); + CClass_CheckPathAccess(path, NULL, ACCESSPUBLIC); + assign_node = getnodeaddress(expr, 0); + assign_node = CExpr_ClassPointerCast(path, assign_node, 0); + assign_node = makemonadicnode(assign_node, EINDIRECT); + assign_node->rtype = type; + } + return CheckResult3; + } + } + + if (IS_TYPE_ENUM(type)) { + switch (expr->rtype->type) { + case TYPEINT: + case TYPEFLOAT: + case TYPEENUM: + if (!copts.cplusplus) { + if (flag1) { + if (copts.pedantic) + CError_Warning(CErrorStr217, expr->rtype, expr->flags & ENODE_FLAG_QUALS, type, 0); + assign_node = do_typecast(expr, type, 0); + assign_node->flags = expr->flags; + } + return CheckResult2; + } else { + if (flag1) + CError_Error(CErrorStr217, expr->rtype, expr->flags & ENODE_FLAG_QUALS, type, 0); + } + } + } + + return CodeGen_AssignCheck(expr, type, flag1, flag2); +} + +static short is_compatible_conversion(Type *a, Type *b) { + if (IS_TYPE_REFERENCE(a)) + a = TYPE_POINTER(a)->target; + if (IS_TYPE_REFERENCE(b)) + b = TYPE_POINTER(b)->target; + return iscpp_typeequal(b, a); +} + +static void CExpr_ConIteratorInit(ConIterator *iter) { + ClassList *base; + ConIterator *subiter; + ConIteratorList *list; + + for (base = iter->tclass->bases; base; base = base->next) { + if (base->base->flags & CLASS_IS_CONVERTIBLE) { + subiter = galloc(sizeof(ConIterator)); + memclrw(subiter, sizeof(ConIterator)); + subiter->parent = iter; + subiter->tclass = base->base; + CExpr_ConIteratorInit(subiter); + + list = galloc(sizeof(ConIteratorList)); + memclrw(list, sizeof(ConIteratorList)); + list->iter = subiter; + list->next = iter->children; + iter->children = list; + } + } +} + +void CExpr_ConversionIteratorInit(ConversionIterator *iter, TypeClass *tclass) { + memclrw(iter, sizeof(ConversionIterator)); + if (tclass->flags & CLASS_IS_CONVERTIBLE) { + iter->coniter = &iter->myconiter; + iter->myconiter.tclass = tclass; + CExpr_ConIteratorInit(&iter->myconiter); + CScope_InitObjectIterator(&iter->objiter, tclass->nspace); + } +} + +static Boolean CExpr_ConversionIteratorIsHidden(ConIterator *iter, TypeFunc *tfunc) { + CScopeObjectIterator objiter; + ObjBase *obj; + TypeFunc *objtfunc; + + while (iter) { + CScope_InitObjectIterator(&objiter, iter->tclass->nspace); + while (1) { + if (!(obj = CScope_NextObjectIteratorObject(&objiter))) + break; + + objtfunc = TYPE_FUNC(OBJECT(obj)->type); + if ( + IS_TYPE_FUNC(objtfunc) && + (objtfunc->flags & FUNC_CONVERSION) && + is_compatible_conversion(tfunc->functype, objtfunc->functype) && + (tfunc->args->qual & Q_CONST) == (objtfunc->args->qual & Q_CONST) && + (tfunc->qual & Q_CONST) == (objtfunc->qual & Q_CONST) + ) + return 1; + } + iter = iter->parent; + } + + return 0; +} + +Object *CExpr_ConversionIteratorNext(ConversionIterator *iter) { + ConIterator *ci; + Object *obj; + + ci = iter->coniter; + if (!ci) + return NULL; + +restart: + if ((obj = OBJECT(CScope_NextObjectIteratorObject(&iter->objiter)))) { + if ( + IS_TYPE_FUNC(obj->type) && + (TYPE_FUNC(obj->type)->flags & FUNC_CONVERSION) && + !CExpr_ConversionIteratorIsHidden(ci->parent, TYPE_FUNC(obj->type)) + ) { + return obj; + } + goto restart; + } + + do { + if (ci->children) { + iter->coniter = ci->children->iter; + ci->children = ci->children->next; + ci = iter->coniter; + CScope_InitObjectIterator(&iter->objiter, ci->tclass->nspace); + goto restart; + } + } while ((ci = ci->parent)); + + return NULL; +} + +short user_assign_check(ENode *expr, Type *type, UInt32 qual, Boolean flag1, Boolean flag2, Boolean flag3) { + Object *r26; + ENode *r25; + Boolean r24; + Boolean r23; + Boolean r22; + Type *r18b; + short r18; + TypeFunc *r17; + Object *r17b; + NameSpaceObjectList *r16b; + Object *r16; + Object *r15; + ENode *r15b; + ENode *r14; + short r14b; + TypeFunc *r14c; + ENodeList *r14d; + TypeMemberFunc *r13; + ENodeList *r13b; + short result; + FuncArg *arg; + ConversionIterator iter; + Match5 stdmatch; + Match5 match_8C; + Match5 match_98; + BClassList path; + UInt16 chk; + Boolean is_const, is_volatile; + + CError_ASSERT(2378, copts.old_argmatch); + + memclrw(&stdmatch, sizeof(Match5)); + r24 = 0; + r22 = 0; + r23 = 0; + + if (!type->size) + CDecl_CompleteType(type); + if (!expr->rtype->size) + CDecl_CompleteType(expr->rtype); + + if (IS_TYPE_CLASS(expr->rtype)) { + r18 = 0; + CExpr_ConversionIteratorInit(&iter, TYPE_CLASS(expr->rtype)); + while ((r16 = CExpr_ConversionIteratorNext(&iter))) { + r17 = TYPE_FUNC(r16->type); + r14 = CExpr_NewENode(ETEMP); + r14->rtype = r17->functype; + if (IS_TYPE_REFERENCE(r14->rtype)) { + r14->rtype = TYPE_POINTER(r14->rtype)->target; + if (!CParser_IsConst(r14->rtype, r17->qual)) { + r14 = makemonadicnode(r14, EINDIRECT); + r14->data.monadic->rtype = TYPE(&void_ptr); + r14 = makemonadicnode(r14, EINDIRECT); + r14->data.monadic->rtype = TYPE(&void_ptr); + } + } + if ((result = std_assign_check(r14, type, 0, flag3))) { + CExpr_CalcStdAssign(result, &match_98, r17->functype, r17->qual, type, qual, 1); + CError_ASSERT(2419, r17->args && IS_TYPE_POINTER_ONLY(r17->args->type)); + chk = expr->flags; + if (!(is_const = (r17->args->qual & Q_CONST)) && (chk & Q_CONST) != 0) + continue; + if (!(is_volatile = (r17->args->qual & Q_VOLATILE)) && (chk & Q_VOLATILE) != 0) + continue; + //if (((r17->args->qual & Q_CONST) == 0 && (chk & Q_CONST) != 0) || ((r17->args->qual & Q_VOLATILE) == 0 && (chk & Q_VOLATILE) != 0)) + // continue; + + r14b = 0; + if (is_const == (expr->flags & Q_CONST)) + r14b++; + if (is_volatile == (expr->flags & Q_VOLATILE)) + r14b++; + switch (CExpr_StdMatchCompare(&match_98, &stdmatch, 1)) { + case -1: + continue; + case 0: + if (r26 == r16) + continue; + if (r14b < r18) + continue; + if (r14b != r18) + break; + r22 = 1; + continue; + } + r26 = r16; + stdmatch = match_98; + r24 = 1; + r22 = 0; + r18 = r14b; + } + } + } + + if (IS_TYPE_CLASS(type) && (r16b = CClass_Constructor(TYPE_CLASS(type)))) { + memclrw(&match_8C, sizeof(Match5)); + for (; r16b; r16b = r16b->next) { + r17b = OBJECT(r16b->object); + if (r17b->otype != OT_OBJECT) + continue; + r14c = TYPE_FUNC(r17b->type); + if (!IS_TYPE_FUNC(r14c)) + continue; + if (!flag2 && (r14c->qual & Q_EXPLICIT)) + continue; + if (!r14c->args) + continue; + if (!(arg = r14c->args->next)) + continue; + if ((TYPE_CLASS(type)->flags & CLASS_HAS_VBASES) && !(arg = arg->next)) + continue; + if (arg == &elipsis) + continue; + if (arg->next && !arg->next->dexpr && arg->next != &elipsis) + continue; + + r18b = arg->type; + if (IS_TYPE_REFERENCE(r18b)) { + r18b = TYPE_POINTER(r18b)->target; + if (!CParser_IsConst(r18b, arg->qual) && !CExpr_IsLValue(expr)) + continue; + } + + if ((result = std_assign_check(expr, r18b, 0, flag3))) { + CExpr_CalcStdAssign(result, &match_98, r14c->functype, r14c->qual, type, qual, 0); + switch (CExpr_StdMatchCompare(&match_98, &match_8C, 1)) { + case -1: + case 0: + continue; + } + r25 = expr; + match_8C = match_98; + r23 = 1; + r15 = r17b; + } + } + + if (r23) { + if (r24) { + switch (CExpr_StdMatchCompare(&stdmatch, &match_8C, 1)) { + case -1: + stdmatch = match_8C; + r24 = 0; + break; + case 0: + r22 = 1; + break; + } + } else { + stdmatch = match_8C; + } + } + } + + if (r22 && flag1) + CError_Error(CErrorStr199); + + if (r24 || r23) { + if (flag1) { + if (r24) { + r13 = TYPE_METHOD(r26->type); + CError_ASSERT(2537, r13->flags & FUNC_METHOD); + r15b = create_objectrefnode(r26); + r26->flags |= OBJECT_USED; + r14d = lalloc(sizeof(ENodeList)); + r14d->next = NULL; + expr = getnodeaddress(expr, 0); + r14d->node = CExpr_AssignmentPromotion(expr, CDecl_NewPointerType(TYPE(r13->theclass)), expr->flags, 0); + + expr = lalloc(sizeof(ENode)); + expr->type = EFUNCCALL; + expr->cost = 4; + expr->rtype = r13->functype; + expr->flags = r13->qual & ENODE_FLAG_QUALS; + expr->data.funccall.funcref = r15b; + expr->data.funccall.args = r14d; + expr->data.funccall.functype = TYPE_FUNC(r26->type); + assign_node = checkreference(CExpr_AdjustFunctionCall(expr)); + if (assign_node->rtype != type) + assign_node = CExpr_AssignmentPromotion(assign_node, type, qual, 1); + if (!IS_TYPE_REFERENCE(r13->functype)) + temp_reference_init = 1; + } else { + r13b = lalloc(sizeof(ENodeList)); + r13b->next = NULL; + r13b->node = r25; + if (TYPE_CLASS(type)->flags & CLASS_HAS_VBASES) { + r13b->next = lalloc(sizeof(ENodeList)); + r13b->next->node = r25; + r13b->next->next = NULL; + r13b->node = intconstnode(TYPE(&stsignedshort), 1); + } + path.next = NULL; + path.type = type; + assign_node = makemonadicnode(create_temp_node(type), EINDIRECT); + assign_node->rtype = type; + assign_node = CExpr_GenericFuncCall(&path, assign_node, 0, r15, NULL, NULL, r13b, 0, 0, 1); + if (ENODE_IS2(assign_node, EFUNCCALL, EFUNCCALLP)) { + assign_node->rtype = CDecl_NewPointerType(type); + assign_node = makemonadicnode(assign_node, EINDIRECT); + assign_node->rtype = type; + } + temp_reference_init = 1; + } + } + + user_std_match = stdmatch; + return CheckResult4; + } else { + if (flag1) + CError_Error(CErrorStr244, expr->rtype, expr->flags & ENODE_FLAG_QUALS, type, qual); + return CheckResult0; + } +} + +ENode *CExpr_ConvertToCondition(ENode *expr) { + switch (expr->rtype->type) { + case TYPEINT: + case TYPEFLOAT: + case TYPEPOINTER: + return expr; + case TYPEENUM: + expr->rtype = TYPE_ENUM(expr->rtype)->enumtype; + return expr; + case TYPEMEMBERPOINTER: + return memberpointercompare(ENOTEQU, expr, nullnode()); + case TYPECLASS: + return CExpr_Convert(expr, TYPE(&stbool), 0, 0, 1); + default: + CError_Error(CErrorStr376, expr->rtype, expr->flags & ENODE_FLAG_QUALS); + return nullnode(); + } +} + +ENode *CExpr_ConvertToIntegral(ENode *expr) { + ConversionIterator iter; + Type *found; + Object *obj; + + switch (expr->rtype->type) { + case TYPEINT: + case TYPEENUM: + return integralpromote(expr); + case TYPECLASS: + CDecl_CompleteType(expr->rtype); + found = NULL; + CExpr_ConversionIteratorInit(&iter, TYPE_CLASS(expr->rtype)); + while ((obj = CExpr_ConversionIteratorNext(&iter))) { + if (IS_TYPE_INT_OR_ENUM(TYPE_FUNC(obj->type)->functype)) { + if (found) { + CError_Error(CErrorStr199); + break; + } + found = TYPE_FUNC(obj->type)->functype; + } + } + if (found) + return integralpromote(CExpr_Convert(expr, found, 0, 0, 1)); + break; + } + + CError_Error(CErrorStr376, expr->rtype, expr->flags & ENODE_FLAG_QUALS); + return nullnode(); +} + +void CExpr_CheckArithmConversion(ENode *expr, Type *type) { + CInt64 val; + + if (expr->rtype == type) + return; + if (expr->rtype == TYPE(&stbool)) + return; + + if (IS_TYPE_INT(expr->rtype)) { + if (IS_TYPE_FLOAT(type)) + return; + CError_ASSERT(2772, IS_TYPE_INT(type)); + + if (type->size > expr->rtype->size) + return; + if (type->size == expr->rtype->size && is_unsigned(type) == is_unsigned(expr->rtype)) + return; + + switch (expr->type) { + case EINTCONST: + if (!CInt64_IsNegative(&expr->data.intval) || is_unsigned(expr->rtype) || !is_unsigned(type)) { + val = CExpr_IntConstConvert(type, expr->rtype, expr->data.intval); + val = CExpr_IntConstConvert(expr->rtype, type, val); + if (CInt64_Equal(val, expr->data.intval)) + return; + } + break; + case ELOGNOT: + case ELESS: + case EGREATER: + case ELESSEQU: + case EGREATEREQU: + case EEQU: + case ENOTEQU: + case ELAND: + case ELOR: + return; + } + } else { + if (IS_TYPE_FLOAT(type) && type->size >= expr->rtype->size) + return; + } + + CError_Warning(CErrorStr317, expr->rtype, 0, type, 0); +} + +ENode *get_address_of_temp_copy(ENode *expr, Boolean flag) { + char buf[64]; + ENode *result; + Object *obj; + Type *innertype; + + if (flag) { + if (ENODE_IS2(expr, EINTCONST, EFLOATCONST)) { + obj = CParser_NewCompilerDefDataObject(); + obj->type = expr->rtype; + obj->name = CParser_GetUniqueName(); + obj->sclass = TK_STATIC; + if (ENODE_IS(expr, EINTCONST)) { + innertype = expr->rtype; + switch (innertype->type) { + case TYPEINT: + break; + case TYPEENUM: + innertype = TYPE_ENUM(innertype)->enumtype; + break; + case TYPEPOINTER: + innertype = TYPE(&stunsignedlong); + break; + default: + CError_FATAL(2857); + } + CMach_InitIntMem(innertype, expr->data.intval, buf); + } else { + CMach_InitFloatMem(expr->rtype, expr->data.floatval, buf); + } + CInit_DeclareData(obj, buf, NULL, obj->type->size); + return create_objectrefnode(obj); + } + + if (cinit_tempnodefunc == NULL) + result = CExpr_NewETEMPNode(expr->rtype, 1); + else + result = cinit_tempnodefunc(expr->rtype, 0); + result = makemonadicnode(result, EINDIRECT); + result->rtype = TYPE_POINTER(result->rtype)->target; + return makecommaexpression(makediadicnode(result, expr, EASS), result->data.monadic); + } else { + result = nullnode(); + CInt64_SetLong(&result->data.intval, -1); + result->rtype = CDecl_NewPointerType(expr->rtype); + return result; + } +} + +short assign_check(ENode *expr, Type *type, UInt32 qual, Boolean flag1, Boolean flag2, Boolean flag3) { + Type *type2; + Boolean r30; + Boolean r29; + short result; + + assign_value = 1000; + r30 = 0; + r29 = 0; + temp_reference_init = 0; + + type2 = type; + if (IS_TYPE_REFERENCE(type) && !IS_TYPE_FUNC(TYPE_POINTER(type)->target)) { + type2 = TYPE_POINTER(type)->target; + r30 = 1; + } + + assign_node = expr; + if (IS_TYPE_ARRAY(type2)) { + r29 = 1; + type2 = CDecl_NewPointerType(TYPE_POINTER(type2)->target); + } + + if (!type2->size) { + CDecl_CompleteType(type2); + if (!type2->size && !r30) { + if (flag1) { + if (IS_TYPE_CLASS(type2)) + CError_Error(CErrorStr136, type2, 0); + else + CError_Error(CErrorStr244, expr->rtype, expr->flags & ENODE_FLAG_QUALS, type2, qual); + } + return CheckResult0; + } + } + + if (copts.warn_implicitconv && flag1 && !flag2) { + if (IS_TYPE_INT_OR_FLOAT(type2) && IS_TYPE_INT_OR_FLOAT(expr->rtype)) + CExpr_CheckArithmConversion(expr, type2); + } + + result = std_assign_check(expr, type2, flag1, flag3); + if (!result) { + if (IS_TYPE_CLASS(expr->rtype) || IS_TYPE_CLASS(type2)) { + result = user_assign_check(expr, type2, qual, flag1, flag2, flag3); + } else if (flag1) { + CError_Error(CErrorStr244, expr->rtype, expr->flags & ENODE_FLAG_QUALS, type2, qual); + } + } + + if (r30 && result) { + if (flag1) { + if (!ENODE_IS(assign_node, EINDIRECT)) { + if (!r29) { + assign_node = CExpr_LValue(assign_node, 0, 0); + if (!ENODE_IS(assign_node, EINDIRECT)) { + assign_node = get_address_of_temp_copy(assign_node, 1); + temp_reference_init = 1; + } else { + assign_node = getnodeaddress(assign_node, 0); + } + } + } else { + if (!CExpr_IsLValue(assign_node)) + temp_reference_init = 1; + if (!r29) + assign_node = getnodeaddress(assign_node, 0); + } + } else { + if (!r29 && !CExpr_IsLValue(assign_node) && !CParser_IsConst(TYPE_POINTER(type)->target, qual)) { + result = CheckResult0; + } + } + } + + return result; +} + +Boolean CExpr_MatchCompare(Object *obj, Match13 *a, Match13 *b) { + Object *tmp; + ObjectList *list; + + switch (CExpr_StdMatchCompare(&b->anotherm5, &a->anotherm5, 0)) { + case -1: + return 0; + case 0: + if (a->xE > b->xE) + return 0; + if (a->xE != b->xE) + break; + switch (CExpr_StdMatchCompare(&b->match5, &a->match5, 1)) { + case -1: + return 0; + case 0: + if (a->anotherm5.x8 > b->anotherm5.x8) + return 0; + if (a->anotherm5.x8 == b->anotherm5.x8 && (tmp = a->obj)) { + if (tmp->datatype == obj->datatype) { + add_it: + list = lalloc(sizeof(ObjectList)); + list->next = a->list; + a->list = list; + list->object = obj; + return 0; + } + if (obj->datatype == DALIAS) + return 0; + if (tmp->datatype != DALIAS) + goto add_it; + } + } + } + + *a = *b; + a->obj = obj; + return 1; +} + +static void MatchOverloadFunc(Object *obj, FuncArg *args, ENodeList *argexprs, Match13 *match) { + Match13 match2; + + if (IS_TYPE_FUNC(obj->type) && !(TYPE_FUNC(obj->type)->flags & FUNC_IS_TEMPL)) { + memclrw(&match2, sizeof(Match13)); + while (1) { + if (!args || args->type == &stvoid) { + if (!argexprs) + break; + return; + } + + if (args == &elipsis) + break; + if (args == &oldstyle) + break; + + if (!argexprs) { + if (args->dexpr) + break; + return; + } + + if (!CExpr_MatchAssign(args->type, args->qual, argexprs->node, &match2)) + return; + + argexprs = argexprs->next; + args = args->next; + } + + CExpr_MatchCompare(obj, match, &match2); + } +} + +Boolean CExpr_GetFuncMatchArgs(Object *obj, ENodeList *argexprs, ENode *expr, FuncMatchArgs *result) { + ENode *intexpr; + + if (!(TYPE_FUNC(obj->type)->flags & FUNC_METHOD)) { + result->exprs = argexprs; + result->args = TYPE_FUNC(obj->type)->args; + return 1; + } + + if (TYPE_METHOD(obj->type)->is_static) { + result->exprs = argexprs; + result->args = TYPE_FUNC(obj->type)->args; + return 1; + } + + if (TYPE_FUNC(obj->type)->flags & FUNC_IS_CTOR) { + result->exprs = argexprs; + result->args = TYPE_FUNC(obj->type)->args->next; + return 1; + } + + if (expr) { + intexpr = lalloc(sizeof(ENode)); + intexpr->type = EINTCONST; + intexpr->cost = 0; + intexpr->flags = expr->flags; + intexpr->rtype = CDecl_NewPointerType(expr->rtype); + intexpr->data.intval = cint64_zero; + + result->exprs = lalloc(sizeof(ENodeList)); + result->exprs->next = argexprs; + result->exprs->node = intexpr; + + if (obj->datatype == DALIAS) { + result->args = lalloc(sizeof(FuncArg)); + *result->args = *TYPE_FUNC(obj->type)->args; + result->args->type = CDecl_NewPointerType(expr->rtype); + } else { + result->args = TYPE_FUNC(obj->type)->args; + } + + return 1; + } + + return 0; +} + +static NameSpaceObjectList *CExpr_CopyNameSpaceObjectList(NameSpaceObjectList *list) { + NameSpaceObjectList *first; + NameSpaceObjectList *work; + + first = work = lalloc(sizeof(NameSpaceObjectList)); + while (1) { + work->object = list->object; + list = list->next; + if (!list) { + work->next = NULL; + break; + } else { + work->next = lalloc(sizeof(NameSpaceObjectList)); + work = work->next; + } + } + return first; +} + +static void CExpr_MatchArgList(NameSpaceObjectList *list, TemplArg *templargs, ENodeList *argexprs, Match13 *match, ENode *expr, Boolean flag) { + NameSpaceObjectList *copied_list; + NameSpaceObjectList *scan_list; + Object *obj; + ENodeList *scan_expr; + Boolean is_template; + FuncMatchArgs fma; + + if (!copts.old_argmatch) { + CExpr_FuncArgMatch(CExpr_CopyNameSpaceObjectList(list), templargs, argexprs, match, expr, flag); + return; + } + + copied_list = CExpr_CopyNameSpaceObjectList(list); + + for (scan_expr = argexprs; scan_expr; scan_expr = scan_expr->next) + CDecl_CompleteType(scan_expr->node->rtype); + + scan_list = copied_list; + is_template = 0; + for (; scan_list; scan_list = scan_list->next) { + obj = OBJECT(scan_list->object); + if (obj->otype != OT_OBJECT) + continue; + if (IS_TYPE_FUNC(obj->type) && (!flag || !(obj->qual & Q_EXPLICIT))) { + if (!(TYPE_FUNC(obj->type)->flags & FUNC_IS_TEMPL)) { + if (CExpr_GetFuncMatchArgs(obj, argexprs, expr, &fma)) + MatchOverloadFunc(obj, fma.args, fma.exprs, match); + } else { + is_template = 1; + } + } + } + + if (is_template) { + if (!match->obj || match->anotherm5.x2 || match->anotherm5.x4 || match->xE) + CTempl_FuncMatch(copied_list, templargs, argexprs, match, expr); + } +} + +ENode *CExpr_GetDefaultArgument(ENode *funcexpr, FuncArg *arg) { + ENode *tmp; + + if (CTemplTool_IsTemplateArgumentDependentExpression(arg->dexpr)) { + CError_ASSERT(3264, ENODE_IS(funcexpr, EOBJREF)); + tmp = CTemplTool_DeduceDefaultArg( + funcexpr->data.objref, + CInline_CopyExpression(arg->dexpr, CopyMode0) + ); + return argumentpromotion(tmp, arg->type, arg->qual, 1); + } + + return CInline_CopyExpression(arg->dexpr, CopyMode0); +} + +static ENode *CExpr_GenericCall(ENode *funcexpr, ENodeList *argexprs, TypeFunc *tfunc, FuncArg *args) { + ENodeList *list; + ENode *callexpr; + + while (args) { + if (args->dexpr) { + if (argexprs) { + list = argexprs; + while (list->next) + list = list->next; + list->next = lalloc(sizeof(ENodeList)); + list = list->next; + } else { + list = argexprs = lalloc(sizeof(ENodeList)); + } + list->next = NULL; + list->node = CExpr_GetDefaultArgument(funcexpr, args); + } + args = args->next; + } + + callexpr = lalloc(sizeof(ENode)); + callexpr->type = EFUNCCALL; + callexpr->cost = 4; + callexpr->rtype = tfunc->functype; + callexpr->flags = tfunc->qual & ENODE_FLAG_QUALS; + callexpr->data.funccall.funcref = funcexpr; + callexpr->data.funccall.funcref->rtype = CDecl_NewPointerType(TYPE(tfunc)); + callexpr->data.funccall.args = argexprs; + callexpr->data.funccall.functype = tfunc; + funcexpr->data.objref->flags |= OBJECT_USED; + return CExpr_AdjustFunctionCall(callexpr); +} + +static Boolean CExpr_IsObjrefPlusX(ENode *expr) { + Type *type; + + if (ENODE_IS(expr, EOBJREF)) { + type = expr->data.objref->type; + while (IS_TYPE_ARRAY(type)) + type = TYPE_POINTER(type)->target; + return IS_TYPE_CLASS(type); + } + + if (ENODE_IS2(expr, EADD, ESUB)) { + if (CExpr_IsObjrefPlusX(expr->data.diadic.left)) + return 1; + if (CExpr_IsObjrefPlusX(expr->data.diadic.right)) + return 1; + } + + return 0; +} + +static Boolean CExpr_IsStaticType(ENode *expr) { + return ENODE_IS(expr, EINDIRECT) && CExpr_IsObjrefPlusX(expr->data.monadic); +} + +ENode *CExpr_VarArgPromotion(ENode *expr, Boolean flag) { + if (!copts.old_argmatch) + expr = pointer_generation(expr); + + switch (expr->rtype->type) { + case TYPEVOID: + case TYPEFUNC: + CError_Error(CErrorStr353); + expr = nullnode(); + break; + case TYPEINT: + case TYPEENUM: + expr = integralpromote(expr); + break; + case TYPEFLOAT: + if (TYPE_INTEGRAL(expr->rtype)->integral < IT_DOUBLE) + expr = promote(expr, TYPE(&stdouble)); + break; + case TYPECLASS: + expr = classargument(expr); + break; + } + + if (!flag && copts.warn_largeargs) { + if ((IS_TYPE_INT(expr->rtype) && TYPE_INTEGRAL(expr->rtype)->integral >= IT_LONGLONG) || IS_TYPE_FLOAT(expr->rtype)) + CError_Warning(CErrorStr316); + } + + return expr; +} + +ENode *CExpr_GenericFuncCall(BClassList *path, ENode *funcexpr, Boolean flag1, Object *obj, NameSpaceObjectList *nsol, TemplArg *templargs, ENodeList *nodes, Boolean flag2, Boolean flag3, Boolean flag4) { + TypeFunc *tfunc; + AccessType access; + FuncArg *scan_arg; + BClassList *buildpath; + ENode *objexpr; + ENodeList *scan_expr; + BClassList *pathcopy; + Boolean had_alias; + NameSpaceObjectList my_list; + Match13 match; + + memclrw(&match, sizeof(Match13)); + + if (!obj || IS_TEMPL_FUNC(obj->type)) { + if (!funcexpr && cscope_currentfunc && cscope_currentclass && cscope_is_member_func) { + funcexpr = CClass_CreateThisSelfExpr(); + if (funcexpr) { + funcexpr = makemonadicnode(funcexpr, EINDIRECT); + funcexpr->rtype = TYPE(cscope_currentclass); + } + } + + if (obj) { + my_list.next = NULL; + my_list.object = OBJ_BASE(obj); + nsol = &my_list; + } + + CExpr_MatchArgList(nsol, templargs, nodes, &match, funcexpr, flag2); + if (!match.obj) { + CError_ErrorFuncCall(CErrorStr248, nsol, nodes); + return nullnode(); + } + if (match.list) + CError_OverloadedFunctionError(match.obj, match.list); + obj = match.obj; + } + + objexpr = create_objectrefnode(obj); + tfunc = TYPE_FUNC(obj->type); + if (!IS_TYPE_FUNC(tfunc)) { + CError_Error(CErrorStr161); + return nullnode(); + } + + if (IS_TYPEFUNC_METHOD(tfunc) && !TYPE_METHOD(tfunc)->is_static) { + had_alias = 0; + buildpath = NULL; + access = obj->access; + while (obj->datatype == DALIAS) { + buildpath = buildpath ? CClass_AppendPath(buildpath, CClass_GetPathCopy(obj->u.alias.member, 0)) : CClass_GetPathCopy(obj->u.alias.member, 0); + obj = obj->u.alias.object; + objexpr = create_objectrefnode(obj); + had_alias = 1; + } + if (flag3) + CError_Error(CErrorStr188); + + if (TYPE_METHOD(tfunc)->theclass->sominfo && (!(obj->qual & Q_INLINE) || (obj->datatype == DVFUNC && !flag1))) { + pathcopy = CClass_GetPathCopy(path, 0); + funcexpr = CExpr_GetClassAccessNode(path, buildpath, funcexpr, obj, access, flag4); + if (!funcexpr) + return nullnode(); + objexpr = CSOM_MethodAccess(pathcopy, obj, flag1); + } else { + if (obj->datatype == DVFUNC) { + if (flag1 || (!copts.always_vdispatch && !had_alias && funcexpr && CExpr_IsStaticType(funcexpr))) + objexpr->flags |= ENODE_FLAG_80; + } + funcexpr = CExpr_GetClassAccessNode(path, buildpath, funcexpr, obj, access, flag4); + if (!funcexpr) + return nullnode(); + } + + if ( + (tfunc->flags & FUNC_PURE) && + cscope_currentfunc && + (TYPE_FUNC(cscope_currentfunc->type)->flags & (FUNC_IS_CTOR | FUNC_IS_DTOR)) && + cscope_currentclass == TYPE_METHOD(tfunc)->theclass && + ENODE_IS(funcexpr, EINDIRECT) && + ENODE_IS(funcexpr->data.monadic, EINDIRECT) && + ENODE_IS(funcexpr->data.monadic->data.monadic, EOBJREF) && + funcexpr->data.monadic->data.monadic->data.objref->name == this_name_node && + !(objexpr->flags & ENODE_FLAG_80) + ) + CError_Warning(CErrorStr195); + + scan_expr = lalloc(sizeof(ENodeList)); + scan_expr->next = nodes; + scan_expr->node = funcexpr->data.monadic; + if (ENODE_IS(scan_expr->node, EOBJREF)) + scan_expr->node->data.objref->flags |= OBJECT_FLAGS_2; + + if (((funcexpr->flags & Q_CONST) && !(tfunc->args->qual & Q_CONST)) || ((funcexpr->flags & Q_VOLATILE) && !(tfunc->args->qual & Q_VOLATILE))) { + if (!(tfunc->flags & (FUNC_IS_CTOR | FUNC_IS_DTOR))) + CError_Error(CErrorStr236); + } + + nodes = scan_expr; + scan_expr = scan_expr->next; + scan_arg = tfunc->args->next; + } else { + if (flag4 && obj->access != ACCESSPROTECTED) + CClass_CheckObjectAccess(path, obj); + + scan_arg = tfunc->args; + scan_expr = nodes; + if (tfunc->flags & FUNC_METHOD) { + CError_ASSERT(3599, TYPE_METHOD(tfunc)->theclass->sominfo == NULL); + } + } + + while (scan_expr) { + if (scan_arg && scan_arg != &elipsis && scan_arg != &oldstyle) { + scan_expr->node = argumentpromotion(scan_expr->node, scan_arg->type, scan_arg->qual, 1); + scan_arg = scan_arg->next; + } else { + if (!scan_arg) { + my_list.next = NULL; + my_list.object = OBJ_BASE(obj); + CError_ErrorFuncCall(CErrorStr248, &my_list, nodes); + } + scan_expr->node = CExpr_VarArgPromotion(scan_expr->node, scan_arg == &elipsis); + } + scan_expr = scan_expr->next; + } + + if (scan_arg) { + if (scan_arg != &elipsis && scan_arg != &oldstyle) { + if (!scan_arg->dexpr) { + my_list.next = NULL; + my_list.object = OBJ_BASE(obj); + CError_ErrorFuncCall(CErrorStr248, &my_list, nodes); + scan_arg = NULL; + } + } else { + scan_arg = NULL; + } + } + + return CExpr_GenericCall(objexpr, nodes, tfunc, scan_arg); +} + +ENode *CExpr_GenericPtmfCall(Object *obj, TypeFunc *tfunc, ENodeList *arg_exprs) { + ENodeList *scan_expr; + FuncArg *arg; + + scan_expr = arg_exprs; + arg = tfunc->args; + while (scan_expr) { + if (!arg) { + CError_Error(CErrorStr162); + return nullnode(); + } + + if (arg != &elipsis && arg != &oldstyle) { + scan_expr->node = argumentpromotion(scan_expr->node, arg->type, arg->qual, 1); + arg = arg->next; + } else { + scan_expr->node = CExpr_VarArgPromotion(scan_expr->node, arg == &elipsis); + } + scan_expr = scan_expr->next; + } + + if (arg) { + if (arg != &elipsis && arg != &oldstyle) { + if (!arg->dexpr) { + CError_Error(CErrorStr162); + arg = NULL; + } + } else { + arg = NULL; + } + } + + return CExpr_GenericCall(create_objectrefnode(obj), arg_exprs, tfunc, arg); +} + +static ENode *CExpr_ConvertEMember(ENode *expr) { + ENode *result; + + if (expr->data.emember->list->next || expr->data.emember->templargs) { + result = CExpr_NewENode(EOBJLIST); + result->rtype = OBJECT(expr->data.emember->list->object)->type; + result->data.objlist.list = expr->data.emember->list; + result->data.objlist.templargs = expr->data.emember->templargs; + return result; + } + + if (expr->data.emember->list->object->otype != OT_OBJECT) + return NULL; + return CExpr_MakeObjRefNode(OBJECT(expr->data.emember->list->object), 1); +} + +ENode *CExpr_MakeFunctionCall(ENode *funcexpr, ENodeList *arg_exprs) { + ENode *expr; + TypeFunc *tfunc; + BClassList *save_path; + ENode *save_expr; + Boolean save_1D; + Boolean save_isambig; + + FuncArg *scan_arg; + ENodeList *scan_expr; + Boolean has_varargs; + + if (ENODE_IS(funcexpr, EOBJLIST) && funcexpr->data.objlist.name) { + funcexpr->data.objlist.list = CScope_ArgumentDependentNameLookup( + funcexpr->data.objlist.list, + funcexpr->data.objlist.name, + arg_exprs, 0); + if (!funcexpr->data.objlist.list) { + CError_Error(CErrorStr140, CError_GetNameString(NULL, funcexpr->data.objlist.name)); + return nullnode(); + } + + if ( + funcexpr->data.objlist.list->object->otype == OT_OBJECT && + (TYPE_FUNC(OBJECT(funcexpr->data.objlist.list->object)->type)->flags & FUNC_INTRINSIC) && + (expr = CodeGen_HandleIntrinsicCall(OBJECT(funcexpr->data.objlist.list->object), arg_exprs))) + return expr; + + return CExpr_GenericFuncCall( + NULL, NULL, 0, NULL, + funcexpr->data.objlist.list, + funcexpr->data.objlist.templargs, + arg_exprs, 0, 0, 1); + } + + if (ENODE_IS(funcexpr, EMEMBER)) { + save_path = funcexpr->data.emember->path; + save_expr = funcexpr->data.emember->expr; + save_1D = funcexpr->data.emember->pr_1D; + save_isambig = funcexpr->data.emember->isambig; + funcexpr = CExpr_ConvertEMember(funcexpr); + if (!funcexpr) { + CError_Error(CErrorStr161); + return nullnode(); + } + } else { + save_path = NULL; + save_expr = NULL; + save_1D = 0; + save_isambig = 0; + } + + if (ENODE_IS(funcexpr, EOBJREF) && IS_TYPE_FUNC(funcexpr->data.objref->type) && (TYPE_FUNC(funcexpr->data.objref->type)->flags & FUNC_INTRINSIC)) { + if (!(expr = CodeGen_HandleIntrinsicCall(funcexpr->data.objref, arg_exprs))) { + expr = CExpr_GenericFuncCall( + save_path, save_expr, save_1D, funcexpr->data.objref, + NULL, NULL, + arg_exprs, 0, save_isambig, 1); + } + return expr; + } + + if (ENODE_IS(funcexpr, EOBJLIST)) { + return CExpr_GenericFuncCall( + save_path, save_expr, save_1D, NULL, + funcexpr->data.objlist.list, funcexpr->data.objlist.templargs, + arg_exprs, 0, save_isambig, 1); + } + + if (!IS_TYPE_POINTER_ONLY(funcexpr->rtype) || !IS_TYPE_FUNC((tfunc = TYPE_FUNC(TYPE_POINTER(funcexpr->rtype)->target)))) { + CError_Error(CErrorStr161); + return nullnode(); + } + + if (ENODE_IS(funcexpr, EOBJREF)) { + return CExpr_GenericFuncCall( + save_path, save_expr, save_1D, funcexpr->data.objref, + NULL, NULL, arg_exprs, 0, save_isambig, 1); + } + + scan_expr = arg_exprs; // r25 + scan_arg = tfunc->args; // r26 + has_varargs = 0; + while (scan_expr) { + if (!has_varargs) { + if (!scan_arg) { + CError_Error(CErrorStr162); + return nullnode(); + } + if (scan_arg == &elipsis || scan_arg == &oldstyle) { + scan_expr->node = CExpr_VarArgPromotion(scan_expr->node, scan_arg == &elipsis); + has_varargs = 1; + } else { + scan_expr->node = argumentpromotion(scan_expr->node, scan_arg->type, scan_arg->qual, 1); + scan_arg = scan_arg->next; + } + } else { + scan_expr->node = CExpr_VarArgPromotion(scan_expr->node, 0); + } + scan_expr = scan_expr->next; + } + + if (!has_varargs && scan_arg && scan_arg != &elipsis && scan_arg != &oldstyle) { + do { + if (!scan_arg->dexpr) { + CError_Error(CErrorStr162); + return nullnode(); + } + + if (arg_exprs) { + scan_expr = arg_exprs; + while (scan_expr->next) + scan_expr = scan_expr->next; + scan_expr->next = lalloc(sizeof(ENodeList)); + scan_expr = scan_expr->next; + } else { + scan_expr = lalloc(sizeof(ENodeList)); + arg_exprs = scan_expr; + } + + scan_expr->next = NULL; + scan_expr->node = CExpr_GetDefaultArgument(funcexpr, scan_arg); + } while ((scan_arg = scan_arg->next) && scan_arg != &elipsis && scan_arg != &oldstyle); + } + + expr = CExpr_NewENode(EFUNCCALL); + expr->cost = 4; + expr->rtype = tfunc->functype; + expr->flags = tfunc->qual & ENODE_FLAG_QUALS; + expr->data.funccall.funcref = funcexpr; + expr->data.funccall.args = arg_exprs; + expr->data.funccall.functype = tfunc; + return CExpr_AdjustFunctionCall(expr); +} + +static Boolean accept_conversion_type(Type *type, short mode) { + switch (mode) { + case 0: + return IS_TYPE_INT(type); + case 1: + return IS_TYPE_INT_OR_FLOAT(type); + case 2: + return IS_TYPE_INT_OR_FLOAT(type) || IS_TYPE_POINTER_ONLY(type); + case 3: + return IS_TYPE_POINTER_ONLY(type); + default: + CError_FATAL(3912); + return 0; + } +} + +static ENode *CExpr_OperatorConversion(ENode *expr, Type *type, UInt32 qual) { + if (IS_TYPE_CLASS(expr->rtype) && type) { + if (user_assign_check(expr, type, qual, 1, 0, 1)) + return assign_node; + CError_Error(CErrorStr144); + } + return expr; +} + +static Boolean wild_conversion_check(ENode *left, ENode *right, Conversion *conv) { + ConversionIterator iter; + Object *obj; + + Type *check; + Type *left_type; + Type *right_type; + + left_type = right_type = NULL; + if (IS_TYPE_CLASS(left->rtype)) { + CExpr_ConversionIteratorInit(&iter, TYPE_CLASS(left->rtype)); + while ((obj = CExpr_ConversionIteratorNext(&iter))) { + check = TYPE_FUNC(obj->type)->functype; + if (accept_conversion_type(check, 2)) { + while ((obj = CExpr_ConversionIteratorNext(&iter))) { + if (accept_conversion_type(TYPE_FUNC(obj->type)->functype, 2)) + CError_Error(CErrorStr199); + } + left_type = check; + goto found_left; + } + } + return 0; + } +found_left: + if (IS_TYPE_CLASS(right->rtype)) { + CExpr_ConversionIteratorInit(&iter, TYPE_CLASS(right->rtype)); + while ((obj = CExpr_ConversionIteratorNext(&iter))) { + check = TYPE_FUNC(obj->type)->functype; + if (accept_conversion_type(check, 2)) { + while ((obj = CExpr_ConversionIteratorNext(&iter))) { + if (accept_conversion_type(TYPE_FUNC(obj->type)->functype, 2)) + CError_Error(CErrorStr199); + } + right_type = check; + goto found_right; + } + } + return 0; + } +found_right: + conv->x0 = NULL; + conv->left = CExpr_OperatorConversion(left, left_type, 0); + conv->right = CExpr_OperatorConversion(right, right_type, 0); + return 1; +} + +static Boolean monadic_conversion_check(ENode *expr, short which, Conversion *conv) { + ConversionIterator iter; + Object *obj; + Type *check; + + if (!IS_TYPE_CLASS(expr->rtype)) + return 0; + + if (which == 4) + which = 2; + else if (which == 5) + which = 1; + + CExpr_ConversionIteratorInit(&iter, TYPE_CLASS(expr->rtype)); + while ((obj = CExpr_ConversionIteratorNext(&iter))) { + check = TYPE_FUNC(obj->type)->functype; + if (accept_conversion_type(check, which)) { + while ((obj = CExpr_ConversionIteratorNext(&iter))) { + if (accept_conversion_type(TYPE_FUNC(obj->type)->functype, which)) + CError_Error(CErrorStr199); + } + + conv->x0 = NULL; + conv->left = CExpr_OperatorConversion(expr, check, 0); + conv->right = NULL; + return 1; + } + } + + return 0; +} + +static Boolean is_legal_type_combination(Type *left, Type *right, short mode) { + int left_type; + int right_type; + + if (IS_TYPE_ENUM(left)) + left = TYPE_ENUM(left)->enumtype; + if (IS_TYPE_ENUM(right)) + right = TYPE_ENUM(right)->enumtype; + + if (IS_TYPE_REFERENCE(left)) + left = TYPE_POINTER(left)->target; + if (IS_TYPE_REFERENCE(right)) + right = TYPE_POINTER(right)->target; + + left_type = left->type; // r7 + right_type = right->type; // r8 + switch (mode) { + case 3: + if (left_type != TYPEPOINTER || right_type != TYPEPOINTER) + return 0; + use_cpp_typeequal: + diadic_arg1.type = left; + diadic_arg2.type = right; + return iscpp_typeequal(left, right); + case 7: + if ((left_type == TYPEPOINTER && right_type == TYPEINT) || (left_type == TYPEINT && right_type == TYPEPOINTER)) { + diadic_arg1.type = left; + diadic_arg2.type = right; + return 1; + } + return 0; + case 6: + if ((left_type == TYPEPOINTER && right_type == TYPEINT) || (left_type == TYPEINT && right_type == TYPEPOINTER)) { + diadic_arg1.type = left; + diadic_arg2.type = right; + return 1; + } + case 2: + if (left_type == TYPEPOINTER || right_type == TYPEPOINTER) + goto use_cpp_typeequal; + case 1: + mode1: + if (left_type == TYPEFLOAT || right_type == TYPEFLOAT) { + if (left_type == TYPEFLOAT) { + if (right_type == TYPEFLOAT) { + if (TYPE_INTEGRAL(right)->integral > TYPE_INTEGRAL(left)->integral) + left = right; + diadic_arg2.type = left; + diadic_arg1.type = left; + return 1; + } + if (right_type != TYPEINT) + return 0; + diadic_arg2.type = left; + diadic_arg1.type = left; + return 1; + } + if (left_type != TYPEINT) + return 0; + diadic_arg2.type = right; + diadic_arg1.type = right; + return 1; + } + case 0: + if (left_type != TYPEINT || right_type != TYPEINT) + return 0; + if (TYPE_INTEGRAL(right)->integral > TYPE_INTEGRAL(left)->integral) + left = right; + if (TYPE_INTEGRAL(left)->integral < IT_INT) + left = TYPE(&stsignedint); + diadic_arg2.type = left; + diadic_arg1.type = left; + return 1; + case 4: + if (left_type == TYPEPOINTER) { + if (right_type != TYPEINT) + return 0; + diadic_arg1.type = left; + diadic_arg2.type = right; + return 1; + } + if (right_type == TYPEPOINTER) { + if (left_type != TYPEINT) + return 0; + diadic_arg1.type = left; + diadic_arg2.type = right; + return 1; + } + goto mode1; + case 5: + if (left_type != TYPEPOINTER) + goto mode1; + if (right_type == TYPEPOINTER) + goto use_cpp_typeequal; + if (right_type != TYPEINT) + return 0; + diadic_arg1.type = left; + diadic_arg2.type = right; + return 1; + default: + CError_FATAL(4132); + return 0; + } +} + +static void match_class_type_conversion(Match13 *match, ENode *left, ENode *right, ENodeList *list, short which) { + ConversionIterator iter; + Object *obj; + + if (which == 6) { + if (!ENODE_IS(right, EINTCONST) || !CInt64_IsZero(&right->data.intval) || !IS_TYPE_INT(right->rtype)) + which = 2; + } + + CExpr_ConversionIteratorInit(&iter, TYPE_CLASS(left->rtype)); + while ((obj = CExpr_ConversionIteratorNext(&iter))) { + if (is_legal_type_combination(TYPE_FUNC(obj->type)->functype, right->rtype, which)) { + MatchOverloadFunc(obj, &diadic_arg1, list, match); + if (match->obj == obj) { + cexpr_left_conversion_type = diadic_arg1.type; + cexpr_right_conversion_type = diadic_arg2.type; + } + } + } +} + +static void match_type_class_conversion(Match13 *match, ENode *left, ENode *right, ENodeList *list, short which) { + ConversionIterator iter; + Object *obj; + + if (which == 6) { + if (!ENODE_IS(left, EINTCONST) || !CInt64_IsZero(&left->data.intval) || !IS_TYPE_INT(left->rtype)) + which = 2; + } + + CExpr_ConversionIteratorInit(&iter, TYPE_CLASS(right->rtype)); + while ((obj = CExpr_ConversionIteratorNext(&iter))) { + if (is_legal_type_combination(left->rtype, TYPE_FUNC(obj->type)->functype, which)) { + MatchOverloadFunc(obj, &diadic_arg1, list, match); + if (match->obj == obj) { + cexpr_left_conversion_type = diadic_arg1.type; + cexpr_right_conversion_type = diadic_arg2.type; + } + } + } +} + +static void match_class_class_conversion(Match13 *match, ENode *left, ENode *right, ENodeList *list, short which) { + ConversionIterator iter_left; + ConversionIterator iter_right; + Object *obj_left; + Object *obj_right; + + if (which == 6) + which = 2; + + CExpr_ConversionIteratorInit(&iter_left, TYPE_CLASS(left->rtype)); + while ((obj_left = CExpr_ConversionIteratorNext(&iter_left))) { + CExpr_ConversionIteratorInit(&iter_right, TYPE_CLASS(right->rtype)); + while ((obj_right = CExpr_ConversionIteratorNext(&iter_right))) { + if (is_legal_type_combination(TYPE_FUNC(obj_left->type)->functype, TYPE_FUNC(obj_right->type)->functype, which)) { + MatchOverloadFunc(obj_left, &diadic_arg1, list, match); + if (match->obj == obj_left) { + cexpr_left_conversion_type = diadic_arg1.type; + cexpr_right_conversion_type = diadic_arg2.type; + } + } + } + } +} + +Boolean CExpr_CheckOperatorConversion(short token, ENode *left, ENode *right, ENodeList *list, Conversion *conv) { + Match13 match; + short which; + + switch (token) { + case '*': + if (!right) { + which = 3; + break; + } + case '/': + which = 1; + break; + case '&': + if (!right) + return 0; + case '%': + case '^': + case '|': + case '~': + case TK_SHL: + case TK_SHR: + which = 0; + break; + case '[': + which = 7; + break; + case '+': + which = 4; + break; + case '-': + which = 5; + break; + case '!': + case ':': + case '<': + case '>': + case TK_LESS_EQUAL: + case TK_GREATER_EQUAL: + which = 2; + break; + case TK_LOGICAL_EQ: + case TK_LOGICAL_NE: + which = 6; + break; + case TK_LOGICAL_OR: + case TK_LOGICAL_AND: + return wild_conversion_check(left, right, conv); + default: + return 0; + } + + if (!right) + return monadic_conversion_check(left, which, conv); + + cexpr_left_conversion_type = cexpr_right_conversion_type = NULL; + memclrw(&match, sizeof(Match13)); + + if (IS_TYPE_CLASS(left->rtype)) { + if (IS_TYPE_CLASS(right->rtype)) + match_class_class_conversion(&match, left, right, list, which); + else + match_class_type_conversion(&match, left, right, list, which); + } else { + if (IS_TYPE_CLASS(right->rtype)) + match_type_class_conversion(&match, left, right, list, which); + else + return 0; + } + + if (!match.obj) + return 0; + if (match.list) + CError_OverloadedFunctionError(match.obj, match.list); + + conv->x0 = NULL; + conv->left = CExpr_OperatorConversion(left, cexpr_left_conversion_type, 0); + conv->right = CExpr_OperatorConversion(right, cexpr_right_conversion_type, 0); + return 1; +} + +Boolean CExpr_CheckOperator(short token, ENode *left, ENode *right, Conversion *conv) { + Match13 match; + NameResult pr; + NameResult pr2; + ENode *expr; + Object *obj; + ENodeList *nodes; + HashNameNode *name; + BClassList *path; + EMemberInfo *member; + Object *prev_obj; + NameSpaceObjectList mylist_A8; + NameSpaceObjectList mylist_B0; + + if (!copts.old_argmatch) { + if (token == '(') { + CDecl_CompleteType(left->rtype); + if (IS_TYPE_CLASS(left->rtype) && CScope_FindClassMemberObject(TYPE_CLASS(left->rtype), &pr, + CMangler_OperatorName(token))) { + if (pr.nsol_14 || (pr.obj_10 && pr.obj_10->otype == OT_OBJECT && IS_TYPE_FUNC(OBJECT(pr.obj_10)->type))) { + member = lalloc(sizeof(EMemberInfo)); + memclrw(member, sizeof(EMemberInfo)); + member->path = pr.bcl_18; + member->expr = left; + member->pr_1D = pr.x1D; + if (!pr.nsol_14) { + member->list = galloc(sizeof(NameSpaceObjectList)); + member->list->next = NULL; + member->list->object = pr.obj_10; + } else { + member->list = pr.nsol_14; + } + expr = CExpr_NewENode(EMEMBER); + expr->rtype = &stvoid; + expr->data.emember = member; + tk = lex(); + conv->x0 = checkreference(CExpr_MakeFunctionCall(expr, CExpr_ScanExpressionList(1))); + conv->left = NULL; + conv->right = NULL; + tk = lex(); + return 1; + } else { + CError_FATAL(4371); + } + } + return 0; + } else { + return CExpr_OperatorMatch(token, left, right, conv); + } + } + + if (!IS_TYPE_CLASS(left->rtype)) { + if (!IS_TYPE_ENUM(left->rtype)) { + if (!right) + return 0; + if (!IS_TYPE_CLASS(right->rtype) && !IS_TYPE_ENUM(right->rtype)) + return 0; + } + } else { + CDecl_CompleteType(left->rtype); + } + + memclrw(&match, sizeof(Match13)); + name = CMangler_OperatorName(token); + if (token == '(') { + if (IS_TYPE_CLASS(left->rtype) && CScope_FindClassMemberObject(TYPE_CLASS(left->rtype), &pr2, name)) { + if (pr2.nsol_14 || (pr2.obj_10 && pr2.obj_10->otype == OT_OBJECT && IS_TYPE_FUNC(OBJECT(pr2.obj_10)->type))) { + member = lalloc(sizeof(EMemberInfo)); + memclrw(member, sizeof(EMemberInfo)); + member->path = pr2.bcl_18; + member->expr = left; + member->pr_1D = pr2.x1D; + if (!pr2.nsol_14) { + member->list = galloc(sizeof(NameSpaceObjectList)); + member->list->next = NULL; + member->list->object = pr2.obj_10; + } else { + member->list = pr2.nsol_14; + } + expr = CExpr_NewENode(EMEMBER); + expr->rtype = &stvoid; + expr->data.emember = member; + tk = lex(); + conv->x0 = checkreference(CExpr_MakeFunctionCall(expr, CExpr_ScanExpressionList(1))); + conv->left = NULL; + conv->right = NULL; + tk = lex(); + return 1; + } else { + CError_FATAL(4439); + } + } + return 0; + } + + nodes = lalloc(sizeof(ENodeList)); + nodes->node = left; + if (right) { + nodes->next = lalloc(sizeof(ENodeList)); + nodes->next->node = right; + nodes->next->next = NULL; + } else { + nodes->next = NULL; + } + + obj = NULL; + if (IS_TYPE_CLASS(left->rtype) && CScope_FindClassMemberObject(TYPE_CLASS(left->rtype), &pr2, name)) { + if (pr2.obj_10) { + mylist_B0.next = NULL; + mylist_B0.object = pr2.obj_10; + pr2.nsol_14 = &mylist_B0; + } else { + CError_ASSERT(4470, pr2.nsol_14); + } + + if (token != '=' || (pr2.bcl_18->type == left->rtype && pr2.bcl_18->next == NULL)) { + prev_obj = match.obj; + CExpr_MatchArgList(pr2.nsol_14, NULL, nodes->next, &match, left, 0); + if (prev_obj != match.obj) { + obj = match.obj; + path = pr2.bcl_18; + } + } + } + + if (CScope_FindNonClassObject(cscope_current, &pr2, name)) { + if (pr2.obj_10) { + mylist_A8.next = NULL; + mylist_A8.object = pr2.obj_10; + pr2.nsol_14 = &mylist_A8; + } + } else { + pr2.nsol_14 = NULL; + } + + if (copts.arg_dep_lookup) + pr2.nsol_14 = CScope_ArgumentDependentNameLookup(pr2.nsol_14, name, nodes, 1); + if (pr2.nsol_14) + CExpr_MatchArgList(pr2.nsol_14, NULL, nodes, &match, NULL, 0); + + if (!match.obj) { + if (!IS_TYPE_CLASS(left->rtype) && (!right || !IS_TYPE_CLASS(right->rtype))) + return 0; + return CExpr_CheckOperatorConversion(token, left, right, nodes, conv); + } + + if (!(token == '&' && !right) && (token != ',')) { + if (!IS_TYPE_CLASS(left->rtype) && (!right || !IS_TYPE_CLASS(right->rtype)) && match.xE) + return 0; + if (right && match.xE == 2 && CExpr_CheckOperatorConversion(token, left, right, nodes, conv)) + return 1; + } + + if (match.list) + CError_OverloadedFunctionError(match.obj, match.list); + + if (match.obj == obj) { + conv->x0 = CExpr_GenericFuncCall(path, nodes->node, 0, match.obj, NULL, NULL, nodes->next, 0, 0, 1); + } else { + conv->x0 = CExpr_GenericFuncCall(NULL, NULL, 0, match.obj, NULL, NULL, nodes, 0, 0, 1); + } + + conv->x0 = checkreference(conv->x0); + conv->left = NULL; + conv->right = NULL; + return 1; +} + +ENode *CExpr_ConstructObject(TypeClass *tclass, ENode *addr_expr, ENodeList *args, Boolean flag1, Boolean flag2, Boolean flag3, Boolean flag4, Boolean flag5) { + ENode *expr; + NameSpaceObjectList *ctorlist; + BClassList path; + + CError_ASSERT(4595, IS_TYPE_POINTER_ONLY(addr_expr->rtype)); + + addr_expr = makemonadicnode(addr_expr, EINDIRECT); + addr_expr->rtype = TYPE(tclass); + + if (!flag3 && args && !args->next && args->node->rtype == TYPE(tclass) && !CClass_CopyConstructor(tclass)) { + CError_ASSERT(4605, IS_TYPE_CLASS(addr_expr->rtype)); + expr = makediadicnode(addr_expr, args->node, EASS); + if (!flag1) + expr = getnodeaddress(expr, 0); + return expr; + } + + if ((ctorlist = CClass_Constructor(tclass))) { + if (tclass->flags & CLASS_HAS_VBASES) { + ENodeList *list = lalloc(sizeof(ENodeList)); + list->next = args; + args = list; + list->node = intconstnode(TYPE(&stsignedshort), flag2 != 0); + } + path.next = NULL; + path.type = TYPE(tclass); + expr = CExpr_GenericFuncCall(&path, addr_expr, 0, NULL, ctorlist, NULL, args, !flag5, 0, flag4); + if (ENODE_IS2(expr, EFUNCCALL, EFUNCCALLP)) + expr->rtype = CDecl_NewPointerType(TYPE(tclass)); + if (flag1) { + expr = makemonadicnode(expr, EINDIRECT); + expr->rtype = TYPE(tclass); + } + return expr; + } else { + if (args) { + if (!args->next && ENODE_IS(addr_expr, EINDIRECT)) { + return makediadicnode( + addr_expr, + CExpr_AssignmentPromotion(args->node, TYPE(tclass), 0, 1), + EASS); + } + CError_Error(CErrorStr174); + } + return addr_expr; + } +} + +static ENode *CExpr_DeleteFuncCall(Object *obj, ENode *arg, Type *type, Boolean include_size) { + ENode *expr; + ENodeList *list; + + expr = lalloc(sizeof(ENode)); + expr->type = EFUNCCALL; + expr->cost = 4; + expr->flags = 0; + expr->rtype = &stvoid; + expr->data.funccall.funcref = create_objectrefnode(obj); + expr->data.funccall.functype = TYPE_FUNC(obj->type); + obj->flags |= OBJECT_USED; + + list = lalloc(sizeof(ENodeList)); + list->node = arg; + expr->data.funccall.args = list; + + if (include_size) { + list->next = lalloc(sizeof(ENodeList)); + list->next->node = nullnode(); + CInt64_SetLong(&list->next->node->data.intval, type->size); + list->next->node->rtype = CABI_GetSizeTType(); + list->next->next = NULL; + } else { + list->next = NULL; + } + + return expr; +} + +static ENode *CExpr_CopyPlacementNewArg(ENodeList *list) { + switch (list->node->type) { + case EINDIRECT: + if (!ENODE_IS(list->node->data.monadic, EOBJREF)) + break; + if (list->node->data.monadic->data.objref->datatype != DLOCAL && !is_const_object(list->node->data.monadic->data.objref)) + break; + case EINTCONST: + case EFLOATCONST: + case ESTRINGCONST: + case EOBJREF: + case EARGOBJ: + case ELOCOBJ: + case EOBJLIST: + case EVECTOR128CONST: + return CInline_CopyExpression(list->node, CopyMode0); + } + + switch (list->node->rtype->type) { + default: + CError_FATAL(4726); + case TYPEINT: + case TYPEFLOAT: + case TYPEENUM: + case TYPESTRUCT: + case TYPECLASS: + case TYPEMEMBERPOINTER: + case TYPEPOINTER: + case TYPEOBJCID: + return CExpr_GetETEMPCopy(list->node); + } +} + +static ENode *CExpr_PlacementDeleteCall(Type *type, ENode *expr, Object *obj, Boolean flag1, Boolean flag2) { + ENodeList *list; + Object *funcobj; + ENode *result; + ENodeList *inputarg; + Boolean outflag; + + CError_ASSERT(4752, ENODE_IS(expr, EFUNCCALL) && ENODE_IS(expr->data.funccall.funcref, EOBJREF)); + + funcobj = expr->data.funccall.funcref->data.objref; + CError_ASSERT(4756, IS_TYPE_FUNC(funcobj->type) && TYPE_FUNC(funcobj->type)->args && TYPE_FUNC(funcobj->type)->args->next); + + funcobj = CParser_FindDeallocationObject(type, TYPE_FUNC(funcobj->type)->args->next, flag1, flag2, &outflag); + if (!funcobj) + return NULL; + + result = CExpr_NewENode(EFUNCCALL); + result->type = EFUNCCALL; + result->cost = 4; + result->rtype = &stvoid; + result->data.funccall.funcref = create_objectrefnode(funcobj); + result->data.funccall.functype = TYPE_FUNC(funcobj->type); + funcobj->flags |= OBJECT_USED; + + list = lalloc(sizeof(ENodeList)); + list->node = create_objectnode(obj); + result->data.funccall.args = list; + + CError_ASSERT(4780, (inputarg = expr->data.funccall.args) && (inputarg = inputarg->next)); + + do { + list->next = lalloc(sizeof(ENodeList)); + list = list->next; + list->node = CExpr_CopyPlacementNewArg(inputarg); + inputarg = inputarg->next; + } while (inputarg); + list->next = NULL; + + return result; +} + +static Type *scan_type_name(UInt32 *qual) { + DeclInfo di; + memclrw(&di, sizeof(DeclInfo)); + + CParser_GetDeclSpecs(&di, 0); + di.x46 = 1; + scandeclarator(&di); + + if (di.name) + CError_Error(CErrorStr146); + + firstarrayexpr = di.x24; + *qual = di.qual; + return di.thetype; +} + +static UInt32 cv_qualifier_list(void) { + UInt32 qual; + + qual = 0; + tk = lex(); + while (tk >= TK_CONST && tk <= TK_ASM) { + switch (tk) { + case TK_CONST: + if (qual & Q_CONST) + CError_Error(CErrorStr121); + qual |= Q_CONST; + break; + case TK_VOLATILE: + if (qual & Q_VOLATILE) + CError_Error(CErrorStr121); + qual |= Q_VOLATILE; + break; + default: + CError_Error(CErrorStr121); + } + + tk = lex(); + } + + return qual; +} + +static void scan_new_declarator(DeclInfo *di, Boolean flag) { + NameResult pr; + SInt32 size; + ENode *expr; + + switch (tk) { + case '*': + makethetypepointer(di, cv_qualifier_list()); + if (tk != '[') + scan_new_declarator(di, flag); + break; + case TK_IDENTIFIER: + case TK_COLON_COLON: + if (CScope_ParseQualifiedNameSpace(&pr, 1, 0) && pr.nspace_0 && pr.nspace_0->theclass && tk == '*') { + makememberpointertype(di, pr.nspace_0->theclass, cv_qualifier_list()); + if (tk != '[') + scan_new_declarator(di, flag); + } else { + CError_Error(CErrorStr121); + } + break; + } + + if (tk == '[') { + tk = lex(); + expr = expression(); + + if (IS_TYPE_ENUM(expr->rtype)) + expr->rtype = TYPE_ENUM(expr->rtype)->enumtype; + if (!IS_TYPE_INT(expr->rtype)) + CError_Error(CErrorStr146); + + if (tk != ']') + CError_Error(CErrorStr125); + else + tk = lex(); + + if (tk == '[') + scan_new_declarator(di, 0); + + if (CanCreateObject(di->thetype) && IsCompleteType(di->thetype)) { + di->thetype = CDecl_NewArrayType(di->thetype, 0); + if (!ENODE_IS(expr, EINTCONST)) { + size = 1; + if (!flag) + CError_Error(CErrorStr124); + else + firstarrayexpr = expr; + } else { + size = CInt64_GetULong(&expr->data.intval); + } + TYPE_POINTER(di->thetype)->size = size * TYPE_POINTER(di->thetype)->target->size; + } else { + CError_Error(CErrorStr129); + } + } +} + +static Type *scan_new_type_name(UInt32 *qual) { + DeclInfo di; + memclrw(&di, sizeof(DeclInfo)); + + di.x4F = 1; + CParser_GetDeclSpecs(&di, 0); + scan_new_declarator(&di, 1); + + *qual = di.qual; + return di.thetype; +} + +static ENode *CExpr_NewAlloc(Type *type, ENodeList *args, Boolean flag1, Boolean flag2) { + NameSpaceObjectList *list; + Object *obj; + Boolean found; + HashNameNode *name; + NameResult pr; + + found = 0; + if (!flag1 && IS_TYPE_CLASS(type)) { + list = NULL; + obj = NULL; + name = (flag2 && copts.array_new_delete) ? newa_fobj->name : newp_fobj->name; + if (CScope_FindClassMemberObject(TYPE_CLASS(type), &pr, name)) { + list = pr.nsol_14; + obj = OBJECT(pr.obj_10); + CError_ASSERT(4935, list || obj); + found = 1; + } else if (TYPE_CLASS(type)->flags & CLASS_HANDLEOBJECT) { + CError_ASSERT(4942, !flag2); + obj = newh_func; + found = 1; + } + } + + if (!found) { + if (flag2 && copts.array_new_delete) + list = &newa_fobj->first; + else + list = &newp_fobj->first; + obj = NULL; + } + + return CExpr_GenericFuncCall(NULL, NULL, 0, obj, list, NULL, args, 0, 0, 1); +} + +static ENode *CExpr_NewExceptionSafeAlloc(Type *type, ENode *node, ENodeList *args, Boolean flag1, Boolean flag2, Object **objptr) { + Object *obj; + ENode *result; + ENode *catchexpr; + Object *deletefunc; + Boolean include_size; + + if (!cscope_currentfunc || !copts.delete_exception || !copts.exceptions) + return NULL; + + obj = create_temp_object(TYPE(&void_ptr)); + *objptr = obj; + deletefunc = NULL; + catchexpr = NULL; + include_size = 0; + if (args) + catchexpr = CExpr_PlacementDeleteCall(type, node, obj, flag1, flag2); + if (!args) + deletefunc = CParser_FindDeallocationObject(type, NULL, flag1, flag2, &include_size); + + if (!deletefunc && !catchexpr) + return NULL; + + result = lalloc(sizeof(ENode)); + *result = *node; + node = makediadicnode(create_objectnode(obj), node, EASS); + if (!catchexpr && !include_size) { + result->type = ENEWEXCEPTION; + result->data.newexception.initexpr = node; + result->data.newexception.tryexpr = NULL; + result->data.newexception.pointertemp = obj; + result->data.newexception.deletefunc = deletefunc; + } else { + if (!catchexpr) + catchexpr = CExpr_DeleteFuncCall(deletefunc, create_objectnode(obj), type, include_size); + result->type = EINITTRYCATCH; + result->data.itc.initexpr = node; + result->data.itc.tryexpr = NULL; + result->data.itc.result = create_objectnode(obj); + result->data.itc.catchexpr = catchexpr; + } + + return result; +} + +static ENode *CExpr_NewExceptionSafeInit(ENode *expr, ENode *tryexpr) { + switch (expr->type) { + case ENEWEXCEPTION: + expr->data.newexception.tryexpr = tryexpr; + break; + case EINITTRYCATCH: + expr->data.itc.tryexpr = tryexpr; + break; + default: + CError_FATAL(5056); + } + return expr; +} + +static ENode *CExpr_NewArray(Type *type, UInt32 qual, ENodeList *nodelist, Boolean flag) { + Type *tptr; + Type *sizetype; + Type *innertype; + ENodeList *newlist; + ENode *result; + Object *ctor; + Object *dtor; + ENode *ass; + ENode *etemp; + ENode *mul; + SInt32 count; + ENode *newalloc; + ENode *newESalloc; + Object *tempobj; + ENode *callexpr; + + tptr = CDecl_NewPointerType(TYPE_POINTER(type)->target); + sizetype = CABI_GetSizeTType(); + innertype = TYPE_POINTER(type)->target; + while (IS_TYPE_ARRAY(innertype)) + innertype = TYPE_POINTER(innertype)->target; + + if (!CanAllocObject(innertype) || !IsCompleteType(innertype)) + return nullnode(); + + newlist = lalloc(sizeof(ENodeList)); + newlist->next = nodelist; + if (tk == '(') { + tk = lex(); + if (CExpr_ScanExpressionList(1)) + CError_Error(CErrorStr174); + if (tk == ')') + tk = lex(); + else + CError_Error(CErrorStr115); + } + + if (!IS_TYPE_CLASS(innertype) || CClass_IsPODClass(TYPE_CLASS(innertype))) { + newlist->node = intconstnode(sizetype, type->size); + if (firstarrayexpr) { + newlist->node = makediadicnode(newlist->node, promote(firstarrayexpr, sizetype), EMUL); + optimizecomm(newlist->node); + } + result = CExpr_NewAlloc(innertype, newlist, flag, 1); + result->rtype = tptr; + result->flags |= (qual & ENODE_FLAG_QUALS); + return result; + } + + ctor = NULL; + if (CClass_Constructor(TYPE_CLASS(innertype))) { + ctor = CClass_DefaultConstructor(TYPE_CLASS(innertype)); + if (ctor) { + ctor->flags |= OBJECT_USED; + } else { + ctor = CClass_DummyDefaultConstructor(TYPE_CLASS(innertype)); + if (!ctor) + CError_Error(CErrorStr203); + } + } + + dtor = CClass_Destructor(TYPE_CLASS(innertype)); + if (dtor) + dtor = CABI_GetDestructorObject(dtor, CABIDestroy1); + + ass = NULL; + if (firstarrayexpr) { + etemp = CExpr_NewETEMPNode(sizetype, 1); + mul = promote(firstarrayexpr, sizetype); + if (innertype->size) + count = type->size / innertype->size; + else + count = 0; + if (count > 1) { + mul = makediadicnode(mul, intconstnode(sizetype, count), EMUL); + optimizecomm(mul); + } + ass = makediadicnode(CExpr_DerefETEMPCopy(etemp), mul, EASS); + mul = makediadicnode(CExpr_DerefETEMPCopy(etemp), intconstnode(sizetype, innertype->size), EMUL); + optimizecomm(mul); + mul = makediadicnode(mul, intconstnode(sizetype, 16), EADD); + optimizecomm(mul); + newlist->node = mul; + etemp = CExpr_DerefETEMPCopy(etemp); + } else { + newlist->node = intconstnode(sizetype, type->size + 16); + if (innertype->size) + count = type->size / innertype->size; + else + count = 0; + etemp = intconstnode(sizetype, count); + } + + newalloc = CExpr_NewAlloc(innertype, newlist, flag, 1); + newalloc->rtype = tptr; + newESalloc = CExpr_NewExceptionSafeAlloc(innertype, newalloc, nodelist, 1, flag, &tempobj); + if (newESalloc) { + callexpr = CExpr_FuncCallSix( + cnar_func, + create_objectnode(tempobj), + ctor ? create_objectrefnode(ctor) : nullnode(), + dtor ? create_objectrefnode(dtor) : nullnode(), + intconstnode(sizetype, innertype->size), + etemp, + NULL + ); + result = CExpr_NewExceptionSafeInit(newESalloc, makediadicnode(create_objectnode(tempobj), callexpr, EASS)); + } else { + result = CExpr_FuncCallSix( + cnar_func, + newalloc, + ctor ? create_objectrefnode(ctor) : nullnode(), + dtor ? create_objectrefnode(dtor) : nullnode(), + intconstnode(sizetype, innertype->size), + etemp, + NULL + ); + } + + if (ass) + result = makecommaexpression(ass, result); + result->rtype = tptr; + result->flags |= (qual & ENODE_FLAG_QUALS); + return result; +} + +static ENode *CExpr_NewSimpleClass(TypeClass *tclass, ENode *expr, ENodeList *args) { + ENode *precomp; + ENode *nullcheck; + + precomp = lalloc(sizeof(ENode)); + *precomp = *expr; + precomp->type = EPRECOMP; + precomp->data.precompid = CParser_GetUniqueID(); + + nullcheck = lalloc(sizeof(ENode)); + *nullcheck = *expr; + nullcheck->type = ENULLCHECK; + nullcheck->cost = 4; + nullcheck->data.nullcheck.nullcheckexpr = expr; + nullcheck->data.nullcheck.condexpr = CExpr_ConstructObject(tclass, precomp, args, 0, 1, 1, 1, 1); + nullcheck->data.nullcheck.precompid = precomp->data.precompid; + return nullcheck; +} + +static ENode *CExpr_NewClass(TypeClass *tclass, ENode *expr, ENodeList *args1, ENodeList *args2, Boolean flag) { + Object *objptr; + ENode *newESalloc; + + if (!args2 && !flag && CABI_ConstructorCallsNew(tclass)) { + expr = nullnode(); + expr->rtype = CDecl_NewPointerType(TYPE(tclass)); + return CExpr_ConstructObject(tclass, expr, args1, 0, 1, 1, 1, 1); + } else { + newESalloc = CExpr_NewExceptionSafeAlloc(TYPE(tclass), expr, args2, 0, flag, &objptr); + if (newESalloc) { + return CExpr_NewExceptionSafeInit( + newESalloc, + CExpr_ConstructObject(tclass, create_objectnode(objptr), args1, 0, 1, 1, 1, 1)); + } else { + return CExpr_NewSimpleClass(tclass, expr, args1); + } + } +} + +ENode *scannew(Boolean flag) { + Type *type; // r27 + UInt32 qual; + ENodeList *args; // r28 + Boolean placement_flag; // r26 + ENodeList *newargs; // r26 + ENode *expr; // r26 + ENodeList *args2; // r29 + Object *tempobj; + ENode *newESalloc; // r28 + ENode *tempobj_expr; // r25 + ENode *etemp_expr; // r28 + ENode *indirect_expr; // r25 + ENode *ass; // r25 + ENode *cond; // r27 + + type = NULL; + args = NULL; + firstarrayexpr = NULL; + if ((tk = lex()) == '(') { + tk = lex(); + placement_flag = isdeclaration(1, 1, 1, ')'); + if (!placement_flag) + args = CExpr_ScanExpressionList(1); + if (placement_flag) + type = scan_type_name(&qual); + if (tk != ')') + CError_Error(CErrorStr115); + else + tk = lex(); + } + + if (!type) { + if (tk == '(') { + tk = lex(); + type = scan_type_name(&qual); + if (tk != ')') + CError_Error(CErrorStr115); + else + tk = lex(); + } else { + type = scan_new_type_name(&qual); + } + } + + if (IS_TYPE_ARRAY(type)) + return CExpr_NewArray(type, qual, args, flag); + + if (IS_TYPE_CLASS(type)) { + if (TYPE_CLASS(type)->sominfo) + return CSOM_New(TYPE_CLASS(type)); + if (TYPE_CLASS(type)->objcinfo) + return CObjC_New(TYPE_CLASS(type)); + } + + if (!IsCompleteType(type) || !CanAllocObject(type)) + return nullnode(); + + newargs = lalloc(sizeof(ENodeList)); + newargs->next = args; + newargs->node = intconstnode(CABI_GetSizeTType(), type->size); + + expr = CExpr_NewAlloc(type, newargs, flag, 0); + expr->rtype = CDecl_NewPointerType(type); + expr->flags |= (qual & ENODE_FLAG_QUALS); + + if (tk == '(') { + tk = lex(); + args2 = CExpr_ScanExpressionList(1); + if (!args2 && !IS_TYPE_CLASS(type)) { + args2 = lalloc(sizeof(ENodeList)); + memclrw(args2, sizeof(ENodeList)); + args2->node = do_typecast(nullnode(), type, 0); + } + if (tk == ')') + tk = lex(); + else + CError_Error(CErrorStr115); + } else { + args2 = NULL; + } + + if (ENODE_IS(expr, EINTCONST)) + return expr; + + if (IS_TYPE_CLASS(type) && CClass_Constructor(TYPE_CLASS(type))) + return CExpr_NewClass(TYPE_CLASS(type), expr, args2, args, flag); + + if (args2) { + if (args2->next) { + CError_Error(CErrorStr174); + return nullnode(); + } + + newESalloc = CExpr_NewExceptionSafeAlloc(type, expr, args, 0, flag, &tempobj); + if (newESalloc) { + tempobj_expr = makemonadicnode(create_objectnode(tempobj), EINDIRECT); + tempobj_expr->rtype = type; + tempobj_expr->flags = args2->node->flags & ENODE_FLAG_QUALS; + return CExpr_NewExceptionSafeInit( + newESalloc, + makediadicnode(tempobj_expr, CExpr_AssignmentPromotion(args2->node, type, newESalloc->flags, 1), EASS) + ); + } else { + etemp_expr = CExpr_GetETEMPCopy(expr); + indirect_expr = makemonadicnode(etemp_expr, EINDIRECT); + indirect_expr->rtype = type; + indirect_expr->flags = args2->node->flags & ENODE_FLAG_QUALS; + ass = makediadicnode(indirect_expr, CExpr_AssignmentPromotion(args2->node, type, indirect_expr->flags, 1), EASS); + cond = CExpr_NewENode(ECOND); + cond->cost = 4; + cond->rtype = &stvoid; + cond->data.cond.cond = expr; + cond->data.cond.expr1 = ass; + cond->data.cond.expr2 = nullnode(); + cond = makecommaexpression(cond, etemp_expr); + cond->rtype = etemp_expr->rtype; + cond->flags = etemp_expr->flags; + return cond; + } + } else { + return expr; + } +} + +static ENode *CExpr_DeleteArray(ENode *expr, Type *type, Boolean flag) { + Object *obj; + Object *dtor; + Boolean outflag; + ENode *precomp; + SInt32 precompid; + ENode *tmp; + ENode *result; + + obj = CParser_FindDeallocationObject(type, NULL, 1, flag, &outflag); + + if (!IS_TYPE_CLASS(type) || CClass_IsPODClass(TYPE_CLASS(type))) + return CExpr_DeleteFuncCall(obj, expr, type, outflag); + + dtor = CClass_Destructor(TYPE_CLASS(type)); + if (dtor || outflag) { + if (obj->nspace == cscope_root && !outflag) { + return funccallexpr(dnar_func, expr, dtor ? create_objectrefnode(dtor) : nullnode(), NULL, NULL); + } + return funccallexpr( + dnar3_func, + expr, + dtor ? create_objectrefnode(dtor) : nullnode(), + create_objectrefnode(obj), + intconstnode(TYPE(&stsignedshort), outflag)); + } + + precomp = lalloc(sizeof(ENode)); + *precomp = *expr; + precomp->type = EPRECOMP; + precomp->data.precompid = precompid = CParser_GetUniqueID(); + tmp = CExpr_DeleteFuncCall(obj, makediadicnode(precomp, intconstnode(CABI_GetSizeTType(), 16), ESUB), type, 0); + + result = CExpr_NewENode(ENULLCHECK); + result->rtype = &stvoid; + result->cost = 4; + result->data.nullcheck.nullcheckexpr = expr; + result->data.nullcheck.condexpr = tmp; + result->data.nullcheck.precompid = precompid; + + return result; +} + +ENode *scandelete(Boolean flag) { + Boolean is_array; // r24 + ENode *expr; // r25 + Type *conv_type; // r22 + UInt32 conv_qual; // r23 + Type *innertype; // r23 + Type *t; + Object *obj; + Object *dtor; // r24 + ENode *result_expr; // r24??? + ENode *precomp_orig; // r31 + SInt32 precompid; // r30 + Boolean is_virtual; // r23 + ENode *nc; + ConversionIterator iter; + Boolean outflag; + BClassList path; + + if ((tk = lex()) == '[') { + if ((tk = lex()) != ']') + CError_Error(CErrorStr125); + else + tk = lex(); + is_array = 1; + } else { + is_array = 0; + } + + expr = cast_expression(); + if (!IS_TYPE_POINTER_ONLY(expr->rtype)) { + if (IS_TYPE_CLASS(expr->rtype)) { + conv_type = NULL; + CExpr_ConversionIteratorInit(&iter, TYPE_CLASS(expr->rtype)); + while ((obj = CExpr_ConversionIteratorNext(&iter))) { + if (IS_TYPE_POINTER_ONLY(TYPE_FUNC(obj->type)->functype)) { + if (conv_type) { + CError_Error(CErrorStr199); + break; + } + conv_type = TYPE_FUNC(obj->type)->functype; + conv_qual = TYPE_FUNC(obj->type)->qual; + } + } + if (conv_type) { + if (!copts.old_argmatch) { + expr = CExpr_Convert(expr, conv_type, conv_qual, 1, 1); + } else { + if (user_assign_check(expr, conv_type, conv_qual, 1, 0, 1)) + expr = assign_node; + } + } + } + if (!IS_TYPE_POINTER_ONLY(expr->rtype)) { + CError_Error(CErrorStr146); + return nullnode(); + } + } + + innertype = TYPE_POINTER(expr->rtype)->target; + if (innertype->size == 0) + CDecl_CompleteType(innertype); + + if (IS_TYPE_ARRAY(innertype) && !is_array) + CError_Error(CErrorStr146); + + if (is_array) { + t = innertype; + while (IS_TYPE_ARRAY(t)) + t = TYPE_POINTER(t)->target; + return CExpr_DeleteArray(expr, t, flag); + } + + if (copts.objective_c && CObjC_IsType_id(expr->rtype)) + return CObjC_Delete(NULL, expr); + + if (!IS_TYPE_CLASS(innertype)) { + obj = CParser_FindDeallocationObject(innertype, NULL, 0, flag, &outflag); + CClass_CheckObjectAccess(NULL, obj); + return CExpr_DeleteFuncCall(obj, expr, innertype, outflag); + } + + if (TYPE_CLASS(innertype)->sominfo) + return CSOM_Delete(TYPE_CLASS(innertype), expr); + + if (TYPE_CLASS(innertype)->objcinfo) + return CObjC_Delete(TYPE_CLASS(innertype), expr); + + if (!(TYPE_CLASS(innertype)->flags & CLASS_COMPLETED) && copts.pedantic) + CError_Warning(CErrorStr136, innertype, 0); + + obj = CParser_FindDeallocationObject(innertype, NULL, 0, flag, &outflag); + CClass_CheckObjectAccess(NULL, obj); + dtor = CClass_Destructor(TYPE_CLASS(innertype)); + if (!dtor) + return CExpr_DeleteFuncCall(obj, expr, innertype, outflag); + + path.next = NULL; + path.type = innertype; + CClass_CheckObjectAccess(&path, dtor); + + result_expr = lalloc(sizeof(ENode)); + result_expr->type = EFUNCCALL; + result_expr->cost = 4; + result_expr->flags = 0; + result_expr->rtype = &stvoid; + if (dtor->datatype == DVFUNC) { + precomp_orig = expr; + expr = lalloc(sizeof(ENode)); + *expr = *precomp_orig; + expr->type = EPRECOMP; + expr->data.precompid = precompid = CParser_GetUniqueID(); + is_virtual = 1; + } else { + is_virtual = 0; + } + + if (!flag) { + result_expr = CABI_DestroyObject(dtor, expr, 2, 0, 1); + } else { + CError_ASSERT(5650, !outflag); + result_expr = CABI_DestroyObject(dtor, expr, 2, 0, 0); + result_expr->rtype = TYPE(&void_ptr); + result_expr = funccallexpr(obj, result_expr, NULL, NULL, NULL); + obj->flags |= OBJECT_USED; + } + + if (is_virtual) { + nc = lalloc(sizeof(ENode)); + nc->type = ENULLCHECK; + nc->rtype = &stvoid; + nc->cost = 4; + nc->flags = 0; + nc->data.nullcheck.nullcheckexpr = precomp_orig; + nc->data.nullcheck.condexpr = result_expr; + nc->data.nullcheck.precompid = precompid; + return nc; + } else { + return result_expr; + } +} |