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