#include "compiler/CExpr.h" #include "compiler/CABI.h" #include "compiler/CClass.h" #include "compiler/CDecl.h" #include "compiler/CError.h" #include "compiler/CException.h" #include "compiler/CInit.h" #include "compiler/CInline.h" #include "compiler/CIRTransform.h" #include "compiler/CMachine.h" #include "compiler/CMangler.h" #include "compiler/CInt64.h" #include "compiler/CObjC.h" #include "compiler/CObjCModern.h" #include "compiler/CParser.h" #include "compiler/CPrep.h" #include "compiler/CPrepTokenizer.h" #include "compiler/CRTTI.h" #include "compiler/CSOM.h" #include "compiler/CTemplateNew.h" #include "compiler/CTemplateTools.h" #include "compiler/CodeGen.h" #include "compiler/CompilerTools.h" #include "compiler/PPCError.h" #include "compiler/objects.h" #include "compiler/scopes.h" #include "compiler/templates.h" Boolean (*name_obj_check)(HashNameNode *, Object *); Boolean disallowgreaterthan; // forward declarations static ENode *makeaddnode(ENode *left, ENode *right); static ENode *makesubnode(ENode *left, ENode *right); ENode *CExpr_RewriteConst(ENode *expr) { Object *obj; restart: if (ENODE_IS(expr, EINDIRECT) && ENODE_IS(expr->data.monadic, EOBJREF)) { obj = expr->data.monadic->data.objref; if (obj->datatype == DALIAS) { CExpr_AliasTransform(expr->data.monadic); goto restart; } if ((obj->qual & Q_INLINE_DATA) && expr->rtype == obj->type) { switch (expr->rtype->type) { case TYPEINT: case TYPEENUM: expr->type = EINTCONST; expr->data.intval = obj->u.data.u.intconst; break; case TYPEPOINTER: expr->type = EINTCONST; expr->data.intval = obj->u.data.u.intconst; expr->rtype = TYPE(&stunsignedlong); expr = makemonadicnode(expr, ETYPCON); expr->rtype = obj->type; break; case TYPEFLOAT: expr->type = EFLOATCONST; if (obj->u.data.u.floatconst) expr->data.floatval = *obj->u.data.u.floatconst; else expr->data.floatval = CMach_CalcFloatConvertFromInt(TYPE(&stsignedlong), cint64_zero); break; default: CError_FATAL(105); } } } return expr; } void optimizecomm(ENode *expr) { ENode *right; ENode *left; if (ENODE_IS((right = expr->data.diadic.right), EINTCONST)) return; if (ENODE_IS((left = expr->data.diadic.left), EINTCONST)) { swap: expr->data.diadic.right = left; expr->data.diadic.left = right; return; } if (ENODE_IS(left, EFLOATCONST)) return; if (ENODE_IS(right, EFLOATCONST)) goto swap; if (expr->rtype->type > TYPEFLOAT) return; if (left->cost > right->cost) goto swap; } static void checkadditive(ENode *expr) { switch (expr->rtype->type) { case TYPEINT: if (expr->rtype == TYPE(&stbool)) break; case TYPEFLOAT: return; case TYPEENUM: if (copts.cplusplus) break; return; case TYPEPOINTER: if (TPTR_TARGET(expr->rtype)->size == 0) CDecl_CompleteType(TPTR_TARGET(expr->rtype)); if (TPTR_TARGET(expr->rtype)->size == 0) break; return; case TYPEARRAY: if (ENODE_IS(expr, EOBJREF)) return; } CError_Error(CErrorStr376, expr->rtype, ENODE_QUALS(expr)); } static void CExpr_CompareConvert(ENode **leftp, char *opname, ENode **rightp, Boolean flag) { ENode *left; ENode *right; CInt64 val; left = *leftp; right = *rightp; switch (left->rtype->type) { case TYPEINT: break; case TYPEFLOAT: if (left->rtype != right->rtype) CExpr_ArithmeticConversion(leftp, rightp); return; case TYPEENUM: left->rtype = TYPE_ENUM(left->rtype)->enumtype; break; default: CError_Error(CErrorStr377, left->rtype, ENODE_QUALS(left), opname, right->rtype, ENODE_QUALS(right)); left = nullnode(); } switch (right->rtype->type) { case TYPEINT: break; case TYPEFLOAT: CExpr_ArithmeticConversion(leftp, rightp); return; case TYPEENUM: right->rtype = TYPE_ENUM(right->rtype)->enumtype; break; default: CError_Error(CErrorStr377, left->rtype, ENODE_QUALS(left), opname, right->rtype, ENODE_QUALS(right)); right = nullnode(); } if (left->rtype == right->rtype) { *leftp = left; *rightp = right; return; } if (left->rtype->size == right->rtype->size) { if (is_unsigned(left->rtype) == is_unsigned(right->rtype)) { left->rtype = right->rtype; *leftp = left; *rightp = right; return; } } else { if (ENODE_IS(right, EINTCONST) && left->rtype->size <= right->rtype->size && (is_unsigned(left->rtype) == is_unsigned(right->rtype) || is_unsigned(left->rtype))) { val = CMach_CalcIntDiadic(left->rtype, right->data.intval, '+', cint64_zero); val = CMach_CalcIntDiadic(right->rtype, val, '+', cint64_zero); if (CInt64_Equal(val, right->data.intval)) { right->rtype = left->rtype; *leftp = left; *rightp = right; return; } } if (ENODE_IS(left, EINTCONST) && left->rtype->size >= right->rtype->size && (is_unsigned(left->rtype) == is_unsigned(right->rtype) || is_unsigned(right->rtype))) { val = CMach_CalcIntDiadic(right->rtype, left->data.intval, '+', cint64_zero); val = CMach_CalcIntDiadic(left->rtype, val, '+', cint64_zero); if (CInt64_Equal(val, left->data.intval)) { left->rtype = right->rtype; *leftp = left; *rightp = right; return; } } } *leftp = left; *rightp = right; CExpr_ArithmeticConversion(leftp, rightp); } static ENode *CExpr_ConstResult(ENode *expr, SInt32 value) { ENode *constnode; if (IS_TYPE_FLOAT(expr->rtype)) { constnode = intconstnode(TYPE(&stsignedint), value); constnode->type = EFLOATCONST; constnode->data.floatval = CMach_CalcFloatConvertFromInt(TYPE(&stsignedint), constnode->data.intval); constnode->rtype = expr->rtype; } else { constnode = intconstnode(expr->rtype, value); } if (CInline_ExpressionHasSideEffect(expr)) return makediadicnode(expr, constnode, ECOMMA); else return constnode; } static ENode *makemultnode(ENode *left, ENode *right) { CExpr_ArithmeticConversion(&left, &right); if (iszero(left)) return CExpr_ConstResult(right, 0); if (iszero(right)) return CExpr_ConstResult(left, 0); if (CExpr_IsOne(right)) return left; if (CExpr_IsOne(left)) return right; if (ENODE_IS(left, EINTCONST) && ENODE_IS(right, EINTCONST)) { left->data.intval = CMach_CalcIntDiadic(left->rtype, left->data.intval, '*', right->data.intval); return left; } if (ENODE_IS(left, EFLOATCONST) && ENODE_IS(right, EFLOATCONST)) { left->data.floatval = CMach_CalcFloatDiadic(left->rtype, left->data.floatval, '*', right->data.floatval); return left; } left = makediadicnode(left, right, EMUL); optimizecomm(left); if (IS_TYPE_INT(left->rtype) && left->rtype->size > 2) { left->cost++; if (left->cost > 200) left->cost = 200; } if (IS_TYPE_FLOAT(left->rtype)) left = CExpr_BinaryFloatExpression(left); return left; } static ENode *makedivnode(ENode *left, ENode *right, Boolean no_warning) { CExpr_ArithmeticConversion(&left, &right); if (iszero(right) && IS_TYPE_INT(right->rtype)) { if (!no_warning) CError_Warning(CErrorStr139); return right; } if (CExpr_IsOne(right)) return left; if (iszero(left) && IS_TYPE_INT(left->rtype)) return CExpr_ConstResult(right, 0); if (ENODE_IS(left, EINTCONST) && ENODE_IS(right, EINTCONST)) { left->data.intval = CMach_CalcIntDiadic(left->rtype, left->data.intval, '/', right->data.intval); return left; } if (ENODE_IS(left, EFLOATCONST) && ENODE_IS(right, EFLOATCONST)) { left->data.floatval = CMach_CalcFloatDiadic(left->rtype, left->data.floatval, '/', right->data.floatval); return left; } left = makediadicnode(left, right, EDIV); if (IS_TYPE_FLOAT(left->rtype)) left = CExpr_BinaryFloatExpression(left); return left; } static short canadd2(ENode *expr, CInt64 value) { Float tmp; if (CInt64_IsZero(&value)) return 1; switch (expr->type) { case EINTCONST: expr->data.intval = CMach_CalcIntDiadic(expr->rtype, expr->data.intval, '+', value); return 1; case EFLOATCONST: tmp = CMach_CalcFloatConvertFromInt(TYPE(&stsignedlong), value); expr->data.floatval = CMach_CalcFloatDiadic(expr->rtype, expr->data.floatval, '+', tmp); return 1; case EADD: if (canadd2(expr->data.diadic.left, value)) return 1; if (canadd2(expr->data.diadic.right, value)) return 1; return 0; case ESUB: if (canadd2(expr->data.diadic.left, value)) return 1; if (canadd2(expr->data.diadic.right, CInt64_Neg(value))) return 1; return 0; case ETYPCON: if (IS_TYPE_POINTER_ONLY(expr->rtype) && ENODE_IS(expr->data.monadic, EINTCONST)) { expr->data.monadic->data.intval = CMach_CalcIntDiadic(TYPE(&stunsignedlong), expr->data.monadic->data.intval, '+', value); return 1; } return 0; default: return 0; } } short canadd(ENode *expr, SInt32 value) { CInt64 value64; CInt64_SetLong(&value64, value); return canadd2(expr, value64); } static ENode *addconst(ENode *expr, SInt32 value) { ENode *right; if (canadd(expr, value)) return expr; if (stsignedint.size < 4 && (value > 0x7FFF || value < -0x8000)) right = intconstnode(TYPE(&stsignedlong), value); else right = intconstnode(TYPE(&stsignedint), value); CExpr_ArithmeticConversion(&expr, &right); expr = makediadicnode(expr, right, EADD); return expr; } static ENode *integralpointerpromote(ENode *expr) { Boolean uns; Type *type; if (!IS_TYPE_INT(expr->rtype)) expr = forceintegral(expr); if (expr->rtype->size != 4) { type = TYPE(&stunsignedlong); if (is_unsigned(type) != (uns = is_unsigned(expr->rtype))) { if (uns) { if (stunsignedlong.size == 4) { type = TYPE(&stunsignedlong); } else if (stunsignedint.size == 4) { type = TYPE(&stunsignedint); } else { CError_FATAL(480); } } else { if (stsignedlong.size == 4) { type = TYPE(&stsignedlong); } else if (stsignedint.size == 4) { type = TYPE(&stsignedint); } else { CError_FATAL(486); } } } if (ENODE_IS(expr, EINTCONST)) expr->data.intval = CExpr_IntConstConvert(type, expr->rtype, expr->data.intval); else expr = makemonadicnode(expr, ETYPCON); expr->rtype = type; } return expr; } static ENode *padd(ENode *left, ENode *right) { Type *innertype; SInt32 innersize; ENode *expr; right = integralpointerpromote(right); innertype = TPTR_TARGET(left->rtype); innersize = innertype->size; if (innersize == 0) { CDecl_CompleteType(innertype); innersize = innertype->size; if (innersize == 0) { CError_Error(CErrorStr146); return left; } } expr = makemultnode( right, intconstnode((innersize > 0x7FFF) ? TYPE(&stsignedlong) : TYPE(&stsignedint), innersize)); if (ENODE_IS(expr, EINTCONST) && canadd2(left, expr->data.intval)) return left; if (ENODE_IS(left, EADD) && ENODE_IS(left->data.diadic.right, EINTCONST)) { left->data.diadic.left = makediadicnode(left->data.diadic.left, expr, EADD); return left; } expr = makediadicnode(left, expr, EADD); expr->rtype = left->rtype; expr->flags = left->flags; return expr; } static ENode *psub(ENode *left, ENode *right) { Type *innertype; SInt32 innersize; ENode *expr; if (IS_TYPE_POINTER(right->rtype)) { innersize = TPTR_TARGET(left->rtype)->size; if (innersize == 0) { CDecl_CompleteType(TPTR_TARGET(left->rtype)); innersize = TPTR_TARGET(left->rtype)->size; if (innersize == 0) { CError_Error(CErrorStr146); return left; } } if (!is_typeequal(left->rtype, right->rtype)) { CError_Error(CErrorStr245, left->rtype, ENODE_QUALS(left), right->rtype, ENODE_QUALS(right)); return left; } if (ENODE_IS(left, ETYPCON) && ENODE_IS(left->data.monadic, EINTCONST) && ENODE_IS(right, ETYPCON) && ENODE_IS(right->data.monadic, EINTCONST)) { left->data.monadic->rtype = right->data.monadic->rtype = CABI_GetPtrDiffTType(); expr = makesubnode(left->data.monadic, right->data.monadic); if (innersize > 1) expr = makedivnode(expr, intconstnode(CABI_GetPtrDiffTType(), innersize), 11); return expr; } expr = makediadicnode(left, right, ESUB); expr->rtype = CABI_GetPtrDiffTType(); if (innersize > 1) expr = makediadicnode(expr, intconstnode(CABI_GetPtrDiffTType(), innersize), EDIV); return expr; } right = integralpointerpromote(right); innertype = TPTR_TARGET(left->rtype); innersize = innertype->size; if (innersize == 0) { CDecl_CompleteType(innertype); innersize = innertype->size; if (innersize == 0) { CError_Error(CErrorStr146); return left; } } expr = makemultnode(right, intconstnode(CABI_GetPtrDiffTType(), innersize)); if (ENODE_IS(expr, EINTCONST) && canadd2(left, CInt64_Neg(expr->data.intval))) return left; expr = makediadicnode(left, expr, ESUB); expr->rtype = left->rtype; expr->flags = left->flags; return expr; } static ENode *makeaddnode(ENode *left, ENode *right) { if (IS_TYPE_POINTER(left->rtype)) return padd(left, right); if (IS_TYPE_POINTER(right->rtype)) return padd(right, left); CExpr_ArithmeticConversion(&left, &right); if (iszero(right)) return left; if (iszero(left)) return right; if (ENODE_IS(left, EINTCONST) && ENODE_IS(right, EINTCONST)) { left->data.intval = CMach_CalcIntDiadic(left->rtype, left->data.intval, '+', right->data.intval); return left; } if (ENODE_IS(left, EFLOATCONST) && ENODE_IS(right, EFLOATCONST)) { left->data.floatval = CMach_CalcFloatDiadic(left->rtype, left->data.floatval, '+', right->data.floatval); return left; } if (ENODE_IS(left, EINTCONST) && canadd2(right, left->data.intval)) return right; if (ENODE_IS(right, EINTCONST) && canadd2(left, right->data.intval)) return left; left = makediadicnode(left, right, EADD); optimizecomm(left); if (IS_TYPE_FLOAT(left->rtype)) left = CExpr_BinaryFloatExpression(left); return left; } static ENode *makesubnode(ENode *left, ENode *right) { if (ENODE_IS(right, EINTCONST) && !is_unsigned(right->rtype) && !IS_TYPE_FLOAT(left->rtype)) { right->data.intval = CInt64_Neg(right->data.intval); return makeaddnode(left, right); } if (IS_TYPE_POINTER(left->rtype)) return psub(left, right); CExpr_ArithmeticConversion(&left, &right); if (iszero(right)) return left; if (iszero(left)) { if (ENODE_IS(right, EINTCONST)) { right->data.intval = CInt64_Neg(right->data.intval); return right; } if (ENODE_IS(right, EFLOATCONST)) { right->data.floatval = CMach_CalcFloatMonadic(right->rtype, '-', right->data.floatval); return right; } return CExpr_UnaryFloatExpression(makemonadicnode(right, EMONMIN)); } if (ENODE_IS(left, EINTCONST) && ENODE_IS(right, EINTCONST)) { left->data.intval = CMach_CalcIntDiadic(left->rtype, left->data.intval, '-', right->data.intval); return left; } if (ENODE_IS(left, EFLOATCONST) && ENODE_IS(right, EFLOATCONST)) { left->data.floatval = CMach_CalcFloatDiadic(left->rtype, left->data.floatval, '-', right->data.floatval); return left; } if (ENODE_IS(right, EINTCONST) && canadd2(left, CInt64_Neg(right->data.intval))) return left; left = makediadicnode(left, right, ESUB); if (IS_TYPE_FLOAT(left->rtype)) left = CExpr_BinaryFloatExpression(left); return left; } ENode *checkreference(ENode *expr) { if (!IS_TYPE_REFERENCE(expr->rtype)) return expr; expr = makemonadicnode(expr, EINDIRECT); expr->rtype = TPTR_TARGET(expr->rtype); return expr; } static ENode *pointer_generation2(ENode *expr) { switch (expr->type) { case EINDIRECT: switch (expr->rtype->type) { case TYPEARRAY: switch (expr->data.monadic->type) { case EPOSTINC: case EPOSTDEC: case EPREINC: case EPREDEC: expr->type = ETYPCON; expr->rtype = CDecl_NewPointerType(TPTR_TARGET(expr->rtype)); return expr; default: expr->data.monadic->rtype = CDecl_NewPointerType(TPTR_TARGET(expr->rtype)); expr->data.monadic->flags = expr->flags; return expr->data.monadic; } case TYPEFUNC: expr = expr->data.monadic; if (ENODE_IS(expr, EOBJREF) && expr->data.objref->datatype == DINLINEFUNC) CError_Error(CErrorStr175); return expr; } } return expr; } ENode *pointer_generation(ENode *expr) { return CExpr_RewriteConst(pointer_generation2(expr)); } ENode *CExpr_PointerGeneration(ENode *expr) { switch (expr->type) { case EINDIRECT: switch (expr->rtype->type) { case TYPEARRAY: expr->data.monadic->rtype = CDecl_NewPointerType(TPTR_TARGET(expr->rtype)); return expr->data.monadic; case TYPEFUNC: return expr->data.monadic; } } return expr; } static void CExpr_ConstPointerCheck(ENode *expr, Type *type, short qual) { Type *exprtype; Type *b; Type *a; short exprqual; exprtype = expr->rtype; if (IS_TYPE_POINTER_ONLY(type) && IS_TYPE_POINTER_ONLY(exprtype)) { exprqual = expr->flags; if (TPTR_TARGET(type) == &stvoid) { exprqual = CParser_GetCVTypeQualifiers(TPTR_TARGET(exprtype), exprqual); } else { a = TPTR_TARGET(type); b = TPTR_TARGET(exprtype); while (IS_TYPE_POINTER_ONLY(a) && IS_TYPE_POINTER_ONLY(b)) { if (CParser_IsMoreCVQualified(TPTR_QUAL(b), TPTR_QUAL(a))) { CError_Warning(CErrorStr220, expr->rtype, ENODE_QUALS(expr), type, qual); return; } a = TPTR_TARGET(a); b = TPTR_TARGET(b); } } if (CParser_IsMoreCVQualified(exprqual, qual)) { CError_Warning(CErrorStr220, expr->rtype, ENODE_QUALS(expr), type, (UInt32) qual); } } } ENode *oldassignmentpromotion(ENode *expr, Type *type, short qual, Boolean flag) { Boolean is_ref; UInt32 ref_qual; short orig_qual; is_ref = 0; if (!IS_TYPE_MEMBERPOINTER(type)) { if (IS_TYPE_REFERENCE(type)) { if (ENODE_IS(expr, ECOND)) expr = CExpr_LValue(expr, 0, 0); expr = pointer_generation2(expr); ref_qual = CParser_GetCVTypeQualifiers(expr->rtype, expr->flags); is_ref = 1; } else { expr = pointer_generation(expr); } } if (ENODE_IS(expr, EMEMBER)) expr = getpointertomemberfunc(expr, type, 1); if (!is_ref) CExpr_ConstPointerCheck(expr, type, qual); else CExpr_ConstPointerCheck(expr, TPTR_TARGET(type), qual); if (!(assign_check(expr, type, orig_qual = qual, 1, 0, flag))) return expr; if (is_ref) { if (temp_reference_init) { switch (TPTR_TARGET(type)->type) { case TYPEPOINTER: qual = TPTR_QUAL(TPTR_TARGET(type)); } if (!(qual & Q_CONST)) CError_Warning(CErrorStr228); } else { if (ref_qual && ref_qual > CParser_GetCVTypeQualifiers(TPTR_TARGET(type), orig_qual)) CError_Warning(CErrorStr259); } } return assign_node; } ENode *argumentpromotion(ENode *expr, Type *type, short qual, Boolean flag) { ENode *tmp; ENodeList *list; if (IS_TYPE_CLASS(type) && CClass_ReferenceArgument(TYPE_CLASS(type))) { if ((tmp = CExpr_IsTempConstruction(expr, type, NULL))) return tmp; list = lalloc(sizeof(ENodeList)); list->next = NULL; list->node = expr; tmp = CExpr_ConstructObject( TYPE_CLASS(type), create_temp_node(type), list, 1, 1, 1, 1, 0); return getnodeaddress(tmp, 0); } return CExpr_AssignmentPromotion(expr, type, qual, flag); } ENode *classargument(ENode *expr) { ENodeList *list; if (CClass_CopyConstructor(TYPE_CLASS(expr->rtype))) { list = lalloc(sizeof(ENodeList)); list->next = NULL; list->node = expr; return CExpr_ConstructObject( TYPE_CLASS(expr->rtype), create_temp_node(expr->rtype), list, 1, 1, 1, 1, 0); } return expr; } ENodeList *CExpr_ScanExpressionList(Boolean is_parens) { ENodeList *list; ENodeList *current; if (is_parens && tk == ')') return NULL; list = current = lalloc(sizeof(ENodeList)); while (1) { current->next = NULL; current->node = assignment_expression(); if (copts.old_argmatch && !ENODE_IS(current->node, EMEMBER)) current->node = pointer_generation(current->node); if (is_parens) { if (tk == ')') break; } else { if (tk == ']') break; } if (tk != ',') { CError_ErrorSkip(CErrorStr116); break; } tk = lex(); current->next = lalloc(sizeof(ENodeList)); current = current->next; } return list; } static ENode *skipcommaexpr(ENode *expr) { while (ENODE_IS(expr, ECOMMA)) expr = expr->data.diadic.right; return expr; } ENode *CExpr_DoExplicitConversion(Type *type, UInt32 qual, ENodeList *list) { Object *obj; ENode *tmp; if (!IS_TYPE_CLASS(type)) { if (!list) return do_typecast(nullnode(), type, qual); if (list->next) CError_Error(CErrorStr356); return do_typecast(pointer_generation(list->node), type, qual); } CDecl_CompleteType(type); if (!(TYPE_CLASS(type)->flags & CLASS_COMPLETED)) CError_Error(CErrorStr136, type, 0); CanCreateObject(type); if (!list && CClass_IsPODClass(TYPE_CLASS(type))) { obj = CParser_NewGlobalDataObject(NULL); obj->name = CParser_GetUniqueName(); obj->nspace = cscope_root; obj->type = type; obj->qual = qual; obj->sclass = TK_STATIC; CInit_DeclareData(obj, NULL, NULL, type->size); tmp = makemonadicnode(create_temp_node(type), EINDIRECT); tmp->rtype = type; tmp->flags = qual & ENODE_FLAG_QUALS; return makediadicnode(tmp, create_objectnode(obj), EASS); } return CExpr_ConstructObject(TYPE_CLASS(type), create_temp_node(type), list, 1, 1, 1, 1, 1); } static ENode *CExpr_TemplArgDepCast(Type *type, UInt32 qual, ENodeList *args) { ENode *expr = CExpr_NewTemplDepENode(TDE_CAST); expr->data.templdep.u.cast.args = args; expr->data.templdep.u.cast.type = type; expr->data.templdep.u.cast.qual = qual; return expr; } static ENode *CExpr_ParseExplicitConversion(Type *type, UInt32 qual) { ENodeList *args; ENodeList *scan; if (IS_TEMPL_CLASS(type) && !CParser_CheckTemplateClassUsage(TEMPL_CLASS(type), 1)) type = TYPE(&stsignedint); if (tk == '(') tk = lex(); else CError_Error(CErrorStr114); args = CExpr_ScanExpressionList(1); if (tk != ')') { CError_Error(CErrorStr115); return nullnode(); } tk = lex(); if (CTemplTool_IsTemplateArgumentDependentType(type)) return CExpr_TemplArgDepCast(type, qual, args); for (scan = args; scan; scan = scan->next) { if (CTemplTool_IsTemplateArgumentDependentExpression(scan->node)) return CExpr_TemplArgDepCast(type, qual, args); } return CExpr_DoExplicitConversion(type, qual, args); } static ENode *CExpr_MemberVarAccess(BClassList *path, ObjMemberVar *var, ENode *expr) { ENode *accessnode; BClassList *varpath; CError_ASSERT(1152, path); if (TYPE_CLASS(path->type)->sominfo) return CSOM_MemberVarAccess(path, var, expr); varpath = NULL; if (var->has_path) varpath = OBJ_MEMBER_VAR_PATH(var)->path; accessnode = CExpr_GetClassAccessNode(path, varpath, expr, NULL, var->access, 1); if (!accessnode) return nullnode(); return CClass_AccessMember(accessnode, var->type, var->qual, var->offset); } static Boolean CExpr_IsTemplateFunc(Object *obj) { return IS_TEMPL_FUNC(obj->type); } static ENode *CExpr_ExplicitTemplateArgCheck(NameResult *pr) { NameSpaceObjectList *list; NameSpaceObjectList *newhead; NameSpaceObjectList *newlist; ENode *expr; if (pr->obj_10) { if (pr->obj_10->otype != OT_OBJECT || !CExpr_IsTemplateFunc(OBJECT(pr->obj_10))) return NULL; list = lalloc(sizeof(NameSpaceObjectList)); memclrw(list, sizeof(NameSpaceObjectList)); list->object = pr->obj_10; } else if (pr->nsol_14) { for (list = pr->nsol_14; list; list = list->next) { if (list->object->otype == OT_OBJECT && CExpr_IsTemplateFunc(OBJECT(list->object))) { newhead = newlist = galloc(sizeof(NameSpaceObjectList)); *newlist = *list; newlist->next = NULL; while ((list = list->next)) { if (list->object->otype == OT_OBJECT && CExpr_IsTemplateFunc(OBJECT(list->object))) { newlist->next = galloc(sizeof(NameSpaceObjectList)); newlist = newlist->next; *newlist = *list; newlist->next = NULL; } } list = newhead; break; } } if (!list) return NULL; } else { return NULL; } expr = CExpr_NewENode(EOBJLIST); expr->rtype = OBJECT(list->object)->type; expr->data.objlist.list = list; expr->data.objlist.templargs = CTempl_ParseUncheckTemplArgs(NULL, 0); tk = lex(); return expr; } ENode *CExpr_MakeNameLookupResultExpr(NameResult *pr) { ENode *expr; if (pr->obj_10) { switch (pr->obj_10->otype) { case OT_OBJECT: CClass_CheckObjectAccess(pr->bcl_18, OBJECT(pr->obj_10)); return create_objectnode(OBJECT(pr->obj_10)); case OT_ENUMCONST: CClass_CheckEnumAccess(pr->bcl_18, OBJ_ENUM_CONST(pr->obj_10)); expr = lalloc(sizeof(ENode)); expr->type = EINTCONST; expr->cost = 0; expr->flags = 0; expr->rtype = OBJ_ENUM_CONST(pr->obj_10)->type; expr->data.intval = OBJ_ENUM_CONST(pr->obj_10)->val; return expr; case OT_MEMBERVAR: CError_Error(CErrorStr221); return nullnode(); default: CError_FATAL(1268); } } if (pr->nsol_14) { expr = CExpr_NewENode(EOBJLIST); expr->rtype = OBJECT(pr->nsol_14->object)->type; expr->data.objlist.list = pr->nsol_14; return expr; } CError_FATAL(1278); return NULL; } static Type *CExpr_NewPTMType(EMemberInfo *member, Object *obj) { TypeMemberPointer *ptm; TypeMemberFunc *tmethod; BClassList *path; ptm = galloc(sizeof(TypeMemberPointer)); memclrw(ptm, sizeof(TypeMemberPointer)); ptm->type = TYPEMEMBERPOINTER; if (member->list->object->otype == OT_MEMBERVAR) { path = member->path; while (path->next) path = path->next; ptm->size = 4; ptm->ty2 = path->type; ptm->ty1 = OBJ_MEMBER_VAR(member->list->object)->type; } else { if (!obj) { CError_ASSERT(1306, member->list->object->otype == OT_OBJECT); obj = OBJECT(member->list->object); CError_ASSERT(1308, IS_TYPE_FUNC(obj->type)); } tmethod = galloc(sizeof(TypeMemberFunc)); memclrw(tmethod, sizeof(TypeMemberFunc)); *tmethod = *TYPE_METHOD(obj->type); CError_ASSERT(1312, tmethod->args); tmethod->args = tmethod->args->next; CDecl_MakePTMFuncType(TYPE_FUNC(tmethod)); tmethod->flags &= ~FUNC_DEFINED; ptm->size = 12; ptm->ty2 = TYPE(tmethod->theclass); ptm->ty1 = TYPE(tmethod); } return TYPE(ptm); } static ENode *CExpr_ParseNameResultExpr(NameResult *pr, ENode *expr, Boolean flag1, Boolean flag2) { ENode *result; ENode *ta_expr; ObjEnumConst *oec; TemplateAction *act; EMemberInfo *member; NameSpaceObjectList *list; Object *obj; TypeFunc *tfunc; SInt32 val; if (pr->type) { if (copts.cplusplus) { if (IS_TYPE_TEMPLATE(pr->type)) { if (TYPE_TEMPLATE(pr->type)->dtype == TEMPLDEP_ARGUMENT && TYPE_TEMPLATE(pr->type)->u.pid.type == TPT_NONTYPE) { result = CExpr_NewTemplDepENode(TDE_PARAM); result->data.templdep.u.pid = TYPE_TEMPLATE(pr->type)->u.pid; tk = lex(); return result; } if (TYPE_TEMPLATE(pr->type)->dtype == TEMPLDEP_QUALNAME && !pr->x20) { result = CExpr_NewTemplDepENode(TDE_QUALNAME); result->data.templdep.u.qual.type = TYPE_TEMPLATE(pr->type)->u.qual.type; result->data.templdep.u.qual.name = TYPE_TEMPLATE(pr->type)->u.qual.name; tk = lex(); return result; } } tk = lex(); return CExpr_ParseExplicitConversion(pr->type, pr->qual); } CError_ErrorSkip(CErrorStr141); tk = lex(); return nullnode(); } if (pr->obj_10) { switch (pr->obj_10->otype) { case OT_OBJECT: if (OBJECT(pr->obj_10)->nspace && OBJECT(pr->obj_10)->nspace->theclass && (OBJECT(pr->obj_10)->nspace->theclass->flags & CLASS_IS_TEMPL)) { result = CExpr_NewTemplDepENode(TDE_OBJ); result->data.templdep.u.obj = OBJECT(pr->obj_10); tk = lex(); return result; } if (!expr || !IS_TEMPL_FUNC(OBJECT(pr->obj_10)->type)) { if (!IS_TYPE_NONSTATIC_METHOD(OBJECT(pr->obj_10)->type)) { tk = lex(); if (tk == '<' && (ta_expr = CExpr_ExplicitTemplateArgCheck(pr))) return ta_expr; if (OBJECT(pr->obj_10)->datatype == DLOCAL && OBJECT(pr->obj_10)->u.var.info->func != cscope_currentfunc) { CError_Error(CErrorStr330); return nullnode(); } if (OBJECT(pr->obj_10)->datatype == DEXPR) { result = CInline_CopyExpression(OBJECT(pr->obj_10)->u.expr, CopyMode0); if (IS_TYPE_POINTER_ONLY(result->rtype) && ENODE_IS(result, EINTCONST)) { result = makemonadicnode(result, ETYPCON); result->data.monadic->rtype = TYPE(&stunsignedlong); } return result; } CClass_CheckObjectAccess(pr->bcl_18, OBJECT(pr->obj_10)); if (tk == '(' && flag2 && OBJECT(pr->obj_10)->datatype == DFUNC && copts.cplusplus && !pr->x1D && !IS_TYPEFUNC_METHOD(TYPE_FUNC(OBJECT(pr->obj_10)->type))) { result = CExpr_NewENode(EOBJLIST); result->rtype = OBJECT(pr->obj_10)->type; result->data.objlist.list = galloc(sizeof(NameSpaceObjectList)); result->data.objlist.list->next = pr->nsol_14; result->data.objlist.list->object = pr->obj_10; result->data.objlist.name = OBJECT(pr->obj_10)->name; return result; } result = create_objectnode(OBJECT(pr->obj_10)); if (expr) { while (ENODE_IS(expr, EINDIRECT)) expr = expr->data.monadic; switch (expr->type) { case EINTCONST: case EOBJREF: case EOBJLIST: break; default: result = makecommaexpression(expr, result); } } return result; } if (CClass_IsDestructor(OBJECT(pr->obj_10))) { if ((tk = lex()) != '(') { CError_Error(CErrorStr114); return nullnode(); } if ((tk = lex()) != ')') { CError_Error(CErrorStr115); return nullnode(); } if (!expr && (!cscope_currentfunc || !cscope_currentclass || !cscope_is_member_func)) { CError_Error(CErrorStr221); return nullnode(); } if (pr->isambig) CError_Error(CErrorStr188); if ((expr = CExpr_GetClassAccessNode(pr->bcl_18, NULL, expr, OBJECT(pr->obj_10), pr->obj_10->access, 1))) { tk = lex(); return CABI_DestroyObject(OBJECT(pr->obj_10), expr->data.monadic, 1, pr->x1D, 0); } } } break; case OT_ENUMCONST: CClass_CheckEnumAccess(pr->bcl_18, OBJ_ENUM_CONST(pr->obj_10)); oec = OBJ_ENUM_CONST(pr->obj_10); if (CInt64_IsZero(&oec->val) && IS_TYPE_ENUM(oec->type) && TYPE_ENUM(oec->type)->nspace && TYPE_ENUM(oec->type)->nspace->theclass && (TYPE_ENUM(oec->type)->nspace->theclass->flags & CLASS_IS_TEMPL)) { val = 0; expr = NULL; for (act = TEMPL_CLASS(TYPE_ENUM(oec->type)->nspace->theclass)->actions; act; act = act->next) { if (act->type == TAT_ENUMERATOR) { if (act->u.enumerator.initexpr) { expr = act->u.enumerator.initexpr; val = 0; } else { val++; } if (act->u.enumerator.objenumconst == oec) { CError_ASSERT(1521, expr); expr = CInline_CopyExpression(expr, CopyMode0); if (val) expr = makediadicnode(expr, intconstnode(TYPE(&stsignedlong), val), EADD); tk = lex(); return expr; } } } } result = lalloc(sizeof(ENode)); result->type = EINTCONST; result->cost = 0; result->flags = 0; result->rtype = OBJ_ENUM_CONST(pr->obj_10)->type; result->data.intval = OBJ_ENUM_CONST(pr->obj_10)->val; tk = lex(); return result; case OT_MEMBERVAR: if (!flag1 || expr || !pr->x1D) { if (pr->isambig) CError_Error(CErrorStr188); result = checkreference(CExpr_MemberVarAccess(pr->bcl_18, OBJ_MEMBER_VAR(pr->obj_10), expr)); tk = lex(); return result; } break; default: CError_FATAL(1552); } member = lalloc(sizeof(EMemberInfo)); memclrw(member, sizeof(EMemberInfo)); member->path = pr->bcl_18; member->expr = expr; member->pr_1D = pr->x1D; member->isambig = pr->isambig; if ((tk = lex()) == '<' && (ta_expr = CExpr_ExplicitTemplateArgCheck(pr))) { CError_ASSERT(1564, ENODE_IS(ta_expr, EOBJLIST)); member->list = ta_expr->data.objlist.list; member->templargs = ta_expr->data.objlist.templargs; } else { member->list = galloc(sizeof(NameSpaceObjectList)); member->list->next = NULL; member->list->object = pr->obj_10; } result = CExpr_NewENode(EMEMBER); result->data.emember = member; result->rtype = &stvoid; return result; } if (pr->nsol_14) { if ((tk = lex()) == '<' && (ta_expr = CExpr_ExplicitTemplateArgCheck(pr))) { CError_ASSERT(1591, ENODE_IS(ta_expr, EOBJLIST)); for (list = ta_expr->data.objlist.list; list; list = list->next) { if (list->object->otype == OT_OBJECT && IS_TYPE_NONSTATIC_METHOD(OBJECT(list->object)->type)) { member = lalloc(sizeof(EMemberInfo)); memclrw(member, sizeof(EMemberInfo)); member->path = pr->bcl_18; member->expr = expr; member->list = ta_expr->data.objlist.list; member->templargs = ta_expr->data.objlist.templargs; member->pr_1D = pr->x1D; member->isambig = pr->isambig; result = CExpr_NewENode(EMEMBER); result->data.emember = member; result->rtype = &stvoid; return result; } } return ta_expr; } for (list = pr->nsol_14; list; list = list->next) { if (list->object->otype == OT_OBJECT && IS_TYPE_NONSTATIC_METHOD(OBJECT(list->object)->type)) { member = lalloc(sizeof(EMemberInfo)); memclrw(member, sizeof(EMemberInfo)); member->path = pr->bcl_18; member->expr = expr; member->list = pr->nsol_14; member->pr_1D = pr->x1D; member->isambig = pr->isambig; result = CExpr_NewENode(EMEMBER); result->data.emember = member; result->rtype = &stvoid; return result; } } if (tk == '<' && (ta_expr = CExpr_ExplicitTemplateArgCheck(pr))) return ta_expr; result = CExpr_NewENode(EOBJLIST); result->rtype = OBJECT(pr->nsol_14->object)->type; result->data.objlist.list = pr->nsol_14; if (tk == '(' && copts.cplusplus && flag2 && !pr->x1D && pr->nsol_14->object->otype == OT_OBJECT) result->data.objlist.name = OBJECT(pr->nsol_14->object)->name; return result; } if (pr->name_4) { if (copts.cplusplus && flag2) { if (lookahead() == '(') { result = CExpr_NewENode(EOBJLIST); result->rtype = &stvoid; result->data.objlist.name = pr->name_4; tk = lex(); return result; } CError_Error(CErrorStr140, pr->name_4->name); tk = lex(); return nullnode(); } if (lookahead() != '(') { CError_Error(CErrorStr140, pr->name_4->name); tk = lex(); return nullnode(); } if (copts.checkprotos) CError_Error(CErrorStr178); tfunc = galloc(sizeof(TypeFunc)); memclrw(tfunc, sizeof(TypeFunc)); tfunc->type = TYPEFUNC; tfunc->functype = TYPE(&stsignedint); tfunc->args = &oldstyle; CDecl_SetFuncFlags(tfunc, 0); obj = CParser_NewFunctionObject(NULL); obj->name = pr->name_4; obj->sclass = TK_EXTERN; obj->nspace = cscope_root; obj->type = TYPE(tfunc); CScope_AddGlobalObject(obj); tk = lex(); return create_objectrefnode(obj); } CError_FATAL(1711); return NULL; } static ENode *CExpr_ParseRotate(Boolean is_right) { ENode *expr1; ENode *expr2; if (lex() != '(') { CError_Error(CErrorStr114); return nullnode(); } tk = lex(); expr1 = assignment_expression(); if (tk != ',') { CError_Error(CErrorStr116); return nullnode(); } tk = lex(); expr2 = assignment_expression(); if (tk != ')') { CError_Error(CErrorStr115); return nullnode(); } if (!IS_TYPE_INT(expr1->rtype)) expr1 = forceintegral(expr1); expr2 = integralpromote(expr2); tk = lex(); if (iszero(expr1) || iszero(expr2)) return expr1; return makediadicnode(expr1, expr2, is_right ? EROTR : EROTL); } static ENode *CExpr_ParseNextArg(void) { NameSpaceObjectList *list; NameResult pr; ENode *expr; SInt32 rounded_size; if ((tk = lex()) != '(') { CError_Error(CErrorStr114); return nullnode(); } if ((tk = lex()) != TK_IDENTIFIER) { CError_Error(CErrorStr107); return nullnode(); } list = CScope_FindObjectList(&pr, tkidentifier); if (!list) { CError_Error(CErrorStr140, tkidentifier->name); return nullnode(); } if (list->object->otype != OT_OBJECT || OBJECT(list->object)->datatype != DLOCAL) { CError_Error(CErrorStr140, tkidentifier->name); return nullnode(); } rounded_size = CMach_RoundedSizeOf(OBJECT(list->object)); expr = CExpr_MakeObjRefNode(OBJECT(list->object), 1); expr = makediadicnode(expr, intconstnode(CABI_GetPtrDiffTType(), rounded_size), EADD); expr->rtype = TYPE(&void_ptr); if ((tk = lex()) != ')') { CError_Error(CErrorStr115); return expr; } else { tk = lex(); return expr; } } static ENode *CExpr_ParseVecStep(void) { ENode *expr; Type *type; SInt32 value; DeclInfo di; expr = intconstnode(TYPE(&stsignedint), 0); if ((tk = lex()) == '(') { if (tk == '(' && islookaheaddeclaration()) { tk = lex(); memclrw(&di, sizeof(DeclInfo)); CParser_GetDeclSpecs(&di, 0); scandeclarator(&di); if (di.name) CError_Error(CErrorStr121); if (tk != ')') CError_ErrorSkip(CErrorStr115); else tk = lex(); type = di.thetype; if (IS_TYPE_REFERENCE(type)) type = TPTR_TARGET(type); } else { expr = unary_expression(); if (ENODE_IS(expr, EINDIRECT) && ENODE_IS(expr->data.monadic, EBITFIELD)) CError_Error(CErrorStr144); type = expr->rtype; } CDecl_CompleteType(type); if (IS_TYPE_VECTOR(type)) { switch (TYPE_STRUCT(type)->stype) { case STRUCT_VECTOR_UCHAR: case STRUCT_VECTOR_SCHAR: case STRUCT_VECTOR_BCHAR: value = 16; break; case STRUCT_VECTOR_USHORT: case STRUCT_VECTOR_SSHORT: case STRUCT_VECTOR_BSHORT: case STRUCT_VECTOR_PIXEL: value = 8; break; default: value = 4; } expr = intconstnode(TYPE(&stsignedint), value); } else { PPCError_Error(PPCErrorStr104, "vec_step", "vec_step", type, 0); } } else { CError_Error(CErrorStr114); } return expr; } static SInt32 CExpr_BuiltInComputeAlign(Type *type) { return CMach_GetTypeAlign(type); } static SInt32 CExpr_AtomTypeID(IntegralType what) { switch (what) { case IT_BOOL: return 1; case IT_CHAR: return 2; case IT_SCHAR: return 3; case IT_UCHAR: return 4; case IT_WCHAR_T: return 5; case IT_SHORT: return 6; case IT_USHORT: return 7; case IT_INT: return 8; case IT_UINT: return 9; case IT_LONG: return 10; case IT_ULONG: return 10; case IT_LONGLONG: return 12; case IT_ULONGLONG: return 13; case IT_FLOAT: return 14; case IT_SHORTDOUBLE: return 15; case IT_DOUBLE: return 16; case IT_LONGDOUBLE: return 17; case IT_17: return 32; case IT_18: return 33; case IT_19: return 34; case IT_20: return 35; case IT_21: return 36; case IT_22: return 37; case IT_23: return 38; case IT_24: return 39; default: CError_FATAL(1976); return 0; } } static SInt32 CExpr_BuiltInComputeType(Type *type) { switch (type->type) { case TYPEINT: return 0x100 | CExpr_AtomTypeID(TYPE_INTEGRAL(type)->integral); case TYPEFLOAT: return 0x200 | CExpr_AtomTypeID(TYPE_INTEGRAL(type)->integral); case TYPEENUM: return 0x400 | (CExpr_BuiltInComputeType(TYPE_ENUM(type)->enumtype) & 0xFF); case TYPEPOINTER: return 0x800; case TYPEARRAY: return 0x1000; case TYPESTRUCT: return 0x2000; case TYPECLASS: return 0x2000; case TYPEMEMBERPOINTER: return 0x4000; case TYPEFUNC: return 0x8000; default: CError_Error(CErrorStr146); case TYPEVOID: return 0; } } static SInt32 CExpr_BuiltInClassifyType(Type *type) { switch (type->type) { case TYPEVOID: return 0; case TYPEFUNC: return 10; case TYPEENUM: return 3; case TYPEINT: return 1; case TYPEFLOAT: return 8; case TYPEPOINTER: case TYPEMEMBERPOINTER: return 5; case TYPEARRAY: return 14; case TYPESTRUCT: return 12; case TYPECLASS: return 12; case TYPEBITFIELD: return -1; case TYPETEMPLATE: return -1; default: return -1; } } static SInt32 CExpr_BuiltInComputeVArgType(Type *type) { switch (type->type) { case TYPEINT: case TYPEENUM: return 0; case TYPEFLOAT: return 1; default: return 2; } } static Type *CExpr_ParseTypeExpression(Boolean *outflag) { ENode *expr; Type *type; DeclInfo di; tk = lex(); if (tk == '(' && islookaheaddeclaration()) { tk = lex(); memclrw(&di, sizeof(DeclInfo)); CParser_GetDeclSpecs(&di, 0); scandeclarator(&di); if (di.name) CError_Error(CErrorStr121); if (tk != ')') CError_ErrorSkip(CErrorStr115); else tk = lex(); type = di.thetype; if (IS_TYPE_REFERENCE(type)) type = TPTR_TARGET(type); } else { expr = unary_expression(); if (ENODE_IS(expr, EINDIRECT) && ENODE_IS(expr->data.monadic, EBITFIELD)) CError_Error(CErrorStr144); if (outflag) *outflag = ENODE_IS(expr, EINTCONST) && CInt64_IsZero(&expr->data.intval); type = expr->rtype; } CDecl_CompleteType(type); return type; } static ENode *CExpr_ParseBuiltin(SInt32 (*parser)(Type *)) { ENode *expr; expr = intconstnode(TYPE(&stsignedint), 0); CInt64_SetLong(&expr->data.intval, parser(CExpr_ParseTypeExpression(NULL))); return expr; } static ENode *CExpr_ParseBuiltin_isintconst(void) { ENode *expr; expr = intconstnode(TYPE(&stsignedint), 0); tk = lex(); if (tk != '(') CError_ErrorSkip(CErrorStr121); else tk = lex(); if (ENODE_IS(expression(), EINTCONST)) CInt64_SetLong(&expr->data.intval, 1); if (tk != ')') CError_ErrorSkip(CErrorStr115); else tk = lex(); return expr; } static ENode *primary_expression(Boolean flag) { NameResult pr; ENode *expr; switch (tk) { case TK_TRUE: expr = lalloc(sizeof(ENode)); expr->type = EINTCONST; expr->cost = 0; expr->flags = 0; expr->rtype = TYPE(&stbool); CInt64_SetULong(&expr->data.intval, 1); tk = lex(); return expr; case TK_FALSE: expr = lalloc(sizeof(ENode)); expr->type = EINTCONST; expr->cost = 0; expr->flags = 0; expr->rtype = TYPE(&stbool); CInt64_SetULong(&expr->data.intval, 0); tk = lex(); return expr; case TK_INTCONST: expr = lalloc(sizeof(ENode)); expr->type = EINTCONST; expr->cost = 0; expr->flags = 0; expr->rtype = atomtype(); expr->data.intval = tkintconst; tk = lex(); return expr; case TK_FLOATCONST: expr = lalloc(sizeof(ENode)); expr->type = EFLOATCONST; expr->cost = 0; expr->flags = 0; expr->rtype = atomtype(); expr->data.floatval = tkfloatconst; tk = lex(); return expr; case TK_STRING: expr = CExpr_NewENode(ESTRINGCONST); expr->rtype = CDecl_NewArrayType(ispascalstring ? TYPE(&stunsignedchar) : TYPE(&stchar), tksize); expr->data.string.size = tksize; expr->data.string.data = tkstring; expr->data.string.ispascal = ispascalstring; if (copts.const_strings) expr->flags = ENODE_FLAG_CONST; expr = makemonadicnode(expr, EINDIRECT); expr->data.monadic->rtype = CDecl_NewPointerType(expr->rtype); tk = lex(); return expr; case TK_STRING_WIDE: expr = CExpr_NewENode(ESTRINGCONST); expr->rtype = CDecl_NewArrayType(CParser_GetWCharType(), tksize); expr->data.string.size = tksize; expr->data.string.data = tkstring; expr->data.string.ispascal = ispascalstring; if (copts.const_strings) expr->flags = ENODE_FLAG_CONST; expr = makemonadicnode(expr, EINDIRECT); expr->data.monadic->rtype = CDecl_NewPointerType(expr->rtype); tk = lex(); return expr; case TK_THIS: case TK_SELF: expr = CClass_CreateThisSelfExpr(); if (!expr) expr = nullnode(); tk = lex(); return expr; case TK_AT_SELECTOR: return CObjC_ParseSelectorExpression(); case TK_AT_ENCODE: return CObjC_ParseEncodeExpression(); case TK_AT_PROTOCOL: return CObjC_ParseProtocolExpression(); case '@': if (copts.objective_c) return CObjC_ParseAtExpression(); break; case '(': tk = lex(); expr = s_expression(); if (tk != ')') CError_ErrorSkip(CErrorStr115); else tk = lex(); if (ENODE_IS(expr, EASS)) expr->flags = expr->flags | ENODE_FLAG_80; return expr; case '[': if (copts.objective_c) return CObjC_ParseMessageExpression(); break; case TK_IDENTIFIER: if (tkidentifier->name[0] == '_' && tkidentifier->name[1] == '_') { if (!strcmp(tkidentifier->name, "__builtin_align")) return CExpr_ParseBuiltin(CExpr_BuiltInComputeAlign); if (!strcmp(tkidentifier->name, "__builtin_ntype")) return CExpr_ParseBuiltin(CExpr_BuiltInComputeType); if (!strcmp(tkidentifier->name, "__builtin_type") || !strcmp(tkidentifier->name, "__builtin_vargtype")) return CExpr_ParseBuiltin(CExpr_BuiltInComputeVArgType); if (!strcmp(tkidentifier->name, "__builtin_classify_type")) return CExpr_ParseBuiltin(CExpr_BuiltInClassifyType); if (!strcmp(tkidentifier->name, "__builtin_next_arg")) return CExpr_ParseNextArg(); } if (copts.altivec_model && !strcmp("vec_step", tkidentifier->name)) return CExpr_ParseVecStep(); case '~': case TK_OPERATOR: case TK_INHERITED: case TK_COLON_COLON: if (CScope_ParseExprName(&pr)) return CExpr_ParseNameResultExpr(&pr, NULL, flag, 1); tk = lex(); return nullnode(); } CError_ErrorSkip(CErrorStr141); return nullnode(); } static ENode *CExpr_SimpleExplicitConversion(void) { DeclInfo di; memclrw(&di, sizeof(DeclInfo)); if (!copts.cpp_extensions && tk != TK_UU_TYPEOF_UU && tk != TK_TYPENAME && lookahead() != '(') CError_Error(CErrorStr114); CParser_GetDeclSpecs(&di, 0); return CExpr_ParseExplicitConversion(di.thetype, di.qual); } static ENode *CExpr_NewPTMFCall(void) { tk = lex(); CExpr_ScanExpressionList(1); if (tk != ')') { CError_Error(CErrorStr115); return nullnode(); } else { CError_FATAL(2465); return nullnode(); } } static ENode *call_ptmf(ENode *expr) { Type *rettype; ENodeList *args; ENodeList *list1; ENodeList *list2; Object *callobj; rettype = TYPE_FUNC(TPTR_TARGET(expr->data.mfpointer.mfpointer->rtype))->functype; tk = lex(); args = CExpr_ScanExpressionList(1); if (tk != ')') { CError_Error(CErrorStr115); return nullnode(); } if (IS_TYPE_STRUCT(rettype) || IS_TYPE_CLASS(rettype) || IS_TYPE_12BYTES_MEMBERPOINTER(rettype)) callobj = rt_ptmf_scall4; else callobj = rt_ptmf_scall; list1 = lalloc(sizeof(ENodeList)); list1->next = args; list1->node = expr->data.mfpointer.accessnode->data.monadic; list2 = lalloc(sizeof(ENodeList)); list2->next = list1; list2->node = expr->data.mfpointer.mfpointer->data.monadic; if (!copts.old_argmatch) { CError_ASSERT(2568, IS_TYPE_POINTER_ONLY(list2->node->rtype)); list2->node->rtype = TYPE(&void_ptr); } expr = CExpr_GenericPtmfCall( callobj, TYPE_FUNC(TPTR_TARGET(expr->data.mfpointer.mfpointer->rtype)), list2); tk = lex(); return expr; } static ENode *CExpr_DummyDestr(ENode *expr) { SInt32 state; NameResult pr; DeclInfo di; NameSpace *nspace; CPrep_TokenStreamGetState(&state); nspace = cscope_current; if ((tk = lex()) == TK_COLON_COLON) { nspace = cscope_root; tk = lex(); } else if (tk != '~' && tk != TK_IDENTIFIER && !(tk >= TK_AUTO && tk <= TK_BYREF)) { CPrep_TokenStreamSetCurState(&state); return NULL; } loop: if (tk == '~') goto is_tilde; if (tk == TK_IDENTIFIER) { if (CScope_FindTypeName(nspace, tkidentifier, &pr)) { tk = lex(); if (pr.nspace_0) { if (tk == TK_COLON_COLON) { tk = lex(); nspace = pr.nspace_0; goto loop; } } else if (IS_TYPE_CLASS(pr.type) && tk == TK_COLON_COLON) { tk = lex(); nspace = TYPE_CLASS(pr.type)->nspace; goto loop; } else { if (!is_typesame(pr.type, expr->rtype)) CError_Error(CErrorStr146); if (tk == TK_COLON_COLON && ((tk = lex()) == '~') && ((tk = lex()) == TK_IDENTIFIER)) { parse_dtor: if (CScope_FindTypeName(nspace, tkidentifier, &pr) && !pr.nspace_0) { if (!is_typesame(pr.type, expr->rtype)) CError_Error(CErrorStr146); tk = lex(); goto parsed; } } } } } else if (tk >= TK_AUTO && tk <= TK_BYREF) { memclrw(&di, sizeof(DeclInfo)); CParser_GetDeclSpecs(&di, 0); if (di.storageclass || di.qual || !is_typesame(di.thetype, expr->rtype)) CError_Error(CErrorStr146); if (tk == TK_COLON_COLON && ((tk = lex()) == '~')) { is_tilde: if ((tk = lex()) == TK_IDENTIFIER) goto parse_dtor; memclrw(&di, sizeof(DeclInfo)); CParser_GetDeclSpecs(&di, 0); if (di.storageclass || !is_typesame(di.thetype, expr->rtype)) CError_Error(CErrorStr146); goto parsed; } } CError_Error(CErrorStr141); return NULL; parsed: if (tk == '(') { if ((tk = lex()) != ')') CError_Error(CErrorStr115); else tk = lex(); } else { CError_Error(CErrorStr114); } expr = makemonadicnode(expr, ETYPCON); expr->rtype = &stvoid; return expr; } static ENode *postfix_expression(Boolean flag) { NameResult pr; Conversion conv; ENode *expr; ENode *subexpr; ENode *funcexpr; ENodeList *args; ENode *copy; ENode *tmp; StructMember *member; if (copts.cplusplus) { switch (tk) { case TK_VOID: case TK_CHAR: case TK_SHORT: case TK_INT: case TK_LONG: case TK_FLOAT: case TK_DOUBLE: case TK_SIGNED: case TK_UNSIGNED: case TK_UNK_113: case TK_UNK_114: case TK_UNK_115: case TK_UNK_116: case TK_UNK_117: case TK_UNK_118: case TK_UNK_119: case TK_UNK_11A: case TK_UU_TYPEOF_UU: case TK_BOOL: case TK_WCHAR_T: case TK_TYPENAME: expr = CExpr_SimpleExplicitConversion(); break; default: expr = primary_expression(flag); break; case TK_CONST_CAST: expr = CRTTI_Parse_const_cast(); break; case TK_DYNAMIC_CAST: expr = CRTTI_Parse_dynamic_cast(); break; case TK_REINTERPRET_CAST: expr = CRTTI_Parse_reinterpret_cast(); break; case TK_STATIC_CAST: expr = CRTTI_Parse_static_cast(); break; case TK_TYPEID: expr = CRTTI_ParseTypeID(); break; } } else { expr = primary_expression(flag); } loop: switch (tk) { case '[': expr = pointer_generation(expr); tk = lex(); subexpr = expression(); if (copts.cplusplus && CExpr_CheckOperator('[', expr, subexpr, &conv)) { if ((expr = conv.x0)) { if (tk != ']') CError_ErrorSkip(CErrorStr125); else tk = lex(); goto loop; } CError_ASSERT(2753, expr = conv.left); CError_ASSERT(2754, subexpr = conv.right); } if (IS_TYPE_POINTER(expr->rtype)) { expr = padd(expr, subexpr); } else if (IS_TYPE_POINTER(subexpr->rtype)) { expr = padd(subexpr, expr); } else { CError_Error(CErrorStr148); goto dont_do_indirect; } expr = makemonadicnode(expr, EINDIRECT); expr->rtype = TPTR_TARGET(expr->rtype); dont_do_indirect: if (tk != ']') CError_ErrorSkip(CErrorStr125); else tk = lex(); goto loop; case '(': funcexpr = CExpr_PointerGeneration(expr); if (copts.cplusplus) { if (CExpr_CheckOperator('(', funcexpr, NULL, &conv)) { CError_ASSERT(2775, expr = conv.x0); goto loop; } if (ENODE_IS(funcexpr, EMFPOINTER)) { expr = checkreference(call_ptmf(funcexpr)); goto loop; } } tk = lex(); args = CExpr_ScanExpressionList(1); if (tk != ')') CError_Error(CErrorStr115); if (ENODE_IS(funcexpr, ETEMPLDEP)) { expr = CExpr_NewENode(EFUNCCALL); expr->rtype = &sttemplexpr; expr->data.funccall.funcref = funcexpr; expr->data.funccall.args = args; expr->data.funccall.functype = &rt_func; tk = lex(); } else { expr = checkreference(CExpr_MakeFunctionCall(funcexpr, args)); tk = lex(); } goto loop; case TK_ARROW: expr = pointer_generation(expr); if (copts.cplusplus) { while (IS_TYPE_CLASS(expr->rtype) && CExpr_CheckOperator(TK_ARROW, expr, NULL, &conv)) { CError_ASSERT(2810, subexpr = conv.x0); expr = pointer_generation(subexpr); } } if (!IS_TYPE_POINTER(expr->rtype)) { CError_ErrorSkip(CErrorStr148); return expr; } if (copts.cplusplus && copts.objective_c && CObjC_IsType_id(expr->rtype)) { expr = makemonadicnode(expr, EINDIRECT); expr->rtype = TPTR_TARGET(expr->rtype); if ((subexpr = CObjC_CheckModernSendMessage(NULL, expr))) return subexpr; } else { expr = makemonadicnode(expr, EINDIRECT); expr->rtype = TPTR_TARGET(expr->rtype); } case '.': expr = pointer_generation(expr); if (IS_TYPE_CLASS(expr->rtype)) { CDecl_CompleteType(expr->rtype); if (TYPE_CLASS(expr->rtype)->objcinfo && copts.cplusplus && (subexpr = CObjC_CheckModernSendMessage(TYPE_CLASS(expr->rtype), expr))) return subexpr; if (!(TYPE_CLASS(expr->rtype)->flags & CLASS_COMPLETED)) CError_Error(CErrorStr136, expr->rtype, 0); if ((tk = lex()) == TK_TEMPLATE && (tk = lex()) != TK_IDENTIFIER) CError_Error(CErrorStr107); if (CScope_ParseMemberName(TYPE_CLASS(expr->rtype), &pr, 0)) { if (pr.x1C) { if ((tk = lex()) == '(') { if ((tk = lex()) != ')') CError_Error(CErrorStr115); else tk = lex(); } else { CError_Error(CErrorStr114); } expr = makemonadicnode(expr, ETYPCON); expr->rtype = &stvoid; } else { expr = checkreference(CExpr_ParseNameResultExpr(&pr, expr, 0, 0)); } } goto loop; } if (!IS_TYPE_STRUCT(expr->rtype) || TYPE_STRUCT(expr->rtype)->stype > STRUCT_TYPE_MAX) { if (copts.cplusplus && (subexpr = CExpr_DummyDestr(expr))) return subexpr; CError_ErrorSkip(CErrorStr149); return expr; } if (!ENODE_IS(expr, EINDIRECT)) { subexpr = CExpr_NewETEMPNode(expr->rtype, 1); copy = lalloc(sizeof(ENode)); *copy = *subexpr; tmp = makemonadicnode(subexpr, EINDIRECT); tmp->rtype = expr->rtype; tmp = makediadicnode(tmp, expr, EASS); tmp = makediadicnode(tmp, copy, ECOMMA); tmp->rtype = copy->rtype; tmp = makemonadicnode(tmp, EINDIRECT); tmp->rtype = expr->rtype; expr = tmp; } if ((tk = lex()) != TK_IDENTIFIER) { CError_Error(CErrorStr107); return expr; } member = ismember(TYPE_STRUCT(expr->rtype), tkidentifier); if (!member) { if (!expr->rtype->size) CError_Error(CErrorStr136, expr->rtype, 0); else CError_Error(CErrorStr150, tkidentifier->name); return expr; } if (!IS_TYPE_POINTER(expr->data.monadic->rtype)) { CError_ErrorSkip(CErrorStr149); return expr; } expr = checkreference(CClass_AccessMember(expr, member->type, member->qual, member->offset)); tk = lex(); goto loop; case TK_INCREMENT: tmp = pointer_generation(expr); if (copts.cplusplus && CExpr_CheckOperator(TK_INCREMENT, tmp, nullnode(), &conv)) { if ((expr = conv.x0)) { tk = lex(); goto loop; } CError_ASSERT(2952, tmp = conv.left); } tmp = CExpr_LValue(tmp, 1, 1); if (tmp->rtype == TYPE(&stbool)) { expr = CExpr_TempModifyExpr(tmp); tk = lex(); } else { checkadditive(tmp); expr = makemonadicnode(tmp, EPOSTINC); tk = lex(); } goto loop; case TK_DECREMENT: tmp = pointer_generation(expr); if (copts.cplusplus && CExpr_CheckOperator(TK_DECREMENT, tmp, nullnode(), &conv)) { if ((expr = conv.x0)) { tk = lex(); goto loop; } CError_ASSERT(2976, tmp = conv.left); } tmp = CExpr_LValue(tmp, 1, 1); checkadditive(tmp); expr = makemonadicnode(tmp, EPOSTDEC); tk = lex(); goto loop; } return expr; } static ENode *CExpr_ParseSizeof(void) { Type *type; ENode *expr; type = CExpr_ParseTypeExpression(NULL); if (IS_TYPE_CLASS(type) && TYPE_CLASS(type)->sominfo) CError_Error(CErrorStr286); if (CTemplTool_IsTemplateArgumentDependentType(type)) { expr = CExpr_NewTemplDepENode(TDE_SIZEOF); expr->data.templdep.u.typeexpr.type = type; return expr; } if (type->size == 0) { if (copts.gcc_extensions && (IS_TYPE_FUNC(type) || IS_TYPE_VOID(type))) return intconstnode(CABI_GetSizeTType(), 1); if (IS_TYPE_CLASS(type) || IS_TYPE_STRUCT(type)) CError_Error(CErrorStr136, type, 0); else CError_Error(CErrorStr146); } return intconstnode(CABI_GetSizeTType(), type->size); } SInt32 scansizeof(void) { ENode *expr; expr = CExpr_ParseSizeof(); if (!ENODE_IS(expr, EINTCONST)) { CError_Error(CErrorStr190); return 0; } return CInt64_GetULong(&expr->data.intval); } static ENode *CExpr_ParseAlignof(void) { Type *type; ENode *expr; SInt16 align; type = CExpr_ParseTypeExpression(NULL); if (IS_TYPE_CLASS(type) && TYPE_CLASS(type)->sominfo) CError_Error(CErrorStr364); if (CTemplTool_IsTemplateArgumentDependentType(type)) { expr = CExpr_NewTemplDepENode(TDE_ALIGNOF); expr->data.templdep.u.typeexpr.type = type; return expr; } if (type->size == 0) { if (IS_TYPE_CLASS(type) || IS_TYPE_STRUCT(type)) CError_Error(CErrorStr136, type, 0); else CError_Error(CErrorStr146); } align = CMach_GetTypeAlign(type); if (align == 0) align = 1; return intconstnode(CABI_GetSizeTType(), align); } SInt32 scanalignof(void) { ENode *expr; expr = CExpr_ParseAlignof(); if (!ENODE_IS(expr, EINTCONST)) { CError_Error(CErrorStr190); return 0; } return CInt64_GetULong(&expr->data.intval); } static ENode *logicalexpression(ENode *expr) { if (copts.cplusplus && copts.booltruefalse) expr->rtype = TYPE(&stbool); else expr->rtype = TYPE(&stsignedint); return expr; } ENode *getnodeaddress(ENode *expr, Boolean flag) { ENode *result; Object *obj; if (!ENODE_IS(expr, EINDIRECT)) { expr = CExpr_LValue(expr, flag, flag); if (!ENODE_IS(expr, EINDIRECT)) { if (!flag) CError_Error(CErrorStr142); return nullnode(); } } else { if (flag && ENODE_IS(expr->data.monadic, EOBJREF) && expr->data.monadic->data.objref->name == this_name_node && cscope_currentfunc && cscope_currentclass && expr->data.monadic->data.objref == CClass_ThisSelfObject()) CError_Error(CErrorStr189); } result = lalloc(sizeof(ENode)); *result = *expr; restart: switch (result->data.monadic->type) { case EPOSTINC: case EPOSTDEC: case EPREINC: case EPREDEC: result->type = ETYPCON; if (IS_TYPE_POINTER_ONLY(result->rtype)) result->flags = TPTR_QUAL(result->rtype) & ENODE_FLAG_QUALS; result->rtype = CDecl_NewPointerType(result->rtype); return result; case EOBJREF: obj = result->data.monadic->data.objref; if (obj->datatype == DALIAS) { CExpr_AliasTransform(result->data.monadic); goto restart; } if (obj->datatype == DINLINEFUNC) CError_Error(CErrorStr175); obj->flags = obj->flags | OBJECT_FLAGS_2; if (flag && !copts.cplusplus && obj->sclass == TK_REGISTER) CError_Error(CErrorStr163); break; case EFUNCCALL: if (flag && !IS_TYPE_POINTER_ONLY(result->data.monadic->data.funccall.functype->functype)) CError_Warning(CErrorStr142); break; case EBITFIELD: CError_Error(CErrorStr144); return nullnode(); } switch (result->rtype->type) { case TYPEPOINTER: result->data.monadic->rtype = CDecl_NewPointerType(result->rtype); result->data.monadic->flags = result->flags; break; default: result->data.monadic->rtype = CDecl_NewPointerType(result->rtype); result->data.monadic->flags = result->flags; } return result->data.monadic; } static ENode *CExpr_MakeStaticMemberList(NameSpaceObjectList *list) { NameSpaceObjectList *newlist; NameSpaceObjectList *n; ENode *result; newlist = NULL; while (list) { if (list->object->otype == OT_OBJECT && IS_TYPE_STATIC_METHOD(OBJECT(list->object)->type)) { n = galloc(sizeof(NameSpaceObjectList)); *n = *list; n->next = newlist; newlist = n; } list = list->next; } if (!newlist) { CError_Warning(CErrorStr331); return nullnode(); } result = CExpr_NewENode(EOBJLIST); result->rtype = OBJECT(newlist->object)->type; result->data.objlist.list = newlist; return result; } static ENode *CExpr_MakePTDM(ENode *expr) { ENode *result; CError_ASSERT(3414, ENODE_IS(expr, EMEMBER) && expr->data.emember->list->object->otype == OT_MEMBERVAR); result = nullnode(); result->rtype = CExpr_NewPTMType(expr->data.emember, NULL); CInt64_SetLong(&result->data.intval, OBJ_MEMBER_VAR(expr->data.emember->list->object)->offset + 1); return result; } ENode *getpointertomemberfunc(ENode *expr, Type *type, Boolean flag) { NameSpaceObjectList *list; Object *obj; Object *dataobj; Type *ptmtype; TypeMemberFunc *tmethod; OLinkList *olist; SInt32 data[3]; CError_ASSERT(3442, ENODE_IS(expr, EMEMBER)); if (expr->data.emember->expr && !copts.cpp_extensions) CError_Error(CErrorStr141); if (!copts.cpp_extensions) { if (!(expr->data.emember->x11 && expr->data.emember->pr_1D)) { if (type && IS_TYPE_MEMBERPOINTER(type)) CError_Warning(CErrorStr331); } } if (expr->data.emember->list->next) { if (type) { if (IS_TYPE_MEMBERPOINTER(type)) { type = TYPE_MEMBER_POINTER(type)->ty1; for (list = expr->data.emember->list; list; list = list->next) { if (list->object->otype == OT_OBJECT && is_memberpointerequal(OBJECT(list->object)->type, type)) { obj = OBJECT(list->object); break; } } if (!list) { CError_Error(CErrorStr146); return nullnode(); } } else { return CExpr_MakeStaticMemberList(expr->data.emember->list); } } else { obj = OBJECT(expr->data.emember->list->object); } } else { obj = OBJECT(expr->data.emember->list->object); } while (obj->datatype == DALIAS) obj = obj->u.alias.object; CError_ASSERT(3503, obj->otype == OT_OBJECT && IS_TYPE_NONSTATIC_METHOD(obj->type)); if (TYPE_FUNC(obj->type)->flags & FUNC_IS_TEMPL) CError_Error(CErrorStr190); ptmtype = CExpr_NewPTMType(expr->data.emember, obj); tmethod = TYPE_METHOD(obj->type); dataobj = CParser_NewGlobalDataObject(NULL); dataobj->name = CParser_GetUniqueName(); dataobj->nspace = cscope_root; dataobj->type = ptmtype; dataobj->sclass = TK_STATIC; if (flag) { data[0] = 0; if (obj->datatype == DVFUNC) { olist = NULL; data[1] = tmethod->vtbl_index; data[2] = tmethod->theclass->vtable->offset; } else { data[1] = -1; data[2] = 0; olist = galloc(sizeof(OLinkList)); olist->next = NULL; olist->obj = obj; olist->somevalue = 0; olist->offset = 8; } CInit_DeclareData(dataobj, data, olist, dataobj->type->size); } return create_objectnode(dataobj); } static ENode *getpointertomember(ENode *expr) { CError_ASSERT(3554, ENODE_IS(expr, EMEMBER)); if (expr->data.emember->expr) CError_Error(CErrorStr141); expr->data.emember->x11 = 1; if (!expr->data.emember->list->next) { if (expr->data.emember->list->object->otype == OT_MEMBERVAR) return CExpr_MakePTDM(expr); else return getpointertomemberfunc(expr, NULL, 1); } return expr; } ENode *CExpr_New_ELOGNOT_Node(ENode *input) { ENode *expr; Conversion conv; if (IS_TYPE_TEMPLDEPEXPR(input->rtype)) return CTempl_MakeTemplDepExpr(NULL, ELOGNOT, input); expr = pointer_generation(input); if (copts.cplusplus && CExpr_CheckOperator('!', expr, NULL, &conv)) { if ((input = conv.x0)) return input; CError_ASSERT(3593, expr = conv.left); } switch (expr->rtype->type) { case TYPEINT: case TYPEFLOAT: case TYPEPOINTER: case TYPEARRAY: break; case TYPEENUM: expr = forceintegral(expr); break; case TYPEMEMBERPOINTER: expr = CExpr_ConvertToCondition(expr); break; default: CError_Error(CErrorStr144); return expr; } switch (expr->type) { case EINTCONST: expr->data.intval = CInt64_Not(expr->data.intval); break; case EFLOATCONST: expr->type = EINTCONST; CInt64_SetLong(&expr->data.intval, CMach_FloatIsZero(expr->data.floatval)); break; default: expr = makemonadicnode(expr, ELOGNOT); } return logicalexpression(expr); } ENode *CExpr_New_EMONMIN_Node(ENode *input) { ENode *expr; Conversion conv; if (IS_TYPE_TEMPLDEPEXPR(input->rtype)) return CTempl_MakeTemplDepExpr(NULL, EMONMIN, input); expr = pointer_generation(input); if (copts.cplusplus && CExpr_CheckOperator('-', expr, NULL, &conv)) { if ((input = conv.x0)) return input; CError_ASSERT(3652, expr = conv.left); } switch (expr->rtype->type) { case TYPEINT: case TYPEENUM: expr = integralpromote(expr); if (ENODE_IS(expr, EINTCONST)) { expr->data.intval = CMach_CalcIntMonadic(expr->rtype, '-', expr->data.intval); return expr; } return makemonadicnode(expr, EMONMIN); case TYPEFLOAT: if (ENODE_IS(expr, EFLOATCONST)) { expr->data.floatval = CMach_CalcFloatMonadic(expr->rtype, '-', expr->data.floatval); return expr; } return CExpr_UnaryFloatExpression(makemonadicnode(expr, EMONMIN)); default: CError_Error(CErrorStr144); return expr; } } ENode *CExpr_New_EBINNOT_Node(ENode *input) { ENode *expr; Conversion conv; if (IS_TYPE_TEMPLDEPEXPR(input->rtype)) return CTempl_MakeTemplDepExpr(NULL, EBINNOT, input); expr = pointer_generation(input); if (copts.cplusplus && CExpr_CheckOperator('~', expr, NULL, &conv)) { if ((input = conv.x0)) return input; CError_ASSERT(3702, expr = conv.left); } expr = integralpromote(expr); if (ENODE_IS(expr, EINTCONST)) { expr->data.intval = CMach_CalcIntMonadic(expr->rtype, '~', expr->data.intval); return expr; } return makemonadicnode(expr, EBINNOT); } ENode *unary_expression(void) { ENode *expr; ENode *tmp; Conversion conv; switch (tk) { case TK_COLON_COLON: switch (lookahead()) { case TK_NEW: tk = lex(); return scannew(1); case TK_DELETE: tk = lex(); return scandelete(1); } return postfix_expression(0); case TK_NEW: return scannew(0); case TK_DELETE: return scandelete(0); case TK_INCREMENT: tk = lex(); if (copts.cplusplus) { expr = pointer_generation(cast_expression()); if (CExpr_CheckOperator(TK_INCREMENT, expr, NULL, &conv)) { if (conv.x0) return conv.x0; CError_ASSERT(3748, expr = conv.left); } } else { expr = pointer_generation(unary_expression()); } expr = CExpr_LValue(expr, 1, 1); if (expr->rtype == TYPE(&stbool)) { tmp = nullnode(); tmp->rtype = TYPE(&stbool); CInt64_SetLong(&tmp->data.intval, 1); return makediadicnode(expr, tmp, EASS); } else { checkadditive(expr); return makemonadicnode(expr, EPREINC); } case TK_DECREMENT: tk = lex(); if (copts.cplusplus) { expr = pointer_generation(cast_expression()); if (CExpr_CheckOperator(TK_DECREMENT, expr, NULL, &conv)) { if (conv.x0) return conv.x0; CError_ASSERT(3776, expr = conv.left); } } else { expr = pointer_generation(unary_expression()); } expr = CExpr_LValue(expr, 1, 1); checkadditive(expr); return makemonadicnode(expr, EPREDEC); case '&': if (copts.cplusplus) { switch ((tk = lex())) { case TK_IDENTIFIER: case TK_INHERITED: case TK_COLON_COLON: expr = postfix_expression(1); if (ENODE_IS(expr, EMEMBER)) return getpointertomember(expr); break; default: expr = cast_expression(); } if (CExpr_CheckOperator('&', expr, NULL, &conv)) { CError_ASSERT(3809, conv.x0); return conv.x0; } } else { tk = lex(); expr = cast_expression(); } if (copts.mpwc_relax && !copts.cplusplus && IS_TYPE_ARRAY(expr->rtype) && ENODE_IS(expr, EINDIRECT)) return pointer_generation(expr); if (ENODE_IS(expr, EOBJLIST)) return expr; if (IS_TYPE_TEMPLDEPEXPR(expr->rtype)) { tmp = CExpr_NewTemplDepENode(TDE_ADDRESS_OF); tmp->data.templdep.u.monadic = expr; return tmp; } return getnodeaddress(expr, 1); case '*': tk = lex(); expr = pointer_generation(cast_expression()); if (copts.cplusplus && CExpr_CheckOperator('*', expr, NULL, &conv)) { if (conv.x0) return conv.x0; CError_ASSERT(3840, expr = conv.left); } if (!IS_TYPE_POINTER(expr->rtype)) { CError_Error(CErrorStr148); return expr; } tmp = makemonadicnode(expr, EINDIRECT); CDecl_CompleteType(tmp->rtype = TPTR_TARGET(tmp->rtype)); return tmp; case '+': tk = lex(); expr = pointer_generation(cast_expression()); if (copts.cplusplus && CExpr_CheckOperator('+', expr, NULL, &conv)) { if (conv.x0) return conv.x0; CError_ASSERT(3852, expr = conv.left); } switch (expr->rtype->type) { case TYPEINT: case TYPEENUM: return integralpromote(expr); case TYPEFLOAT: case TYPEPOINTER: case TYPEARRAY: return expr; default: CError_Error(CErrorStr144); return expr; } case '-': tk = lex(); return CExpr_New_EMONMIN_Node(cast_expression()); case '~': tk = lex(); return CExpr_New_EBINNOT_Node(cast_expression()); case '!': tk = lex(); return CExpr_New_ELOGNOT_Node(cast_expression()); case TK_SIZEOF: return CExpr_ParseSizeof(); case TK_UU_ALIGNOF_UU: return CExpr_ParseAlignof(); case TK_LOGICAL_AND: if (copts.ANSIstrict) break; if ((tk = lex()) != TK_IDENTIFIER) { CError_Error(CErrorStr107); return nullnode(); } expr = lalloc(sizeof(ENode)); expr->type = ELABEL; expr->cost = 0; expr->flags = 0; expr->rtype = TYPE(&void_ptr); expr->data.label = findlabel(); if (!expr->data.label) { expr->data.label = newlabel(); expr->data.label->name = tkidentifier; expr->data.label->next = Labels; Labels = expr->data.label; } tk = lex(); return expr; } return postfix_expression(0); } ENode *do_castnullcheck(ENode *condexpr, ENode *nullcheckexpr) { ENode *result; if (isnotzero(nullcheckexpr)) return condexpr; result = lalloc(sizeof(ENode)); *result = *condexpr; result->type = ENULLCHECK; result->data.nullcheck.nullcheckexpr = lalloc(sizeof(ENode)); *result->data.nullcheck.nullcheckexpr = *nullcheckexpr; result->data.nullcheck.condexpr = condexpr; result->data.nullcheck.precompid = CParser_GetUniqueID(); nullcheckexpr->type = EPRECOMP; nullcheckexpr->data.precompid = result->data.nullcheck.precompid; return result; } ENode *CExpr_SafeClassPointerCast(ENode *expr, TypeClass *a, TypeClass *b, Boolean typconflag, Boolean pathcheckflag) { ENode *result; result = CClass_ClassPointerCast(expr, a, b, typconflag, 1, pathcheckflag); if (result != expr) { if (!(ENODE_IS(result, ETYPCON) && result->data.monadic == expr)) result = do_castnullcheck(result, expr); } return result; } ENode *PointerToMemberCast(ENode *expr, TypeMemberPointer *tm1, TypeMemberPointer *tm2, Boolean flag) { BClassList *path; Boolean negate; short depth; Boolean isambig; SInt32 pathoffset; CInt64 pathoffset64; ENode *tmp; CError_ASSERT(3984, IS_TYPE_CLASS(tm1->ty2)); CError_ASSERT(3985, IS_TYPE_CLASS(tm2->ty2)); if (tm1->ty2 == tm2->ty2) { expr->rtype = TYPE(tm2); return expr; } negate = 0; path = CClass_GetBasePath(TYPE_CLASS(tm2->ty2), TYPE_CLASS(tm1->ty2), &depth, &isambig); if (!path) { path = CClass_GetBasePath(TYPE_CLASS(tm1->ty2), TYPE_CLASS(tm2->ty2), &depth, &isambig); if (!path) goto failed; negate = 1; } if (isambig) CError_Error(CErrorStr188); if ((pathoffset = CClass_GetPathOffset(path)) < 0) goto failed; if (negate) pathoffset = -pathoffset; if (flag) CClass_CheckPathAccess(path, NULL, ACCESSPUBLIC); if (tm1->size != tm2->size) { failed: CError_Error(CErrorStr247, tm1, 0, tm2, 0); return nullnode(); } if (!pathoffset) { expr->rtype = TYPE(tm2); return expr; } if (tm1->size == 4u) { if (ENODE_IS(expr, EINTCONST)) { if (!CInt64_IsZero(&expr->data.intval)) { CInt64_SetLong(&pathoffset64, pathoffset); expr->data.intval = CInt64_Add(expr->data.intval, pathoffset64); } expr->rtype = TYPE(tm2); return expr; } else { expr->rtype = TYPE(&stunsignedlong); tmp = intconstnode(TYPE(&stunsignedlong), pathoffset); tmp = makediadicnode(expr, tmp, EADD); tmp = makemonadicnode(tmp, ETYPCON); tmp->rtype = TYPE(tm2); return do_castnullcheck(tmp, expr); } } else { tmp = create_temp_node(TYPE(&ptmstruct)); expr = getnodeaddress(expr, 0); tmp = funccallexpr(rt_ptmf_cast, intconstnode(TYPE(&stsignedlong), pathoffset), expr, tmp, NULL); tmp = makemonadicnode(tmp, EINDIRECT); tmp->rtype = TYPE(tm2); return tmp; } } ENode *CExpr_MemberPointerConversion(ENode *expr, TypeMemberPointer *type, Boolean flag1) { if (ENODE_IS(expr, EINTCONST) && CInt64_IsZero(&expr->data.intval)) { if (IS_TYPE_FUNC(type->ty1)) expr = create_objectnode(rt_ptmf_null); expr->rtype = TYPE(type); } else if (ENODE_IS(expr, EMEMBER)) { expr = getpointertomemberfunc(expr, TYPE(type), flag1); } return expr; } static ENode *CExpr_MemberPointerCast(ENode *expr, TypeMemberPointer *type, UInt32 qual) { if (!IS_TYPE_MEMBERPOINTER(expr->rtype)) expr = CExpr_MemberPointerConversion(expr, type, 1); if (!IS_TYPE_MEMBERPOINTER(expr->rtype)) { CError_Error(CErrorStr164); return nullnode(); } expr = PointerToMemberCast(expr, TYPE_MEMBER_POINTER(expr->rtype), type, 0); expr->flags = qual & ENODE_FLAG_QUALS; return expr; } ENode *do_typecast(ENode *expr, Type *type, UInt32 qual) { TypePointer *tptr; ENode *tmp; short flags; if (!copts.old_argmatch) return CExpr_Convert(expr, type, qual, 1, 0); if (copts.cpp_extensions && is_typesame(expr->rtype, type) && !ENODE_IS(expr, EOBJLIST)) { expr->rtype = type; expr->flags &= ~ENODE_FLAG_QUALS; expr->flags |= qual & ENODE_FLAG_QUALS; return expr; } switch (type->type) { case TYPEARRAY: CError_Error(CErrorStr247, expr->rtype, ENODE_QUALS(expr), type, qual); return expr; case TYPEMEMBERPOINTER: if (!IS_TYPE_CLASS(expr->rtype)) return CExpr_MemberPointerCast(expr, TYPE_MEMBER_POINTER(type), qual); } flags = qual & ENODE_FLAG_QUALS; if (ENODE_IS(expr, EOBJLIST)) return CExpr_AssignmentPromotion(expr, type, qual & ENODE_FLAG_QUALS, 1); if (ENODE_IS(expr, EOBJREF) && IS_TYPE_NONSTATIC_METHOD(expr->data.objref->type)) { CError_Error(CErrorStr221); return nullnode(); } if (type == &stvoid) { expr = makemonadicnode(expr, ETYPCON); expr->rtype = type; expr->flags = flags; return expr; } if (IS_TYPE_REFERENCE(type)) { tmp = getnodeaddress(expr, 0); tptr = galloc(sizeof(TypePointer)); *tptr = *TYPE_POINTER(type); tptr->qual &= ~Q_REFERENCE; tmp = do_typecast(tmp, TYPE(tptr), qual); tmp = makemonadicnode(tmp, EINDIRECT); tmp->rtype = TPTR_TARGET(type); tmp->flags = flags; return tmp; } if (IS_TYPE_CLASS(expr->rtype) || IS_TYPE_CLASS(type)) { if (expr->rtype->size == 0) CDecl_CompleteType(expr->rtype); if (expr->rtype == type && !CClass_CopyConstructor(TYPE_CLASS(type))) return expr; if (user_assign_check(expr, type, qual, 1, 1, 1)) { assign_node->flags = flags; return assign_node; } CError_Error(CErrorStr247, expr->rtype, ENODE_QUALS(expr), type, qual); return nullnode(); } if (IS_TYPE_STRUCT(type) && copts.cplusplus && is_typesame(expr->rtype, type)) { expr->rtype = type; expr->flags = flags; return expr; } if (type == TYPE(&stbool)) { expr = CExpr_ConvertToBool(expr, 1); expr->flags = flags; return expr; } if (IS_TYPE_ENUM(type)) { tmp = do_typecast(expr, TYPE_ENUM(type)->enumtype, qual); if (!ENODE_IS(tmp, EINTCONST)) tmp = makemonadicnode(tmp, ETYPCON); tmp->rtype = type; tmp->flags = flags; return tmp; } if (IS_TYPE_INT_OR_FLOAT(type)) { if (ENODE_IS(expr, ETYPCON) && expr->rtype->type == type->type && expr->rtype->size == type->size) { if (is_unsigned(expr->rtype) == is_unsigned(type) && ENODE_QUALS(expr) == qual) { expr->rtype = type; expr->flags = expr->flags | ENODE_FLAG_80; return expr; } } if (IS_TYPE_ENUM(expr->rtype)) expr = forceintegral(expr); if (IS_TYPE_INT_OR_FLOAT(expr->rtype)) { expr = promote(expr, type); expr->flags = flags; return expr; } if (!(IS_TYPE_POINTER_ONLY(expr->rtype) && !IS_TYPE_FLOAT(type))) CError_Error(CErrorStr247, expr->rtype, ENODE_QUALS(expr), type, qual); if (ENODE_IS(expr, ETYPCON) && ENODE_IS(tmp = expr->data.monadic, EINTCONST)) { tmp->rtype = type; tmp->flags = flags; tmp->data.intval = CExpr_IntConstConvert(type, TYPE(&stunsignedlong), tmp->data.intval); return tmp; } if (type->size != 4) { expr = makemonadicnode(expr, ETYPCON); expr->rtype = TYPE(&stunsignedlong); } expr = makemonadicnode(expr, ETYPCON); expr->rtype = type; expr->flags = flags; return expr; } if (IS_TYPE_POINTER(type)) { if (IS_TYPE_POINTER(expr->rtype)) { if (IS_TYPE_CLASS(TPTR_TARGET(expr->rtype)) && IS_TYPE_CLASS(TPTR_TARGET(type))) expr = CExpr_SafeClassPointerCast(expr, TYPE_CLASS(TPTR_TARGET(expr->rtype)), TYPE_CLASS(TPTR_TARGET(type)), 1, 0); if (!ENODE_IS(expr, ETYPCON)) expr = makemonadicnode(expr, ETYPCON); expr->rtype = type; expr->flags = flags; return expr; } if (!IS_TYPE_INT(expr->rtype)) { if (!IS_TYPE_ENUM(expr->rtype)) { CError_Error(CErrorStr247, expr->rtype, ENODE_QUALS(expr), type, qual); return expr; } expr = forceintegral(expr); } if (expr->rtype->size != 4) { if (!ENODE_IS(expr, EINTCONST)) expr = makemonadicnode(expr, ETYPCON); expr->rtype = TYPE(&stunsignedlong); } expr = makemonadicnode(expr, ETYPCON); expr->rtype = type; expr->flags = flags; return expr; } if ((tmp = CodeGen_HandleTypeCast(expr, type, qual))) return tmp; CError_Error(CErrorStr247, expr->rtype, ENODE_QUALS(expr), type, qual); return nullnode(); } static Boolean isvectorconst(ENode *node) { if (ENODE_IS3(node, ECOMMA, EINTCONST, EFLOATCONST)) return 1; else return 0; } ENode *cast_expression(void) { ENode *expr; ENode *tmp; ENodeList *args; MWVector128 vec; DeclInfo di; if (!(tk == '(' && islookaheaddeclaration())) return unary_expression(); tk = lex(); memclrw(&di, sizeof(DeclInfo)); CParser_GetDeclSpecs(&di, 0); scandeclarator(&di); if (tk != ')') CError_ErrorSkip(CErrorStr115); else tk = lex(); if (di.name) CError_Error(CErrorStr164); if (copts.altivec_model && tk == '(' && IS_TYPE_VECTOR(di.thetype)) { tk = lex(); expr = s_expression(); if (tk != ')') CError_ErrorSkip(CErrorStr115); else tk = lex(); if (CodeGen_CollapseVectorExpression(expr, &vec, di.thetype)) { tmp = lalloc(sizeof(ENode)); tmp->type = EVECTOR128CONST; if ((tmp->cost = expr->cost) == 0) tmp->cost = 1; tmp->flags = ENODE_QUALS(expr); tmp->rtype = di.thetype; tmp->data.vector128val = vec; } else { tmp = makemonadicnode(expr, ETYPCON); } tmp->rtype = di.thetype; tmp->flags = expr->flags; return tmp; } if (tk == '{' && (!copts.ANSIstrict || copts.c9x) && !IS_TYPE_VECTOR(di.thetype)) return CInit_AutoObject(NULL, di.thetype, di.qual); expr = cast_expression(); if (copts.cplusplus && (CTemplTool_IsTemplateArgumentDependentType(di.thetype) || CTemplTool_IsTemplateArgumentDependentExpression(expr))) { args = lalloc(sizeof(ENodeList)); args->next = NULL; args->node = expr; return CExpr_TemplArgDepCast(di.thetype, di.qual, args); } if (!IS_TYPE_REFERENCE(di.thetype)) expr = pointer_generation(expr); return do_typecast(expr, di.thetype, di.qual); } static ENode *pm_expression(void) { ENode *left; ENode *right; ENode *tmp; Type *type; UInt32 qual; short flags; Conversion conv; left = cast_expression(); restart: switch (tk) { case TK_ARROW_STAR: left = pointer_generation(left); tk = lex(); right = pointer_generation(cast_expression()); if (CExpr_CheckOperator(TK_ARROW_STAR, left, right, &conv)) { CError_ASSERT(4457, left = conv.x0); goto restart; } if (!IS_TYPE_POINTER(left->rtype)) { CError_Error(CErrorStr148); return left; } left = makemonadicnode(left, EINDIRECT); left->rtype = TPTR_TARGET(left->rtype); goto common_part; case TK_DOT_STAR: left = pointer_generation(left); tk = lex(); right = pointer_generation(cast_expression()); if (!ENODE_IS(left, EINDIRECT)) { CError_Error(CErrorStr142); return left; } common_part: if (!IS_TYPE_CLASS(left->rtype)) { CError_Error(CErrorStr149); return left; } if (!IS_TYPE_MEMBERPOINTER(right->rtype)) { CError_Error(CErrorStr144); return left; } if (left->rtype != TYPE_MEMBER_POINTER(right->rtype)->ty2) { if (CClass_IsBaseClass(TYPE_CLASS(left->rtype), TYPE_CLASS(TYPE_MEMBER_POINTER(right->rtype)->ty2), NULL, 1, 1)) { left->data.monadic = CClass_ClassPointerCast( left->data.monadic, TYPE_CLASS(left->rtype), TYPE_CLASS(TYPE_MEMBER_POINTER(right->rtype)->ty2), 0, 1, 1); left->rtype = TYPE_MEMBER_POINTER(right->rtype)->ty2; } else { CError_Error(CErrorStr146); return left; } } type = CClass_CombineClassAccessQualifiers( TYPE_MEMBER_POINTER(right->rtype)->ty1, ENODE_QUALS(right), left->flags, &qual); flags = qual; if (!IS_TYPE_FUNC(type)) { if (!ENODE_IS(right, EINTCONST)) { if (!canadd(left->data.monadic, -1)) { left->data.monadic = makediadicnode(left->data.monadic, nullnode(), EADD); CInt64_SetLong(&left->data.monadic->data.diadic.right->data.intval, -1); optimizecomm(left->data.monadic); } right->rtype = TYPE(&stunsignedlong); left->data.monadic = makediadicnode(left->data.monadic, right, EADD); optimizecomm(left->data.monadic); } else { right->data.intval = CInt64_Sub(right->data.intval, cint64_one); if (!canadd2(left->data.monadic, right->data.intval)) { right->rtype = TYPE(&stunsignedlong); left->data.monadic = makediadicnode(left->data.monadic, right, EADD); optimizecomm(left->data.monadic); } } if (IS_TYPE_BITFIELD(type)) { left->data.monadic = makemonadicnode(left->data.monadic, EBITFIELD); left->data.monadic->rtype = type; left->rtype = TYPE_BITFIELD(type)->bitfieldtype; } else { left->rtype = type; } left->flags = flags; left = checkreference(left); goto restart; } else { CError_ASSERT(4535, ENODE_IS(right, EINDIRECT)); tmp = lalloc(sizeof(ENode)); tmp->type = EMFPOINTER; tmp->cost = 4; tmp->flags = 0; tmp->rtype = &stvoid; tmp->data.mfpointer.accessnode = left; tmp->data.mfpointer.mfpointer = right; return tmp; } default: return left; } } ENode *CExpr_New_EMUL_Node(ENode *left, ENode *right) { Conversion conv; if (IS_TYPE_TEMPLDEPEXPR(left->rtype) || IS_TYPE_TEMPLDEPEXPR(right->rtype)) return CTempl_MakeTemplDepExpr(left, EMUL, right); left = pointer_generation(left); right = pointer_generation(right); if (copts.cplusplus && CExpr_CheckOperator('*', left, right, &conv)) { if (conv.x0) return conv.x0; CError_ASSERT(4566, left = conv.left); CError_ASSERT(4567, right = conv.right); } return makemultnode(left, right); } ENode *CExpr_New_EDIV_Node(ENode *left, ENode *right, Boolean no_warning) { Conversion conv; if (IS_TYPE_TEMPLDEPEXPR(left->rtype) || IS_TYPE_TEMPLDEPEXPR(right->rtype)) return CTempl_MakeTemplDepExpr(left, EDIV, right); left = pointer_generation(left); right = pointer_generation(right); if (copts.cplusplus && CExpr_CheckOperator('/', left, right, &conv)) { if (conv.x0) return conv.x0; CError_ASSERT(4592, left = conv.left); CError_ASSERT(4593, right = conv.right); } return makedivnode(left, right, no_warning); } ENode *CExpr_New_EMODULO_Node(ENode *left, ENode *right, Boolean no_warning) { Conversion conv; if (IS_TYPE_TEMPLDEPEXPR(left->rtype) || IS_TYPE_TEMPLDEPEXPR(right->rtype)) return CTempl_MakeTemplDepExpr(left, EMODULO, right); left = pointer_generation(left); right = pointer_generation(right); if (copts.cplusplus && CExpr_CheckOperator('%', left, right, &conv)) { if (conv.x0) return conv.x0; CError_ASSERT(4618, left = conv.left); CError_ASSERT(4619, right = conv.right); } left = integralpromote(left); right = integralpromote(right); CExpr_ArithmeticConversion(&left, &right); if (iszero(right)) { if (!no_warning) CError_Warning(CErrorStr139); return left; } if (ENODE_IS(left, EINTCONST) && ENODE_IS(right, EINTCONST)) { left->data.intval = CMach_CalcIntDiadic(left->rtype, left->data.intval, '%', right->data.intval); return left; } if (iszero(left)) return makediadicnode(right, left, ECOMMA); if (CExpr_IsOne(right)) { right = nullnode(); right->rtype = left->rtype; return makediadicnode(left, right, ECOMMA); } return makediadicnode(left, right, EMODULO); } ENode *CExpr_New_EADD_Node(ENode *left, ENode *right) { Conversion conv; if (IS_TYPE_TEMPLDEPEXPR(left->rtype) || IS_TYPE_TEMPLDEPEXPR(right->rtype)) return CTempl_MakeTemplDepExpr(left, EADD, right); left = pointer_generation(left); right = pointer_generation(right); if (copts.cplusplus && CExpr_CheckOperator('+', left, right, &conv)) { if (conv.x0) return conv.x0; CError_ASSERT(4665, left = conv.left); CError_ASSERT(4666, right = conv.right); } return makeaddnode(left, right); } ENode *CExpr_New_ESUB_Node(ENode *left, ENode *right) { Conversion conv; if (IS_TYPE_TEMPLDEPEXPR(left->rtype) || IS_TYPE_TEMPLDEPEXPR(right->rtype)) return CTempl_MakeTemplDepExpr(left, ESUB, right); left = pointer_generation(left); right = pointer_generation(right); if (copts.cplusplus && CExpr_CheckOperator('-', left, right, &conv)) { if (conv.x0) return conv.x0; CError_ASSERT(4690, left = conv.left); CError_ASSERT(4691, right = conv.right); } return makesubnode(left, right); } ENode *CExpr_New_ESHL_Node(ENode *left, ENode *right) { Conversion conv; if (IS_TYPE_TEMPLDEPEXPR(left->rtype) || IS_TYPE_TEMPLDEPEXPR(right->rtype)) return CTempl_MakeTemplDepExpr(left, ESHL, right); left = pointer_generation(left); right = pointer_generation(right); if (copts.cplusplus && CExpr_CheckOperator(TK_SHL, left, right, &conv)) { if (conv.x0) return conv.x0; CError_ASSERT(4715, left = conv.left); CError_ASSERT(4716, right = conv.right); } left = integralpromote(left); right = integralpromote(right); if (iszero(left) || iszero(right)) { return left; } if (ENODE_IS(left, EINTCONST) && ENODE_IS(right, EINTCONST)) { left->data.intval = CMach_CalcIntDiadic(left->rtype, left->data.intval, TK_SHL, right->data.intval); return left; } return makediadicnode(left, right, ESHL); } ENode *CExpr_New_ESHR_Node(ENode *left, ENode *right) { Conversion conv; if (IS_TYPE_TEMPLDEPEXPR(left->rtype) || IS_TYPE_TEMPLDEPEXPR(right->rtype)) return CTempl_MakeTemplDepExpr(left, ESHR, right); left = pointer_generation(left); right = pointer_generation(right); if (copts.cplusplus && CExpr_CheckOperator(TK_SHR, left, right, &conv)) { if (conv.x0) return conv.x0; CError_ASSERT(4752, left = conv.left); CError_ASSERT(4753, right = conv.right); } left = integralpromote(left); right = integralpromote(right); if (iszero(left) || iszero(right)) { return left; } if (ENODE_IS(left, EINTCONST) && ENODE_IS(right, EINTCONST)) { left->data.intval = CMach_CalcIntDiadic(left->rtype, left->data.intval, TK_SHR, right->data.intval); return left; } return makediadicnode(left, right, ESHR); } static ENode *pointercompare(ENodeType nt, ENode *left, ENode *right) { Type *ltype; Type *rtype; ltype = left->rtype; rtype = right->rtype; if (IS_TYPE_POINTER_ONLY(ltype) && IS_TYPE_POINTER_ONLY(rtype)) { ltype = TPTR_TARGET(left->rtype); rtype = TPTR_TARGET(right->rtype); if (IS_TYPE_CLASS(ltype) && IS_TYPE_CLASS(rtype)) { if (ltype != rtype) { if (ltype == TPTR_TARGET(left->rtype)) { if (CClass_IsBaseClass(TYPE_CLASS(ltype), TYPE_CLASS(rtype), NULL, 0, 1)) { left = CExpr_SafeClassPointerCast(left, TYPE_CLASS(ltype), TYPE_CLASS(rtype), 0, 1); } else if (CClass_IsBaseClass(TYPE_CLASS(rtype), TYPE_CLASS(ltype), NULL, 0, 1)) { right = CExpr_SafeClassPointerCast(right, TYPE_CLASS(rtype), TYPE_CLASS(ltype), 0, 1); } else { CError_Error(CErrorStr245, left->rtype, ENODE_QUALS(left), right->rtype, ENODE_QUALS(right)); } } else { CError_Error(CErrorStr245, left->rtype, ENODE_QUALS(left), right->rtype, ENODE_QUALS(right)); } } } else if (!is_typeequal(left->rtype, right->rtype)) { if (!copts.objective_c || !CObjC_IsCompatibleType(left->rtype, right->rtype)) { CError_Error(CErrorStr245, left->rtype, ENODE_QUALS(left), right->rtype, ENODE_QUALS(right)); } } } else if (nt == EEQU || nt == ENOTEQU) { if (IS_TYPE_INT(ltype)) { if (!(ENODE_IS(left, EINTCONST) && CInt64_IsZero(&left->data.intval))) CError_Error(CErrorStr144); CError_ASSERT(4847, IS_TYPE_POINTER_ONLY(rtype)); left->rtype = TYPE(&stunsignedlong); } else if (IS_TYPE_INT(rtype)) { if (!(ENODE_IS(right, EINTCONST) && CInt64_IsZero(&right->data.intval))) CError_Error(CErrorStr144); CError_ASSERT(4855, IS_TYPE_POINTER_ONLY(ltype)); right->rtype = TYPE(&stunsignedlong); } else if (!is_typeequal(ltype, rtype)) { CError_Error(CErrorStr245, left->rtype, ENODE_QUALS(left), right->rtype, ENODE_QUALS(right)); } } else { if (!is_typeequal(ltype, rtype)) CError_Error(CErrorStr245, left->rtype, ENODE_QUALS(left), right->rtype, ENODE_QUALS(right)); } return logicalexpression(makediadicnode(left, right, nt)); } static ENode *unsigncheck(ENode *expr, Boolean flag1, Boolean flag2) { if (is_unsigned(expr->data.diadic.left->rtype)) { if (ENODE_IS(expr->data.diadic.left, EINTCONST) && CInt64_IsZero(&expr->data.diadic.left->data.intval)) { flag1 = !flag1; } else if (!(ENODE_IS(expr->data.diadic.right, EINTCONST) && CInt64_IsZero(&expr->data.diadic.right->data.intval))) { return logicalexpression(expr); } if (flag1 && flag2) { expr->type = EEQU; return logicalexpression(expr); } if (!flag1 && !flag2) { expr->type = ENOTEQU; return logicalexpression(expr); } return CExpr_ConstResult(logicalexpression(expr), !flag1); } return logicalexpression(expr); } ENode *CExpr_New_ELESS_Node(ENode *left, ENode *right) { Conversion conv; if (IS_TYPE_TEMPLDEPEXPR(left->rtype) || IS_TYPE_TEMPLDEPEXPR(right->rtype)) return CTempl_MakeTemplDepExpr(left, ELESS, right); left = pointer_generation(left); right = pointer_generation(right); if (copts.cplusplus && CExpr_CheckOperator('<', left, right, &conv)) { if (conv.x0) return conv.x0; CError_ASSERT(4929, left = conv.left); CError_ASSERT(4930, right = conv.right); } if (IS_TYPE_POINTER(left->rtype) || IS_TYPE_POINTER(right->rtype)) return pointercompare(ELESS, left, right); CExpr_CompareConvert(&left, "<", &right, 0); if (ENODE_IS(left, EINTCONST) && ENODE_IS(right, EINTCONST)) { left->data.intval = CMach_CalcIntDiadic(left->rtype, left->data.intval, '<', right->data.intval); left->rtype = CParser_GetBoolType(); } else if (ENODE_IS(left, EFLOATCONST) && ENODE_IS(right, EFLOATCONST)) { CInt64_SetLong(&left->data.intval, CMach_CalcFloatDiadicBool(left->rtype, left->data.floatval, '<', right->data.floatval)); left->type = EINTCONST; left->rtype = CParser_GetBoolType(); } else { left = unsigncheck(makediadicnode(left, right, ELESS), 1, 0); } return left; } ENode *CExpr_New_ELESSEQU_Node(ENode *left, ENode *right) { Conversion conv; if (IS_TYPE_TEMPLDEPEXPR(left->rtype) || IS_TYPE_TEMPLDEPEXPR(right->rtype)) return CTempl_MakeTemplDepExpr(left, ELESSEQU, right); left = pointer_generation(left); right = pointer_generation(right); if (copts.cplusplus && CExpr_CheckOperator(TK_LESS_EQUAL, left, right, &conv)) { if (conv.x0) return conv.x0; CError_ASSERT(4976, left = conv.left); CError_ASSERT(4977, right = conv.right); } if (IS_TYPE_POINTER(left->rtype) || IS_TYPE_POINTER(right->rtype)) return pointercompare(ELESSEQU, left, right); CExpr_CompareConvert(&left, "<=", &right, 0); if (ENODE_IS(left, EINTCONST) && ENODE_IS(right, EINTCONST)) { left->data.intval = CMach_CalcIntDiadic(left->rtype, left->data.intval, TK_LESS_EQUAL, right->data.intval); left->rtype = CParser_GetBoolType(); } else if (ENODE_IS(left, EFLOATCONST) && ENODE_IS(right, EFLOATCONST)) { CInt64_SetLong(&left->data.intval, CMach_CalcFloatDiadicBool(left->rtype, left->data.floatval, TK_LESS_EQUAL, right->data.floatval)); left->type = EINTCONST; left->rtype = CParser_GetBoolType(); } else { left = unsigncheck(makediadicnode(left, right, ELESSEQU), 1, 1); } return left; } ENode *CExpr_New_EGREATER_Node(ENode *left, ENode *right) { Conversion conv; if (IS_TYPE_TEMPLDEPEXPR(left->rtype) || IS_TYPE_TEMPLDEPEXPR(right->rtype)) return CTempl_MakeTemplDepExpr(left, EGREATER, right); left = pointer_generation(left); right = pointer_generation(right); if (copts.cplusplus && CExpr_CheckOperator('>', left, right, &conv)) { if (conv.x0) return conv.x0; CError_ASSERT(5023, left = conv.left); CError_ASSERT(5024, right = conv.right); } if (IS_TYPE_POINTER(left->rtype) || IS_TYPE_POINTER(right->rtype)) return pointercompare(EGREATER, left, right); CExpr_CompareConvert(&left, ">", &right, 0); if (ENODE_IS(left, EINTCONST) && ENODE_IS(right, EINTCONST)) { left->data.intval = CMach_CalcIntDiadic(left->rtype, left->data.intval, '>', right->data.intval); left->rtype = CParser_GetBoolType(); } else if (ENODE_IS(left, EFLOATCONST) && ENODE_IS(right, EFLOATCONST)) { CInt64_SetLong(&left->data.intval, CMach_CalcFloatDiadicBool(left->rtype, left->data.floatval, '>', right->data.floatval)); left->type = EINTCONST; left->rtype = CParser_GetBoolType(); } else { left = unsigncheck(makediadicnode(left, right, EGREATER), 0, 0); } return left; } ENode *CExpr_New_EGREATEREQU_Node(ENode *left, ENode *right) { Conversion conv; if (IS_TYPE_TEMPLDEPEXPR(left->rtype) || IS_TYPE_TEMPLDEPEXPR(right->rtype)) return CTempl_MakeTemplDepExpr(left, EGREATEREQU, right); left = pointer_generation(left); right = pointer_generation(right); if (copts.cplusplus && CExpr_CheckOperator(TK_GREATER_EQUAL, left, right, &conv)) { if (conv.x0) return conv.x0; CError_ASSERT(5070, left = conv.left); CError_ASSERT(5071, right = conv.right); } if (IS_TYPE_POINTER(left->rtype) || IS_TYPE_POINTER(right->rtype)) return pointercompare(EGREATEREQU, left, right); CExpr_CompareConvert(&left, ">=", &right, 0); if (ENODE_IS(left, EINTCONST) && ENODE_IS(right, EINTCONST)) { left->data.intval = CMach_CalcIntDiadic(left->rtype, left->data.intval, TK_GREATER_EQUAL, right->data.intval); left->rtype = CParser_GetBoolType(); } else if (ENODE_IS(left, EFLOATCONST) && ENODE_IS(right, EFLOATCONST)) { CInt64_SetLong(&left->data.intval, CMach_CalcFloatDiadicBool(left->rtype, left->data.floatval, TK_GREATER_EQUAL, right->data.floatval)); left->type = EINTCONST; left->rtype = CParser_GetBoolType(); } else { left = unsigncheck(makediadicnode(left, right, EGREATEREQU), 0, 1); } return left; } ENode *memberpointercompare(ENodeType nt, ENode *left, ENode *right) { Object *func; ENodeList *arg; if (!IS_TYPE_MEMBERPOINTER(left->rtype)) { if (!(IS_TYPE_INT(left->rtype) && ENODE_IS(left, EINTCONST) && CInt64_IsZero(&left->data.intval))) { CError_Error(CErrorStr144); return nullnode(); } } else if (!IS_TYPE_MEMBERPOINTER(right->rtype)) { if (!(IS_TYPE_INT(right->rtype) && ENODE_IS(right, EINTCONST) && CInt64_IsZero(&right->data.intval))) { CError_Error(CErrorStr144); return nullnode(); } } else if (!is_typeequal(left->rtype, right->rtype)) { left = PointerToMemberCast(left, TYPE_MEMBER_POINTER(left->rtype), TYPE_MEMBER_POINTER(right->rtype), 1); } if ((ENODE_IS(left, EINTCONST) || !IS_TYPE_FUNC(TYPE_MEMBER_POINTER(left->rtype)->ty1)) && (ENODE_IS(right, EINTCONST) || !IS_TYPE_FUNC(TYPE_MEMBER_POINTER(right->rtype)->ty1))) { left->rtype = TYPE(&stunsignedlong); right->rtype = TYPE(&stunsignedlong); return logicalexpression(makediadicnode(left, right, nt)); } arg = lalloc(sizeof(ENodeList)); if (ENODE_IS(left, EINTCONST) || ENODE_IS(right, EINTCONST)) { func = rt_ptmf_test; if (ENODE_IS(left, EINTCONST)) arg->node = getnodeaddress(right, 0); else arg->node = getnodeaddress(left, 0); arg->next = NULL; } else { func = rt_ptmf_cmpr; arg->next = lalloc(sizeof(ENodeList)); arg->node = getnodeaddress(left, 0); arg->next->node = getnodeaddress(right, 0); arg->next->next = NULL; } left = lalloc(sizeof(ENode)); left->type = EFUNCCALL; left->rtype = TYPE(&stsignedlong); left->cost = 4; left->data.funccall.funcref = create_objectrefnode(func); left->data.funccall.args = arg; left->data.funccall.functype = TYPE_FUNC(func->type); left->flags = TYPE_FUNC(func->type)->qual & ENODE_FLAG_QUALS; if (nt == EEQU) left = makemonadicnode(left, ELOGNOT); return left; } ENode *CExpr_New_EEQU_Node(ENode *left, ENode *right) { Conversion conv; if (IS_TYPE_TEMPLDEPEXPR(left->rtype) || IS_TYPE_TEMPLDEPEXPR(right->rtype)) return CTempl_MakeTemplDepExpr(left, EEQU, right); left = pointer_generation(left); right = pointer_generation(right); if (copts.cplusplus && CExpr_CheckOperator(TK_LOGICAL_EQ, left, right, &conv)) { if (conv.x0) return conv.x0; CError_ASSERT(5201, left = conv.left); CError_ASSERT(5202, right = conv.right); } if (IS_TYPE_POINTER(left->rtype) || IS_TYPE_POINTER(right->rtype)) return pointercompare(EEQU, left, right); if (IS_TYPE_MEMBERPOINTER(left->rtype) || IS_TYPE_MEMBERPOINTER(right->rtype)) return memberpointercompare(EEQU, left, right); CExpr_CompareConvert(&left, "==", &right, 1); if (ENODE_IS(left, EINTCONST) && ENODE_IS(right, EINTCONST)) { left->data.intval = CMach_CalcIntDiadic(left->rtype, left->data.intval, TK_LOGICAL_EQ, right->data.intval); left->rtype = CParser_GetBoolType(); } else if (ENODE_IS(left, EFLOATCONST) && ENODE_IS(right, EFLOATCONST)) { left->type = EINTCONST; CInt64_SetLong(&left->data.intval, CMach_CalcFloatDiadicBool(left->rtype, left->data.floatval, TK_LOGICAL_EQ, right->data.floatval)); left->type = EINTCONST; left->rtype = CParser_GetBoolType(); } else { left = makediadicnode(left, right, EEQU); optimizecomm(left); } return logicalexpression(left); } ENode *CExpr_New_ENOTEQU_Node(ENode *left, ENode *right) { Conversion conv; if (IS_TYPE_TEMPLDEPEXPR(left->rtype) || IS_TYPE_TEMPLDEPEXPR(right->rtype)) return CTempl_MakeTemplDepExpr(left, ENOTEQU, right); left = pointer_generation(left); right = pointer_generation(right); if (copts.cplusplus && CExpr_CheckOperator(TK_LOGICAL_NE, left, right, &conv)) { if (conv.x0) return conv.x0; CError_ASSERT(5261, left = conv.left); CError_ASSERT(5262, right = conv.right); } if (IS_TYPE_POINTER(left->rtype) || IS_TYPE_POINTER(right->rtype)) return pointercompare(ENOTEQU, left, right); if (IS_TYPE_MEMBERPOINTER(left->rtype) || IS_TYPE_MEMBERPOINTER(right->rtype)) return memberpointercompare(ENOTEQU, left, right); CExpr_CompareConvert(&left, "!=", &right, 1); if (ENODE_IS(left, EINTCONST) && ENODE_IS(right, EINTCONST)) { left->data.intval = CMach_CalcIntDiadic(left->rtype, left->data.intval, TK_LOGICAL_NE, right->data.intval); left->rtype = CParser_GetBoolType(); } else if (ENODE_IS(left, EFLOATCONST) && ENODE_IS(right, EFLOATCONST)) { CInt64_SetLong(&left->data.intval, CMach_CalcFloatDiadicBool(left->rtype, left->data.floatval, TK_LOGICAL_NE, right->data.floatval)); left->type = EINTCONST; left->rtype = CParser_GetBoolType(); } else { left = makediadicnode(left, right, ENOTEQU); optimizecomm(left); } return logicalexpression(left); } ENode *CExpr_New_EAND_Node(ENode *left, ENode *right) { Conversion conv; if (IS_TYPE_TEMPLDEPEXPR(left->rtype) || IS_TYPE_TEMPLDEPEXPR(right->rtype)) return CTempl_MakeTemplDepExpr(left, EAND, right); left = pointer_generation(left); right = pointer_generation(right); if (copts.cplusplus && CExpr_CheckOperator('&', left, right, &conv)) { if (conv.x0) return conv.x0; CError_ASSERT(5321, left = conv.left); CError_ASSERT(5322, right = conv.right); } left = integralpromote(left); right = integralpromote(right); CExpr_ArithmeticConversion(&left, &right); if (iszero(left) || CExpr_AllBitsSet(right)) return left; if (iszero(right) || CExpr_AllBitsSet(left)) return right; if (ENODE_IS(left, EINTCONST) && ENODE_IS(right, EINTCONST)) { left->data.intval = CMach_CalcIntDiadic(left->rtype, left->data.intval, '&', right->data.intval); return left; } left = makediadicnode(left, right, EAND); optimizecomm(left); return left; } ENode *CExpr_New_EXOR_Node(ENode *left, ENode *right) { Conversion conv; if (IS_TYPE_TEMPLDEPEXPR(left->rtype) || IS_TYPE_TEMPLDEPEXPR(right->rtype)) return CTempl_MakeTemplDepExpr(left, EXOR, right); left = pointer_generation(left); right = pointer_generation(right); if (copts.cplusplus && CExpr_CheckOperator('^', left, right, &conv)) { if (conv.x0) return conv.x0; CError_ASSERT(5360, left = conv.left); CError_ASSERT(5361, right = conv.right); } left = integralpromote(left); right = integralpromote(right); CExpr_ArithmeticConversion(&left, &right); if (iszero(right)) return left; if (iszero(left)) return right; if (ENODE_IS(left, EINTCONST) && ENODE_IS(right, EINTCONST)) { left->data.intval = CMach_CalcIntDiadic(left->rtype, left->data.intval, '^', right->data.intval); return left; } left = makediadicnode(left, right, EXOR); optimizecomm(left); return left; } ENode *CExpr_New_EOR_Node(ENode *left, ENode *right) { Conversion conv; if (IS_TYPE_TEMPLDEPEXPR(left->rtype) || IS_TYPE_TEMPLDEPEXPR(right->rtype)) return CTempl_MakeTemplDepExpr(left, EOR, right); left = pointer_generation(left); right = pointer_generation(right); if (copts.cplusplus && CExpr_CheckOperator('|', left, right, &conv)) { if (conv.x0) return conv.x0; CError_ASSERT(5399, left = conv.left); CError_ASSERT(5400, right = conv.right); } left = integralpromote(left); right = integralpromote(right); CExpr_ArithmeticConversion(&left, &right); if (iszero(right) || CExpr_AllBitsSet(left)) return left; if (iszero(left) || CExpr_AllBitsSet(right)) return right; if (ENODE_IS(left, EINTCONST) && ENODE_IS(right, EINTCONST)) { left->data.intval = CMach_CalcIntDiadic(left->rtype, left->data.intval, '|', right->data.intval); return left; } left = makediadicnode(left, right, EOR); optimizecomm(left); return left; } ENode *CExpr_New_ELAND_Node(ENode *left, ENode *right) { Conversion conv; if (IS_TYPE_TEMPLDEPEXPR(left->rtype) || IS_TYPE_TEMPLDEPEXPR(right->rtype)) return CTempl_MakeTemplDepExpr(left, ELAND, right); left = pointer_generation(left); right = pointer_generation(right); if (copts.cplusplus && CExpr_CheckOperator(TK_LOGICAL_AND, left, right, &conv)) { if (conv.x0) return conv.x0; CError_ASSERT(5438, left = conv.left); CError_ASSERT(5439, right = conv.right); } switch (left->rtype->type) { case TYPEINT: case TYPEFLOAT: case TYPEPOINTER: case TYPEARRAY: break; case TYPEENUM: case TYPEMEMBERPOINTER: left = CExpr_ConvertToCondition(left); break; default: CError_Error(CErrorStr144); left = nullnode(); } switch (right->rtype->type) { case TYPEINT: case TYPEFLOAT: case TYPEPOINTER: case TYPEARRAY: break; case TYPEENUM: case TYPEMEMBERPOINTER: right = CExpr_ConvertToCondition(right); break; default: CError_Error(CErrorStr144); right = nullnode(); } if (iszero(left)) { left->type = EINTCONST; left->rtype = CParser_GetBoolType(); CInt64_SetLong(&left->data.intval, 0); return left; } if (isnotzero(left)) { if (iszero(right)) { left->type = EINTCONST; left->rtype = CParser_GetBoolType(); CInt64_SetLong(&left->data.intval, 0); return left; } else if (isnotzero(right)) { left->type = EINTCONST; left->rtype = CParser_GetBoolType(); CInt64_SetLong(&left->data.intval, 1); return left; } else { left = makemonadicnode(right, ELOGNOT); left->rtype = CParser_GetBoolType(); return makemonadicnode(left, ELOGNOT); } } else { if (isnotzero(right)) { left = makemonadicnode(left, ELOGNOT); left->rtype = CParser_GetBoolType(); return makemonadicnode(left, ELOGNOT); } else if (iszero(right)) { right->type = EINTCONST; right->rtype = CParser_GetBoolType(); CInt64_SetLong(&right->data.intval, 0); return makecommaexpression(left, right); } else { left = makediadicnode(left, right, ELAND); left->rtype = CParser_GetBoolType(); return left; } } } ENode *CExpr_New_ELOR_Node(ENode *left, ENode *right) { Conversion conv; if (IS_TYPE_TEMPLDEPEXPR(left->rtype) || IS_TYPE_TEMPLDEPEXPR(right->rtype)) return CTempl_MakeTemplDepExpr(left, ELOR, right); left = pointer_generation(left); right = pointer_generation(right); if (copts.cplusplus && CExpr_CheckOperator(TK_LOGICAL_OR, left, right, &conv)) { if (conv.x0) return conv.x0; CError_ASSERT(5543, left = conv.left); CError_ASSERT(5544, right = conv.right); } switch (left->rtype->type) { case TYPEINT: case TYPEFLOAT: case TYPEPOINTER: case TYPEARRAY: break; case TYPEENUM: case TYPEMEMBERPOINTER: left = CExpr_ConvertToCondition(left); break; default: CError_Error(CErrorStr144); left = nullnode(); } switch (right->rtype->type) { case TYPEINT: case TYPEFLOAT: case TYPEPOINTER: case TYPEARRAY: break; case TYPEENUM: case TYPEMEMBERPOINTER: right = CExpr_ConvertToCondition(right); break; default: CError_Error(CErrorStr144); right = nullnode(); } if (isnotzero(left)) { left->type = EINTCONST; left->rtype = CParser_GetBoolType(); CInt64_SetLong(&left->data.intval, 1); return left; } if (iszero(left)) { if (iszero(right)) { left->type = EINTCONST; left->rtype = CParser_GetBoolType(); CInt64_SetLong(&left->data.intval, 0); return left; } else if (isnotzero(right)) { left->type = EINTCONST; left->rtype = CParser_GetBoolType(); CInt64_SetLong(&left->data.intval, 1); return left; } else { left = makemonadicnode(right, ELOGNOT); left->rtype = CParser_GetBoolType(); return makemonadicnode(left, ELOGNOT); } } else { if (isnotzero(right)) { right->type = EINTCONST; right->rtype = CParser_GetBoolType(); CInt64_SetLong(&right->data.intval, 1); } else if (iszero(right)) { left = makemonadicnode(left, ELOGNOT); left->rtype = CParser_GetBoolType(); return makemonadicnode(left, ELOGNOT); } left = makediadicnode(left, right, ELOR); left->rtype = CParser_GetBoolType(); return left; } } ENode *CExpr_NewDyadicNode(ENode *left, ENodeType nt, ENode *right) { switch (nt) { default: CError_FATAL(5642); case EADD: return CExpr_New_EADD_Node(left, right); case ESUB: return CExpr_New_ESUB_Node(left, right); case EMUL: return CExpr_New_EMUL_Node(left, right); case EDIV: return CExpr_New_EDIV_Node(left, right, 1); case EMODULO: return CExpr_New_EMODULO_Node(left, right, 1); case EAND: return CExpr_New_EAND_Node(left, right); case EXOR: return CExpr_New_EXOR_Node(left, right); case EOR: return CExpr_New_EOR_Node(left, right); case ESHL: return CExpr_New_ESHL_Node(left, right); case ESHR: return CExpr_New_ESHR_Node(left, right); case ELESS: return CExpr_New_ELESS_Node(left, right); case EGREATER: return CExpr_New_EGREATER_Node(left, right); case ELESSEQU: return CExpr_New_ELESSEQU_Node(left, right); case EGREATEREQU: return CExpr_New_EGREATEREQU_Node(left, right); case EEQU: return CExpr_New_EEQU_Node(left, right); case ENOTEQU: return CExpr_New_ENOTEQU_Node(left, right); case ELAND: return CExpr_New_ELAND_Node(left, right); case ELOR: return CExpr_New_ELOR_Node(left, right); } } typedef struct DyadicInfo { ENodeType t; UInt8 prec; } DyadicInfo; static Boolean CExpr_GetDyadicInfo(short token, DyadicInfo *info) { switch (token) { case '*': info->t = EMUL; info->prec = 20; return 1; case '/': info->t = EDIV; info->prec = 20; return 1; case '%': info->t = EMODULO; info->prec = 20; return 1; case '+': info->t = EADD; info->prec = 19; return 1; case '-': info->t = ESUB; info->prec = 19; return 1; case TK_SHL: info->t = ESHL; info->prec = 18; return 1; case TK_SHR: info->t = ESHR; info->prec = 18; return 1; case '<': info->t = ELESS; info->prec = 17; return 1; case TK_LESS_EQUAL: info->t = ELESSEQU; info->prec = 17; return 1; case '>': if (disallowgreaterthan) return 0; info->t = EGREATER; info->prec = 17; return 1; case TK_GREATER_EQUAL: info->t = EGREATEREQU; info->prec = 17; return 1; case TK_LOGICAL_EQ: info->t = EEQU; info->prec = 16; return 1; case TK_LOGICAL_NE: info->t = ENOTEQU; info->prec = 16; return 1; case '&': info->t = EAND; info->prec = 15; return 1; case '^': info->t = EXOR; info->prec = 14; return 1; case '|': info->t = EOR; info->prec = 13; return 1; case TK_LOGICAL_AND: info->t = ELAND; info->prec = 12; return 1; case TK_LOGICAL_OR: info->t = ELOR; info->prec = 11; return 1; default: return 0; } } static ENode *CExpr_ParseDyadicExpression(ENode *left, UInt8 prec, Boolean no_warning) { ENode *right; Boolean is_eland_or_elor; Boolean save_dgt; Boolean cont; DyadicInfo left_info; DyadicInfo right_info; save_dgt = disallowgreaterthan; if (!left) { disallowgreaterthan = 0; left = pm_expression(); disallowgreaterthan = save_dgt; } do { if (!CExpr_GetDyadicInfo(tk, &left_info)) return left; switch (left_info.t) { case ELAND: CExpr_CheckUnwantedAssignment(left); if (iszero(left)) no_warning = 1; is_eland_or_elor = 1; break; case ELOR: CExpr_CheckUnwantedAssignment(left); if (isnotzero(left)) no_warning = 1; is_eland_or_elor = 1; break; default: is_eland_or_elor = 0; } tk = lex(); disallowgreaterthan = 0; right = pm_expression(); disallowgreaterthan = save_dgt; inner_loop: if (CExpr_GetDyadicInfo(tk, &right_info)) { if (left_info.prec >= right_info.prec) { cont = (prec >= right_info.prec); } else { right = CExpr_ParseDyadicExpression(right, left_info.prec, no_warning); goto inner_loop; } } else { cont = 1; } if (is_eland_or_elor) CExpr_CheckUnwantedAssignment(right); switch (left_info.t) { case EDIV: left = CExpr_New_EDIV_Node(left, right, no_warning); break; case EMODULO: left = CExpr_New_EMODULO_Node(left, right, no_warning); break; default: left = CExpr_NewDyadicNode(left, left_info.t, right); } } while (!cont); return left; } static Boolean CExpr_IsBlockMoveType(Type *type) { switch (type->type) { case TYPESTRUCT: case TYPECLASS: return 1; case TYPEMEMBERPOINTER: return type->size != 4; default: return 0; } } ENode *CExpr_New_ECOND_Node(ENode *cond, ENode *expr1, ENode *expr2) { ENode *result; ENodeList *args; short cost; Conversion conv; cond = CExpr_ConvertToCondition(pointer_generation(cond)); expr1 = pointer_generation(expr1); expr2 = pointer_generation(expr2); if (!IS_TYPE_INT_OR_FLOAT(cond->rtype) && !IS_TYPE_POINTER_ONLY(cond->rtype)) { CError_Error(CErrorStr144); return nullnode(); } cost = cond->cost + 1; if (expr1->cost > expr2->cost) cost += expr1->cost; else cost += expr2->cost; if (expr2->cost > cost) cost = expr2->cost; if (cost > 200) cost = 200; result = CExpr_NewENode(ECOND); result->cost = cost; result->rtype = expr1->rtype; result->flags = expr1->flags | expr2->flags; result->data.cond.cond = cond; if (ENODE_IS(expr1, EFUNCCALL) && expr1->rtype == &stvoid && (expr1->flags & ENODE_FLAG_VOLATILE) != 0) { result->rtype = expr2->rtype; result->flags = expr2->flags; result->data.cond.expr1 = expr1; result->data.cond.expr2 = expr2; return result; } if (ENODE_IS(expr2, EFUNCCALL) && expr2->rtype == &stvoid && (expr2->flags & ENODE_FLAG_VOLATILE) != 0) { result->rtype = expr1->rtype; result->flags = expr1->flags; result->data.cond.expr1 = expr1; result->data.cond.expr2 = expr2; return result; } if ( ENODE_IS(expr1, EINDIRECT) && ENODE_IS(expr2, EINDIRECT) && is_typesame(expr1->rtype, expr2->rtype) && ENODE_QUALS(expr1) == ENODE_QUALS(expr2) && CExpr_IsBlockMoveType(expr1->rtype) && !ENODE_IS(expr1->data.monadic, EBITFIELD) && !ENODE_IS(expr2->data.monadic, EBITFIELD) ) { if (isnotzero(cond)) return expr1; if (iszero(cond)) return expr2; result->data.cond.expr1 = getnodeaddress(expr1, 0); result->data.cond.expr2 = getnodeaddress(expr2, 0); result->rtype = result->data.cond.expr1->rtype; result = makemonadicnode(result, EINDIRECT); result->rtype = TPTR_TARGET(result->rtype); return result; } if ((IS_TYPE_CLASS(expr1->rtype) || IS_TYPE_CLASS(expr2->rtype)) && !is_typesame(expr1->rtype, expr2->rtype)) { if (!copts.old_argmatch) { if (CExpr_CondOperatorMatch(expr1, expr2, &conv)) { CError_ASSERT(6246, !conv.x0); expr1 = conv.left; expr2 = conv.right; } else if (CExpr_CanImplicitlyConvert(expr1, expr2->rtype, ENODE_QUALS(expr2))) { if (CExpr_CanImplicitlyConvert(expr2, expr1->rtype, ENODE_QUALS(expr1))) CError_Error(CErrorStr188); expr1 = CExpr_Convert(expr1, expr2->rtype, ENODE_QUALS(expr2), 0, 1); } else if (CExpr_CanImplicitlyConvert(expr2, expr1->rtype, ENODE_QUALS(expr1))) { expr2 = CExpr_Convert(expr2, expr1->rtype, ENODE_QUALS(expr1), 0, 1); } else { goto failed; } result->rtype = expr1->rtype; } else { args = lalloc(sizeof(ENodeList)); args->node = expr1; args->next = lalloc(sizeof(ENodeList)); args->next->node = expr2; args->next->next = NULL; if (CExpr_CheckOperatorConversion(':', expr1, expr2, args, &conv)) { CError_ASSERT(6274, !conv.x0); expr1 = conv.left; expr2 = conv.right; } result->rtype = expr1->rtype; } } switch (expr1->rtype->type) { case TYPEENUM: if (expr1->rtype == expr2->rtype) break; expr1 = forceintegral(expr1); case TYPEINT: if (IS_TYPE_POINTER_ONLY(expr2->rtype) || IS_TYPE_MEMBERPOINTER(expr2->rtype)) { expr1 = CExpr_Convert(expr1, expr2->rtype, ENODE_QUALS(expr2), 0, 1); result->rtype = expr2->rtype; break; } case TYPEFLOAT: if (expr1->rtype != expr2->rtype) { CExpr_ArithmeticConversion(&expr1, &expr2); result->rtype = expr1->rtype; } break; case TYPEPOINTER: if (ENODE_IS(expr2, EINTCONST) && CInt64_IsZero(&expr2->data.intval)) { expr2->rtype = TYPE(&stunsignedlong); break; } if (IS_TYPE_POINTER_ONLY(expr2->rtype)) { if (IS_TYPE_CLASS(TPTR_TARGET(expr1->rtype)) && IS_TYPE_CLASS(TPTR_TARGET(expr2->rtype))) { if (TPTR_TARGET(expr1->rtype) != TPTR_TARGET(expr2->rtype)) { if (CClass_IsBaseClass(TYPE_CLASS(TPTR_TARGET(expr1->rtype)), TYPE_CLASS(TPTR_TARGET(expr2->rtype)), NULL, 0, 1)) { expr1 = CExpr_SafeClassPointerCast( expr1, TYPE_CLASS(TPTR_TARGET(expr1->rtype)), TYPE_CLASS(TPTR_TARGET(expr2->rtype)), 0, 1); expr1->rtype = expr2->rtype; } else if (CClass_IsBaseClass(TYPE_CLASS(TPTR_TARGET(expr2->rtype)), TYPE_CLASS(TPTR_TARGET(expr1->rtype)), NULL, 0, 1)) { expr2 = CExpr_SafeClassPointerCast( expr2, TYPE_CLASS(TPTR_TARGET(expr2->rtype)), TYPE_CLASS(TPTR_TARGET(expr1->rtype)), 0, 1); expr2->rtype = expr1->rtype; } else { goto failed; } } result->rtype = expr1->rtype; break; } if (TPTR_TARGET(expr2->rtype) == &stvoid) result->rtype = expr2->rtype; } if (!is_typeequal(expr1->rtype, expr2->rtype)) { if (!copts.objective_c) goto failed; if (!CObjC_IsCompatibleType(expr1->rtype, expr2->rtype)) goto failed; expr1->rtype = expr2->rtype = CObjC_GetObjCType_id(1); } break; case TYPEVOID: if (!is_typeequal(expr1->rtype, expr2->rtype)) goto failed; break; case TYPESTRUCT: case TYPECLASS: if (!is_typeequal(expr1->rtype, expr2->rtype)) goto failed; result->rtype = expr1->rtype; break; case TYPEMEMBERPOINTER: if (IS_TYPE_MEMBERPOINTER(expr2->rtype) && TYPE_MEMBER_POINTER(expr1->rtype)->ty2 == TYPE_MEMBER_POINTER(expr2->rtype)->ty2) { expr2 = CExpr_Convert(expr2, expr1->rtype, ENODE_QUALS(expr1), 0, 1); } else if (CExpr_CanImplicitlyConvert(expr1, expr2->rtype, ENODE_QUALS(expr2))) { if (CExpr_CanImplicitlyConvert(expr2, expr1->rtype, ENODE_QUALS(expr1))) CError_Error(CErrorStr188); expr1 = CExpr_Convert(expr1, expr2->rtype, ENODE_QUALS(expr2), 0, 1); } else if (CExpr_CanImplicitlyConvert(expr2, expr1->rtype, ENODE_QUALS(expr1))) { expr2 = CExpr_Convert(expr2, expr1->rtype, ENODE_QUALS(expr1), 0, 1); } else { goto failed; } result->rtype = expr1->rtype; break; default: failed: CError_Error(CErrorStr245, expr1->rtype, ENODE_QUALS(expr1), expr2->rtype, ENODE_QUALS(expr2)); return nullnode(); } result->data.cond.expr1 = expr1; result->data.cond.expr2 = expr2; if (isnotzero(cond)) result = expr1; else if (iszero(cond)) result = expr2; return result; } static ENode *conditional_expression(void) { ENode *cond; ENode *expr1; ENode *expr2; ENode *result; Boolean is_templdep_cond; is_templdep_cond = 0; cond = CExpr_ParseDyadicExpression(NULL, 0, 0); if (tk != '?') return cond; cond = pointer_generation(cond); if (!IS_TYPE_TEMPLDEPEXPR(cond->rtype)) { cond = CExpr_ConvertToCondition(cond); if (!IS_TYPE_INT_OR_FLOAT(cond->rtype) && !IS_TYPE_POINTER_ONLY(cond->rtype)) { CError_Error(CErrorStr144); return nullnode(); } } else { is_templdep_cond = 1; } tk = lex(); expr1 = expression(); if (tk != ':') CError_ErrorSkip(CErrorStr141); else tk = lex(); expr2 = (copts.cplusplus && !copts.ARMconform) ? assignment_expression() : conditional_expression(); if (is_templdep_cond || IS_TYPE_TEMPLDEPEXPR(expr1->rtype) || IS_TYPE_TEMPLDEPEXPR(expr2->rtype)) { result = CExpr_NewENode(ECOND); result->rtype = &sttemplexpr; result->data.cond.cond = cond; result->data.cond.expr1 = expr1; result->data.cond.expr2 = expr2; return result; } return CExpr_New_ECOND_Node(cond, expr1, expr2); } static ENode *CExpr_MakeOpAssNode(ENode *left, ENode *right, ENodeType nt) { if (left->rtype != right->rtype) { switch (right->rtype->type) { case TYPEINT: case TYPEFLOAT: break; case TYPEENUM: right->rtype = TYPE_ENUM(right->rtype)->enumtype; break; default: right = CExpr_AssignmentPromotion(right, left->rtype, 0, 1); } if (IS_TYPE_FLOAT(left->rtype)) { if (IS_TYPE_INT(right->rtype) || (IS_TYPE_FLOAT(right->rtype) && left->rtype->size >= right->rtype->size)) right = CExpr_AssignmentPromotion(right, left->rtype, 0, 1); } else if (IS_TYPE_INT(left->rtype)) { if (IS_TYPE_INT(right->rtype) && (left->rtype->size > right->rtype->size || (left->rtype->size == right->rtype->size && is_unsigned(left->rtype) == is_unsigned(right->rtype)))) right = CExpr_AssignmentPromotion(right, left->rtype, 0, 1); } } return makediadicnode(left, right, nt); } static ENode *makeassignmentnode(ENode *left, ENodeType nt, short token) { ENode *right; ENode *tmp; ENode *funcexpr; ENodeList *args; Conversion conv; tk = lex(); right = assignment_expression(); if (copts.cplusplus) { if (copts.old_argmatch && !ENODE_IS(right, EMEMBER)) right = pointer_generation(right); if (CExpr_CheckOperator(token, left, right, &conv)) { if (!conv.x0) { if (nt == EASS) goto continue_anyway; CError_FATAL(6531); } return conv.x0; } if (IS_TYPE_CLASS(left->rtype) && CClass_AssignmentOperator(TYPE_CLASS(left->rtype))) CError_Error(CErrorStr144); } continue_anyway: if (IS_TYPE_ARRAY(left->rtype)) { if (copts.gcc_extensions && nt == EASS && is_typesame(left->rtype, right->rtype)) { tmp = makediadicnode(left, right, nt); tmp->flags = left->flags; return tmp; } CError_Error(CErrorStr144); return nullnode(); } left = CExpr_LValue(pointer_generation(left), 1, 1); if (nt != EASS) { if (!IS_TYPE_INT(right->rtype)) { if (!IS_TYPE_ENUM(right->rtype)) { CError_Error(CErrorStr144); return left; } right = forceintegral(right); } if (!IS_TYPE_INT(left->rtype)) { if (copts.cplusplus) { CError_Error(CErrorStr144); return left; } left = forceintegral(left); if (!IS_TYPE_INT(left->rtype)) { CError_Error(CErrorStr144); return left; } } return CExpr_MakeOpAssNode(left, right, nt); } if (IS_TYPE_CLASS(left->rtype) && TYPE_CLASS(left->rtype)->sominfo) { CError_Error(CErrorStr285); return left; } if (copts.warn_implicitconv && ENODE_IS(left, EINDIRECT) && ENODE_IS(left->data.monadic, EBITFIELD) && !ENODE_IS(right, EINTCONST)) { copts.warn_implicitconv = 0; right = CExpr_AssignmentPromotion(right, left->rtype, left->flags, 1); copts.warn_implicitconv = 1; } else { right = CExpr_AssignmentPromotion(right, left->rtype, left->flags, 1); } tmp = right; if (IS_TYPE_FLOAT(right->rtype) && ENODE_IS(right, ETYPCON) && right->rtype->size == right->data.monadic->rtype->size) tmp = right->data.monadic; if ( ENODE_IS(left, EINDIRECT) && ENODE_IS(left->data.monadic, EOBJREF) && ENODE_IS(tmp, EINDIRECT) && (ENODE_IS(funcexpr = right->data.monadic, EFUNCCALL) || ENODE_IS(funcexpr, EFUNCCALLP)) && left->rtype == funcexpr->data.funccall.functype->functype && CMach_GetFunctionResultClass(funcexpr->data.funccall.functype) == 1 && (args = funcexpr->data.funccall.args) ) { switch (CABI_GetStructResultArgumentIndex(funcexpr->data.funccall.functype)) { case 0: break; case 1: if ((args = args->next)) break; CError_FATAL(6625); default: CError_FATAL(6626); } if (ENODE_IS(args->node, ETEMP)) { if (!(IS_TYPE_CLASS(left->rtype) && CClass_Destructor(TYPE_CLASS(left->rtype)))) { args->node = getnodeaddress(left, 0); return right; } } } right = makediadicnode(left, right, nt); right->flags = left->flags; return right; } static ENode *makepassignmentnode(ENode *left, ENodeType nt, short token) { ENode *right; Boolean is_array; Conversion conv; is_array = IS_TYPE_ARRAY(left->rtype); left = pointer_generation(left); if (copts.cplusplus) { tk = lex(); right = pointer_generation(assignment_expression()); if (CExpr_CheckOperator(token, left, right, &conv)) { CError_ASSERT(6669, conv.x0); return conv.x0; } left = CExpr_LValue(left, 1, 1); } else { left = CExpr_LValue(left, 1, 1); tk = lex(); right = pointer_generation(assignment_expression()); } if (is_array) CError_Error(CErrorStr144); switch (left->rtype->type) { case TYPEINT: case TYPEFLOAT: case TYPEPOINTER: break; case TYPEENUM: if (copts.cplusplus) { CError_Error(CErrorStr144); return left; } left = forceintegral(left); break; default: CError_Error(CErrorStr144); return left; } if (IS_TYPE_ENUM(right->rtype)) right = forceintegral(right); if (iszero(right)) return left; if (IS_TYPE_POINTER_ONLY(left->rtype)) { if (IS_TYPE_INT(right->rtype)) { if (nt == ESUBASS) { left = psub(left, right); if (ENODE_IS(left, ESUB)) left->type = ESUBASS; return left; } else { left = padd(left, right); if (ENODE_IS(left, EADD)) left->type = EADDASS; return left; } } CError_Error(CErrorStr144); return left; } else { return CExpr_MakeOpAssNode(left, right, nt); } } static ENode *makemulassignmentnode(ENode *left, ENodeType nt, short token) { ENode *right; Boolean is_array; Conversion conv; is_array = IS_TYPE_ARRAY(left->rtype); left = pointer_generation(left); if (copts.cplusplus) { tk = lex(); right = pointer_generation(assignment_expression()); if (CExpr_CheckOperator(token, left, right, &conv)) { CError_ASSERT(6753, conv.x0); return conv.x0; } if (!IS_TYPE_INT(left->rtype) && !(IS_TYPE_FLOAT(left->rtype) && nt != EMODASS)) { CError_Error(CErrorStr144); return nullnode(); } left = CExpr_LValue(left, 1, 1); } else { if (IS_TYPE_ENUM(left->rtype)) left = forceintegral(left); if (!IS_TYPE_INT(left->rtype) && !(IS_TYPE_FLOAT(left->rtype) && nt != EMODASS)) { CError_Error(CErrorStr144); return nullnode(); } left = CExpr_LValue(left, 1, 1); tk = lex(); right = pointer_generation(assignment_expression()); } if (is_array) CError_Error(CErrorStr144); if (IS_TYPE_ENUM(right->rtype)) right = forceintegral(right); if (IS_TYPE_INT(left->rtype) && IS_TYPE_FLOAT(right->rtype) && nt == EMODASS) { CError_Error(CErrorStr144); return nullnode(); } return CExpr_MakeOpAssNode(left, right, nt); } static ENode *CExpr_TransformOpAssign(ENode *expr) { switch (expr->type) { case EMULASS: case EDIVASS: case EMODASS: case EADDASS: case ESUBASS: case ESHLASS: case ESHRASS: case EANDASS: case EXORASS: case EORASS: if (expr->rtype == TYPE(&stbool)) { expr = CIRTrans_TransformOpAss(expr); if (ENODE_IS(expr, EASS)) { expr->data.diadic.right = makemonadicnode(expr->data.diadic.right, ELOGNOT); expr->data.diadic.right->rtype = TYPE(&stbool); expr->data.diadic.right = makemonadicnode(expr->data.diadic.right, ELOGNOT); } } } return expr; } ENode *assignment_expression(void) { ENode *expr; if (tk == TK_THROW) return CExcept_ScanThrowExpression(); expr = conditional_expression(); switch (tk) { case '=': return makeassignmentnode(expr, EASS, tk); case TK_ADD_ASSIGN: return CExpr_TransformOpAssign(makepassignmentnode(expr, EADDASS, tk)); case TK_SUB_ASSIGN: return CExpr_TransformOpAssign(makepassignmentnode(expr, ESUBASS, tk)); case TK_MULT_ASSIGN: expr = makemulassignmentnode(expr, EMULASS, tk); if (ENODE_IS(expr, EMULASS) && CExpr_IsOne(expr->data.diadic.right)) return expr->data.diadic.left; return CExpr_TransformOpAssign(expr); case TK_DIV_ASSIGN: expr = makemulassignmentnode(expr, EDIVASS, tk); if (ENODE_IS(expr, EDIVASS)) { if (iszero(expr->data.diadic.right) && !IS_TYPE_FLOAT(expr->rtype)) { CError_Warning(CErrorStr139); return expr->data.diadic.left; } if (CExpr_IsOne(expr->data.diadic.right)) return expr->data.diadic.left; } return CExpr_TransformOpAssign(expr); case TK_MOD_ASSIGN: expr = makemulassignmentnode(expr, EMODASS, tk); if (ENODE_IS(expr, EMODASS)) { if (iszero(expr->data.diadic.right)) { CError_Warning(CErrorStr139); return expr->data.diadic.left; } } return CExpr_TransformOpAssign(expr); case TK_SHL_ASSIGN: expr = makeassignmentnode(expr, ESHLASS, tk); if (ENODE_IS(expr, ESHLASS) && iszero(expr->data.diadic.right)) return expr->data.diadic.left; return CExpr_TransformOpAssign(expr); case TK_SHR_ASSIGN: expr = makeassignmentnode(expr, ESHRASS, tk); if (ENODE_IS(expr, ESHRASS) && iszero(expr->data.diadic.right)) return expr->data.diadic.left; return CExpr_TransformOpAssign(expr); case TK_AND_ASSIGN: expr = makeassignmentnode(expr, EANDASS, tk); if (ENODE_IS(expr, EANDASS) && CExpr_AllBitsSet(expr->data.diadic.right)) return expr->data.diadic.left; return expr; case TK_XOR_ASSIGN: expr = makeassignmentnode(expr, EXORASS, tk); if (ENODE_IS(expr, EXORASS) && iszero(expr->data.diadic.right)) return expr->data.diadic.left; return CExpr_TransformOpAssign(expr); case TK_OR_ASSIGN: expr = makeassignmentnode(expr, EORASS, tk); if (ENODE_IS(expr, EORASS) && iszero(expr->data.diadic.right)) return expr->data.diadic.left; return CExpr_TransformOpAssign(expr); default: return expr; } } ENode *conv_assignment_expression(void) { return pointer_generation(assignment_expression()); } static Boolean CExpr_HasSideEffect(ENode *expr) { switch (expr->type) { case EMONMIN: case EBINNOT: case ELOGNOT: case EMUL: case EDIV: case EMODULO: case EADD: case ESUB: case ESHL: case ESHR: case ELESS: case EGREATER: case ELESSEQU: case EGREATEREQU: case EEQU: case ENOTEQU: case EAND: case EXOR: case EOR: case ELAND: case ELOR: case EROTL: case EROTR: case EBITFIELD: case EINTCONST: case EFLOATCONST: case ESTRINGCONST: case EOBJREF: case ETEMP: case EARGOBJ: case ELOCOBJ: case EOBJLIST: case EMEMBER: case EVECTOR128CONST: return 0; case ETYPCON: return IS_TYPE_VOID(expr->rtype); case EINDIRECT: switch (expr->data.monadic->type) { case EFUNCCALL: case EFUNCCALLP: return 1; default: return 0; } case ECOMMA: return CInline_ExpressionHasSideEffect(expr->data.diadic.right); case ECOND: return CInline_ExpressionHasSideEffect(expr->data.cond.expr1) || CInline_ExpressionHasSideEffect(expr->data.cond.expr2); case EPOSTINC: case EPOSTDEC: case EPREINC: case EPREDEC: case EFORCELOAD: case EASS: case EMULASS: case EDIVASS: case EMODASS: case EADDASS: case ESUBASS: case ESHLASS: case ESHRASS: case EANDASS: case EXORASS: case EORASS: case EFUNCCALL: case EFUNCCALLP: case EMFPOINTER: case ENULLCHECK: case EPRECOMP: case ELABEL: case ENEWEXCEPTION: case ENEWEXCEPTIONARRAY: case EINITTRYCATCH: case EINSTRUCTION: return 1; default: CError_FATAL(7056); return 0; } } void CExpr_CheckUnusedExpression(ENode *expr) { ENode *scan; ENodeList *arg; if (copts.warn_possunwant) { scan = expr; while (ENODE_IS(scan, ETYPCON)) scan = scan->data.monadic; if (ENODE_IS(scan, EEQU)) { CError_Warning(CErrorStr208); return; } } if (copts.warn_no_side_effect) { if (!CExpr_HasSideEffect(expr)) { CError_Warning(CErrorStr369); return; } } if (copts.warn_resultnotused) { scan = expr; if (IS_TYPE_VOID(expr->rtype)) return; if (ENODE_IS(expr, EINDIRECT)) scan = expr->data.monadic; switch (scan->type) { case EFUNCCALL: case EFUNCCALLP: if (ENODE_IS(scan->data.funccall.funcref, EOBJREF) && scan->data.funccall.funcref->data.objref->name == asop_name_node) return; if (CMach_GetFunctionResultClass(scan->data.funccall.functype) == 1 && (arg = scan->data.funccall.args)) { switch (CABI_GetStructResultArgumentIndex(scan->data.funccall.functype)) { case 0: break; case 1: if ((arg = arg->next)) break; CError_FATAL(7110); default: CError_FATAL(7111); } if (!ENODE_IS(arg->node, ETEMP)) return; } CError_Warning(CErrorStr370); } } } ENode *s_expression(void) { ENode *left; ENode *right; Conversion conv; left = assignment_expression(); while (tk == ',') { left = pointer_generation(left); tk = lex(); right = pointer_generation(assignment_expression()); if (copts.cplusplus && CExpr_CheckOperator(',', left, right, &conv)) { CError_ASSERT(7143, left = conv.x0); } else { CExpr_CheckUnusedExpression(left); left = makecommaexpression(left, right); left->rtype = right->rtype; } } return left; } ENode *expression(void) { return pointer_generation(s_expression()); } CInt64 CExpr_IntegralConstExprType(Type **tint) { ENode *expr; expr = pointer_generation(conditional_expression()); if (ENODE_IS(expr, EINTCONST)) { switch (expr->rtype->type) { case TYPEINT: *tint = expr->rtype; return expr->data.intval; case TYPEENUM: *tint = TYPE_ENUM(expr->rtype)->enumtype; return expr->data.intval; } } CError_Error(CErrorStr124); *tint = TYPE(&stchar); return cint64_zero; } ENode *CExpr_IntegralConstOrDepExpr(void) { ENode *expr; expr = pointer_generation(conditional_expression()); if (ENODE_IS(expr, EINTCONST)) { switch (expr->rtype->type) { case TYPEINT: return expr; case TYPEENUM: expr->rtype = TYPE_ENUM(expr->rtype)->enumtype; return expr; default: CError_FATAL(7209); } } if (CTemplTool_IsTemplateArgumentDependentExpression(expr)) return expr; CError_Error(CErrorStr124); expr = nullnode(); expr->rtype = TYPE(&stchar); return expr; } CInt64 CExpr_IntegralConstExpr(void) { Type *throwaway; return CExpr_IntegralConstExprType(&throwaway); } void CExpr_CheckUnwantedAssignment(ENode *expr) { if (copts.warn_possunwant) { if (ENODE_IS(expr, EASS) && !(expr->flags & ENODE_FLAG_80)) CError_Warning(CErrorStr207); } } Boolean CExpr_ParseAsmExpr(Object **objptr, CInt64 *valptr) { ENode *expr; if (objptr) *objptr = NULL; *valptr = cint64_zero; expr = pointer_generation(assignment_expression()); if (ENODE_IS(expr, EINTCONST)) { *valptr = expr->data.intval; return 1; } if (objptr) { switch (expr->type) { case EINDIRECT: if (CInit_RelocInitCheck(expr->data.monadic, objptr, valptr, 1)) return 1; break; case EOBJREF: *objptr = expr->data.objref; while ((*objptr)->datatype == DALIAS) *objptr = (*objptr)->u.alias.object; return 1; case EMEMBER: if (expr->data.emember->list->object->otype == OT_OBJECT) { if (expr->data.emember->list->next && expr->data.emember->list->next->object->otype == OT_OBJECT) CError_Error(CErrorStr199); *objptr = OBJECT(expr->data.emember->list->object); while ((*objptr)->datatype == DALIAS) *objptr = (*objptr)->u.alias.object; return 1; } break; case EOBJLIST: CError_Error(CErrorStr199); return 0; } } CError_Error(CErrorStr155); return 0; }