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